This wasn’t the planned next step in this project, but I noticed that performance isn’t as good as I would like it to be. It seems that, in the end, everything will have to be rewritten in C. MicroPython is just a toy and the fastest solution for some hobby projects.

The first issue I noticed was a 1ms delay between the moment the MPU generates an interrupt and when the ESP starts processing the data. No matter what I did, I couldn’t reduce it below 1ms.

In the end, the ESP32 platform for MicroPython runs on the FreeRTOS task system. The MicroPython interpreter operates as a single FreeRTOS task. A software task scheduler is used to allocate CPU time to different processes in the MicroPython environment.
Interrupts (ISR) work at a low level. FreeRTOS provides a preemptive multitasking environment, but MicroPython does not utilize multiple tasks. Everything runs within a single task using cooperative scheduling through an event loop.

I tried various approaches, from using micropython.schedule() (which supposedly has priority) to introducing a 1µs sleep in the main loop. I moved all dynamically allocated variables to statically defined arrays, disabled Garbage Collection, but since it can’t be avoided completely, I manually invoke it at what I consider an optimal moment.

In the end, this is the result, and I am not particularly proud of it. If anyone has an idea, feel free to contact me—I would be grateful.

pygame_raw_data

  1. Interrupt in from the MPU. The interrupt occurs every 4ms, stability was achieved by setting the CONFIG register to 0x01, which ensures that the gyro and accelerometer sample rates are both 1kHz, and enabling DLPF at 184Hz.
  2. The 1ms delay that remains no matter what I do.
  3. Interrupt processing including micropython.schedule() (~150µs).
  4. Time lost in the main loop (~100µs).
  5. Packing sensor register data into packet_buffer, which is then sent to REPL (~270µs).
  6. Transmission time (~200µs).
  7. Garbage collection (~350µs).