Summary
In the previous article I showed you how to use the FreeRTOS task notification mechanism to replace a binary semaphore. In this article I will build PSoC FreeRTOS Task Notification Value firmware. Every FreeRTOS task has one built-in “uint32_t” which you can use to pass information between the task that sends the notification and the task that receives the notification. In this article, instead of using the task notification as a binary semaphore, I will use it as a Queue of depth 1 that can hold one 32-bit word. I will also show you a lesson that I learned about the interrupt registers in the SCB UART.
PSoC FreeRTOS Task Notification Value
I start by copying the project 9-TaskNotify and calling it 10-TaskNotifyValue. I thought that it would be interesting to pass the cause of the UART interrupt to the UART Task, so that it could be told to the user. To do this I call “xTaskNotifyFromISR” instead of “vTaskGiveFromISR”. This function lets me set the value of the FreeRTOS Task notification value, is case to the bit mask of the cause of the UART interrupt. The function also lets you specific if you want to
- eNoAction – don’t do anything (this is what the xTaskNotifyFromISR does)
- eSetBits – or the current notification value with the value you send
- eIncrement – increment the notification value by 1 (in which case it ignore the value you send)
- eSetValueWithOverwrite – replace the current notification value with the value passed in this function
- eSetValueWithoutOverwrite – if there is no pending write, then write the value from this function into the notification value
In the UART_Task I take the value and then clear all of the bit (aka set it to 0) when I exit.
CY_ISR(uartHandler) { uint32_t intrBits = UART_GetRxInterruptSourceMasked(); UART_SetRxInterruptMode(0); // Turn off the Rx interrupt BaseType_t xHigherPriorityTaskWoken; xTaskNotifyFromISR( uartTaskHandle,intrBits,eSetValueWithOverwrite,&xHigherPriorityTaskWoken); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } void UART_Task( void *arg) { (void)arg; char c; UART_Start(); UART_SetCustomInterruptHandler(uartHandler); while(1) { uint32_t intrBits; xTaskNotifyWait( 0x00, /* Don't clear any bits on entry. */ ULONG_MAX, /* Clear all bits on exit. */ &intrBits, portMAX_DELAY ); /* Block indefinitely. */ switch(intrBits) { case UART_INTR_RX_NOT_EMPTY: UART_UartPutString("Interrupt: FIFO Not Empty\n"); break; case UART_INTR_RX_ERR: UART_UartPutString("Interrupt: Error\n"); break; case UART_INTR_RX_FULL: UART_UartPutString("Interrupt: FIFO Full\n"); break; default: UART_UartPutString("Interrupt: Unknown\n"); break; } while(UART_SpiUartGetRxBufferSize()) { c = UART_UartGetChar(); UART_UartPutString("Char = "); UART_UartPutChar(c); UART_UartPutString("\n"); } // re-enable the interrupt UART_ClearRxInterruptSource(UART_INTR_RX_NOT_EMPTY); UART_SetRxInterruptMode(UART_INTR_RX_NOT_EMPTY); } }
New Learning
When I first wrote the program I had something “weird” happening. Specifically it looked like I was getting the interrupt service routine called twice:
I originally wrote the code like this:
CY_ISR(uartHandler) { uint32_t intrBits = UART_GetRxInterruptSourceMasked(); UART_SetRxInterruptMode(0); // Turn off the Rx interrupt UART_ClearRxInterruptSource(UART_INTR_RX_NOT_EMPTY); BaseType_t xHigherPriorityTaskWoken; xTaskNotifyFromISR( uartTaskHandle,intrBits,eSetValueWithOverwrite,&xHigherPriorityTaskWoken); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); }
But, what happens is:
- Turn off interrupts
- Clear the interrupt source (meaning turn off the flag in the SCB that says there is a character in the Rx Buffer)
- One or so UART clock cycles later the flag is reset (because there is still something in the UART Rx Buffer)
- Send the notification to the UART Task
- The UART Task wakes up and processes the UART Rx Buffer
- The UART Task turns back on the interrupts
- The interrupt is called because the RX_NOT_EMPTY flag is still set (it is set until it is clear)
- The interrupt handler clears the flag (which isn’t reset this time because there is nothing in the Rx buffer)
- The interrupt handler sends the notification
- The UART Task wakes up again… prints out the Flag..
- The UART Task tries to read out of the Rx Buffer… but there isn’t anything in it.
Each time I start thinking that I know what I am doing, I find something else to learn. I suppose that is what makes this whole thing fun though.
Topic
Description
FreeRTOS: A PSoC4 FreeRTOS Port
An introduction to making FreeRTOS work on PSoC 4
FreeRTOS PSoC Examples
Using multiple tasks in FreeRTOS
FreeRTOS Queue Example
Using a queue to communicate between tasks
PSoC 6 FreeRTOS - The First Example
Booting FreeRTOS on PSoC 6
FreeRTOS Binary Semaphore
An first example of a binary semaphore
FreeRTOS Binary Semaphore (Part 2)
Removing polling in the UART Task
FreeRTOS Counting Semaphore
An example using a counting semaphore
PSoC FreeRTOS
Reading I2C Sensors with a shared I2C Bus
PSoC FreeRTOS Task Notify
A light weight scheme to replace Semaphores
PSoC FreeRTOS Task Notification Values
A very light weight method to transfer one word of information into a task
No comment yet, add your voice below!