FreeRTOS UART receiver ISR using a binary semaphore

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
jihe_298791
Level 2
Level 2

How do you write a UART receiver ISR in FreeRTOS when I send a command and sometimes get a response quickly. I'm trying to use a binary semaphore but I have a race condition where I get the response before I execute the xSemaphoreTake(). Here's what I'm doing:

SemaphoreHandle_t msg_rcvd_semaphore = NULL;

uint32 my_data;

void xbee_rx_isr(void)

{

     volatile uint32_t read_data;

     // Ignore all but received byte interrupts

     if((XBEE_UART_HW->INTR_RX_MASKED & SCB_INTR_RX_MASKED_NOT_EMPTY_Msk ) == 0) {

          return;

     }

    // Clear UART "RX fifo not empty interrupt"

     XBEE_UART_HW->INTR_RX = XBEE_UART_HW->INTR_RX & SCB_INTR_RX_NOT_EMPTY_Msk;       

       

     // Get the byte

     my_data = Cy_SCB_UART_Get(XBEE_UART_HW);

     //

     BaseType_t xHigherPriorityTaskWoken = pdFALSE;

     xSemaphoreGiveFromISR(msg_rcvd_semaphore, &xHigherPriorityTaskWoken);

     if (xHigherPriorityTaskWoken == pdTRUE) {

          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

     }

}

void task (void)

{

     msg_rcvd_semaphore = xSemaphoreCreateBinary();

     // Initialize the receiver here

     // Send commands and block for their responses

     for (;;) {

          // Transmit a command

          xbee_uart_put_string("my_command");

          // MY PROBLEM: Sometimes the response (and ISR) comes before I execute the following

          // xSemaphoreTake(), in which case xSemaphoreTake() hangs forever.

          // Wait for response (with 100 ms timeout)

           if (xSemaphoreTake(msg_rcvd_semaphore, pdMS_TO_TICKS(100u)) == pdPASS) {

               // Process my_data

          } else {

               // Process timeout

          }

     }

}

0 Likes
3 Replies
RiBa_4055821
Level 1
Level 1

What is the problem with receiving the reply before executing xSemaphoreTake()?  If that happens the fact the interrupt occurred is latched by the semaphore, so the call to take the semaphore will return immediately as the semaphore is already there.  If interrupts occur quickly you may want to use a counting semaphore instead.  Also, if it is always the same task that is signaled from the interrupt, consider using a task notification in place of a semaphore.  There are some code examples here: FreeRTOS task notifications, fast Real Time Operating System (RTOS) event mechanism

0 Likes

Mine doesn’t work that way for some reason. If the interrupt occurs before xSemaphoreTake(),it does not return immediately. It hangs. Do I need to initialize the semaphore before transmitting the command? I will look into your other suggestions. Thanks!!

0 Likes

/Hi jihe_298791​,

Are you generating an interrupt on every character received? If so, if you are receiving multiples character at a faster rate, there are chances that you might miss the interrupt event and hence the received character is lost when using Binary Semaphore. As suggested you can use a counting semaphore or task notifications. You can also try using level interrupts instead of RX FIFO NOT EMPTY interrupt so that your ISR is not triggered often.

Also, is the xSemaphoreTake() not returning even once?

What is the priority of the UART interrupt and what is the setting of configMAX_API_CALL_INTERRUPT_PRIORITY in your project?

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes