Home | Projects | Notes > Real-Time Operating Systems (RTOS) > Exercise: FreeRTOS FromISR
& Task Priority (06_LED_Button_ISR
, 07_Task_Priority
)
FromISR
& Task Priority (06_LED_Button_ISR
, 07_Task_Priority
)
FromISR
(06_LED_Button_ISR
)Implement ISR-to-task notification using direct notification APIs of FreeRTOS.
Create 3 tasks that toggle 3 different LEDs of the STM32F407 Discovery board.
Upon the button press, the button interrupt handler must run, and it should send the notification to the current LED toggling task.
When LED toggling task receives the notification, it should delete itself.
Since we are using the interrupt handler which runs in the Handler Mode (interrupt context) unlike in the previous exercise where the button task ran in the Thread Mode (process context), we need to use the different version of task notification API. That is, the xTaskNotifyFromISR()
.
Go through all the process you went through to setup the Exercise: 005_LED_Task_Notify.
Do the following GPIO configuration.
GPIO PA0
is connected to EXTI line0 interrupt
. So do the following setup.
Call button_interrupt_handler()
from EXTI0_IRQHandler()
shown in the file above and implement it in main.c
. (Make sure to declare this function as extern
in the file.)
Also, clear the pending bit for GPIO_PIN_0
.
xxxxxxxxxx
121/* stm32f4xx_it.c */
2...
3void EXTI0_IRQHandler(void)
4{
5 /* USER CODE BEGIN EXTI0_IRQn 0 */
6 button_interrupt_handler();
7
8 // clear EXTI 0 pending bit in the exti pending register
9 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
10 /* USER CODE END EXTI0_IRQn 0 */
11 ...
12}
In my case,
HAL_GPIO_EXTI_IRQHandler(B1_Pin)
was already there generated in the code as shown in the snapshot above. (B1_Pin
is defined asGPIO_PIN_0
)
Implement button_interrupt_handler()
.
xxxxxxxxxx
131/* main.c */
2...
3
4/* USER CODE BEGIN 4 */
5
6void button_interrupt_handler(void)
7{
8 traceISR_ENTER(); // to monitor the entry of the ISR from the SEGGER SystemView
9 xTaskNotifyFromISR(next_task_handle, 0, eNoAction, NULL);
10 traceISR_EXIT();
11}
12
13...
Update led_green_handler()
. Here, the shared variable next_task_handle
is also shared with the ISR which is not a user task, so synchronizing the access to this variable using vTaskSuspendAll()
/vTaskResumeAll()
will not work!
Use portENTER_CRITICAL()
/portEXIT_CRITICAL()
which is implemented as vPortEnterCritical()
in port.c
instead. This will disable interrupts. However, in general, disabling interrupts is not recommended. If this is the case, use mutex or semaphore instead.
xxxxxxxxxx
281/* main.c */
2...
3static void led_green_task_handler(void *parameters)
4{
5 BaseType_t status;
6
7 while (1)
8 {
9 SEGGER_SYSVIEW_PrintfTarget("Toggling green LED");
10 HAL_GPIO_TogglePin(GPIOD, LED_GREEN_PIN);
11
12 // If there's no notifications pending, go to the BLOCKED state for 1 sec
13 // until it receives a notification.
14 status = xTaskNotifyWait(0, 0, NULL, pdMS_TO_TICKS(1000));
15
16 if (status == pdTRUE)
17 {
18 // If there was a notification (i.e., User has pressed the button),
19 // update the 'next_task_handle', turn the LED on, and delete itself.
20 portENTER_CRITICAL(); // Synchronization begins
21 next_task_handle = led_orange_task_handle;
22 HAL_GPIO_WritePin(GPIOD, LED_GREEN_PIN, GPIO_PIN_SET);
23 SEGGER_SYSVIEW_PrintfTarget("Delete Green LED Task");
24 portEXIT_CRITICAL(); // Synchronization ends
25 vTaskDelete(NULL);
26 }
27 }
28}
vPortEnterCritical()
callsportDISABLE_INTERRUPTS()
which disables all the interrupts with priority values [configMAX_SYSCALL_INTERRUPT_PRIORITY
, 0xF], [0x5, 0xF] in our case. Interrupts with the priority values within range [0x0, 0x4] are not affected. Note that any interrupt handler that is of higher priority (i.e., lower priority value) thanconfigMAX_SYSCALL_INTERRUPT_PRIORITY
cannot use the FreeRTOS API within it.xxxxxxxxxx
181/* Project/Common/ThirdParty/FreeRTOS/portable/GCC/ARM_CM4F/portmacro.h */
2...
34...
5
6portFORCE_INLINE static void vPortRaiseBASEPRI( void )
7{
8uint32_t ulNewBASEPRI;
9
10__asm volatile
11(
12" mov %0, %1 \n"\
13" msr basepri, %0 \n"\
14" isb \n"\
15" dsb \n"\
16: "=r" ( ulNewBASEPRI ) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
17);
18}
Since the interrupt handlers used for the context switching (e.g.,
PendSVHandler()
) has the lowest priority (i.e., highest priority value), it will also be disabled by the callportDISABLE_INTERRUPTS
.
If you are copying the main.c
from the previous exercise, make sure to remove everything related to button_handler
since we are no longer using that task to send notification upon button press. We are using ISR in this exercise.
Analyze using SEGGER SystemView.
I faced a problem with this exercise. Left the question on the Q&A board.
Strange! This issue did not appear on the 2nd implementation.
In
ISR 22
22 means the ISR number.
Solution:
xxxxxxxxxx
221/* main.c */
2...
3void button_interrupt_handler(void)
4{
5BaseType_t pxHigherPriorityTaskWoken = pdFALSE; // Must be initialized to 0
6
7traceISR_ENTER(); // To monitor the entry of the ISR from the SEGGER SystemView
8xTaskNotifyFromISR(next_task_handle, 0, eNoAction, &pxHigherPriorityTaskWoken);
9// xTaskNotifyFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE
10// if sending the notification caused a task to unblock, and the unblocked
11// task has a priority higher than the currently running task.
12//
13// If xTaskNotifyFromISR() sets this value to pdTRUE then a context switch
14// should be requested before the interrupt is exited.
15//
16// pxHigherPriorityTaskWoken is an optional parameter and can be set to NULL.
17
18// Once the ISR exits, the macro below makes the higher priority task unblocked
19// to resume on the CPU.
20portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
21traceISR_EXIT();
22}
07_Task_Priority
)Write an application that creates 2 tasks:
Task-1
Priority value: 2
Continuous task
Toggles the red LED with 100 ms ON/OFF duration
Task-2
Priority value: 3
Continuous task
Toggles the green LED with 1 s ON/OFF duration
When the user button is pressed, the priority of the tasks should be exchanged. (i.e., Task-1's priority must be reconfigured for Task-2's priority and vice versa.)
Check the following 2 APIs that helps reconfiguring the FreeRTOS value of a task.
uxTaskPriorityGet()
vTaskPrioritySet()
Error fixes!
Lets say the Task-1 is executing on the CPU whose Priority is 3 . Now processor hits with an interrupt of the USART Tx whose priority is 2 , will Task1 be preempted? (Assume lower priority value = lower priority)
Lets say USART TX interrupt is being serviced by the processor whose priority is 2 , now another interrupt is pended whose priority is 5, Do you think processor will preempt the USART TX ISR to attend the ISR of newly pended interrupt ? in other words do you think interrupt nesting will happen? (Assume lower priority value = lower priority)
Lets say in freeRTOS , Task1( priority )= 5 is currently executing on the CPU, if Task2(priority)= 6 unblocks due to some reason, will context switch take place to task 2 immediately or task 2 should wait until the next tick interrupt?
In which processor mode FreeRTOS tasks will be executing in the ARM Cortex-Mx processor?
If 6 bits are implemented in the priority register of the MCU, then how many interrupts levels are available? What is the highest priority level and lowest priority level?
Does having more priority levels affect RAM usage of the MCU?
Nayak, K. (2022). Mastering RTOS: Hands on FreeRTOS and STM32Fx with Debugging [Video file]. Retrieved from https://www.udemy.com/course/mastering-rtos-hands-on-with-freertos-arduino-and-stm32fx/