首页 > 其他分享 >FreeRTOS学习——临界段代码保护及调度器挂起与恢复及其API函数内部实现详解

FreeRTOS学习——临界段代码保护及调度器挂起与恢复及其API函数内部实现详解

时间:2024-10-22 21:18:10浏览次数:8  
标签:CRITICAL 函数 FreeRTOS 中断 vTaskSuspendAll 临界 API 器挂 任务调度

FreeRTOS临界段代码保护及调度器挂起与恢复

FreeRTOS临界段代码保护及调度器挂起与恢复

临界保护区

什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段(在rtos中优先级高于系统管理的中断还是可以打断保护区内的代码

使用场景:时序产生时(IIC,SPI等),系统自身需求,用户需求。

临界区是直接屏蔽了中断,系统任务调度靠中断,ISR也靠中断

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

以下函数都是使用开关中断的方式来实现保护

函数描述
taskENTER_CRITICAL()任务级进入临界段
taskEXIT_CRITICAL()任务级退出临界段
taskENTER_CRITICAL_FROM_ISR()中断级进入临界段
taskEXIT_CRITICAL_FROM_ISR()中断级退出临界段

使用示例

任务级

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

中断级

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

注意事项:

  • 尽量保持临界段耗时短(因为该函数是用==开关中断的方式==,所以保护区内的代码耗时尽量短,若耗时久则会造成延时中断)
  • 成对使用
  • 支持嵌套

嵌套实现

void vPortEnterCritical( void )
{
    portDISABLE_INTERRUPTS();     //关中断函数
    uxCriticalNesting++;        //该变量在任务调度函数vTaskStartScheduler中初始化为0 通过该变量来实现保护区嵌套 同时达到成对使用的效果

    /* 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 );
    }
}

void vPortExitCritical( void )
{
    configASSERT( uxCriticalNesting );    //判断uxCriticalNesting是否为0 ,为0则报错  调试作用
    uxCriticalNesting--;

    if( uxCriticalNesting == 0 )			//通过该变量来实现保护区嵌套
    {
        portENABLE_INTERRUPTS();		//开中断函数
    }
}

任务调度器挂起与恢复

挂起任务调度器, 调用此函数不需要关闭中断(用于保护代码执行,使其不被打断)

函数描述
vTaskSuspendAll()挂起任务调度器
xTaskResumeAll()恢复任务调度器(有返回值,用于判断是否要任务切换
使用格式
vTaskSuspendAll() ;
{
        … …	/* 内容 对该内容进行保护*/
}
xTaskResumeAll();
特点
  • 与临界区不一样的是,挂起任务调度器,未关闭中断;
  • 它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应
  • 挂起调度器的方式,适用于临界区位于任务与任务之间;既不用去延时中断,又可以做到临界区的安全
函数内部实现
vTaskSuspendAll() ;

vTaskDelay(10); 延时函数内部使用了任务调度器,下图所示

屏幕截图 2024-10-22 125414

vTaskSuspendAll() ;再跳转到其 内部实现 ,可见只有一个变量在自增,

屏幕截图 2024-10-22 130505

前面我们提到过任务调度是由**PendSV中断来实现任务调度的,故此我们可以猜想是不是通过uxSchedulerSuspended变量的自增来实现PendSV**的悬起 来挂起任务调度器呢

为了验证这个猜想我们调到ystick中断服务函数

image-20241022131727212

我们可以发现这一步操作就是给PendSV悬起的操作(使Systick无法触发该中断

portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;

跳转到其宏定义可发先,该操作就是再给0xe000ed04寄存器的28位(1UL << 28UL)置1

#define portNVIC_INT_CTRL_REG     ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT    ( 1UL << 28UL )

该为正好是PendSV的悬起开关(下图Cortex-M3内核手册131)

image-20241022132109814

判断了其内部操作,我们再看看它的进入条件

if( xTaskIncrementTick() != pdFALSE )该函数是一个返回值为xSwitchRequired变量的函数

跳转到其函数内部可以发现 它对uxSchedulerSuspended变量的值进行了判断

image-20241022132724198

而 uxSchedulerSuspended 的初值在系统中早有定义为pdFALSE

PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;

但是在我们调用挂起函数vTaskSuspendAll() 后该变量会自增故不会执行if中的语句

我们再跳转到该if对应的else

image-20241022133006301

发现他并没有对返回值xSwitchRequired进行操作即返回原值pdFALSE

总结

vTaskSuspendAll() 该函数是通过使uxSchedulerSuspended自增来实现任务调度器(PendSV)的挂起

xTaskResumeAll();

同样进入函数内部

image-20241022194226010

与之前的与之前任务保护区的实现由异曲同工之妙

简述一下该函数内部实现的功能(初次接触还未能全部理解,稍作总结)

  • 等待就绪列表的任务恢复到就绪列表中再按优先级给任务排序(任务挂起后是把任务放到等待就绪列表中)
  • 更新阻塞时间(任务创建中有提到过)
  • 恢复滴答定时器在任务调度器被挂起时所缺失的节拍数(xTaskIncrementTick()函数实现)
  • 任务切换

如有不对 欢迎各位大神指正

标签:CRITICAL,函数,FreeRTOS,中断,vTaskSuspendAll,临界,API,器挂,任务调度
From: https://blog.csdn.net/m0_74219261/article/details/143167357

相关文章

  • 浏览器任务调度API
    window.scheduler是一个相对较新的浏览器API,旨在帮助开发者更高效地管理任务调度,特别是在处理复杂的Web应用程序时。这个API旨在提高应用的性能和响应性,通过允许开发者将任务分配到浏览器的空闲时间片段中执行。什么是 window.scheduler?window.scheduler是一个实验性......
  • api-ms-win-core-synch-l1-1-0.dll丢失怎么办?dll缺失解决方法
    当您遇到“api-ms-win-core-synch-l1-1-0.dll丢失”错误时,这通常意味着您的Windows系统中一个重要的动态链接库文件(DLL文件)缺失或损坏,这可能会影响到某些应用程序的正常运行。别担心,这个问题可以通过几个步骤来解决。下面是一份详细的指导文档,帮助您解决这一问题:api-ms-win-c......
  • API数据接口对电商运营的发展是怎样的
    API数据接口对电商运营的发展具有多方面的重要影响:提升用户体验:个性化推荐:通过API接口,电商平台可以收集用户的浏览历史、购买行为等数据,并以此为基础为用户定制个性化的产品推荐和促销活动。例如,用户在浏览某类商品后,平台能够根据其兴趣推送相关的商品或优惠信息,提高......
  • AbMole|Apilimod mesylate Apilimod甲磺酸盐(CAS号 870087-36-8;目录号M9418)
    Apilimodmesylate(STA5326mesylate,Apilimod甲磺酸盐)是Apilimod的甲磺酸盐形式,也是一种具有口服活性的IL-12/IL-23抑制剂,抑制IFN-γ/LPS刺激的人PBMC产生IL-12的IC50值为10nM。可用于难治性葡萄膜炎的相关研究。生物活性Apilimod甲磺酸盐是一种IL-12/IL-23抑制剂,抑制IFN-......
  • .NET 8 Web API从基础到提高全面示例
    .NET8WebAPI从基础到提高全面示例 概述:1.设置.NET8WebAPI项目概念使用.NETCLI创建新的WebAPI项目。这设置了一个基本的项目结构,包括启动和WeatherForecast控制器作为示例。Program.cs代码示例dotnetnewwebapi-nMyWebApi2.Program.cs—最低限度的API......
  • k8s 中的 Gateway API 的背景和简介【k8s 系列之四】
    〇、GatewayAPI的背景第一阶段:Service初始的Kubernetes内部服务向外暴露,使用的是自身的LoadBlancer和NodePort类型的Service。在集群规模逐渐扩大的时候,这种Service管理的方式满足不了我们的需求。比如NodePort需要大量的端口难以维护,多了一层NAT,请求量大会对......
  • 使用ollama本地部署qwen2并api调用
    目录一、下载ollama二、安装qwen大模型 三、Api调用四、尝试apifox调用一、下载ollamaOllama是一个开源的、本地运行的AI聊天模型,允许在自己的设备上运行LLM,无需依赖云服务。它支持多种LLM。目前Ollamalibrary已经支持Qwen2,可以直接使用。首先安装ollama,访问官......
  • 闲鱼API接口有哪些常用的API呢?
    闲鱼作为阿里巴巴旗下的二手交易平台,为开发者提供了丰富的API接口。这些接口促进了第三方开发者与闲鱼平台之间的数据交互,实现了功能的扩展与优化,为二手交易领域带来了更多的可能性。以下是闲鱼API接口中常用的几种类型:1.商品发布接口功能:用于在闲鱼平台上发布商品,包括商品......
  • FreeRTOS:任务
    目录一、简介二、任务栈三、任务控制块四、任务状态五、任务调度 五、任务间的通信六、相关API 一、简介    在裸机系统中,系统的主体就是main函数里面顺序执行的无限循环,这个无限循环里面,CPU按照顺序执行代码。在多任务系统中,我们根据功能的不同,把整......
  • C++文字识别接口介绍-翔云-通用文字识别API接口
    文字识别接口是一种提供给开发者使用的API服务,主要功能是通过光学字符识别(OCR,OpticalCharacterRecognition)技术将图片中的文字转换为可编辑的文本。这种技术广泛应用于各种场景,比如证件识别、票据识别、书籍扫描等。使用第三方平台如翔云文字识别接口通常需要以下几......