Using two gpio pins to trigger an interrupt in esp-idf

Isaac_Atia
Posts: 6
Joined: Fri Jun 21, 2024 9:23 am

Using two gpio pins to trigger an interrupt in esp-idf

Postby Isaac_Atia » Fri Oct 25, 2024 5:03 pm

I am trying to trigger an interrupt using two gpio pins say A and B. The interrupt would only trigger if gpio A is a low and gpio B is a high.
This is the code I am using to set the interrupt pins and also to trigger it.

Code: Select all

gpio_config_t intr_conf = {
        .mode = GPIO_MODE_INPUT,
        .pin_bit_mask = (1ULL << ON_SIGNAL) | (1ULL << COIL_OUTPUT),
        .intr_type = GPIO_INTR_ANYEDGE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .pull_up_en = GPIO_PULLUP_DISABLE};
    ESP_ERROR_CHECK(gpio_config(&intr_conf));
}

void IRAM_ATTR ignitionOff(void *args)
{
    // uint32_t gpio_num = (uint32_t)args;
    if ((gpio_get_level(ON_SIGNAL) == 0) && (gpio_get_level(COIL_OUTPUT) == 1))
    {
        gpio_set_level(GATE_SIGNAL, 1);
        printf("interrupt triggered\n");
        // puts screen to sleep
        sendData("sleep=1");
        BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
        if (xTimerStartFromISR(xIgnitionPulseTimer, &pxHigherPriorityTaskWoken) == pdPASS)
            portYIELD_FROM_ISR();
    }
}

void vIgnitionPulseCallback(TimerHandle_t xTimer)
{
    gpio_set_level(GATE_SIGNAL, 0);
}
However, the interrupt is not triggered even if the the conditions are right. What could I be doing wrong?

username
Posts: 536
Joined: Thu May 03, 2018 1:18 pm

Re: Using two gpio pins to trigger an interrupt in esp-idf

Postby username » Fri Oct 25, 2024 9:40 pm

Is ignitionOff() your ISR handler ?

Did you use gpio_install_isr_service() & gpio_isr_handler_add() ?

If all is true, your doing way to much in the ISR. For sure, you dont want to slap a printf in there.
When it comes to ISR's you want to get in and out as fast as you can, doing as little as you can.
You should use something like xQueueSendFromISR(), to fire off another function and let that function handle your stuff.

Isaac_Atia
Posts: 6
Joined: Fri Jun 21, 2024 9:23 am

Re: Using two gpio pins to trigger an interrupt in esp-idf

Postby Isaac_Atia » Mon Oct 28, 2024 9:29 am

username wrote:
Fri Oct 25, 2024 9:40 pm
Is ignitionOff() your ISR handler ?

Did you use gpio_install_isr_service() & gpio_isr_handler_add() ?
Yes ignitionOff() is my ISR handler. Originally the printf() statement wasn't included, I just did that for debugging purposes. And yes I did use gpio_install_isr_service() and gpio_sir_handler_add(). In fact this is my implementation of those;

Code: Select all

 ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_IRAM));
 ESP_ERROR_CHECK(gpio_isr_handler_add(ON_SIGNAL, ignitionOff,(void*)ON_SIGNAL));
 ESP_ERROR_CHECK(gpio_isr_handler_add(COIL_OUTPUT, ignitionOff, (void*)COIL_OUTPUT));
since I have two gpios I am looking at to trigger the interrupt.

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: Using two gpio pins to trigger an interrupt in esp-idf

Postby eriksl » Tue Oct 29, 2024 10:13 am

You're looking for a logic AND functionality. What this code achieves is a logic OR functionality. You will need an external logic gate or implement it in software.

MicroController
Posts: 1724
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Using two gpio pins to trigger an interrupt in esp-idf

Postby MicroController » Tue Oct 29, 2024 11:42 am

Not sure if there's anything wrong in your code. Are the electrical signals 'clean'?

Just to clarify,
The interrupt would only trigger if gpio A is a low and gpio B is a high.
...
However, the interrupt is not triggered even if the the conditions are right.
- The interrupt triggers only when one of the signals changes. Is that how you tested?

And some notes:
1) Are you sure sendData() is safe to be called from an ISR?
2)

Code: Select all

        BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
        if (xTimerStartFromISR(xIgnitionPulseTimer, &pxHigherPriorityTaskWoken) == pdPASS)
            portYIELD_FROM_ISR();
should be

Code: Select all

        BaseType_t pxHigherPriorityTaskWoken = pdFALSE;
        xTimerStartFromISR(xIgnitionPulseTimer, &pxHigherPriorityTaskWoken);
        if (pxHigherPriorityTaskWoken != pdFALSE) {
            portYIELD_FROM_ISR();
        }
3) You can reduce 'false' triggering of the ISR by 50% if you configure ON_SIGNAL for GPIO_INTR_NEGEDGE and COIL_OUTPUT for GPIO_INTR_POSEDGE.


(I think the pulse counter (PCNT) could be (ab)used to do the signal-combining logic for you, giving you one interrupt only when the conditions are right.)

Isaac_Atia
Posts: 6
Joined: Fri Jun 21, 2024 9:23 am

Re: Using two gpio pins to trigger an interrupt in esp-idf

Postby Isaac_Atia » Tue Oct 29, 2024 4:29 pm

I finally solved this. I did restructure my code just to make it readable, it's not much different from the first one. I did find out that the main issue stemmed from setting on one of the gpios as an output. I noticed while searching online that, quiet a few people run into this same issue where esp-idf for some unknown reason had issues with setting some pins as an output. The interrupt type was also an issue and once I changed it, the chip stopped resetting as indicated earlier.. For anyone that may be facing the same issue here is a snippet of my code changed

Code: Select all

void gpio_init(void)
{
    gpio_config_t io_conf = {};
    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_OUTPUT;
    io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pin_bit_mask = GATE_SIGNAL;
    ESP_ERROR_CHECK(gpio_config(&io_conf));
    gpio_reset_pin(GATE_SIGNAL);
    gpio_set_direction(GATE_SIGNAL, GPIO_MODE_INPUT_OUTPUT);

    io_conf.intr_type = GPIO_INTR_POSEDGE;
    io_conf.pull_up_en = GPIO_PULLDOWN_DISABLE;
    io_conf.pin_bit_mask = INTERRUPT_PINS;
    ESP_ERROR_CHECK(gpio_config(&io_conf));
    gpio_set_intr_type(ON_SIGNAL, GPIO_INTR_NEGEDGE);
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_IRAM));
    ESP_ERROR_CHECK(gpio_isr_handler_add(ON_SIGNAL, ignitionOff, (void *)ON_SIGNAL));
    ESP_ERROR_CHECK(gpio_isr_handler_add(COIL_OUTPUT, ignitionOff, (void *)COIL_OUTPUT));
}

static void IRAM_ATTR ignitionOff(void *args)
{
    // BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    uint32_t gpio_num = (uint32_t)args;
    if ((gpio_get_level(ON_SIGNAL) == 0) && (gpio_get_level(COIL_OUTPUT) == 1))
        xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
    // portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void handle_intr_sequence(void *args)
{
    uint32_t io_num;
    for (;;) {
        if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
             gpio_set_level(GATE_SIGNAL, 1);
            sendData("sleep=1");
             xTimerStart(xIgnitionPulseTimer, portMAX_DELAY);
        }
    }
}

void vIgnitionPulseCallback(TimerHandle_t xTimer)
{
    gpio_set_level(GATE_SIGNAL, 0);
}

Who is online

Users browsing this forum: No registered users and 93 guests