Skip to content

Commit 8859387

Browse files
authored
Merge pull request #367 from DennisErnst/master
Fix hangs when transfer errors occur
2 parents ce20340 + c8287a1 commit 8859387

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

cores/arduino/SERCOM.cpp

+32-17
Original file line numberDiff line numberDiff line change
@@ -556,29 +556,35 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
556556
// Address Transmitted
557557
if ( flag == WIRE_WRITE_FLAG ) // Write mode
558558
{
559-
while( !sercom->I2CM.INTFLAG.bit.MB )
560-
{
559+
while( !sercom->I2CM.INTFLAG.bit.MB ) {
561560
// Wait transmission complete
561+
562+
// If certain errors occur, the MB bit may never be set (RFTM: SAMD21 sec:28.10.6; SAMD51 sec:36.10.7).
563+
// The data transfer errors that can occur (including BUSERR) are all
564+
// rolled up into INTFLAG.bit.ERROR from STATUS.reg
565+
if (sercom->I2CM.INTFLAG.bit.ERROR) {
566+
return false;
567+
}
562568
}
563569
}
564570
else // Read mode
565571
{
566-
while( !sercom->I2CM.INTFLAG.bit.SB )
567-
{
568-
// If the slave NACKS the address, the MB bit will be set.
569-
// In that case, send a stop condition and return false.
570-
if (sercom->I2CM.INTFLAG.bit.MB) {
571-
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
572-
return false;
573-
}
572+
while( !sercom->I2CM.INTFLAG.bit.SB ) {
574573
// Wait transmission complete
574+
575+
// If the slave NACKS the address, the MB bit will be set.
576+
// A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register
577+
// In that case, send a stop condition and return false.
578+
if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) {
579+
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
580+
return false;
581+
}
575582
}
576583

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

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

598604
//Wait transmission successful
599605
while(!sercom->I2CM.INTFLAG.bit.MB) {
600-
601-
// If a bus error occurs, the MB bit may never be set.
602-
// Check the bus error bit and bail if it's set.
603-
if (sercom->I2CM.STATUS.bit.BUSERR) {
606+
// If a data transfer error occurs, the MB bit may never be set.
607+
// Check the error bit and bail if it's set.
608+
// The data transfer errors that can occur (including BUSERR) are all
609+
// rolled up into INTFLAG.bit.ERROR from STATUS.reg
610+
if (sercom->I2CM.INTFLAG.bit.ERROR) {
604611
return false;
605612
}
606613
}
@@ -701,9 +708,17 @@ uint8_t SERCOM::readDataWIRE( void )
701708
{
702709
if(isMasterWIRE())
703710
{
704-
while( sercom->I2CM.INTFLAG.bit.SB == 0 )
705-
{
711+
while (sercom->I2CM.INTFLAG.bit.SB == 0) {
706712
// Waiting complete receive
713+
// A variety of errors in the STATUS register can set the ERROR bit in the INTFLAG register
714+
// In that case, send a stop condition and return false.
715+
// readDataWIRE should really be able to indicate an error (which would never be used
716+
// because the readDataWIRE callers (in Wire.cpp) should have checked availableWIRE() first and timed it
717+
// out if the data never showed up
718+
if (sercom->I2CM.INTFLAG.bit.MB || sercom->I2CM.INTFLAG.bit.ERROR) {
719+
sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition
720+
return 0xFF;
721+
}
707722
}
708723

709724
return sercom->I2CM.DATA.bit.DATA ;

0 commit comments

Comments
 (0)