@@ -542,8 +542,18 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
542
542
// 7-bits address + 1-bits R/W
543
543
address = (address << 0x1ul ) | flag;
544
544
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
+ }
547
557
548
558
// Send start and address
549
559
sercom->I2CM .ADDR .bit .ADDR = address;
@@ -639,6 +649,21 @@ bool SERCOM::isBusOwnerWIRE( void )
639
649
return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_OWNER_STATE;
640
650
}
641
651
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
+
642
667
bool SERCOM::isDataReadyWIRE ( void )
643
668
{
644
669
return sercom->I2CS .INTFLAG .bit .DRDY ;
0 commit comments