Blinky
In this demo, we want to toggle an LED with a single task. This is a very simple RTOS application which allows us to demonstrate some common thoughts we should consider for larger applications, too.
Application Overview
After power on, the CPU starts with privileged access mode at the reset vector, the generated project will initialize the C runtime environment, enter the first function, called main(), and initialize the configured peripherals (see “Entry Function main()” in the process layout).
In main(), we call MX_Blinky_Init() which initializes the RTOS, creates the first (and only) task, and passes the execution control to the Flexible Safety RTOS (see “RTOS Scheduler” and “Idle Task” in the process layout).
When creating the first task, the Flexible Safety RTOS requires that we assign a writable memory region to this task. This memory region contains at least the task stack. We call such a memory space “process” (see: “Blinky Task Data” in the process layout).
The Blinky Process Layout
Note
All tasks we create before the RTOS is started, will start execution in privileged access mode. We will lower the task to unprivileged access mode in the task itself.
Peripherals activates interrupt service handlers, which are started in privileged access mode by hardware design (see: “Systick Exception Handler” in the process layout).
Using the HAL, and in consequence the peripheral registers, needs some preparation for tasks in unprivileged access mode. There are multiple ways in granting permission to the peripherals:
a. creating and assigning a shared memory for the peripheral register memory region to the process
b. adding an I/O handler task, running with privileged access mode
c. temporarily raise single function call to run in privileged access mode
Note: We choose method “c.” for the generated demo application.
Memory Map
With this highlevel view on the application, we can start organizing the memory. In general, we think on each single task and decide which data must be readable, writable, and/or executable.
For the single “Blinky Task” we want the following memory access permissions:
memory region |
readable |
writable |
executable |
---|---|---|---|
Appliction Code |
yes |
no |
yes |
main data |
no |
no |
no |
Task Stack |
yes |
yes |
no |
main heap |
no |
no |
no |
main stack |
no |
no |
no |
GPIO Registers |
yes |
yes |
no |

The Blinky Memory Map
Note
The Entry function main()
is used during startup and is never activated again after passing control to the RTOS.
Demo Files
The demo implementation consists of the following files:
+- Blinky : demo application directory
| +- App : ST standard application directory
| | +- app_blinky_callbacks.c : RTOS callback interface
| | +- app_blinky.h : Blinky interface header
| | +- app_blinky.c : Blinky demo application
Find the detailed description of the application implementation within these files. The main functionality is located in app_blinky.c
in the single task function:
static void BlinkyTask(void *p_arg)
{
(void)p_arg; /* unused; prevent compiler warning */
SP_SET_USR_MODE(); /* lower task to unprivileged access mode */
while(1) { /* the mandatory endless task loop */
SP_DO_PRIVIL( /* call next function in privileged mode */
BSP_LED_Toggle(LED_GREEN); /* to get access to peripheral registers */
)
OSTimeDly(500u); /* wait for 500 ticks */
}
}