-
Notifications
You must be signed in to change notification settings - Fork 7.3k
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
i2c: busy wait in s_i2c_send_commands
is not very power efficient. (IDFGH-12076)
#13137
Comments
s_i2c_send_commands
is not very power efficient.s_i2c_send_commands
is not very power efficient. (IDFGH-12076)
If FreeRTOS is always expected to be in the build for this driver, then maybe the synchronous version should suspend the task with This provides not just better CPU sharing and power-usage efficiency, but an 8x performance improvement over 1kHz systicks and ~75x over 100Hz systicks. Here is a simple sync vs async benchmark:
Test project: n.b.: I'm not sure if |
@mythbuster5 I believe this hasn't been sufficiently documented since the new driver was added. The previous API used a FreeRTOS queue to receive messages once commands were completed, while now the API is truly CPU blocking. I have had TWDT trigger because of this when device is offline. |
This commit introduces a private member `i2c_master_bus_t::in_progress_semphr` which allows `i2c_master_transmit` and related functions to give up their timeslice so other tasks can proceed. Without this commit, one must delay at least one tick via `vTaskDelay(1)` to prevent trigging the idle watchdog, thus limiting the maximum I2C transaction rate to about the speed of `CONFIG_FREERTOS_HZ`. With this commit, over 6600 samples/sec are possible and the tick delay is unnecessary. CPU usage below was measured using `vTaskGetRunTimeStats()`. The FreeRTOS %CPU numbers seem to increase over time and level out after a time, so CPU usage was sampled after 5 seconds across each test for consistency across measurements. Measurements were taken with `CONFIG_FREERTOS_HZ` set to 100Hz and 1000Hz: Before: 100Hz: samples/sec= 99 with 1% CPU ( 99.0 samples/%cpu) 1000Hz: samples/sec= 995 with 10% CPU ( 99.5 samples/%cpu) After: 100Hz: samples/sec=6637 with 23% CPU (288.6 samples/%cpu) 1000Hz: samples/sec=6610 with 24% CPU (275.4 samples/%cpu) Closes: espressif#13137 Signed-off-by: Eric Wheeler <[email protected]>
@nebkat, and @mythbuster5: Please see PR #13322 which would close this issue. |
This commit introduces a private member `i2c_master_bus_t::in_progress_semphr` which allows `i2c_master_transmit` and related functions to give up their timeslice so other tasks can proceed. Without this commit, one must delay at least one tick via `vTaskDelay(1)` to prevent trigging the idle watchdog, thus limiting the maximum I2C transaction rate to about the speed of `CONFIG_FREERTOS_HZ`. With this commit, over 6600 samples/sec are possible and the tick delay is unnecessary. CPU usage below was measured using `vTaskGetRunTimeStats()`. The FreeRTOS %CPU numbers seem to increase over time and level out after a time, so CPU usage was sampled after 5 seconds across each test for consistency across measurements. Measurements were taken with `CONFIG_FREERTOS_HZ` set to 100Hz and 1000Hz: Before: 100Hz: samples/sec= 99 with 1% CPU ( 99.0 samples/%cpu) 1000Hz: samples/sec= 995 with 10% CPU ( 99.5 samples/%cpu) After: 100Hz: samples/sec=6637 with 23% CPU (288.6 samples/%cpu) 1000Hz: samples/sec=6610 with 24% CPU (275.4 samples/%cpu) Closes: espressif#13137 Signed-off-by: Eric Wheeler <[email protected]>
Answers checklist.
General issue report
While researching #13136, I noticed that s_i2c_send_commands does a "busy wait" while waiting for the interrupt handler to (eventually) finish the i2c transfer.
Correct me if I'm wrong, but this isn't very power efficient; at low i2c clock rates, it isn't computationally efficient for other tasks, either, because it spins the CPU waiting for the transfer to complete:
Wouldn't this be better for power consumption?
or if FreeRTOS is involved, maybe this would be better to suspend the busy wait until the next systick?
The text was updated successfully, but these errors were encountered: