From 19fc766fdc0197ff28f98a01321c936049ab4f63 Mon Sep 17 00:00:00 2001 From: Alberto <34496994+lupalby@users.noreply.github.com> Date: Tue, 12 Dec 2017 19:11:52 -0800 Subject: [PATCH] Check for loss of arbitration When initiating an I2C communication as master, there is a chance of losing arbitration of the bus if there are other masters on the bus. This is a perfectly normal scenario and it is handled by trying to start the communication again. If arbitration was lost during the first try, now the bus state is busy so the second call to startTransmissionWIRE will wait until the bus is idle again before retrying. I made this change on my MKRZERO over a month ago and since then I didn't have any more errors. I have a system with 7 masters on the same I2C bus sending messages at about 10Hz each, so loss of arbitration happens frequently (2 masters starting to communicate at the same time). One of the 2 gets priority over the other while the other loses arbitration. The loser simply retries the communication when loss of arbitration is detected, and everything works smoothly without data loss. Without this check we can't be aware of any loss of arbitration and the library would detect the NACK without understanding that it was not a real NACK from the slave. --- cores/arduino/SERCOM.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 200c6cda1..51ee78195 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -370,7 +370,7 @@ void SERCOM::enableWIRE() { // I2C Master and Slave modes share the ENABLE bit function. - // Enable the I�C master mode + // Enable the I²C master mode sercom->I2CM.CTRLA.bit.ENABLE = 1 ; while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 ) @@ -391,7 +391,7 @@ void SERCOM::disableWIRE() { // I2C Master and Slave modes share the ENABLE bit function. - // Enable the I�C master mode + // Enable the I²C master mode sercom->I2CM.CTRLA.bit.ENABLE = 0 ; while ( sercom->I2CM.SYNCBUSY.bit.ENABLE != 0 ) @@ -497,6 +497,12 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag { // Wait transmission complete } + // Check for loss of arbitration (multiple masters starting communication at the same time) + if(!isBusOwnerWIRE()) + { + // Restart communication + startTransmissionWIRE(address >> 1, flag); + } } else // Read mode {