中断入门(基于ESP-IDF)
主要参考资料:
GPIO & RTC GPIO: https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/gpio.html
generic_gpio例程: https://github.com/espressif/esp-idf/tree/af25eb44/examples/peripherals/gpio/generic_gpio
中断简介
在《Unix传奇》中有这样一句话,用户态的进程/线程是三等公民、root线程是二等公民、硬件中断是一等公民。
在操作系统中,"用户态"和"内核态"是两种不同的执行级别或模式。进程和线程是用户态下的执行实体,而硬件中断处理则通常在内核态进行。这里的“三等公民”、“二等公民”和“一等公民”是形象地描述它们在资源访问权限和优先级上的不同。
ESP32的中断矩阵
ESP32-S3拥有99个外部中断源,但每个CPU最多同时处理32个中断,其中26个是外部中断,6个是内部中断。
IRAM_ATTR
IRAM_ATTR是一个宏定义,用于将特定的函数或变量指定为在IRAM(指令RAM)中运行或存储。IRAM是ESP32等芯片内部的一块特殊RAM区域,它主要用于存储那些需要在RAM中直接执行的代码,以加快代码执行速度并减少从Flash加载代码所消耗的时间。
使用IRAM_ATTR宏定义可以确保相关的代码或数据被放置在IRAM中。这对于时间关键的代码部分尤为重要,因为这些代码需要尽可能快地执行,以便及时响应中断或执行其他关键任务。通过将这部分代码放在IRAM中,可以减少CPU访问Flash所带来的延迟,因为直接从RAM中读取和执行代码通常比从Flash中读取要快得多。
例如,某些中断服务程序(ISR)需要快速响应中断事件,因此它们应该被放置在IRAM中以确保快速执行。同样,一些需要在RAM中运行的库函数或应用程序代码也可以使用IRAM_ATTR来指定它们的存储位置。
需要注意的是,IRAM的容量有限,因此应该谨慎使用IRAM_ATTR,确保只将真正需要快速执行的代码放置在IRAM中,以避免浪费宝贵的RAM资源。在ESP-IDF的文档和参考手册中,通常会详细说明IRAM的大小和使用限制,以便开发者能够正确地使用它。
在使用IRAM_ATTR前,需要先包含头文件"esp_attr.h"
代码分析
static QueueHandle_t gpio_evt_queue = NULL;
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
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)
{
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//interrupt of rising edge
io_conf.intr_type = GPIO_INTR_POSEDGE;
//bit mask of the pins
io_conf.pin_bit_mask = GPIO_OUTPUT_IO_0;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
//change gpio intrrupt type for one pin
gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);
//create a queue to handle gpio event from isr
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
//start gpio task
xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
//install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
//remove isr handler for gpio number.
gpio_isr_handler_remove(GPIO_INPUT_IO_0);
//hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0);
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
int cnt = 0;
while(1) {
printf("cnt: %d\n", cnt++);
vTaskDelay(1000 / portTICK_RATE_MS);
gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2);
}
}
原文地址:https://blog.csdn.net/qq_40773212/article/details/140606702
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!