Skip to content

fix(ulp): correct LP I2C interrupt wait cycle duration (IDFGH-17203)#18208

Closed
puyogo-suzuki wants to merge 1 commit intoespressif:masterfrom
puyogo-suzuki:fix-lpi2c-timeout
Closed

fix(ulp): correct LP I2C interrupt wait cycle duration (IDFGH-17203)#18208
puyogo-suzuki wants to merge 1 commit intoespressif:masterfrom
puyogo-suzuki:fix-lpi2c-timeout

Conversation

@puyogo-suzuki
Copy link
Contributor

Description

This pull request updates the lp_core_i2c module to improve how I2C interrupt wait timeouts are handled. The main change is switching from a software-based loop counter to using the RISC-V mcycle CSR for more accurate and robust cycle counting.

  • Replaced the manual increment of a timeout counter with reading the RISC-V mcycle CSR to measure elapsed cycles for timeouts in lp_core_i2c_wait_for_interrupt, improving accuracy and reliability.
  • Added #include "riscv/csr.h" to access CSR functions.

Related

None.

Testing

This is a test case repository: https://github.com/puyogo-suzuki/esp-lpi2c-timeout
I tested on ESP32-C6 with the latest ESP-IDF (master branch).

I connected Pin 6 (LPI2C SDA) to GND.
The expected behavior is that lp_core_i2c_master_read_from_device returns ESP_ERR_TIMEOUT after cycles_to_wait cycles.

#define LP_I2C_TRANS_TIMEOUT_CYCLES 5000

uint8_t data_rd[2];
uint32_t start = RV_READ_CSR(mcycle);
lp_core_i2c_master_read_from_device(LP_I2C_NUM_0, 16, data_rd, sizeof(data_rd), LP_I2C_TRANS_TIMEOUT_CYCLES);
uint32_t end = RV_READ_CSR(mcycle);
uint32_t result = end - start;

I measured the elapsed cycles by reading mcycle.
However, before this PR, the result was approximately 30x longer than LP_I2C_TRANS_TIMEOUT_CYCLES (= 150000).

This PR improves the precision of the timeout.
result will be reduced to approx. 5300, which is closer to LP_I2C_TRANS_TIMEOUT_CYCLES.


Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

Messages
📖 🎉 Good Job! All checks are passing!

👋 Hello puyogo-suzuki, we appreciate your contribution to this project!


📘 Please review the project's Contributions Guide for key guidelines on code, documentation, testing, and more.

🖊️ Please also make sure you have read and signed the Contributor License Agreement for this project.

Click to see more instructions ...


This automated output is generated by the PR linter DangerJS, which checks if your Pull Request meets the project's requirements and helps you fix potential issues.

DangerJS is triggered with each push event to a Pull Request and modify the contents of this comment.

Please consider the following:
- Danger mainly focuses on the PR structure and formatting and can't understand the meaning behind your code or changes.
- Danger is not a substitute for human code reviews; it's still important to request a code review from your colleagues.
- To manually retry these Danger checks, please navigate to the Actions tab and re-run last Danger workflow.

Review and merge process you can expect ...


We do welcome contributions in the form of bug reports, feature requests and pull requests via this public GitHub repository.

This GitHub project is public mirror of our internal git repository

1. An internal issue has been created for the PR, we assign it to the relevant engineer.
2. They review the PR and either approve it or ask you for changes or clarifications.
3. Once the GitHub PR is approved, we synchronize it into our internal git repository.
4. In the internal git repository we do the final review, collect approvals from core owners and make sure all the automated tests are passing.
- At this point we may do some adjustments to the proposed change, or extend it by adding tests or documentation.
5. If the change is approved and passes the tests it is merged into the default branch.
5. On next sync from the internal git repository merged change will appear in this public GitHub repository.

Generated by 🚫 dangerJS against ea27268

@github-actions github-actions bot changed the title fix(ulp): correct LP I2C interrupt wait cycle duration fix(ulp): correct LP I2C interrupt wait cycle duration (IDFGH-17203) Feb 6, 2026
@espressif-bot espressif-bot added the Status: Opened Issue is new label Feb 6, 2026
@meetpatelvgec
Copy link
Collaborator

Hi @puyogo-suzuki
Thanks a lot for submitting this change to improve I2C performance in ULP. We will be reviewing your changes internally and get back to you soon.

@sudeep-mohanty
Copy link
Collaborator

sha=ea27268c7e613fce27210d810790af001afa6168

@sudeep-mohanty sudeep-mohanty added the PR-Sync-Rebase Pull request sync as rebase commit label Feb 17, 2026
@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable Resolution: Done Issue is done internally and removed Status: Opened Issue is new Resolution: NA Issue resolution is unavailable labels Feb 24, 2026
@safocl
Copy link
Contributor

safocl commented Feb 24, 2026

Will these changes work on non-RISCV based chips?

@puyogo-suzuki
Copy link
Contributor Author

This change only affects RISC-V based chips, as the codebase for Xtensa based chips is different.
The i2c_wait_for_interrupt function for such chips is defined here:

static inline int32_t ulp_riscv_i2c_wait_for_interrupt(int32_t cycles_to_wait)
{
uint32_t status = 0;
uint32_t to = 0;
while (1) {

Because the read_from_device and write_to_device functions for non-RISC-V based chips do not take the wait_to_cycles argument, I've left them as is for now.
I can create a separate PR for those if requested.

@meetpatelvgec
Copy link
Collaborator

Hi @safocl, @puyogo-suzuki
I have merged my code changes into master branch 7b30754. The changes are slightly more structured and cover SPI, I2C and UART instead of only I2C. They cover both ULP RISC-V and ULP LP Core chips. As far as ESP32 is concerned, it only has ULP FSM, so I think full I2C master/slave functionality won't work on the low power core of ESP32.

@puyogo-suzuki
Copy link
Contributor Author

Thanks 👍

@safocl
Copy link
Contributor

safocl commented Feb 25, 2026

Hi @safocl, @puyogo-suzuki I have merged my code changes into master branch 7b30754. The changes are slightly more structured and cover SPI, I2C and UART instead of only I2C. They cover both ULP RISC-V and ULP LP Core chips. As far as ESP32 is concerned, it only has ULP FSM, so I think full I2C master/slave functionality won't work on the low power core of ESP32.

I meant that it is generally present in the general file #include "riscv/csr.h", although it is clearly only for risc-v. (in components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR-Sync-Rebase Pull request sync as rebase commit Resolution: Done Issue is done internally Status: Done Issue is done internally

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants