ESP32: I2C transfers block the scheduler, and each i2c call costs about 1 ms
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Necesita aclaración
- Estado de actividad
- Activo
- Stack tecnológico
- c, erlang
Línea de trabajo
Start by reading the ESP32 I2C port driver and event loop; the issue does not name specific files or tests. The report identifies synchronous transfers and delayed event polling as possible bottlenecks, but leaves open whether to add a non-blocking path, change scheduler wakeups, or expose batched sensor results. Done would require agreeing on the desired behavior and validating its effect on scheduler delays.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
I've been writing firmware for a little robot with an ESP32-C6 (Microbots CodeCell C6 Drive) that has a BNO085 IMU and a VCNL4040 proximity sensor on the same I2C bus at 400 kHz. The BNO085 clock-stretching timeouts were the first problem, and the new I2C driver PR sorts those out. But once the IMU was talking, my control loops still crawled, so I spent some time measuring where the time goes. I'm not sure this counts as a bug, but the numbers might be useful.
I wrote a small Erlang module that does nothing except read the BNO085: soft reset, turn on the rotation vector at 100 Hz, then read each packet (a 4-byte header read, then the full packet) whenever INT goes low. Each loop it also reads two bytes from the VCNL4040, which never stretches the clock, as a baseline. A second process just runs timer:sleep(1) in a loop and records how late it wakes up. This is all on v0.7.0-beta.0 with ESP-IDF 5.5.5.
With the VM otherwise idle, a two-byte i2c:read_bytes/4 from the VCNL4040 takes about 1.1 ms on the release image. For comparison, a gpio:read/2 (a port:call to a port that doesn't touch any hardware) takes about 0.7 ms, and a plain message round trip to another process takes about 270 µs. I put some timers inside the port driver (debug build, so a bit slower than release) and the bus transfer itself, i2c_master_cmd_begin, averages about 0.57 ms across all transfers including the BNO085's, while the whole i2cdriver_consume_mailbox handler averages about 0.82 ms. So for a simple read, most of the cost is the round trip through the port rather than the bus.
With the IMU streaming at 100 Hz, each BNO085 read takes about 2.5–3 ms and the VCNL4040 read about 2.2 ms, and the sleep(1) process wakes up 0.7–1.8 ms late on average and occasionally 18–35 ms late, depending on the build (legacy driver with the timeout raised, or the new driver PR). Because the transfers run synchronously on the scheduler, nothing else gets to run while one is in flight. In the real firmware, with a handful of other processes going, it all piled up: a GenServer.call with no I/O took 8–20 ms and loops meant to run at 20 Hz ran at about 9 Hz.
I tried moving the legacy port driver's i2c_master_cmd_begin onto a FreeRTOS worker task and replying from an event listener on a queue in event_set. That stopped the scheduler blocking, but the replies then sat around until the scheduler's next event poll. On a busy VM an idle two-byte read went from about 1.7 ms to 19 ms, so it made things worse overall. I don't know the event loop well enough to tell whether there's a cheap way for a finished job to wake the scheduler straight away. Changing the build from -Og to -O2 shaved 10–25% off everything but didn't change the overall picture.
A few things I'm curious about. Is a ~270 µs message round trip normal on a single-core C6, or does that suggest something's off in how I'm building? Would a non-blocking I2C path be welcome, and if so, how should a completed transfer wake the scheduler? And for sensors like this, would you rather people batch into fewer, larger reads, or move the protocol into a native task and just expose the results?
Happy to share the test module, or to try things on the hardware.
- Lenguaje dominante
- Erlang
- Estrellas
- 2.3k
- Forks
- 171
- Merge medio
- 5 d 11 h
- PR fusionados (30 d)
- 19
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de atomvm/AtomVM
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
atomvm/AtomVM#2435 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
atomvm/AtomVM#2429 · 1 reacción ·
Los mantenedores suelen responder en 2 días
Todos los issues de atomvm/AtomVM
Issues similares
-
Crash in mdns componentAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 75/100
openvehicles/Open-Vehicle-Monitoring-System-3#1575 ·
Los mantenedores suelen responder en 4 días
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
betrusted-io/xous-core#1019 ·
-
Component:APU Status:New Type:Bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
openhwfoundation/cva6#3734 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
lowRISC/ibex-demo-system#157 ·
-
community:good-first-issue kind:bug kind:test scope:control status:needs-triage vehicle:rover
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
PX4/PX4-Autopilot#29727 ·
Los mantenedores suelen responder en 1 día