mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 04:34:31 +02:00
Break out high-level interrupts so a component can override them
This commit is contained in:
@@ -25,12 +25,17 @@ ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
|
|||||||
LINKER_SCRIPTS += esp32.rom.spiflash.ld
|
LINKER_SCRIPTS += esp32.rom.spiflash.ld
|
||||||
endif
|
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_ADD_LDFLAGS := -lesp32 \
|
||||||
$(COMPONENT_PATH)/libhal.a \
|
$(COMPONENT_PATH)/libhal.a \
|
||||||
-L$(COMPONENT_PATH)/lib \
|
-L$(COMPONENT_PATH)/lib \
|
||||||
$(addprefix -l,$(LIBS)) \
|
$(addprefix -l,$(LIBS)) \
|
||||||
-L $(COMPONENT_PATH)/ld \
|
-L $(COMPONENT_PATH)/ld \
|
||||||
-T esp32_out.ld \
|
-T esp32_out.ld \
|
||||||
|
-u ld_include_panic_highint_hdl \
|
||||||
|
-u ld_include_dport_highint_hdl \
|
||||||
$(addprefix -T ,$(LINKER_SCRIPTS))
|
$(addprefix -T ,$(LINKER_SCRIPTS))
|
||||||
|
|
||||||
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
|
||||||
|
93
components/esp32/dport_highint_hdl.S
Normal file
93
components/esp32/dport_highint_hdl.S
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#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:
|
||||||
|
|
128
components/esp32/panic_highint_hdl.S
Normal file
128
components/esp32/panic_highint_hdl.S
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
// 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:
|
||||||
|
|
20
components/esp32/test/test_int_wdt.c
Normal file
20
components/esp32/test/test_int_wdt.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
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);
|
||||||
|
}
|
158
components/freertos/xtensa_vector_defaults.S
Normal file
158
components/freertos/xtensa_vector_defaults.S
Normal file
@@ -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 */
|
||||||
|
|
@@ -471,28 +471,10 @@ Debug Exception.
|
|||||||
.section .DebugExceptionVector.text, "ax"
|
.section .DebugExceptionVector.text, "ax"
|
||||||
.global _DebugExceptionVector
|
.global _DebugExceptionVector
|
||||||
.align 4
|
.align 4
|
||||||
|
.global xt_debugexception
|
||||||
_DebugExceptionVector:
|
_DebugExceptionVector:
|
||||||
|
wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* preserve a0 */
|
||||||
#ifdef XT_SIMULATOR
|
call0 xt_debugexception /* load exception handler */
|
||||||
/*
|
|
||||||
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
|
|
||||||
|
|
||||||
.end literal_prefix
|
.end literal_prefix
|
||||||
|
|
||||||
@@ -1060,9 +1042,6 @@ locking.
|
|||||||
|
|
||||||
/* Co-processor exception occurred outside a thread (not supported). */
|
/* Co-processor exception occurred outside a thread (not supported). */
|
||||||
.L_xt_coproc_invalid:
|
.L_xt_coproc_invalid:
|
||||||
#if XCHAL_HAVE_DEBUG
|
|
||||||
break 1, 1 /* unhandled user exception */
|
|
||||||
#endif
|
|
||||||
movi a0,PANIC_RSN_COPROCEXCEPTION
|
movi a0,PANIC_RSN_COPROCEXCEPTION
|
||||||
wsr a0,EXCCAUSE
|
wsr a0,EXCCAUSE
|
||||||
call0 _xt_panic /* not in a thread (invalid) */
|
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
|
These stubs just call xt_highintX/xt_nmi to handle the real interrupt. Please define
|
||||||
here. However a template and example can be found in the Cadence Design Systems tools
|
these in an external assembly source file. If these symbols are not defined anywhere
|
||||||
documentation: "Microprocessor Programmer's Guide".
|
else, the defaults in xtensa_vector_defaults.S are used.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2
|
#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"
|
.section .Level2InterruptVector.text, "ax"
|
||||||
.global _Level2Vector
|
.global _Level2Vector
|
||||||
.type _Level2Vector,@function
|
.type _Level2Vector,@function
|
||||||
|
.global xt_highint2
|
||||||
.align 4
|
.align 4
|
||||||
_Level2Vector:
|
_Level2Vector:
|
||||||
wsr a0, EXCSAVE_2 /* preserve a0 */
|
wsr a0, EXCSAVE_2 /* preserve a0 */
|
||||||
call0 _xt_highint2 /* load interrupt handler */
|
call0 xt_highint2 /* load interrupt handler */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* Level 2 */
|
||||||
|
|
||||||
#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
|
#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3
|
||||||
@@ -1581,38 +1537,15 @@ _xt_highint2:
|
|||||||
.section .Level3InterruptVector.text, "ax"
|
.section .Level3InterruptVector.text, "ax"
|
||||||
.global _Level3Vector
|
.global _Level3Vector
|
||||||
.type _Level3Vector,@function
|
.type _Level3Vector,@function
|
||||||
|
.global xt_highint3
|
||||||
.align 4
|
.align 4
|
||||||
_Level3Vector:
|
_Level3Vector:
|
||||||
wsr a0, EXCSAVE_3 /* preserve a0 */
|
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) */
|
/* never returns here - call0 is used as a jump (see note at top) */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* Level 3 */
|
||||||
|
|
||||||
#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
|
#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4
|
||||||
@@ -1621,110 +1554,15 @@ _xt_highint3:
|
|||||||
.section .Level4InterruptVector.text, "ax"
|
.section .Level4InterruptVector.text, "ax"
|
||||||
.global _Level4Vector
|
.global _Level4Vector
|
||||||
.type _Level4Vector,@function
|
.type _Level4Vector,@function
|
||||||
|
.global xt_highint4
|
||||||
.align 4
|
.align 4
|
||||||
_Level4Vector:
|
_Level4Vector:
|
||||||
wsr a0, EXCSAVE_4 /* preserve a0 */
|
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) */
|
/* never returns here - call0 is used as a jump (see note at top) */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* Level 4 */
|
||||||
|
|
||||||
#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
|
#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
|
||||||
@@ -1733,96 +1571,15 @@ _xt_highint4:
|
|||||||
.section .Level5InterruptVector.text, "ax"
|
.section .Level5InterruptVector.text, "ax"
|
||||||
.global _Level5Vector
|
.global _Level5Vector
|
||||||
.type _Level5Vector,@function
|
.type _Level5Vector,@function
|
||||||
|
.global xt_highint5
|
||||||
.align 4
|
.align 4
|
||||||
_Level5Vector:
|
_Level5Vector:
|
||||||
wsr a0, EXCSAVE_5 /* preserve a0 */
|
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) */
|
/* never returns here - call0 is used as a jump (see note at top) */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* Level 5 */
|
||||||
|
|
||||||
#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
|
#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
|
||||||
@@ -1831,38 +1588,15 @@ _xt_highint5:
|
|||||||
.section .Level6InterruptVector.text, "ax"
|
.section .Level6InterruptVector.text, "ax"
|
||||||
.global _Level6Vector
|
.global _Level6Vector
|
||||||
.type _Level6Vector,@function
|
.type _Level6Vector,@function
|
||||||
|
.global xt_highint6
|
||||||
.align 4
|
.align 4
|
||||||
_Level6Vector:
|
_Level6Vector:
|
||||||
wsr a0, EXCSAVE_6 /* preserve a0 */
|
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) */
|
/* never returns here - call0 is used as a jump (see note at top) */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* Level 6 */
|
||||||
|
|
||||||
#if XCHAL_HAVE_NMI
|
#if XCHAL_HAVE_NMI
|
||||||
@@ -1871,38 +1605,15 @@ _xt_highint6:
|
|||||||
.section .NMIExceptionVector.text, "ax"
|
.section .NMIExceptionVector.text, "ax"
|
||||||
.global _NMIExceptionVector
|
.global _NMIExceptionVector
|
||||||
.type _NMIExceptionVector,@function
|
.type _NMIExceptionVector,@function
|
||||||
|
.global xt_nmi
|
||||||
.align 4
|
.align 4
|
||||||
_NMIExceptionVector:
|
_NMIExceptionVector:
|
||||||
wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */
|
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) */
|
/* never returns here - call0 is used as a jump (see note at top) */
|
||||||
|
|
||||||
.end literal_prefix
|
.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 */
|
#endif /* NMI */
|
||||||
|
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@ API Guides
|
|||||||
ESP32 Core Dump <core_dump>
|
ESP32 Core Dump <core_dump>
|
||||||
Partition Tables <partition-tables>
|
Partition Tables <partition-tables>
|
||||||
Flash Encryption <../security/flash-encryption>
|
Flash Encryption <../security/flash-encryption>
|
||||||
|
High Level Interrupts <hlinterrupts>
|
||||||
Secure Boot <../security/secure-boot>
|
Secure Boot <../security/secure-boot>
|
||||||
Deep Sleep Wake Stubs <deep-sleep-stub>
|
Deep Sleep Wake Stubs <deep-sleep-stub>
|
||||||
ULP Coprocessor <ulp>
|
ULP Coprocessor <ulp>
|
||||||
|
66
docs/hlinterrupts.rst
Normal file
66
docs/hlinterrupts.rst
Normal file
@@ -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 <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.
|
||||||
|
|
Reference in New Issue
Block a user