[getting started with FreeRTOS] FreeRTOS kernel control

Posted by scott_ttocs46 on Mon, 10 Jan 2022 07:58:19 +0100

FreeRTOS kernel control

FreeRTOS has some functions only for the kernel, which are generally not allowed by applications. These are the system kernel functions.

Kernel control function API

  • taskYIELD(): task switching
  • taskENTER_CRITICAL(): enter the critical area, which is used in the task
  • taskEXIT_CRITICAL(): exit the critical area, which is used in the task
  • taskENTER_CRITICAL_FROM_ISR(): enter the critical area, which is used in the interrupt service function
  • taskEXIT_CRITICAL_FROM_ISR(): exit the critical area, which is used in the interrupt service function
  • taskDISABLE_INTERRUPTS(): turn off interrupts
  • taskENABLE_INTERRUPTS(): enable interrupt
  • vTaskStartScheduler(): start the task scheduler
  • vTaskEndScheduler(): close the task scheduler
  • Vtask suspendall(): suspend task scheduler
  • Xtask resumeall(): resume task scheduler
  • vTaskStepTick(): set the system metronome

Detailed explanation of control function

taskYIELD(): task switching

This function is used for task switching. It is essentially a macro. This function will be explained in detail later.

taskENTER_CRITICAL(): enter the critical area, which is used in the task

Enter the critical area, which is used in the task function. It is essentially a macro

Critical section

Critical segments are code segments that cannot be interrupted during execution. There are usually two situations in which the critical section will be interrupted, one is system scheduling, and the other is external interrupt. Therefore, FreeRTOS's protection of the critical section finally returns to the control of interrupt on and off.

Quick switch interrupt command

Correlation register

name Function description
PRIMASK This is a single bit register. After it is set to 1, all maskable are turned off, leaving only NMI and hard FAULT to respond. Its default value is 0, indicating that there is no shutdown interrupt.
FAULTMASK This is a 1-bit register. When it is set to 1, only NMI can respond, and all other exceptions, even hard FAULT, cannot respond. Its default value is 0, indicating that there is no interrupt off
BASEPRI This register has a maximum of 9 bits (determined by the number of bits expressing priority). It defines the threshold of the masked priority. When it is set to a certain value, all interrupts with priority number greater than or equal to this value are turned off (the higher the priority number, the lower the priority). However, if it is set to 0, no interrupt will be closed, and 0 is also the default value.
CPSID I ; PRIMASK=1 Off interrupt
CPSIE I ; PRIMASK=0 Open interrupt
CPSID F ; FAULTMASK=1 Guan anomaly
CPSIE F ; FAULTMASK=0 Abnormal opening

Open portmacro H file

#define portDISABLE_INTERRUPTS()				vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS()				vPortSetBASEPRI( 0 )

The source code is as follows

/*-----------------------------------------------------------*/

	static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
	__asm
	{
		/* Barrier instructions are not used as this function is only used to
		lower the BASEPRI value. */
		msr basepri, ulBASEPRI
	}
}
/*-----------------------------------------------------------*/

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/* Set BASEPRI to the max syscall priority to effect a critical
		section. */
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}
  • vPortSetBASEPRI(0) writes 0 to basepri, indicating that no interrupt is masked
  • vPortRaiseBASEPRI() writes the minimum value to basepri, indicating that all freertos interrupts are shielded

Note:
DSB: data synchronization isolation. More stringent than DMB, only if all memory access operations in front of it
After all instructions are executed, the instructions behind them are executed (that is, any instructions have to wait for memory access operation)
ISB: instruction synchronous isolation. Strictest: it cleans the pipeline to ensure that all the instructions in front of it are executed
After the line is completed, the instructions after it are executed.

Critical segments and interrupt nesting

/*Interrupt function without interrupt protection*/
#define portENABLE_INTERRUPTS()					vPortSetBASEPRI( 0 )
/*Interrupt function with interrupt protection*/
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)	vPortSetBASEPRI(x)

As shown above, the interrupt function with interrupt protection is designed to interrupt nesting

For example:

  • Start, set the interrupt mask vPortSetBASEPRI(11), set the interrupt mask above 11, and the return value is 0
  • Then, set the interrupt mask vPortSetBASEPRI(5), set the interrupt mask above 5, and the return value is 11. Here, save 11
  • After the task in the interrupt mask is completed, it is set to 11, which plays the role of protecting the previous interrupt mask

Enter critical section

The critical segment is entered. The version without interrupt protection cannot be nested

/*In task Defined in H (217)*/
#define taskENTER_CRITICAL()		portENTER_CRITICAL()

/*In portmacro Defined in H (149)*/
#define portENTER_CRITICAL()					vPortEnterCritical()

Enter the critical section, with interrupt protection version, and can be nested

/*In task Defined in H (218)*/
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()

/*In portmacro Defined in H (151)*/
#define portSET_INTERRUPT_MASK_FROM_ISR()		ulPortRaiseBASEPRI()

Exit critical section

Exit critical segment, version without interrupt protection, and cannot be nested

/*In task Defined in H (232)*/
#define taskEXIT_CRITICAL()			portEXIT_CRITICAL()

/*In portmacro Defined in H (150)*/
#define portEXIT_CRITICAL()						vPortExitCritical()

Enter the critical section, with interrupt protection version, and can be nested

/*In task Defined in H (233)*/
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )

/*In portmacro Defined in H (152)*/
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)	vPortSetBASEPRI(x)

Application of critical section

  • In case of interruption, critical segments can be nested
{
    uint32_t ulReturn;
    ulReturn = taskENTER_CRITICAL_FROM_ISR(); //Enter critical section
    /*Critical segment code*/
    taskEXIT_CRITICAL_FROM_ISR(ulReturn); //Exit critical section
}

  • In the case of non interruption, critical segments cannot be nested
{
    taskENTER_CRITICAL(); //Enter critical section
    /*Critical segment code*/
    taskEXIT_CRITICAL(); //Exit critical section
}

Topics: Operating System FreeRTOS