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

ulp_lp_core_i2c during deep sleep doesn't pull signal low enough (IDFGH-11883) #12969

Closed
3 tasks done
J-D-HW opened this issue Jan 12, 2024 · 9 comments
Closed
3 tasks done
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally

Comments

@J-D-HW
Copy link

J-D-HW commented Jan 12, 2024

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

General issue report

For my project I read a temperature sensor (AHT20) using I2C. It reads it's temperature during deep sleep using the ULP Core on the ESP32-C6. I noticed not all measurements are performed correctly and sometimes the values seem to be very off. In order to find the cause of this I used a logic analyser which showed the following signal:

SDA SCL

From this logic output I was able to conclude that the logic low of the signal isn't always zero. Sometimes it's zero but often it sticks at ~900mV. This issue with the logic low always takes place at the same places during transmissions.

Also there seem to be small voltage spikes when the ACK is send.

This is the code I'm running in order to initialise the I2C communication before going into deep sleep:

    lp_core_i2c_cfg_t i2c_cfg = {
        .i2c_pin_cfg = {
            .sda_io_num    = GPIO_I2C_SDA,
            .scl_io_num    = GPIO_I2C_SCL,
            .sda_pullup_en = false,
            .scl_pullup_en = false,
        },
        .i2c_timing_cfg = {
            .clk_speed_hz = 100000,
        },
        .i2c_src_clk = LP_I2C_SCLK_LP_FAST,
    };

    ESP_RETURN_ON_ERROR(lp_core_i2c_master_init(LP_I2C_NUM_0, &i2c_cfg), TAG, "failed %s", esp_err_to_name(err_rc_));

The ULP uses the following functions to write and read data during deep sleep:

#define AHT20_I2C_ADDR       0x38
#define LP_I2C_TRANS_TIMEOUT 5000

#define AHT20_CMD_MEASURE_BYTE1 0xAC
#define AHT20_CMD_MEASURE_BYTE2 0x33
#define AHT20_CMD_MEASURE_BYTE3 0x00

void aht20_init()
{
    // Initialize the sensor
}

void main(void)
{
    uint8_t data_wr[3] = {AHT20_CMD_MEASURE_BYTE1, AHT20_CMD_MEASURE_BYTE2, AHT20_CMD_MEASURE_BYTE3};
    uint8_t data_rd[7] = {0};

    // Turn the sensor on the first time when sleeping
    if (sensor_on == false)
    {
        aht20_init();
        sensor_on = true;
    }

    lp_core_i2c_master_write_to_device(LP_I2C_NUM_0, AHT20_I2C_ADDR, data_wr, sizeof(data_wr), LP_I2C_TRANS_TIMEOUT);

    ulp_lp_core_delay_us(100000); // Wait 100ms for the sensor to measure

    lp_core_i2c_master_read_from_device(LP_I2C_NUM_0, AHT20_I2C_ADDR, data_rd, sizeof(data_rd), LP_I2C_TRANS_TIMEOUT);
}

For the temperature sensor I used the recommended circuit:

AHT20

A few things I tried:

  • Different IDF versions ( 5.1, 5.1.2, 5.2-beta2)
  • Measuring the temperature sensor using I2C while not in deep sleep, this gives a perfect signal with every logic low being zero and no voltage spikes
  • Same temperature sensor connected directly to the DevKit without any other components
  • Using a different I2C sensor (TCS34725)
  • Different hardware, same issue on both my custom PCB (ESP32-C6-MINI-1 v1.0 MAN4) and the DevKit (ESP32-C6-MINI-1 v1.0 XXN8)
  • Changing the SDA/SCL pull up resistor values
  • Using different clock speeds (50kHz, 100kHz, 200kHz and 400kHz)
  • Enabling/disabling internal pull ups
  • Change power supply (3.3V supply, battery)

Since this issue only occurs while reading the I2C sensor with the ULP core during deep sleep, it seems to be related to ulp_lp_core_i2c. Also note that the exact same thing happens with a completely different I2C sensor.

@espressif-bot espressif-bot added the Status: Opened Issue is new label Jan 12, 2024
@github-actions github-actions bot changed the title ulp_lp_core_i2c during deep sleep doesn't pull signal low enough ulp_lp_core_i2c during deep sleep doesn't pull signal low enough (IDFGH-11883) Jan 12, 2024
@sudeep-mohanty
Copy link
Collaborator

Hello @JochemHomewizard,
Thanks for reporting this issue to us. So far in my (limited) testing, I haven't noticed this problem. One thing I didn't understand clearly is if you have tried the ulp_lp_core_i2c controller without enabling deep sleep? I would like to understand if the abnormal signal levels are anyway related to the deep sleep power mode or are being purely driven by the LP_I2C peripheral irrespective of the power mode. Could you please help share this data?

@J-D-HW
Copy link
Author

J-D-HW commented Jan 15, 2024

Thanks for your reply. I just tried running this code with deep sleep turned off, and I see the same kind of output with the logic low at ~900mV. It seems to be purely caused by LP_I2C.

@sudeep-mohanty
Copy link
Collaborator

Thank you for the confirmation. We will look into this and keep the issue updated with our findings.

@DCSBL
Copy link
Contributor

DCSBL commented Jan 16, 2024

I have tested on the same development board. When using a self-made I2C using simple GPIO-bitbanging we see the same behaviour. If we configure the GPIO using RTC_GPIO_MODE_INPUT_OUTPUT_OD everything works as intended.

// main code
rtc_gpio_init(GPIO_I2C_SDA);
rtc_gpio_set_direction(GPIO_I2C_SDA, RTC_GPIO_MODE_INPUT_OUTPUT_OD);
rtc_gpio_set_direction_in_sleep(GPIO_I2C_SDA, RTC_GPIO_MODE_INPUT_OUTPUT_OD);
rtc_gpio_pulldown_dis(GPIO_I2C_SDA);
rtc_gpio_pullup_dis(GPIO_I2C_SDA);

rtc_gpio_init(GPIO_I2C_SCL);
rtc_gpio_set_direction(GPIO_I2C_SCL, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_direction_in_sleep(GPIO_I2C_SCL, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_pulldown_dis(GPIO_I2C_SCL);
rtc_gpio_pullup_dis(GPIO_I2C_SCL);

ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start));

ulp_lp_core_cfg_t core_cfg = {
    .wakeup_source              = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER,
    .lp_timer_sleep_duration_us = MEASUREMENT_TIME * SEC_TO_USEC, // Wakes up every 'measurement time' seconds to measure once
};
ulp_lp_core_run(&core_cfg);

esp_deep_sleep_start();
// LP core code
void send_bit(uint8_t level)
{
    rtcio_ll_set_level(GPIO_I2C_SDA, level);
    ulp_lp_core_delay_us(250);   
    rtcio_ll_set_level(GPIO_I2C_SCL, 1);
    ulp_lp_core_delay_us(250);   
    rtcio_ll_set_level(GPIO_I2C_SCL, 0);
    ulp_lp_core_delay_us(250);
}


void get_ack(bool *ack_received)
{
    rtcio_ll_set_level(GPIO_I2C_SDA, 1);
    ulp_lp_core_delay_us(250);   
    rtcio_ll_set_level(GPIO_I2C_SCL, 1);
    ulp_lp_core_delay_us(250);   
    *ack_received = rtcio_ll_get_level(GPIO_I2C_SDA);
    rtcio_ll_set_level(GPIO_I2C_SCL, 0);
    ulp_lp_core_delay_us(250);   
}

void send_byte(uint8_t data)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        send_bit(data & 0x80);
        data <<= 1;
    }
    
    bool ack_received;
    get_ack(&ack_received); 
}

send_start();
send_byte(AHT20_I2C_ADDR << 1); // 0x38 0b0111000
send_byte(AHT20_CMD_MEASURE_BYTE1);
send_byte(AHT20_CMD_MEASURE_BYTE2);
send_byte(AHT20_CMD_MEASURE_BYTE3);
send_stop();
image

When looking at this, we see no open drain is selected which should be used for I2C AFAIK. But this does not fix the issue.

static esp_err_t lp_i2c_configure_io(gpio_num_t io_num, bool pullup_en)
{
/* Initialize IO Pin */
ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), LPI2C_TAG, "LP GPIO Init failed for GPIO %d", io_num);
/* Set direction to input+output */
ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_INPUT_OUTPUT), LPI2C_TAG, "LP GPIO Set direction failed for %d", io_num);
/* Disable pulldown on the io pin */
ESP_RETURN_ON_ERROR(rtc_gpio_pulldown_dis(io_num), LPI2C_TAG, "LP GPIO pulldown disable failed for %d", io_num);
/* Enable pullup based on pullup_en flag */
if (pullup_en) {
ESP_RETURN_ON_ERROR(rtc_gpio_pullup_en(io_num), LPI2C_TAG, "LP GPIO pullup enable failed for %d", io_num);
} else {
ESP_RETURN_ON_ERROR(rtc_gpio_pullup_dis(io_num), LPI2C_TAG, "LP GPIO pullup disable failed for %d", io_num);
}
return ESP_OK;
}
static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg)

@espressif-bot espressif-bot added Status: Selected for Development Issue is selected for development Status: Opened Issue is new and removed Status: Opened Issue is new Status: Selected for Development Issue is selected for development labels Jan 17, 2024
@DCSBL
Copy link
Contributor

DCSBL commented Jan 24, 2024

Hey @sudeep-mohanty, sorry to bother but do you have an update maybe?

@sudeep-mohanty
Copy link
Collaborator

Hello @DCSBL,
Apologies for not reverting earlier. I still haven't managed to reproduce this problem yet but with some consultation it could be an issue with the IO lines not being in Open-drain mode. With this context, would you mind trying out this patch in your setup and let us know the results? Thanks! -

lp_i2c.patch

@DCSBL
Copy link
Contributor

DCSBL commented Jan 24, 2024

Thanks! It seems to be the case indeed, as fixing this while using direct GPIO bit-bang fixed the issue for us after selecting OD.

would you mind trying out this patch in your setup and let us know the results?

@JochemHomewizard can I assign this to you? After this we will get back to you Sudeep!

@J-D-HW
Copy link
Author

J-D-HW commented Jan 25, 2024

@sudeep-mohanty Thanks for the patch! With your patch it works without any issues. This solved the problem.

@sudeep-mohanty
Copy link
Collaborator

Thanks for testing out the patch @JochemHomewizard! Glad it worked. I shall do some further tests on the changes and formalize the fix asap! Thanks!

@espressif-bot espressif-bot added Status: In Progress Work is in progress Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: Selected for Development Issue is selected for development Status: In Progress Work is in progress labels Jan 26, 2024
espressif-bot pushed a commit that referenced this issue Feb 20, 2024
…n-drain mode

This commit fixes an issue where in the LP I2C IO lines were not
initialized in open-drain mode.

Closes #12969
espressif-bot pushed a commit that referenced this issue Mar 1, 2024
…n-drain mode

This commit fixes an issue where in the LP I2C IO lines were not
initialized in open-drain mode.

Closes #12969
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally
Projects
None yet
Development

No branches or pull requests

4 participants