2727#include " RingBuffer.h"
2828#include < stddef.h>
2929
30- // WIRE_HAS_END means Wire has end()
30+ // WIRE_HAS_END means Wire has end()
3131#define WIRE_HAS_END 1
3232
3333// NOTE: SAMD21/SAMD51 silicon errata: when I2C master uses SCLSM=1, CTRLB.CMD
3838
3939class TwoWire : public Stream
4040{
41- public:
42- TwoWire (SERCOM *s, uint8_t pinSDA, uint8_t pinSCL);
43- void begin ();
44- void begin (uint8_t , bool enableGeneralCall = false );
45- void begin (uint16_t , bool enableGeneralCall, uint8_t speed = 0x0 ,
46- bool enable10Bit = false );
47- void end ();
48- void setClock (uint32_t );
49-
50- void beginTransmission (uint8_t );
51- // If onComplete is nullptr, this blocks for legacy sync behavior.
52- // If onComplete is non-null, this enqueues and returns immediately (async).
53- uint8_t endTransmission (bool stopBit = true ,
54- void (*onComplete)(void *user, int status) = nullptr,
55- void *user = nullptr);
56-
57- // If onComplete is nullptr, this blocks for legacy sync behavior.
58- // If onComplete is non-null, this enqueues and returns immediately (async).
59- // If rxBuffer is nullptr, the internal buffer is used; otherwise rxBuffer is
60- // used.
61- uint8_t requestFrom (uint8_t address, size_t quantity, bool stopBit = true ,
62- uint8_t *rxBuffer = nullptr ,
63- void (*onComplete)(void *user, int status) = nullptr,
64- void *user = nullptr);
65-
66- size_t write (uint8_t data);
67- // 3-arg write: when setExternal=true, data is used directly (zero-copy) and
68- // quantity is treated as both length and capacity; subsequent write() calls
69- // return 0. For streaming > WIRE_BUFFER_LENGTH or async usage, call
70- // setTxBuffer() before write() on every transaction.
71- size_t write (const uint8_t *data, size_t quantity, bool setExternal = false );
41+ public:
42+ TwoWire (SERCOM *s, uint8_t pinSDA, uint8_t pinSCL);
43+ void begin ();
44+ void begin (uint8_t , bool enableGeneralCall = false );
45+ void begin (uint16_t , bool enableGeneralCall, uint8_t speed = 0x0 , bool enable10Bit = false );
46+ void end ();
47+ void setClock (uint32_t );
48+
49+ void beginTransmission (uint8_t );
50+ // If onComplete is nullptr, this blocks for legacy sync behavior.
51+ // If onComplete is non-null, this enqueues and returns immediately (async).
52+ uint8_t endTransmission (bool stopBit = true ,
53+ void (*onComplete)(void *user, int status) = nullptr,
54+ void *user = nullptr);
55+
56+ // If onComplete is nullptr, this blocks for legacy sync behavior.
57+ // If onComplete is non-null, this enqueues and returns immediately (async).
58+ // If rxBuffer is nullptr, the internal buffer is used; otherwise rxBuffer is used.
59+ uint8_t requestFrom (uint8_t address, size_t quantity, bool stopBit = true ,
60+ uint8_t *rxBuffer = nullptr ,
61+ void (*onComplete)(void *user, int status) = nullptr,
62+ void *user = nullptr);
63+
64+ size_t write (uint8_t data);
65+ // 3-arg write: when setExternal=true, data is used directly (zero-copy) and
66+ // quantity is treated as both length and capacity; subsequent write() calls return 0.
67+ // For streaming > WIRE_BUFFER_LENGTH or async usage, call setTxBuffer() before write()
68+ // on every transaction.
69+ size_t write (const uint8_t *data, size_t quantity, bool setExternal = false );
7270
7371 virtual int available (void );
7472 virtual int read (void );
@@ -93,21 +91,8 @@ class TwoWire : public Stream
9391
9492 inline void onService (void );
9593
96- #ifdef _DEBUG_
97- inline SercomTxn *getSlaveTxn (void ) { return &slaveTxn; }
98- inline const SercomTxn *getSlaveTxn (void ) const { return &slaveTxn; }
99- inline SercomTxn *getLoaderTxn (void ) { return &loader; }
100- inline const SercomTxn *getLoaderTxn (void ) const { return &loader; }
101- inline SercomTxn *getActiveTxn (void ) {
102- return sercom ? sercom->getCurrentTxnWIRE () : nullptr ;
103- }
104- inline const SercomTxn *getActiveTxn (void ) const {
105- return sercom ? sercom->getCurrentTxnWIRE () : nullptr ;
106- }
107- #endif // _DEBUG_
108-
109- private:
110- SERCOM *sercom;
94+ private:
95+ SERCOM *sercom;
11196 uint8_t _uc_pinSDA;
11297 uint8_t _uc_pinSCL;
11398
@@ -117,7 +102,7 @@ class TwoWire : public Stream
117102 static constexpr size_t WIRE_BUFFER_LENGTH = 255 ;
118103 uint8_t rxBuffer[WIRE_BUFFER_LENGTH];
119104 uint8_t txBuffer[WIRE_BUFFER_LENGTH];
120- uint8_t *rxBufferPtr;
105+ uint8_t *rxBufferPtr;
121106 size_t rxBufferCapacity;
122107 size_t rxLength;
123108 size_t rxIndex;
@@ -130,12 +115,12 @@ class TwoWire : public Stream
130115 int pendingReceiveLength;
131116 SercomTxn slaveTxn;
132117 SercomTxn loader; // Staging area for building transactions
133-
118+
134119 // Transaction pool for async operations (matches SERCOM queue depth)
135120 static constexpr size_t TXN_POOL_SIZE = 8 ;
136121 SercomTxn txnPool[TXN_POOL_SIZE];
137122 uint8_t txnPoolHead;
138-
123+
139124 SercomTxn *allocateTxn ();
140125 void freeTxn (SercomTxn *txn);
141126
@@ -151,22 +136,22 @@ class TwoWire : public Stream
151136};
152137
153138#if WIRE_INTERFACES_COUNT > 0
154- extern TwoWire Wire;
139+ extern TwoWire Wire;
155140#endif
156141#if WIRE_INTERFACES_COUNT > 1
157- extern TwoWire Wire1;
142+ extern TwoWire Wire1;
158143#endif
159144#if WIRE_INTERFACES_COUNT > 2
160- extern TwoWire Wire2;
145+ extern TwoWire Wire2;
161146#endif
162147#if WIRE_INTERFACES_COUNT > 3
163- extern TwoWire Wire3;
148+ extern TwoWire Wire3;
164149#endif
165150#if WIRE_INTERFACES_COUNT > 4
166- extern TwoWire Wire4;
151+ extern TwoWire Wire4;
167152#endif
168153#if WIRE_INTERFACES_COUNT > 5
169- extern TwoWire Wire5;
154+ extern TwoWire Wire5;
170155#endif
171156
172157inline void TwoWire::onService (void )
@@ -176,9 +161,9 @@ inline void TwoWire::onService(void)
176161 bool isMaster = sercom->isMasterWIRE ();
177162
178163 if ((!isMaster && !sercom->isSlaveWIRE ()) || flags == 0 ) {
179- sercom->clearINTFLAG ();
180- return ;
181- }
164+ sercom->clearINTFLAG ();
165+ return ;
166+ }
182167
183168 if (status & SERCOM_I2CM_STATUS_RXNACK) {
184169 sercom->prepareCommandBitsWIRE (WIRE_MASTER_ACT_STOP);
@@ -212,7 +197,7 @@ inline void TwoWire::onService(void)
212197 err = SercomWireError::LENGTH_ERROR;
213198 if (busState == 0x0 )
214199 err = SercomWireError::BUS_STATE_UNKNOWN;
215-
200+
216201 sercom->clearINTFLAG ();
217202 sercom->deferStopWIRE (err);
218203 return ;
@@ -221,9 +206,9 @@ inline void TwoWire::onService(void)
221206 bool isRead = (txn->config & I2C_CFG_READ);
222207
223208 if (sercom->getTxnIndexWIRE () < sercom->getTxnLengthWIRE ()) {
224- bool more = isRead ? sercom->readDataWIRE () : sercom->sendDataWIRE ();
209+ isRead ? sercom->readDataWIRE () : sercom->sendDataWIRE ();
225210 awaitingAddressAck = false ;
226- if (!isRead || more) return ;
211+ return ;
227212 }
228213
229214 if ((txn->config & I2C_CFG_STOP) && !isRead)
@@ -259,7 +244,7 @@ inline void TwoWire::onService(void)
259244 bool prec = (flags & SERCOM_I2CS_INTFLAG_PREC); // Stop detected
260245 bool amatch = (flags & SERCOM_I2CS_INTFLAG_AMATCH); // Address Match detected
261246 bool drdy = (flags & SERCOM_I2CS_INTFLAG_DRDY); // Data Ready detected
262-
247+
263248 // Stop or Restart detected - defer receive callback
264249 if (prec || (amatch && sr && !isMasterRead))
265250 {
@@ -268,23 +253,24 @@ inline void TwoWire::onService(void)
268253 sercom->deferReceiveWIRE (pendingReceiveLength);
269254 return ;
270255 }
271-
256+
272257 // Address Match - setup transaction
273258 // AACKEN enabled: address ACK is automatic, no manual ACK/clear needed
274- else if (amatch) {
259+ else if (amatch)
260+ {
275261 if (isMasterRead) // Master Read / Slave TX
276262 {
277263 // onRequestCallback runs in ISR context here. Deferring to PendSV
278264 // would require stalling DRDY or returning 0xFF until the buffer is filled.
279265 // onRequestCallback is what will set TwoWire::slaveTxn for the transaction.
280266 if (onRequestCallback)
281267 onRequestCallback ();
282-
268+
283269 // Ensure callback actually set slaveTxn.length; if not, stall with 0-length txn
284- if (slaveTxn.length == 0 )
270+ if (slaveTxn.length == 0 )
285271 return ;
286272
287- if (!(slaveTxn.config & I2C_CFG_READ))
273+ if (!(slaveTxn.config & I2C_CFG_READ))
288274 slaveTxn.config |= I2C_CFG_READ;
289275 }
290276 else // Master Write / Slave RX
@@ -302,12 +288,12 @@ inline void TwoWire::onService(void)
302288
303289 // SCLSM=0 (Smart Mode disabled): AMATCH and DRDY never fire together
304290 // → return now, DRDY will fire in next interrupt
305- // SCLSM=1 (Smart Mode enabled) + Master Read: AMATCH+DRDY fire together
291+ // SCLSM=1 (Smart Mode enabled) + Master Read: AMATCH+DRDY fire together
306292 // → fall through to handle data immediately
307293 // SCLSM=1 + Master Write: DRDY not set yet
308294 // → return now, DRDY fires later
309295 if (!drdy)
310- return ;
296+ return ;
311297 // else: DRDY is set (SCLSM=1 Master Read case), fall through
312298 }
313299
@@ -317,7 +303,7 @@ inline void TwoWire::onService(void)
317303 isMasterRead ? sercom->sendDataWIRE () : sercom->readDataWIRE ();
318304
319305 if (!isMasterRead)
320- rxLength = sercom->getTxnIndexWIRE ();
306+ rxLength = sercom->getTxnIndexWIRE ();
321307 }
322308 }
323309}
0 commit comments