新星杯-ESP32智能硬件开发--ESP32的I/O组成-系统中断矩阵

本博文内容导读📕🎉🔥

ESP32开发板的中断矩阵、功能描述与实现、相关API和示例程序进行介绍

ESP32中断矩阵将任一外部中断源单独分配到每个CPU的任一外部中断上,提供了强大的灵活性,能适应不同的应用需求。

ESP32中断主要有以下特性:

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

包括外设中断配置寄存器、中断源、中断矩阵和中断输出寄存器。

1.外部中断源

ESP32共有71个外部中断源,有67个可以分配给两个CPU,

其余4个外部中断源只能分配给特定的CPU,每个CPU2个。GPIO_INTERRUPT_PRO和GPIO_INTERRUPT_PRO_NMI只可以分配给PRO_CPU,GPIO_INTERRUPT_APP和GPIO_INTERRUPT_APP_NMI只可以分配给APP_CPU。

因此,PRO_CPU与APP_CPU各分配到69个外部中断源。

2.CPU中断源

两个CPU(PRO_CPU和APP_CPU)各有32个中断,其中26个为外部中断。

|----|------|-------|-----|----|------|-------|-----|
| 编号 | 类别 | 种类 | 优先级 | 编号 | 类别 | 种类 | 优先级 |
| 0 | 外部中断 | 电平触发 | 1 | 16 | 内部中断 | 定时器 2 | 5 |
| 1 | 外部中断 | 电平触发 | 1 | 17 | 外部中断 | 电平触发 | 1 |
| 2 | 外部中断 | 电平触发 | 1 | 18 | 外部中断 | 电平触发 | 1 |
| 3 | 外部中断 | 电平触发 | 1 | 19 | 外部中断 | 电平触发 | 2 |
| 4 | 外部中断 | 电平触发 | 1 | 20 | 外部中断 | 电平触发 | 2 |
| 5 | 外部中断 | 电平触发 | 1 | 21 | 外部中断 | 电平触发 | 2 |
| 6 | 内部中断 | 定时器 0 | 1 | 22 | 外部中断 | 边沿触发 | 3 |
| 7 | 内部中断 | 软件 | 1 | 23 | 外部中断 | 电平触发 | 3 |
| 8 | 外部中断 | 电平触发 | 1 | 24 | 外部中断 | 电平触发 | 4 |
| 9 | 外部中断 | 电平触发 | 1 | 25 | 外部中断 | 电平触发 | 4 |
| 10 | 外部中断 | 边沿触发 | 1 | 26 | 外部中断 | 电平触发 | 5 |
| 11 | 内部中断 | 解析 | 3 | 27 | 外部中断 | 电平触发 | 3 |
| 12 | 外部中断 | 电平触发 | 1 | 28 | 外部中断 | 边沿触发 | 4 |
| 13 | 外部中断 | 电平触发 | 1 | 29 | 内部中断 | 软件 | 3 |
| 14 | 外部中断 | NMI | NMI | 30 | 外部中断 | 边沿触发 | 4 |
| 15 | 内部中断 | 定时器 1 | 3 | 31 | 外部中断 | 电平触发 | 5 |

3.分配外部中断源至CPU外部中断

**首先,**按照如下规则描述中断:记号Source_X代表某个外部中断源。记号PRO_X_MAP_REG(或 APP_X_MAP_REG)表示PRO_CPU(或 APP_CPU)的某个外部中断配置。寄存器,且此外部中断配置寄存器与外部中断源Source_X相对应。

即表4-7中"PRO_CPU(APP_CPU)-外设中断配置寄存器"一列中与"外设中断源名称"一列中的某个外部中断源处于同一行的寄存器。记号Interrupt_P表示CPU中断序号为Num_P的外部中断,Num_P的取值范围为是0~5、8~10、12~14、17~28、30~31。记号Interrupt_I表示CPU中断序号为Num_I的内部中断,Num_I的取值范围是6、7、11、15、16、29。

**其次,**根据中断源、寄存器、内外中断,可以这样描述中断矩阵控制器操作:将外部中断源Source_X分配到CPU(PRO_CPU或APP_CPU)。

寄存器PRO_X_MAP_REG(APP_X_MAP_REG)配成Num_P。Num_P可以取任意CPU外部中断值,CPU中断可以被多个外设共享。关闭CPU(PRO_CPU或APP_CPU)外部中断源Source_X。将寄存器PRO_X_MAP_REG(APP_X_MAP_REG)配成任意 Num_I。由于任何被配成 Num_I 的中断都没有连接到2 CPU上,选择特定内部中断值不会造成影响。

将多个外部中断源Source_Xn ORed分配到PRO_CPU(APP_CPU)的外部中断。将各个寄存器PRO_Xn_MAP_REG (APP_Xn_MAP_REG)配成同样的Num_P。这些外设中断都会触发CPU的Interrupt_P。

4.屏蔽CPU的NMI类型中断

中断矩阵能够根据信号PRO_CPU的NMI中断屏蔽(或APP_CPU的NMI中断屏蔽)暂时屏蔽所有被分配到PRO_CPU(或APP_CPU)的外部中断源的NMI中断。

信号PRO_CPU的NMI中断屏蔽和APP_CPU的NMI中断屏蔽分别来自外设进程号控制器。

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

读寄存器 PRO_INTR_STATUS_REG_n(APP_INTR_STATUS_REG_n)中特定位的值就可以获知外部中断源当前的中断状态。

寄存器PRO_INTR_STATUS_REG_n(APP_INTR_STATUS_REG_n)与外部中断源的对应关系。

中断类型定义

中断的大多数功能与GPIO有关,从GPIO的头文件中有很多定义和函数是针对中断的,本节对其主要的定义和函数进行总结。在gpio_types.h或者gpio.h,头文件中的预定义。gpio_int_type_t是ESP32中断类型的定义,是枚举类型,定义如下:

cpp 复制代码
typedef enum {
    GPIO_INTR_DISABLE = 0,     /*禁用GPIO中断*/
    GPIO_INTR_POSEDGE = 1,     /*GPIO中断类型:上升沿*/
    GPIO_INTR_NEGEDGE = 2,     /*GPIO中断类型:下降沿*/
    GPIO_INTR_ANYEDGE = 3,     /*GPIO中断类型:上升和下降沿*/
    GPIO_INTR_LOW_LEVEL = 4,   /*GPIO中断类型:低电平触发*/
    GPIO_INTR_HIGH_LEVEL = 5,  /*GPIO中断类型:高电平触发*/
    GPIO_INTR_MAX,
} gpio_int_type_t;

中断示例程序

基于ESP IDF的VS Code、Arduino和MicroPython环境的三种代码实现。

本程序将GPIO18定义为输出,GPIO4定义为输入,上拉状态,从上升沿触发中断,将GPIO18与GPIO4通过导线直接连接,GPIO18产生的脉冲触发,开始计数,对GPIO4进行余4运算,每隔4s产生中断,在串口打印中断信息。

1. 基于ESP IDF的VS Code开发环境实现方式

代码如下:

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#define GPIO_OUTPUT_IO_0    18
#define GPIO_OUTPUT_PIN_SEL  (1ULL<<GPIO_OUTPUT_IO_0)
#define GPIO_INPUT_IO_0     4
#define GPIO_INPUT_PIN_SEL  (1ULL<<GPIO_INPUT_IO_0)
#define ESP_INTR_FLAG_DEFAULT 0
static xQueueHandle gpio_evt_queue = NULL;          //FreeRTOS的队列句柄
static void IRAM_ATTR gpio_isr_handler(void* arg)     //函数gpio_isr_handler的调用规范
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);    
}
static void gpio_task_example(void* arg)               //构建任务
{
    uint32_t io_num;
    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {  //接收队列
            printf("GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
        }
    }
}
void app_main(void)                                  //主函数
{
    gpio_config_t io_conf;                            //定义结构体
    io_conf.intr_type = GPIO_PIN_INTR_DISABLE;      //禁用中断
    io_conf.mode = GPIO_MODE_OUTPUT;            //设置输出模式
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;    //GPIO18的比特掩码
    io_conf.pull_down_en = 0;                         //禁用下拉模式
    io_conf.pull_up_en = 0;                           //禁用上拉模式
    gpio_config(&io_conf);                           //使用以上参数初始化GPIO
    io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;     //上升沿触发中断
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;      //GPIO4的比特掩码
    io_conf.mode = GPIO_MODE_INPUT;              //设置输入模式
    io_conf.pull_up_en = 1;                           //使能上拉模式
    gpio_config(&io_conf);                           //使用以上参数配置
    gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));  //创建队列处理中断
    xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL); //开启任务
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);  //安装GPIO中断服务
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
//GPIO引脚挂钩ISR处理程序
    int cnt = 0;
    while(1) {
        printf("cnt: %d\n", cnt++);                       //打印计数
        vTaskDelay(1000 / portTICK_RATE_MS);         //延时1S
        gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 4);     //每隔4个计数,打印一次中断
        //gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
    }
}

2. Arduino开发环境实现

代码如下:

cpp 复制代码
void callBack(void)
{
  Serial.printf("GPIO 4 Interrupted\n");
}
void setup()
{
  Serial.begin(115200);                //设置串口监视器波特率
  Serial.println();
  pinMode(18, OUTPUT);              //GPIO18为输出模式
  pinMode(4, INPUT);                 //GPIO4为输入模式
  attachInterrupt(4, callBack, RISING);   //上升沿触发中断
}
int cnt = 0;
void loop()                         //主函数
{
    Serial.printf("cnt: %d\n", cnt++);    //打印计数
    digitalWrite(18, cnt % 4);         //每隔4个计数,打印一次中断
    delay(1000);                   //延时1S
    //detachInterrupt(4); //关闭中断
}

3. MicroPython开发环境实现

代码如下:

cpp 复制代码
import time
import machine
from machine import Pin 
GPIO_OUTPUT=Pin(18,Pin.OUT)
GPIO_INPUT=Pin(4,Pin.IN, Pin.PULL_UP)
cnt=0                          #定义计数
interrupt = 0
interruptsCounter = 0              #计算中断事件次数
def callback(pin):                 #定义回调函数
  global interrupt, interruptsCounter  #声明为全局变量
  interrupt = 1
  interruptsCounter = interruptsCounter+1
GPIO_INPUT.irq(trigger=Pin.IRQ_RISING, handler=callback)
while True:
    GPIO_OUTPUT.value(cnt%4)
    time.sleep(1)
    cnt=cnt+1
    if interrupt:
        #state = machine.disable_irq()  #禁用计数器
        interrupt = 0
        #machine.enable_irq(state)  #重新启动计数器
        print("Interrupt has occurred: " + str(interruptsCounter))
相关推荐
AiNightVision12 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
mk0152 天前
单片机同步降压稳压器输出最低1V,关断时损耗3uA
单片机·嵌入式硬件·硬件工程·智能硬件·pcb工艺
领麦微红外3 天前
红外测温传感器 赋能充电桩热安全与运维智能化
运维·安全·产品经理·智能硬件
聆思科技AI芯片5 天前
【AI硬件开发上手教程】怎么使用AI编程实现小聆AI语音控制舵机
人工智能·嵌入式硬件·开源·ai编程·智能硬件
AiNightVision7 天前
星光级 是什么?——星光级摄像机是什么?0.001Lux 照度门槛与选型真相
人工智能·算法·车载系统·自动驾驶·无人机·视频·智能硬件
美摄科技8 天前
智能硬件如何增加一键成片剪辑功能?
数码相机·智能手机·智能硬件
光子物联单片机9 天前
ESP32传感器模块编程实践(一)DIY智能WIFI视频控制小车
嵌入式硬件·esp32·智能硬件·硬件
蒲公英内测分发9 天前
智能家居厂商有多个产品线,包装上的 App 下载入口该共用还是分开?
android·人工智能·数码相机·机器人·智能家居·智能硬件
老孟说禅11 天前
测试中的安全规范
智能硬件
Industio_触觉智能12 天前
把NPU检测直接嵌进采集终端|RK3576 AI采集终端全链路拆解教程-上
人工智能·嵌入式硬件·硬件架构·硬件工程·智能硬件·npu·rk3576