FreeRTOS learning notes

FreeRTOS programming conventions

  • port means interface
  • int type is never used, only short and long types are used. In the MCU of Cortex-M kernel, short is 16 bits and long is 32 bits
  • Data type redefinition is implemented in the header file portmacro.h
    *In keil, the default char is unsigned

Variable prefix

  1. The prefix of char type variable is c,
  2. The prefix of a short variable is s,
  3. The prefix of a long variable is l,
  4. portBASE_ The prefix of type variable is x.
  5. There are other data types, such as data structure, task handle, queue handle, etc. the prefix of variable name defined is also x
  6. Unsigned, there will be a prefix u
  7. A pointer variable will have a previous
    p.

Function prefix

  1. Private functions are prefixed with prv (private)
  2. The function name contains the type of the return value of the function, the file name of the function and the function of the function

Macro definition

  • Macros are represented by uppercase letters and prefixed with lowercase letters. The prefix is used to indicate which header file the macro is in
    Righteousness,
  • Note that the functions of semaphores are all macro definitions, but the naming method of their functions follows the naming method of functions rather than macro definitions

Porting FreeRTOS

  • Use V9.0.0
  • FreeRTOS uses dynamic memory allocation when creating kernel objects
  • Preemptive scheduling: in this scheduling mode, the system always selects the task with the highest priority
    Row scheduling, and once the high priority task is ready, it will be scheduled without waiting for the low priority task
    Tasks voluntarily give up the CPU. High priority tasks seize the CPU use right of low priority tasks, which is preemption,
    In the internship operating system, this method is often the most applicable
  1. Add source file

  2. Add the interface file and memory allocation method file. Add the port.c file according to the kernel. At present, it is CotextM4

  3. Add header file FreeRTOSConfig.h

  4. Remove the original svc and PendSV interrupt functions
    4. Add header file path to mdk

There was a problem with the migration
A1586E: Bad operand types (UnDefOT, Constant) for operator
terms of settlement:
Change 4U of "stm32f407xx.h" file to 4

FreeRTOS startup process

  • FreeRTOS will automatically help us do initialization, such as initializing heap memory
  • Turning on the scheduler will help us create idle and scheduled tasks
  • Call the API function xTaskGetIdleTaskHandle() to get the free task handle.

task

  1. The task in FreeRTOS is a preemptive scheduling mechanism. High priority tasks can interrupt low priority tasks. Low priority tasks can be scheduled only after high priority tasks are blocked or finished.
  2. At the same time, FreeRTOS also supports time slice rotation scheduling, but time slice scheduling does not allow preemption of CPU usage of tasks.
  3. Other parts of the system can be preempted except the interrupt handling function, the code of the scheduler locking part and the code of prohibiting interrupt
  4. 0 is the lowest priority and is allocated to idle tasks. Generally, users are not recommended to use this priority. Generally, 32 priorities are set
  5. The FreeRTOS kernel also allows the creation of tasks of the same priority. Tasks with the same priority are scheduled by time slice rotation (commonly known as time-sharing scheduler). Time slice rotation scheduling is effective only when there are no ready tasks with higher priority in the current system

Task status

Task suspend function

  • A suspended task will never get CPU access, regardless of the priority of the task
void vTaskSuspend( TaskHandle_t xTaskToSuspend )

Suspend all tasks = suspend scheduler

The essence is to suspend the scheduler

 void vTaskSuspendAll( void )

Task recovery function

Put the task into ready state

 void vTaskResume( TaskHandle_t xTaskToResume )

**Interrupt function specific**
Xtask resumefromisr() cannot be used between tasks and interrupts
Synchronization of

 BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume )

Recovery dispatching area

BaseType_t xTaskResumeAll( void )

Dynamic task creation

TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,//Task function entry
									const char * const pcName,//Task name
									const uint32_t ulStackDepth,//Stack size
									void * const pvParameters,//Parameters passed to the task
									UBaseType_t uxPriority,//Task priority
									TaskHandle_t * const pxCreatedTask ) //Task control block 

#define pdFALSE			( ( BaseType_t ) 0 )
#define pdTRUE			( ( BaseType_t ) 1 )

#define pdPASS			( pdTRUE )
#define pdFAIL			( pdFALSE )
//Return: pdPASS creates the task successfully, and pdFAIL creates the task failed

Delete task

void vTaskDelete( TaskHandle_t xTaskToDelete )//Task handle returned when creating a task

Task delay

Unit: system beat period

void vTaskDelay( const TickType_t xTicksToDelay )

Absolute delay function vTaskDelayUntil()

 void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime,//Point to a variable that holds the time when the task was last unblocked. When used for the first time, the variable must be initialized to the current time, and then the variable will be automatically updated in the vTaskDelayUntil() function
										const TickType_t xTimeIncrement );//Cycle time. When the time is equal to (* pxPreviousWakeTime + xTimeIncrement), the task is unblocked

Start task scheduler

After starting the scheduler, the function will not return;

void vTaskStartScheduler( void )

Message queue

  • The transmitted data is of variable length
  • FIFO and LIFO are supported
  • Both support timeout mechanism.
  • Each message queue is in the same continuous memory space as the message space
  • The size of the message queue is the size of the message queue control block + (single message space size * message queue length)
  • Either the task or the interrupt service program can send messages to the message queue
  • Timeout sending. If timeout sending fails, return errQUEUE_FULL
  • To send an emergency message is to put it at the head of the queue
  • Support message read timeout
  • Include header file
#include <queue.h>
  • Message queue operation model

    3 cases of reading messages
  1. Take it out if you have it and leave without turning around
  2. No, wait a minute
  3. Death and other news
    send message
    Wait when the queue is full, and return errqueue when it times out_ FULL

Memory structure of message queue

data structure

typedef struct QueueDefinition
{
	int8_t *pcHead;					/*< Point to the beginning of the queue message store, that is, the first message space */
	int8_t *pcTail;					/* Address to the end of the queue message store */
	int8_t *pcWriteTo;				/*< Points to the next available message space in the queue message store */

	union							/* Is a pair of mutually exclusive variables*/. */
	{
		int8_t *pcReadFrom;			/*< Points to the last place that a queued item was read from when the structure is used as a queue. */
		UBaseType_t uxRecursiveCallCount;/*When the struct is used for mutexes, uxRecursiveCallCount is used for counting */
	} u;

	List_t xTasksWaitingToSend;		/*< Send message blocking list */
	List_t xTasksWaitingToReceive;	/*< Get message blocking list */

	volatile UBaseType_t uxMessagesWaiting;/*< Number of messages in the current message queue */
	UBaseType_t uxLength;			/*< Length of queue */
	UBaseType_t uxItemSize;			/*< Shows the size of a single message*/

	volatile int8_t cRxLock;		/*< After the queue is locked, the number of list items received from the queue, that is, the number of out of the queue, is stored. If the queue is not locked, it is set to queueUNLOCKED*/
	volatile int8_t cTxLock;		/*< After the queue is locked, the number of list items sent to the queue, that is, the number of queue entries, is stored. If the queue is not locked, it is set to queueUNLOCKED*/

	#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
		uint8_t ucStaticallyAllocated;	/*< Set to pdTRUE if the memory used by the queue was statically allocated to ensure no attempt is made to free the memory. */
	#endif

	#if ( configUSE_QUEUE_SETS == 1 )
		struct QueueDefinition *pxQueueSetContainer;
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t uxQueueNumber;
		uint8_t ucQueueType;
	#endif

} xQUEUE;

Message queuing function

//Macro definition
#define xQueueCreate( uxQueueLength, uxItemSize ) xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), ( queueQUEUE_TYPE_BASE ) )


QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,// The maximum number of message units that the queue can store and the number of messages that can be stored
 											UBaseType_t uxItemSize );//The size of the message unit in the queue, in bytes
 return NULL,Failed to create. The queue handle is returned successfully
queueQUEUE_TYPE_BASE: Represents a queue. 
queueQUEUE_TYPE_SET: Represents a collection of queues. 
queueQUEUE_TYPE_MUTEX: Represents a mutex. 
queueQUEUE_TYPE_COUNTING_SEMAPHORE: Indicates a count semaphore.
queueQUEUE_TYPE_BINARY_SEMAPHORE: Represents a binary semaphore. 
queueQUEUE_TYPE_RECURSIVE_MUTEX : Represents a recursive mutex.

Message queue delete function

 void vQueueDelete( QueueHandle_t xQueue )

Send message function

  1. Send a queue message to the end of the queue
  2. Messages are queued as copies, not as references
  3. This function must not be called in the interrupt service program,
  4. xQueueSendFromISR() with interrupt protection function is used instead of interrupt

Send message to tail

//
#define       xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

BaseType_t xQueueSend(QueueHandle_t xQueue,//Queue handle.
									 const void * pvItemToQueue,//Pointer to the queue message to be sent to the end of the queue
									 TickType_t xTicksToWait);//When the queue is full, the maximum timeout for waiting for the queue to be idle. The unit of timeout is the system beat cycle
//Return: pdTRUE is returned if the message is sent successfully. Otherwise, errqueue is returned_ FULL. 

Send message to header

//
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )

BaseType_t xQueueSendToFront( QueueHandle_t xQueue,//Queue handle.
												 const void * pvItemToQueue,//Pointer to the queue message to be sent to the end of the queue
												 TickType_t xTicksToWait );//The maximum timeout for waiting for the queue to become idle when the queue is full. If the queue is full and xTicksToWait is set to 0, the number is returned immediately. The unit of timeout is the system beat cycle, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, in ms. If include_ Vtask suspend is set to 1, and the specified delay is portMAX_DELAY will cause the task to block indefinitely (without timeout)
//Return: pdTRUE is returned if the message is sent successfully. Otherwise, errqueue is returned_ FULL. 

General version

BaseType_t xQueueGenericSend( QueueHandle_t xQueue, //Queue handle
												const void * const pvItemToQueue, //Pointer to the queue message to be sent to the end of the queue
												TickType_t xTicksToWait, //The maximum timeout for waiting for the queue to become idle when the queue is full. If the queue is full and xTicksToWait is set to 0, the number is returned immediately. The unit of timeout is the system beat cycle, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, in ms. If include_ Vtask suspend is set to 1, and the specified delay is portMAX_DELAY will cause the task to block indefinitely (without timeout)
												const BaseType_t xCopyPosition )// {queueSEND_TO_BACK: send to the end of the queue; queueSEND_TO_FRONT: send to the head of the queue; queueOVERWRITE: send by overwrite}

Interrupt message sending of protection version

Send message to queue header

//
#define xQueueSendToFrontFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_FRONT )

BaseType_t xQueueSendToFrontFromISR(QueueHandle_t xQueue,//Queue handle
														 const void *pvItemToQueue,//Pointer to the message to be sent to the end of the queue
														 BaseType_t *pxHigherPriorityTaskWoken);//If joining the queue causes a task to be unlocked, and the priority of the unlocked task is higher than that of the currently interrupted task, set * pxHigherPriorityTaskWoken to pdTRUE, and then perform a context switch before the interrupt exits to execute the awakened task with higher priority. Starting from FreeRTOS V7.3.0, pxHigherPriorityTaskWoken can be set to NULL as an optional parameter.
//Return value:
//pdTRUE is returned if the message is sent successfully, otherwise errqueue is returned_ FULL. 

Send message to end of queue

#define xQueueSendToBackFromISR( xQueue, pvItemToQueue, pxHigherPriorityTaskWoken ) xQueueGenericSendFromISR( ( xQueue ), ( pvItemToQueue ), ( pxHigherPriorityTaskWoken ), queueSEND_TO_BACK )

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,//Queue handle
											 const void *pvItemToQueue,//Pointer to the message to be sent to the end of the queue
											 BaseType_t *pxHigherPriorityTaskWoken);//If joining the queue causes a task to be unlocked, and the priority of the unlocked task is higher than that of the currently interrupted task, set * pxHigherPriorityTaskWoken to pdTRUE, and then perform a context switch before the interrupt exits to execute the awakened task with higher priority. Starting from FreeRTOS V7.3.0, pxHigherPriorityTaskWoken can be set to NULL as an optional parameter.

//Return value:
//pdTRUE is returned if the message is sent successfully, otherwise errqueue is returned_ FULL. 

Generic version of interrupt sending

 BaseType_t xQueueGenericSendFromISR(
										   QueueHandle_t		xQueue,
										   const	void	*pvItemToQueue,
										   BaseType_t	*pxHigherPriorityTaskWoken,
										   BaseType_t	xCopyPosition//{queueSEND_TO_BACK: send to the end of the queue; queueSEND_TO_FRONT: send to the head of the queue; queueOVERWRITE: send by overwrite}
									   );

Message reading function - normal version

//Remove acquired messages
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
 BaseType_t xQueueGenericReceive(
									   QueueHandle_t	xQueue,
									   void	*pvBuffer,//Pointer to the received data to be saved.
									   TickType_t	xTicksToWait,//The maximum time of blocking timeout when the queue is empty. If this parameter is set to 0, the function returns immediately. The unit of timeout is the system beat cycle, and the constant portTICK_PERIOD_MS is used to assist in calculating the real time, in ms. If include_ Vtask suspend is set to 1, and the specified delay is portMAX_DELAY will cause the task to block indefinitely (without timeout).
									   BaseType_t	xJustPeek,//Whether to remove pdFALSE; pdTRUE do not remove
									);
//pdTRUE is returned if the queue item is received successfully. Otherwise, pdFALSE is returned.

Message reading function - interrupt version

//Remove acquired messages
BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue, //Queue handle.
													void * const pvBuffer, //Pointer to the received data to be saved.
													BaseType_t * const pxHigherPriorityTaskWoken )//When a task delivers information to a queue, if the queue is full, the task will block on the queue. If xQueueReceiveFromISR() receives a task and unlocks it, set * pxHigherPriorityTaskWoken to pdTRUE. Otherwise, the value of * pxHigherPriorityTaskWoken will remain unchanged. Starting from FreeRTOS V7.3.0, pxHigherPriorityTaskWoken can be set to NULL as an optional parameter.
//Return value: pdTRUE is returned if the queue item is received successfully; otherwise, pdFALSE is returned.


//Do not remove acquired messages
BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, //Queue handle
												 void * const pvBuffer )//Pointer to the received data to be saved.

Precautions for using message queue

  1. Before using xQueueSend(), xQueueSendFromISR(), xQueueReceive() and other functions, you should first create the required message queue and operate according to the queue handle.
  2. The queue reading adopts the first in first out (FIFO) mode, and the data stored in the queue will be read first. Of course, FreeRTOS also supports the last in first out (LIFO) mode, which will read the data of the last in queue when reading.
  3. When getting messages in the queue, we must define a place to store and read data, and the size of the data area is not less than the message size. Otherwise, it is likely to cause an illegal address error.
  4. Whether sending or receiving messages, they are copied. If the message is too large, the address of the message can be sent and received as a message

Keywords: queue stm32 FreeRTOS

Added by hoolahoops on Wed, 17 Nov 2021 14:45:49 +0200