STM32 FreeRTOS中断管理

目录

FreeRTOS的中断管理

1、STM32中断优先级管理

2、FreeRTOS任务优先级管理

3、寄存器和内存映射寄存器

4、BASEPRI寄存器

5、FreeRTOS与STM32中断管理结合使用

 vPortRaiseBASEPRI

 vPortSetBASEPRI

6、FromISR后缀

7、在中断服务函数中调用FreeRTOS的API函数需注意

FreeRTOS的临界段代码

1、通过中断管理临界区

1)taskENTER_CRITICAL():进入临界区

2)taskEXIT_CRITICAL():退出临界区

3)taskENTER_CRITICAL_FROM_ISR():进入临界区(中断级)

4)taskEXIT_CRITICAL_FROM_ISR():退出临界区(中断级)

2、通过挂起和恢复任务调度器管理临界区

1)uxSchedulerSuspended

2)vTaskSuspendAll():挂起任务调度器

3)xTaskResumeAll():恢复任务调度器


FreeRTOS的中断管理

1、STM32中断优先级管理

在STM32中,中断优先级是通过中断优先级配置寄存器的高4位 [7:4] 来配置的。因此STM32支持最多16级中断优先级,其中数值越小表示优先级越高,即更紧急的中断。

2、FreeRTOS任务优先级管理

FreeRTOS任务调度的优先级相反,数值越大越优先。任务优先级的最大值由FreeRTOSConfig.h中的配置项configMAX_PRIORITIES决定,默认为5,如下。

#define configMAX_PRIORITIES        ( 5 )

 该配置项在当前环境下不能大于32,否则编译报错,如下。

#if ( configMAX_PRIORITIES > 32 )#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32.  It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif

因此,可以得出结论,在当前配置下,FreeRTOS的任务最多可以有32个优先级。

优先级范围[0, configMAX_PRIORITIES),即最大优先级为configMAX_PRIORITIES-1。

3、寄存器和内存映射寄存器

这里的寄存器不同于STM32的外设寄存器,后者是内存映射寄存器,实际上是在内存中划分特定的地址空间,用于访问和控制外设的功能。而此处的寄存器是Cortex-M3内核中“真正的”寄存器,基于SR锁存器构建。

4、BASEPRI寄存器

BASEPRI寄存器即Base Priority Mask Register(基本优先级屏蔽寄存器)。顾名思义,该寄存器是用来屏蔽中断响应的,位定义如下。

BASEPRI只有bit7-bit4起作用,当这四位不为0时,会屏蔽优先级数值上大于等于该值的中断响应。如:BASEPRI设置为0x50(只看bit7-bit4,也就是5),代表中断优先级在5~15内的均被屏蔽,0~4的中断优先级正常执行。

当bit7-bit4为0时无效,即不屏蔽任何中断。

5、FreeRTOS与STM32中断管理结合使用

FreeRTOS可以与STM32原生的中断机制结合使用。

FreeRTOS初始化时,PendSV和SysTick被设置最低中断优先级(数值最大,15),保证系统任务切换不会阻塞系统其他中断的响应。

FreeRTOS提供了一组宏定义用于禁用和启用中断,如下。

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

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

该函数先把configMAX_SYSCALL_INTERRUPT_PRIORITY赋值给ulNewBASEPRI,然后通过msr指令将ulNewBASEPRI的值赋给basepri寄存器。上述过程实际上是将configMAX_SYSCALL_INTERRUPT_PRIORITY配置项的值赋给了basepri寄存器。该配置项在FreeRTOSConfig.h中定义,默认值为191。因为是赋给basepri的,所以只有bit7-bit4有效,因而191等价于0xB0。 

#define configMAX_SYSCALL_INTERRUPT_PRIORITY    191

该配置项默认值为191,那么,默认情况下,FreeRTOS进入临界区时会屏蔽中断优先级数值上大于等于11的中断。我们可以说FreeRTOS管理的最大优先级为11。

在STM32F103ZET6单片机上使用FreeRTOS时,建议将上述配置项设置为较低的优先级值(逻辑上优先级较高),通常是5。需要注意的是,vPortRaiseBASEPRI函数中,会将configMAX_SYSCALL_INTERRUPT_PRIORITY直接赋值给BASEPRI寄存器,而不会进行移位操作,因此,当我们要让FreeRTOS可以管理的最大优先级设置为5时,要确保configMAX_SYSCALL_INTERRUPT_PRIORITY的bit7-bit4为5,通常赋值为0x50。

 vPortSetBASEPRI

vPortSetBASEPRI也是一个内联汇编函数,如下。

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

 该函数将ulBASEPRI赋值给BASEPRI寄存器。因此,portENABLE_INTERRUPTS()宏的逻辑是将0赋给BASERPI,不再屏蔽任何中断。

6、FromISR后缀

FreeRTOS提供了一组带FromISR后缀的函数,这类函数是对应无后缀API的另一个版本,专门用于在ISR(Interrupt Service Routine,中断服务函数或例程)中调用,相较于无后缀版本,增加了一些额外操作。

7、在中断服务函数中调用FreeRTOS的API函数需注意

1、中断服务函数的优先级需在FreeRTOS所管理的范围内,阈值由configMAX_SYSCALL_INTERRUPT_PRIORITY指定。

2、建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理。

3、在中断服务函数里边需调用FreeRTOS的API函数,必须使用带“FromISR”后缀的函数。

FreeRTOS的临界段代码

临界段代码,又称为临界区,指的是那些必须在不被打断的情况下完整运行的代码段。例如,某些外设的初始化可能要求严格的时序,因此在初始化过程中不允许被中断打断。

1、通过中断管理临界区

在FreeRTOS中,临界段代码需要被“临界区进入”和“临界区退出”函数保护起来。临界区的进入和退出可以通过中断来实现,相关函数有 4 个:

1)taskENTER_CRITICAL():进入临界区
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 );}
}

是通过portDISABLE_INTERRUPTS()宏禁用中断实现的。 

2)taskEXIT_CRITICAL():退出临界区
void vPortExitCritical( void )
{configASSERT( uxCriticalNesting );uxCriticalNesting--;if( uxCriticalNesting == 0 ){portENABLE_INTERRUPTS();}
}

是通过调用portENABLE_INTERRUPTS()宏启用中断实现的。

3)taskENTER_CRITICAL_FROM_ISR():进入临界区(中断级)
4)taskEXIT_CRITICAL_FROM_ISR():退出临界区(中断级)

进入和退出临界区是成对使用的。每进入一次临界区,全局变量uxCriticalNesting都会加一,每调用一次退出临界区,uxCriticalNesting减一,只有当 uxCriticalNesting 为 0 时才会调用函数 portENABLE_INTERRUPTS()使能中断。这确保了在存在多个临界区代码的情况下,不会因为某个临界区代码的退出而破坏其他临界区的保护。只有当所有的临界区代码都退出时,中断才会被重新使能。

上文提到,PendSV和SysTick两个中断的优先级在FreeRTOS初始化时都被置为最低优先级15,而这两个中断时FreeRTOS任务切换的核心。因此,在进入临界区时,FreeRTOS无法执行任务切换,保证了临界区操作的原子性。但要注意,优先级高于(数值上低于)配置项configMAX_SYSCALL_INTERRUPT_PRIORITY的中断未被FreeRTOS管理,仍然可以打断任务执行。

2、通过挂起和恢复任务调度器管理临界区

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

1)uxSchedulerSuspended

这是一个全局变量,声明及初始化如下。

PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t ) pdFALSE;

pdFALSE数值上为0,如下。 

#define pdFALSE                                  ( ( BaseType_t ) 0 )

在FreeRTOS中,任务调度器可以被多次挂起,uxSchedulerSuspended用于记录调度器被挂起的次数,只要它不为0,则无法进行任务切换。 

2)vTaskSuspendAll():挂起任务调度器

该函数的核心逻辑只有一行,如下。

++uxSchedulerSuspended;

调用该函数后,任务切换被禁止,当前任务的执行不会被其它任务打断,从而保护了临界区代码。

3)xTaskResumeAll():恢复任务调度器

该函数核心逻辑如下。

--uxSchedulerSuspended;if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){……}

首先将uxSchedulerSuspended减1,而后判断是否为pdFALSE,是则说明所有临界区已退出,可以恢复任务调度,执行相关操作。

vTaskSuspendAll和xTaskResumeAll是成对出现的,临界区可以嵌套,仅在所有临界区全部退出时,才能恢复任务切换。

与中断管理临界区不同的是,挂起任务调度器时未关闭中断;这种方式仅仅防止了任务之间的资源争夺,中断仍然可以直接响应;挂起调度器的方法适用于临界区位于任务与任务之间的情况;这样既不需要延迟中断,同时又能确保临界区的安全性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Spring] SpringCloud概述与环境工程搭建

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…

mobaxterm内置编辑器中文出现乱码如何解决:直接更换编辑器为本地编辑器

诸神缄默不语-个人CSDN博文目录 使用场景是我需要用mobaxterm通过SSH的方式登录服务器,进入服务器之后我就直接打开代码文件,mobaxterm会直接用内置的编辑器(MobaTextEditor)打开,但这会导致中文编程乱码。 我一开始是…

机器学习与人工智能的关系

机器学习与人工智能的关系 一、人工智能二、机器学习2.1 机器学习与人工智能的关系2.2 机器学习的本质 三、其他玩艺 曾几何时,人工智能还是个科幻名词,仿佛只属于未来世界。如今,它已经渗透到了我们生活的方方面面,成为顶流。我们…

一些常见的Java面试题及其答案

Java基础 1. Java中的基本数据类型有哪些? 答案:Java中的基本数据类型包括整数类型(byte、short、int、long)、浮点类型(float、double)、字符类型(char)和布尔类型(boo…

构建高性能网络服务:从 Socket 原理到 Netty 应用实践

1. 引言 在 Java 网络编程中,Socket 是实现网络通信的基础(可以查看我的上一篇博客)。它封装了 TCP/IP 协议栈,提供了底层通信的核心能力。而 Netty 是在 Socket 和 NIO 的基础上,进一步封装的高性能、异步事件驱动的…

Docker PG流复制搭建实操

目录标题 制作镜像1. 删除旧的容器2. 创建并配置容器3. 初始化数据库并启动 主库配置参数4. 配置主库5. 修改 postgresql.conf 配置 备库配置参数6. 创建并配置备库容器7. 初始化备库 流复制8. 检查主库复制状态9. 检查备库配置 优化建议问题1:FATAL: using recover…

Elasticsearch 批量导入数据(_bluk方法)

官方API&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html 建议先看API POST /<索引名>/_bulk 格式要求&#xff1a; POST _bulk { "index" : { "_index" : "test", "_id" : &q…

Active Prompting with Chain-of-Thought for Large Language Models

题目 大型语言模型的思维链主动提示 论文地址&#xff1a;https://arxiv.org/abs/2302.12246 项目地址&#xff1a;https://github.com/shizhediao/active-prompt 摘要 大型语言模型(LLM)规模的不断扩大为各种需要推理的复杂任务带来了涌现能力&#xff0c;例如算术和常识推理…

Windows图形界面(GUI)-QT-C/C++ - QT控件创建管理初始化

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 控件创建 包含对应控件类型头文件 实例化控件类对象 控件设置 设置父控件 设置窗口标题 设置控件大小 设置控件坐标 设置文本颜色和背景颜色 控件排版 垂直布局 QVBoxLayout …

04、Redis深入数据结构

一、简单动态字符串SDS 无论是Redis中的key还是value&#xff0c;其基础数据类型都是字符串。如&#xff0c;Hash型value的field与value的类型&#xff0c;List型&#xff0c;Set型&#xff0c;ZSet型value的元素的类型等都是字符串。redis没有使用传统C中的字符串而是自定义了…

traceroute原理探究

文章中有截图&#xff0c;看不清的话&#xff0c;可以把浏览器显示比例放大到200%后观看。 linux下traceroute的原理 本文通过抓包观察一下linux下traceroute的原理 环境&#xff1a;一台嵌入式linux设备&#xff0c;内网ip是192.168.186.195&#xff0c;其上有192.168.202.…

无源器件-电容

电容器件的参数 基本概念由中学大学物理或电路分析内容获得&#xff0c;此处不做过多分析。 电容的产量占全球电子元器件产品的40%以上。 单位&#xff1a;法拉 F&#xff1b;1F10^6uF&#xff1b;电路中常见的104电容就是10*10^4pF100nF0.1uF C为电容&#xff0c;Rp为绝缘电…

自动连接校园网wifi脚本实践(自动网页认证)

目录 起因执行步骤分析校园网登录逻辑如何判断当前是否处于未登录状态&#xff1f; 书写代码打包设置开机自动启动 起因 我们一般通过远程控制的方式访问实验室电脑&#xff0c;但是最近实验室老是断电&#xff0c;但重启后也不会自动连接校园网账户认证&#xff0c;远程工具&…

知识图谱抽取分析中,如何做好实体对齐?

在知识图谱抽取分析中&#xff0c;实体对齐是将不同知识图谱中的相同实体映射到同一表示空间的关键步骤。为了做好实体对齐&#xff0c;可以参考以下方法和策略&#xff1a; 基于表示学习的方法&#xff1a; 使用知识图谱嵌入技术&#xff0c;如TransE、GCN等&#xff0c;将实体…

FFmpeg硬件解码

使用FFmpeg进行硬件解码时&#xff0c;通常需要结合FFmpeg的API和硬件加速API&#xff08;如CUDA、VAAPI、DXVA2等&#xff09;。以下是一个简单的C代码示例&#xff0c;展示如何使用FFmpeg进行硬件解码。这个示例使用了CUDA作为硬件加速的后端。 1. 安装FFmpeg和CUDA 确保你…

Python----Python高级(函数基础,形参和实参,参数传递,全局变量和局部变量,匿名函数,递归函数,eval()函数,LEGB规则)

一、函数基础 1.1、函数的用法和底层分析 函数是可重用的程序代码块。 函数的作用&#xff0c;不仅可以实现代码的复用&#xff0c;更能实现代码的一致性。一致性指的是&#xff0c;只要修改函数的代码&#xff0c;则所有调用该函数的地方都能得到体现。 在编写函数时&#xf…

win32汇编环境,窗口程序中对按钮控件常用操作的示例

;运行效果 ;win32汇编环境&#xff0c;窗口程序中对按钮控件常用操作的示例 ;常用的操作&#xff0c;例如创建按钮控件&#xff0c;使其无效&#xff0c;改变文本&#xff0c;得到文本等。 ;将代码复制进radasm软件里&#xff0c;直接就可以编译运行。重点部分加备注。 ;>&g…

支付宝租赁小程序提升租赁行业效率与用户体验

内容概要 在当今数字化的世界里&#xff0c;支付宝租赁小程序的出现构建了一种新的租赁模式&#xff0c;使得用户在使用过程中体验更加流畅。想象一下&#xff0c;你在寻找租赁服务时&#xff0c;不再需要繁琐的流程和冗长的等待&#xff0c;只需通过手机轻松点击几下&#xf…

ffmpeg 编译遇到的坑

makeinfo: error parsing ./doc/t2h.pm: Undefined subroutine &Texinfo::Config::set_from_init_file called at ./doc/t2h.pm line 24. 编译选项添加&#xff1a; --disable-htmlpages

day06_Spark SQL

文章目录 day06_Spark SQL课程笔记一、今日课程内容二、DataFrame详解&#xff08;掌握&#xff09;5.清洗相关的API6.Spark SQL的Shuffle分区设置7.数据写出操作写出到文件写出到数据库 三、Spark SQL的综合案例&#xff08;掌握&#xff09;1、常见DSL代码整理2、电影分析案例…