@@ -284,9 +284,9 @@ bool SERCOM::enqueueUART(SercomTxn* txn)
284284#ifdef USE_ZERODMA
285285 if (!_dmaConfigured)
286286 return false ;
287- #else
288- return false ;
289287#endif
288+ if (_txnQueue.isFull ())
289+ return false ; // Queue full; caller must retry at runtime
290290 if (!_txnQueue.store (txn))
291291 return false ;
292292 if (!_uart.active ) {
@@ -315,14 +315,31 @@ SercomTxn* SERCOM::stopTransmissionUART(void)
315315SercomTxn* SERCOM::stopTransmissionUART (SercomUartError error)
316316{
317317 SercomTxn* txn = nullptr ;
318- if (_txnQueue.read (txn) && txn ! = nullptr )
319- {
320- _uart. active = false ;
321- _uart. currentTxn = nullptr ;
318+ if (! _txnQueue.peek (txn) || txn = = nullptr )
319+ return nullptr ;
320+
321+ // Call completion callback before deciding to dequeue
322322 if (txn->onComplete )
323323 txn->onComplete (txn->user , static_cast <int >(error));
324+
325+ // Check if callback wants to chain another phase
326+ if (txn->chainNext ) {
327+ txn->chainNext = false ; // reset for next iteration
328+ if (!startTransmissionUART ()) {
329+ // Hardware start failed, force dequeue
330+ _txnQueue.read (txn);
331+ _uart.active = false ;
332+ _uart.currentTxn = nullptr ;
333+ return txn;
334+ }
335+ return txn;
324336 }
325337
338+ // Normal completion: dequeue and start next transaction
339+ _txnQueue.read (txn);
340+ _uart.active = false ;
341+ _uart.currentTxn = nullptr ;
342+
326343 SercomTxn* next = nullptr ;
327344 if (_txnQueue.peek (next) && next)
328345 startTransmissionUART ();
@@ -421,6 +438,8 @@ bool SERCOM::enqueueSPI(SercomTxn* txn)
421438{
422439 if (txn == nullptr )
423440 return false ;
441+ if (_txnQueue.isFull ())
442+ return false ; // Queue full; caller must retry at runtime
424443 if (!_txnQueue.store (txn))
425444 return false ;
426445 if (!_spi.active ) {
@@ -443,14 +462,25 @@ SercomTxn* SERCOM::stopTransmissionSPI(void)
443462SercomTxn* SERCOM::stopTransmissionSPI (SercomSpiError error)
444463{
445464 SercomTxn* txn = nullptr ;
446- if (_txnQueue.read (txn) && txn ! = nullptr )
447- {
448- _spi. active = false ;
449- _spi. currentTxn = nullptr ;
465+ if (! _txnQueue.peek (txn) || txn = = nullptr )
466+ return nullptr ;
467+
468+ // Call completion callback before deciding to dequeue
450469 if (txn->onComplete )
451470 txn->onComplete (txn->user , static_cast <int >(error));
471+
472+ // Check if callback wants to chain another phase
473+ if (txn->chainNext ) {
474+ txn->chainNext = false ; // reset for next iteration
475+ startTransmissionSPI (); // restart with updated context, same queue slot
476+ return txn;
452477 }
453478
479+ // Normal completion: dequeue and start next transaction
480+ _txnQueue.read (txn);
481+ _spi.active = false ;
482+ _spi.currentTxn = nullptr ;
483+
454484 SercomTxn* next = nullptr ;
455485 if (_txnQueue.peek (next) && next)
456486 startTransmissionSPI ();
@@ -816,6 +846,8 @@ bool SERCOM::enqueueWIRE(SercomTxn* txn)
816846{
817847 if (txn == nullptr )
818848 return false ;
849+ if (_txnQueue.isFull ())
850+ return false ; // Queue full; caller must retry at runtime
819851 if (!_txnQueue.store (txn))
820852 return false ;
821853 if (!_wire.active )
@@ -889,6 +921,13 @@ SercomTxn* SERCOM::stopTransmissionWIRE( SercomWireError error )
889921 if (txn && txn->onComplete )
890922 txn->onComplete (txn->user , static_cast <int >(error));
891923
924+ // Allow multi-phase I2C transactions to chain without dequeuing.
925+ if (isMasterWIRE () && txn && txn->chainNext ) {
926+ txn->chainNext = false ; // reset for next iteration
927+ startTransmissionWIRE ();
928+ return txn;
929+ }
930+
892931 if (isMasterWIRE ())
893932 _txnQueue.read (txn); // remove the completed transaction from the queue
894933 else {
0 commit comments