energia / tivac-core

7 stars 17 forks source link

Implement I²C Clock Stretching on the Stellaris / Tiva C #28

Closed robertinant closed 4 years ago

robertinant commented 7 years ago

From @rei-vilo on March 7, 2014 8:32

The I²C specifications (NXP, I²C-bus.org) allow the slave to set the SCL clock line low to make the master wait. This is called clock streching.

An I2C slave is allowed to hold down the clock if it needs to reduce the bus speed. The master on the other hand is required to read back the clock signal after releasing it to high state and wait until the line has actually gone high.

How to implement clock stretching on the Stellaris LM4F120 / Tiva C TM4C123?

For example, the twi.h library for the MSP430 includes two functions that are used this purpose:

void twi_stop(void);
void twi_releaseBus(void);

Thank you!

Copied from original issue: energia/Energia#336

robertinant commented 7 years ago

From @rei-vilo on March 8, 2014 12:28

The E2E forum suggested me to use void I2CMasterTimeoutSet(uint32_t ui32Base, uint32_t ui32Value), as explained in

of the Tiva™ C Series TM4C123GH6PM Microcontroller Data Sheet (Rev. D).

The I2C slave can extend the transaction by pulling the clock low periodically to create a slow bit transfer rate. The I2C module has a 12-bit programmable counter that is used to track how long the clock has been held low. The upper 8 bits of the count value are software programmable through the I2C Master Clock Low Timeout Count (I2CMCLKOCNT) register. The lower four bits are not user visible and are 0x0. The CNTL value programmed in the I2CMCLKOCNT register has to be greater than 0x01. The application can program the eight most significant bits of the counter to reflect the acceptable cumulative low period in transaction. The count is loaded at the START condition and counts down on each falling edge of the internal bus clock of the Master. Note that the internal bus clock generated for this counter keeps running at the programmed I2C speed even if SCL is held low on the bus. Upon reaching terminal count, the master state machine forces ABORT on the bus by issuing a STOP condition at the instance of SCL and SDA release.

Now, how to implement it on Energia, as the I²C bus is managed by interrupts, ReceiveEvent(int howMany) and RequestEvent()?

robertinant commented 7 years ago

From @rei-vilo on April 21, 2014 11:37

Here's the solution that I've tested on port I²C (3) of the Stellaris LM4F120 and Tiva C TM4C123 LaunchPads.

Libraries to include with #include "Wire.h"

#include "driverlib/i2c.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"

This routine initialise the SCL pin. Not sure it is really useful.

void stretchInit()
{
    SysCtlPeripheralEnable(I2C_SCL3_PERIPH);
}

This routine configures the SCL line as a standard output and sets it LOW. Not sure about the 4mA parameter.

void stretchPause()
{
    // Standard output
    GPIOPadConfigSet(I2C_SCL3_BASE, I2C_SCL3_PIN, GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD);
    GPIODirModeSet(I2C_SCL3_BASE, I2C_SCL3_PIN, GPIO_DIR_MODE_OUT);
    // Set LOW
    GPIOPinWrite(I2C_SCL3_BASE, I2C_SCL3_PIN, 0);
}

This routine configures the SCL line back to normal. I tried another option but it didn't work.

void stretchResume()
{
    // Reconfigure for I2C
    ROM_GPIOPinConfigure(GPIO_PD0_I2C3SCL);
    ROM_GPIOPinTypeI2CSCL(I2C_SCL3_BASE, I2C_SCL3_PIN);

    // Doesn't work
    // HIGH for floating?
    //    GPIOPinWrite(I2C_SCL3_BASE, I2C_SCL3_PIN, I2C_SCL3_PIN);
    // Open drain
    //    GPIOPadConfigSet(I2C_SCL3_BASE, I2C_SCL3_PIN, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
    //    GPIODirModeSet(I2C_SCL3_BASE, I2C_SCL3_PIN, GPIO_DIR_MODE_HW);
}

Typical usage requires

Questions:

Thanks!

robertinant commented 7 years ago

From @rei-vilo on April 21, 2014 12:23

Integration into Wire library was easier than expected. See pull request #375 Tested on LM4F120- and TM4C123-based LaunchPads Please proceed with other tests and commit!

robertinant commented 7 years ago

From @rei-vilo on April 21, 2014 12:32

capture 2014-04-21 a 14 11 51

robertinant commented 7 years ago

From @spirilis on April 21, 2014 12:50

Slick! I like it.

robertinant commented 7 years ago

From @rei-vilo on April 21, 2014 12:51

I removed the digitalWrite(GREEN_LED, HIGH); on line 613 from Wire.cpp.

See 263e48cf6dc22752636ff13456fa0a19fbb0ac00

robertinant commented 7 years ago

From @rei-vilo on May 22, 2014 18:0

See #375

robertinant commented 4 years ago

No plans to implement I2C slave Clock Stretching.