汽车电子expert成长之路

本博客发布的个人原创精品----嵌入式系统技术文章,欢迎大家参考学习,并转发分享!

外设使用Tips之MPC56xx_57xx系列MCU内核异常(IVORx)与IRQ中断处理详解

0
阅读(13524)

外设使用Tips之Qorivva MPC56xx_57xx系列MCU内核异常(IVORx)与IRQ中断处理详解

内容提要

 

引言

1. Qorivva MPC56xx/57xx系列MCU使用的PowerPC e200系列CPU内核系统异常简介

1.1. Power e200z3/z4/z6/z7内核的系统异常

1.2. Power e200z0内核的系统异常

1.3 PowerPC e200内核异常IVOR4介绍

2. INTC模块功能介绍

2.1  INTC控制寄存器(INTC_BCR/INTC_MCR)--配置IRQ中断为硬件向量还是软件向量模式

在MPC56xx系列MCU中则是INTC_MCR寄存器,其定义如下:

2.2 INTC当前优先级寄存器(INTC_CPR0)--配置当其INTC模块处理的优先级

2.3 INTC中断确认寄存器(INTC_IACKR0)

2.4 INTC中断结束寄存器(INTC_EOIR0)

2.5 INTC软件设置中断寄存器(INTC_SSCIRn)

2.6 INTC中断优先级设置寄存器(INTC_PSRn)

2.7 INTC监测模式寄存器(INTC_MMCR0)

2.8 INTC中断监测选择寄存器(INTC_HIPRInC0)

2.9 INTC延迟寄存器(INTC_LATnCR0)

2.10 INTC定时器寄存器(INTC_TIMERnCR0)

3. INTC模块管理的两类IRQ中断请求:

3.1 软件设置中断

3.2 外设硬件中断

4. INTC模块中断初始化流程

5. 软件向量模式(Software Vector Mode)

5.1 软件向量模式下CPU内核系统异常和INTC模块初始化详解

6. 硬件向量模式(Hardware Vector Mode)

总结


引言


很多读者和客户跟我反馈说,我们的Qorivva MPC56xx/57xx系列MCU的相关资料书籍特别少,尤其是内核和指令集以及异常和中断处理相关的介绍。这无疑不利于大家使用我们的Qorivva MPC56xx/57xx系列MCU开发出高效可靠的汽车电子ECU应用程序。


因此,基于自己这些年支持客户开发Qorivva MPC56xx/57xx系列MCU的经验,对Qorivva MPC56xx/57xx系列MCU所使用的PowerPC e200系列内核的内核异常(IVORx)与INTC管理的外设和软件设置中断(IRQ中断)进行总结,并结合大家使用时常见的问题(FAQ)进行介绍,希望对家有所帮助。


1. Qorivva MPC56xx/57xx系列MCU使用的PowerPC e200系列CPU内核系统异常简介


Qorivva MPC56xx/57xx系列MCU使用了众多版本的PowerPC e200系列CPU内核,不同的e200内核版本由于其内核功能和指令集的不同而具有不同的系统异常定义,下面将分别介绍。


1.1. Power e200z3/z4/z6/z7内核的系统异常


PowerPC e200z3/z4/z6/z7内核的中断向量前缀寄存器(IVPR)是其特殊寄存器SPR 63,用于存放内核系统异常向量表的基地址。该寄存器宽度为32-bit,但仅最高16-bit有效,低16-bit为0,所以PowerPC e200z4内核的系统异常向量表必须按2^16=64KB地址对齐:

2.jpg

每个PowerPC e200z3/z4/z6/z7内核的系统异常--IVORxx拥有自己独立的异常中断向量偏移寄存器(IVORxx),PowerPC e200z3/z4/z6/z7内核总共有18个系统异常(IVOR0~15以及IVOR32~34,所对应的特殊寄存器为SPR400~415以及SPR528~530,这些特殊寄存器用于设置内核系统异常向量的偏移地址),其定义如下:

3.jpg

PowerPC e200z4内核的IVORxx寄存器宽度为32-bit,但只有4~15位有效,其余高16位和低4位默认为0,所以PowerPC e200z4内核的系统异常向量(异常服务函数地址)必须按2^4=16字节对齐,这就意味着只有16个字节的空间用于处理系统异常。

4.jpg

Tips:这16字节的地址空间往往不足以存放下完整的系统异常处理代码,所以,一般是将真正的系统异常处理函数单独编写,而在对于的系统异常向量地址中放置相应的跳转语句。


比如典型的系统异常IVOR4--外部输入中断,用于处理有INTC管理的片上外设中断,在其异常处理向量IVOR4_Vector中,就是直接跳转到IVOR4_Handler:

 

5.jpg   

 而IVOR4_Handler在intc_sw_handlers.s中定义:

6.jpg

1.2. Power e200z0内核的系统异常


而对于PowerPC e200z0内核的中断向量前缀寄存器(IVPR)是其特殊寄存器SPR 63,用于存放内核系统异常向量表的基地址。该寄存器宽度也为32-bit,但仅最高20-bit有效,低12-bit为0,所以PowerPC e200z0内核的系统异常向量表必须按2^12=4KB地址对齐:

7.jpg

在PowerPC e200z0n2p和z0H2np内核并没有独立的中断向量偏移寄存器(IVORxx),而是在设计时将其硬线(hardwire)连接,使用IVPR寄存器的高20bit与12-bit向量偏移值(Vector Offset)一起组合产生其内核异常的硬线向量偏移,每个硬件偏移为2^4=16字节地址:PowerPC e200z0内核总共有16个系统异常(IVOR0~15,其定义如下表,具体触发条件定义请参考内核手册):

8.jpg

9.jpg


所以PowerPC e200z0内核的系统异常向量(异常服务函数地址)也必须按2^4=16字节对齐--只有16个字节的空间用于处理系统异常(一般仅用于存放异常服务函数跳转)。


1.3 PowerPC e200内核异常IVOR4介绍


PowerPC e200内核的系统异常中都定义外部输入(External Input)异常--IVOR4,且其定义都是相同的。该异常由内核机器状态寄存器MSR的EE位使能和关闭。常被用于IRQ中断的软件向量模式,统一IRQ中断入口,并为其提供相同的中断Prologue和Epilogue。

10.jpg

Tips:无论INTC被配置为IRQ中断软件向量模式还是硬件向量模式,MSR[EE]都是IRQ中断的全局使能和关闭控制位。其操作使用专门的汇编指令--writeei完成:


IRQ中断全局使能-->置位MSR[EE] : writeei 1

IRQ中断全局关闭-->清除MSR[EE] : writeei 0


2. INTC模块功能介绍


Qorivva MPC56xx/57xx系列MCU的所有片上外设和软件设置中断(统称为IRQ中断)都由INTC模块统一管理--对中断向量模式、中断向量表基地址和中断优先级进行配置和中断优先级仲裁并向CPU内核产生IRQ中断请求:

11.jpg

12.jpg

所以,这里有必要先介绍一下INTC模块及其相关寄存器。


2.1  INTC控制寄存器(INTC_BCR/INTC_MCR)--配置IRQ中断为硬件向量还是软件向量模式


在MPC57xx系列MCU中为INTC_BCR寄存器,其定义如下:

13.jpg

在MPC56xx系列MCU中则是INTC_MCR寄存器,其定义如下:

14.jpg

HVEN位为1时,配置为硬件向量模式,HVEN位为0时,配置为软件向量模式;关于硬件向量模式和软件向量模式,请参考下文分解。


2.2 INTC当前优先级寄存器(INTC_CPR0)--配置当其INTC模块处理的优先级


该寄存器相对于ARM Cortex M系列MCU NVIC模块的优先级屏蔽寄存器,低于该寄存器设置优先级的外设中断将被屏蔽,该寄存器在外设中断配置为软件向量模式时用于存放当前执行中断的优先级,其在中断处理时会被自动压栈和出栈。

15.jpg

Tips:该寄存器不同的内核其有效位宽不同,PowerPC e200z4内核为5-bit,故其优先级设置为0~31,而PowerPC e200z0内核为4-bit,因此其优先级设置为0~15,复位后这些位默认都是1,也就是相应的设置为31或者15,即最高优先级,这时相对于所有的外设中断都被屏蔽了。所以在初始化外设中断INTC模块时,需要将其设置为低优先级的值(常常为0--最低优先级)以使能外设中断,并且将要响应的外设中断的优先级需要设置为非零。


2.3 INTC中断确认寄存器(INTC_IACKR0)


INTC_IACKR0为32-bit寄存器,其高20位(VTBA)用于外设中断向量表基地址,2~19位(INTVEC)为外设中断或者软件设置中断向量,其最低两位为0,所以中断ISR函数地址必须4字节对齐:

16.jpg

2.4 INTC中断结束寄存器(INTC_EOIR0)


INTC_EOIR0为只写寄存器,在中断响应的最后需要向其写入0,以标识中断服务结束,并从硬件LIFO中自动出栈INTC_CPR0寄存器,恢复中断产生之前的INTC当前优先级。

17.jpg

2.5 INTC软件设置中断寄存器(INTC_SSCIRn)


MPC56/57xx系列MCU的INTC模块提供了若干(一般8个或者16个)软件设置中断,用户可以通过软件设置INTC_SSCIRn的SET位来触发相应的软件中断,在其软件中断服ISR务函数中对INTC_SSCIRn的CLR位写1清除相应的中断请求。INTC_SSCIRn的SET 位和CLR位都是写0无效;

18.jpg


Tips:MPC56/57xx系列MCU的INTC模块的软件设置中断常被用于多核CPU间通信。



在多核MCU中,每个内核有自己对于的INTC_SSCIRn寄存器,任一CPU都可以写1设置NTC_SSCIRn寄存器的SET位来触发中断请求,但NTC_SSCIRn寄存器的CLR位只能被由INTC_PSRn[PRC_SELn]指定的CPU来写1清除(即响应该软件中断)。


2.6 INTC中断优先级设置寄存器(INTC_PSRn)


INTC_PSRn寄存器用于设置INTC管理的外设中断和软件设置中断的优先级,每个中断都有其独立的优先级设置寄存器,其中PRC_SELN0位用于选择该中断是否有相应的CPU内核响应,SWTN位用于用于软件模拟产生非SSCIRs控制的片上外设中断;最低的5位PRIN用于设置该中断的优先级0~31,0为最低优先级(复位后的默认值),为了让CPU响应INTC_PSRn对应的中断,必须将其优先级配置为非零值。

19.jpg

Tips:MPC56xx系列中的单核MCU(比如MPC560x系列),其INTC_PSR寄存器为8位宽度,不存在PRC_SELN和SWTN位。

20.jpg

2.7 INTC监测模式寄存器(INTC_MMCR0)


INTC_MMCR0仅最低2位有效,用于设置中断监测的中断延迟或中断处理时间模式:

 



00(复位默认):监测关闭;

01:中断确认监测,监测IRQ中断产生到CPU确认中断的时间,超出编程延迟时间则产生错误信号;

10:中断结束监测,监测IRQ中断产生到CPU响应中断结束的时间,超出编程延迟时间则产生错误信号;

11:软件监测,在IRQ中断产生时开始定时器计时,不产生任何错误信号,但软件可用随时读取该定时器;

21.jpg


2.8 INTC中断监测选择寄存器(INTC_HIPRInC0)


INTC_HIPRInC0用于选择要监测的IRQ中断:

2-1.jpg


2.9 INTC延迟寄存器(INTC_LATnCR0)


INTC_LATnCR0用于设置IRQ中断监测的最大中断延迟时间:

2-1.jpg

2.10 INTC定时器寄存器(INTC_TIMERnCR0)


INTC_TIMERnCR0为IRQ中断延迟定时器,提供24-bitIRQ中断监测INTC时钟周期计数值:

2-1.jpg

Tips:INTC寄存器INTC_MMCR0、INTC_HIPRInC0、INTC_LATnCR0、INTC_TIMERnCR0仅存在于MPC5643L和MPC57xx系列MCU,用于满足功能安全要求。以上INTC模块寄存器介绍基于MPC574XP系列MCU的参考手册,具体的INTC模块寄存器定义可能存在差异,具体请参考所使用芯片的参考手册INTC模块章节。


3. INTC模块管理的两类IRQ中断请求:


3.1 软件设置中断


通过软件设置INTC_SSCIRn寄存器的SET位产生的中断请求;在中断ISR中对INTC_SSCIRn寄存器的CLR位写1清除中断请求/标志(即响应该软件中断);


从INTC_SSCIRn寄存器的SET位置1到INTC模块检查到该中断并向CPU内核产生中断请求的时间间隔为4个时钟周期;


3.2 外设硬件中断


所有片上外设模块产生的中断请求,比如PIT定时器中断,FlexCAN的发送完成和接收中断等;此类中断在相应的外设模块控制寄存器中有相应的中断使能位,并且拥有相应的中断标志位;


从外设产生中断请求(外设中断事件产生,相应的外设中断标志位置1)到INTC模块检查到该中断并向CPU内核产生中断请求的时间间隔为3个时钟周期;


INTC模块不管理了CPU内核的系统异常,所以当某一外设、软件设置中断请求产生时,如果其中断优先级(寄存器INTC_PSRn)高于当前优先级(寄存器INTC_CPRn设置值),相应的CPU内核就会响应该中断。同时该中断请求的优先级(INTC_PSRn)也会更新到INTC当前优先级寄存器(INTC_CPRn)。而该中断产生之前的INTC当前优先级寄存器将被压栈到INTC模块的LIFO上。


4. INTC模块中断初始化流程


从上面的INTC模块寄存器介绍,我们知道MCU复位后,INTC中断优先级选择寄存器INTC_PSRn的默认值为0(最低优先级),而INTC当前优先级寄存器INTC_CPR的默认值为15/31(最高优先级)。这时即使IRQ中断请求产生,INTC模块也不会向CPU发出中断请求。为了让INTC模块可以正常产生IRQ中断请求给CPU内核,需要对INTC模块做以下初始化:


1. 配置INTC_BCR寄存器的HVEN位(MPC57xx系列MCU)或者寄存器INTC_MCR的VTES和HVEN位(MPC56xx系列MCU),选择IRQ中断向量模式;


2. 将IRQ中断向量表基地址配置给寄存器INTC_IACKR的VTAB位域;


3. 配置需要使用的IRQ中断的INTC_PSRn寄存器中的PRIn优先级为非0值(提升优先级);


4. 配置产生IRQ中断的外设模块,使能IRQ中断--置位中断使能位(比如PIT定时器的通道中断使能位)/清除中断屏蔽位(比如FlexCAN模块的MB中断屏蔽位);


5. 将寄存器INTC_CPR中的当前中断优先级配置为0--最低优先级;


6. 使能CPU内核全局中断(置位MSR寄存器EE位)


5. 软件向量模式(Software Vector Mode)


INTC模块配置为软件向量模式时,由其管理的片上外设中断和软件设置中断通过CPU内核系统异常IVOR4--外部输入中断异常统一管理:

25.jpg

当外设中断或者软件设置中断产生后,CPU首先根据IVPR[PREFIX] + IVOR4[Vector Offset]获取IVOR4的异常处理服务函数,再在IVOR4中的中断Prilogue处理中通过读取IACKR寄存器获得中断向量表中相应的中断ISR地址并跳转执行:

26.jpg

相应的中断Prologue--通过压栈保护现场以和Epilogue--出栈恢复现场处理如下:

27.jpg

具体在MPC57xx系列MCU的S32DS for Power V1.2应用工程中,软件向量模式的中断处理prologue和epilogue处理如下(定义在工程的intc_sw_handlers.S文件中,由汇编语句编写):

28.jpg

5.1 软件向量模式下CPU内核系统异常和INTC模块初始化详解


MPC57xx系列MCU的32DS for Power v1.2应用工程调用API--xcptn_xmpl()完成CPU内核系统异常和INTC模块的初始化工作:

29.jpg

其中,首先调用API--SetIVPR(),将CPU内核系统异常向量表基地址初始化给内核特殊寄存器SPR63:

30.jpg

Tips:CPU内核异常向量表VTABLE使用C嵌套汇编语言的方式定义在工程的vector.c中,其中IVOR4_Handler申明为外部定义,在异常向量IVOR4_Vector中跳转到IVOR4_Handler,从而实现对INTC管理中断的统一处理,其他CPU内核系统异常处理默认为死循环:

31.jpg

Tips:如果是MPC5777C系列MCU,还需要调用API--InitIVORS()配置特殊寄存器IVORxx,其他MPC57xx系列的CPU内核IVORxx时硬线连接的,无需初始化;对于MPC56xx系列MCU,所有内核为e200z3(比如MPC563xM)、e200z4(MPC5643L/MPC564xA/MPC564xB/C/D)和e200z7(比如MPC567xK)的MCU也需要初始化IVORxx寄存器(请参考S32DS for Power v1.2的新建Qorivva MPC56xx系列MCU应用工程的MPC56xx_Interrupt_Init.c文件中定义的xcptn_xmpl()函数)

32.jpg

具体Qorivva MPC57xx和MPC56xx系列MCU如下:其part number的第三位数字,就表示时使用的内核版本,比如MPC574xP系列,其使用内核为PowerPC e200z4内核:

33.jpg

34.jpg

然后,在调用API--InitINTC()完成INTC模块的初始化,在InitINTC()中,首先将INTC模块配置为软件向量模式,然后再将中断向量表的基地址写到INTC_IACKR0寄存器(需要为所有INTC管理的片上外设中断和软件设置中断建立一个统一的中断向量表--每个中断向量为4字节,用于存放中断ISR的32-bit地址);


如下为MPC5744P的S32DS for Power v1.2应用工程INTC初始化函数(位于文件MPC57xx__Interrupt_Init.c中)

35.jpg

Tips:如果是多核MCU,INTC初始化时,需要先调用API函数--GetCoreID ()获取存放在特殊寄存器SPR286中的内核ID,再根据内核ID进行相应的INTC设置;


#define GetCoreID() ((uint16_t) MFSPR(286))


其中,中断向量表IntcIsrVectorTable[] 定义在应用工程的intc_SW_mode_isr_vectors_MPC5744P.c文件中:

36.jpg

Tips:IRQ中断向量表可以位于Flash中,也可以放在SRAM中--在S32DS for Power v1.2的新建应用工程中,中断向量表IntcIsrVectorTable[] 默认存放在Flash中;在CodeWarrior 10.6/7 IDE新建的应用工程中,中断向量表INTCInterruptsHandlerTable[]默认定义在SRAM中:

37.jpg

当中断向量表定义在Flash中时,我们必须在编程时将相应的IRQ中断ISR放置到中断向量表中,一旦程序运行起来之后,我们就不能再修改中断ISR了;而如果将中断向量表定义在SRAM中,我们可以在程序运行时动态的调用API函数--INTC_InstallINTCInterruptHandler()来安装和改变中断ISR,当然也可以节省Flash空间:

38.jpg

比如通过以下API调用,将中断向量IRQ59的PIT通道0的中断ISR函数安装到中断向量表中,并将其优先级设置为3:


INTC_InstallINTCInterruptHandler(PIT_CH0_ISR,59,3);


另外,请注意:默认CodeWarrior 10.6/7 IDE新建的应用工程的中断处理是不允许中断嵌套(interrupt nest)的,要实现中断嵌套需要将IntcInterrupts.c中定义的条件编译宏定义--INTC_NESTED_INTERRUPT修改为1;


千万不能简单的通过在中断ISR打开全局中断的方式来实现中断嵌套,否则会导致中断返回工程中出栈出错,而进入系统异常IVOR1。

39.jpg

最后,再调用API--enableIrq(),使能INTC中断:将INTC的当前中断优先级设置为0--最低优先级,并将MSR寄存器的EE位置1(使用专用汇编指令--“writeei 1”),使能INTC全局中断/外部中断/系统异常IVOR4:

2-1.jpg

Tips:可以通过设置MSR寄存器的EE位或者设置INTC模块的当前中断优先级寄存器来使能和关闭INTC全局中断:


使能INTC全局中断:

#define INTC_Global_IRQ_Enable  PPCAM("writeei 1")

or

INTC.CPR0.R = 0U(最低优先级);


关闭INTC全局中断:

#define INTC_Global_IRQ_Disable  PPCAM("writeei 0")

or

INTC.CPR0.R = 15U/31U(最高优先级);


6. 硬件向量模式(Hardware Vector Mode)


INTC模块的INTC_BCR寄存器HVEN0为置1时,使能硬件向量模式,在硬件向量模式下,INTC管理的片上外设中断和软件设置中断不再由系统异常IVOR4统一管理,而是每个中断拥有自己独立的中断Prologue和Epilogue:

相应的中断ISR地址为IVPR[PREFIX]+ INTC_IACKR[INTVEC]组合得到:

43.jpg

相应的中断处理过程如下:

44.jpg


总结


从以上介绍可以看到,PowerPC e200系列CPU内核的对意外事件的处理分为系统异常(IVORxx)和片上外设中断/软件设置中断(IRQxx)两大类。


其中系统异常用于处理内核运行过程中遇到的指令或者数据异常等具有较高优先级的异步中断,比如ECC、非对齐指令/数据访问引起的总线错误进而触发的机器检查(machine check)以及外部输入中断等;


而片上外设中断/软件设置中断等同步中断(也常被称作IRQ中断)由INTC模块统一管理,具体又可配置为软件向量模式和硬件向量模式:


软件向量模式下,所有的IRQ中断由内核异常IVOR4统一入口管理,用于同样的中断Prilogue和Epilogue处理,IRQ中断的响应需要先通过IVPR[PREFIX] + IVOR4[Vector Offset]获得内核异常IVOR4的异常向量(IVOR4_Vector),进而跳转异常IVOR4处理服务函数(IVOR4_Handler),然后再在IVOR4_Handler中运行同样的IRQ中断Prilogue和Epilogue处理,在Prilogue通过读取寄存器INTC_IACKR获得中断向量表(IntcIsrVectorTable[])中相应的IRQ中断向量---32-bit中断ISR函数地址,并跳转到该中断ISR执行中断处理(运行中断事件处理程序并清除中断请求标志);执行完中断ISR后,将返回IVOR4_Handler继续执行中断Epilogue处理,关闭全局中断(清除MSR寄存器的EE位),向寄存器INTC_EOIR写入0,将LIFO上保存的寄存器INTC_PCR出栈,恢复当前中断优先级,最后出栈CPU中断发生时运行上下文(runtime context--CPU内核的GPR和SPR寄存器),并运行rfi/se_rfi执行中断返回并重新使能全局中断。


Tips:rfi/se_rfi--return from interrupt,中断返回指令,rfi为PowerPC BookEd标准32-bit指令,而se_rfi为16-bit的VLE指令;


硬件向量模式下,INTC模块管理的IRQ中断不再由内核异常IVOR4统一入口管理,而是拥有自己独立的中断Prilogue和Epilogue处理,相应的中断ISR地址由IVPR[PREFIX]+INTC_IACKR[INTVEC]组合得到。其IRQ中断响应因为没有异常IVOR4的跳转和可以自定义中断Prilogue和Epilogue处理而比软件向量模式更加实时/快。其中用户自定义独立的中断Prilogue和Epilogue处理对用户的CPU内核和汇编语言知识要求较高,且每个IRQ中断编一个独立的中断Prilogue和Epilogue处理也会占用更多的存储器资源,所以,在实际使用中,很少用到IRQ中断的硬件向量模式(事实上,无论CodeWarrior IDE还是S32DS for Power IDE的新建Qorivva MPC56xx/57xx系列MCU的应用工程,默认都是配置的软件向量模式)。


以下为IRQ中断的软件向量模式和硬件向量模式的优缺点比较:

 

45.jpg