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, ulNewBASEPRI
        dsb
        isb
/* *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是成对出现的,临界区可以嵌套,仅在所有临界区全部退出时,才能恢复任务切换。

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在idea中搭建SpringBoot项目

如何在idea中快速搭建SpringBoot项目 目录 如何在idea中快速搭建SpringBoot项目前言一、环境准备:搭建前的精心布局 1.下载jdk (1)安装JDK:(2)运行安装程序:(3)设置安装…

Linux:expect spawn简介与用法

一、背景 大家在使用linux系统的很多时候,都用linux指令来实现一些操作,执行特定的job,有时一些场景中需要执行交互指令来完成任务,比如ssh登录这个命令大家一定很熟悉: ssh-keygen -t rsa # 以及 ssh-copy-id -i /hom…

服务器硬盘RAID速度分析

​ 在现代数据中心和企业环境中,服务器的存储性能至关重要,RAID(独立磁盘冗余阵列)技术通过将多块硬盘组合成一个逻辑单元,提供了数据冗余和性能优化,本文将详细探讨不同RAID级别对服务器硬盘速度的影响&am…

Android开发与网络请求

目标:快速开发一个安卓页面(用户登录&跳转) 抓包就是在后端逻辑与API之间截取信息。 1.安卓UI和后台逻辑 1.1 安卓UI 将activity_main.xml文件中的代码替换后,将会得到上面的UI界面 <?xml version="1.0" encoding="utf-8"?> <Linear…

【Linux】利用‘shell脚本’快速查看linux服务器的基本信息

一、脚本目的 为了方便&#xff0c;当拿到一台linux服务器的时候&#xff0c;我们应首先了解服务器的硬件、操作系统信息。俗话说“工欲善其事必先利其器” 只有熟悉了自己的武器&#xff0c;才能更好的发挥武器的威力。所以写了一个shell脚本&#xff0c;方便快速获取服务器C…

Solana 套利机器人原理

引言 加密货币的交易世界中&#xff0c;套利是利用市场价格差异进行无风险获利的一种策略。随着 DeFi&#xff08;去中心化金融&#xff09;的快速发展&#xff0c;套利机会屡见不鲜&#xff0c;尤其是在高速、高效能的区块链上&#xff0c;如 Solana。这些区块链通过提供低交易…

麦田物语学习笔记:制作[SceneName]Attribute特性

基本流程 因为在现有的项目中,像开始场景的切换或者Telepot组件都需要手动输入场景名,有时还可能键入出错,而该特性能用选择的方式去解决这一问题 1.代码实现 SceneNameDrawer.cs //参数绘制 using UnityEditor; using UnityEngine; #if UNITY_EDITOR [CustomPropertyDrawer(…

OCP使用中的常见问题与解决方法

OCP的常见问题 页面卡顿&#xff1a; 遇到页面卡顿的问题时&#xff0c;首先需要区分是全局性的卡顿&#xff0c;即所有页面都出现延迟或响应缓慢&#xff0c;还是仅限于特定的监控页面。 监控数据看不到: 需要明确是全部数据都无法查看&#xff0c;还是仅限于特定集群的数…

大模型LLM-微调 RAG

RAG小结 这篇文章是一篇关于大型语言模型&#xff08;LLMs&#xff09;增强技术的综述论文&#xff0c;特别聚焦于检索增强生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;这一领域。详细考察了RAG的发展、技术基础、关键技术、评估框架以及未来的研究方向。…

51c~缺陷检测~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/12386431 一、缺陷检测~使用深度学习1 这里研究工业ai, 在制造业中任何公司的主要目标都是为客户生产无缺陷产品。如果在产品开发过程中出现任何内部孔、凹坑、磨损或划痕&#xff08;由于多种原因&#xff0c;从生产设备…

25春秋杯wp

春秋杯 图片不显示的去我blog找&#x1f447; 25春秋杯 | DDLS BLOG 文章所有内容部分来自自己写的&#xff0c;部分来自各路非公开wp&#xff0c;部分来自公开wp(附上链接&#xff0c;在文章末尾) easy_flask {{().__class__.__mro__.__getitem__(1).__subclasses__()[13…

C# 事件(Event)详解

C# 事件详解 事件&#xff08;Event&#xff09;是 C# 中的一种特殊类型的委托&#xff0c;它是基于委托的基础上构建的&#xff0c;用来实现事件驱动编程。在 C# 中&#xff0c;事件常用于处理用户输入、系统通知、数据更新等场景&#xff0c;允许一个对象通知其他对象某些行…

三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D

挪威文化历史博物馆在其修复工作中融入现代3D扫描技术&#xff0c;让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识&#xff0c;该博物馆被誉为挪威博物馆研究领域的领先机构。馆…

Ubuntu 24.04 LTS 系统语言英文改中文

Ubuntu 24.04 LTS 修改软件源 Ubuntu 更改软件源 修改语言 无需输入命令&#xff0c;为Ubuntu 24.04系统添加中文智能拼音输入法 在 setting 的 system 中按下图操作 点击“Apply Changes”。需要管理员密码&#xff0c;安装完成后&#xff0c;退出登录&#xff0c;重新登…

Qt按钮美化教程

前言 Qt按钮美化主要有三种方式&#xff1a;QSS、属性和自绘 QSS 字体大小 font-size: 18px;文字颜色 color: white;背景颜色 background-color: rgb(10,88,163); 按钮边框 border: 2px solid rgb(114,188,51);文字对齐 text-align: left;左侧内边距 padding-left: 10…

51c自动驾驶~合集48

我自己的原文哦~ https://blog.51cto.com/whaosoft/13133866 #UDMC 考虑轨迹预测的统一决策控制框架 论文&#xff1a;https://arxiv.org/pdf/2501.02530 代码&#xff1a;​​https://github.com/henryhcliu/udmc_carla.git​​ 1. 摘要 当前的自动驾驶系统常常在确…

C# 动态创建Label和ComboBox控件并修改Text

背景&#xff1a;在做项目的时候可能需要根据一定数量创建某些控件并修改其属性&#xff0c;本文以控件label、ConboBox控件进行动态创建。 程序运行前后的的Form动态图 代码如下&#xff1a; using System; using System.Collections.Generic; using System.ComponentModel; …

【物联网】keil仿真环境设置 keilV5可以适用ARM7

文章目录 一、ARM指令模拟器环境搭建1. keil软件2. Legacy Support 二、Keil仿真环境设置1. 创建一个项目2. 编译器介绍(1)arm-none-eabi-gcc(2)arm-none-linux-gnueabi-gcc(3)arm-eabi-gcc(4)grmcc(5)aarch64-linux-gnu-gcc 3. 安装编译器(1)设置调试 一、ARM指令模拟器环境搭…

2024年度总结:从后端Java到全栈成长的蜕变

目录 前言1. 用数据与实践书写成长篇章2. 技术与生活的双重蜕变3. 技术的进阶与生活的绽放 前言 今年是我入行的第十年&#xff0c;也是记录在CSDN平台上的第五年。这五年来&#xff0c;我始终坚持记录成长的点滴&#xff0c;将个人事业与博客创作紧密相连。一路走来&#xff0…

U-Net - U型网络:用于图像分割的卷积神经网络

U-Net是一种专为图像分割任务设计的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;最初由Olaf Ronneberger等人于2015年提出。它被广泛应用于医学影像分析、遥感图像分割、自动驾驶和其他许多需要对图像进行像素级分类的任务中。U-Net具有强大的特征提取和恢复能力&…