I know, this is a long question but you would really help me out with it. After 3 days of trial and error and research, I'm out of ideas. Maybe you'll find something obvious I've missed or you just know better than I do.
The project
I'm currently building a small car that utilizes the following stuff:
- DShot600 ESC (transmission is done over the RMT peripheral)
- DShot Telemetry (basic UART on Serial2), most importantly: I need wheel RPM
- WebSockets for control via an app
- Timer interrupt to trigger the function that sends data every 1ms
- logging of the acquired data every 1ms
- MPU6050 for acceleration measurements (every 1ms).
Yeah, no steering, it just has to go straight - but it has to do that quickly. "Car" is a bit of an overstatement
What works
I've got all of it working reliably except the MPU part. I use Jeff Rowberg's I2CDevLib for the fetching (I just need the x-axis acceleration and just the raw value, no fancy DMP stuff and no gyro functionality).
What doesn't
The problem is that whenever I try to fetch any data from the MPU, I get an [...]esp-idf/components/freertos/queue.c:1446 (xQueueGenericReceive)- assert failed!
error. I have no idea what this is and how to fix it.
CPU core assignments
I have all the time-sensitive stuff (telemetry processing, MPU processing and throttle calculation) on the core 1 loop, whereas the less time-sensitive stuff (WebSockets, Serial communication to the PC) is done on core 0.
- core 0
- loop
- WebSocket
- Serial communication with the PC
- interrupts
- every 1ms: sending the ESC value via RMT
- loop
- core 1
- loop
- MPU data fetching (every 1ms according to the
millis()
function) - getting the telemetry data
- throttle calculation
- MPU data fetching (every 1ms according to the
- loop
For clarification: the timer interrupt and therefore throttle sending is done on core 0. I did that so that the timer interrupt does not interfere with the MPU data fetching (which takes around 300µs).
What I tried
Handling it on core 1 doesn't fix it.
I've read that there is a portENTER_CRITICAL
and portEXIT_CRITICAL
function pair that temporarily disables interrupts. Wrapping the MPU data fetching with this fixes the issue but introduces a delay of 50ms at the exit function. These 50ms make the ESC go into failsafe (i.e. turn off).
Manually fetching the MPU data within the interrupt function does not help. This gives me Guru Meditation error
s. Setting a flag within the interrupt service routine and fetching it in the main loop also gives errors.
When I disable the ESC interrupt, this error does not occur, even though this interrupt is handled on the other core.
Other info
For the ESC transmission function I need to use a timer because the ESC throttle value has to be transmitted exactly every 1ms with a difference of at most 50µs. The issue would be that the telemetry (which the ESC sends back as soon as I sent the full throttle packet) needs >800µs (which is received asynchronously by the UART peripheral). Another function then has to process the telemetry wheel speed and adjust the new throttle value to that before that value is sent. That all works. I just wanted to mention it so no one recommends me to put that function in the main loop.
I'd be happy to provide more debug information, I just don't know what could be useful. I've tried a few things more than I explained here (which would lead to a much longer question). Generally fetching the data in a separate project (just the MPU) works flawlessly. So there are no broken cables, there's no dead processor or anything like that.
Thanks in advance.
Software: PlatformIO w/ Arduino core, Windows 10 and Manjaro Linux (same errors)
Hardware: Ryzen 1700, 16GB RAM, Radeon Vega 56, ESP32 WROOM