@@ -537,8 +537,18 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
537
537
// 7-bits address + 1-bits R/W
538
538
address = (address << 0x1ul ) | flag;
539
539
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
+ }
542
552
543
553
// Send start and address
544
554
sercom->I2CM .ADDR .bit .ADDR = address;
@@ -634,6 +644,21 @@ bool SERCOM::isBusOwnerWIRE( void )
634
644
return sercom->I2CM .STATUS .bit .BUSSTATE == WIRE_OWNER_STATE;
635
645
}
636
646
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
+
637
662
bool SERCOM::isDataReadyWIRE ( void )
638
663
{
639
664
return sercom->I2CS .INTFLAG .bit .DRDY ;
0 commit comments