[分享] 软件如何解决 ESP32 GPIO 中断丢失的问题

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

[分享] 软件如何解决 ESP32 GPIO 中断丢失的问题

Postby ESP_houwenxiang » Tue May 21, 2019 12:59 pm

ESP32 共有 40 个 GPIO, 每个 GPIO 都可响应外部中断, 中断触发模式有边沿触发和电平触发. 其中 GPIO0 ~ GPIO31 中断状态由寄存器 GPIO_STATUS_W1TC_REG 清除, GPIO32 ~ GPIO39 中断状态由寄存器 GPIO_STATUS1_W1TC_REG 清除. 在清除中断状态时, 如果位于同一组寄存器的 GPIO 刚好产生中断, 很有可能会导致该中断丢失. 即在置位 GPIO_STATUS_W1TC_REG 中某一 bit 时, 如果 GPIO0~GPIO31 刚好有一个 GPIO 产生一个中断, 则该中断很有可能会丢失. GPIO32~GPIO39 同理. 但在置位 GPIO_STATUS_W1TC_REG 时, 不会导致 GPIO32~GPIO39 的中断丢失. 该问题只会导致边沿触发类型的中断丢失. 下面介绍如何通过软件来解决这个问题.

对于电平触发的中断, 当触发电平有效时, 中断状态被清除, 硬件会继续产生中断, 所以电平触发的中断不会丢失. 解决中断丢失的方案就是使用电平触发的中断, 以下的示例代码将在高电平的时候产生一次中断, 与 rising edge 类型中断效果相同.

Code: Select all


const uint64_t INPUT_PIIN_MASK = (1ULL<<GPIO_NUM_34) | (1ULL<<GPIO_NUM_36) | (1ULL<<GPIO_NUM_39);
typedef struct io_isr_param_ {
    uint32_t io_tagle;
    uint32_t io_number;
    uint32_t isr_cnt;
} io_isr_param_t;

uint32_t isr_mode[2] = {GPIO_INTR_HIGH_LEVEL, GPIO_INTR_LOW_LEVEL};

io_isr_param_t io34_param = {
    .io_tagle = 0x1,
    .io_number = 34,
};

io_isr_param_t io36_param = {
    .io_tagle = 0x1,
    .io_number = 36,
};

io_isr_param_t io39_param = {
    .io_tagle = 0x1,
    .io_number = 39,
};

IRAM_ATTR void gpio_isr(void *param)
{
    io_isr_param_t *io_param = (io_isr_param_t *)param;
    if(io_param->io_tagle) {
        //do some thing here;
    }
    gpio_set_intr_type(io_param->io_number, isr_mode[io_param->io_tagle]);
    io_param->io_tagle ^= 0x1;
}

void io_init(void)
{
    gpio_config_t io_conf = {
        .intr_type = GPIO_PIN_INTR_DISABLE,
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = INPUT_PIIN_MASK,
        .pull_down_en = 0,
        .pull_up_en = 1,
    };
    //configure GPIO with the given settings
    gpio_config(&io_conf);
    if(gpio_install_isr_service( 0 ) != ESP_OK) {
        printf("ISR install fail\n");
        return;
    }
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_NUM_34, gpio_isr, (void*) &io34_param);
    gpio_isr_handler_add(GPIO_NUM_36, gpio_isr, (void*) &io36_param);
    gpio_isr_handler_add(GPIO_NUM_39, gpio_isr, (void*) &io39_param);
    gpio_set_intr_type(GPIO_NUM_34, GPIO_INTR_HIGH_LEVEL);
    gpio_intr_enable(GPIO_NUM_34);
    gpio_set_intr_type(GPIO_NUM_36, GPIO_INTR_HIGH_LEVEL);
    gpio_intr_enable(GPIO_NUM_36);
    gpio_set_intr_type(GPIO_NUM_39, GPIO_INTR_HIGH_LEVEL);
    gpio_intr_enable(GPIO_NUM_39);
}

以上代码可以解决中断丢失的问题, 但是带来的代价是中断次数会加倍(相对于 rising edge 和 falling edge )
wookooho

Who is online

Users browsing this forum: No registered users and 150 guests