espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.77k stars 7.31k forks source link

I2C command error while programming for ULP in Assembly. (IDFGH-3870) #5772

Open Ankith-A-Muralidhar opened 4 years ago

Ankith-A-Muralidhar commented 4 years ago

Environment

Problem Description

While programming for ULP core in Assembly using the instruction set, The code resets after the I2C_rd and I2C_WR command. While reading or writing using the I2C command, the information was not sending. to test this we had an two global variables and print these in the main.c, but the one before the I2C command was printing and not the one after. It always shows zero.

Expected Behavior

Need to get some values using I2C_RD command

Actual Behavior

Code resets to begin as soon as I2C command is encountered

Steps to reproduce

After initialization, giving the I2C command will give this problem

// If possible, attach a picture of your setup/wiring here.

Code to reproduce this issue


    WRITE_RTC_REG(RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_HOLD_S, RTC_IO_TOUCH_PAD3_HOLD_M, 0)
    WRITE_RTC_REG(RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_HOLD_S, RTC_IO_TOUCH_PAD2_HOLD_M, 0)
    WRITE_RTC_REG(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SDA_SEL_S, RTC_IO_SAR_I2C_SDA_SEL_M, 1)
    WRITE_RTC_REG(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SCL_SEL_S, RTC_IO_SAR_I2C_SCL_SEL_M, 1)
    WRITE_RTC_REG(SENS_SAR_SLAVE_ADDR1_REG, SENS_I2C_SLAVE_ADDR0_S, SENS_I2C_SLAVE_ADDR0_M, 0x29)
    WRITE_RTC_REG(SENS_SAR_SLAVE_ADDR1_REG, SENS_I2C_SLAVE_ADDR1_S, SENS_I2C_SLAVE_ADDR1_M, 0x29)
    WRITE_RTC_REG(RTC_I2C_SCL_LOW_PERIOD_REG, RTC_I2C_SCL_LOW_PERIOD_S, RTC_I2C_SCL_LOW_PERIOD_M, 40)
    WRITE_RTC_REG(RTC_I2C_SCL_HIGH_PERIOD_REG, RTC_I2C_SCL_HIGH_PERIOD_S, RTC_I2C_SCL_HIGH_PERIOD_M, 40)
    WRITE_RTC_REG(RTC_I2C_SDA_DUTY_REG, RTC_I2C_SDA_DUTY_S, RTC_I2C_SDA_DUTY_M, 16)
    WRITE_RTC_REG(RTC_I2C_SCL_START_PERIOD_REG, RTC_I2C_SCL_START_PERIOD_S, RTC_I2C_SCL_START_PERIOD_M, 30)
    WRITE_RTC_REG(RTC_I2C_SCL_STOP_PERIOD_REG, RTC_I2C_SCL_STOP_PERIOD_S, RTC_I2C_SCL_STOP_PERIOD_M, 44)
    WRITE_RTC_REG(RTC_I2C_TIMEOUT_REG, RTC_I2C_TIMEOUT_S, RTC_I2C_TIMEOUT_M, 10000)
    WRITE_RTC_REG(RTC_I2C_CTRL_REG, RTC_I2C_MS_MODE_S, RTC_I2C_MS_MODE_M, 1)
    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE, 1)
    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_CTRL, 0x000A000)
    I2C_WR 0x01, 0x00, 7, 0, 0
    I2C_WR 0x0F, 0x01, 7, 0, 0
// If your code is longer than 30 lines, [GIST](https://gist.github.com) is preferred.

## Debug Logs

No error, Just wrong value.
sagar448 commented 4 years ago

Hey, I'm having a similar problem. The i2c is causing resets in assembly. @Alvin1Zhang

NaimSakaamini commented 4 years ago

Facing similar issue here!

boarchuz commented 4 years ago
  1. The third parameter of WRITE_RTC_REG is bit_width, not a mask: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ulp_instruction_set.html#convenience-macros-for-peripheral-registers-access

  2. What is the intention here? Setting START_FORCE will prevent the ULP I2C instruction from working...

    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE, 1)
    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_CTRL, 0x000A000)
  3. It's generally much more convenient and robust for the SoC to handle initialisation of the RTC I2C peripheral, especially while troubleshooting. Is there any reason for having the ULP handle all this?

See here for working initialisation (tested just now) https://github.com/boarchuz/HULP/blob/fbc9b61d57c6b83079def9ddb6ced9c30d1f7bb7/src/hulp.cpp#L108-L184

Alvin1Zhang commented 4 years ago

Thanks for reporting and sorry for the inconvenience, we will look into.

Ankith-A-Muralidhar commented 4 years ago
  1. The third parameter of WRITE_RTC_REG is bit_width, not a mask: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/ulp_instruction_set.html#convenience-macros-for-peripheral-registers-access
  2. What is the intention here? Setting START_FORCE will prevent the ULP I2C instruction from working...
    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE, 1)
    WRITE_RTC_FIELD(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_CTRL, 0x000A000)
  1. It's generally much more convenient and robust for the SoC to handle initialisation of the RTC I2C peripheral, especially while troubleshooting. Is there any reason for having the ULP handle all this?

See here for working initialisation (tested just now) https://github.com/boarchuz/HULP/blob/fbc9b61d57c6b83079def9ddb6ced9c30d1f7bb7/src/hulp.cpp#L108-L184

Ankith-A-Muralidhar commented 4 years ago

I tried the same set up as mentioned. but the code still resets as soon as I2C command is read. The code I tried is below: rtc_gpio_init(GPIO_NUM_2); rtc_gpio_set_level(GPIO_NUM_2, 0); rtc_gpio_pulldown_dis(GPIO_NUM_2); rtc_gpio_pullup_dis(GPIO_NUM_2);

rtc_gpio_init(GPIO_NUM_15); rtc_gpio_set_level(GPIO_NUM_15, 0); rtc_gpio_pulldown_dis(GPIO_NUM_15); rtc_gpio_pullup_en(GPIO_NUM_15);

REG_SET_FIELD(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SCL_SEL, 1); REG_SET_FIELD(RTC_IO_SAR_I2C_IO_REG, RTC_IO_SAR_I2C_SDA_SEL, 1);

SET_PERI_REG_BITS(rtc_gpio_desc[hulp_gtr(GPIO_NUM_2)].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0x3, rtc_gpio_desc[hulp_gtr(GPIO_NUM_2)].func); SET_PERI_REG_BITS(rtc_gpio_desc[hulp_gtr(GPIO_NUM_15)].reg, RTC_IO_TOUCH_PAD1_FUN_SEL_V, 0x3, rtc_gpio_desc[hulp_gtr(GPIO_NUM_15)].func);

REG_SET_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_RX_LSB_FIRST, 1); REG_SET_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_TX_LSB_FIRST, 1); REG_SET_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_SCL_FORCE_OUT, 0); REG_SET_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_SDA_FORCE_OUT, 0);

REG_SET_FIELD(RTC_I2C_SCL_LOW_PERIOD_REG, RTC_I2C_SCL_LOW_PERIOD, 40); REG_SET_FIELD(RTC_I2C_SCL_HIGH_PERIOD_REG, RTC_I2C_SCL_HIGH_PERIOD, 40); REG_SET_FIELD(RTC_I2C_SDA_DUTY_REG, RTC_I2C_SDA_DUTY, 16); REG_SET_FIELD(RTC_I2C_SCL_START_PERIOD_REG, RTC_I2C_SCL_START_PERIOD, 30); REG_SET_FIELD(RTC_I2C_SCL_STOP_PERIOD_REG, RTC_I2C_SCL_STOP_PERIOD, 44); REG_SET_FIELD(RTC_I2C_TIMEOUT_REG, RTC_I2C_TIMEOUT, 10000); REG_SET_FIELD(RTC_I2C_CTRL_REG, RTC_I2C_MS_MODE, 1);

SET_PERI_REG_BITS(SENS_SAR_SLAVE_ADDR1_REG, SENS_I2C_SLAVE_ADDR0, 0x29, SENS_I2C_SLAVE_ADDR0_S);

I am still unsure why the i2c is not initialized. I tried to initiate it through the SoC rather than ULP core. Any help would be appreciated.

costaud commented 4 years ago

For using I2C in ULP, maybe this one could be helpful.

https://github.com/espressif/esp-iot-solution/tree/master/examples/ulp_examples/ulp_i2c_bitbang

Ankith-A-Muralidhar commented 4 years ago

I have tried this as well but no avail. I did the i2c in a different .s file and called it in the main assembly file. Yet the situation is still the same. I initialize the i2c and then make a read and then give a global variable a constant value. so even if the read value is not valid I will know if the command works. But the constant is never transferred to the global variable. So If anyone has any insights it will be greatly appreciated! Thank you!