@@ -542,8 +542,18 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
542542 // 7-bits address + 1-bits R/W
543543 address = (address << 0x1ul ) | flag;
544544
545- // Wait idle or owner bus mode
546- while ( !isBusIdleWIRE () && !isBusOwnerWIRE () );
545+ // If another master owns the bus or the last bus owner has not properly
546+ // sent a stop, return failure early. This will prevent some misbehaved
547+ // devices from deadlocking here at the cost of the caller being responsible
548+ // for retrying the failed transmission. See SercomWireBusState for the
549+ // possible bus states.
550+ if (!isBusOwnerWIRE ())
551+ {
552+ if ( isBusBusyWIRE () || (isArbLostWIRE () && !isBusIdleWIRE ()) || isBusUnknownWIRE () )
553+ {
554+ return false ;
555+ }
556+ }
547557
548558 // Send start and address
549559 sercom->I2CM .ADDR .bit .ADDR = address;
@@ -639,6 +649,21 @@ bool SERCOM::isBusOwnerWIRE( void )
639649 return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_OWNER_STATE;
640650}
641651
652+ bool SERCOM::isBusUnknownWIRE ( void )
653+ {
654+ return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_UNKNOWN_STATE;
655+ }
656+
657+ bool SERCOM::isArbLostWIRE ( void )
658+ {
659+ return sercom->I2CM .STATUS .bit .ARBLOST == 1 ;
660+ }
661+
662+ bool SERCOM::isBusBusyWIRE ( void )
663+ {
664+ return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_BUSY_STATE;
665+ }
666+
642667bool SERCOM::isDataReadyWIRE ( void )
643668{
644669 return sercom->I2CS .INTFLAG .bit .DRDY ;
0 commit comments