Skip to content

Commit 4ca9f97

Browse files
committed
Update Wire peripheral handler
The existing onService method for I2C peripheral (slave) implementation swapped the sense of onRequest (master read) and onReceive (master write) handlers. It also didn't handle writes correctly, requiring two write operations to get bytes out of the buffer and in the onReceive handler. This implementation follows the SERCOM I2C flow defined for the default clock-stretching case (CTRLB.SCLSM=0) as described in the SAMD21 datasheet. Make sure the write NACK only happens on a stop
1 parent 5ae2f68 commit 4ca9f97

File tree

1 file changed

+68
-61
lines changed

1 file changed

+68
-61
lines changed

Diff for: libraries/Wire/Wire.cpp

+68-61
Original file line numberDiff line numberDiff line change
@@ -217,67 +217,74 @@ void TwoWire::onRequest(void(*function)(void))
217217
onRequestCallback = function;
218218
}
219219

220-
void TwoWire::onService(void)
221-
{
222-
if ( sercom->isSlaveWIRE() )
223-
{
224-
if(sercom->isStopDetectedWIRE() ||
225-
(sercom->isAddressMatch() && sercom->isRestartDetectedWIRE() && !sercom->isMasterReadOperationWIRE())) //Stop or Restart detected
226-
{
227-
sercom->prepareAckBitWIRE();
228-
sercom->prepareCommandBitsWire(0x03);
229-
230-
//Calling onReceiveCallback, if exists
231-
if(onReceiveCallback)
232-
{
233-
onReceiveCallback(available());
234-
}
235-
236-
rxBuffer.clear();
237-
}
238-
else if(sercom->isAddressMatch()) //Address Match
239-
{
240-
sercom->prepareAckBitWIRE();
241-
sercom->prepareCommandBitsWire(0x03);
242-
243-
if(sercom->isMasterReadOperationWIRE()) //Is a request ?
244-
{
245-
txBuffer.clear();
246-
247-
transmissionBegun = true;
248-
249-
//Calling onRequestCallback, if exists
250-
if(onRequestCallback)
251-
{
252-
onRequestCallback();
253-
}
254-
}
255-
}
256-
else if(sercom->isDataReadyWIRE())
257-
{
258-
if (sercom->isMasterReadOperationWIRE())
259-
{
260-
uint8_t c = 0xff;
261-
262-
if( txBuffer.available() ) {
263-
c = txBuffer.read_char();
264-
}
265-
266-
transmissionBegun = sercom->sendDataSlaveWIRE(c);
267-
} else { //Received data
268-
if (rxBuffer.isFull()) {
269-
sercom->prepareNackBitWIRE();
270-
} else {
271-
//Store data
272-
rxBuffer.store_char(sercom->readDataWIRE());
273-
274-
sercom->prepareAckBitWIRE();
275-
}
276-
277-
sercom->prepareCommandBitsWire(0x03);
278-
}
279-
}
280-
}
220+
void TwoWire::onService(void) {
221+
if (sercom->isSlaveWIRE()) {
222+
if (sercom->isAddressMatch()) { // address match interrupt
223+
if (sercom->isMasterReadOperationWIRE()) { // the master is making a read request
224+
sercom->prepareAckBitWIRE();
225+
sercom->prepareCommandBitsWire(0x03);
226+
227+
txBuffer.clear();
228+
transmissionBegun = true;
229+
230+
// call the onRequest callback to put bytes in the txBuffer
231+
if(onRequestCallback) {
232+
onRequestCallback();
233+
}
234+
235+
while(!sercom->isStopDetectedWIRE()) { // write the bytes out to the master
236+
if (sercom->isDataReadyWIRE()) {
237+
uint8_t c = 0xff;
238+
if (txBuffer.available()) {
239+
c = txBuffer.read_char();
240+
}
241+
242+
sercom->sendDataSlaveWIRE(c);
243+
}
244+
}
245+
246+
// done sending bytes, NACK to shut things down
247+
sercom->prepareNackBitWIRE();
248+
sercom->prepareCommandBitsWire(0x03);
249+
250+
} else if (!(sercom->isMasterReadOperationWIRE())) { // acknowledge master write request
251+
sercom->prepareAckBitWIRE();
252+
sercom->prepareCommandBitsWire(0x03);
253+
254+
while(!(sercom->isStopDetectedWIRE() || sercom->isRestartDetectedWIRE())) { // read bytes from the master
255+
if(sercom->isDataReadyWIRE()) {
256+
if (rxBuffer.isFull()) {
257+
sercom->prepareNackBitWIRE();
258+
sercom->prepareCommandBitsWire(0x03);
259+
break;
260+
} else {
261+
rxBuffer.store_char(sercom->readDataWIRE());
262+
sercom->prepareAckBitWIRE();
263+
sercom->prepareCommandBitsWire(0x03);
264+
}
265+
}
266+
}
267+
268+
if(sercom->isStopDetectedWIRE() || sercom->isRestartDetectedWIRE()) {
269+
if (onReceiveCallback) {
270+
onReceiveCallback(available());
271+
}
272+
273+
rxBuffer.clear();
274+
}
275+
276+
if(sercom->isStopDetectedWIRE()) {
277+
sercom->prepareNackBitWIRE();
278+
sercom->prepareCommandBitsWire(0x03);
279+
}
280+
281+
} else {
282+
// do nothing
283+
}
284+
} else {
285+
// do nothing
286+
}
287+
}
281288
}
282289

283290
#if WIRE_INTERFACES_COUNT > 0

0 commit comments

Comments
 (0)