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 \
+ -u ld_include_dport_highint_hdl \
$(addprefix -T ,$(LINKER_SCRIPTS))
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
--- /dev/null
+#include <xtensa/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include <xtensa/simcall.h>
+#include "freertos/xtensa_context.h"
+#include "esp_panic.h"
+#include "sdkconfig.h"
+#include "soc/soc.h"
+#include "soc/dport_reg.h"
+
+
+#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"
+ .global xt_highint5
+ .type xt_highint5,@function
+ .align 4
+xt_highint5:
+
+
+ /* 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
+
+
+/* The linker has no reason to link in this file; all symbols it exports are already defined
+ (weakly!) in the default int handler. Define a symbol here so we can use it to have the
+ linker inspect this anyway. */
+
+ .global ld_include_dport_highint_hdl
+ld_include_dport_highint_hdl:
+
--- /dev/null
+// 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/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include <xtensa/simcall.h>
+#include "freertos/xtensa_context.h"
+#include "esp_panic.h"
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+
+
+/*
+In some situations, the panic handler needs to be invoked even when (low/medium priority) interrupts
+are disabled. In that case, we use a high interrupt to panic anyway. This is the high-level interrupt
+handler for such a situation. We use interrupt level 4 for this.
+*/
+
+ .section .iram1,"ax"
+ .global xt_highint4
+ .type xt_highint4,@function
+ .align 4
+xt_highint4:
+
+
+ /* 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<<ETS_CACHEERR_INUM)
+ and a0, a4, a0
+ wsr a0, INTENABLE
+ movi a0, PANIC_RSN_CACHEERR
+ j 9f
+1:
+#if CONFIG_INT_WDT_CHECK_CPU1
+ /* Check if the cause is the app cpu failing to tick.*/
+ movi a0, int_wdt_app_cpu_ticked
+ l32i a0, a0, 0
+ bnez a0, 2f
+ /* It is. Modify cause. */
+ movi a0,PANIC_RSN_INTWDT_CPU1
+ j 9f
+2:
+#endif
+ /* Set EXCCAUSE to reflect cause of the wdt int trigger */
+ movi a0,PANIC_RSN_INTWDT_CPU0
+9:
+ /* Found the reason, now save it. */
+ s32i a0, sp, XT_STK_EXCCAUSE
+
+ /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
+ rsr a0, EXCSAVE_4 /* save interruptee's a0 */
+
+ s32i a0, sp, XT_STK_A0
+
+ /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
+ movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
+ wsr a0, PS
+
+ //Call panic handler
+ mov a6,sp
+ call4 panicHandler
+
+ call0 _xt_context_restore
+ 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_4
+ l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
+ l32i sp, sp, XT_STK_A1 /* remove exception frame */
+ rsync /* ensure PS and EPC written */
+
+ rsr a0, EXCSAVE_4 /* restore a0 */
+ rfi 4
+
+
+
+/* The linker has no reason to link in this file; all symbols it exports are already defined
+ (weakly!) in the default int handler. Define a symbol here so we can use it to have the
+ linker inspect this anyway. */
+
+ .global ld_include_panic_highint_hdl
+ld_include_panic_highint_hdl:
+
--- /dev/null
+/*
+ Tests for the interrupt watchdog
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#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);
+}
--- /dev/null
+// 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 */
+
.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
/* 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) */
*******************************************************************************/
/*
-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
.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
.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
.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<<ETS_CACHEERR_INUM)
- and a0, a4, a0
- wsr a0, INTENABLE
- movi a0, PANIC_RSN_CACHEERR
- j 9f
-1:
-#if CONFIG_INT_WDT_CHECK_CPU1
- /* Check if the cause is the app cpu failing to tick.*/
- movi a0, int_wdt_app_cpu_ticked
- l32i a0, a0, 0
- bnez a0, 2f
- /* It is. Modify cause. */
- movi a0,PANIC_RSN_INTWDT_CPU1
- j 9f
-2:
-#endif
- /* Set EXCCAUSE to reflect cause of the wdt int trigger */
- movi a0,PANIC_RSN_INTWDT_CPU0
-9:
- /* Found the reason, now save it. */
- s32i a0, sp, XT_STK_EXCCAUSE
-
- /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
- rsr a0, EXCSAVE_4 /* save interruptee's a0 */
-
- s32i a0, sp, XT_STK_A0
-
- /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
- movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
- wsr a0, PS
-
- //Call panic handler
- mov a6,sp
- call4 panicHandler
-
- call0 _xt_context_restore
- 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_4
- l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */
- l32i sp, sp, XT_STK_A1 /* remove exception frame */
- rsync /* ensure PS and EPC written */
-
- rsr a0, EXCSAVE_4 /* restore a0 */
- rfi 4
-
#endif /* Level 4 */
#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
.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
.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
.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 */
ESP32 Core Dump <core_dump>
Partition Tables <partition-tables>
Flash Encryption <../security/flash-encryption>
+ High Level Interrupts <hlinterrupts>
Secure Boot <../security/secure-boot>
Deep Sleep Wake Stubs <deep-sleep-stub>
ULP Coprocessor <ulp>
--- /dev/null
+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 <api/system/intr_alloc>`. 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.
+