Pushing to volatile queue from timer (IRAM_ATTR) on ESP32

I have timer and want to sample analog pin and push the samples to queue. I know the variables I'm accessing in the timer function need to be volatile, but from googling it seems I can't turn std::queue into volatile thing by just labeling it as volatile.

Do I have options different from filling volatile array?

STL containers are not thread-safe for read-write operations.

you could explore thread aware packages like GitHub - oneapi-src/oneTBB: oneAPI Threading Building Blocks (oneTBB) or GitHub - CodeExMachina/BlockingCollection: C++11 thread safe, multi-producer, multi-consumer blocking queue, stack & priority queue class and see if you can extract something that works for you.

Alternatively implement your own queue using standard techniques like Arduino ESP32 FreeRTOS 4: How to use Binary Semaphore - Mutex - Counting semaphore - Critical section for resources management

Thanks, I'm aware they are not thread-safe, but want to experiment a little. I could do similar things in Java, but won't get exception or kernel panic. Yes, some data will be corrupt but in this case I'm OK with that, I'm toying around.

I'm not 100% sure if I get the panic because the variable was not declared volatile (that matters only during compilation, right?) or because of illegal memory access?

To phraze my question differently: If I use semaphores, locks, etc. + std::queue should I expect the code to run OK?

Even if you manage to put in critical section (disable interrupts) all the calls to the queue instance you have challenges related to the fact that you don't control the back end data and its volatile requirements. Theoretically the compiler might optimize things and keep pointers in registers that would not be modified through the ISR so controlling what's happening for the storage is challenging.

The queue might not be the best class to use on a small micro-controller. Implementing your own circular buffer for example with a fixed size (like the Serial buffer for example) to store the results of your analog reads might be more efficient (no dynamic allocation from within an interrupt context) and easier to keep under control.

Thanks, I'll buffer things and do the real processing outside the interrupt. Interrupts should be short anyway.

Seems to me the whole point of queues in an RTOS is to support inter-thread data transfer. Why wouldn't they be thread-safe? Additionally, the ESP32 port of FreeRtos has xQueueSendToBackFromISR(), which seems like exactly what @gdanov needs. Nothing needs to volatile for this to work.

Of course the FreeRtos queues work by making copies of the data to be enqueued. So they only work with plain old data and not fancier C++ constructs.

EDIT:
I'm assuming @gdanov wants to push data into the queue in the ISR and pull it out in non-ISR code.

1 Like

You are assuming correctly, this is one of the usecases I'm after.

FreeRTOS - Open Source Software for Embedded Systems - FreeRTOS xQueueSendFromISR() interrupt safe API function description

I assumed OP meant the Standard Template Library C++ fancy queue container ➜ std::queue - cppreference.com

An interesting read here Modern C++: Writing a thread-safe Queue – Code Trips & Tips

I Agree xQueueSendFromISR seems suitable for OP’s need indeed.

1 Like

Interesting and actually readable. Way easier than slogging my way through anything written on https://en.cppreference.com/.

Thanks everyone, I have working prototype with queue (espressif have ring buffer based one). The article is also very good for C++ beginner.
Additionally I realized that my timer ISR was labeled with the IRAM_ATTR by the arduino_esp32 library and this caused number of weird crashes.

I really doubt it. You will probably see more weird crashes without the attribute.

agreed !

I think You need the IRAM_ATTR and also keep the ISR very simple, to not block the code otherwise the WDT will trigger.

you may doubt, but this effectively tells the rtos to not disable my ISR when flash cache is disabled and when I initiate OTA I get guru meditation error because I'm using analogRead in the ISR. Registering my handler without the IRAM_ATTR removes this problem.

The doc is states:

Here are the cases when parts of application may or should be placed into IRAM.

  • Interrupt handlers must be placed into IRAM if ESP_INTR_FLAG_IRAM is used when registering the interrupt handler. In this case, ISR may only call functions placed into IRAM or functions present in ROM. Note 1: all FreeRTOS APIs are currently placed into IRAM, so are safe to call from interrupt handlers. If the ISR is placed into IRAM, all constant data used by the ISR and functions called from ISR (including, but not limited to, const char arrays), must be placed into DRAM using DRAM_ATTR.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.