Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timeout on SERCOM I2C functions #626

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 38 additions & 18 deletions cores/arduino/SERCOM.cpp
Original file line number Diff line number Diff line change
@@ -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 )
@@ -519,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.
@@ -564,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?