Page 1 of 1
High Interrupt calling C function
Posted: Sun Dec 06, 2020 1:22 pm
by mendesgeo
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
Posted: Sun Dec 06, 2020 5:12 pm
by ESP_Dazz
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.
Note that there is technically nothing in the hardware that prevents the CPU from calling C code in a level 7 (i.e., high level) interrupt. It is purely a software restriction enforced due to the reasons listed above.
Re: High Interrupt calling C function
Posted: Mon Dec 07, 2020 1:55 am
by ESP_Sprite
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
Posted: Mon Dec 14, 2020 12:20 pm
by mendesgeo
ESP_Sprite wrote: ↑Mon Dec 07, 2020 1:55 am
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.
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???
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.
Re: High Interrupt calling C function
Posted: Mon Dec 14, 2020 1:10 pm
by ESP_Sprite
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
Posted: Mon Dec 14, 2020 1:27 pm
by mendesgeo
ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pm
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.
Thank you, so far I'm using as a reference the panic handler code and
call0 to
_xt_context_save and
_xt_context_restore.
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
Posted: Mon Dec 14, 2020 2:00 pm
by mendesgeo
ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pm
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.
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 ?
For example, does this interrupt happen each 0.625ms or 1.25ms?
Re: High Interrupt calling C function
Posted: Tue Jan 05, 2021 2:18 pm
by darthcloud
ESP_Sprite wrote: ↑Mon Dec 14, 2020 1:10 pm
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.
I'm interested by this also, did it make it to a public branch yet?