Page 1 of 1

RTC_I2C SDA sampling

Posted: Wed Feb 07, 2018 6:39 pm
by feuerrot
Hi everyone,

I have a problem regarding the usage of I2C from ULP. I'm trying to read from a Bosch BMI160 using the following code:

Code: Select all

init_i2c:
        // Use TOUCH3/RTC_GPIO13/GPIO15 as SDA
        WRITE_RTC_FIELD(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SDA_SEL, 1)
        // Use TOUCH2/RTC_GPIO12/GPIO2 as SCL
        WRITE_RTC_FIELD(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SCL_SEL, 1)

        // rtc_gpio_init(GPIO_NUM_2)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL, 1)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_FUN_SEL, 0)
        // rtc_gpio_init(GPIO_NUM_15)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL, 1)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_FUN_SEL, 0)

        // rtc_gpio_set_level(GPIO_NUM_2, 1);
        // RTCIO_GPIO2_CHANNEL == 12, 4096 == 1<<12
        WRITE_RTC_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, 4096)
        // rtc_gpio_set_level(GPIO_NUM_15, 1);
        // RTCIO_GPIO15_CHANNEL == 13, 8192 == 1<<13
        WRITE_RTC_FIELD(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS, 8192)

        // rtc_gpio_set_direction(GPIO_NUM_2, RTC_GPIO_MODE_INPUT_OUTUT);
        // rtc_gpio_output_enable(GPIO_NUM_2)
        // RTCIO_GPIO2_CHANNEL == 12, 4096 == 1<<12
        WRITE_RTC_FIELD(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS, 4096)
        // rtc_gpio_input_enable(GPIO_NUM_2)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_FUN_IE, 1)

        // rtc_gpio_set_direction(GPIO_NUM_15, RTC_GPIO_MODE_INPUT_OUTUT);
        // rtc_gpio_output_enable(GPIO_NUM_15)
        // RTCIO_GPIO15_CHANNEL == 13, 8192 == 1<<13
        WRITE_RTC_FIELD(RTC_GPIO_ENABLE_W1TS_REG, RTC_GPIO_ENABLE_W1TS, 8192)
        // rtc_gpio_input_enable(GPIO_NUM_15)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_FUN_IE, 1)

        // magic???
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_FUN_SEL, 3)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_FUN_SEL, 3)

        // Disable Pulldown on Touch2 and Touch3
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RDE, 0)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RDE, 0)
        // Enable Pullup on Touch2 and Touch3
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE, 1)
        WRITE_RTC_FIELD(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE, 1)

        // Set slave address 0
        WRITE_RTC_FIELD(SENS_SAR_SLAVE_ADDR1_REG, SENS_I2C_SLAVE_ADDR0, 0x69)

        // initialization as described in TRM 29.6.1
        // Set SCL low/high period
        WRITE_RTC_FIELD(RTC_I2C_SCL_LOW_PERIOD_REG, RTC_I2C_SCL_LOW_PERIOD, 40)
        WRITE_RTC_FIELD(RTC_I2C_SCL_HIGH_PERIOD_REG, RTC_I2C_SCL_HIGH_PERIOD, 40)
        // Set cycles between SDA switch and SCL falling edge
        WRITE_RTC_FIELD(RTC_I2C_SDA_DUTY_REG, RTC_I2C_SDA_DUTY, 16)
        // Set waiting time after start condition
        WRITE_RTC_FIELD(RTC_I2C_SCL_START_PERIOD_REG, RTC_I2C_SCL_START_PERIOD, 30)
        // Set waiting time before end condition
        WRITE_RTC_FIELD(RTC_I2C_SCL_STOP_PERIOD_REG, RTC_I2C_SCL_STOP_PERIOD, 44)
        // Set transaction timeout
        WRITE_RTC_FIELD(RTC_I2C_TIMEOUT_REG, RTC_I2C_TIMEOUT, 200)
        // Enable master mode
        WRITE_RTC_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_MS_MODE, 1)

init_imu:
        I2C_RD  0x00, 7, 0, 0
As you can see in the screenshot, this results in an I2C transaction:Image

However R0 doesn't contain the expected data afterwards. According to the note in TRM 29.6.2.1, this should be expected:
The RTC_I2C peripheral samples the SDA signals on the falling edge of SCL. If the slave changes SDA in less
than 0.38 microseconds, the master will receive incorrect data
Zooming into the trace reveals that the BMI160 changes SDA at most 0.2μs after the falling edge of SCL, which is likely the reason why R0 contains incorrect data:
Image

However, this behaviour does not seem to be I2C compliant, as the specification only guarantees SDA to be valid while SCL is high:
3.1.3: The data on the SDA line must be stable during the HIGH period of the clock
Is it possible to change the RTC_I2C behaviour so that it only samples between the rising and falling edge of SCL? If it isn't this seems to be a bug in the RTC I2C implementation.

Re: RTC_I2C SDA sampling

Posted: Thu Feb 08, 2018 8:33 pm
by WiFive
Probably not, you could try the SW i2c https://github.com/tomtor/ulp-i2c or maybe a delay line?

Re: RTC_I2C SDA sampling

Posted: Fri Feb 09, 2018 3:41 am
by ESP_Sprite
WiFive unfortunately is correct: the I2C hardware in the ULP samples at the wrong edge. Either using a delay element or software I2C is a possible solution.

Re: RTC_I2C SDA sampling

Posted: Fri Mar 29, 2019 9:43 am
by ramvij30
Is it possible to get a complete example of this project for me to try as it's not published as part of the ESP-IDF example?

Re: RTC_I2C SDA sampling

Posted: Sat Mar 30, 2019 7:56 am
by ESP_Sprite
I have successfully built off this example before: https://github.com/tomtor/ulp-i2c
Edit: Just saw Wifive also mentioned this.

Re: RTC_I2C SDA sampling

Posted: Thu Apr 23, 2020 2:46 pm
by fededim
ESP_Sprite wrote:
Fri Feb 09, 2018 3:41 am
WiFive unfortunately is correct: the I2C hardware in the ULP samples at the wrong edge. Either using a delay element or software I2C is a possible solution.
I do have the same problem with BME280, it reads bad values. What do you mean by using a delay element ?