diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index be7962ec2..ed5fac997 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -499,6 +499,19 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag // 7-bits address + 1-bits R/W address = (address << 0x1ul) | flag; + // If another master owns the bus or the last bus owner has not properly + // sent a stop, return failure early. This will prevent some misbehaved + // devices from deadlocking here at the cost of the caller being responsible + // for retrying the failed transmission. See SercomWireBusState for the + // possible bus states. + if(!isBusOwnerWIRE()) + { + if( isBusBusyWIRE() || (isArbLostWIRE() && !isBusIdleWIRE()) ) + { + return false; + } + } + // Wait idle or owner bus mode while ( !isBusIdleWIRE() && !isBusOwnerWIRE() ); @@ -596,6 +609,16 @@ bool SERCOM::isBusOwnerWIRE( void ) return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE; } +bool SERCOM::isArbLostWIRE( void ) +{ + return sercom->I2CM.STATUS.bit.ARBLOST == 1; +} + +bool SERCOM::isBusBusyWIRE( void ) +{ + return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE; +} + bool SERCOM::isDataReadyWIRE( void ) { return sercom->I2CS.INTFLAG.bit.DRDY; diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h index 750592aee..6f855af19 100644 --- a/cores/arduino/SERCOM.h +++ b/cores/arduino/SERCOM.h @@ -202,6 +202,8 @@ class SERCOM bool isSlaveWIRE( void ) ; bool isBusIdleWIRE( void ) ; bool isBusOwnerWIRE( void ) ; + bool isArbLostWIRE( void ); + bool isBusBusyWIRE( void ); bool isDataReadyWIRE( void ) ; bool isStopDetectedWIRE( void ) ; bool isRestartDetectedWIRE( void ) ;