TMS320C28x的中断

中断架构总览

 说明:

  • 总共有16路中断送入CPU。其中INT1~INT12的来源是ePIE,INT13和INT14是TIMER1和TIMER2.另外还有NMI和RTOSINT
  • TIMER0中断与TIMER1和TIMER2不同,它不是直接送给CPU,而是先送到ePIE。
  • 外部输入中断:从GPIO口经过Input X-BAR的选择后送给XINT1~XINT5,再送到ePIE
  • 其他外设的中断都是先经过ePIE。

中断传播路径

 说明:

  • 外设中断先到达外设中断标志寄存器中锁存:PIEIFRx.y。其中,x最大有12路,y最大有16路。外设中断最多可以有12 * 16 = 192个。
  • 每一个都有对应的中断使能寄存器:PIEIERx.y。最多也有192个。
  • 每一组中的16个外设中断源通过“或”操作,送到PIEACK。每一组只占PIEACK的一个位。
  • 当PIEACK=0时,中断可以传播全局中断标志寄存器IFR。当PIEACK=1时,传播路径断开。
  • 中断应答寄存器PIEACK具备“自锁”功能。也就是说,当有中断过来的时候,PIEACK会自动断开,需要在处理完中断响应函数后由软件清除PIEACK位(写1清零)。这样可以确保同一组中的多个中断同时发生时能依次处理,而不会遗漏。

多路复用中断

INTM

 最靠近CPU的是全局使能开关:INTM。是全局中断掩码(Interrupt global mask)。它是CPU核心寄存器ST1中的一个位。

 这个位是个“掩码位”,不是个“使能位”。因此,当INTM=1时,屏蔽所有中断;为0时才开启全局中断。复位后的默认值是1,即关闭全局中断。

 开启全局中断的方法是,将ST1.INTM位清零。使用宏定义语句:EINT

#define  EINT   __asm(" clrc INTM")

关闭中断是:DINT

#define  DINT   __asm(" setc INTM")

中断使能和中断标志

分别是IER和IFR。这两个寄存器也是属于CPU内核寄存器。

 IER

中断使能寄存器。共16位。

其中,INT1~INT12用于PIE。INT13是定时器1(TIMER1)中断;INT14是定时器2(TIMER2)中断。bit14是DLOGINT;bit15是RTOSINT。

 IFR

中断标志寄存器。每个位的所对应的中断与IER相同。

PIE

PIE是外设中断扩展模块(Peripheral Interrupt Expansion)

总共有12组外设中断。

PIE中断通道映射

不同的CPU型号,中断通道映射也不同。具体要查芯片手册。比如280025的PIE通道映射如下:

中断向量表

当发生中断时,CPU从中断向量表(Interrupt Vectors)中取出中断服务函数(ISR)的地址。

中断向量表保存在0x0D00 ~ 0x0EFF地址空间。

CPU中断向量表

 PIE中断向量表

中断优先级

数字越小,优先级越高。

  • 首先看CPU级别的中断,INT1比INT14的优先级要高。
  • 再看ePIE级别的中断。比如,在INT1组内,INT1.1比INT1.16的优先级要高。

 中断向量表的初始化

可以调用库函数:Interrupt_initVectorTable()。该函数先将默认的中断处理函数Interrupt_defaultHandler()的地址保存到中断向量表中。然后再更改INT_NMI中断和INT_ILLEGAL中断的响应函数。

//*****************************************************************************
//
// Interrupt_initVectorTable
//
//*****************************************************************************
void
Interrupt_initVectorTable(void)
{
    uint16_t i;

    EALLOW;

    //
    // We skip the first three locations because they are initialized by Boot
    // ROM with boot variables.
    //
    for(i = 3U; i < 224U; i++)
    {
        HWREG(PIEVECTTABLE_BASE + (2U * i)) =
            (uint32_t)Interrupt_defaultHandler;
    }

    //
    // NMI and ITRAP get their own handlers.
    //
    HWREG((uint32_t)PIEVECTTABLE_BASE + ((INT_NMI >> 16U) * 2U)) =
        (uint32_t)Interrupt_nmiHandler;
    HWREG((uint32_t)PIEVECTTABLE_BASE + ((INT_ILLEGAL >> 16U) * 2U)) =
        (uint32_t)Interrupt_illegalOperationHandler;

    EDIS;
}

更新中断服务函数

即:注册一个中断处理函数。

//*****************************************************************************
//
//! Registers a function to be called when an interrupt occurs.
//!
//! \param interruptNumber specifies the interrupt in question.
//! \param handler is a pointer to the function to be called.
//!
//! This function is used to specify the handler function to be called when the
//! given interrupt is asserted to the processor.  When the interrupt occurs,
//! if it is enabled (via Interrupt_enable()), the handler function will be
//! called in interrupt context.  Since the handler function can preempt other
//! code, care must be taken to protect memory or peripherals that are accessed
//! by the handler and other non-handler code.
//!
//! The available \e interruptNumber values are supplied in
//! <tt>inc/hw_ints.h</tt>.
//!
//! \note This function assumes that the PIE has been enabled. See
//! Interrupt_initModule().
//!
//! \return None.
//
//*****************************************************************************
static inline void
Interrupt_register(uint32_t interruptNumber, void (*handler)(void))
{
    uint32_t address;

    //
    // Calculate appropriate address for the interrupt number
    //
    address = (uint32_t)PIEVECTTABLE_BASE +
              (((interruptNumber & 0xFFFF0000U) >> 16U) * 2U);

    //
    // Copy ISR address into PIE table
    //
    EALLOW;
    HWREG(address) = (uint32_t)handler;
    EDIS;
}

PIE控制寄存器

包含2个字段:PIE使能位(ENPIE)和PIE向量。

 PIE使能

不使能时,从BOOTROM中读取中断向量;

使能后,从PieVectTable中取中断向量。

 

PIE向量

这个字段是只读的。当发生中断时,这里会保存取中断向量的位置。

 由于每个中断向量的地址都是32位的(2个字),因此,中断向量地址的最低位全都是0. 在PIE控制寄存器中就把这一位省掉了(用作PIE使能位)。实际理解的时候,应把这一位补上。或者这样理解:中断向量地址PIEVECT=PIE控制寄存器PIECTRL & 0xFFFE。

实例

当发生ADCD1中断时,PIECTRL = 0x0D4B。

 查看手册:

ADCD1中断为INT1.6

 中断INT1.6的向量地址为:0x0D4A

 中断向量地址0x0D4A + ENPIE = 0x0D4B。与实际情况刚好相符。

小结

中断处理流程

C280x多路复用的中断请求流程

步骤操作
步骤 1:PIE 组内的任何外设或外部中断生成中断。 如果在外设模块内启用了这些中断,则向 PIE 模块发送中断请求。
步骤 2:PIE 模块识别 PIE 组 x 内的中断 y (INTx.y) 已发出中断且已锁定适当的 PIE 中断标志位:PIEIFRx.y = 1。
步骤 3:要将中断请求从 PIE 发送到 CPU,以下两个条件必须同时为真:
3a:必须设置了正确的启用位 (PIEIERx.y = 1) 且
3b:该组 的 PIEACKx 位必须已清除。
步骤 4:如果 3a 和 3b 中的两个条件同时为真,则中断请求被发送到 CPU 且再次设置确认位 (PIEACKx = 1)。
PIEACKx 位将保持设置,直到您清除它以指示可以将来自该组的其它中断从 PIE 发送到 CPU。
步骤 5:设置 CPU 中断标志位 (CPU IFRx = 1) 以指示 CPU 级别的暂挂中断 x。
步骤 6 和步骤 7:如果已启用该 CPU 中断(CPU IER 位 x = 1 或 DBGIER 位 x = 1)且全局中断屏蔽已清除 (INTM = 0),则CPU 将为 INTx 提供服务
步骤 8:CPU 识别中断,然后执行自动背景保存、清除 IER 位、设置 INTM 并清除 EALLOW。 TMS320C28x DSP CPU 和指令集参考指南(文献编号 SPRU430)中描述了 CPU 准备服务中断时所执行的所有步骤。
步骤 9:CPU 然后将向 PIE 请求合适的变量。 对于多路复用中断,PIE 模块使用 PIEIERx 和 PIEIFRx 寄存器中的当前值来解码应使用哪个矢量地址。

可屏蔽中断的标准操作流程

流程图如下:

 具体流程:

  1. 中断请求发送到CPU
  2. IFR寄存器相关的标志位置位
  3. 相应的中断是否使能(IER使能位是否为1)?全局中断是否使能(INTM为0)?
  4. 中断允许后,送到CPU处理。此时,立即清除IFR标志位。
  5. 清空流水线。
  6. 程序计数器PC指针增加(指向中断返回后的第一条指令),然后临时保存到CPU内部。
  7. 取中断向量。PC 中填充了相应中断向量的地址,然后从该位置获取该向量。
  8. 栈指针(SP)加一。准备保存中断上下文。堆栈指针 (SP) 增加 1 以准备自动上下文保存(步骤 9)。
  9. 执行自动上下文保存。
  10. 清除相应的IER位。在步骤 9 中将 IER 寄存器保存到堆栈中后,CPU 会清除与正在处理的中断对应的 IER 位。 这可以防止重新进入同一中断。 如果您想嵌套发生的中断,请让 ISR 再次设置该 IER 位。
  11. 设置 INTM 和 DBGM。 清除 LOOP、EALLOW 和 IDLESTAT。 所有这些位都在状态寄存器 ST1 中。 通过将 INTM 设置为 1,CPU 可以防止可屏蔽中断干扰 ISR。 如果您希望嵌套中断,请让 ISR 清除 INTM 位。 通过将 DBGM 设置为 1,CPU 可以防止调试事件干扰 ISR 中的时间关键代码。 如果您不想阻止调试事件,请让 ISR 清除 DBGM。 CPU 清除 LOOP、EALLOW 和 IDLESTAT,以便 ISR 在新的上下文中运行。

  12. 用获取的向量加载 PC。 PC 加载了在步骤 7 中获取的中断向量。该向量将程序控制强制给 ISR。

  13. 执行中断服务程序。 这是 CPU 执行您准备处理中断的程序代码的地方。 
    虽然在步骤 10 中自动保存了一些寄存器值,但如果 ISR 使用其他寄存器,您可能需要在 ISR 的开头保存这些寄存器的内容。 然后必须在从 ISR 返回之前恢复这些值。 
    如果希望 ISR 通知外设正在处理中断,可以使用 IACK 指令发送中断确认信号。 IACK 指令接受一个 16 位常量作为操作数。 有关 IACK 指令的详细说明,请参见C28x 汇编语言指令。

  14. 程序继续。 如果中断没有得到 CPU 的批准,则忽略该中断,程序不中断地继续运行。 如果中断被批准,则执行其中断服务程序,程序从中断处继续(在返回地址处)

中断上下文保存的寄存器

许多寄存器值会自动保存到堆栈中。
这些寄存器成对保存; 每对都保存在一个 32 位操作中。 在每个 32 位保存操作结束时,SP 会增加 2。下表显示了寄存器对及其保存顺序。 CPU 期望所有 32 位保存都由内存包装器进行偶数字对齐。 如表中所示,SP 不受此对齐方式的影响。

参考:C28x 中断上下文的保存和恢复

C28x 中断上下文的保存和恢复_booksyhay的专栏-CSDN博客C28x 上下文保存和恢复介绍本文介绍了 C28x CPU 的自动上下文保存/恢复。这也适用于带有 FPU 和 VCU 扩展的设备。其他资源上下文保存和恢复的详细内容在 《C28x TMS320C28x CPU 和指令集参考指南》(TMS320C28x CPU and Instruction Set Reference Guide (Rev. F)-spru430f.pdf)文档中。堆栈基础首先是关于 C28x 堆栈指针的一些事实:C28x 堆栈指针 (SP) 始终指向堆栈中的.https://blog.csdn.net/booksyhay/article/details/120347937

中断嵌套

上文已提到,在保存中断上下文时,会自动禁止全局中断,并清除当前中断的IER位。因此,默认情况下,CPU是不支持中断嵌套的。

如果想要支持中断嵌套,必须在中断服务函数中重新使能IER标志位,并打开全局中断。

具体内容请见参考文档.

TI C28x DSP的中断嵌套_booksyhay的专栏-CSDN博客介绍一个常见的问题是 C28x 中断是否可以嵌套。本文解释了如何通过对中断服务例程 (ISR) 代码进行简单更改来实现中断嵌套。本文假设读者已经熟悉以下内容:C28x PIE 模块:控制寄存器、向量表、PIE 组C28x 中断控制寄存器:特别是 IER、IFR、INTM。有关这些主题的更多信息,请参阅以下内容:TMS320C28x CPU 和指令集参考指南 (spru430) 中记录了 CPU 级别的中断以及 CPU 如何响应中断该研讨会材料包含的C2.https://blog.csdn.net/booksyhay/article/details/120349053

参考文档

TMS320x280x DSP-系统控制和中断参考指南.pdf(中文版)

TMS320C28x CPU and Instruction Set Reference Guide (Rev. F)-spru430f.pdf

C28x Interrupt NestingC28x Interrupt Nestinghttps://software-dl.ti.com/C2000/docs/c28x_interrupt_nesting/html/index.html

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值