Skip to content

Commit 445cc98

Browse files
committed
Add dynamic I2C speed mode with automatic HS address bit handling
1 parent d2772f8 commit 445cc98

1 file changed

Lines changed: 28 additions & 7 deletions

File tree

cores/arduino/SERCOM.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -476,18 +476,38 @@ void SERCOM::initMasterWIRE( uint32_t baudrate )
476476

477477

478478
// Enable all interrupts
479-
// sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR ;
479+
// sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR ;
480480

481-
uint8_t speedBit = sercom->I2CM.CTRLA.bit.SPEED;
482-
uint32_t topSpeeds[3] = {400000, 1000000, 3400000}; // {(sm/fm), (fm+), (hs)}
483-
const uint32_t minBaudrate = freqRef / 512; // BAUD = 255: SAMD51 ~195kHz, SAMD21 ~94kHz
484-
const uint32_t maxBaudrate = topSpeeds[speedBit];
481+
// Determine speed mode based on requested baudrate
482+
const uint32_t topSpeeds[3] = {400000, 1000000, 3400000}; // {(sm/fm), (fm+), (hs)}
483+
uint8_t speedBit = 0;
484+
bool clockStretchMode = false;
485+
sercom->I2CM.CTRLA.bit.SCLSM = 0; // See: 28.6.2.4.6
486+
487+
if (baudrate > topSpeeds[0] && baudrate <= topSpeeds[1])
488+
{
489+
speedBit = 1; // Fast mode+
490+
clockStretchMode = false; // See: 28.6.2.4.6
491+
}
492+
else if (baudrate > topSpeeds[1])
493+
{
494+
speedBit = 2; // High speed
495+
clockStretchMode = true; // See: 28.6.2.4.6
496+
}
497+
// else speedBit = 0 and clockStretchMode = false for Standard/Fast mode (up to 400kHz)
498+
499+
sercom->I2CM.CTRLA.bit.SPEED = speedBit;
500+
sercom->I2CM.CTRLA.bit.SCLSM = clockStretchMode; // See: 28.6.2.4.6
501+
502+
uint32_t minBaudrate = freqRef / 512; // BAUD = 255: SAMD51(@100MHz) ~195kHz, SAMD21 ~94kHz
503+
uint32_t maxBaudrate = topSpeeds[speedBit];
485504
baudrate = max(minBaudrate, min(baudrate, maxBaudrate));
486505

487506
if (speedBit == 0x2)
488507
sercom->I2CM.BAUD.bit.HSBAUD = freqRef / (2 * baudrate) - 1;
489508
else
490-
sercom->I2CM.BAUD.bit.BAUD = freqRef / (2 * baudrate) - 5 - freqRef * WIRE_RISE_TIME_NANOSECONDS / (2 * 1e9f);
509+
sercom->I2CM.BAUD.bit.BAUD = freqRef / (2 * baudrate) - 5 -
510+
(freqRef/1000000ul * WIRE_RISE_TIME_NANOSECONDS) / 2000;
491511
}
492512

493513
void SERCOM::prepareNackBitWIRE( void )
@@ -543,7 +563,8 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
543563
}
544564

545565
// Send start and address
546-
sercom->I2CM.ADDR.bit.ADDR = address;
566+
sercom->I2CM.ADDR.reg = SERCOM_I2CM_ADDR_ADDR(address) |
567+
((sercom->I2CM.CTRLA.bit.SPEED == 0x2) ? SERCOM_I2CM_ADDR_HS : 0);
547568

548569
// Address Transmitted
549570
if ( flag == WIRE_WRITE_FLAG ) // Write mode

0 commit comments

Comments
 (0)