Skip to content

Commit 3acc3c4

Browse files
committed
add support to allow transaction chaining for uart/spi/i2c
1 parent d1157c1 commit 3acc3c4

2 files changed

Lines changed: 50 additions & 10 deletions

File tree

cores/arduino/SERCOM.cpp

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
315315
SercomTxn* 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)
443462
SercomTxn* 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 {

cores/arduino/SERCOM_Txn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct SercomTxn {
1212
uint8_t* rxPtr;
1313
void (*onComplete)(void* user, int status);
1414
void* user;
15+
bool chainNext; // callback sets true to continue transaction with updated context
1516
};
1617

1718
// Mirrors WireDMA I2CError values for SERCOM-level reporting.

0 commit comments

Comments
 (0)