From 63366dddd6a6152187aa76971262fc5def1467a1 Mon Sep 17 00:00:00 2001 From: Andreas Watterott <1488433+awatterott@users.noreply.github.com> Date: Sun, 28 Mar 2021 16:56:27 +0200 Subject: [PATCH 1/2] check I2C baudrate prescaler range --- cores/arduino/SERCOM.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index b9fbf05b9..bb7829188 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -458,7 +458,12 @@ void SERCOM::initMasterWIRE( uint32_t baudrate ) // sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR ; // Synchronous arithmetic baudrate - sercom->I2CM.BAUD.bit.BAUD = SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000)); + baudrate = SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000)); + if(baudrate > 255) // I2C baud rate is 8bit + { + baudrate = 255; + } + sercom->I2CM.BAUD.bit.BAUD = baudrate; } void SERCOM::prepareNackBitWIRE( void ) From 64b6fca042eb2d72834af3c8e37ea9bf353ccfc3 Mon Sep 17 00:00:00 2001 From: Andreas Watterott <1488433+awatterott@users.noreply.github.com> Date: Sun, 28 Mar 2021 17:01:33 +0200 Subject: [PATCH 2/2] I2C rx+tx timeout --- cores/arduino/SERCOM.cpp | 49 ++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index bb7829188..77f497017 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -524,28 +524,41 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag // Address Transmitted if ( flag == WIRE_WRITE_FLAG ) // Write mode { - while( !sercom->I2CM.INTFLAG.bit.MB ) + // The loop takes about 100us @ 100kHz baudrate. + // Timeout: 20ms = 10000*2us + for(uint16_t tmr = 10000; tmr; tmr--) { + if(sercom->I2CM.INTFLAG.bit.MB) // byte is transmitted + { + // Check for loss of arbitration (multiple masters starting communication at the same time) + if(!isBusOwnerWIRE()) + { + // Restart communication + sercom->I2CM.ADDR.bit.ADDR = address; + } + else + { + break; + } + } // Wait transmission complete - } - // Check for loss of arbitration (multiple masters starting communication at the same time) - if(!isBusOwnerWIRE()) - { - // Restart communication - startTransmissionWIRE(address >> 1, flag); + delayMicroseconds(2); // wait 2us } } else // Read mode { - while( !sercom->I2CM.INTFLAG.bit.SB ) + // The loop takes about 200us @ 100kHz baudrate. + // Timeout: 20ms = 10000*2us + for(uint16_t tmr = 10000; tmr && !sercom->I2CM.INTFLAG.bit.SB; tmr--) { - // If the slave NACKS the address, the MB bit will be set. - // In that case, send a stop condition and return false. - if (sercom->I2CM.INTFLAG.bit.MB) { - sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition - return false; - } + // If the slave NACKS the address, the MB bit will be set. + // In that case, send a stop condition and return false. + if (sercom->I2CM.INTFLAG.bit.MB) { + sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition + return false; + } // Wait transmission complete + delayMicroseconds(2); // wait 2us } // Clean the 'Slave on Bus' flag, for further usage. @@ -569,14 +582,16 @@ bool SERCOM::sendDataMasterWIRE(uint8_t data) //Send data sercom->I2CM.DATA.bit.DATA = data; - //Wait transmission successful - while(!sercom->I2CM.INTFLAG.bit.MB) { - + // Wait transmission successful + // The loop takes about 100us @ 100kHz baudrate. + // Timeout: 20ms = 10000*2us + for(uint16_t tmr = 10000; tmr && !sercom->I2CM.INTFLAG.bit.MB; tmr--) { // If a bus error occurs, the MB bit may never be set. // Check the bus error bit and bail if it's set. if (sercom->I2CM.STATUS.bit.BUSERR) { return false; } + delayMicroseconds(2); // wait 2us } //Problems on line? nack received?