diff --git a/components/esp32/component.mk b/components/esp32/component.mk index aef14ab3c..666384e73 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -25,12 +25,16 @@ ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH LINKER_SCRIPTS += esp32.rom.spiflash.ld endif +#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the +#linker will ignore panic_highint_hdl.S as it has no other files depending on any +#symbols in it. COMPONENT_ADD_LDFLAGS := -lesp32 \ $(COMPONENT_PATH)/libhal.a \ -L$(COMPONENT_PATH)/lib \ $(addprefix -l,$(LIBS)) \ -L $(COMPONENT_PATH)/ld \ -T esp32_out.ld \ + -u ld_include_panic_highint_hdl \ $(addprefix -T ,$(LINKER_SCRIPTS)) ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) diff --git a/components/esp32/dport_panic_highint_hdl.S b/components/esp32/dport_panic_highint_hdl.S new file mode 100644 index 000000000..e921e258f --- /dev/null +++ b/components/esp32/dport_panic_highint_hdl.S @@ -0,0 +1,200 @@ +// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include +#include +#include +#include +#include "freertos/xtensa_context.h" +#include "esp_panic.h" +#include "sdkconfig.h" +#include "soc/soc.h" +#include "soc/dport_reg.h" + +/* + +Interrupt , a high-priority interrupt, is used for several things: +- Dport access mediation +- Cache error panic handler +- Interrupt watchdog panic handler + +*/ + +#define L4_INTR_STACK_SIZE 8 +#define L4_INTR_A2_OFFSET 0 +#define L4_INTR_A3_OFFSET 4 + .data +_l4_intr_stack: + .space L4_INTR_STACK_SIZE + + .section .iram1,"ax" + .global xt_highint4 + .type xt_highint4,@function + .align 4 +xt_highint4: + + /* See if we're here for the dport access interrupt */ + rsr a0, INTERRUPT + extui a0, a0, ETS_DPORT_INUM, 1 + bnez a0, .handle_dport_access_int + + /* Allocate exception frame and save minimal 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_4 /* 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- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + + /* Save vaddr into exception frame */ + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + /* Figure out reason, save into EXCCAUSE reg */ + + rsr a0, INTERRUPT + extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */ + beqz a0, 1f + /* Kill this interrupt; we cannot reset it. */ + rsr a0, INTENABLE + movi a4, ~(1< +#include +#include "rom/ets_sys.h" +#include "unity.h" +#include "soc/dport_reg.h" +#include "soc/io_mux_reg.h" +#include "esp_intr_alloc.h" +#include "freertos/FreeRTOS.h" + + + +TEST_CASE("Int wdt test", "[esp32][ignore]") +{ + portENTER_CRITICAL_NESTED(); + while(1); +} diff --git a/components/freertos/xtensa_vector_defaults.S b/components/freertos/xtensa_vector_defaults.S new file mode 100644 index 000000000..c800a09ed --- /dev/null +++ b/components/freertos/xtensa_vector_defaults.S @@ -0,0 +1,158 @@ +// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "xtensa_rtos.h" +#include "esp_panic.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +/* +This file contains the default handlers for the high interrupt levels as well as some specialized exceptions. +The default behaviour is to just exit the interrupt or call the panic handler on the exceptions +*/ + + +#if XCHAL_HAVE_DEBUG + .global xt_debugexception + .weak xt_debugexception + .set xt_debugexception, _xt_debugexception + .section .iram1,"ax" + .type _xt_debugexception,@function + .align 4 + +_xt_debugexception: + movi a0,PANIC_RSN_DEBUGEXCEPTION + wsr a0,EXCCAUSE + call0 _xt_panic /* does not return */ + rsr a0, EXCSAVE+XCHAL_DEBUGLEVEL + rfi XCHAL_DEBUGLEVEL + +#endif /* Debug exception */ + + +#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 + .global xt_highint2 + .weak xt_highint2 + .set xt_highint2, _xt_highint2 + .section .iram1,"ax" + .type _xt_highint2,@function + .align 4 +_xt_highint2: + + /* Default handler does nothing; just returns */ + .align 4 +.L_xt_highint2_exit: + rsr a0, EXCSAVE_2 /* restore a0 */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 + + .global xt_highint3 + .weak xt_highint3 + .set xt_highint3, _xt_highint3 + .section .iram1,"ax" + .type _xt_highint3,@function + .align 4 +_xt_highint3: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint3_exit: + rsr a0, EXCSAVE_3 /* restore a0 */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 + + .global xt_highint4 + .weak xt_highint4 + .set xt_highint4, _xt_highint4 + .section .iram1,"ax" + .type _xt_highint4,@function + .align 4 +_xt_highint4: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint4_exit: + rsr a0, EXCSAVE_4 /* restore a0 */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 + + .global xt_highint5 + .weak xt_highint5 + .set xt_highint5, _xt_highint5 + .section .iram1,"ax" + .type _xt_highint5,@function + .align 4 +_xt_highint5: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 /* restore a0 */ + rfi 5 + + +#endif /* Level 5 */ + +#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 + + .global _xt_highint6 + .global xt_highint6 + .weak xt_highint6 + .set xt_highint6, _xt_highint6 + .section .iram1,"ax" + .type _xt_highint6,@function + .align 4 +_xt_highint6: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint6_exit: + rsr a0, EXCSAVE_6 /* restore a0 */ + rfi 6 + +#endif /* Level 6 */ + +#if XCHAL_HAVE_NMI + + .global _xt_nmi + .global xt_nmi + .weak xt_nmi + .set xt_nmi, _xt_nmi + .section .iram1,"ax" + .type _xt_nmi,@function + .align 4 +_xt_nmi: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_nmi_exit: + rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ + rfi XCHAL_NMILEVEL + +#endif /* NMI */ + diff --git a/components/freertos/xtensa_vectors.S b/components/freertos/xtensa_vectors.S index e88957e38..2846a65d1 100644 --- a/components/freertos/xtensa_vectors.S +++ b/components/freertos/xtensa_vectors.S @@ -471,28 +471,10 @@ Debug Exception. .section .DebugExceptionVector.text, "ax" .global _DebugExceptionVector .align 4 - + .global xt_debugexception _DebugExceptionVector: - - #ifdef XT_SIMULATOR - /* - In the simulator, let the debugger (if any) handle the debug exception, - or simply stop the simulation: - */ - wsr a2, EXCSAVE+XCHAL_DEBUGLEVEL /* save a2 where sim expects it */ - movi a2, SYS_gdb_enter_sktloop - simcall /* have ISS handle debug exc. */ - #elif 0 /* change condition to 1 to use the HAL minimal debug handler */ - wsr a3, EXCSAVE+XCHAL_DEBUGLEVEL - movi a3, xthal_debugexc_defhndlr_nw /* use default debug handler */ - jx a3 - #else - wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* save original a0 somewhere */ - movi a0,PANIC_RSN_DEBUGEXCEPTION - wsr a0,EXCCAUSE - call0 _xt_panic /* does not return */ - rfi XCHAL_DEBUGLEVEL /* make a0 point here not later */ - #endif + wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* preserve a0 */ + call0 xt_debugexception /* load exception handler */ .end literal_prefix @@ -1060,9 +1042,6 @@ locking. /* Co-processor exception occurred outside a thread (not supported). */ .L_xt_coproc_invalid: - #if XCHAL_HAVE_DEBUG - break 1, 1 /* unhandled user exception */ - #endif movi a0,PANIC_RSN_COPROCEXCEPTION wsr a0,EXCCAUSE call0 _xt_panic /* not in a thread (invalid) */ @@ -1531,9 +1510,9 @@ the minimum necessary before jumping to the handler in the .text section. *******************************************************************************/ /* -Currently only shells for high priority interrupt handlers are provided -here. However a template and example can be found in the Cadence Design Systems tools -documentation: "Microprocessor Programmer's Guide". +These stubs just call xt_highintX/xt_nmi to handle the real interrupt. Please define +these in an external assembly source file. If these symbols are not defined anywhere +else, the defaults in xtensa_vector_defaults.S are used. */ #if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 @@ -1542,37 +1521,14 @@ documentation: "Microprocessor Programmer's Guide". .section .Level2InterruptVector.text, "ax" .global _Level2Vector .type _Level2Vector,@function + .global xt_highint2 .align 4 _Level2Vector: wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_highint2 /* load interrupt handler */ + call0 xt_highint2 /* load interrupt handler */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint2,@function - .align 4 -_xt_highint2: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 2<<2 - beqz a0, 1f -.Ln_xt_highint2_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint2_exit: - rsr a0, EXCSAVE_2 /* restore a0 */ - rfi 2 - #endif /* Level 2 */ #if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 @@ -1581,38 +1537,15 @@ _xt_highint2: .section .Level3InterruptVector.text, "ax" .global _Level3Vector .type _Level3Vector,@function + .global xt_highint3 .align 4 _Level3Vector: wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_highint3 /* load interrupt handler */ + call0 xt_highint3 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint3,@function - .align 4 -_xt_highint3: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 3<<2 - beqz a0, 1f -.Ln_xt_highint3_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint3_exit: - rsr a0, EXCSAVE_3 /* restore a0 */ - rfi 3 - #endif /* Level 3 */ #if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 @@ -1621,110 +1554,15 @@ _xt_highint3: .section .Level4InterruptVector.text, "ax" .global _Level4Vector .type _Level4Vector,@function + .global xt_highint4 .align 4 _Level4Vector: wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_highint4 /* load interrupt handler */ + call0 xt_highint4 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint4,@function - .align 4 -_xt_highint4: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 4<<2 - beqz a0, 1f -.Ln_xt_highint4_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - - /* On the ESP32, this level is used for panic events that are detected by hardware and should - also panic when interrupts are disabled. At the moment, these are the interrupt watchdog - as well as the cache invalid access interrupt. (24 and 25) */ - - /* Allocate exception frame and save minimal 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_4 /* 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- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - - /* Save vaddr into exception frame */ - rsr a0, EXCVADDR - s32i a0, sp, XT_STK_EXCVADDR - - /* Figure out reason, save into EXCCAUSE reg */ - - rsr a0, INTERRUPT - extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */ - beqz a0, 1f - /* Kill this interrupt; we cannot reset it. */ - rsr a0, INTENABLE - movi a4, ~(1<=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 @@ -1733,96 +1571,15 @@ _xt_highint4: .section .Level5InterruptVector.text, "ax" .global _Level5Vector .type _Level5Vector,@function + .global xt_highint5 .align 4 _Level5Vector: wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_highint5 /* load interrupt handler */ + call0 xt_highint5 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix -#define L5_INTR_STACK_SIZE 8 -#define L5_INTR_A2_OFFSET 0 -#define L5_INTR_A3_OFFSET 4 - .data -_l5_intr_stack: - .space L5_INTR_STACK_SIZE - - .section .iram1,"ax" - .type _xt_highint5,@function - .align 4 -_xt_highint5: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 5<<2 - beqz a0, 1f -.Ln_xt_highint5_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* This section is for access dport register protection */ - /* Allocate exception frame and save minimal context. */ - /* Because the interrupt cause code have protection that only - allow one cpu enter in L5 interrupt at one time, so - there needn't have two _l5_intr_stack for each cpu */ - - movi a0, _l5_intr_stack - s32i a2, a0, L5_INTR_A2_OFFSET - s32i a3, a0, L5_INTR_A3_OFFSET - - /* Check interrupt */ - rsr a0, INTERRUPT - extui a0, a0, ETS_DPORT_INUM, 1 /* get dport int bit */ - beqz a0, 1f - - /* handle dport interrupt */ - /* get CORE_ID */ - getcoreid a0 - beqz a0, 2f - - /* current cpu is 1 */ - movi a0, DPORT_CPU_INTR_FROM_CPU_3_REG - movi a2, 0 - s32i a2, a0, 0 /* clear intr */ - movi a0, 0 /* other cpu id */ - j 3f -2: - /* current cpu is 0 */ - movi a0, DPORT_CPU_INTR_FROM_CPU_2_REG - movi a2, 0 - s32i a2, a0, 0 /* clear intr */ - movi a0, 1 /* other cpu id */ -3: - /* set and wait flag */ - movi a2, dport_access_start - addx4 a2, a0, a2 - movi a3, 1 - s32i a3, a2, 0 - memw - movi a2, dport_access_end - addx4 a2, a0, a2 -.check_dport_access_end: - l32i a3, a2, 0 - beqz a3, .check_dport_access_end - -1: - movi a0, _l5_intr_stack - l32i a2, a0, L5_INTR_A2_OFFSET - l32i a3, a0, L5_INTR_A3_OFFSET - rsync /* ensure register restored */ - - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 - - - .align 4 -.L_xt_highint5_exit: - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 - #endif /* Level 5 */ #if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 @@ -1831,38 +1588,15 @@ _xt_highint5: .section .Level6InterruptVector.text, "ax" .global _Level6Vector .type _Level6Vector,@function + .global xt_highint6 .align 4 _Level6Vector: wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_highint6 /* load interrupt handler */ + call0 xt_highint6 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint6,@function - .align 4 -_xt_highint6: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 6<<2 - beqz a0, 1f -.Ln_xt_highint6_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint6_exit: - rsr a0, EXCSAVE_6 /* restore a0 */ - rfi 6 - #endif /* Level 6 */ #if XCHAL_HAVE_NMI @@ -1871,38 +1605,15 @@ _xt_highint6: .section .NMIExceptionVector.text, "ax" .global _NMIExceptionVector .type _NMIExceptionVector,@function + .global xt_nmi .align 4 _NMIExceptionVector: wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ - call0 _xt_nmi /* load interrupt handler */ + call0 xt_nmi /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_nmi,@function - .align 4 -_xt_nmi: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, XCHAL_NMILEVEL<<2 - beqz a0, 1f -.Ln_xt_nmi_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. - */ - - .align 4 -.L_xt_nmi_exit: - rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ - rfi XCHAL_NMILEVEL - #endif /* NMI */ diff --git a/components/soc/esp32/include/soc/soc.h b/components/soc/esp32/include/soc/soc.h index fdcf92cd3..3b1e85f2f 100644 --- a/components/soc/esp32/include/soc/soc.h +++ b/components/soc/esp32/include/soc/soc.h @@ -392,12 +392,12 @@ * 23 3 extern level * 24 4 extern level TG1_WDT * 25 4 extern level CACHEERR - * 26 5 extern level Reserved Reserved + * 26 5 extern level * 27 3 extern level Reserved Reserved - * 28 4 extern edge + * 28 4 extern edge DPORT ACCESS DPORT ACCESS * 29 3 software Reserved Reserved * 30 4 extern edge Reserved Reserved - * 31 5 extern level DPORT ACCESS DPORT ACCESS + * 31 5 extern level ************************************************************************************************************* */ @@ -409,7 +409,7 @@ #define ETS_FRC1_INUM 22 #define ETS_T1_WDT_INUM 24 #define ETS_CACHEERR_INUM 25 -#define ETS_DPORT_INUM 31 +#define ETS_DPORT_INUM 28 //CPU0 Interrupt number used in ROM, should be cancelled in SDK #define ETS_SLC_INUM 1 diff --git a/docs/api-guides/index.rst b/docs/api-guides/index.rst index ea27a63ab..6b92552c6 100644 --- a/docs/api-guides/index.rst +++ b/docs/api-guides/index.rst @@ -10,6 +10,7 @@ API Guides ESP32 Core Dump Partition Tables Flash Encryption <../security/flash-encryption> + High Level Interrupts Secure Boot <../security/secure-boot> Deep Sleep Wake Stubs ULP Coprocessor diff --git a/docs/hlinterrupts.rst b/docs/hlinterrupts.rst new file mode 100644 index 000000000..508c47371 --- /dev/null +++ b/docs/hlinterrupts.rst @@ -0,0 +1,66 @@ +High-Level Interrupts +===================== + +.. toctree:: + :maxdepth: 1 + +The Xtensa architecture has support for 32 interrupts, divided over 8 levels, plus an assortment of exceptions. On the ESP32, the interrupt +mux allows most interrupt sources to be routed to these interrupts using the :doc:`interrupt allocator `. Normally, +interrupts will be written in C, but ESP-IDF allows high-level interrupts to be written in assembly as well, allowing for very low interrupt +latencies. + +Interrupt Levels +---------------- + +===== ================= ==================================================== +Level Symbol Remark +===== ================= ==================================================== +1 N/A Exception and level 0 interrupts. Handled by ESP-IDF +2-3 N/A Medium level interrupts. Handled by ESP-IDF +4 xt_highint4 Normally used by ESP-IDF debug logic +5 xt_highint5 Free to use +NMI xt_nmi Free to use +dbg xt_debugexception Debug exception. Called on e.g. a BREAK instruction. +===== ================= ==================================================== + +Using these symbols is done by creating an assembly file (suffix .S) and defining the named symbols, like this:: + + .section .iram1,"ax" + .global xt_highint5 + .type xt_highint5,@function + .align 4 + xt_highint5: + ... your code here + rsr a0, EXCSAVE_5 + rfi 5 + + +For a real-life example, see the components/esp32/panic_highint_hdl.S file; the panic handler iunterrupt is implemented there. + +Notes +----- + + - Do not call C code from a high-level interrupt; because these interupts still run in critical sections, this can cause crashes. + (The panic handler interrupt does call normal C code, but this is OK because there is no intention of returning to the normal code + flow afterwards.) + + - Make sure your assembly code gets linked in. If the interrupt handler symbol is the only symbol the rest of the code uses from this + file, the linker will take the default ISR instead and not link the assembly file into the final project. To get around this, in the + assembly file, define a symbol, like this:: + + .global ld_include_my_isr_file + ld_include_my_isr_file: + + +(The symbol is called ``ld_include_my_isr_file`` here but can have any arbitrary name not defined anywhere else.) +Then, in the component.mk, add this file as an unresolved symbol to the ld command line arguments:: + + COMPONENT_ADD_LDFLAGS := -u ld_include_my_isr_file + +This should cause the linker to always include a file defining ``ld_include_my_isr_file``, causing the ISR to always be linked in. + + - High-level interrupts can be routed and handled using esp_intr_alloc and associated functions. The handler and handler arguments + to esp_intr_alloc must be NULL, however. + + - In theory, medium priority interrupts could also be handled in this way. For now, ESP-IDF does not support this. +