FreeRTOS学习笔记(四)Freertos的中断管理及临界保护

2024-09-08 12:36

本文主要是介绍FreeRTOS学习笔记(四)Freertos的中断管理及临界保护,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、Cortex-M 中断管理
    • 1.1 中断优先级分组
    • 1.2 相关寄存器
    • 1.3 相关宏定义
    • 1.4 FreeRTOS 开关中断
  • 二、临界段及其保护
    • 2.1 taskENTER_CRITICAL( ) 和 taskEXIT_CRITICAL( )
    • 2.2 taskENTER_CRITICAL_FROM_ISR( ) 和 taskEXIT_CRITICAL_FROM_ISR( )
    • 2.3 任务调度器的挂起及恢复


前言

  本章主要是讲述Freertos的中断管理及临界保护,具体的基础知识不再赘述,可以移步观看裸机开发部分。


一、Cortex-M 中断管理

1.1 中断优先级分组

  Cortex-M利用8位宽的寄存器来处理优先级,但stm32实际上只使用了高四位[7:4],即16级中断优先级。stm32的中断优先级可以分为抢占优先级(高优先级抢占低优先级)和子优先级(数值小先执行)。
中断分组
  由于FreeRTOS 的中断配置没有处理子优先级这种情况,所以只能配置为组 4,即 NVIC_PriorityGroup_4 。此时4 位优先级就都全是抢占优先级了,没有子优先级,那么就有 0~15 共 16 个优先级。

1.2 相关寄存器

  PendSV 和 SysTick 寄存器主要用于中断服务,并且在 FreeRTOS 中扮演了重要的角色,尤其是在任务切换和系统计时方面。这里首先介绍设置PendSV(PRI_14)和SysTick(PRI_15)优先级的两个寄存器。
在这里插入图片描述
  如上图所示,4 个相临的寄存器可以拼成一个32位的寄存器(SHPR1~ SHPR3),因而FreeRTOS 在设置 PendSV 和 SysTick 的中断优先级的时候都是直接操作的地址 0xE000_ED20 + offset。为了保证任务切换不会阻碍其他任务,在 FreeRTOS中 PendSV 和 SysTick 的中断优先级都是最低的!
  接着这里再讲述三个中断屏蔽寄存器。值得注意的是FreeRTOS 的开关中断就是操作 BASEPRI 寄存器来实现的,它可以关闭低于某个阈值的中断,高于这个阈值的中断就不会被关闭。

寄存器描述
PRIMASK禁止除 NMI 和 HardFalut 外的所有异常和中断,置1视为开启
FAULTMASK禁止除 NM 外的所有异常和中断,置1视为开启
BASEPRI最大9bit,只屏蔽优先级低于设置阈值的中断

1.3 相关宏定义

描述
configPRIO_BITS设置 MCU 使用几位优先级
configLIBRARY_LOWEST_INTERRUPT_PRIORITY设置最低优先级
configKERNEL_INTERRUPT_PRIORITY设置内核中断优先级
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY设置 FreeRTOS 系统可管理的最大优先级
configMAX_SYSCALL_INTERRUPT_PRIORITY低于此优先级的中断可以调用 FreeRTOS 的 API 函数,反之则禁止

1.4 FreeRTOS 开关中断

  FreeRTOS 开关中断函数为 portENABLE_INTERRUPTS ()和portDISABLE_INTERRUPTS(),这两个函数其实是宏定义,在 portmacro.h 中有定义,如下:

#define portDISABLE_INTERRUPTS( ) vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS( )  vPortSetBASEPRI(0)

  函数 vPortSetBASEPRI( )是向寄存器 BASEPRI 写入一个值,此值作为参数 ulBASEPRI 传递进来,portENABLE_INTERRUPTS( )是开中断,它传递了个 0 给 vPortSetBASEPRI( ),根据我们前面讲解 BASEPRI 寄存器可知,结果就是开中断。

二、临界段及其保护

  临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段,比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。
  FreeRTOS 在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。FreeRTOS 系统本身就有很多的临界段代码,这些代码都加了临界段代码保护,我们在写自己的用户程序的时候有些地方也需要添加临界段代码保护。

2.1 taskENTER_CRITICAL( ) 和 taskEXIT_CRITICAL( )

  这两个函数用于进入和退出临界区,在任务上下文中使用。它们通过禁用中断来保护临界区中的代码,确保该代码段在执行期间不会被打断。

  • taskENTER_CRITICAL( ):调用此函数后,所有中断都会被禁用,任务调度也会被禁止,这样可以确保当前任务在执行关键代码时不会被其他任务抢占或中断。
  • taskEXIT_CRITICAL( ):退出临界区时调用该函数,恢复中断和任务调度。必须确保在进入临界区后总是退出,以防止系统卡死或影响其他任务。
// 示例
void start_task(void *pvParameters)
{taskENTER_CRITICAL();  // 禁用中断,进入临界区...				   // 关键代码taskEXIT_CRITICAL();   // 重新启用中断,退出临界区
}

2.2 taskENTER_CRITICAL_FROM_ISR( ) 和 taskEXIT_CRITICAL_FROM_ISR( )

  这两个函数是在中断服务程序(ISR)中使用的版本,与任务上下文中的函数不同,这些函数可以确保临界区在中断中安全运行。除此之外,这个中断的优先级一定要低于前面提到的configMAX_SYSCALL_INTERRUPT_PRIORITY。

  • taskENTER_CRITICAL_FROM_ISR( ):与 taskENTER_CRITICAL() 类似,它也会禁用中断,但是该函数会返回一个变量,指示中断的先前状态,以便在退出临界区时恢复到正确的状态。
  • taskEXIT_CRITICAL_FROM_ISR( ):退出临界区时使用,需要传入先前的中断状态来恢复中断。
// 示例
UBaseType_t uxSavedInterruptStatus;	// FreeRTOS 中用于保存中断状态的变量
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();// 保存中断状态并进入临界区...											   // ISR 中的关键代码
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);// 退出临界区并恢复中断状态

2.3 任务调度器的挂起及恢复

  任务调度器的挂起和恢复常用于需要确保一段代码在不被其他任务打断的情况下执行,比如同时修改多个任务的优先级或共享资源。值得注意的是,调度器的挂起和恢复会影响整个系统,不管有多少任务,它都会停止任务的切换行为,而我们前面提到的任务挂起和恢复仅影响指定的任务。
  此外,与临界区不同的是任务调度器的挂起不会影响中断,它仅仅是防止任务之间相互抢占资源。适用于临界区位于任务和任务之间,可以做到既不采用延时,也可以保护临界段。

函数描述
vTaskSuspendAll( )暂停整个任务调度器的运行
xTaskResumeAll( )恢复任务调度器,重新允许任务切换

免责声明:本文参考了网上公开资料,仅用于学习交流,若有错误或侵权请联系笔者。

这篇关于FreeRTOS学习笔记(四)Freertos的中断管理及临界保护的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148123

相关文章

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Linux系统管理与进程任务管理方式

《Linux系统管理与进程任务管理方式》本文系统讲解Linux管理核心技能,涵盖引导流程、服务控制(Systemd与GRUB2)、进程管理(前台/后台运行、工具使用)、计划任务(at/cron)及常用... 目录引言一、linux系统引导过程与服务控制1.1 系统引导的五个关键阶段1.2 GRUB2的进化优

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Spring Security 前后端分离场景下的会话并发管理

《SpringSecurity前后端分离场景下的会话并发管理》本文介绍了在前后端分离架构下实现SpringSecurity会话并发管理的问题,传统Web开发中只需简单配置sessionManage... 目录背景分析传统 web 开发中的 sessionManagement 入口ConcurrentSess

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

Linux之UDP和TCP报头管理方式

《Linux之UDP和TCP报头管理方式》文章系统讲解了传输层协议UDP与TCP的核心区别:UDP无连接、不可靠,适合实时传输(如视频),通过端口号标识应用;TCP有连接、可靠,通过确认应答、序号、窗... 目录一、关于端口号1.1 端口号的理解1.2 端口号范围的划分1.3 认识知名端口号1.4 一个进程

SpringBoot结合Knife4j进行API分组授权管理配置详解

《SpringBoot结合Knife4j进行API分组授权管理配置详解》在现代的微服务架构中,API文档和授权管理是不可或缺的一部分,本文将介绍如何在SpringBoot应用中集成Knife4j,并进... 目录环境准备配置 Swagger配置 Swagger OpenAPI自定义 Swagger UI 底