一、临界段代码保护
1、什么是临界段代码
临界段代码指的是那些不能被打断的代码,例如 IIC,SPI 等对时序有着严格的控制的代码。
2、临界段保护的函数
任务级进入临界区: taskENTER_CRITICAL();
任务级退出临界区: taskEXIT_CRITICAL();
中断级进入临界区: taskENTER_CRITICAL_FROM_ISR();
中断级退出临界区: taskEXIT_CRITICAL_FROM_ISR( x );
二者的区别就仅仅是中断级的只能用在中断中。(24.4.29更新)
#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 )
其实仔细分析其内部实现,发现调用的还是上一片文章讲到的中断开启与关闭函数。不同的是多了一个变量 uxCriticalNesting 可以支持嵌套,即每次调用一次进入临界区函数,uxCriticalNesting 值加1,每次退出一次临界区,uxCriticalNesting 值减1。当 uxCriticalNesting 值为 0时,才会调用开启中断函数来退出临界区。
3、应用模板
taskENTER_CRITICAL(); //进入临界区
{
…… …… /*临界区代码部分*/
}
taskEXIT_CRITICAL(); //退出临界区
uint32_t save_status;
save_status=taskENTER_CRITICAL_FROM_ISR();
{
…… …… /*临界区代码部分*/
}
taskEXIT_CRITICAL_FROM_ISR(save_status);
二、 任务调度器的挂起与恢复
1、任务调度器挂起
挂起任务调度器之后,任务不能被调度但是中断可以正常运行。一般适用于临界区位于任务与任务之间。既不用延时中断又可以做到临界区的相对安全。
2、任务调度器的挂起与恢复函数
任务调度器挂起函数:vTaskSuspendAll();
任务调度器恢复函数:xTaskResumeAll();返回值为 BaseType_t 类型,如果返回 pdTRUE 则代表恢复的任务优先级比较高,需要进行任务切换,返回 pdFALSE 表示不需要进行任务切换。
任务的调度本质还是pendsv的中断来执行的。而pendsv中的中断在 if 判断语句中执行:
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
如果条件不成立就不会执行中断。所以任务调度器挂起函数:vTaskSuspendAll();通过修改 uxSchedulerSuspended 的值来挂起任务调度器。
void vTaskSuspendAll( void )
{
/* A critical section is not required as the variable is of type
BaseType_t. Please read Richard Barry's reply in the following link to a
post in the FreeRTOS support forum before reporting this as a bug! -
http://goo.gl/wu4acr */
++uxSchedulerSuspended;
}
同理, 任务调度器恢复函数:xTaskResumeAll();通过 --uxSchedulerSuspended 来恢复任务调度器。
3、应用模版
{
...//代码
vTaskSuspendAll();
{
...//被保护的代码
}
xAlreadyYielded = xTaskResumeAll();
/* Force a reschedule if xTaskResumeAll has not already done so, we may have put ourselves to sleep. */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API(); //任务切换函数
}
else
{
mtCOVERAGE_TEST_MARKER();
}
...//代码
}
4、实例 vTaskDelay() 的实现
void vTaskDelay( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded = pdFALSE;
/* A delay time of zero just forces a reschedule. */
if( xTicksToDelay > ( TickType_t ) 0U )
{
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
traceTASK_DELAY();
/* A task that is removed from the event list while the
scheduler is suspended will not get placed in the ready
list or removed from the blocked list until the scheduler
is resumed.This task cannot be in an event list as it is the currently
executing task. */
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
xAlreadyYielded = xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Force a reschedule if xTaskResumeAll has not already done so, we may
have put ourselves to sleep. */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
临界段代码保护与任务调度器的挂起和恢复&spm=1001.2101.3001.5002&articleId=136565287&d=1&t=3&u=c4a338893ad142658e953b11040c2a26)
792

被折叠的 条评论
为什么被折叠?



