中断入门(基于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);
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值