High Interrupt calling C function
High Interrupt calling C function
Dear all, I've seen on the oficial Espressif Documentation and also some comments around that High interrupt is not usually used or cannot be used with C functions. Is there a reason why? Is it because of the DPORT workaround which sometimes causes the cores to hang?
Re: High Interrupt calling C function
Two main reasons:
- Interrupt Latency
Calling a C function from an interrupt requires the CPU's context to be saved, and the call stack to be switch to that of the C ISR. This process is generally time consuming (currently clocks in at approximately a few microseconds on the ESP32) and is not suited for High Level interrupts since they're meant to have low latency.
By making high level interrupts assembly only, the entire context saving and stack switching routine is skipped making high level interrupt latency much lower (in theory, the CPU be able to should jump to the high level interrupt in a couple of CPU clock cycles). However, in order to ensure that the CPU is left in the same state before and after the interrupt, users are responsible for saving and restoring whichever CPU registers their assembly routine uses. - Critical Sections
If an ISR can run C code, then it can share access to C variables with other threads and ISRs. This means that the higher the level of interrupt that C code is allowed to run, the higher the level of interrupt that must be disabled during a critical section.
-
- Posts: 9761
- Joined: Thu Nov 26, 2015 4:08 am
Re: High Interrupt calling C function
Actually, that's not entirely true. The crux of the issue is that a high-level interrupt can pre-empt a windowing exception, meaning the register stack can be in an unknown state. C code assumes it can happily use the windowed ABI and would corrupt it.
Re: High Interrupt calling C function
Oh My God!!! Thank you so much for this answer. I managed to create a High Level handler that saves context and switches to C code which modifies registers of the callee. And "sometimes" I'll get crashes as if the registers I'm accessing are pointing to invalid memory (which is not true if only looking at the assembly code). Do you know if it's possible to avoid interrupting windowed exceptions or at least detect when this is happening on the calee (interrupted function) so I can handler it later???ESP_Sprite wrote: ↑Mon Dec 07, 2020 1:55 amActually, that's not entirely true. The crux of the issue is that a high-level interrupt can pre-empt a windowing exception, meaning the register stack can be in an unknown state. C code assumes it can happily use the windowed ABI and would corrupt it.
Thank you in advance. It's actually not difficult to save context given that ESP-IDF already has a function to do that, I simply need to call them in assembly, but these random crashes were really difficult to understand.
-
- Posts: 9761
- Joined: Thu Nov 26, 2015 4:08 am
Re: High Interrupt calling C function
We actually have something in progress for BT interrupts internally. Should make it to the master branch shortly. From what I can see, it just saves all 64 registers plus WINDOWBASE and WINDOWSTART and switches to a new stack. Whatever state the registers are in will be saved that way.
Re: High Interrupt calling C function
Thank you, so far I'm using as a reference the panic handler code and call0 to _xt_context_save and _xt_context_restore.ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pmWe actually have something in progress for BT interrupts internally. Should make it to the master branch shortly. From what I can see, it just saves all 64 registers plus WINDOWBASE and WINDOWSTART and switches to a new stack. Whatever state the registers are in will be saved that way.
https://github.com/espressif/esp-idf/bl ... S#L90-L105
My full handler is shown below. In summary, I'm able to execute C code from the debug handler (I set breakpoints during runtime and disable them on the user_handler so I can modify registers during runtime and return to calee. The code works, but random crashes are hard to debug especially because I cannot debug this using JTAG as my exception handler is overwritten.
Could you point to this specific commit of the update you mention, or is it not on github develop branch yet?
- #include <xtensa/coreasm.h>
- #include <xtensa/corebits.h>
- #include <xtensa/config/system.h>
- #include <freertos/xtensa_context.h>
- #include <freertos/xtensa_rtos.h>
- #include <esp_private/panic_reason.h>
- #include <soc/soc.h>
- #include "sdkconfig.h"
- .section .iram1,"ax"
- .global xt_debugexception
- .type xt_debugexception,@function
- .align 4
- xt_debugexception:
- /* Set up PS for C, enable debug and NMI interrupts and clear EXCM. */
- movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
- wsr a0, PS
- /* Start saving context */
- mov a0, sp
- addi sp, sp, -XT_STK_FRMSZ
- s32i a0, sp, XT_STK_A1
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -12 /* for debug backtrace */
- #endif
- rsr a0, PS /* save interruptee's PS */
- s32i a0, sp, XT_STK_PS
- rsr a0, EPC_6 /* save interruptee's PC */
- s32i a0, sp, XT_STK_PC
- #if XCHAL_HAVE_WINDOWED
- s32e a0, sp, -16 /* for debug backtrace */
- #endif
- s32i a12, sp, XT_STK_A12 /* _xt_context_save requires a12,a13 */
- s32i a13, sp, XT_STK_A13
- call0 _xt_context_save /* Save xtensa context */
- rsr a0, EXCSAVE_6
- s32i a0, sp, XT_STK_A0 /* save interruptee's a0 */
- // User function here (must use call4)
- mov a6,sp
- call4 user_handler
- // User function end
- call0 _xt_context_restore /* Restore xtensa context */
- l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */
- wsr a0, PS
- l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */
- wsr a0, EPC_6
- l32i sp, sp, XT_STK_A1 /* remove exception frame */
- rsync /* ensure PS and EPC written */
- rsr a0, EXCSAVE_6 /* restore a0 */
- rfi 6
Re: High Interrupt calling C function
By the way, I'm actually also using BT. Is there some timing I need to be careful to not hang BT interrupt on _xt_low1 ?ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pmWe actually have something in progress for BT interrupts internally. Should make it to the master branch shortly. From what I can see, it just saves all 64 registers plus WINDOWBASE and WINDOWSTART and switches to a new stack. Whatever state the registers are in will be saved that way.
For example, does this interrupt happen each 0.625ms or 1.25ms?
- darthcloud
- Posts: 5
- Joined: Mon Aug 19, 2019 3:33 pm
Re: High Interrupt calling C function
I'm interested by this also, did it make it to a public branch yet?ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pmWe actually have something in progress for BT interrupts internally. Should make it to the master branch shortly. From what I can see, it just saves all 64 registers plus WINDOWBASE and WINDOWSTART and switches to a new stack. Whatever state the registers are in will be saved that way.
Who is online
Users browsing this forum: sage1234 and 99 guests