FreeRTOS 遇坑(1)

FreeRTOS 遇坑(1)

转载标明出处!

1. 问题

1.1 原理方案

STM32F04 系列上增加了 FreeRTOS 实时系统,创建了二值信号量,功能为通过 USART2 发送数据给 MCUMCU 通过 DMA 接收数据,在 DMA 中断服务函数内用到了 FreeRTOS API 函数,然后在 USART1 上打印出系统出结果。

这里 USART1 做了重定向。

2. 报错结果

  1. 通过系统报错信息Error: ...\FreeRTOS\portable\RVDS\ARM_CM4F\port.c, 768,也就此路径的 768 行。

image-20210225175315917

3. 解决方案

    NVIC_InitTypeDef NVIC_InitStr;
	NVIC_InitStr.NVIC_IRQChannel                    = DMA1_Stream5_IRQn;
    NVIC_InitStr.NVIC_IRQChannelPreemptionPriority  = 2;
    NVIC_InitStr.NVIC_IRQChannelSubPriority         = 0;
    NVIC_InitStr.NVIC_IRQChannelCmd                 = ENABLE;
    NVIC_Init(&NVIC_InitStr);
  1. UART2DMA 中断优先级更改大于 FreeRTOSConfig.h 里所设定的宏定义 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
	NVIC_InitTypeDef NVIC_InitStr;
	NVIC_InitStr.NVIC_IRQChannel                    = DMA1_Stream5_IRQn;
    NVIC_InitStr.NVIC_IRQChannelPreemptionPriority  = 6;
    NVIC_InitStr.NVIC_IRQChannelSubPriority         = 0;
    NVIC_InitStr.NVIC_IRQChannelCmd                 = ENABLE;
    NVIC_Init(&NVIC_InitStr);

修改完之后,重新编译烧录,就会发现不会报错了。

4. 原理性问题

如上图报错结果,追踪到此函数出现问题,大概率能够判断是因为当前优先级大于系统最大优先级,导致报错。

configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );

能够追踪到 port.c 里,从注释可得知,这是一个 Interrupt priority 的问题:

image-20210225180238365

也就是说,我们对 FreeRTOSConfig.h 中的与 FreeRTOS 中断配置有关的选项,要有一定的了解:

/* 根据 MCU 架构设置 */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15

/* 此用于设置 FreeRTOS 系统可管理的最大优先级 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5

/* 内核中断优先级 */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

4.1 NVIC 中断控制器

FreeRTOSConfig.h 配置之前,我们要来讲一下,STM32Cortex-M 处理器的中断优先级,这个是非常重要的,只有清除了解之后,才能懂得为何我们要这么去配置。

这里以 STM32F407Cortex-M4 处理器为例,它拥有 4 位优先级,也就是 16 个优先级数。

招投标工作组织规范

16个优先级在使用 FreeRTOS 系统时,全部设置为抢占优先级,那怎么设置呢?调用下面的函数,就可以实现。那为什么要把 4 位优先级全部设置成抢占优先级呢?主要是我们使用了 FreeRTOS 系统,它的中断配置没有处理亚优先级的这种情况。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

此函数放在 main 函数内部第一行中,最先开始就要告诉 RTOS 系统。

那优先级级数等级是怎么设定的?

首先它拥有 16 个优先级数,有一个优先级级别为 2 和 优先级级别为 5 的进行比较,优先级别为 2 的优先级比较高。所说的优先级别 为 n 的我们称之为数字级别,那么得出结果我们称之为逻辑级别,这点大家一定要清楚。接下来说明的,都以逻辑级别来说明。

4.2 FreeRTOS 中断级别配置

/* 根据 MCU 架构设置 */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15

此宏定义是用来设置 MCU 架构的最小优先级,由于 STM32 只拥有 16 级的优先级,所以我们设置为 15,也就是 0 ~ 15 的优先级号。

/* 此用于设置 FreeRTOS 系统可管理的最大优先级数 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5

此宏定义是用来设置 FreeRTOS 系统可管理的最大优先级数,那么我们从上一个宏定义可知,我们拥有 16 级优先级。那么可以简单理解为,0 ~ 4FreeRTOS系统管理, 而 5 ~ 15 归我们用户去管理,这说明,权限肯定就有差别了。那有什么用的差别呢?

招投标工作组织规范 (3)

所说的 FreeRTOS API 函数是以 “FromISR” 结尾的 API 的函数。

/* 内核中断优先级 */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

那最后这个 FreeRTOSConfig.h 的配置,其实简单来理解,它就是对我们所设置好的内核架构及 FreeRTOS 可管理的最大优先级数进行移位,移位到我们用户可用的优先级位置上,也就是 Bit4 ~ Bit7 位。

总结:所以,我们每次使用到中断服务函数的时候,就要设置 NVIC 中断控制器,也就是中断号。那这个中断号要设置到用户管理还是系统管理的位置,就需要根据我们实际的情况去设置。如果你设置到系统管理位置,记住一件事情,绝对不允许中断当中使用 FreeRTOS API 提供的函数,也就是以 ”FromISR“ 结尾的。

猜你喜欢

转载自blog.csdn.net/qq_43125185/article/details/114100444