From 13ac6069deafdd2bb53496c6ed1fc5ec25b9f85e Mon Sep 17 00:00:00 2001 From: Six Date: Thu, 21 Feb 2019 12:34:36 -0500 Subject: [PATCH 1/2] deadlock detect and early return in startTransmissionWIRE --- cores/arduino/SERCOM.cpp | 23 +++++++++++++++++++++++ cores/arduino/SERCOM.h | 2 ++ 2 files changed, 25 insertions(+) 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 ) ; From b1f527c2f0e44cee294c8dbb7562c5e96528f5fa Mon Sep 17 00:00:00 2001 From: pdgeek Date: Thu, 21 Feb 2019 12:34:36 -0500 Subject: [PATCH 2/2] deadlock detect and early return in startTransmissionWIRE --- cores/arduino/SERCOM.cpp | 23 +++++++++++++++++++++++ cores/arduino/SERCOM.h | 2 ++ 2 files changed, 25 insertions(+) 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 ) ;