mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
Merge branch 'fix/xtensa_nmi_v5.3' into 'release/v5.3'
fix(esp_hw_support): make the NMI interrupts available for the main application (backport v5.3) See merge request espressif/esp-idf!34268
This commit is contained in:
commit
cb8d1796b8
@ -167,7 +167,7 @@ const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = {
|
||||
[11] = { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } },
|
||||
[12] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } },
|
||||
[13] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } },
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, // NMI
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, // NMI
|
||||
#if CONFIG_FREERTOS_CORETIMER_1
|
||||
[15] = { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } },
|
||||
#else
|
||||
|
@ -44,7 +44,7 @@ const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = {
|
||||
[12] = { 1, ESP_CPU_INTR_TYPE_LEVEL, 0 },
|
||||
[13] = { 1, ESP_CPU_INTR_TYPE_LEVEL, 0 },
|
||||
/* Interrupt 14 reserved for NMI (Non-Maskable Interrupts) */
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, ESP_CPU_INTR_DESC_FLAG_RESVD },
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, 0 },
|
||||
#if CONFIG_FREERTOS_CORETIMER_1
|
||||
[15] = { 3, ESP_CPU_INTR_TYPE_NA, ESP_CPU_INTR_DESC_FLAG_RESVD },
|
||||
#else
|
||||
|
@ -42,7 +42,7 @@ const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = {
|
||||
[12] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } },
|
||||
[13] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } },
|
||||
/* Interrupt 14 reserved for NMI (Non-Maskable Interrupts) */
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, // NMI
|
||||
[14] = { 7, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, // NMI
|
||||
[15] = { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } },
|
||||
[16] = { 5, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } },
|
||||
[17] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } },
|
||||
|
@ -119,3 +119,5 @@ This will ensure the linker to always includes the file defining ``ld_include_my
|
||||
- In theory, medium priority interrupts could also be handled in this way. ESP-IDF does not support this yet.
|
||||
|
||||
- To check Xtensa instruction set architecture (ISA), please refer to `Xtensa ISA Summary <https://www.cadence.com/content/dam/cadence-www/global/en_US/documents/tools/ip/tensilica-ip/isa-summary.pdf>`_.
|
||||
|
||||
See :example:`system/nmi_isr` for an example of how to implement a custom NMI handler on Xtensa-based targets.
|
||||
|
@ -124,6 +124,11 @@ examples/system/light_sleep:
|
||||
disable:
|
||||
- if: SOC_LIGHT_SLEEP_SUPPORTED != 1
|
||||
|
||||
examples/system/nmi_isr:
|
||||
enable:
|
||||
- if: IDF_TARGET_ARCH_XTENSA == 1
|
||||
reason: test NMI for Xtensa targets only
|
||||
|
||||
examples/system/ota/advanced_https_ota:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32h2", "esp32p4", "esp32c5"]
|
||||
|
6
examples/system/nmi_isr/CMakeLists.txt
Normal file
6
examples/system/nmi_isr/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(nmi_isr)
|
40
examples/system/nmi_isr/README.md
Normal file
40
examples/system/nmi_isr/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- |
|
||||
|
||||
# NMI ISR Example
|
||||
|
||||
This example demonstrates how to allocate and use non-maskable interrupt (NMI) on Xtensa-based targets. The `asm_funcs.S` file contains the ISR that will be run on the core that installed the NMI. The callback should be fairly simple and must be entirely written in assembly.
|
||||
|
||||
Defining an NMI handler can be done by defining a routine named `xt_nmi`. That routine will be called via `call0` instruction, as such, before returning from the ISR, the return address register, `a0`, must be restored thanks to the instruction:
|
||||
|
||||
```
|
||||
rsr a0, EXCSAVE + XCHAL_NMILEVEL
|
||||
```
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example can run on any Xtensa-based ESP32 development board. Since the example uses GPIO19 as a bi-directional pin, make sure not to connect it to anything.
|
||||
|
||||
### Configure the project
|
||||
|
||||
No particular configuration is required to run this example, the default one is suitable.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
```
|
||||
idf.py build flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
|
||||
## Example output
|
||||
|
||||
```
|
||||
example: Start
|
||||
example: Success
|
||||
```
|
4
examples/system/nmi_isr/main/CMakeLists.txt
Normal file
4
examples/system/nmi_isr/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "nmi_isr_main.c"
|
||||
"asm_funcs.S"
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE)
|
47
examples/system/nmi_isr/main/asm_funcs.S
Normal file
47
examples/system/nmi_isr/main/asm_funcs.S
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <xtensa/coreasm.h>
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "example_gpio.h"
|
||||
|
||||
.global nmi_triggered
|
||||
|
||||
.section .bss
|
||||
nmi_triggered:
|
||||
.space 4
|
||||
|
||||
|
||||
/**
|
||||
* @brief This current ISR was called via `call0` instruction, so `a0` (return address)
|
||||
* was altered. Fortunately, `a0` was saved in EXCSAVE registers, restore it before
|
||||
* returning
|
||||
*/
|
||||
.section .iram1, "ax"
|
||||
.align 4
|
||||
.global xt_nmi
|
||||
.type xt_nmi, @function
|
||||
xt_nmi:
|
||||
addi sp, sp, -16
|
||||
s32i a3, sp, 0
|
||||
|
||||
/* Set the interrupt flag to 1 */
|
||||
movi a0, nmi_triggered
|
||||
movi a3, 1
|
||||
s32i a3, a0, 0
|
||||
|
||||
/* Set the GPIO level back to low to prevent triggering an interrupt again */
|
||||
movi a0, GPIO_OUT_W1TC_REG
|
||||
movi a3, 1 << EXAMPLE_GPIO_IN
|
||||
s32i a3, a0, 0
|
||||
|
||||
/* Restore a3 and a0 before leaving*/
|
||||
l32i a3, sp, 0
|
||||
addi sp, sp, 16
|
||||
rsr a0, EXCSAVE + XCHAL_NMILEVEL
|
||||
|
||||
/* Return from NMI, we need to specify the level */
|
||||
rfi XCHAL_NMILEVEL
|
9
examples/system/nmi_isr/main/example_gpio.h
Normal file
9
examples/system/nmi_isr/main/example_gpio.h
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define EXAMPLE_GPIO_IN 19
|
64
examples/system/nmi_isr/main/nmi_isr_main.c
Normal file
64
examples/system/nmi_isr/main/nmi_isr_main.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
#include "soc/interrupts.h"
|
||||
#include "example_gpio.h"
|
||||
|
||||
extern volatile int nmi_triggered;
|
||||
|
||||
extern void xt_nmi(void*);
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
intr_handle_t handle;
|
||||
esp_err_t err;
|
||||
|
||||
printf("example: Start\n");
|
||||
|
||||
gpio_reset_pin(EXAMPLE_GPIO_IN);
|
||||
/* Make sure we have a pull-down on the input GPIO to prevent noise (when disconnected) */
|
||||
gpio_pulldown_en(EXAMPLE_GPIO_IN);
|
||||
gpio_set_direction(EXAMPLE_GPIO_IN, GPIO_MODE_INPUT_OUTPUT);
|
||||
|
||||
/* Register the interrupt handler as an NMI. When registering high level interrupts,
|
||||
* the interrupt allocator expects the handler passed as an argument to be NULL. */
|
||||
err = esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_NMI, NULL, NULL, &handle);
|
||||
if (err != ESP_OK) {
|
||||
printf("Failure: could not install NMI ISR, %d(0x%x)\n", err, err);
|
||||
return;
|
||||
}
|
||||
gpio_set_intr_type(EXAMPLE_GPIO_IN, GPIO_INTR_HIGH_LEVEL);
|
||||
gpio_intr_enable(EXAMPLE_GPIO_IN);
|
||||
|
||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||
|
||||
/* Disable interrupts on the CPU side and make sure the NMI is still triggered */
|
||||
const uint32_t mask = esp_cpu_intr_get_enabled_mask();
|
||||
esp_cpu_intr_disable(0xFFFFFFFF);
|
||||
nmi_triggered = 0;
|
||||
|
||||
/* Setting EXAMPLE_GPIO_IN to 1 will trigger the NMI interrupt. */
|
||||
gpio_set_level(EXAMPLE_GPIO_IN, 1);
|
||||
|
||||
/* Wait for the interrupt to occur */
|
||||
while (nmi_triggered == 0) {
|
||||
/* We cannot use vTaskDelay since the interrupts are disabled */
|
||||
}
|
||||
|
||||
esp_cpu_intr_enable(mask);
|
||||
|
||||
gpio_intr_disable(EXAMPLE_GPIO_IN);
|
||||
esp_intr_free(handle);
|
||||
printf("example: Success\n");
|
||||
}
|
13
examples/system/nmi_isr/pytest_nmi_isr.py
Normal file
13
examples/system/nmi_isr/pytest_nmi_isr.py
Normal file
@ -0,0 +1,13 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s2
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
def test_nmi_isr(dut: Dut) -> None:
|
||||
dut.expect_exact('example: Start')
|
||||
dut.expect_exact('example: Success')
|
0
examples/system/nmi_isr/sdkconfig.defaults
Normal file
0
examples/system/nmi_isr/sdkconfig.defaults
Normal file
@ -14,7 +14,7 @@ CPU 0 interrupt status:
|
||||
11 3 Level CPU-internal
|
||||
12 1 Level Free
|
||||
13 1 Level Free
|
||||
14 7 Level Reserved
|
||||
14 7 Level Free
|
||||
15 3 Level CPU-internal
|
||||
16 5 Level CPU-internal
|
||||
17 1 Level Free
|
||||
@ -48,7 +48,7 @@ CPU 1 interrupt status:
|
||||
11 3 Level CPU-internal
|
||||
12 1 Level Free
|
||||
13 1 Level Free
|
||||
14 7 Level Reserved
|
||||
14 7 Level Free
|
||||
15 3 Level CPU-internal
|
||||
16 5 Level CPU-internal
|
||||
17 1 Level Free
|
||||
|
@ -14,7 +14,7 @@ CPU 0 interrupt status:
|
||||
11 3 Level CPU-internal
|
||||
12 1 Level Free
|
||||
13 1 Level Free
|
||||
14 7 Level Reserved
|
||||
14 7 Level Free
|
||||
15 3 Level CPU-internal
|
||||
16 5 Level CPU-internal
|
||||
17 1 Level Free
|
||||
|
@ -14,7 +14,7 @@ CPU 0 interrupt status:
|
||||
11 3 Level CPU-internal
|
||||
12 1 Level Free
|
||||
13 1 Level Free
|
||||
14 7 Level Reserved
|
||||
14 7 Level Free
|
||||
15 3 Level CPU-internal
|
||||
16 5 Level CPU-internal
|
||||
17 1 Level Free
|
||||
@ -48,7 +48,7 @@ CPU 1 interrupt status:
|
||||
11 3 Level CPU-internal
|
||||
12 1 Level Free
|
||||
13 1 Level Free
|
||||
14 7 Level Reserved
|
||||
14 7 Level Free
|
||||
15 3 Level CPU-internal
|
||||
16 5 Level CPU-internal
|
||||
17 1 Level Free
|
||||
|
Loading…
x
Reference in New Issue
Block a user