@@ -537,8 +537,18 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
537537 // 7-bits address + 1-bits R/W
538538 address = (address << 0x1ul ) | flag;
539539
540- // Wait idle or owner bus mode
541- while ( !isBusIdleWIRE () && !isBusOwnerWIRE () );
540+ // If another master owns the bus or the last bus owner has not properly
541+ // sent a stop, return failure early. This will prevent some misbehaved
542+ // devices from deadlocking here at the cost of the caller being responsible
543+ // for retrying the failed transmission. See SercomWireBusState for the
544+ // possible bus states.
545+ if (!isBusOwnerWIRE ())
546+ {
547+ if ( isBusBusyWIRE () || (isArbLostWIRE () && !isBusIdleWIRE ()) || isBusUnknownWIRE () )
548+ {
549+ return false ;
550+ }
551+ }
542552
543553 // Send start and address
544554 sercom->I2CM .ADDR .bit .ADDR = address;
@@ -634,6 +644,21 @@ bool SERCOM::isBusOwnerWIRE( void )
634644 return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_OWNER_STATE;
635645}
636646
647+ bool SERCOM::isBusUnknownWIRE ( void )
648+ {
649+ return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_UNKNOWN_STATE;
650+ }
651+
652+ bool SERCOM::isArbLostWIRE ( void )
653+ {
654+ return sercom->I2CM .STATUS .bit .ARBLOST == 1 ;
655+ }
656+
657+ bool SERCOM::isBusBusyWIRE ( void )
658+ {
659+ return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_BUSY_STATE;
660+ }
661+
637662bool SERCOM::isDataReadyWIRE ( void )
638663{
639664 return sercom->I2CS .INTFLAG .bit .DRDY ;
0 commit comments