High Interrupt calling C function

mendesgeo
Posts: 7
Joined: Sun Dec 06, 2020 12:31 pm

High Interrupt calling C function

Postby mendesgeo » Sun Dec 06, 2020 1:22 pm

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?

ESP_Dazz
Posts: 308
Joined: Fri Jun 02, 2017 6:50 am

Re: High Interrupt calling C function

Postby ESP_Dazz » Sun Dec 06, 2020 5:12 pm

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.

ESP_Sprite
Posts: 9761
Joined: Thu Nov 26, 2015 4:08 am

Re: High Interrupt calling C function

Postby ESP_Sprite » 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.

mendesgeo
Posts: 7
Joined: Sun Dec 06, 2020 12:31 pm

Re: High Interrupt calling C function

Postby mendesgeo » Mon Dec 14, 2020 12:20 pm

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.

ESP_Sprite
Posts: 9761
Joined: Thu Nov 26, 2015 4:08 am

Re: High Interrupt calling C function

Postby ESP_Sprite » 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.

mendesgeo
Posts: 7
Joined: Sun Dec 06, 2020 12:31 pm

Re: High Interrupt calling C function

Postby mendesgeo » Mon Dec 14, 2020 1:27 pm

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?

  1. #include <xtensa/coreasm.h>
  2. #include <xtensa/corebits.h>
  3. #include <xtensa/config/system.h>
  4. #include <freertos/xtensa_context.h>
  5. #include <freertos/xtensa_rtos.h>
  6. #include <esp_private/panic_reason.h>
  7. #include <soc/soc.h>
  8. #include "sdkconfig.h"
  9.  
  10.     .section .iram1,"ax"
  11.     .global     xt_debugexception
  12.     .type       xt_debugexception,@function
  13.     .align      4
  14. xt_debugexception:
  15.     /* Set up PS for C, enable debug and NMI interrupts and clear EXCM. */
  16.     movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
  17.     wsr     a0, PS
  18.     /* Start saving context */
  19.     mov     a0, sp
  20.     addi    sp, sp, -XT_STK_FRMSZ
  21.     s32i    a0, sp, XT_STK_A1
  22.     #if XCHAL_HAVE_WINDOWED
  23.     s32e    a0, sp, -12                     /* for debug backtrace */
  24.     #endif
  25.     rsr     a0, PS                          /* save interruptee's PS */
  26.    s32i    a0, sp, XT_STK_PS
  27.    rsr     a0, EPC_6                       /* save interruptee's PC */
  28.     s32i    a0, sp, XT_STK_PC
  29.     #if XCHAL_HAVE_WINDOWED
  30.     s32e    a0, sp, -16                     /* for debug backtrace */
  31.     #endif
  32.     s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires a12,a13 */
  33.     s32i    a13, sp, XT_STK_A13            
  34.     call0   _xt_context_save                /* Save xtensa context */
  35.     rsr     a0, EXCSAVE_6                  
  36.     s32i    a0, sp, XT_STK_A0               /* save interruptee's a0 */
  37.  
  38.    // User function here (must use call4)
  39.     mov     a6,sp
  40.     call4   user_handler          
  41.    // User function end
  42.  
  43.     call0   _xt_context_restore             /* Restore xtensa context */
  44.  
  45.    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
  46.     wsr     a0, PS
  47.     l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
  48.    wsr     a0, EPC_6
  49.    l32i    sp, sp, XT_STK_A1               /* remove exception frame */              
  50.    rsync                                   /* ensure PS and EPC written */
  51.  
  52.    rsr     a0, EXCSAVE_6                   /* restore a0 */
  53.    rfi     6

mendesgeo
Posts: 7
Joined: Sun Dec 06, 2020 12:31 pm

Re: High Interrupt calling C function

Postby mendesgeo » Mon Dec 14, 2020 2:00 pm

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?

User avatar
darthcloud
Posts: 5
Joined: Mon Aug 19, 2019 3:33 pm

Re: High Interrupt calling C function

Postby darthcloud » Tue Jan 05, 2021 2:18 pm

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?

Who is online

Users browsing this forum: No registered users and 94 guests