ESP32 外部中断原理分析 GPIO外部中断实战

news/2024/7/4 19:15:52

ESP32 外部中断原理分析 & GPIO外部中断实战

阅读建议:

  有一定Cortex-m架构、Xtensa® 32-bit LX6 架构知识基础。

软件环境

  • VSCODE-ESP32-IDF4.3 插件版
  • LVGL project for ESP32

硬件环境

  • ESP32-D2WD

外部中断原理

ESP32-GPIO

  ESP32 共有 34 个 GPIO 管脚,通过配置对应的寄存器,可以为这些管脚分配不同的功能,包括如下几类 GPIO:只有数字功能的 GPIO、带模拟功能的 GPIO、带电容触摸功能的 GPIO 等。
  带模拟功能的 GPIO 和带电容触摸功能的 GPIO 可以被配置为数字 GPIO。大部分带数字功能的 GPIO 都可以被配置为内部上拉/下拉,或者被设置为高阻。当被配置为输入时,可通过读取寄存器获取输入值。输入管脚也可以被设置为通过边缘触发或电平触发来产生 CPU 中断。大部分数字 IO 管脚都是双向、非反相和三态的,包括带有三态控制的输入和输出缓冲器。这些管脚可以复用作其他功能,例如SDIO、UART、SPI 等(更多信息请参考附录 IO_MUX)。当芯片低功耗运行时,GPIO 可被设定为保持状态。

ESP32-INTERRUPT

  ESP32 中断矩阵将任一外部中断源单独分配到每个 CPU 的任一外部中断上。这提供了强大的灵活性,能适应不同的应用需求。这和Cortex-m架构的外部中断并不相同并不是通过NVIC向量表的方式而是中断矩阵来设置。

图1: 中断矩阵结构图

主要特性
• 接受 71 个外部中断源作为输入
• 为两个 CPU 分别生成 26 个外部中断(总共 52 个) 作为输出
• 屏蔽 CPU 的 NMI 类型中断
• 查询外部中断源当前的中断状态

值得注意的是这里分出了两个概念:外部中断源CPU的外部中断 ,这是理解ESP32中断的核心。

ESP32-外部中断源

  ESP32 总共有 71 个外部中断源。图2列出了所有外部中断源。ESP32 中的 71 个外部中断源中有 67 个可以分配给两个 CPU。其余的 4 个外部中断源只能分配给特定的 CPU,每个 CPU 2 个GPIO_INTERRUPT_PROGPIO_INTERRUPT_PRO_NMI 只可以分配PRO _CPUGPIO_INTERRUPT_APPGPIO_INTERRUPT_APP_NMI 只可以分配给 APP_CPU。因此,PRO_CPUAPP_CPU 各可以分配到 69 个外部中断源

图2: 外部中断源
图3: 外部GPIO中断源

ESP32-CPU的外部中断

  两个 CPU(PRO_CPUAPP_CPU)各有 32 个中断,其中 26 个为外部中断。图3列出了每个 CPU 所有的
中断。

图4: CPU的外部中断

ESP32-CPU的外部中断 & 外部中断源

  每一个外设的中断对应着一个中断源,每一个中断源对应着一个中断源重定向寄存器,如图3所示,GPIO_INTERRUPT_PRO中断源就对应着PRO_GPIO_INTERRUPT_PRO_MAP_REG寄存器通过设置这个寄存器就可以映射到对应的CPU的外部中断如图4所示。每当中断发生时,就可以通过对应CPU的外部中断的回调函数实现中断处理与服务。
值得注意的是:
  CPU的一个外部中断可以由多个中断源触发,只要在对应的寄存器中写入对应的外部中断号即可。(将各个寄存器 PRO_Xn_MAP_REG (APP_Xn_MAP_REG) 都配成同样的 中断号。这些外设中断都会触发CPU Interrupt_P)。

外部中断实战

  1. 首先配置GPIO

  ESP-IDF提供了一个结构体方便对其进行初始化,结构体如下:

typedef struct {
    uint64_t pin_bit_mask;          /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
    gpio_mode_t mode;               /*!< GPIO mode: set input/output mode                     */
    gpio_pullup_t pull_up_en;       /*!< GPIO pull-up                                         */
    gpio_pulldown_t pull_down_en;   /*!< GPIO pull-down                                       */
    gpio_int_type_t intr_type;      /*!< GPIO interrupt type                                  */
} gpio_config_t;

  这结构体中的五个成员都需要初始化,其中第一个通过设置对应位就可以开启对应号码的GPIO,剩下的就是模式设置和中断管理成员。
下面展示一个初始化的例子

#define GPIO(n)  (1ULL<<n)
#define EXTI_Num 0

 	gpio_config_t EXTI_config;
    EXTI_config.pin_bit_mask=GPIO(EXTI_Num);          /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
    EXTI_config.mode=GPIO_MODE_INPUT;         /*!< GPIO mode: set input/output mode*/    
    EXTI_config.pull_up_en = 1;              /*!< GPIO pull-up*/
    EXTI_config.pull_down_en = 0; 
    EXTI_config.intr_type=GPIO_INTR_NEGEDGE;    /*!< GPIO interrupt type*/

  这个例子通过宏定义 #define GPIO(n) (1ULL<<n) 来设定对应GPIO的位,这里就是设置 GPIO0,模式因为是外部中断所以设定为输入模式,同时因为是低电平触发,需要将IO口先拉高,所以这里使能了EXTI_config.pull_up_en = 1;将其拉高,最后一个是中断模式的设定,官方一共给出了6种中断模式,如下。

typedef enum {
    GPIO_INTR_DISABLE = 0,     /*!< Disable GPIO interrupt                             */
    GPIO_INTR_POSEDGE = 1,     /*!< GPIO interrupt type : rising edge                  */
    GPIO_INTR_NEGEDGE = 2,     /*!< GPIO interrupt type : falling edge                 */
    GPIO_INTR_ANYEDGE = 3,     /*!< GPIO interrupt type : both rising and falling edge */
    GPIO_INTR_LOW_LEVEL = 4,   /*!< GPIO interrupt type : input low level trigger      */
    GPIO_INTR_HIGH_LEVEL = 5,  /*!< GPIO interrupt type : input high level trigger     */
    GPIO_INTR_MAX,
} gpio_int_type_t;

  从上向下分别是不使能中断,上下沿触发中断,高低电平触发中断,这里使用的是下降沿触发中断。

  最后通过gpio_config函数来将结构体的设置导入到对应寄存器。

gpio_config(&EXTI_config);

接下来就是对应中断的设定。
  首先开启GPIO中断,注意这个函数并不是需要每一个GPIO中断都要使用一次,而是开启整个gpio的中断,并向当前运行的核心注册GPIO中断,也就是说你调用这个函数在哪个核心,中断处理函数就在哪个核心进行运行。函数如下:

gpio_install_isr_service(ESP_INTR_FLAG_LEVEL3);

  其中 ESP_INTR_FLAG_LEVEL3 也是一个宏定义它规定了这个中断的优先级如上文所属,所有中断优先级定义如下:

/** @brief Interrupt allocation flags
 *
 * These flags can be used to specify which interrupt qualities the
 * code calling esp_intr_alloc* needs.
 *
 */

//Keep the LEVELx values as they are here; they match up with (1<<level)
#define ESP_INTR_FLAG_LEVEL1        (1<<1)  ///< Accept a Level 1 interrupt vector (lowest priority)
#define ESP_INTR_FLAG_LEVEL2        (1<<2)  ///< Accept a Level 2 interrupt vector
#define ESP_INTR_FLAG_LEVEL3        (1<<3)  ///< Accept a Level 3 interrupt vector
#define ESP_INTR_FLAG_LEVEL4        (1<<4)  ///< Accept a Level 4 interrupt vector
#define ESP_INTR_FLAG_LEVEL5        (1<<5)  ///< Accept a Level 5 interrupt vector
#define ESP_INTR_FLAG_LEVEL6        (1<<6)  ///< Accept a Level 6 interrupt vector
#define ESP_INTR_FLAG_NMI           (1<<7)  ///< Accept a Level 7 interrupt vector (highest priority)
#define ESP_INTR_FLAG_SHARED        (1<<8)  ///< Interrupt can be shared between ISRs
#define ESP_INTR_FLAG_EDGE          (1<<9)  ///< Edge-triggered interrupt
#define ESP_INTR_FLAG_IRAM          (1<<10) ///< ISR can be called if cache is disabled
#define ESP_INTR_FLAG_INTRDISABLED  (1<<11) ///< Return with this interrupt disabled

#define ESP_INTR_FLAG_LOWMED    (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C.
#define ESP_INTR_FLAG_HIGH      (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly.

#define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \
                                 ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \
                                 ESP_INTR_FLAG_NMI) ///< Mask for all level flags

最后是注册中断回调函数开启中断:

gpio_isr_handler_add(EXTI_Num,EXIT_Handelr,NULL);

到这里一个外中断就初始化完成了。


http://www.niftyadmin.cn/n/1102382.html

相关文章

[外包]!采用asp.net core 快速构建小型创业公司后台管理系统(二.config强类型)

接着上一章继续聊这个项目 本章主要会介绍到一下几点 配置文件强类型model转化redis使用一.基础类接口的实现 1.首先创建IConfigGeter接口 接口代码如下&#xff1a; public interface IConfigGeter{TConfig Get<TConfig>(string key);TConfig Get<TConfig>();Stri…

如何使用Kubernetes里的NetworkPolicy

创建一个类型为NetworkPolicy的Kubernetes对象的yaml文件。 第九行的podSelector指定这个NetworkPolicy施加在哪些pod上&#xff0c;通过label来做pod的过滤。 从第16行开始的ingress定义&#xff0c;定义了只有具备标签componentads,moduleapp的pod才能够连接componentads, mo…

K8s 原理架构介绍(一)

一、Kubernetes 是什么 Kubernetes是当今最流行的开源容器管理平台&#xff0c;它就是大名鼎鼎的Google Borg的开源版本。Google在2014年推出了Kubernetes&#xff0c;本文发布时最新的版本是1.11。 Kubernetes源于希腊语&#xff0c;意为舵手&#xff0c;K8S是一个简称&#x…

ESP32 硬件开发指北 -- 外接FLASH使用指北

ESP32 硬件开发指北 ----外接FLASH权威指北 硬件环境&#xff1a; ESP32-D0WDESP32-D0WD-V3P25Q32H-UXH-IR USON8封装 软件环境&#xff1a; ESP-IDF V4.3 VScode插件版本 一、选型 ESP32选型&#xff1a; ESP32 将 External Flash 与 External SRAM 作为片外存储器。图1…

Pytorch —— 基础指北_壹 [什么是Torch]

Pytorch ——基础指北_壹 系列文章目录 Pytorch ——基础指北_零 Pytorch ——基础指北_壹 Pytorch ——基础指北_贰 Pytorch ——基础指北_叁 软件环境&#xff1a; pytorch 1.10pycharmCUDA 10.2 提示&#xff1a; 使用配套教程体验更好&#xff1a; youtobe教程&#…

Web开发实战——spring 应用笔记(壹)

Spring_前传(1) 软件环境&#xff1a; IDE:IDEA插件&#xff1a;spring InitializermongoDB&#xff1a;v5.0.6驱动项目类型&#xff1a;校园网项目 使用Lombok简化领域对象 领域对象(Domain Object)也被称为实体类&#xff0c;代表了业务的状态&#xff0c;贯穿表现层、业…

Spark快速大数据分析——Scala语言基础(壹)

Spark快速大数据分析——Scala语言基础&#xff08;壹&#xff09; 文章目录Spark快速大数据分析——Scala语言基础&#xff08;壹&#xff09;前记Scala的历史环境搭建&#xff1a;1、SBT构建工具和REPL&#xff1a;2、使用IDE&#xff1a;Scala 入门&#xff1a;一点点补充&a…

项目风险管理落地

发现很多做项目的同学&#xff0c;会忽略对项目风险的管理&#xff0c;以至于成为项目的救火队长&#xff0c;处理各种应急事件。为了让项目开展更顺畅&#xff0c;避免出现项目既乱又累的问题&#xff0c;不应以战术上的勤奋&#xff0c;掩盖战略上的懒惰&#xff0c;梳理总结…