没志青年
发布于 2025-07-27 / 20 阅读
0

ESP32 中断管理

中断分配 - ESP32 - — ESP-IDF 编程指南 v5.5 文档

手册 9.3.2

中断基础概念

ESP32 是 Xtensa 架构的,中断优先级分为 7 个级别(1 ~ 7),数值越大,优先级越高。

STM32 将所有中断固定在单核上,每一个中断源对应一个中断号,因此不需要手动给中断源分配中断号。数值越小,优先级越高,没有级别的概念。

而 ESP32 每个 CPU 只有 32 个中断号 (0 ~ 31),其中包括 26 个外部中断,6 个内部中断。因此需要使用中断矩阵手动给中断源分配中断号。

之所以叫作中断矩阵,是因为外部中断和 CPU 核心是多对多的关系,一个外部中断源可同时映射到两个 CPU 上,多个外部中断源可同时映射到同一个 CPU 的中断号上,具有很高的灵活性。

中断传递流程:外设->中断矩阵->CPU核心

ESP32-S3 支持六级中断嵌套,CPU 中断:

(1)外部中断,外部中断源引发的中断:

  • 电平触发类型中断:高电平触发,要求保持中断的电平状态直到 CPUx 响应

  • 边沿触发类型中断:上升沿触发,此中断一旦产生,CPUx 即可响应

  • NMI 中断:最高优先级的中断,一旦触发,CPU必须处理,软件不可使用 CPUx 内部特殊寄存器屏蔽此类中断。World Controller 模块提供了屏蔽此中断的机制。

(2)内部中断, CPUx 内部自己产生的中断:

  • 定时器中断:由内部定时器触发,可用于产生周期性的中断

  • 软件中断:软件写特殊寄存器时将触发此中断

  • 解析中断:用于性能监测和分析。

中断号详情:

中断号

类别

种类

优先级等级

0

外部中断

电平触发

1

1

外部中断

电平触发

1

2

外部中断

电平触发

1

3

外部中断

电平触发

1

4

外部中断

电平触发

1

5

外部中断

电平触发

1

6

内部中断

定时器 0

1

7

内部中断

软件

1

8

外部中断

电平触发

1

9

外部中断

电平触发

1

10

外部中断

边沿触发

1

11

内部中断

解析

3

12

外部中断

电平触发

1

13

外部中断

电平触发

1

14

外部中断

NMI

NMI

15

内部中断

定时器 1

3

16

内部中断

定时器 2

5

17

外部中断

电平触发

1

18

外部中断

电平触发

1

19

外部中断

电平触发

2

20

外部中断

电平触发

2

21

外部中断

电平触发

2

22

外部中断

边沿触发

3

23

外部中断

电平触发

3

24

外部中断

电平触发

4

25

外部中断

电平触发

4

26

外部中断

电平触发

5

27

外部中断

电平触发

3

28

外部中断

边沿触发

4

29

内部中断

软件

3

30

外部中断

边沿触发

4

31

外部中断

电平触发

5

注意:对于电平类型中断,在 CPU 响应此中断之前该中断信号的电平需要一直保持,如果电平提前掉下去 CPU 会丢失此次中断。

中断处理

中断分配

(1)非共享中断:即一个中断源对应一个中断号。

  • ISR 只有一个

  • 可电平触发,可边沿触发

(2)共享中断:即多个中断源对应一个中断号。

  • 每个中断源都有一个 ISR,当有一个中断源发出中断信号时,会调用多个 ISR。因此需要在各自的 ISR 中进行判断。

  • 只能电平触发,因为边沿触发可能会错过中断。

为什么会边沿触发会错过中断?

假设有外设 A 和外设 B 两个外设,当外设 B 边沿触发中断时,中断标志位会被置 1,外设 B 的 ISR 被执行。若外设 B 的 ISR 还没执行完毕时外设 A 也产生了中断。那么当外设 B 的 ISR 执行完毕时中断标志位会被清零,这样外设 A 就像没触发中断一样,中断丢失了。

为什么电平触发就可以?

在电平触发中,只要信号保持在有效电平,就会持续触发中断。

当外设需要 CPU 处理的时候,就会将中断信号线(芯片内部的物理线路,用户不可见)拉到有效电平并且一直输出,直到它的标志位被清除。所以,若一直是有效电平,就表明还有外设没处理,就不会漏了。

即中断排队处理。

引入头文件:

#include "esp_intr_types.h"    // 类型定义
#include "esp_intr_alloc.h"    // 函数声明

基本中断分配:

esp_err_t esp_intr_alloc(int source,
int flags,
intr_handler_t handler,
void *arg,
intr_handle_t *ret_handle);

非共享中断只调用上面的函数就行了,共享中断要绑定:

esp_err_t esp_intr_alloc_bind(int source,
int flags,
intr_handler_t handler,
void *arg,
intr_handle_t shared_handle,
intr_handle_t *ret_handle);

基于状态寄存器的中断:

esp_err_t esp_intr_alloc_intrstatus(int source,
int flags,
uint32_t intrstatusreg,
uint32_t intrstatusmask,
intr_handler_t handler,
void *arg,
intr_handle_t *ret_handle);

基于状态寄存器的共享中断绑定:

esp_err_t esp_intr_alloc_intrstatus_bind(int source,
int flags,
uint32_t intrstatusreg,
uint32_t intrstatusmask,
intr_handler_t handler,
void *arg,
intr_handle_t shared_handle,
intr_handle_t *ret_handle);

中断屏蔽

CPU 的 32 个中断,除了 NMI 中断,其余中断可使用 INTENABLE 寄存器进行屏蔽和使能。

屏蔽 NMI 中断的两种方法:

  1. 断开外部中断源与 NMI 中断的连接。

  2. 不断开外部中断源与 NMI 中断的连接,但使用 World Controller 模块的 NMI 屏蔽功能进行屏蔽。

中断状态查询

查询外部中断源当前的中断状态

中断响应

  • 高优先级可以抢占低优先级的中断,发生中断嵌套。

  • 相同优先级的不会嵌套,按照中断号从小到大排队处理。

多核问题和注意事项

多核问题:

(1)允许从另一个内核禁用和启用外部中断。

(2)当不需要某个中断时,释放操作必须在分配该中断的内核上进行

(3)在未指定核心的任务中调用 ......

IRAM 安全中断处理程序

EXTI 中断

设置中断:

void gpio_install_isr_service(esp_intr_alloc_flag_t flags);

flags:

  • ESP_INTR_FLAG_LEVEL1:

  • ESP_INTR_FLAG_LEVEL2:

  • ESP_INTR_FLAG_EDGE:边沿触发

  • ESP_INTR_FLAG_LOWMED:中低电平触发

  • ESP_INTR_FLAG_HIGH:高电平触发

设置中断处理函数:

esp_err_t gpio_isr_handler_add( gpio_num_t gpio_num, 
                                gpio_isr_t isr_handler,
                                void* args );
  • gpio_num:引脚号。

  • isr_handler:中断处理函数指针。

  • args:传给中断处理函数的参数。