skip external interrupts with gpio_install_isr_service() but not with gpio_isr_register()

moggiozzi
Posts: 2
Joined: Thu Feb 06, 2020 11:57 am

skip external interrupts with gpio_install_isr_service() but not with gpio_isr_register()

Postby moggiozzi » Sat Oct 30, 2021 12:00 pm

Hi guys!
I try handle external interrupt every 500 us (2000 Hz).

Code: Select all

#define USE_GPIO_ISR_SERVICE // sometime skip interrupts when use interrupt service

IRAM_ATTR static void gpio_isr_handler(void* arg)
{
#ifndef USE_GPIO_ISR_SERVICE
	uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG);   //read status to get interrupt status for GPIO0-31
	uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39
	SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status);    //Clear intr for gpio0-gpio31
	SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39
#endif
	//myCode
	BaseType_t mustYield = pdFALSE;
	vTaskNotifyGiveFromISR(my_task_handle, &mustYield);
	if (mustYield)
		portYIELD_FROM_ISR();
}

void init(void) {
	esp_err_t ret = ESP_OK;
	gpio_config_t io_conf;
	//interrupt of rising edge
	io_conf.intr_type = GPIO_INTR_NEGEDGE;
	io_conf.pin_bit_mask = ((uint64_t)1 << ADC_PIN_nDR);
	io_conf.mode = GPIO_MODE_INPUT;
	io_conf.pull_down_en = 0;
	io_conf.pull_up_en = 0;
	ret |= gpio_config(&io_conf);

	xTaskCreate(dsp_task, "my_task", 4096, NULL, MY_TASK_PRIO, &my_task_handle);

#ifdef USE_GPIO_ISR_SERVICE
	ret |= gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
	gpio_isr_handler_add(ADC_PIN_nDR, gpio_isr_handler, (void*)ADC_PIN_nDR);
#else
	gpio_intr_enable(ADC_PIN_nDR);
	gpio_set_intr_type(ADC_PIN_nDR, GPIO_INTR_NEGEDGE);
	gpio_isr_register(gpio_isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
#endif
}
Sometime ouccur interrupt skips when using gpio_install_isr_service(). IMORTANT: without hi loaded my_task wake up with vTaskNotifyGiveFromISR() interrupt skips not occur.
ERR.png
ERR.png (85.62 KiB) Viewed 3115 times

When use alternate API gpio_isr_register() interrupt skips not occur.
OK.png
OK.png (56.92 KiB) Viewed 3115 times

Why ESP32 not properly handle external interrupts with gpio_install_isr_service()?

SRJ
Espressif staff
Espressif staff
Posts: 3
Joined: Sat Oct 09, 2021 8:19 am

Re: skip external interrupts with gpio_install_isr_service() but not with gpio_isr_register()

Postby SRJ » Mon Nov 01, 2021 11:41 am

I believe you have encountered a race condition which causes interrupt being lost. Here is the Github PR link that has raised this issue: https://github.com/espressif/esp-idf/pull/6853. We do have an internal fix for this issue. Once it has be reviewed, it will be merged to master, and the PR will be closed. If you are urgent, you could try the fix in the PR.

dmitrij999
Posts: 100
Joined: Sat Mar 02, 2019 8:06 pm

Re: skip external interrupts with gpio_install_isr_service() but not with gpio_isr_register()

Postby dmitrij999 » Thu Oct 27, 2022 7:35 pm

I've just run into the trouble like that, but I see that ESP32 sometimes skips pulses ~100 us, but with CPU frequency raising from 160 MHz to 240 MHz it comes to skip them rarer.
But I see that ESP32 doesn't skip pulses in 1-2 ms even on 160 MHz, but I generated pulses with the FreeRTOS task on the apart pin.
ESP-IDF v4.4.1 used.
Is it OK?

User avatar
CseaTec
Posts: 8
Joined: Thu Jul 07, 2022 12:21 pm

Re: skip external interrupts with gpio_install_isr_service() but not with gpio_isr_register()

Postby CseaTec » Mon Feb 03, 2025 6:06 pm

I just ran into the same issue as well, just like moggiozzi. I too had two external interrupts wired into GPIO pins, both running at moderate speeds, configured with gpio_install_isr_service()/gpio_isr_handler_add(). However, I set up test pin outputs with an oscilloscope and I was able to catch instances where some interrupts would completely be missed (not defered!) if they were happening at about the same time. I wondered about configuring my own, catch-all ISR via gpio_isr_register() instead, and then I saw this post. Low and behold, I was able to resolve the issue by doing exactly this.

I am using ESP-IDF V5.4, which is the stable version for this date. Obviously, those who are responsible for the IDF have not yet fixed this issue with gpio_install_isr_service() and gpio_isr_handler_add(). Beware.

UPDATE: My fix to write my own, common GPIO ISR for my two h/w interrupts did improve things by reducing the number of missed interrupts, but it was not 100%. After doing more research into this issue, I now see that it is a hardware race issue with the ESP32, not a firmware issue. That is really disheartening. Since the collisions seem to be happening when GPIO_STATUS_W1TC_REG is written to clear an ISR bit (by the ESP-IDF or any hand-crafted firmware) while another interrupt is coming in simultaneously updating another bit in the GPIO_STATUS_REG (perhaps via GPIO_STATUS_W1TS_REG or some other hardware), it is possible that if I move one of my h/w ISR connections to a pin on the other GPIO bank (i.e. GPIO_STATUS1_REG for GPIO 32-39), it might resolve the issue. I only have two critical h/w interrupts, so I'll give this change a try.
Matteo Giovanetti
Electrical Engineer
CseaTec LLC
Pompano Beach, FL USA

Who is online

Users browsing this forum: ChatGPT-User, Google [Bot] and 8 guests