Skip to content

Commit

Permalink
Merge pull request #367 from DennisErnst/master
Browse files Browse the repository at this point in the history
Fix hangs when transfer errors occur
  • Loading branch information
hathach authored Sep 5, 2024
2 parents ce20340 + c8287a1 commit 8859387
Showing 1 changed file with 32 additions and 17 deletions.
49 changes: 32 additions & 17 deletions cores/arduino/SERCOM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,29 +556,35 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
// Address Transmitted
if ( flag == WIRE_WRITE_FLAG ) // Write mode
{
while( !sercom->I2CM.INTFLAG.bit.MB )
{
while( !sercom->I2CM.INTFLAG.bit.MB ) {
// Wait transmission complete

// If certain errors occur, the MB bit may never be set (RFTM: SAMD21 sec:28.10.6; SAMD51 sec:36.10.7).
// The data transfer errors that can occur (including BUSERR) are all
// rolled up into INTFLAG.bit.ERROR from STATUS.reg
if (sercom->I2CM.INTFLAG.bit.ERROR) {
return false;
}
}
}
else // Read mode
{
while( !sercom->I2CM.INTFLAG.bit.SB )
{
// If the slave NACKS the address, the MB bit will be set.
// In that case, send a stop condition and return false.
if (sercom->I2CM.INTFLAG.bit.MB) {
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
return false;
}
while( !sercom->I2CM.INTFLAG.bit.SB ) {
// Wait transmission complete

// If the slave NACKS the address, the MB bit will be set.
// A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register
// In that case, send a stop condition and return false.
if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) {
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
return false;
}
}

// Clean the 'Slave on Bus' flag, for further usage.
//sercom->I2CM.INTFLAG.bit.SB = 0x1ul;
}


//ACK received (0: ACK, 1: NACK)
if(sercom->I2CM.STATUS.bit.RXNACK)
{
Expand All @@ -597,10 +603,11 @@ bool SERCOM::sendDataMasterWIRE(uint8_t data)

//Wait transmission successful
while(!sercom->I2CM.INTFLAG.bit.MB) {

// If a bus error occurs, the MB bit may never be set.
// Check the bus error bit and bail if it's set.
if (sercom->I2CM.STATUS.bit.BUSERR) {
// If a data transfer error occurs, the MB bit may never be set.
// Check the error bit and bail if it's set.
// The data transfer errors that can occur (including BUSERR) are all
// rolled up into INTFLAG.bit.ERROR from STATUS.reg
if (sercom->I2CM.INTFLAG.bit.ERROR) {
return false;
}
}
Expand Down Expand Up @@ -701,9 +708,17 @@ uint8_t SERCOM::readDataWIRE( void )
{
if(isMasterWIRE())
{
while( sercom->I2CM.INTFLAG.bit.SB == 0 )
{
while (sercom->I2CM.INTFLAG.bit.SB == 0) {
// Waiting complete receive
// A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register
// In that case, send a stop condition and return false.
// readDataWIRE should really be able to indicate an error (which would never be used
// because the readDataWIRE callers (in Wire.cpp) should have checked availableWIRE() first and timed it
// out if the data never showed up
if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) {
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
return 0xFF;
}
}

return sercom->I2CM.DATA.bit.DATA ;
Expand Down

0 comments on commit 8859387

Please sign in to comment.