• STM32 M3M4 MCU与FreeRTOS 中断优先级配置


    STM32 M3/M4 MCU与FreeRTOS 中断优先级配置

    1.MCU NVIC硬件介绍

    强烈推荐用户将 Cortex-M3 内核的 STM32F103 和 Cortex-M4 内核的 STM32F407 以及STM32F429 的 NVIC 优先级分组设置为 4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。 这个也是官方强烈建议的。
    在这里插入图片描述

    (注意:一旦初始化好 NVIC 的优先级分组后,切不可以在应用中再次更改。)
    设置 NVIC 的优先级分组为 4 表示支持 0-15 级抢占优先级 (注意, 0-15 级是 16 个级别,包含 0 级), 不支持子优先级。
    在这里继续强调下这一点,在 NVIC 分组为 4 的情况下,抢占优先级可配置范围是 0-15,那么数值越小,抢占优先级的级别越高,即 0 代表最高优先级,15 代表最低优先级。

    2.FreeRTOS 配置选项中 NVIC 相关配置

    FreeRTOSConfig.h 配置文件中设置到 NVIC 中断的有如下几个选项:

    /*
     * Cortex-M内核使用8bit来配置优先级,但是STM32只使用了高4bit,数值越小,优先级越高。
     * 在往寄存器里面写数值配置的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
     * ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级
     */
    #ifdef __NVIC_PRIO_BITS  /* __NVIC_PRIO_BITS 已经在stm32f4xx.h里面定义为4 */
        #define configPRIO_BITS               __NVIC_PRIO_BITS
    #else
        #define configPRIO_BITS               4
    #endif
    /*============================================== SysTick中断优先级配置 ============================================*/
    /*
     * 在往寄存器里面写数值配置的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
     * ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级。经过这个公式之后得到的是
     * 下面的这个宏:configKERNEL_INTERRUPT_PRIORITY
     * SysTick的优先级我们一般配置为最低,即0xf 。这样可以提高系统的实时响应能力,即其他的外部中断可以及时的得到响应。
     */
    #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY            0xf
    #define configKERNEL_INTERRUPT_PRIORITY         ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
    
    /*===========================================可屏蔽的中断优先级配置====================================================*/
    /*
     * 用于配置STM32的特殊寄存器basepri寄存器的值,用于屏蔽中断,当大于basepri值的优先级的中断将被全部屏蔽。basepri只有4bit有效,
     * 默认只为0,即全部中断都没有被屏蔽。configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY配置为:5,意思就是中断优先级大于5的中断都被屏蔽。
     * 当把配置好的优先级写到寄存器的时候,是按照8bit来写的,所以真正写的时候需要经过转换,公式为:
     * ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff),其中的priority就是我们配置的真正的优先级。经过这个公式之后得到的是下面的这个宏:
     * configMAX_SYSCALL_INTERRUPT_PRIORITY
     *
     * 在FreeRTOS中,关中断是通过配置basepri寄存器来实现的,关掉的中断由配置的basepri的值决定,小于basepri值的
     * 中断FreeRTOS是关不掉的,这样做的好处是可以系统设计者可以人为的控制那些非常重要的中断不能被关闭,在紧要的关头必须被响应。
     * 而在UCOS中,关中断是通过控制PRIMASK来实现的,PRIMASK是一个单1的二进制位,写1则除能除了NMI和硬 fault的所有中断。当UCOS关闭
     * 中断之后,即使是你在系统中设计的非常紧急的中断来了都不能马上响应,这加大了中断延迟的时间,如果是性命攸关的场合,那后果估计挺严重。
     * 相比UCOS的关中断的设计,FreeRTOS的设计则显得人性化很多。
     *
     */
    #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5
    #define configMAX_SYSCALL_INTERRUPT_PRIORITY     ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    #define configPRIO_BITS 4
    此宏定义用于配置 STM32 的 8 位优先级设置寄存器实际使用的位数。 STM32F103,STM32F407
    和 STM32F429 都是使用的 4 位。 另外注意一点,这里使用了一个条件编译,用户可以选择将条件编
    译删掉,直接定义一个#define configPRIO_BITS 4 即可。使用条件编译的好处就是方便与系统统
    一。这个__NVIC_PRIO_BITS 在 STM32F103 标准库的头文件 stm32f10x.h 中以及 STM32F407/439
    的标准库的头文件 stm32f4xx.h 中分别有定义。如果用户在 FreeRTOSConfig.h 文件里面包含了这个
    标准库的头文件,那么就会执行条件编译选项:
    #define configPRIO_BITS __NVIC_PRIO_BITS
    在这里插入图片描述

    #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f
    此宏定义是用来配置 FreeRTOS 用到的 SysTick 中断和 PendSV 中断的优先级。在 NVIC 分组设置为
    4 的情况下,此宏定义的范围就是 0-15,即专门配置抢占优先级。这里配置为了 0x0f,即 SysTick
    和 PendSV 都是配置为了最低优先级,实际项目中也建议大家配置最低优先级即可。
     SVC 中断
    在 FreeRTOS 的移植文件 ports.c 中有用到 SVC 中断的 0 号系统服务,即 SVC 0。此中断在 FreeRTOS
    中仅执行一次, 用于启动第一个要执行的任务。 另外, 由于 FreeRTOS 没有配置 SVC 的中断优先级,
    默认没有配置的情况下, SVC 中断的优先级就是最高的 0。 如果用户在不清楚自己配置的 PendSV 和
    SysTick 中断是否跟实际情况一致时,可以进行硬件调试。 比如 MDK,我们可以在硬件调试的状态下,
    先点击全速运行,然后查看如下调试组件:
    在这里插入图片描述

    在这里插入图片描述

    #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
    此宏定义比较重要,定义了受 FreeRTOS 管理的最高优先级中断。简单的说就是允许用户在这个中断
    服务程序里面调用 FreeRTOS 的 API 的最高优先级。 设置 NVIC 的优先级分组为 4 的情况下。 配置
    configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 为 0x01 表示用户可以在抢占式优先级为 1

    到 15 的中断里面调用 FreeRTOS 的 API 函数,抢占式优先级为 0 的中断里面是不允许调用的。 不受
    FreeRTOS 管理的中断有什么深层的含义吗?

    不受 FreeRTOS 管理中断的深入讨论
    讲解不受 FreeRTOS 管理的中断之前要说一个小知识点----中断延迟。 中断延迟时间是衡量 RTOS 实
    时操作系统的一项重要指标,那什么又是中断延迟呢?从中断触发到执行中断服务程序的第一条指令这段
    时间就是中断延迟时间。
    FreeRTOS 内核源码中有多处开关全局中断的地方,这些开关全局中断会加大中断延迟时间。 比如在
    源码的某个地方关闭了全局中断,但是此时有外部中断触发,这个中断的服务程序就需要等到再次开启全
    局中断后才可以得到执行。开关中断之间的时间越长,中断延迟时间就越大,这样极其影响系统的实时性。
    如果这是一个紧急的中断事件,得不到及时执行的话,后果是可想而知的。
    针对这种情况,FreeRTOS 就专门做了一种新的开关中断实现机制。 关闭中断时仅关闭受 FreeRTOS
    管理的中断,不受 FreeRTOS 管理的中断不关闭,这些不受管理的中断都是高优先级的中断,用户可以在
    这些中断里面加入需要实时响应的程序。 FreeRTOS 能够实现这种功能的奥秘就在于 FreeRTOS 开关中断
    使用的是寄存器 basepri,而像 uCOS 这种使用的是 primask,详情请看下面整理的表格:
    在这里插入图片描述

    在这里插入图片描述

    #define configKERNEL_INTERRUPT_PRIORITY
    宏定义 configLIBRARY_LOWEST_INTERRUPT_PRIORITY的数值经过 4bit偏移后得到一个 8bit
    的优先级数值,即宏定义 configKERNEL_INTERRUPT_PRIORITY 的数值。这个 8bit 的数值才可以
    实际赋值给相应中断的优先级寄存器。
    也许初学者有疑问了,为什么前面 NVIC 配置的时候不是 8bit 的方式进行配置?这是因为 ST 的
    库函数 NVIC_Init()已经为我们做好了。 这里的宏定义数值是供 PendSV 和 SysTick 中断进行优先级
    配置的。 比如:我们这里配置宏定义 configLIBRARY_LOWEST_INTERRUPT_PRIORITY 是 0x0f,经
    过 4bit 偏移后就是 0xf0,即 SysTick 和 PendSV 的中断优先级就是 240。

    #define configMAX_SYSCALL_INTERRUPT_PRIORITY
    宏定义 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 的数值经过 4bit 偏移后得到一
    个 8bit 的优先级数值,即宏定义 configMAX_SYSCALL_INTERRUPT_PRIORITY 的数值。 这个数值
    是赋值给寄存器 basepri 使用的,8bit 的数值才可以实际赋值给相应中断的优先级寄存器。
    这里的宏定义数值赋给寄存器 basepri 后就可以实现全局的开关中断操作了。 比如:我们这里配
    置宏定义 configLIBRARY_LOWEST_INTERRUPT_PRIORITY 是 0x01,经过 4bit 偏移后就是 0x10,
    即 16。 调用了 FreeRTOS 的关中断后,所有优先级数值大于等于 16 的中断都会被关闭。优先级数值
    小于 16 的中断不会被关闭,对寄存器 basepri 寄存器赋值 0,那么被关闭的中断会被打开。

    上面的优先级数值,240和16,是十进制数,是真正8bit的数值,但是ST给我们了库函数,我们只配置4-7位,就可以了,其实就在配置这4-7位为0xf,表示优先级为15,实际十进制为240,配置这4-7位为 0x1,表示优先级为1,实际十进制为16.不要混淆了。
    NOTE:

    这里configMAX_SYSCALL_INTERRUPT_PRIORITY的优先级是个8bit的,之前的configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY是4bit,注意有没有LIBRARY。

    结合实例说明一下:假定设置中断优先级组为2,然后设置

    中断3(RTC_WKUP中断)的抢占优先级为2,响应优先级为1.

    中断6(外部中断0)的抢占优先级为3,响应优先级为0。

    中断7(外部中断1)的抢占优先级为2,响应优先级为0。

    那么这3个中断的优先级顺序为:中断7>中断3>中断6。
    上面例子中的中断3和中断7都可以打断中断6的中断。而中断7和中断3却不可以相互中断。

    级为1.

    中断6(外部中断0)的抢占优先级为3,响应优先级为0。

    中断7(外部中断1)的抢占优先级为2,响应优先级为0。

    那么这3个中断的优先级顺序为:中断7>中断3>中断6。
    上面例子中的中断3和中断7都可以打断中断6的中断。而中断7和中断3却不可以相互中断。

  • 相关阅读:
    操作系统学习笔记2 | 操作系统接口
    【NVMe2.0b 14】NVMe Admin Command Set
    散装问答-总结(更新中)
    【C++】类的继承
    C++ Reference: Standard C++ Library reference: C Library: ctime: difftime
    《计算机网络》考研:2024/3/9 2.1.7-数据交换方式;2.2-物理层传输介质;2.3-物理层设备
    MongoDB~分片数据存储Chunk;其迁移原理、影响,以及避免手段
    NLP机器翻译全景:从基本原理到技术实战全解析
    Knife4j使用教程(四) -- Controller类的配置注解
    「动态规划dp」
  • 原文地址:https://blog.csdn.net/xushx_bigbear/article/details/127815784