Handle Multiple interrupts in same task

coo00l wrote on Monday, December 02, 2019:

Hi,

Can you please help me to handle multiple interrupt routine in the same task.

I’ve a task “Control_task”. I want to handle multiple interrupts such as timer overflow interrupt, pin falling edge interrupt in the same Control_task.

I’ve created like this. I’m facing issue that this approach is not working properly. Can you please help me.


xQueueHandle event_msg_q;

Model::Model() : modelListener(0)
{
	 event_msg_q = xQueueGenericCreate(10, 3, 0);
}

void Control_task(void *param){

    while(1){
    
        vTaskDelay(1);
        
        static uint8_t event_msg;
        if(xQueueReceiveFromISR(event_msg_q,&event_msg,0) == pdTRUE){
        
                switch(event_msg){

                    case falling_edge_int_event:
                        falling_edge_int_handler();
                        break;

                    case timer_ovf_int_event:
                        timer_ovf_int_handler();
                        break;

                        default:
                        break;
                }
          }
}

void timer_ovf_int_handler(){

    /*Read Button value*/
    read_button();

}

void falling_edge_int_handler(){

    /*Send SPI data*/
    SPI_transmit_data();
    
}


void INT1_HANDLER(void){

    event_msg = falling_edge_int_event;
    xQueueSendFromISR(event_msg_q, &event_msg, 0);
}

void INT2_HANDLER(void){

    event_msg = timer_ovf_int_event;
    xQueueSendFromISR(event_msg_q, &event_msg, 0);
}


heinbali01 wrote on Monday, December 02, 2019:

Control_task is a normal task, so you should not call the FromISR() API’s:

-    if(xQueueReceiveFromISR(event_msg_q,&event_msg,0) == pdTRUE){
+    if(xQueueReceive(event_msg_q,&event_msg,0) == pdTRUE){

Do not forget to set the 3rd parameter of xQueueReceive() : the number of clock ticks to wait. A value of 0 means that it will return immediately.

xQueueGenericCreate() takes three arguments: queue-length, item-size and queue-type.

You choose an item size of 3 bytes. That is quite unusual: you are passing an uint8_t:

static uint8_t event_msg;

so the item size should be 1 byte.

In INT1_HANDLER(void) and in INT2_HANDLER(void) I miss the local declaration of event_msg, why?

The API xQueueSendFromISR():

 BaseType_t xQueueSendFromISR(
	QueueHandle_t xQueue,
	const void *pvItemToQueue,
	BaseType_t *pxHigherPriorityTaskWoken
								);

When you call xQueueSendFromISR(), the third parameter is also very important.

Normally the code would look like this:

void ISR()
{
uint8_t event_msg = falling_edge_int_event;

	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	xQueueSendFromISR(event_msg_q, &event_msg, &xHigherPriorityTaskWoken );
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

The call to portYIELD_FROM_ISR is important because it may cause a task switch.

1 Like

coo00l wrote on Monday, December 02, 2019:

Thank you so much Hein Tibosch . I’ll try your suggestions.

coo00l wrote on Monday, December 02, 2019:

Hi Hein Tibosch,

If both interrupts (timer overflow interrupt, SPI interrupt) occur at the same time, how the FreeRTOS handle?

Did I miss one of those interrupt routine??

richard_damon wrote on Monday, December 02, 2019:

One of the parameters to the queue creation call is how many messages it can hold. As long as it can hold messages from both sources you shouldn’t lose events.

Another option for doing this that might be simpler is to use the Direct-to-Task notifications, and give each interrupt their own bit and have the task wait for either of them.

1 Like

Skip the vTaskDelay(1) and replace with a timeout parameter in xQueueReceive (third parameter, instead of 0). Otherwise the task will always wait 1 tick even if there are messages waiting in the queue.

Such issues are easier to debug if you have an RTOS tracing tool. Please excuse the self-promotion, but we at Percepio happens to make one for FreeRTOS that can be pretty useful. Check out https://percepio.com/tz/freertostrace/.

1 Like

Hi Johan,

Thank you for your reply. I’m trying to use the software Percepio tracealyzer. I’m using STM32 device and Ulink plus debugger. When I’m trying to connect the device and debugger. My debugger is not listed in the settings. I couldn’t able to stream. Can you please help me.

We only have built-in support for J-Link and STLINK at the moment, but ULINK plus can also be used. The data is then transferred via Keil uVision, to a file and then read by Tracealyzer. This works also for streaming. See this guide: https://percepio.com/keil-uvision/. Note the link to the Application Note in the end.