1.模块简介
对于嵌入式系统来说,实时性是一个非常重要的特性,相比较于桌面端系统,嵌入式系统往往部署在各种硬件设备上,这些硬件设备的控制往往都要求毫秒甚至微秒级的反馈。而在车规级控制器中,有些硬件功能的实时性要求就更为严苛。
而提到实时性,就不得不提中断,在计算机原理中,中断是一种用于打破正常程序执行流程的机制。中断允许计算机在执行程序的过程中临时暂停当前任务,转而处理其他优先级更高或需要立即处理的事件。这些事件可能来自系统的外部输入(如键盘、鼠标、定时器)或系统内部(如除零错误、内存访问错误等)。
广义的中断概念包括以下几个关键要素:
- 中断请求(Interrupt Request,IRQ):外部设备或系统内部产生中断时,会向计算机发送中断请求。每个中断源通常有一个唯一的IRQ号。
- 中断向量表Interrupt Vector Table,IVT):计算机维护一个中断向量表,其中存储了每个可能中断的处理程序的地址。当中断发生时,计算机通过查找中断向量表找到相应中断的处理程序。
- 中断服务程序(Interrupt Service Routine,ISR):中断服务程序是一段特定的代码,用于处理特定中断类型。当中断发生时,控制权会转移到相应中断的ISR,执行相关操作。
- 中断控制器Interrupt Controller):中断控制器负责管理和协调各个中断源,确保按照优先级处理中断。常见的中断控制器包括 PIC(Programmable Interrupt Controller)和 APIC(Advanced Programmable Interrupt Controller)。
中断的引入提高了计算机系统的响应性和并发性,允许系统在处理一些紧急事件时快速做出响应。中断机制是操作系统和硬件之间协调的重要手段,确保系统能够高效地处理各种事件。
TC3XX系列中断采用中断路由的方式,将硬件中断源和CPU、DMA进行灵活的连接,并且有着稳定可靠高效的硬件上下文保存机制,具有较高的中断实时性。
这里补充一点,中断虽然称为中断,但并不是在任意时刻都可以打断普通程序的运行,在计算机系统微观视角中,一般是每条指令执行之后(一条指令一般包括取指、译码、执行、访存等步骤)由硬件查询是否有中断需要执行,如果有就执行中断响应步骤,如果没有则继续下一条指令。
2.功能介绍
2.1中断系统
TC3XX系列的中断系统涉及到外设、中断控制器、CPU、DMA等的交互,每个模块内部都有与中断相关的控制寄存器,因而这里称其为中断系统,下面我们将从整体上,先阐述TC3XX系列芯片中断系统的交互逻辑。
熟悉ARM的朋友都知道,在ARM系统中,中断向量表中存放了每个中断服务例程(也就是中断函数)的地址**,当出现中断信号时,由向量中断控制器VIC接收该信号,然后进入统一的中断枢纽例程中,在中断枢纽例程中查询向量表然后进行中断服务例程**的跳转。
TC3XX系列的中断响应路线其实和这个类似,不同的是TC3XX中没有中断枢纽例程,CPU接收中断信号后直接跳转到中断向量表,在中断向量表中每个中断有最多32字节的代码空间,一般是在向量表中放跳转指令,跳转到实际执行的中断服务例程中。下图是TC3XX中断系统的硬件框图:
从图中我们可以看到整个中断系统包含来自软硬件的中断源,一个**中断路由器IR,和对应的服务提供者**,服务提供者可以是CPU或者是DMA,所以在这里中断请求的术语称之为Service Request,服务请求,因为它可能触发一个CPU中断,也可能是触发一个DMA转换。
它的大体响应流程是这样的:当外部中断源如ADC等模块产生了服务请求信号,会发送给IR,IR根据配置的优先级进行仲裁,并将胜出的服务请求路由至对应的服务提供者,如果服务提供者是CPU则是中断服务,如果是DMA则是某路DMA通道的转换使能信号。
下面我们展开介绍各个模块在中断系统中的运行逻辑。
2.2中断源
中断源是由外设模块、软件模块等进行的服务请求,每个外设模块都有不同的请求事件,比如ADC模块当某个Group的转换完成之后会发出对应的服务请求,CAN或Eth模块在收到外部数据时会发出接收服务请求。具体的资源情况是硬件固定的,使用时需要查询对应模块的说明。
一般情况下,外设的中断信号没有开关,对应的事件发生之后就会向IR发送请求,而中断的控制逻辑由后续的IR模块和CPU来负责处理。
2.3中断路由器IR
中断路由器IR负责接收系统的服务请求,然后进行优先级仲裁,并将仲裁胜出的请求路由至对应的服务提供者。它的输入是各个外设模块,输出则是CPU或DMA模块。IR模块主要包括服务请求节点(Service Request Node, SRN)、中断控制单元(Interrupt Control Unit,ICU)和外设总线接口(Bus Peripheral Interface,BPI)。IR有很多的SRN,每个SRN对应一个硬件的服务请求,比如ADC0有4个服务请求,则在IR中就有与其对应的4个SRN。中断控制单元负责与对应的服务提供者进行连接。外设总线接口则负责外设总线的连接。
2.3.1 服务请求节点SRN
每个SRN对应一个硬件的服务请求,外设模块的服务请求信号在硬件上一般是直接连接到其对应的SRN的,具体的中断控制如优先级、使能、状态查询等都是在SRN中进行的。每个SRN有一个服务请求控制寄存器(Service Request Control Register,SRC),如SRC_VADC_G3_SR0表示ADC3的SRC寄存器。
SRC寄存器中包含了这个服务请求的控制和状态量,下面我们详细介绍其中的每个成员。
Service Request Priority Number (SRPN):服务请求优先级,也就是我们常说的中断优先级,它决定了服务请求在IR中仲裁的结果;同时它也是和CPU中断向量表对应,这个稍后在CPU中断逻辑中会介绍;另外当路由对象是DMA时,它指示对应的DMA通道;Enable Bit (SRE):也就是中断使能位,如果使用中断则需要打开,决定IR是否将该请求路由到对应的服务提供者,如果使能位没有打开,也可以通过软件轮询SRR中断状态位来执行对应服务例程;Type-Of-Service Control (TOS):服务类型,也就是选择将服务路由到哪个ICU中,CPU0、CPU1或者DMA;Service Request Flag (SRR):中断标志位,该位在服务提供者响应服务的时候会自动清除,所以TC3XX中不需要软件去清除中断标志位,但如果没有打开SRE使用的轮询,则需要每次执行后用CLRR清除中断标志位;Clear Bits(CLRR):中断标志清除位,用来清除SRR,读的话一直是0;Set Bits(CLRR):软件中断请求位,可以通过软件来请求一次中断;Interrupt Trigger Overflow Bit (IOV):中断溢出标志位,如果一个中断没有被接收或者清除,又进行了一次触发,则该位会置位;Interrupt Trigger Overflow Clear Bit (IOVCLR):中断溢出标志清除位,清除中断溢出标志,读的话一直是0SW Sticky Bit (SWS):软请求粘滞位,如果调用过SETR接口进行过软触发,则该位会置位直到清除;SW Sticky Clear Bit (SWSCLR):软请求粘滞清除位,用来清除软请求粘滞位,读的话一直是0;
SRC是中断系统中非常重要的寄存器,比如我们要判断硬件是否发出服务请求,就看SRR位。查看是否路由到CPU,就看SRE使能位,当然CPU中也有中断的使能和仲裁逻辑,我们下面会介绍。
2.3.2 Interrupt Control Unit (ICU)
每个SRN的服务请求会路由到一个ICU中,一个ICU连接一个CPU或者DMA,每个ICU内部进行服务请求的仲裁,并将仲裁的结果发送到连接的服务提供者。ICU中一般不需要配置,与CPU和DMA的连接相对比较固定。我们可以通过查询ICU的寄存器查看仲裁或路由情况,包括LASRx、ECRx等,这些寄存器一般是只读的,不需要用户配置,这里就不展开介绍了。
2.4CPU as Interrupt Service Provider
当服务请求被路由到CPU的时候,CPU会接收IR的信号并作应答,然后执行对应的服务例程,也就是我们常说的中断。接下来我们从CPU的角度介绍中断的处理流程。在此之前,我们先介绍两个重要的寄存器,中断向量表基址指针(Base Interrupt Vector Table Pointer,BIV)和ICU中断控制寄存器(ICU Interrupt Control Register,ICR)。这里需要注意的是,这两个寄存器属于CPU寄存器,在多核系统中,每个核都有一套自己的CPU寄存器,所以会存在CPU0_ICR,CPU1_ICR,而前文提到的IR模块寄存器属于外设寄存器,一个系统里只有一套。CPU寄存器不能直接读写,要通过ENABLE、DISABLE、MTCR、MFCR等内核指令访问。
如上图是中断向量表基址指针寄存器,包括中断向量表基址BIV和向量空间选择位VSS。
- BIV:Base Address of Interrupt Vector Table,中断向量表基址,TC3XX的中断向量表是存放在Flash中的连续地址,因此需要该寄存器来表示向量表基地址;
- VSS:Vector Spacing Select,向量空间选择位,该位表征每个中断向量所占的内存空间,0表示每个中断向量占据32字节,1表示8字节,默认为32字节;
ICR是CPU主要的中断控制寄存器,其中包括全局中断使能位IE,当前CPU中断优先级位CCPN和等待中断优先级位PIPN。
- IE:Global Interrupt Enable Bit,全局中断使能位,我们所使用的关闭所有中断操作,就是将该位置0,因为每个CPU是独立的,也有自己的ICR控制器,所以IE只控制当前核的中断开关;
- CCPN:Current CPU Priority Number,当前CPU中断优先级,在非中断程序执行时,该位为0,进入中断时,该位会被硬件设置为所触发中断的优先级;
- PIPN:Pending Interrupt Priority Number,等待中断优先级,表征当前CPU收到IR路由但还未处理的中断优先级。
2.4.1 中断向量表
众所周知,早期的单片机系统中,硬件触发中断后,进入同一的中断入口函数,在入口函数中查找中断源,然后选择对应的中断服务例程。这样的系统结构中断的响应效率较低,后面才出现了向量中断。向量中断的核心亮点在于由硬件进行中断入口的查找和跳转,这样可以大大降低中断的响应时间,达到真正的高实时性。
TC3XX的中断向量表存放在PFlash(代码段)中的一段连续地址中,默认一个向量的存储空间是8 word(32字节),通过BIV指向其基地址。这里有一个非常巧妙的逻辑,中断向量的位置是和中断优先级绑定的,也就是前文IR模块中的SRC.SRPN,比如优先级为80的中断,它的向量地址就是基址加上偏移为BIV+80*32,CPU在接收该中断信号后第一行运行的代码也就是这个位置。这样设计省去了从中断源到中断入口地址的链接开销,只需要在编译过程中对中断向量表进行编址,CPU在接收到IR的中断信号之后直接按照对应的优先级进行跳转。中断向量表在内存中的结构如下图:
如图我们还可以看到,向量表是支持跨优先级占用的。因为一般情况下32字节放不下中断服务例程,只能放跳转指令,但是如果代码量不那么大,可以通过占有多优先级的方式,省去一次跳转。上图中优先级25放置了一个中断,通过优先级2的中断源触发,这里35因为被占据,所以要注意不能再给其他中断使用了。
2.4.2 CPU中断控制策略
前面我们提到,IR模块中有SRC.SRE位表征到达IR的服务请求信号是否会被路由,但是路由到CPU之后也并非能够直接执行,还需要判断相关的条件。
我们都知道,系统在运行过程中有时需要进入临界区时,防止中断程序或者OS调度程序破坏数据一致性。而根据数据的保护需求,对于临界区的实现可能是关闭所有中断,或者关闭OS中断(也就是关闭某一优先级以下中断)。
对于TC3XX来说,如果要关闭所有中断,那么操作方法就是将ICR.IE置0,此时所有路由到该CPU的中断都处于Pending状态,不会被接收。而如果要关闭OS中断,将所有OS优先级以下的中断全部屏蔽,则可将ICR.CCPN设置为目标门槛优先级,小于或等于该优先级的中断都将被屏蔽。
所以当中断信号到达CPU的时候,如果ICR.IE为1,且该中断优先级大于ICR.CCPN中指示的当前CPU中断优先级,CPU会接收该中断,向IR发出ACK信号,则IR中的中断标志位SRC.SRR会被硬件清除,然后CPU开始执行中断响应步骤。
2.5DMA as Interrupt Server Provider
除了CPU接收IR的服务请求信号执行中断响应程序以外,TC3XX的中断系统还有一个亮点,那就是将服务请求信号路由到DMA中,硬件触发一次DMA转换。这种连接,我们只需要将SRC.TOS设置为DMA,然后将SRC.SRPN设置为目标DMA通道号,即可实现路由。
我们都知道,根据摩尔定律,计算机的计算能力每18个月能翻一倍,而存储器的性能每年只能提升7%,所以经过这么多年的发展,内存已经成为了计算机计数的瓶颈,现在CPU的Cache不断增大,也就是为了照顾这一短板。
而DMA的主要目的是承担CPU数据读写的任务,从而解放CPU的算力。TC3XX中实现了将外设的中断信号连接到DMA中,我们就可以通过设计外设触发链路,不经过CPU就能完成外设数据的处理。比如通过ADC中断触发DMA,能够直接将ADC采样数据取到RAM中;通过将SPI的中断信号路由到DMA,就能完成后台异步SPI发送。
2.6CPU中断处理流程
当所有条件满足,CPU就要开始响应中断了,下面我们将介绍CPU对于中断的响应和退出流程。
在CPU决定响应中断时,并不是直接去按向量表执行其中断服务例程,而是先由硬件执行一系列操作进行上下文保存,也就是保护现场,而在退出中断之后也需要加载上下文,也就是恢复现场。下面我们先详细介绍CPU对于中断的硬件响应步骤:
- 第一步是保存上部分上下文,TC3XX系列芯片中存在硬件CSA机制,分为上、下两部分上下文,主要包括通用寄存器和链接地址等信息,其中上部分是由中断或者异常时由硬件自动保存,并在退出时使用RFE指令加载回来,下图为CSA结构图,关于CSA的机制本文就不展开讨论了,后续会出专题进行介绍;
- 保存返回地址寄存器A[11],也就是我们常说的链接寄存器;
- 如果此时CPU的中断栈使能开关PSW.IS没有打开,则硬件会将栈寄存器A[10](SP指针)指向中断栈指针ISP,以使用中断的栈,同时将PSW.IS置位;
- 将I/O模式(外设访问权限)设置为Supervisor模式;
- 将当前保护寄存器集设置为PSW.PRS=000B,TC3XX每个核有6套内存保护的设置集,如果使用了内存保护则这里表示会切换到PSW.PRS=000指向的保护策略;
- 调用深度计数器PSW.CDC清零,并且调用深度限制被设置为64;
- 调用深度检查打开:PSW.CDE=1;
- PSW安全位被设置为SYSCON中的值:PSW.S = SYSCON.IS;
- 全局地址寄存器A[0], A[1], A[8], A[9]的写入会被禁用:PSW.GW=0;
- 当前全局中断使能位ICR.IE被保存到PCXI链接字寄存器中的先前全局中断使能位PCXI.PIE中,然后将ICR.IE置0,关闭所有中断;
- 当前中断优先级ICR.CCPN被保存到PCXI链接字寄存器中的先前中断优先级位PCXI.PCPN(这里顺便一提,PCXI在上部分上下文中,第一步已经保存到CSA中了,因此在嵌套处理时,此处PCXI可以写入,以实现中断嵌套);
- 等待中断优先级位ICR.PIPN被写入到当前CPU中断优先级位ICR.CCPN;
- 从中断向量表中取第一条指令,然后开始执行中断服务函数,至此硬件的处理流程结束。
回看整个中断响应流程,其实CPU在响应中断的时候,主要做的事情就是保护上下文、切换系统模式、切换中断环境,这在任何一个系统中都是必需的,而TC3XX得益于其独特的硬件上下文自动保存机制,省去了软件压栈的时间,对中断的实时性有较好的优化作用。
中断执行完毕之后自然需要退出中断,退出中断需要使用RFE指令,然后硬件会执行相应的步骤:
- 将链接字寄存器中的先前中断优先级位PCXI.PCPN写入到ICR.CCPN中,这样就恢复了中断进入之前的系统中断优先级门槛;
- 将链接字寄存器中的PCXI.PIE被恢复到ICR.IE中;
- 从CSA中加载进入中断时保存的上部分上下文。
从中断退出流程我们可以看到,其实主要的硬件处理是还是处理上下文和中断环境。TC3XX的中断是可以直接嵌套的,我们可以直接在中断服务例程中使能全局中断,打开嵌套,得益于其完善的硬件上下文保存机制,软件不需要像ARM一样执行系统模式切换和额外的上下文保存工作,从而提升了系统执行效率。
2.7不可屏蔽中断NMI
TC3XX还提供了一种不可屏蔽中断机制(Non-Maskable Interrupt,NMI),一般是SMU模块或者外部ESR0/ESR1引脚触发,用于响应紧急事件。这种机制虽然叫不可屏蔽中断,但是它的本质走的是Trap系统,而不是本文中的中断系统,因此IR模块或CPU的中断控制位都不会对其响应产生影响,从而实现不可屏蔽中断的响应逻辑。关于不可屏蔽中断,本文就不展开介绍了,后续在TC3XX Trap系统中再进行讨论。
3 DaVinci 配置实例
DaVinci Configurator中的中断配置与EB Tresos略微有所差异,但是原理是相同的。
1、在 EB Tresos 中,英飞凌针对 AURIX 芯片专门设计了一个专有模块
Irq,在Irq模块下,英飞凌已经针对 ADC、CAN、GTM 等所有硬件外设,预先建好了各自的配置容器,工具链在后台早就把各个中断的物理地址对应好了,不需要再手动配置。2、DaVinci 的配置逻辑:Vector 认为,不管你是什么外设产生的中断,只要进到 CPU,就必须接受操作系统(OS)的统一调度和管理。因此,它把所有的中断全部收拢到
Os模块的OsIsrs(中断服务程序列表)中统一排队。需要查数据手册,手动配置中断对应的物理地址。
3.1 EB Tresos配置
在EB工具中的Irq模块中,找到IrqAdcConfig页面进行Adc的中断配置(注意TC3XX中有DSADC模块,用于Delta-Sigma转换,本文用的是EVADC),这里我们来到Adc0,将Catogary配置为CAT1(CAT2为OS中断),然后设置中断优先级,这里使用120,然后TOS选CPU0,由CPU0执行中断函数。
3.1 DaVinci:/Os/OsIsrs
在DaVinci中的中断主要配置以下地方
OsIsrCategory:中断服务程序(ISR)类别
- CATEGORY_2(二类中断):由操作系统(OS)完全管理。进入和退出中断的上下文切换(压栈、出栈)由系统自动完成,应用层不需要关心。它运行在独立的专用堆栈上,并且支持内存保护和时间保护(防止中断超时卡死)。
- CATEGORY_1P(保护型一类中断):同样由 OS 管理,进入/退出无需应用层处理,也运行在独立的专用堆栈上且支持内存保护。
- CATEGORY_1(一类中断):不受 OS 管理。中断的进入、现场保存和退出恢复,必须由应用层代码(或外设驱动汇编)自己全权处理。它没有自己独立的堆栈,而是直接借用当前被它打断的那个程序的堆栈。
- CATEGORY_0(零类中断):同样不受 OS 管理,现场处理完全由应用代码负责,同样没有独立堆栈(借用被中断程序的堆栈)。它无法被系统关闭/屏蔽(Can’t be disabled),意味着它可以打断系统里任何其他的 ISR 中断。
OsIsrInitialEnableInterruptSource:该硬件中断源是否应该在系统初始化时被默认开启。
OsIsrInterruptPriority:中断优先级
OsIsrInterruptSource:中断服务程序(ISR)所对应的底层硬件中断源编号(物理标识符),中断源编号参考TC33xTC32x_appx_um_v2.0.pdf的16.4章节
4 Demo示例
4.1 初始化ADC中断
(1)ADC0软件组和ADC1软件组的SR0都已经初始化使能
(2)使能ADC0的SR2(需要配置寄存器实现)
4.2 设置中断服务函数
参考资料
[1] AURIXTC3XX_um_part1_v2.0.pdf
[2] TC33x_TC32xAA_DS_v1.1.pdf
[3] TC33xTC32x_appx_um_v2.0.pdf
[4] TriCore_TC162P_core_architecture_volume_1_of_2.pdf