RTOS in STM32 | STM32F103C8T6 | Arm Cortex M3 | KEIL IDE

 A Real-Time Operating System (RTOS) is a type of computer operating system designed to be small and deterministic. RTOSes are commonly used in embedded systems such as medical devices and automotive ECUs that need to react to external events within strict time constraints.

Each executing program is implemented by one or more threads under control of the operating system. If an operating system can execute multiple threads in this manner it is said to be multitasking. Small RTOSes, like FreeRTOS, normally call threads tasks because they don't support virtual memory, so there is no distinction between processes and threads.


Scheduling:

The scheduler is the part of the kernel responsible for deciding which task should be executing at any particular time. The kernel can pause and later resume a task many times during the task's lifetime. If task B replaces task A as the executing task (task A is paused and task B resumed) then task A is said to have been swapped (or switched) out, and task B swapped (or switched) in.

Documents: 


We are using Free RTOS in STM32 in Keil IDE.
Build_your_first_project (steps to follow by freertos.org)

Steps to include RTOS in KEIL:

1. Download Free RTOS from https://www.freertos.org/
Also available in GitHub repository

2.  Include the required C and header files in your Keil project which are present in below folders
Necessary folders:
-- FreeRTOS -> FreeRTOS-Kernel: contains necessary C files like task.c, timer.c, etc.,.
-- FreeRTOS -> FreeRTOS-Kernel -> include: contains necessary header files
-- FreeRTOS -> FreeRTOS-Kernel ->  portable
          - MemMang: contains heap files
          - Then use the folder based on the board and compiler you are using, in our case GCC -> ARM_CM3 (ARM Cortex M3 and ARM compiler 6, if using compiler 5, then use RVDS instead of GCC)
-- FreeRTOSConfig.h file: 
 Use the FreeRTOSConfig.h from GitHub, which is suitable for your specific board and copy that file to your local RTOS folder, In our case for STM32F103C8T6 in KEIL compiler
                                                                                 https://github.com/FreeRTOS/FreeRTOS/blob/main/FreeRTOS/Demo/CORTEX_STM32F103_Keil/FreeRTOSConfig.h
 Lets copy the file to the new folder, lets say "include" inside path
 FreeRTOS -> FreeRTOS-Kernel -> include, which also need to be included in KEIL

Header files:
In KEIL -> Project -> options for target -> C/C++ -> Include Paths


C files:
Include the C files in Source group
- Right click on Source Group 1 -> Add existing files to group

Heap management: Include any one of the heap C file from FreeRTOS -> FreeRTOS-Kernel   ->  portable -> MemMang. Heap 4 implementation is preferred.

OR, instead of manually including FreeRTOS, we can select RTOS when creating KEIL project


    
3. Include the following header files in your main program:

   #include "FreeRTOS.h"
   #include "task.h" - If you are going to use task functions

- If you are using queue / semaphore / timer - include related header files

4. RTOS uses one of the STM32 timer as SysTick Timer
    - Configure the RCC registers to get desired system clock, for more details see this RCC  post
    - SysClk / 8 is Cortex system timer, which is the SysTick timer

    The SysTick calibration value is set to 9000, which gives a reference time base of 1 ms with the SysTick clock set to 9 MHz (max HCLK/8)
SysClk = 72 MHz
system Timer = 72 / 8 = 9 MHz
9 MHz / 9000 = 1000 Hz
Tick_HZ = 1000 Hz = 1 ms




If your tasks don't run, check out this page

Program:

/* FreeRTOS in STM32 */

#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"

void led_on(void *);
void led_off(void *);

void led_on(void *pvParameters)
{
  while(1)                                 // Tasks runs forever
  {
    GPIOC -> BSRR = GPIO_BSRR_BR13;       // PC13 LED - ON
    vTaskDelay(500 / portTICK_PERIOD_MS); // wait for 500 ticks - 500 / tick_time = 500 / 1 ms = 500 ms
  }
}

void led_off(void *pvParameters)
{
  while(1)                                 // Tasks runs forever
  {
    GPIOC -> BSRR = GPIO_BSRR_BS13;       // PC13 LED - OFF
    vTaskDelay(500 / portTICK_PERIOD_MS); // wait for 500 ticks - 500 / tick_time = 500 / 1 ms = 500 ms
  }
}

void RCC_config(void);

void RCC_config() // RCC clock configuration
{
  RCC -> CR |= RCC_CR_HSEON;                               // HSE ON
  RCC -> CFGR |= (RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);    
// Setting PLL - HSE * 9, APB1 / 2
  RCC -> CFGR |= RCC_CFGR_SW_1;                            // SysClk = PLLCLK
  RCC -> CR |= RCC_CR_PLLON;                                              
  // Turn ON PLL after above PLL configurations, making SysClk = HSE * 9 = 8 * 9 = 72 MHz
RCC -> CFGR |= RCC_CFGR_PPRE1_DIV2;
// APB1 = AHB / 2 = 72 / 2 = 36 MHz (max)
}

int main()
{
  RCC_config();
 
  /* PC13 LED configuration */
  RCC -> APB2ENR |= RCC_APB2ENR_IOPCEN;                  // Enable Port-C Clock
  GPIOC -> CRH |= GPIO_CRH_MODE13_1 | GPIO_CRH_CNF13_0;  // PortC_Pin 13 as output @2MHZ with open-drain
  GPIOC -> BSRR = GPIO_BSRR_BS13;                       // Initialize PC13 LED - OFF
 
  if(xTaskCreate(led_on,           // Function / Task name
                 "ON",             // Descriptive name
                 128,              // Minimum Stack length in words
                 NULL,             // Argument to the function
                 0,                // Priority, 0 - Lowest
                 NULL)             // Task handle
    != pdPASS){                    // Check if task is created successfully using return value
     return 0;  }                  // else return
 
  if(xTaskCreate(led_off, "OFF", 128, NULL, 0, NULL) != pdPASS)
    {return 0;}  
 
  vTaskStartScheduler();           // Start the scheduler
 
  // Code after this will never gets executed
  return 0;
}

Explanation:

1. Initially the main function will run, where we will be configuring the tasks and then start the scheduler. After which RTOS takes over and runs all the created tasks based on priorities.

2. Lets create 2 tasks, one turns ON the LED and other turns OFF the LED

3. Use vTaskDELAY() in RTOS instead of normal delay, as it considers tick time.

4. To Print output in a Serial Terminal use UART, For UART in STM32, see this post

For getting started with STM32, click here

For ADC in STM32, see this post

Connecting Bluetooth with STM32 - post

For I2C driver program in ATMega328P, see this post


Comments