Using Interrupts on the UART

fofi144
Posts: 7
Joined: Fri Jan 18, 2019 5:09 pm

Using Interrupts on the UART

Postby fofi144 » Tue Jan 22, 2019 4:03 pm

Hi,

I'm having some problems with the RX of the Uart.

What i want to do: I want to detect a series of five 0x55 on a RS485-bus and trigger an interrupt. My data packets for testing look like this:

Code: Select all

0x55|0x55|0x55|0x55|0x55|0x10|0x20|0x30|0x40|0xFF
My little test project:

Code: Select all

#include "CT10_Transceive.h"

void CT10_Uart_Init()
{	
	// Set HW Uart
	uart_config_t uart_config = {
		.baud_rate = 115200,
		.data_bits = UART_DATA_8_BITS,
		.parity = UART_PARITY_DISABLE,
		.stop_bits = UART_STOP_BITS_1,
		.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
		.rx_flow_ctrl_thresh = 10,
	};
	ESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));
	
	
	// Set UART pins(TX: IO25, RX: IO26, RTS: IO18, CTS: IO19)
	ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, 25, 26, 27, UART_PIN_NO_CHANGE));
	
	
	// Install UART driver using an event queue here
	ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, 129, 129, NULL, NULL, NULL));
	
	
	//Set Pattern ISR
	//Detect the 0x55 series of five
	//30us timeout, 1,5ms Pre_idle, 1ms post idle
	ESP_ERROR_CHECK(uart_isr_free(UART_NUM_2)); 
	ESP_ERROR_CHECK(uart_isr_register(UART_NUM_2, pattern_isr, NULL, ESP_INTR_FLAG_IRAM, NULL))
	ESP_ERROR_CHECK(uart_enable_pattern_det_intr(UART_NUM_2, 0x55, 5, 2400, 80000, 120000));
	
	
	// Set Halfduplex Mode
	ESP_ERROR_CHECK(uart_set_mode(UART_NUM_2, UART_MODE_RS485_HALF_DUPLEX));	
	
}


static void IRAM_ATTR pattern_isr(void *para)
{
	//Clear Interrupt and send message
	uart_clear_intr_status(UART_NUM_2,UART_AT_CMD_CHAR_DET_INT_CLR);
	uart_write_bytes(UART_NUM_2,(const char*) "OK" , 2);
}

Code: Select all

#ifndef CT10_Trans_H
#define CT10_Trans_H

#include <stdio.h>
#include "driver/timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/uart.h"
#include "esp_log.h"


//function constructors
void CT10_Uart_Init();
static void IRAM_ATTR pattern_isr(void *para);

#endif

Code: Select all

#include <stdio.h>
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/timer_group_struct.h"
#include "driver/periph_ctrl.h"
#include "driver/timer.h"
#include "HW_Timers2.h"
#include "CT10_Transceive.h"


void app_main()
{

	//Uart init
	CT10_Uart_Init();	
	
	
}
So, what happens? As soon as my computer sends a data packet to the ESP32 it crashes.

Code: Select all

Guru Meditation Error: Core  0 panic'ed (Interrupt wdt timeout on CPU0)
Core 0 register dump:
PC      : 0x40087516  PS      : 0x00060234  A0      : 0x80086aee  A1      : 0x3ffb04d0  
A2      : 0x3ffb6e20  A3      : 0x3ffb55b0  A4      : 0x00060221  A5      : 0x00000001  
A6      : 0x00060221  A7      : 0x00000000  A8      : 0x3ffb55b0  A9      : 0x3ffb55b0  
A10     : 0x00000019  A11     : 0x00000019  A12     : 0x40082060  A13     : 0x00000001  
A14     : 0x00060223  A15     : 0x3ffb0cf0  SAR     : 0x0000001d  EXCCAUSE: 0x00000005  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  
Core 0 was running in ISR context:
EPC1    : 0x40086107  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x40087516

Backtrace: 0x40087516:0x3ffb04d0 0x40086aeb:0x3ffb04f0 0x400858e4:0x3ffb0510 0x400849bb:0x3ffb0550 0x400e2ad2:0x3ffb0580 0x400e345d:0x3ffb05c0 0x4008205d:0x3ffb05f0 0x40082a8d:0x3ffb0610 0x4008205d:0x00000000

Core 1 register dump:
PC      : 0x40084edb  PS      : 0x00060034  A0      : 0x80085e4d  A1      : 0x3ffb5b10  
A2      : 0x3ffb1070  A3      : 0x3f4035a0  A4      : 0x00000014  A5      : 0x3ffb0bd0  
A6      : 0x3ffb0c18  A7      : 0x00000001  A8      : 0x0000cdcd  A9      : 0x0000abab  
A10     : 0x00060023  A11     : 0xb33fffff  A12     : 0x0000cdcd  A13     : 0x3ffb0ba0  
A14     : 0x00000008  A15     : 0x00000001  SAR     : 0x00000018  EXCCAUSE: 0x00000005  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  

Backtrace: 0x40084edb:0x3ffb5b10 0x40085e4a:0x3ffb5b30 0x40085090:0x3ffb5b50 0x40085042:0xa5a5a5a5

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x1e (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:6184
load:0x40078000,len:10168
load:0x40080400,len:6632
entry 0x40080764
So the interrupt watchdog triggerd. But why? In the documentation of the API there is a note, not to use ESP_INTR_FLAG_IRAM. I tried that, but then the processor crashes while using uart_isr_register(). Of course the ISR function was changed to " void pattern_isr(void *para)" for testing this . I also looked trough many codes here in the forum and on several github projects, but they all use the ISR in the IRAM :| .

So.....after two days of trying....im asking you for help guys

Greetings from Germany,
Florian

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

Re: Using Interrupts on the UART

Postby ESP_Sprite » Wed Jan 23, 2019 2:23 am

If you're in an ISR, calling any function that uses a (non-ISR-specific) FreeRTOS function is illegal. You use two UART functions in your ISR, of which at least the latter likely uses a FreeRTOS function. Suggest you use the ISR to set a semaphore instead, then spin up a task to block on that semaphore and then do the sending.

fofi144
Posts: 7
Joined: Fri Jan 18, 2019 5:09 pm

Re: Using Interrupts on the UART

Postby fofi144 » Wed Jan 23, 2019 9:25 am

Hi ESP_Sprite,

thanks for the fast answer. You're right, this caused the triggering of the interrupt watchdog :oops: . So now I'm using the xTaskNotifyfromISR() function to unblock my handler task. Here's my current code:

Code: Select all

#include <stdio.h>
#include "esp_types.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/timer_group_struct.h"
#include "driver/periph_ctrl.h"
#include "CT10_Transceive.h"


void Patterndetect_ISR_Handle(void *para)
{		
		
	while (true)
	{
		
		size_t buffered_size;
		
		xTaskNotifyWait(0x00, 0xffffffff, NULL, portMAX_DELAY);
		
		ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM_2, &buffered_size));
		int pos = uart_pattern_pop_pos(UART_NUM_2);
		
		//Flush Buffer to avoid new interrupt
		//if not flushed, the interrupt keeps triggering again after clearing intr status
		uart_flush_input(UART_NUM_2);
		
		uart_clear_intr_status(UART_NUM_2, UART_AT_CMD_CHAR_DET_INT_CLR);
		printf("Pattern detected\n");
		printf("Pattern position: %d , Buffered Size: %d\n",pos,buffered_size);
		
	}	
	
}


void app_main()
{
	static TaskHandle_t UART_Patterndetect_Handle;
			
	//Create Task
	xTaskCreate(Patterndetect_ISR_Handle, "Uart Patterndetect", 2048, NULL, 1, &UART_Patterndetect_Handle);
	
	
	//Uart init
	CT10_Uart_Init(&UART_Patterndetect_Handle);	
	
	
}

Code: Select all

#include "CT10_Transceive.h"

void CT10_Uart_Init(TaskHandle_t *TaskHandle_p)
{	
	// Set HW Uart
	uart_config_t uart_config = {
		.baud_rate = 115200,
		.data_bits = UART_DATA_8_BITS,
		.parity = UART_PARITY_DISABLE,
		.stop_bits = UART_STOP_BITS_1,
		.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
	};
	ESP_ERROR_CHECK(uart_param_config(UART_NUM_2, &uart_config));
	
	
	// Set UART pins(TX: IO25, RX: IO26, RTS: IO18, CTS: IO19)
	ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, 25, 26, 27, UART_PIN_NO_CHANGE));
	
	
	// Install UART driver using an event queue here
	ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, 129, 0, NULL, NULL, NULL));
	
	
	//Set Pattern ISR
	//Detect the 0x55 series of five
	//30us timeout, 1,5ms Pre_idle, 1ms post idle
	ESP_ERROR_CHECK(uart_isr_free(UART_NUM_2)); 
	ESP_ERROR_CHECK(uart_isr_register(UART_NUM_2, pattern_isr, (void*) TaskHandle_p, ESP_INTR_FLAG_IRAM, NULL))
	ESP_ERROR_CHECK(uart_enable_pattern_det_intr(UART_NUM_2, 0x55, 5, 2400, 10, 10));
	ESP_ERROR_CHECK(uart_pattern_queue_reset(UART_NUM_2, 20) );
		
	// Set Halfduplex Mode
	ESP_ERROR_CHECK(uart_set_mode(UART_NUM_2, UART_MODE_RS485_HALF_DUPLEX));	
	
}


static void IRAM_ATTR pattern_isr(void *para)
{
	TaskHandle_t *TaskHandleinISR_p = (TaskHandle_t *)para;
		
	//Notify task and force a task switch
	xTaskNotifyFromISR(*TaskHandleinISR_p, 0x00, eNoAction, NULL);
	portYIELD_FROM_ISR();
	
}

Code: Select all

#ifndef CT10_Trans_H
#define CT10_Trans_H

#include <stdio.h>
#include "driver/timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/uart.h"
#include "esp_log.h"


//function constructors
void CT10_Uart_Init(TaskHandle_t *TaskHandle_p);
static void IRAM_ATTR pattern_isr(void *para);

#endif
First of all: No crashes yet :lol: . I have a problem with the ISR being called as soon as the uart receives a character. It doesn't have to be a special character or a series of 0x55, it triggers as soon as anything is being received. So I looked at the serial monitor to see how much was beeing received. Heres the Output after sending one char (0x20):

Code: Select all

Pattern detected
Pattern position: -1 , Buffered Size: 0
Pattern detected
Pattern position: -1 , Buffered Size: 0
The handler was called two times and everytime the buffer was empty and no pattern received :| . So, in my understanding, there should be nothing in the buffer and also nothing to flush with uart_flush_input() here. But as soon as i uncomment it, the handler is beeing called again and again till the interrupt watchdog is beeing triggered. What am i missing here?

Greetings,
Florian

fofi144
Posts: 7
Joined: Fri Jan 18, 2019 5:09 pm

Re: Using Interrupts on the UART

Postby fofi144 » Mon Jan 28, 2019 9:40 am

Any ideas?

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

Re: Using Interrupts on the UART

Postby ESP_Sprite » Tue Jan 29, 2019 3:03 am

Looking at your code a bit better, I think you're not using the driver correctly... you're supposed to either use uart_driver_install() so you can use all the nice queued read functions etc, or use uart_isr_register() to install your own ISR and handle all hardware things yourself. In your particular case, I'd go with the drivers approach and the event driven system it offers. See e.g. esp-idf/examples/peripherals/uart_events/main/uart_events_example_main.c for an example of how to do that.

amruta
Posts: 18
Joined: Mon Aug 21, 2017 10:03 am

Re: Using Interrupts on the UART

Postby amruta » Wed Jan 30, 2019 2:03 pm

ESP_Sprite wrote:
Tue Jan 29, 2019 3:03 am
Looking at your code a bit better, I think you're not using the driver correctly... you're supposed to either use uart_driver_install() so you can use all the nice queued read functions etc, or use uart_isr_register() to install your own ISR and handle all hardware things yourself. In your particular case, I'd go with the drivers approach and the event driven system it offers. See e.g. esp-idf/examples/peripherals/uart_events/main/uart_events_example_main.c for an example of how to do that.
Hello,

I also have the same issue. In my application, ESP32 communicates with third party device.
I am using uart_isr_register() and I need to call uart_write_bytes() in ISR to meet timing requirements. This is resulting in occasional interrupt watchdog timeout.

Any suggestions ?

chillophil
Posts: 4
Joined: Tue Jan 29, 2019 6:05 am

Re: Using Interrupts on the UART

Postby chillophil » Thu Jan 31, 2019 12:57 am

amruta wrote:
Wed Jan 30, 2019 2:03 pm
ESP_Sprite wrote:
Tue Jan 29, 2019 3:03 am
Looking at your code a bit better, I think you're not using the driver correctly... you're supposed to either use uart_driver_install() so you can use all the nice queued read functions etc, or use uart_isr_register() to install your own ISR and handle all hardware things yourself. In your particular case, I'd go with the drivers approach and the event driven system it offers. See e.g. esp-idf/examples/peripherals/uart_events/main/uart_events_example_main.c for an example of how to do that.
Hello,

I also have the same issue. In my application, ESP32 communicates with third party device.
I am using uart_isr_register() and I need to call uart_write_bytes() in ISR to meet timing requirements. This is resulting in occasional interrupt watchdog timeout.

Any suggestions ?
Have you tried the sample, suggested by ESP_Sprite - in terms of "to meet timing requirements"?

Using the event queue will allow you using uart_write_bytes because UART-Events generated by the ISR are queued and processed after the ISR finished, within a "normal scheduled tick".

amruta
Posts: 18
Joined: Mon Aug 21, 2017 10:03 am

Re: Using Interrupts on the UART

Postby amruta » Mon Feb 11, 2019 10:22 am

chillophil wrote:
Thu Jan 31, 2019 12:57 am
amruta wrote:
Wed Jan 30, 2019 2:03 pm
ESP_Sprite wrote:
Tue Jan 29, 2019 3:03 am
Looking at your code a bit better, I think you're not using the driver correctly... you're supposed to either use uart_driver_install() so you can use all the nice queued read functions etc, or use uart_isr_register() to install your own ISR and handle all hardware things yourself. In your particular case, I'd go with the drivers approach and the event driven system it offers. See e.g. esp-idf/examples/peripherals/uart_events/main/uart_events_example_main.c for an example of how to do that.
Hello,

I also have the same issue. In my application, ESP32 communicates with third party device.
I am using uart_isr_register() and I need to call uart_write_bytes() in ISR to meet timing requirements. This is resulting in occasional interrupt watchdog timeout.

Any suggestions ?
Have you tried the sample, suggested by ESP_Sprite - in terms of "to meet timing requirements"?

Using the event queue will allow you using uart_write_bytes because UART-Events generated by the ISR are queued and processed after the ISR finished, within a "normal scheduled tick".
I had tried it. Unfortunately it didn't work in my case.

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

Re: Using Interrupts on the UART

Postby ESP_houwenxiang » Wed Feb 13, 2019 3:00 am

Hi,
@fofi144
It seems that you are using your own ISR handles. One thing to note when data is received, you should read the data out until the hw fifo is empty, and than clear the interrupt flag. otherwise, the interrupt status can never be cleared.

@amruta
It is not recommended to call "uart_write_bytes" in the interrupt routine, because "uart_write_bytes" may block.


thanks !!
wookooho

Who is online

Users browsing this forum: dzungpv and 158 guests