This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.
In my previous tutorials “Enlightning the Freedom KL25Z Board” and “Accelerating the KL25Z Freedom Board” I have not used an RTOS. In this one I’m creating a project from scratch and run it with the open source FreeRTOS operating system, using the FRDM-KL25Z Freedom board. MCU10.3 comes with gcc, and is nicely integrated with Eclipse and CodeWarrior. With this tutorial, it is possible to get an RTOS up and running on a Kinetis device very quickly.
I have a KL25Z which has 128 KByte FLASH and 16 KByte of RAM. What I want to explore is if things could fit as well to the KL0 family where the smallest device has only 8 KByte of FLASH and 1 KByte of RAM. Can this work?
Related Tutorials
I’m using the Eclipse based CodeWarrior for MCU10.3. Things are slightly different for MCU10.2. Where things are different, I have noted this below so you should be able to run that tutorial with MCU10.2 and Kinetis without much changes.
In order not to repeat too many steps, it would be good if you are familiar with the following tutorials, at least on a high level:
- Tutorial: Enlightening the Freedom KL25Z Board
- Tutorial: Accelerating the KL25Z Freedom Board
- Tutorial: FreeRTOS on DEMOJM
- Tutorial: Timer (LED) with Processor Expert for Kinetis
Installing more Processor Expert Components
I’m using a Processor Expert component for FreeRTOS which makes things really easy. This and other components are not part of the standard CodeWarrior distribution. I assume know now how to install more components as shown in the previous tutorials mentioned above. If not, here are the quick steps what to do:
- Download the latest archive of all available components from http://www.steinerberg.com/EmbeddedComponents/. The current archive is V1.2 and available from this link.
- Unzip the archive to a folder on your hard disk.
- Start CodeWarrior and select the menu Processor Expert > Import Package.
- Browse to the folder from step 2 and select all *.PEupd files and press ‘Open’ button.
Note: If the new components do not show up in the ‘Component Library’ Processor Expert view, then use the ‘Refresh’ context menu on that view.
Creating the project with the wizard
In the Commander View, I press ‘New MCU project’:
Commander view to create new project
Note: MCU10.2 users: that view does not exist in 10.2. The menu File > New > Bareboard Project does the same.
This opens the New Bareboard Project Wizard. The next steps are pretty obvious:
- Give the project a name.
- Select the device (MKL25Z128 for the Freedom board).
- Select the connection (Open Source SDA for the Freedom board).
- Use the default build tools and language settings.
- Select Processor Expert for rapid application development
This will create you a project:
Processor Expert Views
If the Processor Expert views are not shown, use the menu Processor Expert > Show View:
Show Processor Expert Views
Build the project
Time to build the project. Select the project root folder and use the ‘hammer’ icon to build it:
Build Project
This starts code generation followed by compiling and linking the code.
Note: MCU10.2 users: in earlier CodeWarrior versions you might need to generate code first manually. For this select the Processor Expert.pe file in the ‘Project Panel’ view and select ‘Generate Processor Expert code’.
Size Check: Bareboard
We have now created a bareboard (no RTOS yet) application. It is interesting to see what kind of impact (ROM, RAM) the RTOS will have. If you are using gcc and have enabled the code size information (see “Code Size Information with gcc for ARM/Kinetis”):
Bareboard Code Size
Note for MCU10/3 or non-gcc users: that kind of information is only available with gcc
Adding the RTOS
To add the RTOS, I use the ‘Components Library’ view:
FreeRTOS in Components Library view
The ‘Filter’ text at the bottom shows the selected project. Double clicking on the FreeRTOS component will add it to the project, along with the shared Utility component:
Configuring the RTOS
The RTOS component has a red ‘x’ on it, indicating that I need to configure the RTOS tick timer:
Need to configure RTOS tick timer
For ARM architectures, typically the SysTick timer is used, and I configure it to count down (as supported by the hardware):
ARM Cortex SysTick Counter
MCU10.2 users only: Enabling Supervisor Call and Pendable Service
MCU10.3 comes with a better RTOS integration for FreeRTOS, where the RTOS can install interrupt vectors. For MCU10.2 it is necessary to set up two vectors: the Supervisor Call and Pendable Service which are used by the RTOS. In the CPU component, both vectors shall be enabled:
Supervisor Call and Pendable Service enabled for K60
After generating code, it will create two hooks in Events.c where I need to add two calls to the RTOS (highlighted):
01 | /* |
02 | ** =================================================================== |
03 | ** Event : Cpu_OnSupervisorCall (module Events) |
04 | ** |
05 | ** Component : Cpu [MK60N512MD100] |
06 | ** Description : |
07 | ** This event is called when the Supervisor Call exception had |
08 | ** occurred. This event is automatically enabled when the |
09 | ** property is set to 'Enabled'. |
10 | ** Parameters : None |
11 | ** Returns : Nothing |
12 | ** =================================================================== |
13 | */ |
14 | void Cpu_OnSupervisorCall( void ) |
15 | { |
16 | vPortSVCHandler(); |
17 | } |
18 |
19 | /* |
20 | ** =================================================================== |
21 | ** Event : Cpu_OnPendableService (module Events) |
22 | ** |
23 | ** Component : Cpu [MK60N512MD100] |
24 | ** Description : |
25 | ** This event is called when the Pendable Service exception had |
26 | ** occurred. This event is automatically enabled when the |
27 | ** <Pendable Service> property is set to 'Enabled'. |
28 | ** Parameters : None |
29 | ** Returns : Nothing |
30 | ** =================================================================== |
31 | */ |
32 | void Cpu_OnPendableService( void ) |
33 | { |
34 | vPortPendSVHandler(); |
35 | } |
Size Check: Added the RTOS
Generate Code/Build again, and we have the normal ANSI start-up code with the RTOS added. Time for a quick size check:
Application with RTOS
So this means for the RTOS alone roughly 3 KByte for Code and 2 KByte of RAM with the default configuration. We will look into ways how to get that reduced later.
Application main()
Processor Expert has created for me the following main()
code inside ProcessorExpert.c file:
01 | int main( void ) |
02 | /*lint -restore Enable MISRA rule (6.3) checking. */ |
03 | { |
04 | /* Write your local variable definition here */ |
05 |
06 | /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/ |
07 | PE_low_level_init(); |
08 | /*** End of Processor Expert internal initialization. ***/ |
09 |
10 | /* Write your code here */ |
11 | /* For example: for(;;) { } */ |
12 |
13 | /*** Don't write any code pass this line, or it will be deleted during code generation. ***/ |
14 | /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/ |
15 | #ifdef PEX_RTOS_START |
16 | PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */ |
17 | #endif |
18 | /*** End of RTOS startup code. ***/ |
19 | /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/ |
20 | for (;;){} |
21 | /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/ |
22 | } /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/ |
With PE_low_level_init()
it initializes all drivers, and the macro PEX_RTOS_START()
starts the scheduler.
Adding LEDs
I’m reusing what I have created in “Tutorial: Enlightening the Freedom KL25Z Board”and add the components for the RGB LED to my project. For this I can copy-paste the components from one project to the other. To keep things simple, I just use the red and green LED.
Note: MCU10.2 users: copy-paste is not supported, but you can drag&drop the components.
Added Red and Green LEDs
Adding Tasks
So what I need to do is just to add my tasks. To toggle an LED in a task is simple:
1 | static portTASK_FUNCTION(Task1, pvParameters) { |
2 | ( void )pvParameters; /* parameter not used */ |
3 | for (;;) { |
4 | LED1_Neg(); |
5 | FRTOS1_vTaskDelay(1000/portTICK_RATE_MS); |
6 | } |
7 | } |
Don’t be confused by the portTASK_FUNCTION()
macro: it is a way how in FreeRTOS task functions are defined to hide machine specific information. The macro is implemented as
1 | #define portTASK_FUNCTION(vFunction, pvParameters) void vFunction(void *pvParameters) |
for ARM/Kinetis. If you want, you could write a task as well as:
1 | static void Task1( void *pvParameters) { |
2 | ( void )pvParameters; /* parameter not used */ |
3 | for (;;) { |
4 | LED1_Neg(); |
5 | FRTOS1_vTaskDelay(1000/portTICK_RATE_MS); |
6 | } |
7 | } |
vTaskDelay()
will suspend the task for the given amount of milliseconds (1000 milliseconds in above case).
So I create two such tasks, one for each LED.
Creating Tasks
Tasks needs to be created too, and this is accomplished using the xTaskCreate()
API call:
01 | if (FRTOS1_xTaskCreate( |
02 | Task1, /* pointer to the task */ |
03 | ( signed portCHAR *) "Task1" , /* task name for kernel awareness debugging */ |
04 | configMINIMAL_STACK_SIZE, /* task stack size */ |
05 | ( void *)NULL, /* optional task startup argument */ |
06 | tskIDLE_PRIORITY, /* initial priority */ |
07 | (xTaskHandle*)NULL /* optional task handle to create */ |
08 | ) != pdPASS) |
09 | { |
10 | for (;;){}; /* Out of heap memory? */ |
11 | } |
The first argument is the task function, followed by the task name. Additionally the task stack size, the argument (pvParameters
in the task), the initial priority, and an optional task handle pointer needs to be specified.
xTaskCreate()
has a return value which should be checked. The most common cause for a task creation failure is running out of heap. FreeRTOS is using a shared heap to for all the task stacks and the dynamic kernel data structure. With this in mind, we can tune our system a bit….
Reducing the Footprint for KL0
As stated above: FreeRTOS runs easily on a KL25Z. But what if I only have 8 KByte of FLASH and 1 KByte of RAM as on the smallest Kinetis-KL0 listed on the Freescale web site, like the KL0 family?
As FreeRTOS is using its own heap, we can reduce the one set up in the Processor Expert CPU component Build options tab. And as each RTOS task is having a stack in the heap, I can reduce the stack size too:
CPU stack size in CPU component and build options
OK, now time to look at the RTOS configuration itself. The RTOS configuration provides several opportunities for footprint reduction:
- The Task Name Length is used for debugging only. I don’t need it.
- 40 for Minimal Stack Size should be enough (this is equivalent to 40*4=120 Bytes). per task. I just need to keep in mind that there is no separate interrupt stack.
- I only have 2 priorities in my application, so I can reduce the number of Priorities.
- I’m not planning to use Queue and Mutex, so I can turn that off.
- I only allocate memory, so Memory Allocation Scheme 1 is fine.
- Each Task plus the IDLE task needs 120 bytes of stack, so 750 bytes Heap Size sounds good.
Now time to generate code and link the application. Now I have added the RTOS and my application (two tasks flashing each an LED):
Code and Data Size for RTOS plus Application
That’s not bad: 6 KByte for Code plus 1 KByte of RAM .
Optimize for Size
So far I have compiled the code with -O0 (no optimization). An easy way to shrink the code size is to optimize the code for size. For this, there is an option in the ARM gcc compiler:
GNU gcc compiler optimization level
Note: The RTOS port is very sensitive to compiler optimizations, because the stack frame might be different. The FreeRTOS Processor Expert component V1.200 or later supports automatic detection of gcc compiler optimization level.
MCU10.2 and non-gcc Kinetis/ARM compiler users: the compiler optimization level needs to be configured in the FreeRTOS component (Compiler Optimization Level property).
And this has a very positive impact on the code size:
Application optimized for code size
So I only need 5 KByte of FLASH with 1 KByte of RAM . So with this I know I can fit it into a very small device. Of course for the KL25Z I can go ahead and give it more room with more heap and stack size if I want and need it.
Summary
Unlike with many RTOS, it is easily possible to fit FreeRTOS into any of the currently defined Kinetis devices. Of course an 8 KByte FLASH/1 KByte RAM device is not necessarily something which needs an RTOS, but it is good to know that FreeRTOS is tiny and efficient enough to even fit that category. With FreeRTOS I have an ideal RTOS for all the devices I use, and is very scalable: from the tiny 8bit S08, to the 16bit S12, and up to all 32bit ColdFire and Kinetis high-end devices, and down again to the tiny 32bit Kinetis-L K0 one. Not to forget all the other processors which are supported by this open source project.
The sources of this project are available here.