在FreeRTOS中,使用三个宏重写了中断,实现任务调度。
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
在使用STM32 HAL库时,需要在stm32f1xx_it.c
文件中找到被重写的函数体,加上__weak
,防止重定义。
__weak void SysTick_Handler(void){/*...*/}
__weak void PendSV_Handler(void){/*...*/}
__weak void SVC_Handler(void){/*...*/}
SVC_Handler
FreeRTOS中,TCB
(任务控制块)是用来管理任务的关键结构体,它包含了管理和调度任务所需的所有信息。
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack;
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t * pxStack;
char pcTaskName[ configMAX_TASK_NAME_LEN ];
} tskTCB;
.
在《Cortex™-M3 Devices Generic User Guide》中关于SP和LR的描述。
Stack Pointer
The Stack Pointer (SP) is register R13. In Thread mode, bit[1] of the CONTROL register indicates the stack pointer to use:
- 0 = Main Stack Pointer (MSP). This is the reset value.
- 1 = Process Stack Pointer (PSP).
On reset, the processor loads the MSP with the value from address 0x00000000.
Link Register
The Link Register (LR) is register R14. It stores the return information for subroutines, function calls, and exceptions.
On reset, the processor sets the LR value to 0xFFFFFFFF.
.SVC_Handler
具体的汇编程序如下。
SVC_Handler
; 加载pxCurrentTCB地址到R3
LDR r3,[pc,#28] ; LDR R3, =pxCurrentTCB
; 加载当前任务的堆栈地址到R0
LDR r1,[r3,#0]
LDR r0,[r1,#0]
; 从R0指向的堆栈中恢复R4到R11的值,并更新堆栈指针R0
LDM r0!,{r4-r11}
; 将当前线程的堆栈指针更改为R0中的值。
MSR PSP,r0
; 指令同步屏障,确保之前的所有指令完成执行
ISB
; BASEPRI 寄存器中的值存储的是最低的允许运行中断号
; MSR 指令将通用寄存器的内容移动到指定的特殊寄存器中
; 清除基础优先级寄存器BASEPRI,允许所有优先级的中断
MOV r0,#0
MSR BASEPRI,r0
; 通过设置LR[3:0]的值为0X0D,设置堆栈指针为PSP
ORR lr,lr,#0xd
BX lr
.
SysTick_Handler
SysTick_Handler
是一个定时中断服务函数,默认为1ms触发一次。在FreeRTOS中,它被用作触发PendSV
中断,实际的任务切换在PendSV_Handler
函数中执行。
void xPortSysTickHandler( void )
{
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required.*/
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}
.
PendSV_Handler
.PendSV_Handler
具体的汇编程序如下。
PendSV_Handler
; MSR 指令将特殊寄存器的内容移动到指定的通用寄存器中
MRS r0,PSP
; 指令同步屏障,确保之前的所有指令完成执行
ISB
LDR r3,[pc,#52] ; [0x8002020] = 0x2000024c
LDR r2,[r3,#0]
STMDB r0!,{r4-r11}
STR r0,[r2,#0]
PUSH.W {r3,lr}
MOV r0,#0x50
MSR BASEPRI,r0
BL vTaskSwitchContext
MOV r0,#0
MSR BASEPRI,r0
POP {r3,lr}
LDR r1,[r3,#0]
LDR r0,[r1,#0]
LDM r0!,{r4-r11}
MSR PSP,r0
; 指令同步屏障,确保之前的所有指令完成执行
ISB
BX lr
.
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
{ \
List_t * const pxConstList = ( pxList ); \
/* Increment the index to the next item and return the item, ensuring */ \
/* we don't return the marker used at the end of the list. */ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
{ \
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
} \
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
}
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority = uxTopReadyPriority; \
\
/* Find the highest priority queue that contains ready tasks. */ \
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) ) \
{ \
configASSERT( uxTopPriority ); \
--uxTopPriority; \
} \
\
/* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
* the same priority get an equal share of the processor time. */ \
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
uxTopReadyPriority = uxTopPriority; \
}
void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
{
/* The scheduler is currently suspended - do not allow a context
* switch. */
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
/* Select a new task to run using either the generic C or port
* optimised asm code. */
taskSELECT_HIGHEST_PRIORITY_TASK();
}
}
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。