ARMv7-R 架构中断处理流程 (TDA4VM/TDA4VH R5F 核中断处理流程

    • Cortex-R5 IRQ/FIQ 中断处理方式
    • 两种中断服务形式的流程差别
      • 通过 VIC 服务 IRQ/FIQ(一般使用该模式)
      • 不使用 VIC 来服务一个 IRQ/FIQ(一般不使用该模式)

(芯片平台为: TDA4VM / TDA4VH 的 MCU 域的 R5F 核)

Cortex-R5 IRQ/FIQ 中断处理方式

阅读《Cortex-R5 trm》, 得知 r5 服务一个中断的形式有下列两种方式:

  1. 通过 VIC 来服务一个中断,当 IRQ 发生时,r5 内核硬件自动从 VIC 中获取 IRQ 的中断服务程序的地址;
  2. 不使用 VIC,当 IRQ 发生后, 通过读写 VIM 寄存器的形式来服务一个中断,可以类比 Cortex-A7 架构中的中断处理形式,不过 Cortex-A7 使用的是 GICv2 的寄存器。

方式的选择由 SCTLR 寄存器的 bit24:VE 位控制,如下:


TRM 上对该位的解释如下:

两种中断服务形式的流程差别

通过 VIC 服务 IRQ/FIQ(一般使用该模式)

如果我们使用的 ARMv7-R 架构芯片内部集成了 VIC,那么,我们可以使用 VIC 来服务一个中断,也就是说,我们需要在启动汇编代码中,置位 SCTLR 寄存器的 VE 位。
TDA4VM/TDA4VH mcu 域 R5F 芯片内部就集成了 VIC。

当 irq 触发后,r5 内核不会将 pc 指针跳转到异常向量表的 0x00000018 或 0xFFFF0018 处,而是自动与 VIC 完成硬件握手,并直接从 VIC 中获取我们为每一个中断设置的中断服务地址。
VIC 为每一个中断源都提供了设置各自中断服务函数地址的寄存器,以 TDA4VM 举例, 各中断的向量地址寄存器 VIM_VEC_INT如下:

使用 VIC 服务中断的处理流程:

  1. 软件维护一个中断服务函数及其参数的结构体数组,每一个数组元素(结构体)对应一个中断向量。
  2. VIM 寄存器初始化,清除各中断状态,初始化中断优先级,中断映射类型(IRQ/FIQ),中断触发类型,失能所有中断。
  3. 维护一个总的 irq_handler,以及维护一个中断服务函数及其参数的结构体数组。
  4. 注册某一个中断的中断服务函数及其参数,到结构体数组中,并将总的 irq_handler 写入 VIM 的指定中断的向量地址寄存器 VIM_VEC_INT中,并使能指定中断。
  5. 中断触发后,r5 内核与 VIC 完成硬件握手,从之前我们设置的向量地址寄存器中获取中断服务函数地址,即 irq_handler。
  6. 读取活跃中断寄存器VIM_ACTIRQ,获取触发中断的向量号。
  7. 根据向量号,从软件维护的结构体数组中,调用自定义的中断服务函数。
  8. 根据中断触发类型(电平/脉冲),清除中断标志位。
  9. VIM_IRQVEC 寄存器中写任意值,表示中断处理结束。

不使用 VIC 来服务一个 IRQ/FIQ(一般不使用该模式)

(不置位 SCTLR 寄存器的 VE 位)
之前提到,该种方式与 Cortex-A7 的中断处理流程类似,那么在这,带领大家回忆一下 Cortex-A7 的中断处理流程:

  1. 软件维护一个中断服务函数及其参数的结构体数组,每一个数组元素(结构体)对应一个中断向量。
  2. GICv2 初始化,初始化 cpu interface,比如设置合适抢占优先级(GICC_BPR);初始化 distributor,清除各中断状态,设置初始中断优先级,各中断分组,初始中断类型,中断绑核,失能所有中断。
  3. 注册某一个中断的中断服务函数及其参数到结构体数组中,并使能指定中断。
  4. 当中断触发后,pc 指针跳转到中断向量表中偏移量为 0x18 的地址处,再跳转到统一的 irq_handler。
  5. 在这个统一的 irq_handler 中,代码通过读取 cpu interface 的 GICC_IAR 寄存器来应答中断,并获取触发 IRQ 的中断向量号。
  6. 从数组中调用对应中断的中断服务程序,服务中断。
  7. 从指定的中断服务函数中退出,irq_handler 的代码写 GICC_EOIR 寄存器来通知 GIC 中断处理结束,然后退出。
  8. 中断处理结束。

以上是总述形式的 Cortex-A7 的中断处理,有一些细节没有提到,比如中断抢占,RTOS 下中断中的上下文切换等。

Cortex-R5 的中断处理流程,总述如下:

  1. 软件维护一个中断服务函数及其参数的结构体数组,每一个数组元素(结构体)对应一个中断向量。
  2. VIM 寄存器初始化,清除各中断状态,初始化中断优先级,中断映射类型(IRQ/FIQ),中断触发内存,失能所有中断。
  3. 维护一个总的 irq_handler,以及维护一个中断服务函数及其参数的结构体数组。
  4. 注册某一个中断的中断服务函数及其参数,到结构体数组中,并将总的 irq_handler 写入 VIM 的向量地址寄存器中(即使此模式下我们不通过该寄存器来获取中断向量地址),并使能指定中断。
  5. 当中断触发后,pc 指针跳转到中断向量表中偏移量为 0x18 的地址处,再跳转到统一的 irq_handler。
  6. 在 irq_handler 中,读取 VIM_IRQVEC 寄存器,读取该寄存器后会设置活跃中断寄存器。
  7. 读取活跃中断寄存器VIM_ACTIRQ,获取触发中断的向量号。
  8. 使用获取的向量号,从软件维护的结构体数组中,调用自定义的中断服务函数。
  9. 根据中断触发类型,清除中断标志位:
  10. VIM_IRQVEC 寄存器中写任意值,表示中断处理结束。