logo elektroda
logo elektroda
X
logo elektroda

[Solved] [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions

NIXIE_123 3162 56
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
  • #1 19448833
    NIXIE_123
    Level 34  
    Hi

    I have a couple of questions about esp32 and the RTOS that appears in it

    1)Is it true that when using interrupts (e.g. from a timer), the best practice is to make them only wake up the task that "does" all the work?
    Because the fact that ISRs are supposed to be the shortest is obvious, but are we even better programmers by flipping even a short instruction in a task?

    2)What is the best (lightest) way to wake up a task from an interrupt assuming we don't need to pass data? Here it is written that using a queue. I used it in my project and it does indeed work. I also tried vTaskSuspend(); and waking xTaskResumeFromISR(); but esp32 was doing a panic. Here it says it's normal because the function wasn't tested and runs some kind of watchdog. I know it can be turned off but that's probably not the point here.

    3)Does the fact that the system Tick is at 1ms mean that the task cannot execute more often than every 1ms?
    Why I ask - I have in the project an interrupt from gpio exactly every second which wakes up the task using queue(in the task an infinite loop which is blocked by xQueueReceive). And it works, I have no objections.
    I also have a timer interrupt triggered every 35µs. Its instructions are in the ISR everything works.
    When I move these instructions to the task in the ISR I just wake it up, the function slows down terribly I would say it executes every 1ms. The method of waking up is identical to the one in the task, which is every second. Again, it is possible to change the Tick system but I don't want to do that

    4)After switching from avr am I wandering around and unnecessarily using interrupts for the timer. Maybe there is another simpler way to wake up tasks with timer
  • ADVERTISEMENT
  • Helpful post
    #2 19448979
    khoam
    Level 42  
    NIXIE_123 wrote:
    Is it true that, when using interrupts (e.g. from a timer), the best practice is to make them only wake up the task that "does" all the work?
    Because the fact that ISRs have to be the shortest is obvious, but are we even better programmers by flipping even a short instruction in a task?
    .
    This is such an unholy tradition among those who program with ESP-IDF ;) It all depends on how critical shuffles are to be implemented in the ISR - if very and short, it is better to stay with just interrupts.

    NIXIE_123 wrote:
    What is the best (lightest) way to wake up a task from an interrupt assuming we don't need to pass data? Here it says using a queue.
    .
    This is what you should stick to.

    NIXIE_123 wrote:
    Does the fact that the system Tick is at 1ms mean that a task cannot execute more often than every 1ms?
    .
    If the timeout resolution is 1ms, then the scheduler cannot automatically call (and actually queue) tasks more frequently, but ... you can force a task to execute if some conditions are met, e.g. in case of conversion from ISR or in the task itself to force its earlier, next iteration.

    NIXIE_123 wrote:
    I also have a timer interrupt triggered every 35µs. Its instructions are in the ISR everything works.
    .
    If these are interrupts from esp_timer, then by default the ISRs are already "converted" to shuffles, and there is basically one "esp_timer" task that controls the ISR calls from esp_timer. The priority of this task is equal to ESP_TASK_PRIO_MAX - 3, which is quite high. You would have to enable CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD in sdkconfig to make it ISR-only - by default this option is disabled. Unfortunately this option is only available in version 4.3 of ESP-IDF, which is not yet marked as "stable" for the time being.

    NIXIE_123 wrote:
    After switching from avr am I wandering around and unnecessarily using interrupts for the timer.
    .
    Since you switched from AVR, you are no longer erring :) .

    NIXIE_123 wrote:
    When I move these instructions to the task and in the ISR I just wake it up the function slows down terribly by eye I would say it executes every 1ms.
    .
    You simply switch between tasks, one of which is "esp_timer".
  • ADVERTISEMENT
  • #3 19449929
    NIXIE_123
    Level 34  
    khoam wrote:
    If these are interrupts from esp_timer
    .
    Yes, they are triggered by the timer.

    khoam wrote:
    task "esp_timer" which controls the ISR calls from esp_timer
    .
    I understand that the interrupt forces the "esp_timer" task to execute itself which is why it runs more than 1ms, and when I created a separate task and only woke it up with the timer it had to wait for each subsequent tick of the system i.e. 1ms

    khoam wrote:
    It all depends on how critical shuffles are to be implemented in the ISR - if very much and they are short, it is better to stay with just interrupts.
    .

    The mentioned function running every 35µs multiplexes the display in the nixie watch. It has to be so often because it supports 6 lamps, a crossfade effect and 1/6 pwm dimming. I didn't want it to, for example, hinder the processor from handling the wi-fi connection I want to add in a while. It's not super critical somehow but it has to execute frequently otherwise you can see the multiplexing.
    Since
    khoam wrote:
    interrupts from esp_timer, then by default ISRs are already "converted" to shuffles
    .
    then it probably won't be a tragedy.
  • #4 19449941
    khoam
    Level 42  
    NIXIE_123 wrote:
    I understand that the interrupt forces the "esp_timer" task to execute, which is why it runs more than 1ms
    .
    Exactly.

    NIXIE_123 wrote:
    The mentioned function running every 35µs multiplexes the display in the nixie watch.
    .
    This is where I have to worry you a bit. The documentation for IDF version 4.2 talks about a minimum time of 50µs:
    Quote:
    Periodic esp_timer also imposes a 50µs restriction on the minimum timer period. Periodic software timers with period of less than 50µs are not practical since they would consume most of the CPU time. Consider using dedicated hardware peripherals or DMA features if you find that a timer with small period is required.
    .
  • #5 19545151
    NIXIE_123
    Level 34  
    I have this problem:

    An interrupt from the timer every 111µs interferes with the wifi connection. A panic is created. I just uncomment the initialization of the timer and all the code works. The other way when I throw away the wifi connection and leave the timer also everything works.
    I tried first with a simple example_connect(); and now with a full-fledged station mode. Always the same effect.

    The timer works nicely only the addition of wifi remains
  • #6 19545217
    khoam
    Level 42  
    As I wrote earlier interrupts from esp_timer are "converted" to high priority RTOS threads. This is a higher priority (22) than for WiFi handling functions.
    Question one: how long does it take to handle a single esp_timer thread?
    Question two: does the problem only occur at WiFi initiation (STA or AP) or also during WiFi operation?
    By default, esp_timer and WiFi handling are executed on the same Core 0 (PRO_CPU), so they "fight" for resources and esp_timer always wins.
  • #7 19545251
    NIXIE_123
    Level 34  
    khoam wrote:
    how long does it take to operate a single esp_timer thread?
    .
    How to check this? The interrupt is a bit of variable and port setting.

    khoam wrote:
    does the problem only occur at WiFi initiation (STA or AP) or also during WiFi operation?
    .
    So far I have not started the watch with wifi so on initiation. I would like there to be no conflict even at initiation because the clock will sync every half hour and it won't always have access to the wifi network. I don't want workarounds like turning off the display for sync time etc.
    khoam wrote:
    By default esp_timer and WiFi support are executed on the same Core 0 (PRO_CPU), so they "fight" for resources and esp_timer always wins.
    .
    Well, that's right, after all this hardware has two cores. Can it be split into two? That was probably the designers' intention. One core for the program and the other for wifi and bluetooth
  • #8 19545433
    khoam
    Level 42  
    NIXIE_123 wrote:
    How to check this? Interrupt is a bit of variables and port setting.
    .
    Using the esp_timer_get_time() function.

    NIXIE_123 wrote:
    Well, after all this hardware has two cores. Can it be split into two? This was probably the designers' intention. One core for the program and the other for wifi and bluetooth
    .
    If some functional part of the program should be executed on a specific Core, it should be in the task handler, which is pinned to a specific Core - xTaskCreatePinnedToCore().

    To start with, however, I would suggest measuring the execution time of a single callback function assigned to an interrupt with esp_timer.
  • #9 19546113
    NIXIE_123
    Level 34  
    Code: C / C++
    Log in, to see the code
    .

    every 200ms ESP_LOG with time value

    Stands at 5µs. Occasionally peaks to 8 top 10
  • #10 19546151
    khoam
    Level 42  
    Is the interrupt_from_timer() function an ISR callback for esp_timer, or for timer_group? It looks like the latter.
  • #11 19546162
    NIXIE_123
    Level 34  
    Code: C / C++
    Log in, to see the code
    .
  • ADVERTISEMENT
  • #12 19546332
    khoam
    Level 42  
    NIXIE_123 wrote:
    Interruption from timer every 111µs interferes with wifi connection. A panic is created.
    .
    Could you please post this message in full? But already after the exception decoder.
  • #13 19546428
    NIXIE_123
    Level 34  
    Exception decoder I found only for arduino. I downloaded arduino IDE but when I paste the code it sees the library from wifi but still there are errors from wifi and it doesn't compile. I guess there is no point in doing the code under arduino because there will be another exception or it will work.
    [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions .
  • #14 19546435
    khoam
    Level 42  
    NIXIE_123 wrote:
    Exception decoder I found only for arduino.

    Which IDE are you using? For PlatformIO there is also
  • #16 19546466
    khoam
    Level 42  
    There is a PlatformIO plugin for eclipse, and this is probably the only way you will have access to the Exception Decoder: Link .
    Without this tool, it's really hard to catch the causes of program crashes. Alternatively, if you have one, you can use the ESP-PROG debugger, but that will be more difficult.

    Added 5 [hours] 20 [minutes]:

    Actually with the timer on, it crashes, but much earlier, with nvs_flash_init():
    Code: Bash
    Log in, to see the code
    .
    As I increased the alarm_value in timer_set_alarm_value() to 10ms, it works fine (I had previously increased CONFIG_FREERTOS_HZ to 1000 in sdkconfig). Something is wrong in the configuration of the timer itself, but today I don't have the strength to go into it further.

    NIXIE_123 wrote:
    Stops at 5µs. Sometimes spades to 8 top 10
    .
    And I don't believe this after reviewing the code of the interrupt_from_timer_mux() and set_catode() functions. Sorry :) .

    Added after 45 [minutes]:

    Yes, as I sensed there was an error in the timer configuration. With this configuration:
    Code: C / C++
    Log in, to see the code
    and
    Code: C / C++
    Log in, to see the code
    WiFi works correctly. At least with me ;) .
    You also have a bug in your program: the set_catode() function also needs to be IRAM_ATTR.
  • #17 19547626
    NIXIE_123
    Level 34  
    Thank you for leaning into my case.
    khoam wrote:
    With this configuration It works WiFi correctly
    .
    Quote:
    .divider = 10000


    Unfortunately with a divider of 10,000 the interrupt will be triggered every 13.875ms rather than 111µs

    80MHz/10 000 = 8kHz
    1/8kHz = 125µs
    125µs * 111 = 13.875ms

    And I need

    80MHz/80 = 1MHz
    1/1MHz = 1µs
    1µs * 111 = 111µs
  • #18 19547733
    khoam
    Level 42  
    I performed a simple test. I used the simplest possible callback function for the timer:
    Code: C / C++
    Log in, to see the code
    With divider=80 and timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 111) the program works fine.
    So the problem is the interrupt_from_timer_mux() function itself - its execution time and the occupancy on the stack for the ISR, which is limited to 1536 bytes by default (CONFIG_FREERTOS_ISR_STACKSIZE).

    NIXIE_123 wrote:
    Stops at 5µs. Sometimes spades to 8 top 10
    .
    At least five times longer executes, but I leave that to you for further analysis. If this callback is actually supposed to execute every 111µs, then its execution time should not exceed 10µs - so as to give the opportunity for other processes to do any work, including TWDT.
  • #19 19550055
    NIXIE_123
    Level 34  
    I repeated your test at my place and unfortunately it doesn't work at my place. Even after increasing CONFIG_FREERTOS_HZ to 1000

    However, the whole clock works when I use
    timer_isr_register(TIMER_GROUP_0, TIMER_0, przerwanie_od_timer, NULL, 0, NULL);
    .
    And it works even when I go down from 111µs to 35µs.

    Link .
    ESP_Sprite wrote:
    The thing is flash (write) accesses.
    An interrupt marked as in IRAM will keep functioning when a flash write happens (which in this case is what happens when you initialize NVS), a non-IRAM interrupt will be disabled for as long as the flash write takes.
    However, you must guarantee that the interrupt handler plus all data it accesses are in internal memory for you to be able to mark it as in IRAM, otherwise you'll get crashes like this.
    .
  • #20 19550140
    khoam
    Level 42  
    NIXIE_123 wrote:
    It works even when I go from 111µs down to 35µs.
    .
    But in this case without the ESP_INTR_FLAG_IRAM flag, so these interrupts will be blocked on every write to flash (WiFi functions use this too). What is then the realistic interval of these interrupts?

    Anyway, colleague ESP_Sprite also mentioned this ;) .
    Quote:
    As far as it's a workaround: it depends. If it's acceptable for the interrupt not to fire during flash writes , you're okay, if not you'll need to hunt for the bits that are not in IRAM.
    .
  • #21 19550160
    NIXIE_123
    Level 34  
    Well yes, it is a workaround but it gives an interrupt which does nothing and there is still a conflict then what am I left with?
  • Helpful post
    #22 19550193
    khoam
    Level 42  
    Reduce the execution time of the set_catode() and interrupt_from_timer_mux() functions, i.e. instead of the "free" gpio_set_level() function, directly manipulate the GPIO W1TS registers once GPIO W1TC or (even faster) use the RMT controller (RMT channels can be mapped to any pins).
  • ADVERTISEMENT
  • #23 19550199
    NIXIE_123
    Level 34  
    But I have removed this function completely. The interruption does exactly nothing. Nevertheless, there is a conflict
    Code: C / C++
    Log in, to see the code
  • #24 19550214
    khoam
    Level 42  
    I don't understand this. With me with this simple callback function it works (I just checked). The fact that I am using ESP-IDF version 4.3. I also changed the order of execution of timer_isr_register() from timer_enable_intr():
    Code: C / C++
    Log in, to see the code
    .
    In contrast, it takes 7µs to execute the interrupt_from_timer_test() function.
  • #25 19550222
    NIXIE_123
    Level 34  
    And which chip do you have?
    I esp32 rev. 1
    wroom-32
  • #26 19550228
    khoam
    Level 42  
    Also WROOM-32

    Code: Bash
    Log in, to see the code
    .
  • #27 19550365
    mpier
    Level 29  
    Hello,
    I might hit you with a question: do "timer_spinlock_take()" and the rest have IRAM_ATTR to work without flash access? This is where I would look, maybe it can be done differently.

    Greetings.
  • #28 19550445
    NIXIE_123
    Level 34  
    Very good point. After upgrading to esp-idf v4.3 this function is not found at all. In read the docs it says that this function is deprecated and use a better one. I am currently trying to come to terms after the upgrade.
  • #29 19550573
    khoam
    Level 42  
    NIXIE_123 wrote:
    In read the docs it is written that this function is deprecated and use a better one.
    .
    But not in the latest stable version 4.3, but in higher (master) versions.
    The functions timer_spinlock_take() and timer_spinlock_give() are IRAM_ATTR:
    Code: C / C++
    Log in, to see the code
    Responsible for entering and exiting to/from the critical section where other interrupts and threads are blocked.

    In my opinion it is better to use timer_isr_callback_add () instead of timer_isr_register(). Then in your own ISR callback you no longer need to create a critical section.
    Code: C / C++
    Log in, to see the code
    Callback from the interrupt will be called automatically in the critical section.
  • #30 19550615
    NIXIE_123
    Level 34  
    NIXIE_123 wrote:
    I repeated your test with me and unfortunately it does not work with me.
    .
    After upgrading to v4.3 it already works (empty interrupt)
    Now I have these circuses for a change:
    [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions .
    [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions .
    [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions .

    Everything compiles 0 errors 0 warnings and it does not see the BUTTON_DOWN defined. Pressing ctrl and left button on an item not found flips me to it as if it sees it. The program loads and the clock now acts as a paper button....
    My hands are falling off.
    I have already done a fullclean and a build but to no avail
    [RTOS][esp-idf] ESP32 interrupts and shuffles some basic questions .

Topic summary

The discussion revolves around the use of interrupts in the ESP32 with the ESP-IDF RTOS. Key points include best practices for handling interrupts, such as using them to wake tasks rather than performing extensive operations within ISRs. The participants explore methods for waking tasks from interrupts, with queues being a recommended approach. Concerns about the system tick rate limiting task execution frequency to 1ms are addressed, along with issues related to WiFi interference when using timer interrupts. The conversation also touches on the importance of managing execution time within ISRs to avoid conflicts with other processes, particularly WiFi operations. Solutions include using direct GPIO manipulation for efficiency and the potential of using the RMT module to reduce CPU load. The discussion concludes with successful implementations of timer interrupts and HTTP server setups for configuration via a web interface.
Summary generated by the language model.
ADVERTISEMENT