How to use gpio_isr_register?

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

How to use gpio_isr_register?

Postby kolban » Mon Oct 17, 2016 4:23 am

Looking at the driver/gpio.h header file, I find a reference to gpio_isr_register() as a method for registering what appears to be an interrupt handler. Unfortunately, I'm not understanding how to properly use it. The first parameter to it is something called a "gpio_intr_num" and I'm not understanding what the comments in the header say about it. Has anyone looked into this area yet? I think I am sensing that there is also an underlying ROM based GPIO implementation but most of these APIs say not to use in the SDK.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: How to use gpio_isr_register?

Postby WiFive » Mon Oct 17, 2016 7:02 am

Read technical reference manual about interrupt matrix. Interrupt matrix maps peripheral interrupts (table 6) to CPU interrupts (table 7). CPU interrupts have one interrupt handler function, so you have to pick and choose which sources will trigger the same interrupt number and thus share a handler function. Also you have to consider priority levels, shown in table 7. In the case of gpio interrupts, there is only one signal into the interrupt matrix so they will all share the same interrupt handler and you only have to set it up once.

I tried the example in gpio.h with gpio0 and get the interrupt messages over uart when the button on devkitc is pressed.

User avatar
rudi ;-)
Posts: 1698
Joined: Fri Nov 13, 2015 3:25 pm

Re: How to use gpio_isr_register?

Postby rudi ;-) » Tue Oct 18, 2016 10:34 pm

WiFive wrote:
I tried the example in gpio.h with gpio0 and get the interrupt messages over uart when the button on devkitc is pressed.
where is the code?

:roll:

:ugeek:


@Neil

example you connect a PIR to the GPIO17
you build an alarm

https://www.mpja.com/download/31227sc.pdf

The PIR i linked has 3.3 / 0 TTL
with 5 V supply

because Nano32 has 5.0 V output too,
i connect 5 V to Power
ground to ground
TTL to GPIO 17
( bevore i test with push button )


here is a example with PIR and the Nano32 form MakerAsia & GravitechThai
IMG_5453.JPG
IMG_5453.JPG (1019.33 KiB) Viewed 19032 times


an here the code for you.
if you use in your book
please named it

credit: MakerAsia

thank you

Code: Select all



#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/gpio.h"


// 
#define INPUT_GPIO 17

// #define INPUT_GPIO_DOORBUTTON 18
// #define INPUT_GPIO_ALARMBUTTON 19

#define TAG 3


void gpioCallback (void* arg);


/******************************************************************************
 * FunctionName : hello_task
 * Description  : 
 * Parameters   : void* pvParameter
 * Returns      : 
*******************************************************************************/
void hello_task(void* pvParameter)
{
  /* Calc */
  printf("Hello, how are you?!\n");
      for (int i = 10; i >= 0; i--) {
          printf("Restarting in %d seconds...\n", i);
          vTaskDelay(1000 / portTICK_RATE_MS);
      }
      printf("Restarting now.\n");
      fflush(stdout);
      system_restart();
}

/******************************************************************************
 * FunctionName : main_task
 * Description  : 
 * Parameters   : void* pvParameter
 * Returns      : void
*******************************************************************************/
void main_task(void* pvParameter)
{
  /* Calc */
  /* Configure the IOMUX register for pad BLINK_GPIO (some pads are
         muxed to GPIO on reset already, but some default to other
         functions and need to be switched to GPIO. Consult the
         Technical Reference for a list of pads and their default
         functions.)
      */
      
      gpio_pad_select_gpio(INPUT_GPIO);
      
	  /* Set the GPIO as a input */
      gpio_set_direction(INPUT_GPIO, GPIO_MODE_INPUT);
      
	  /* Set the GPIO pull */
      gpio_set_pull_mode(INPUT_GPIO, GPIO_PULLUP_ONLY);
  
      // gpio_set_intr_type(INPUT_GPIO, GPIO_INTR_NEGEDGE);
      // gpio_set_intr_type(INPUT_GPIO, GPIO_INTR_ANYEDGE);
	  gpio_set_intr_type(INPUT_GPIO, GPIO_INTR_ANYEDGE); 
  
      gpio_intr_enable(INPUT_GPIO);
  
      // Intterrupt number see below
      gpio_isr_register(INPUT_GPIO, gpioCallback, (void *)TAG); // 17
  
  
      while(1) {
        // if you need..
        // printf( "Loop...\n" );
        // vTaskDelay(1000 / portTICK_RATE_MS);
  }
}

/******************************************************************************
 * FunctionName : gpioCallback
 * Description  : 
 * Parameters   : void* arg
 * Returns      :  
*******************************************************************************/
void gpioCallback(void* arg)
{
  /* Calc */
  uint32_t gpio_num = 0;
    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
    do {
      if(gpio_num < 32) {
		  
		  			  
        if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
		ets_printf("1 Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
           //This is an isr handler, you should post an event to process it in RTOS queue.
		   
		   / * test your self......
		   switch (gpio_intr_status & BIT(gpio_num)) {
			   
			   case 17: ets_print("GPIO 17 request\n"); break;
			   
			   case 18: ets_print("GPIO 18 request : task2 call\n"); 
						xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL); 
						break;
					   
		   } 
			* / 
		   
		  }
		// }
      } else {
        if(gpio_intr_status_h & BIT(gpio_num - 32)) {
          ets_printf("2 Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
          //This is an isr handler, you should post an event to process it in RTOS queue.
        }
      }
  } while(++gpio_num < GPIO_PIN_COUNT);
  
  /* push_status = ; */
 }

/******************************************************************************
 * * * * * * * *: main of ESP32 
 * FunctionName : app_main
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void app_main()  
{
  /* Calc */
  nvs_flash_init();
  system_init();
      
  // xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);
  xTaskCreate(&main_task, "main_task", 2048, NULL, 5, NULL);
}

output.jpg
output.jpg (67.67 KiB) Viewed 19032 times
:mrgreen:
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

jimbob
Posts: 29
Joined: Fri Aug 05, 2016 10:47 pm

Re: How to use gpio_isr_register?

Postby jimbob » Thu Oct 20, 2016 7:50 am

Thanks @rudi for the example. Just a note of caution,

I haven't triple checked yet but I think the example will only work for certain GPIO pins.

I think the first argument of gpio_isr_register lists the interrupt number -- and from the listing from soc.h, some of them are already used.

In the example interrupt number 17 was the same as the GPIO pin so it worked.

Hope that clarifies things for @kolban?

Code: Select all

//interrupt cpu using table, Please see the core-isa.h
  260 /*************************************************************************************************************
  261  *      Intr num                Level           Type                    PRO CPU usage           APP CPU uasge
  262  *      0                       1               extern level            WMAC                    Reserved
  263  *      1                       1               extern level            BT/BLE Host VHCI        Reserved
  264  *      2                       1               extern level            FROM_CPU                FROM_CPU
  265  *      3                       1               extern level            TG0_WDT                 Reserved
  266  *      4                       1               extern level            WBB
  267  *      5                       1               extern level            BT Controller 
  268  *      6                       1               timer                   FreeRTOS Tick(L1)       FreeRTOS Tick(L1)
  269  *      7                       1               software                Reserved                Reserved
  270  *      8                       1               extern level            BLE Controller 
  271  *      9                       1               extern level            
  272  *      10                      1               extern edge             Internal Timer
  273  *      11                      3               profiling
  274  *      12                      1               extern level
  275  *      13                      1               extern level
  276  *      14                      7               nmi                     Reserved                Reserved
  277  *      15                      3               timer                   FreeRTOS Tick(L3)       FreeRTOS Tick(L3)
  278  *      16                      5               timer
  279  *      17                      1               extern level
  280  *      18                      1               extern level
  281  *      19                      2               extern level
  282  *      20                      2               extern level
  283  *      21                      2               extern level
  284  *      22                      3               extern edge
  285  *      23                      3               extern level
  286  *      24                      4               extern level
  287  *      25                      4               extern level            Reserved                Reserved
  288  *      26                      5               extern level            Reserved                Reserved
  289  *      27                      3               extern level            Reserved                Reserved
  290  *      28                      4               extern edge             
  291  *      29                      3               software                Reserved                Reserved
  292  *      30                      4               extern edge             Reserved                Reserved
  293  *      31                      5               extern level            Reserved                Reserved
  294  *************************************************************************************************************
  295  */

ESP_Sprite
Posts: 8921
Joined: Thu Nov 26, 2015 4:08 am

Re: How to use gpio_isr_register?

Postby ESP_Sprite » Fri Oct 21, 2016 2:49 am

@jimbob: The interrupt number has nothing to do with the GPIO number. The GPIO mux basically allows you to pick a random interrupt for a peripheral; any that are marked as free in the table you mentioned will work.

User avatar
rudi ;-)
Posts: 1698
Joined: Fri Nov 13, 2015 3:25 pm

Re: How to use gpio_isr_register?

Postby rudi ;-) » Sat Oct 22, 2016 2:31 pm

no hurry!


hi

i get a small panic'ed
after isr fired for gpio18..

what is mean with "/queue.c:603 (xQueueGenericSend)- assert failed!"

Code: Select all


1 Intr GPIO18 ,val: 0<\r><\n>
GPIO 18 request : restart call<\r><\n>
c:/sdk32/esp-idf/components/freertos/./queue.c:603 (xQueueGenericSend)- assert failed!<\r><\n>
Guru Meditation Error: Core   0 panic'ed.<\r><\n>
Register dump:<\r><\n>
PC      : Guru Meditation Error of type LoadProhibited occurred on core   0. Exception was unhandled.<\r><\n>
Register dump:<\r><\n>
PC      :  40083456  PS      :  00060033  A0      :  80083679  A1      :  3ffb3180  <\r><\n>
A2      :  00000000  A3      :  00000002  A4      :  00000000  A5      :  00000000  <\r><\n>
A6      :  3f401044  A7      :  3ff4001c  A8      :  0000007d  A9      :  3ff4001c  <\r><\n>
A10     :  3ff4001c  A11     :  3f4002d0  A12     :  00000000  A13     :  3ffb31e0  <\r><\n>
A14     :  00000000  A15     :  3f401158  SAR     :  00000017  EXCCAUSE:  0000001c  <\r><\n>
EXCVADDR:  00000004  LBEG    :  4000c2e0  LEND    :  4000c2f6  LCOUNT  :  00000000  <\r><\n>
Rebooting...<\r><\n>
ets Jun  8 2016 00:22:57<\r><\n>





Code: Select all


/******************************************************************************
 * 
 * Espressif IoT Development Framework with the ESP32  
 *
 * ESP-IDF - 
 * the new Espressif IoT Development Framework with ESP32 from espressif 
 * github              : https://github.com/espressif/esp-idf                       
 *
 *
*******************************************************************************/

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
 
#define PIR_GPIO 17
#define BTN_GPIO 18

#define TAG 3


void gpioCallback (void* arg);


/******************************************************************************
 * FunctionName : main_task
 * Description  : 
 * Parameters   : void* pvParameter
 * Returns      : void
*******************************************************************************/
void main_task(void* pvParameter)
{
  
  /* Configure the IOMUX register for pad BLINK_GPIO (some pads are
         muxed to GPIO on reset already, but some default to other
         functions and need to be switched to GPIO. Consult the
         Technical Reference for a list of pads and their default
         functions.)
      */
      
      gpio_pad_select_gpio(PIR_GPIO);
      gpio_pad_select_gpio(BTN_GPIO);
      
	  /* Set the GPIO as a input */
      gpio_set_direction(PIR_GPIO, GPIO_MODE_INPUT);
	  gpio_set_direction(BTN_GPIO, GPIO_MODE_INPUT);
	  
	  
      
	  /* Set the GPIO pull */
      gpio_set_pull_mode(PIR_GPIO, GPIO_PULLUP_ONLY);
	  gpio_set_pull_mode(BTN_GPIO, GPIO_PULLUP_ONLY);
  
       
      // gpio_set_intr_type(INPUT_GPIO, GPIO_INTR_NEGEDGE);
	  gpio_set_intr_type(PIR_GPIO, GPIO_INTR_ANYEDGE);
      gpio_set_intr_type(BTN_GPIO, GPIO_INTR_NEGEDGE);	  
  
      gpio_intr_enable(PIR_GPIO);
	  gpio_intr_enable(BTN_GPIO);
	 
  
      // Intterrupt number see below
      gpio_isr_register(PIR_GPIO, gpioCallback, (void *)TAG); // 17
      gpio_isr_register(BTN_GPIO, gpioCallback, (void *)TAG); // 18
	  
	  
  
      while(1) {
      //   printf( "Loop...\n" );
      //  vTaskDelay(1000 / portTICK_RATE_MS);
  }
}

/******************************************************************************
 * FunctionName : gpioCallback
 * Description  : 
 * Parameters   : void* arg
 * Returns      :  
*******************************************************************************/
void gpioCallback(void* arg)
{
    uint32_t gpio_num = 0;
    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
    do {
      if(gpio_num < 32) {
        if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
		ets_printf("1 Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num));
           //This is an isr handler, you should post an event to process it in RTOS queue.
		   
		   switch (gpio_num) {
			   
			   case 17: ets_printf("GPIO 17 request\n"); break;
			   
			   case 18: ets_printf("GPIO 18 request : restart call\n"); 
			            fflush(stdout);
						system_restart();
						break;
			} 
			 
		   
		  }
		} else {
        if(gpio_intr_status_h & BIT(gpio_num - 32)) {
          ets_printf("2 Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num));
          //This is an isr handler, you should post an event to process it in RTOS queue.
        }
      }
  } while(++gpio_num < GPIO_PIN_COUNT);
  
  /* push_status = ; */
 }

/******************************************************************************
 * * * * * * * *: main of ESP32 
 * FunctionName : app_main
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void app_main()  
{
  nvs_flash_init();
  system_init();
      
  xTaskCreate(&main_task, "main_task", 2048, NULL, 5, NULL);
}

thanks
best wishes
rudi ;-)
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: How to use gpio_isr_register?

Postby WiFive » Sat Oct 22, 2016 4:18 pm

rudi ;-) wrote:

Code: Select all

			            fflush(stdout);
						

Can you do that inside ISR?

Also don't do this:

Code: Select all

// Intterrupt number see below
      gpio_isr_register(PIR_GPIO, gpioCallback, (void *)TAG); // 17
      gpio_isr_register(BTN_GPIO, gpioCallback, (void *)TAG); // 18
2nd one cancels the first one and you fell into jimbob's trap
Last edited by WiFive on Sat Oct 22, 2016 4:27 pm, edited 2 times in total.

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: How to use gpio_isr_register?

Postby WiFive » Sat Oct 22, 2016 4:22 pm

ESP_Sprite wrote:@jimbob: The interrupt number has nothing to do with the GPIO number. The GPIO mux basically allows you to pick a random interrupt for a peripheral; any that are marked as free in the table you mentioned will work.
That's why he is saying don't use it here:

Code: Select all

gpio_isr_register(INPUT_GPIO, gpioCallback, (void *)TAG); // 17
By coincidence, INPUT_GPIO = 17 so it works.

User avatar
rudi ;-)
Posts: 1698
Joined: Fri Nov 13, 2015 3:25 pm

Re: How to use gpio_isr_register?

Postby rudi ;-) » Sat Oct 22, 2016 4:35 pm

WiFive wrote:
rudi ;-) wrote:

Code: Select all

			            fflush(stdout);
						

Can you do that inside ISR?
:o ups...
WiFive wrote:

Also don't do this:

Code: Select all

// Intterrupt number see below
      gpio_isr_register(PIR_GPIO, gpioCallback, (void *)TAG); // 17
      gpio_isr_register(BTN_GPIO, gpioCallback, (void *)TAG); // 18
2nd one cancels the first one and you fell into jimbob's trap
how you register then second?
need we for each a own Callback now?

i have this mean first think

Code: Select all

   
   gpio_isr_register( (PIR_GPIO & BTN_GPIO ) , gpioCallback, (void *)TAG); // 17, 18
   
but this can not be right?..
..where is the docu ... :oops:


edit: found this..

Code: Select all


esp_err_t 	gpio_isr_register (uint32_t gpio_intr_num, void(*fn)(void *), void *arg)

Last edited by rudi ;-) on Sat Oct 22, 2016 4:41 pm, edited 1 time in total.
-------------------------------------
love it, change it or leave it.
-------------------------------------
問候飛出去的朋友遍全球魯迪

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: How to use gpio_isr_register?

Postby WiFive » Sat Oct 22, 2016 4:41 pm

No no. You do this many times:

Code: Select all

gpio_intr_enable(GPIO_NUM)
And you do this only ONCE:

Code: Select all

gpio_isr_register(UNUSED_INTERRUPT_NUM, gpioCallback, (void *)TAG);
And then you do this inside gpioCallback:

Code: Select all

do {
    if(gpio_intr_status & BIT(gpio_num))
...
  } while(++gpio_num < GPIO_PIN_COUNT);
Capisce? 8-)
Last edited by WiFive on Sat Oct 22, 2016 5:11 pm, edited 1 time in total.

Who is online

Users browsing this forum: No registered users and 117 guests