[go: up one dir, main page]

0% found this document useful (0 votes)
90 views134 pages

Stm32f4 and Freertos

Uploaded by

Vera Similar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
90 views134 pages

Stm32f4 and Freertos

Uploaded by

Vera Similar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 134

FreeRTOS with CubeMX

T.O.M.A.S – Technically Oriented Microcontroller Application Services


v0.02
Using SWO to print information
from STM32
Using SWO 3

• On some stm32 is periphery called ITM, not mix with ETM(real trace)

• This periphery can be used to internal send data from MCU over SWO pin

• Is possible to redirect the printf into this periphery

• And also some IDEs can display this information during debug

• It is similar to USART but


we don’t need any additional
wires and PC terminal

• Video: Link
Using SWO 4

• To make SWO working you musty connect the PA3 and Debugger SWO pin
together

Connect SWO
and PA3

Connect SWO
and PA3
Using SWO for printf 5

• Create project in CubeMX


• Menu > File > New Project
• Select STM32F4 > STM32F429/439 > LQFP144 > STM32F439ZITx

• We need only blank project with clock initialization


• We set the RCC and configure the core to maximum speed and SWD with SWO
Using SWO for printf 6

• Now we set the project details for generation


• Menu > Project > Project Settings
• Set the project name
• Project location
• Type of toolchain

• Now we can Generate Code


• Menu > Project > Generate Code
Using SWO for printf in KEIL 7

• We need to include the stdio.h library to make printf working


/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */

• And define __FILE structure


/* USER CODE BEGIN PFP */
struct __FILE { int handle; /* Add whatever is needed */ };
/* USER CODE END PFP */

• fputc function must be defined to send byte over ITM


/* USER CODE BEGIN 4 */
/*send text over SWV*/
int fputc(int ch, FILE *f) {
ITM_SendChar(ch);//send method for SWV
return(ch);
}
/* USER CODE END 4 */
Using SWO for printf in KEIL 8

• If the MCU run on very high frequency and you not see print f output
you may try put into ITM send delay loop
/* USER CODE BEGIN 4 */
/*send text over SWV*/
int fputc(int ch, FILE *f) {
uint32_t i=0;
for(i=0;i<0xFFFF;i++);//waiting method, lower value will stop the SWV
ITM_SendChar(ch);//send method for SWV
return(ch);
}
/* USER CODE END 4 */
Using SWO for printf in KEIL 9

• In KEIL 1. Target
options 2. Select
DEBUG tab
• Open target options
(ALT+F7)
3. Set ST-Link
• Set ST-Link debugger
4. Open Settings
• Button Settings
6. Go to Trace tab
• Set SW(D)
in Debug TAB
5. Set SW(D)
• Got to Trace TAB
Using SWO for printf in KEIL 10

• Check Trace Enable

• Set core clock (168MHz must be same as in CubeMX clock tree)


2. Set Core clock
• ITM Stimulus Port 0
must be checked 1. Trace
Enable
4. Open Settings
• Button OK

3. Check ITM Port 0

4. Button OK
Using SWO for printf in KEIL 11

• Testing loop printf in main


/* USER CODE BEGIN 3 */
/* Infinite loop */
while (1)
{
printf("test text\n");
HAL_Delay(1000);
}
/* USER CODE END 3 */

• Compile and debug project

• Open Debug (printf) Viewer


Using SWO for printf in IAR 12

• Here is configuration more easier

• Open project options

• General Options 1. General options


2. Library configuration
• TAB library and configuration

• Select stdout/stderr via SWO

• Button OK

3. Set Via SWO


Using SWO for printf in IAR 13

• Add testing printf into loop


/* USER CODE BEGIN 3 */
/* Infinite loop */
while (1)
{
printf("test text\n");
HAL_Delay(1000);
}
/* USER CODE END 3 */

• Compile project and go to debug


Open SWO options

• Open SWO
Using SWO for printf in IAR 14

• Override project default if clocks are different from core


(168MHz in out case)

• Check autodetect SWO clock if possible

• Enable
ITM Port 0
to terminal

• Button OK
Override clock and set
correct value (168MHz)
Enable ITM Port 0

Check autodetect Button OK


Using SWO for printf in IAR 15

• Menu View -> Terminal I/O

• Run program
FreeRTOS
FreeRTOS
17
About FreeRTOS
• Market leading RTOS by Real Time Engineers Ltd.

• Professionally developed with strict quality management

• Commercial versions available: OpenRTOS and SafeRTOS

• Documentation available on www.freertos.org

• Free support through forum (moderated by RTOS original author


Richard Barry)
FreeRTOS
18
Main features
• Preemptive or cooperative real-time kernel

• Scalable RTOS with tiny footprint (less than 10KB ROM)

• Includes a tickless mode for low power applications

• Synchronization and inter-task communications using


• message queues
• binary and counting semaphores
• mutexes
• group events (flags)

• Software timers for tasks scheduling

• Execution trace functionality

• CMSIS-RTOS API port


FreeRTOS
19
APIs overview (1/2)
API category FreeRTOS API Description
Task creation xTaskCreate Creates a new task
vTaskDelete Deletes a task
Task control vTaskDelay Task delay
vTaskPrioritySet Sets task priority
vTaskSuspend Suspends a task
vTaskResume Resumes a task
Kernel control vTaskStartScheduler Starts kernel scheduler
vTaskSuspendAll Suspends all tasks
xTaskResumeAll Resumes all tasks
taskYIELD Forces a context switch
taskENTER_CRITICAL Enter a critical section (stops
context switching)
taskEXIT_CRITICAL Exits from a critical section
FreeRTOS
20
APIs overview (2/2)
API FreeRTOS API Description
category
Message xQueueCreate Creates a queue
queues xQueueSend Sends data to queue
xQueueReceive Receive data from the queue
Semaphores xSemaphoreCreateBinary Creates a binary semaphore
xSemaphoreCreateCounting Creates a counting semaphore
xSemaphoreCreateMutex Creates a mutex semaphore
xSemaphoreTake Semaphore take
xSemaphoreGive Semaphore give
Timers xTimerCreate Creates a timer
xTimerStart Starts a timer
xTimerStop Stops a timer
FreeRTOS
21
CMSIS-RTOS FreeRTOS implementation
• Implementation in file cmsis-os.c (found in folder:
“\Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS”)

• The following table lists examples of the CMSIS-RTOS APIs and the FreeRTOS APIs
used to implement them

API category CMSIS_RTOS API FreeRTOS API


Kernel control osKernelStart vTaskStartScheduler
Thread management osThreadCreate xTaskCreate
Semaphore osSemaphoreCreate vSemaphoreCreateBinary
xSemaphoreCreateCounting
Mutex osMutexWait xSemaphoreTake
Message queue osMessagePut xQueueSend
xQueueSendFromISR
Timer osTimerCreate xTimerCreate

• Note: CMSIS-RTOS implements same model as FreeRTOS for task states


FreeRTOS
22
CMSIS-RTOS API
• CMSIS-RTOS API is a generic RTOS interface for Cortex-M processor based
devices

• Middleware components using the CMSIS-RTOS API are RTOS agnostic, this
allows an easy linking to any third-party RTOS

• The CMSIS-RTOS API defines a minimum feature set including


• Thread Management
• Kernel control
• Semaphore management
• Message queue and mail queue
• Memory management
• …

• For detailed documentation regarding CMSIS-RTOS refer to:


http://www.keil.com/pack/doc/CMSIS/RTOS/html/index.html
FreeRTOS
23
Configuration options
• Configuration options are declared in file FreeRTOSConfig.h

• Important configuration options are:

Config option Description

configUSE_PREEMPTION Enables Preemption

configCPU_CLOCK_HZ CPU clock frequency in hertz

configTICK_RATE_HZ Tick rate in hertz

configMAX_PRIORITIES Maximum task priority

configTOTAL_HEAP_SIZE Total heap size for dynamic allocation

configLIBRARY_LOWEST_INTERRUPT_PRIORITY Lowest interrupt priority (0xF when


using 4 cortex preemption bits)
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY Highest thread safe interrupt priority
(higher priorities are lower numeric
value)
FreeRTOS
24
Tickless idle mode operation
• Kernel can stop system tick interrupt and place MCU in low power
mode, on exit from this mode systick counter is updated

• Enabled when setting configUSE_TICKLESS_IDLE as 1

• The kernel will call a macro portSUPPRESS_TICKS_AND_SLEEP()


when the Idle task is the only task able to run (and no other task is
scheduled to exit from blocked state after n ticks)
• n value is defined in FreeRTOSconf.h file

• FreeRTOS implementation of portSUPRESS_TICKS_AND_SLEEP


for cortexM3/M4 enters MCU in sleep low power mode

• Wakeup from sleep mode can be from a system interrupt/event


FreeRTOS in CubeMX 25

• Use CubeMX project from printf example

• In Pinout TAB select in MiddleWares FreeRTOS

• In Configuration TAB
is now possible to
configure FreeRTOS
Parameters
CubeMX FreeRTOS Configuration 26

• FreeRTOS configuration supported by


CubeMX

• Config parameters
• Set kernel
• Mem setup

• Include parameters
• Include some additional functions,
not necessary for FreeRTOS run

• Tasks and Queues


• We can easily create task or queue by CubeMX

• Timers and semaphores


• CubeMX create semaphore and timer for us
Kernel settings 27

• Use preemption
• If enabled use pre-emptive scheduling
Priority level
Create Task2 Task2 suspend
High priority
Task2

Low priority Task1 Task1

time

• If disabled use co-operative scheduling


Priority level
Create Task2 Task1 suspend
High priority
Task2

Low priority Task1

time
FreeRTOS
Memory allocations types
FreeRTOS
29
Dynamic memory management
• FreeRTOS have own heap which is use for components
• Tasks
• Queues
• Semaphores
• Mutexes
• Dynamic memory allocation

• Is possible to select type of


memory allocation
Total heap size for
FreeRTOS

How is memory allocated


and dealocated
FreeRTOS
30
Dynamic memory management
• Heap_1.c
• Simplest allocation method (deterministic), but does not allow freeing of allocated
memory => could be interesting when no memory freeing is necessary

Heap Heap

Is not possible to return


memory to heap

pvPortMalloc
Allocated vPortFree
block 1
pvPortMalloc
Allocated vPortFree
block 2
pvPortMalloc
Allocated vPortFree
block 2
FreeRTOS
31
Dynamic memory management
• Heap_2.c
• Implements a best fit algorithm for allocation
• Allows memory free operation but does not combine adjacent free blocks => risk of
fragmentation

Heap Heap Heap 1 Heap 1

Free blocks are not


combined together

Allocated Allocated
pvPortMalloc vPortFree Heap 4
block 1 block 1
Allocated Heap 2
pvPortMalloc vPortFree Heap 2
block 2
Allocated Heap 3
pvPortMalloc vPortFree Heap 3
block 2
FreeRTOS
32
Dynamic memory management
• Heap_3.c
• Implements a simple wrapper for the standard C library malloc() and free(), the
wrapper makes these functions thread safe, but makes code increase and not
deterministic

Heap Heap Heap 1 Heap 1

Use C functions for allocation


(linker must be modified)
Allocated Allocated
malloc free Heap 4
block 1 block 1
Allocated Heap 2
malloc free Heap 2
block 2
Allocated Heap 3
malloc free Heap 3
block 2
FreeRTOS
33
Dynamic memory management
• Heap_4.c
• First fit algorithm and able to combine adjacent free memory blocks into a single
block => this model is used in STM32Cube examples

Heap Heap Heap 1 Heap

combine together free


memory

pvPortMalloc
Allocated vPortFree
Allocated vPortFree
block 1 block 1
pvPortMalloc
Allocated vPortFree
block 2 Heap 2
pvPortMalloc
Allocated vPortFree
block 2
Memory allocation 34

• Use heap_4.c

• Memory Handler definition


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osPoolId PoolHandle;

• Memory allocation
void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
osPoolDef(Memory,0x100,uint8_t);
PoolHandle = osPoolCreate(osPool(Memory)); Create memory pool
uint8_t* buffer=osPoolAlloc(PoolHandle);
/* Infinite loop */ Allocate memory from pool
for(;;)
{
osDelay(5000);
}
/* USER CODE END 5 */
}
FreeRTOS
Tasks
FreeRTOS
36
Task states
• Ready
• Tasks are ready to execute but are Suspend
not currently executing because a
different task with equal or higher
osThreadSuspend
priority is running osThreadSuspend

osThreadResume

• Running
• when task is actually running osThreadCreate
Ready Scheduler Runing
osThreadSuspend
• Blocked
• Task is waiting for a either a
temporal or external event Event

Blocked API function


• Suspended
• Task not available for scheduling Blocked
FreeRTOS
37
Task switch
• Task switching on STM32?

• Cortex cores have implemented few


features which directly support os
systems

• Two interrupts dedicated for os


• PendSV interrupt
• SVC interrupt

• Two stack pointers


• Process stack pointer
• Main stack pointer

• SysTick timer
• Used to periodically trigger
scheduling
FreeRTOS OS interrupts 38

• PendSV interrupt • SVC interrupt


• In this interrupt is the scheduler • Interrupt risen by SVC instruction
• Lowest NVIC interrupt priority • Called if task want end earlier (MPU
• Not triggered by any periphery version)
• Pending state set from other interrupts • In this interrupt set pending state
PendSV (MPU version)
• Or from task which want end earlier
(non MPU version)
• SysTick timer
• Set PendSV is context switch is
necessary
Priority level
High priority osDelay

Other IRQs
SVC
PendSV
SysTick

Low priority Task1 Task2 Task1 Task2

time
FreeRTOS
39
Stack pointer
• Main stack pointer
• Used in interrupts
• Allocated by linker during compiling

• Process stack pointer


• Each task have own stack pointer
• During context switch the stack pointer is initialized
for correct task

PendSV interrupt
Task 1 Task 2

PSP stack pointer MSP stack pointer PSP stack pointer

Stack – Task 1 Stack – Task 1 Stack – Task 2 Stack – Task 2


Data Data Data Data
Non scratch Non scratch
registers registers
Tasks API 40

• Create task
osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)

• Delete task
osStatus osThreadTerminate (osThreadId thread_id)

• Get task ID
osThreadId osThreadGetId (void)

• Task handle definition:


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;

• Create Task
/* Create the thread(s) */
/* definition and creation of Task1 */
osThreadDef(Task1, StartTask1, osPriorityNormal, 0, 128);
Task1Handle = osThreadCreate(osThread(Task1), NULL);
Tasks API 41

• Check if task is suspended


osStatus osThreadIsSuspended(osThreadId thread_id)

• Resume task
osStatus osThreadResume (osThreadId thread_id)

• Check state of task


osThreadState osThreadGetState(osThreadId thread_id)

• Suspend task
osStatus osThreadSuspend (osThreadId thread_id)

• Resume all tasks


osStatus osThreadResumeAll (void)

• Suspend all tasks


osStatus osThreadSuspendAll (void)
Tasks lab 42

• By default defined one defaultTask

• Task is defined by
• Name
• Priority
• Stack size
• Name of entry function

• Define two tasks


• Task1
• Task2

• With same priority


Tasks lab 43

• Now we set the project details for generation


• Menu > Project > Project Settings
• Set the project name
• Project location
• Type of toolchain

• Now we can Generate Code


• Menu > Project > Generate Code
Tasks lab 44

• Any component in FreeRTOS need to have handle, very similar to CubeMX


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osThreadId Task2Handle;

• Task function prototypes, names was taken from CubeMX


/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
void StartTask1(void const * argument);
void StartTask2(void const * argument);

• Before the scheduler is start we must create tasks


Define task parameters
/* Create the thread(s) */
/* definition and creation of Task1 */
osThreadDef(Task1, StartTask1, osPriorityNormal, 0, 128);
Create task, allocate
Task1Handle = osThreadCreate(osThread(Task1), NULL);
memory
/* definition and creation of Task2 */
osThreadDef(Task2, StartTask2, osPriorityNormal, 0, 128);
Task2Handle = osThreadCreate(osThread(Task2), NULL);
Tasks lab 45

• Start the scheduler, the scheduler function newer ends


/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */

• On first task run StartTask1 is called

• Task must have inside infinity loop in case we don’t want to end the task

void StartTask1(void const * argument)


{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;) Endless loop
{
printf("Task 1\n");
osDelay(1000);
osDealy will start
} context switch
/* USER CODE END 5 */
}
Tasks lab 46

• Second loop is same as previous


/* StartTask2 function */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
printf("Task 2\n");
osDelay(1000);
}
/* USER CODE END StartTask2 */
}

• Compile and run project in debug and watch terminal window


Tasks lab 47

• If both Dealys are processed the FreeRTOS is in idle state


Priority level
osDelay osDelay Delay ends osDelay osDelay
High priority

Low priority Task1 Task2 Idle Task1 Task2

time

Task1 Task1
Runing Runing Runing Runing Runing Runing
Task2 Task2
Task1
Ready Ready Ready Ready Ready Ready
Task2 Task2
Task1 Task1
Blocked Blocked Blocked Blocked Blocked Blocked
Task2 Task2 Task1

Suspend Suspend Suspend Suspend Suspend Suspend


Tasks lab 48

• Without Delays the threads will be in running state or in Ready state

• Use HAL_Delay
Priority level
SysTick SysTick SysTick SysTick SysTick
High priority

Low priority Task1 Task2 Task1 Task2 Task1

time

Task1 Task1
Runing Runing Runing Runing Runing Runing
Task2 Task2 Task1
Task1 Task1 Task1
Ready Ready Ready Ready Ready Ready
Task2 Task2 Task2 Task2

Blocked Blocked Blocked Blocked Blocked Blocked

Suspend Suspend Suspend Suspend Suspend Suspend


Tasks lab 49

• Set one task Higher priority

• Double click on task for change

• Button OK
Tasks lab 50

• After we 5x times send text put task to block state

• Because task have high priority it allow to run lower priority task
/* USER CODE END 4 */
void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
uint32_t i = 0;
/* Infinite loop */
for(;;)
{
for (i = 0; i < 5; i++){
printf("Task 1\n");
HAL_Delay(50); Helps not spam terminal
}
osDelay(1000);
} Block task
/* USER CODE END 5 */
}
Tasks lab 51

• If higher priority task is not running we can print text from this task
/* StartTask2 function */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
printf("Task 2\n"); Helps not spam terminal
HAL_Delay(50);
}
/* USER CODE END StartTask2 */
}
Tasks lab 52

• What happen if Task1 not call osDelay?

Priority level
osDelay Delay end osDelay Delay end osDelay
High priority

Task1 Task1 Task1


Low priority Task2 Task2

time

Task1 Task1
Runing Runing Runing Runing Runing Runing
Task2 Task2 Task1
Task1
Ready Ready Ready Ready Ready Ready
Task2 Task2 Task2 Task2
Task1 Task1
Blocked Blocked Blocked Blocked Blocked Blocked

Suspend Suspend Suspend Suspend Suspend Suspend


osDelay API 53

• Delay function
osStatus osDelay (uint32_t millisec)

• Delay function which measure time from which is delay measured

osStatus osDelayUntil (uint32_t PreviousWakeTime, uint32_t millisec)


osDelay function 54

• osDelay start measure time from osDelay call

Task 1 - Pri 1
Task 2 - Pri 2

Task 2 Task 1 Task 2


Pri 2 Pri 1 Pri 2

vTaskDela PendS vTaskDela


PendSV(idle)
y V y

Task 2
Delay end

Delay time
osDelayUntil 55

• osDelayUntil measure time from point which we selected

• This allow us to call task in regular intervals


Task 1 - Pri 1
Task 2 - Pri 2

Task 2 Task 1 Task 2


Pri 2 Pri 1 Pri 2

vTaskDelay
Until
PendSV vTaskDelay PendSV(idle)

Task 2
Delay end

DelayUntil time
osDelay and osDelayUntil 56

• Enable vTaskDelayUntil in Include parameters

• Regenerate project, modify tasks to:


void StartTask1(void const * argument)
{

/* USER CODE BEGIN 5 */


uint32_t i = 0;
/* Infinite loop */
for(;;)
{
printf("Task 1\n");
HAL_Delay(1000);
Delay between two
osDelay(2000); run is 2s
}
/* USER CODE END 5 */
}

/* StartTask2 function */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
printf("Task 2\n");
HAL_Delay(200);
}
/* USER CODE END StartTask2 */
}
osDelay and osDelayUntil 57

• Enable vTaskDelayUntil in Include parameters

• Regenerate project, modify tasks to:


void StartTask1(void const * argument)
{

/* USER CODE BEGIN 5 */ For osDelayUntil function


uint32_t wakeuptime;
we need mark wakeup
/* Infinite loop */
for(;;) time
{
wakeuptime=osKernelSysTick();
printf("Task 1\n");
HAL_Delay(1000);
osDelayUntil(wakeuptime,2000); Function will be
} executed every 2s
/* USER CODE END 5 */

} Time from Real delay time


which is delay
measured
Priority change lab 58

• Task1 have higher priority


than Task2

• If not enable vTaskPriorityGet


and uxTaskPrioritySet
in IncludeParameters
Priority change lab 59

• Modify Task1 to:


void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
osPriority priority;
/* Infinite loop */ Reads Task2 priority
for(;;)
{
priority=osThreadGetPriority(Task2Handle);
printf("Task 1\n");
osThreadSetPriority(Task2Handle,priority+1); Increase Task2 priority
HAL_Delay(1000);
}
/* USER CODE END 5 */
}
Priority change lab 60

• Modify Task2 to:


/* StartTask2 function */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
osPriority priority;
/* Infinite loop */ Read priority of current task
for(;;)
{
priority=osThreadGetPriority(NULL);
printf("Task 2\n");
osThreadSetPriority(NULL,priority-2); Decrease task priority
}
/* USER CODE END StartTask2 */
}
Priority change lab 61

• How priorities are changed?

Task 1 - Pri 6
Task 2 - Pri 4

Task 1 Task 1 Task 2 Task 1


PendSV
Pri 6 Pri 6 Pri 6 Pri 6

vTaskPrioritySet vTaskPrioritySet vTaskPrioritySet


Task 2 Pri +1 Task 2 Pri +1 PendSV Task 2 Pri -2 PendSV

Task 2 - Pri 5 Task 2 - Pri 6 Task 2 - Pri 4


Creating and deleting tasks lab 62

• Example how to create and delete tasks

Task 1 - Pri 1

Task 1 Task 1 Task 1


Pri 1 Pri 1 Pri 1

Task 2
xTaskCreate PendSV vTaskDelay PendSV(idle)
Pri 2

vTaskDelete PendSV Task 1


Delay end
Creating and deleting tasks lab 63

• Example how to create and delete tasks

• Comment Task2 creation part in main.c


/* definition and creation of Task2 */
// osThreadDef(Task2, StartTask2, osPriorityNormal, 0, 128);
// Task2Handle = osThreadCreate(osThread(Task2), NULL);

• Modify Task1 to create task2


void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
printf("Create task2");
osThreadDef(Task2, StartTask2, osPriorityNormal, 0, 128);
Task2Handle = osThreadCreate(osThread(Task2), NULL);
osDelay(1000);
} Task 2 creation
/* USER CODE END 5 */
}
Creating and deleting tasks lab 64

• Example how to create and delete tasks

• Modift Task2 to delete him-self:


/* StartTask2 function */
void StartTask2(void const * argument)
{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
printf("Delete Task2\n");
osThreadTerminate(Task2Handle);
} Delete Task
/* USER CODE END StartTask2 */
}
FreeRTOS
Queues
Queue 66

Sender Task Receiver Task


Message 1
osMessagePut

Sender Task Receiver Task


Message 2 Message 1
osMessagePut

Sender Task Receiver Task


Message 2 Message 1
osMessageGet

Sender Task Receiver Task


Message 2
osMessageGet

Sender Task Receiver Task


Queue 67

• Create Queue:
osMessageQId osMessageCreate (const osMessageQDef_t *queue_def, osThreadId thread_id)

Queue Handle Create Queue

• Put data into Queue


osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec)

Queue Handle Item to send Send timeout

• Receive data from Queue


osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec)

Structure with status Queue handle Receiving timeout


and with received
item
Queue 68

• osEvent structure
typedef struct {
osStatus status; ///< status code: event or error information
union {
uint32_t v; ///< message as 32-bit value
void *p; ///< message or mail as void pointer
int32_t signals; ///< signal flags
} value; ///< event value
union {
osMailQId mail_id; ///< mail id obtained by \ref osMailCreate
osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
} def; ///< event definition
} osEvent;

• If we want to get data from osEvent we must use:


• osEventName.v if the value is 32bit message(or 8/16bit)
• osEventName.p and retype on selected datatype
Queue lab 69

• Set both tasks to normal priority

• Queue part

• Button Add

• Set queue size to 256

• Queue type to uint8_t

• Button OK
Queue lab 70

• Queue handler is now defined


/* Private variables ---------------------------------------------------------*/
osThreadId Sender1Handle;
osThreadId ReceiverHandle;
osMessageQId Queue1Handle;

• Queue item type initialization, length definition and create of queue and
memory allocation
/* Create the queue(s) */ Queue item definition
/* definition and creation of Queue1 */
osMessageQDef(Queue1, 256, uint8_t);
Queue1Handle = osMessageCreate(osMessageQ(Queue1), NULL);

Queue size
Queue lab 71

• Sender1 task
void StartSender1(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;) Put value ‘1’ into queue
{
printf("Task1\n");
Item to send
osMessagePut(Queue1Handle,0x1,200);
printf("Task1 delay\n"); Timeout for send
osDelay(1000);
} Queue handle
/* USER CODE END 5 */
}
Queue lab 72

• Teceiver task
/* StartReceiver function */
void StartReceiver(void const * argument)
{
/* USER CODE BEGIN StartReceiver */
osEvent retvalue;
/* Infinite loop */
for(;;) Get item from queue
{
printf("Task2\n"); How long we wait on data in
retvalue=osMessageGet(Queue1Handle,4000); queue
printf(“%d \n",retvalue.value.p); It will Block task
}
/* USER CODE END StartReceiver */ Queue handle
}
Queue Blocking 73

Sender Task Receiver Task


Blocked
osMessageGet

Sender Task Receiver Task


Message 1
Blocked
osMessagePut osMessageGet

Sender Task Receiver Task


Message 1 Blocked
osMessageGet

Sender Task Receiver Task


Queue Blocking 74

• After calling osMessageGet

• If any data are not in queue the task I blocked for settable time

• If the data are in queue the task will continue

Sender1- Pri 1
Receiver- Pri 1

Receiver Sender1 Receiver Sender1


Pri 1 Pri 1 Pri 1 Pri 1

xQueueReceive PendSV xQueueSend PendSV xQueueReceive PendSV


Two senders lab 75

• Two sending tasks

• One receivers tasks

• Same priorities
Two senders lab 76

• Two sending tasks

• They are same no change necessary

void StartSender1(void const * argument) void StartSender2(void const * argument)


{ {
/* USER CODE BEGIN 5 */ /* USER CODE BEGIN StartSender2 */
/* Infinite loop */ /* Infinite loop */
for(;;) for(;;)
{ {
printf("Task1\n"); printf("Task2\n");
osMessagePut(Queue1Handle,0x1,200); osMessagePut(Queue1Handle,0x2,200);
printf("Task1 delay\n"); printf("Task2 delay\n");
osDelay(2000); osDelay(2000);
} }
/* USER CODE END 5 */ /* USER CODE END StartSender2 */
} }
Two senders lab 77

• Simple receiver
/* StartReceiver function */
void StartReceiver(void const * argument)
{
/* USER CODE BEGIN StartReceiver */
osEvent retvalue;
/* Infinite loop */
for(;;)
{
retvalue=osMessageGet(Queue1Handle,4000);
printf("Receiver\n");
printf("%d \n",retvalue.value.p);
}
/* USER CODE END StartReceiver */
}
Two senders lab 78

• What we can see in debug now?

• Because tasks have same priority, receiver will get data from queue after both
task put data into queue

• What happened if will be more tesks?

Sender1- Pri 1 Receiver Sender1 Sender2


Sender2- Pri 1 Pri 1 Pri 1 Pri 1
Receiver- Pri 1

xQueueReceive PendSV xQueueSend PendSV xQueueSend

Receiver Sender1
Pri 1 Pri 1

PendSV xQueueReceive PendSV


Receiver with higher priority lab 79

• Senders have same priority

• Receiver have higher priority than


senders
Receiver with higher priority lab 80

• Receiver is now unblocked every time when sender tasks put data into queue

Sender1- Pri 1
Sender2- Pri 1
Receiver- Pri 2

Receiver Sender1 Receiver Sender2


Pri 2 Pri 1 Pri 2 Pri 1

xQueueReceive PendSV xQueueSend PendSV xQueueReceive PendSV

Sender1 Receiver
Pri 1 Pri 2

xQueueSend PendSV xQueueReceive


Queue items lab 81

• Queues allow to define type


(different variables or structures)
which the queue use.

• Regenerate project
Queue items lab 82

• Item size will be structure called


Data
Queue items lab 83

• Create new structure type for data


/* Define the structure type that will be passed on the queue. */
typedef struct
{
uint8_t Value;
uint8_t Source;
} Data;

• Define Structures which will be sent from sender task


/* Declare two variables of type Data that will be passed on the queue. */
Data DataToSend1={10,1};
Data DataToSend2={20,2};
Queue items lab 84

• Sent data from Sender task


void StartSender1(void const * argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;) Put data into queue
{
printf("Task1\n");
osMessagePut(Queue1Handle,(uint32_t)&DataToSend1,200);
printf("Task1 delay\n");
osDelay(2000);
}
/* USER CODE END 5 */
}
Queue items lab 85

• Receiver data from sender task


/* StartReceiver function */
void StartReceiver(void const * argument)
{
/* USER CODE BEGIN StartReceiver */
osEvent retvalue;
/* Infinite loop */ Get data from queue
for(;;)
{
retvalue=osMessageGet(Queue1Handle,4000);
if(((Data*)retvalue.value.p)->Source==1){
printf("Receiver Receive message from Sender 1\n");
}else{ Decode data from osEvent structure
printf("Receiver Receive message from Sender 2\n");
}
printf("Data: %d \n",((Data*)retvalue.value.p)->Value);
}
/* USER CODE END StartReceiver */
}
FreeRTOS
Semaphores
Semaphores 87

• Used for synchronization between


• Tasks
• Interrupt and task

• Two types
• Binary semaphores
• Counting semaphores

• Binary semaphore
• Have only one ‘token’
• Using to synchronize one action

• Counting semaphore
• Have multiple ‘tokens’
• Synchronize multiple actions
Binary Semaphore 88

Task1 Task2
Blocked
osSemaphoreWait

Task1 Task2
Blocked
osSemaphoreRelease osSemaphoreWait

Task1 Task2
Blocked
osSemaphoreWait

Task1 Task2

osSemaphoreRelease

Task1 Task2

osSemaphoreWait
Binary Semaphore 89

• Semaphore creation
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)

Semaphore Semaphore Semaphore ‘tokens’


handle definition For binary semaphore
is 1
• Wait for Semaphore release
int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)

Number of ‘tokens Semaphore How long wait for


in semaphore’ handle semaphore release

• Semaphore release
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)

Return Semaphore
status handle
Binary Semaphore lab 90

• Create two tasks

• With same priority

• Button Add

• Set parameters

• Button OK
Binary Semaphore lab 91

• Create binary binary semaphore

• Button Add

• Set name

• Button OK
Binary Semaphore lab 92

• Task1 is synchronized with Task2

Task1 - Pri 1
Task2 - Pri 1

Task1 Task2 Task1 Task2


Pri 1 Pri 1 Pri 1 Pri 1

osSemaphore osSemaphore osSemaphore


Wait PendSV Release PendSV Wait PendSV
Binary Semaphore lab 93

• Semaphore handle definition


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osThreadId Task2Handle;
osSemaphoreId myBinarySem01Handle;

• Semaphore creation
/* Create the semaphores(s) */
/* definition and creation of myBinarySem01 */
osSemaphoreDef(myBinarySem01);
myBinarySem01Handle = osSemaphoreCreate(osSemaphore(myBinarySem01), 1);
Binary Semaphore lab 94

• Semaphore use

• If tasks/interrupt is done the semaphore is released

void StartTask1(void const * argument)


{

/* USER CODE BEGIN 5 */


/* Infinite loop */
for(;;)
{
osDelay(2000);
printf("Task1 Release semaphore\n");
osSemaphoreRelease(myBinarySem01Handle);
}
/* USER CODE END 5 */
}
Binary Semaphore lab 95

• Semaphore Wait

• Second task waits on semaphore release


After releasetask is unbocked and continue in work

void StartTask2(void const * argument)


{
/* USER CODE BEGIN StartTask2 */
/* Infinite loop */
for(;;)
{
osSemaphoreWait(myBinarySem01Handle,4000);
printf("Task2 synchronized\n");
}
/* USER CODE END StartTask2 */
}
Counting semaphore 96

• Os API same as Binary semaphore

• Semaphore creation
osSemaphoreId osSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count)

• Wait for Semaphore release


int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec)

• Semaphore release
osStatus osSemaphoreRelease (osSemaphoreId semaphore_id)
Counting Semaphore 97

Task1 Task2 Task3

osSemaphoreRelease

Task1 Task2 Task3

osSemaphoreRelease

Task1 Task2 Task3


Task2
Blocked
osSemaphoreWait

Task1 Task2 Task3


Task2
Blocked
osSemaphoreWait

Task1 Task2 Task3


Blocked
osSemaphoreWait
Counting Semaphore lab 98

• Create three tasks

• With same priority

• Button Add

• Set parameters

• Button OK
Counting Semaphore lab 99

• Create Counting semaphore

• Set count of tokens

• Button Add

• Set name

• Button OK
Counting Semaphore lab 100

• Task1 and Task2 release semaphore

• Task 3 wait for two tokens


Task1- Pri 1
Task2- Pri 1
Task3- Pri 1
Task3 Task1 Task2 Task3
Pri 1 Pri 1 Pri 1 Pri 1

osSemaphore osSemaphore osSemaphore


Wait
PendSV Release
PendSV Release PendSV

Task3 Task1
Pri 1 Pri 1

osSemaphore osSemaphore osSemaphore


Wait Wait
PendSV Release
Counting Semaphore lab 101

• Create Counting semaphore


/* Create the semaphores(s) */
/* definition and creation of myCountingSem01 */
osSemaphoreDef(myCountingSem01);
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 2);

• Task1 and Task2 will be same


void StartTask1(void const * argument)
{

/* USER CODE BEGIN 5 */ void StartTask2(void const * argument)


/* Infinite loop */ {
for(;;) /* USER CODE BEGIN StartTask2 */
{ /* Infinite loop */
osDelay(2000); for(;;)
printf("Task1 Release counting semaphore\n"); {
osSemaphoreRelease(myCountingSem01Handle); osDelay(2000);
} printf("Task2 Release counting semaphore\n
/* USER CODE END 5 */ osSemaphoreRelease(myCountingSem01Handle);
} }
/* USER CODE END StartTask2 */
}
Counting Semaphore lab 102

• Task3 will wait until semaphore will be 2 times released


void StartTask3(void const * argument)
{
/* USER CODE BEGIN StartTask3 */
/* Infinite loop */
for(;;)
{
osSemaphoreWait(myCountingSem01Handle, 4000);
osSemaphoreWait(myCountingSem01Handle, 4000);
printf("Task3 synchronized\n");
}
/* USER CODE END StartTask3 */
}
FreeRTOS
Mutex
Mutex 104

• Used to guard access to limited recourse

• Work very similar as Semaphores

Task1 Task1

osMutexWait Resource
Resourse Resourse
Resource

Task2 Task2
Blocked Blocked
osMutexWait osMutexWait

Task1 Task1

osMutexRelease Resourse
Resource Resourse
Resource

Task2 Task2
Blocked
osMutexWait osMutexRelease
Mutex 105

• Mutex creation
osMutexId osMutexCreate (const osMutexDef_t *mutex_def)

Mutex Mutex
handle definition
• Wait for Mutex release
osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec)

Return status Mutex How long wait for


handle mutex release

• Mutex release
osStatus osMutexRelease (osMutexId mutex_id)

Return Mutex
status handle
Mutex lab 106

• Create two tasks

• With same priority

• Button Add

• Set parameters

• Button OK
Mutex lab 107

• Create Mutex

• Button Add

• Set name

• Button OK
Mutex lab 108

• Both tasks using printf function.

• Mutex is used to avoid collisions

Task1- Pri 1
Task2- Pri 1

Task1 Task2
Pri 1 Pri 1

osMutexWait Print osMutexRelease osDelay PendSV osMutexWait Print

Only one task can have semaphore


Mutex lab 109

• Mutex handle definition


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osThreadId Task2Handle;
osMutexId myMutex01Handle;

• Mutex creation
/* Create the mutex(es) */
/* definition and creation of myMutex01 */
osMutexDef(myMutex01);
myMutex01Handle = osMutexCreate(osMutex(myMutex01));
Mutex lab 110

• Semaphore use

• If tasks/interrupt is done the semaphore is released

void StartTask1(void const * argument)


{

/* USER CODE BEGIN 5 */


/* Infinite loop */
for(;;)
{
osDelay(2000);
printf("Task1 Release semaphore\n");
osSemaphoreRelease(myBinarySem01Handle);
}
/* USER CODE END 5 */
}
Mutex lab 111

• Task1 and Task2 using of Mutex


void StartTask1(void const * argument) void StartTask2(void const * argument)
{ {
/* USER CODE BEGIN 5 */ /* USER CODE BEGIN StartTask2 */
/* Infinite loop */ /* Infinite loop */
for(;;) for(;;)
{ {
osDelay(2000); osDelay(2000);
osMutexWait(myMutex01Handle,1000); osMutexWait(myMutex01Handle,1000);
printf("Task1 Print\n"); printf("Task2 Print\n");
osMutexRelease(myMutex01Handle); osMutexRelease(myMutex01Handle);
} }
/* USER CODE END 5 */ /* USER CODE END StartTask2 */
} }
FreeRTOS
Software Timers
Software Timers 113

• Software timer is one of component in RTOS

• Can extend number of Timers in STM32

• Are not precise but can handle periodic actions or delay actions

• Two modes
• Periodic

Task1 Software Software


Timer Callback Timer Callback
osTimerStart

Software timer counting Software timer counting So

• One Pulse

Task1 Software
Timer Callback
osTimerStart

Software timer counting


Software Timers 114

• Software timer creation


osTimerId osTimerCreate (const osTimerDef_t *timer_def, os_timer_type type, void *argument)

Timer Repeat timing or


Timer definition
handle onetime timing
• Software timer start
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec)

Return status Timer


Timer period
handle

• Software timer stop


osStatus osTimerStop (osTimerId timer_id)

Return
Timer handle
status
Software Timers lab 115

• Software timers are by


default disabled in CubeMX

• FreeRTOS configuration

• Configuration TAB

• Enable Software timers


Software Timers lab 116

• Create one task

• Button Add

• Set parameters

• Set name

• Button OK
Software Timers lab 117

• Create Timer

• Button Add

• Set timer name

• Timer callback name

• Button OK
Software Timers lab 118

• Software timer handle definition


/* Private variables ---------------------------------------------------------*/
osThreadId Task1Handle;
osTimerId myTimer01Handle;

• Software timer creation


/* Create the timer(s) */
• /* definition and creation of myTimer01 */
osTimerDef(myTimer01, Callback01);
myTimer01Handle = osTimerCreate(osTimer(myTimer01), osTimerPeriodic, NULL);

• Software timer start


void StartTask1(void const * argument)
{
/* USER CODE BEGIN 5 */
osTimerStart(myTimer01Handle,1000);
/* Infinite loop */
for(;;)
{
osDelay(2000);
printf("Task1 Print\n");
}
/* USER CODE END 5 */
}
Software Timers lab 119

• Software timer callback


/* Callback01 function */
void Callback01(void const * argument)
{
/* USER CODE BEGIN Callback01 */
printf("Timer Print\n");
/* USER CODE END Callback01 */
}
FreeRTOS advanced
Hooks
Hooks 121

• Callbacks supported by FreeRTOS core

• Can help with FreeRTOS fault handling

• Type of hooks:
• Idle Hool
• Tick Hook
• Malloc Failed Hook
• Stack Overflow Hook

• CubeMX will create hooks in freertos.c file


Idle Hook 122

• If the scheduler cannot run any task


it goes into idle mode

• Idle hook is callback from idle mode

• In to this task is possible to put


power saving function
Idle Hook 123

• Idle hook callback in freertos.c created by CubeMX


/* USER CODE END FunctionPrototypes */
/* Hook prototypes */
void vApplicationIdleHook(void);

/* USER CODE BEGIN 2 */


void vApplicationIdleHook( void )
{
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
task. It is essential that code added to this hook function never attempts
to block in any way (for example, call xQueueReceive() with a block time
specified, or call vTaskDelay()). If the application makes use of the
vTaskDelete() API function (as this demo application does) then it is also
important that vApplicationIdleHook() is permitted to return to its calling
function, because it is the responsibility of the idle task to clean up
memory allocated by the kernel to any task that has since been deleted. */
}
/* USER CODE END 2 */

• Do not use blocking functons(osDelay, …) in this function or while(1)


Idle Hook 124

• If the scheduler cannot run any task


it goes into idle mode

• Idle hook is callback from idle mode

• In to this task is possible to put


power saving function
Idle Hook 125

• Idle hook callback in freertos.c created by CubeMX


/* USER CODE END FunctionPrototypes */
/* Hook prototypes */
void vApplicationIdleHook(void);

/* USER CODE BEGIN 2 */


void vApplicationIdleHook( void )
{
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
task. It is essential that code added to this hook function never attempts
to block in any way (for example, call xQueueReceive() with a block time
specified, or call vTaskDelay()). If the application makes use of the
vTaskDelete() API function (as this demo application does) then it is also
important that vApplicationIdleHook() is permitted to return to its calling
function, because it is the responsibility of the idle task to clean up
memory allocated by the kernel to any task that has since been deleted. */
}
/* USER CODE END 2 */

• Do not use blocking functons(osDelay, …) in this function or while(1)


Tick Hook 126

• Every time the SysTick interrupt is


trigger the TickHook is called

• Is possible use TickHook for periodic


events like watchdog refresh
Tick Hook 127

• Tick hook callback in freertos.c created by CubeMX


/* Hook prototypes */
void vApplicationTickHook(void);

/* USER CODE BEGIN 3 */


void vApplicationTickHook( void )
{
/* This function will be called by each tick interrupt if
configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h. User code can be
added here, but the tick hook is called from an interrupt context, so
code must not attempt to block, and only the interrupt safe FreeRTOS API
functions can be used (those that end in FromISR()). */
}
/* USER CODE END 3 */

• Do not use blocking functons(osDelay, …) in this function or while(1)


Malloc Failed Hook 128

• This callback is called if the memory


allocation process fails

• Helps to react on malloc problems,


when function return is not handelt
Malloc Failed Hook 129

• Malloc Failed hook callback in freertos.c created by CubeMX


/* Hook prototypes */
void vApplicationMallocFailedHook(void);

/* USER CODE BEGIN 5 */


void vApplicationMallocFailedHook(void)
{
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
pvPortMalloc() is called internally by the kernel whenever a task, queue,
timer or semaphore is created. It is also called by various parts of the
demo application. If heap_1.c or heap_2.c are used, then the size of the
heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
to query the size of free heap space that remains (although it does not
provide information on how the remaining heap might be fragmented). */
}
/* USER CODE END 5 */

• Do not use blocking functons(osDelay, …) in this function or while(1)


Malloc Failed Hook 130

• Malloc fail test

• Malloc fail hook:


/* USER CODE BEGIN 5 */
void vApplicationMallocFailedHook(void)
{
printf("malloc fails\n");
}
/* USER CODE END 5 */

• Do impossible memory allocation


void StartTask1(void const * argument) /* Private variables --------------------
{ osThreadId Task1Handle;
/* USER CODE BEGIN 5 */ osPoolId PoolHandle;
osPoolDef(Memory,0x10000000,uint8_t);
/* Infinite loop */
for(;;) Impossible memory allocation
{
PoolHandle = osPoolCreate(osPool(Memory));
osDelay(5000);
}
/* USER CODE END 5 */
}
Stack overflow hook 131
Stack overflow hook 132

• FreeRTOS is able to check stack


against overflow

• Two options

• Option 1
• FreeRTOS check if the stack is in range
which was defined on task creation

• Option 2
• FreeRTOS use Option 1
• Secondary on the bottom of the stack is
known pattern
• If pattern is overwritten the stack is corrupted
Stack overflow hook 133

• Stack overflow hook callback in freertos.c created by CubeMX


/* Hook prototypes */
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);

/* USER CODE BEGIN 4 */


void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
{
/* Run time stack overflow checking is performed if
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is
called if a stack overflow is detected. */
}
/* USER CODE END 4 */

• Do not use blocking functons(osDelay, …) in this function or while(1)


End
Thanks for your attention

You might also like