中断
切换任务,任务执行均在中断中进行
FreeRTOS中定义了一些宏来管理中断,优先级低于此宏的RTOS可以管理,高于此宏的RTOS无法管理——宏:configMAX_SYSCALL_INTERRUPT_PRIORITY
临界段保护:屏蔽RTOS可以管理的那些中断之后进入临界段,临界段代码要快,因为低优先级的中断被屏蔽后无法响应
中断屏蔽:msr basepri, ulNewBASEPRI;将configMAX_SYSCALL_INTERRUPT_PRIORITY的值写入basepri寄存器中
中断级关中断不可以嵌套,任务级运行嵌套
在任务级中,有变量记录调用开关中断函数的次数,只有开中断和关中断数相等时才会开启中断;但是任务级没有应用这个变量
开关中断
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
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
}
}
static portFORCE_INLINE void vPortClearBASEPRIFromISR( void )
{
__asm
{
/* Set BASEPRI to 0 so no interrupts are masked. This function is only
used to lower the mask in an interrupt, so memory barriers are not
used. */
msr basepri, #0
}
}
static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
/* Set BASEPRI to the max syscall priority to effect a critical
section. */
mrs ulReturn, basepri
msr basepri, ulNewBASEPRI
dsb
isb
}
return ulReturn;
}
操作basepri寄存器开启或屏蔽低于basepri的中断
systick和pendsv中断
systick用于记录时间,为OS提供心跳计时
pendsv用于执行任务切换,每出发一次systick中断均悬挂一个pendsv中断,当检测到无中断服务在运行时进行任务切换——缓期执行
因为,如果在systick中进行任务切换并保证定时就无法同时保证实时系统的运行和定时的准确性,会对中断产生延时,因为在任务切换中会屏蔽掉中断,无法及时响应外部中断,这是系统不允许的
滴答定时器如果拥有最高优先级,因为其会周期性触发,会经常抢占外部中断,会导致外部中断的相应变慢,这是不可忍受的,想象一下,外部中断是按键或者串口,按键卡顿或者串口接收数据接收到一半跳出;相发,如果设为最低,可能因为外部中断的触发导致定时会不准确,但这是可以忍受的,影响较小,可以先接收数据,之后在一定时间内处理即可
任务切换中断要求拥有最低优先级,因为如果非最低优先级,在系统进入某个中断时,pendsv中断触发,系统进行任务切换,然后执行下一个任务了,无法再回到被打断的中断服务中
所以需要两个中断保证系统时间的准确和中断响应实时性,而且为了外部中断的及时相应要将其均设为最低优先级
列表和列表项
列表可以看成是一个循环双指针的链表
列表:用于调度FreeRTOS中的任务,列表结构体:
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems; //列表项数量
ListItem_t * configLIST_VOLATILE pxIndex; //当前列表项,可以用来遍历列表
MiniListItem_t xListEnd; //迷你列表项,列表项裁剪掉一部分,有些简单的程序不需要完整的列表;还用于表示列表结束
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
} List_t;
列表项:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; //下一个列表项
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //上一个列表项
void * pvOwner; //指向这个列表项属于哪个任务控制块,属于哪个任务
void * configLIST_VOLATILE pvContainer; //指向这个列表项属于哪个列表,列表种类:信号量、事件等列表
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
};
typedef struct xLIST_ITEM ListItem_t;
列表主要用于跟踪调度任务,列表项指向任务控制块和所属列表,任务控制块中有两个列表项,分别用来描述任务的状态和事件的状态,当任务状态列表项处于就绪列表且优先级最高,在下一次任务切换时,执行其指向的任务。