ESP32-C3中断使用
- 中断系统
- 中断矩阵
- 中断映射
- CPU中断控制器
- 关键函数说明
- 头文件
- 分配中断
- 示例程序
中断系统
中断矩阵
ESP32-C3有62个外部中断©可映射到cpu的31个中断源,主要特性如下:
- 允许62个中断输入
- 输出31个中断到cpu
- 查询当前外设中断状态
- 可配置cpu中断源的优先级、类型、阈值和使能信号
Esp32-c3技术参考手册表8-1列出了所有的外部中断源。
中断映射
通过设置技术参考手册表8-1中的各个MAP寄存器可映射对应外设中断到31个cpu中断,可设置多个外设中断到同一个cpu中断,任何一个中断触发即可触发cpu中断,通过查询中断状态,确定中断来源。
清除MAP寄存器可取消中断映射。
CPU中断控制器
ESP32-C3采用中断控制器,并非ISA,cpu中断编号从1-31,每个中断都有下列特性:
- 优先级从1(最低)-15(最高)
- 可配置电平触发/边沿触发
- 通过中断阈值可屏蔽低优先级中断
每个cpu中断有下列5个属性:
- Enable State:0 == 使能
- Type:1 == 边沿触发; 0 == 电平触发
- Priority:优先级从1(最低)-15(最高),具有相同优先级的中断通过其ID确定优先级,最低ID具有最高优先级
- Pending State:触发cpu中断后,该中断首先会被挂起,若没有更高优先级的挂起中断,则响应该中断,若有更高优先级中断处于挂起状态,则该中断排队等待。挂起且已响应中断服务程序称作”claimed”,挂起但未响应中断服务程序称作”unclaimed”.
- Clear State:将INTERRUPT_CORE0_CPU_INT_CLEAR_REG寄存器相应bit先置1再置0,可清除挂起且已响应的中断。电平类型的中断无法通过该bit清除。如需清除挂起但未响应的中断,可先清除INTERRUPT_CORE0_CPU_INT_ENABLE_REG 寄存器相应bit,然后再清除状态bit。
关键函数说明
头文件
#include "hal/usb_serial_jtag_ll.h" //usb_serial外设驱动
#include "soc/periph_defs.h"//usb_serial外设相关定义
#include "esp_intr_alloc.h"
分配中断
//分配中断
esp_err_t esp_intr_alloc(
int source, //外部中断源,共计62个外部中断源
int flags, //ESP_INTR_FLAG_LEVEL1~6: 1为最低优先级 6为最高优先级; ESP_INTR_FLAG_SHARED:共享中断; ESP_INTR_FLAG_EDGE:边沿触发中断
intr_handler_t handler, //中断句柄,当优先级大于3时为NULL,因为大于3级不能被C调用
void *arg, //给中断服务程序传递的参数
intr_handle_t *ret_handle)//指向中断句柄的指针,用于释放中断,不用为NULL
//释放中断
esp_err_t esp_intr_free(intr_handle_t handle);//传入中断句柄
示例程序
本示例程序为USB_Serial_JTAG外设分配一个中断,在中断服务程序中将主机发来的数据回传,注意由于硬件缓冲区只有64Byte,因此建议一次发送数据不要大于64Byte。
为提高中断响应速度,采用 IRAM_ATTR 属性将中断服务函数放置在内部RAM,避免频繁读取flash延迟影响程序执行效率。
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "string.h"
#include "hal/usb_serial_jtag_ll.h"
#include "soc/periph_defs.h"
#include "esp_intr_alloc.h"
//#include "esp_attr.h"
static void IRAM_ATTR usb_serial_jtag_isr_handler_default(void *arg) //采用IRAM_ATTR属性将该函数放置在内部RAM
{
uint8_t *rxbuf;
uint32_t usbjtag_intr_status = 0;
rxbuf = (uint8_t *)malloc(64);
usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT)
{
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); //清除中断标志
uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(rxbuf, 64);
usb_serial_jtag_ll_write_txfifo((const uint8_t *)rxbuf, rx_fifo_len); //将接收数据回环发送
usb_serial_jtag_ll_txfifo_flush(); //刷新发送buf
}
free(rxbuf); //与malloc成对使用
}
void app_main(void)
{
esp_err_t err = ESP_OK;
intr_handle_t intr_handle;
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); //收到1包数据响应中断
err = esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LOWMED, usb_serial_jtag_isr_handler_default, NULL, &intr_handle);
if (err != ESP_OK)
{
printf("error alloc intr\n");
}
while (1)
{
vTaskDelay(pdMS_TO_TICKS(5000));
}
esp_intr_free(intr_handle);
}
注意: 使用该功能前需要禁止控制台打印到USB,否则控制台打印信息会和usb打印信息混在一起,配置如下: