【5】STM32·FreeRTOS·临界段保护与调度器挂起

embedded/2024/11/27 18:20:06/

目录

一、临界段代码保护简介

二、临界段代码保护函数介绍

2.1、调用示例

2.2、内部实现

三、任务调度器的挂起和恢复

3.1、调用示例

3.2、内部实现


一、临界段代码保护简介

什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段

适用场合如:

1、外设需严格按照时序初始化的外设:IIC、SPI等等
2、系统系统自身需求
3、用户用户需求

中断任务调度可以打断当前程序的运行

二、临界段代码保护函数介绍

FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段以后再开中断

函数描述

taskENTER_CRITICAL()

任务级进入临界段

taskEXIT_CRITICAL()

任务级退出临界段

taskENTER_CRITICAL_FROM_ISR()

中断级进入临界段

taskEXIT_CRITICAL_FROM_ISR()

中断级退出临界段

2.1、调用示例

任务级临界区调用格式示例:

taskENTER_CRITICAL();
{...    /* 临界区 */
}
taskEXIT_CRITICAL();

中断级临界区调用格式示例:

uint32_t save_status;
save_status = taskENTER_CRITICAL_FROM_ISR();
{...    /* 临界区 */
}
taskEXIT_CRITICAL_FROM_ISR(save_status);

特点

1、成对使用

2、支持嵌套

3、尽量保持临界段耗时短

2.2、内部实现

任务级进入临界段:taskENTER_CRITICAL()

#define taskENTER_CRITICAL()               portENTER_CRITICAL()
#define portENTER_CRITICAL()               vPortEnterCritical()void vPortEnterCritical( void )
{portDISABLE_INTERRUPTS();uxCriticalNesting++;/* This is not the interrupt safe version of the enter critical function so* assert() if it is being called from an interrupt context.  Only API* functions that end in "FromISR" can be used in an interrupt.  Only assert if* the critical nesting count is 1 to protect against recursive calls if the* assert function also uses a critical section. */if( uxCriticalNesting == 1 ){configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );}
}#define portDISABLE_INTERRUPTS()           vPortRaiseBASEPRI()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. */
/* *INDENT-OFF* */msr basepri, ulNewBASEPRIdsbisb
/* *INDENT-ON* */}}

任务级退出临界段:taskEXIT_CRITICAL()

#define taskEXIT_CRITICAL()                portEXIT_CRITICAL()
#define portEXIT_CRITICAL()                vPortExitCritical()void vPortExitCritical( void )
{configASSERT( uxCriticalNesting );uxCriticalNesting--;if( uxCriticalNesting == 0 ){portENABLE_INTERRUPTS();}
}#define portENABLE_INTERRUPTS()            vPortSetBASEPRI( 0 )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. */
/* *INDENT-OFF* */msr basepri, ulBASEPRI
/* *INDENT-ON* */}}

中断级进入临界段:taskENTER_CRITICAL_FROM_ISR()

#define taskENTER_CRITICAL_FROM_ISR()      portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR()  ulPortRaiseBASEPRI()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. */
/* *INDENT-OFF* */mrs ulReturn, baseprimsr basepri, ulNewBASEPRIdsbisb
/* *INDENT-ON* */}return ulReturn;}

中断级退出临界段:taskEXIT_CRITICAL_FROM_ISR()

#define taskEXIT_CRITICAL_FROM_ISR( x )           portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#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. */
/* *INDENT-OFF* */msr basepri, ulBASEPRI
/* *INDENT-ON* */}}

三、任务调度器的挂起和恢复

挂起任务调度器,调用此函数不需要关闭中断

函数描述

vTaskSuspendAll()

挂起任务调度器

xTaskResumeAll()

恢复任务调度器

3.1、调用示例

vTaskSuspendAll();
{···    /* 内容 */
}
xTaskResumeAll();

1、与临界区不一样的是,挂起任务调度器,未关闭中断

2、它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应

3、挂起调度器的方式,适用于临界区位于任务与任务之间

4、既不用去延时中断,又可以做到临界区的安全

3.2、内部实现

挂起任务调度器:vTaskSuspendAll()

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! -* https://goo.gl/wu4acr *//* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that* do not otherwise exhibit real time behaviour. */portSOFTWARE_BARRIER();/* The scheduler is suspended if uxSchedulerSuspended is non-zero.  An increment* is used to allow calls to vTaskSuspendAll() to nest. */++uxSchedulerSuspended;/* Enforces ordering for ports and optimised compilers that may otherwise place* the above increment elsewhere. */portMEMORY_BARRIER();
}

当变量 uxSchedulerSuspended 的值不为 0,将会导致 Systick 无法触发 PendSV 中断,即挂起任务调度器

恢复任务调度器:xTaskResumeAll()

BaseType_t xTaskResumeAll( void )
{TCB_t * pxTCB = NULL;BaseType_t xAlreadyYielded = pdFALSE;/* If uxSchedulerSuspended is zero then this function does not match a* previous call to vTaskSuspendAll(). */configASSERT( uxSchedulerSuspended );/* It is possible that an ISR caused a task to be removed from an event* list while the scheduler was suspended.  If this was the case then the* removed task will have been added to the xPendingReadyList.  Once the* scheduler has been resumed it is safe to move all the pending ready* tasks from this list into their appropriate ready list. */taskENTER_CRITICAL();{--uxSchedulerSuspended;if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ){/* Move any readied tasks from the pending list into the* appropriate ready list. */while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ){pxTCB = listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */listREMOVE_ITEM( &( pxTCB->xEventListItem ) );portMEMORY_BARRIER();listREMOVE_ITEM( &( pxTCB->xStateListItem ) );prvAddTaskToReadyList( pxTCB );/* If the moved task has a priority higher than or equal to* the current task then a yield must be performed. */if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}if( pxTCB != NULL ){/* A task was unblocked while the scheduler was suspended,* which may have prevented the next unblock time from being* re-calculated, in which case re-calculate it now.  Mainly* important for low power tickless implementations, where* this can prevent an unnecessary exit from low power* state. */prvResetNextTaskUnblockTime();}/* If any ticks occurred while the scheduler was suspended then* they should be processed now.  This ensures the tick count does* not  slip, and that any delayed tasks are resumed at the correct* time. */{TickType_t xPendedCounts = xPendedTicks; /* Non-volatile copy. */if( xPendedCounts > ( TickType_t ) 0U ){do{if( xTaskIncrementTick() != pdFALSE ){xYieldPending = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}--xPendedCounts;} while( xPendedCounts > ( TickType_t ) 0U );xPendedTicks = 0;}else{mtCOVERAGE_TEST_MARKER();}}if( xYieldPending != pdFALSE ){#if ( configUSE_PREEMPTION != 0 ){xAlreadyYielded = pdTRUE;}#endiftaskYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();return xAlreadyYielded;
}

当变量 uxSchedulerSuspended 的值等于 0,则允许调度

1、当任务数量大于 0 时,恢复调度器才有意义,如果没有一个已创建的任务就无意义

2、移除等待就绪列表中的列表项,恢复至就绪列表,直到 xPendingReadyList 列表为空

3、如果恢复的任务优先级比当前正在执行任务优先级更高,则将 xYieldPending 赋值为 pdTRUE,表示需要进行一次任务切换

4、在调度器被挂起的期间内,是否有丢失未处理的滴答数。xPendedTicks 是丢失的滴答数,有则调用 xTaskIncrementTick() 补齐丢失的滴答数

5、判断是否允许任务切换

6、返回任务是否已经切换,已经切换返回 pdTRUE,反之返回 pdFALSE


http://www.ppmy.cn/embedded/140968.html

相关文章

HDR视频技术之四:HDR 主要标准

HDR 是 UHD 技术中最重要维度之一,带来新的视觉呈现体验。 HDR 技术涉及到采集、加工、传输、呈现等视频流程上的多个环节,需要定义出互联互通的产业标准,以支持规模化应用和部署。本文整理当前 HDR 应用中的一些代表性的国际标准。 1 HDR 发…

【卷积神经网络;深度学习;滑坡检测;遥感|论文解读1】滑坡检测特征增强框架——AMU-Net

【卷积神经网络;深度学习;滑坡检测;遥感|论文解读1】滑坡检测特征增强框架——AMU-Net 【卷积神经网络;深度学习;滑坡检测;遥感|论文解读1】滑坡检测特征增强框架——AMU-Net 文章目录 【卷积神经网络&…

【Java网络编程】详解常见servlet的API使用

servlet常用类和接口 在Java Servlet中,主要涉及的几个类和接口包括: HttpServlet:这是一个抽象类,提供了处理HTTP请求的基本功能。你通常会继承这个类来创建自己的Servlet。 HttpServletRequest:这个接口是ServletR…

Doris 数据集成 LakeSoul

Doris 数据集成 LakeSoul 作为一种全新的开放式的数据管理架构,湖仓一体(Data Lakehouse)融合了数据仓库的高性能、实时性以及数据湖的低成本、灵活性等优势,帮助用户更加便捷地满足各种数据处理分析的需求,在企业的大数据体系中已经得到越来越多的应用。 在过去多个版本…

深度学习在雷达中的应用

1.CNN基本原理 20世纪60年代, Hubel和Wiese研究猫脑皮层发现用于局部敏感和方向选择的神经元具有独特的 网络结构,该结构可以降低反馈神经网络的复杂性,针对此研究提出了CNN。近些年,针对CNN具有避免图像的复杂前期预处理的优势&a…

HTML的自动定义倒计时,这个配色存一下

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>自定义倒计时</title><style>* {mar…

【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录

背景 Jetbrain IDE 支持生成 Test 类&#xff0c;其中选择JUnit5 和 JUnit&#xff0c;但是感觉这不是标准的单元测试&#xff0c;因为接口命名吧。 差异对比 两者生成的单测API名称同原API&#xff0c;没加test前缀的。使用差异主要表现在&#xff1a; setUp &#xff06; …

性能测试工具|如何有效度量前端性能

目标 从用户角度明确前端 Web、H5 性能测试需要重点关注的内容&#xff1b; 根据关注内容明确性能测试过程中的性能评判指标和建议的阈值范围&#xff1b; 整理性能测试过程中各性能评价指标的收集方法&#xff1b; 明确性能测试完毕后的测试结果展现形式。 质量模型 用户…