Stack Overflow issue in GPIO Callback for Interrupt

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Wed Jan 04, 2017 11:52 am

Hi,

I have created one sample application in which i am just registering one GPIO as interrupt in which one task i have created into that callback when interrupt has been raised.

But, I am getting "***ERROR*** A stack overflow in task IDLE has been detected." while creating any task as well as putting some delays using xTaskDelay API. I have also checked with normal call instead of task with some delay and i am getting same stack overflow issue after that.

Code: Select all

	void gpio_task(void* pvParameter)
	{	
	gpio_config_t io_conf;
	//io_conf.intr_type = GPIO_INTR_POSEDGE;             		//enable positive edge interrupt
	io_conf.intr_type = GPIO_INTR_NEGEDGE;             		//enable positive edge interrupt
	io_conf.mode = GPIO_MODE_INPUT;                       	//set as output mode
	io_conf.pin_bit_mask = GPIO_SEL_21;      				//bit mask of the pins that you want to set,e.g.GPIO18/19
	io_conf.pull_down_en = 0;                              	//disable pull-down mode
	io_conf.pull_up_en = 1;                                	//disable pull-up mode
	gpio_config(&io_conf);

	ESP_LOGI(TAG, "zb_tlink_esp_task called..\n");

	ESP_LOGI(TAG,"INPUT_GPIO into zb_tlink_esp_task :: %d\n",gpio_get_level(INPUT_BUTTON_GPIO));
	
	// Intterrupt number see below
	//gpio_isr_register(gpioCallback, INPUT_BUTTON_GPIO, gpioCallback, NULL); // 17
	gpio_isr_register(gpioCallback, NULL, 0, NULL); // 17

	ESP_LOGI(TAG, "zb_tlink_esp_task before while(1) loop..\n");
	
	while(1) {
		vTaskDelay(500 / portTICK_PERIOD_MS);
	}
	}
	
	void IRAM_ATTR gpioCallback(void* arg)
{
	gpio_config_t io_conf;
	
	//GPIO intr process
	ESP_LOGI(TAG,"in gpio_intr callback...\n");
	uint32_t gpio_num = INPUT_BUTTON_GPIO;
	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
			
				ESP_LOGI(TAG,"creating esp_reset_ap_mode_task...\n");
				
				xTaskCreate(&esp_reset_ap_mode_task, "esp_reset_ap_mode_task", 2048, NULL, 5, &esp_reset_ap_mode_task_handler);
			}
		} else {
			if(gpio_intr_status_h & BIT(gpio_num - 32)) {
				ets_printf("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);
}

/******************************************************************************
 * FunctionName : esp_reset_ap_mode_task
 * Description  : 
 * Parameters   : void* pvParameter
 * Returns      : void
*******************************************************************************/
void esp_reset_ap_mode_task(void)
{
	int count = 1;
	gpio_config_t io_conf;
	
	ESP_LOGI(TAG,"Intr GPIO%d ,val: %d\n",INPUT_BUTTON_GPIO,gpio_get_level(INPUT_BUTTON_GPIO));
	
	while ((count <= 6) && (gpio_get_level(INPUT_BUTTON_GPIO) == 0))
	{
		vTaskDelay(500 / portTICK_PERIOD_MS);
		count++;
	}
	
	if ( count == 6)
	{
		ESP_LOGI(TAG, "setting AP MODE on system restart...\n");		
	}
	else
	{
		ESP_LOGI(TAG, "setting STA MODE on system restart...\n");		
	}
}
	
So, does anyone has any idea or clue for this type of issue?
Regards,
Ritesh Prajapati

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Wed Jan 04, 2017 10:02 pm

Any update on this issue?
Regards,
Ritesh Prajapati

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby ESP_igrr » Thu Jan 05, 2017 12:45 am

Ouch, ESP_LOGI in in interrupt... Please check documentation for the logging library; ESP_LOG functions should not be used in an interrupt context.

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Thu Jan 05, 2017 1:49 am

ESP_igrr wrote:Ouch, ESP_LOGI in in interrupt... Please check documentation for the logging library; ESP_LOG functions should not be used in an interrupt context.
So, I can not use ESP_LOGI into interrupt callback function for any GPIO. Correct?

Can I use normal printf or ets_printf function instead of ESP_LOGI function for debugging purpose?

Are you sure the issue is of ESP_LOGI which are used in callback function?
Regards,
Ritesh Prajapati

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

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby WiFive » Thu Jan 05, 2017 2:06 am

Ritesh wrote:So, I can not use ESP_LOGI into interrupt callback function for any GPIO. Correct?
Yes, for any isr including gpio and other. Yes, try ets_printf

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

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby kolban » Thu Jan 05, 2017 3:20 am

This is purely a guess on my part .... it may be that even ets_printf() might not work ... the reason for that *may* be that ets_printf() attempts to drive the UART output and it is the UART output that may be invalid for execution in ISRs. IFF that is the case and there isn't already an architected solution, tricks I have seen in other environments include:

1. Redirecting output away from a UART and into a memory buffer.
or
2. Writing output to a fast in memory queue and dumping the queue back in "application space" periodically.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Thu Jan 05, 2017 5:19 pm

WiFive wrote:
Ritesh wrote:So, I can not use ESP_LOGI into interrupt callback function for any GPIO. Correct?
Yes, for any isr including gpio and other. Yes, try ets_printf
I have commented all debug print statements but still facing same issue.

Do you have any other idea or clue for this type of issue?
Regards,
Ritesh Prajapati

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Thu Jan 05, 2017 5:20 pm

kolban wrote:This is purely a guess on my part .... it may be that even ets_printf() might not work ... the reason for that *may* be that ets_printf() attempts to drive the UART output and it is the UART output that may be invalid for execution in ISRs. IFF that is the case and there isn't already an architected solution, tricks I have seen in other environments include:

1. Redirecting output away from a UART and into a memory buffer.
or
2. Writing output to a fast in memory queue and dumping the queue back in "application space" periodically.
Yes. You are right. Do you have any idea or thought for this issue and how to come out from this issue?
Regards,
Ritesh Prajapati

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

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby kolban » Thu Jan 05, 2017 5:39 pm

I think we have to realize that there are limitations on what one can sensibly do in an "Interrupt Service Routine" ... the way I think about it (which might be woolly) is that the CPU is happily ticking along ... all is well ... its running its programs ... and then an event happens ... this may be time based or it may be an external interrupt such as an electrical signal change ... but it is an "interrupt". Think of the English language usage here ... an "interrupt" is not always a good thing ... and typically it means that we want to go back to what we were originally doing when we started.

In my real world, someone at my door and ringing my door bell is an interrupt. When they ring, they don't know what I may be doing in my house. If I'm reading a book, I'll get up and answer the door ... no issues. However, if I'm in the middle of eating dinner then I want to get back to my dinner as quickly as possible before it gets cold. There are also technical limitations on what you can do during an interrupt ... for example (and try not to think about this too much) ... if I am in the shower, I may wrap a towel around me to answer the door. If the person at the door is my neighbor who needs help moving some boxes ... I'm not going to be able to walk out the door there and then to assist. Instead, what we have to do is arrange a time in the future where I can service his request ... this will involve me finishing my shower, getting dressed and then ... when it suits me ... go help him schlep the boxes.

And this is where you are ... when an interrupt occurs and you get control in your interrupt service routines ... you want to get "in and out" as quickly as possible AND you are constrained in what you can do in those routines. If you want to write debug information to the serial port while in the ISR ... sorry ... tough ... you can't. It isn't a limitation (opinion) that is unreasonable. Its just "the rules" ... so as long as you play by the rules, you will be ok. Do we have a detailed list of those rules ... probably not ... but some of the big ones are:

1) Don't spend a long time in the ISR. Specifically, don't block or try and perform tasks that themselves may generate interrupts (eg. writing to serial may cause an interrupt ...). How do you handle an interrupt ... that causes an interrupt ... that causes an interrupt ... you will run out of stack (Oh ... that's likely what happened to you).

2) Check for side-effect rules. Historically, the things you could do in an ISR were limited ... for example, if you grossly changes the state of the environment in an ISR ... when you return to where you came from, things may not be as the originally setup environment thought they would be. These are dangerous problems ... because we don't know when an interrupt will exactly occur and we can't sensibly test for an interrupt happening in all possible places in our code. My advice ... don't change global state in an ISR.

So what can you do? Probably things like register that the interrupt happened or respond to the interrupt directly.

Let's turn the puzzle around. Come back with a detailed description of what you are doing or want to do in your ISR.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

Ritesh
Posts: 1365
Joined: Tue Sep 06, 2016 9:37 am
Location: India
Contact:

Re: Stack Overflow issue in GPIO Callback for Interrupt

Postby Ritesh » Thu Jan 05, 2017 5:55 pm

kolban wrote:I think we have to realize that there are limitations on what one can sensibly do in an "Interrupt Service Routine" ... the way I think about it (which might be woolly) is that the CPU is happily ticking along ... all is well ... its running its programs ... and then an event happens ... this may be time based or it may be an external interrupt such as an electrical signal change ... but it is an "interrupt". Think of the English language usage here ... an "interrupt" is not always a good thing ... and typically it means that we want to go back to what we were originally doing when we started.

In my real world, someone at my door and ringing my door bell is an interrupt. When they ring, they don't know what I may be doing in my house. If I'm reading a book, I'll get up and answer the door ... no issues. However, if I'm in the middle of eating dinner then I want to get back to my dinner as quickly as possible before it gets cold. There are also technical limitations on what you can do during an interrupt ... for example (and try not to think about this too much) ... if I am in the shower, I may wrap a towel around me to answer the door. If the person at the door is my neighbor who needs help moving some boxes ... I'm not going to be able to walk out the door there and then to assist. Instead, what we have to do is arrange a time in the future where I can service his request ... this will involve me finishing my shower, getting dressed and then ... when it suits me ... go help him schlep the boxes.

And this is where you are ... when an interrupt occurs and you get control in your interrupt service routines ... you want to get "in and out" as quickly as possible AND you are constrained in what you can do in those routines. If you want to write debug information to the serial port while in the ISR ... sorry ... tough ... you can't. It isn't a limitation (opinion) that is unreasonable. Its just "the rules" ... so as long as you play by the rules, you will be ok. Do we have a detailed list of those rules ... probably not ... but some of the big ones are:

1) Don't spend a long time in the ISR. Specifically, don't block or try and perform tasks that themselves may generate interrupts (eg. writing to serial may cause an interrupt ...). How do you handle an interrupt ... that causes an interrupt ... that causes an interrupt ... you will run out of stack (Oh ... that's likely what happened to you).

2) Check for side-effect rules. Historically, the things you could do in an ISR were limited ... for example, if you grossly changes the state of the environment in an ISR ... when you return to where you came from, things may not be as the originally setup environment thought they would be. These are dangerous problems ... because we don't know when an interrupt will exactly occur and we can't sensibly test for an interrupt happening in all possible places in our code. My advice ... don't change global state in an ISR.

So what can you do? Probably things like register that the interrupt happened or respond to the interrupt directly.

Let's turn the puzzle around. Come back with a detailed description of what you are doing or want to do in your ISR.
Thanks for explanation in details with routine example.

Please see my below requirements for GPIO interrupt.

1) We have one button in our product and purpose of that button is multiple w.r.t. press event and its duration.

2) On shot press event like press and release within 1 to 2 second should restart ESP or should perform other action if pressed from more than 3 seconds.

So that is why I have chossed GPIO interrupt instead of polling base to fulfill that requirement.

Let me know if need any further informations from my side.
Regards,
Ritesh Prajapati

Who is online

Users browsing this forum: No registered users and 164 guests