1.1 NVIC 基础知识

NVIC 的全称是 Nested vectored interrupt controller,即嵌套向量中断控制器。

对于 M3 和 M4 内核的 MCU,每个中断的优先级都是用寄存器中的 8 位来设置的。8 位的话就可以 设置 2^8 = 256 级中断,实际中用不了这么多,所以芯片厂商根据自己生产的芯片做出了调整。比如 ST 的 STM32F1xx 和 F4xx 只使用了这个 8 位中的高四位[7:4],低四位取零,这样 2^4=16,只能表示 16 级中断嵌套。

对于这个 NVIC,有个重要的知识点就是优先级分组,抢占优先级子优先级

STM32F1xx 和 F4xx 都是只使用了这个 8 位寄存器的高四位[7:4]。

数字越小,优先级越大

Reset、NMI、Hard Fault 优先级为负数,高于普通中断优先级,且优先级不可配置。

对于初学者还有一个比较纠结的问题就是系统中断(比如:PendSV,SVC,SysTick)是不是一
定比外部中断(比如 SPI,USART)要高,答案:不是的,它们是在同一个 NVIC 下面设置的。

1.2 使用 FreeRTOS 时如何配置外设 NVIC

FreeRTOS中NVIC 优先级分组设置为 4,这 样中断优先级的管理将非常方便。

设置 NVIC 的优先级分组为 4

抢占优先级可配置范围是 0-15,那么数值越小, 抢占优先级的级别越高,即 0 代表最高优先级,15 代表最低优先级。

1.3 FreeRTOS 配置选项中 NVIC 相关配置

1.4 不受 FreeRTOS 管理中的的深入讨论

primask这是个只有 1 个 bit 的寄存器。 在它被置 1 后,就关掉所有可屏蔽的异常,只剩下
NMI 和硬 fault 可以响应。它的缺省值是 0,表示没有关中断。
faultmask这是个只有 1 个 bit 的寄存器。当它置 1 时,只有 NMI 才能响应,所有其它的异
常,甚至是硬 fault,也通通闭嘴。它的缺省值也是 0,表示没有关异常。
basepri这个寄存器最多有 9 位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。
当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优
先级越低)。但若被设成 0,则不关闭任何中断,
0 也是缺省值。

2.1任务优先级说明

freertos中,数字越大,优先级越高。与stm32的nvic相反。

  • FreeRTOS 中任务的最高优先级是configMAX_PRIORITIES
  • 用户实际可以使用的优先级范围是 0 到 configMAX_PRIORITIES – 1
  • 用户配置任务的优先级数值越小,那么此任务的优先级越低,空闲任务的优先级是 0。
  • 建议用户配置宏定义 configMAX_PRIORITIES 的最大值不要超过 32,
    • 通用方式,没有优化—配置宏定义 configUSE_PORT_OPTIMISED_TASK_SELECTION 为 0
      • 所有平台的移植文件都可以配置为 0,因为这是通用方式。
      • 纯 C 编写,比专用方式效率低。
      • 可用的优先级数量不限制。
    • 专用方式,进行优化—配置宏定义 configUSE_PORT_OPTIMISED_TASK_SELECTION 为为 1
      • 部分平台支持。
      • 这些平台架构有专用的汇编指令可以加速算法执行速度。
      • 比通用方式高效。
      • 有最大优先级数限制,通常限制为 32 个。
  • 只要芯片资源允许,可以配置任意多个同优先级任务。
  • FreeRTOS 中处于运行状态的任务永远是当前能够运行的最高优先级任务

什么是时间片:时间片就是同一个优先级下可以有多个任务,每个任务轮流地享有相同的 CPU 时间, 享有 CPU 的时间我们叫时间片。

2.2任务优先级分配

  • IRQ 任务:IRQ 任务是指通过中断服务程序进行触发的任务,此类任务应该设置为所有任务里面优先 级最高的。
  • 高优先级后台任务:比如按键检测,触摸检测,USB 消息处理,串口消息处理等,都可以归为这一类 任务。
  • 低优先级的时间片调度任务:比如 emWin 的界面显示,LED 数码管的显示等不需要实时执行的都可 以归为这一类任务。实际应用中用户不必拘泥于将这些任务都设置为优先级 1 的同优先级任务,可以 设置多个优先级,只需注意这类任务不需要高实时性。
  • 空闲任务:空闲任务是系统任务。

对于 STM32F103 来说,中断优先级的数值越小,优先级越高。

而 FreeRTOS 的任务优先级是,任务优先级数值越小,任务优先级越低。

2.3任务优先级修改

FreeRTOS 的任务优先级修改:vTaskPrioritySet (TaskHandle_t xTask, UBaseType_t uxNewPriority)

  • 第 1 个参数是任务句柄,用于区分不同的任务。
  • 第 2 个参数是给任务配置的新优先级

2.4任务优先级获取

FreeRTOS 的任务优先级获取:vTaskPriorityGet ( TaskHandle_t xTask )

  • 第 1 个参数是任务句柄,用于区分不同的任务。

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01

为 0x01 表示用户可以在抢 占式优先级为 1 到 15 的中断里面调用 FreeRTOS 的 API 函数,抢占式优先级为 0 的中断里面是 不允许调用的。

3,任务调度—抢占式,时间片和合作式

3.1

FreeRTOS 操作系统支持的任务调度方式:抢占式,时间片和合作式

说合作式调度主要用在资源有限的设备上面,现在已经很少使用了。

  • 抢占式调度:每个任务都有不同的优先级,任务会一直运行直到被高优先级任务抢占或者遇到阻塞式的 API 函数, 比如 vTaskDelay。
  • 时间片调度:每个任务都有相同的优先级,任务会运行固定的时间片个数或者遇到阻塞式的 API 函数,比如 vTaskDelay,才会执行同优先级任务之间的任务切换。

3.2什么是调度器

调度器:调度器就是使用相关的调度算法来决定当前需要执行的任务。

  • 调度器可以区分就绪态任务挂起任务(由于延迟,信号量等待,邮箱等待,事件组等待等原因而使 得任务被挂起)。
  • 调度器可以选择就绪态中的一个任务,然后激活它(通过执行这个任务)。当前正在执行的任务是运 行态的任务。
  • 不同调度器之间最大的区别就是如何分配就绪态任务间的完成时间

嵌入式实时操作系统的核心就是调度器和任务切换,调度器的核心就是调度算法。

3.3抢占式调度器

抢占式调度要掌握的最关键一点是:每个任务都被分配了不同的优先级,抢占式调度 器会获得就绪列表中优先级最高的任务,并运行这个任务。

如果在 FreeRTOSConfig.h 中禁止使用时间片调度,那么每个任务必须配 置不同的优先级。

例子:

  • 创建 3 个任务 Task1,Task2 和 Task3。
  • Task1 的优先级为 1,Task2 的优先级为 2,Task3 的优先级为 3。FreeRTOS 操作系统是设置的数值 越小任务优先级越低,故 Task3 的优先级最高,Task1 的优先级最低。

3.4 时间片调度器

  • 最常用的的时间片调度算法就是 Round-robin 调度算法,
  • 时间片调度适合用于不要求任务实时响应的情况。
  • 只有同优先级任务才会使用时间片调度
  • 使能#define configUSE_TIME_SLICING 1

说明:

  • 创建 4 个同优先级任务 Task1,Task2,Task3 和 Task4。
  • 每个任务分配的时间片大小是 5 个系统时钟节拍。
  • 任务 Task3 在运行期间调用了阻塞式 API 函数,调用函数时,虽然 5 个系统时钟节拍的时间片大小 还没有用完,此时依然会通过时间片调度切换到下一个任务 Task4。(注意,没有用完的时间片不会 再使用,下次任务 Task3 得到执行还是按照 5 个系统时钟节拍运行)
  • 任务 Task4 运行够 5 个系统时钟节拍后,通过时间片调度切换到任务 Task1