SoC 第三讲 AMP架构双核应用程序开发和软中断处理(二)—— ZYNQ 的软中断
本节介绍ZYNQ基于ARM架构的中断原理和结构,包括中断控制器(GIC)。
ZYNQ中断结构图如下(Zynq的PS是基于ARM架构,使用两个ARM Cortex A9处理器和GIC PL390中断控制器):
硬中断,可连接到外设。串口、IIC都可以利用中断模式进行数据的传输。主要在PS-PL应用中比较多。由PS和PL上的各种I/O控制器和存储器控制器产生,这些中断信号被路由的CPU.
通用中断控制器是基于非向量的 ARM 通用中断控制器架构v1.0 的。中断控制器的框图:
GIC 寄存器是通过CPU 私有总线来访问的,这条私有总线避开了互联中的瓶颈和偶尔的阻塞,从而确保了读写的快速响应时间。所有的中断源都被中断分配器(ICD, Interrupt Controller Distributor)集中起来,然后其中最高优先级被分派到具体的某个CPU 上去。
通常把GIC分成两个部分,分发器(ICD, Interrupt Controller Distributor)和CPU接口
2.1.1 分发器(ICD, Interrupt Controller Distributor):
分发器的主要的作用是检测各个中断源的状态,控制各个中断源的行为,分发各个中断源产生的中断事件到指定的一个或者多个CPU接口上。虽然分发器可以管理多个中断源,但是它总是把优先级最高的那个中断请求送往CPU接口。分发器对中断的控制包括:
(a)中断使能或禁能控制。
(b)控制将当前优先级最高的中断事件分发到一个或者一组CPU接口。
(c)优先级控制。
(d)中断属性设定,例如是电平触发还是边沿触发。
(e)中断的设定。
分发器可以管理若干个中断源,这些中断源用ID来标识,我们称之interrupt ID
2.1.2 ICD 寄存器:
寄存器 地址 中断号
ICDICFR0 0xF8F01C00 #0-#15
ICDICFR1 0xF8F01C04 #27-#31(16-26保留)
ICDICFR2 0xF8F01C08 #32-#47(36保留)
ICDICFR3 0xF8F01C0C #48-#63
ICDICFR4 0xF8F01C10 #64-#79
ICDICFR5 0xF8F01C14 #80-#95(93/94/95保留)
2.1.3. 中断控制器(ICC寄存器):
2.2 CPU接口功能
CPU接口主要用于和CPU进行接口。主要功能包括:
(a)使能或者禁能CPU接口向连接的CPU提交中断事件。对于ARM,CPU接口和CPU之间的中断信号线是nIRQCPU和nFIQCPU。如果禁能了中断,那么即便是分发器分发了一个中断事件到CPU接口,但是也不会提交指定的nIRQ或者nFIQ通知CPU。
(b)ackowledging中断。CPU会向CPU接口应答中断,中断一旦被应答,分发器就会把该中断的状态从pending状态修改成active,如果没有后续pending的中断,那么CPU 接口就会deassert nIRQCPU和nFIQCPU信号线。如果在这个过程中又产生了新的中断,那么分发器就会把该中断的状态从pending状态修改成pending and active。此时,CPU接口仍然会保持nIRQ或者nFIQ信号的asserted状态,也就是向CPU通知下一个中断。
(c)中断处理完毕的通知。当中断处理器处理完了一个中断的时候,会向写CPU 接口的寄存器从而通知GIC已经处理完该中断。做这个动作一方面是通知分发器将中断状态修改为deactive,另外一方面,可以允许其他的pending的中断向CPU接口提交。
(d)设定优先级掩码。通过优先级掩码可以mask掉一些优先级比较低的中断,这些中断不会通知到CPU。
(e)设定中断抢占的策略。
(f)在多个中断事件同时到来的时候,选择一个优先级最高的通知CPU。
2.3 GPIO中断源配置
所有GPIO共享一个中断(#52,bank1),必须在软件上检查INT_MASK和INT_STAT的值判断是哪个GPIO引发了中断。
每个CPU 都能用SGI 来中断自己、另一个CPU 或同时中断两个CPU。被路由到一个或者两个CPU上,通过写ICDSGIR寄存器产生SGI.
向软件产生的中断寄存器(Software Generated Interrupts Register,ICDSGIR)写入SGI 中断编号并指定目标CPU (或两个CPU),就产生了一个SGI。这个写入是由源CPU 的CPU 私有总线执行的。每个CPU 各自有一组SGI寄存器,可以产生16 个软件产生中断中的一个或多个。中断的清除是通过读取中断确认寄存器(Interrupt Acknowledge Register,ICCIAR)或向中断挂起清除寄存器(Interrupt Clear-Pending Register,ICDICPR)对应的位写入“1” 值来实现的。
所有的SGI 都是边缘触发的,它们的敏感性类型是固定的,而且不能被修改。
用于各个core之间的通信
每个CPU都有一组PPI(每个CPU核连接到了一个有五个外设中断的私有组上),包括全局定时器、私有看门狗定时器、私有定时器和来自PL的FIQ/IRQ
GIC 必须被编程以实现让所有的PPI 敏感性类型都与请求源绑定,而且不能被改变。这些寄存器不能被Boot ROM 所编程,因此GIC 必须被SDK 芯片驱动程序编程来配合这些PPI 敏感性类型。
值得提及的是,从PL 来的中断(IRQ)和快速中断(FIQ)信号在发送给中断控制器之前,会在传输给PS 的时候被反转。这些信号因此在PL 内被反转为低电平有效前,在PS 内的PS-PL 接口上是高电平有效的。
有大约 60 个来自各种模块的中断可以被传送到 PL 或一个或两个CPU。那些目标为CPU 的中断的优先级和中断的接收情况是由中断控制器管理的
和PPI 类似,SPI 的中断敏感性类型是与请求源绑定的,不能被修改。SDK 驱动程序必须对GIC 编程来适应这些敏感性类型。
如 global timer 、uart 、gpio 产生的中断
上面介绍了中断的整体结构框架,下面介绍了中断时具体怎么控制的
中断的处理流程是:
分发器把收集来的中断先缓存,依次把优先级最高的中断请求送往CPU接口,CPU读取一个中断,其实就是读取接口的一个寄存器,只不过这个寄存器存放的是中断号,此时中断的状态由pending转为active,CPU处理完了以后,将中断号写入GIC的接口,告诉GIC处理完了,可以将这个中断清理。
下节将利用上面的软中断,在用软中断之前需要对GIC进行初始化,然后才能与CPU进行通信。
具体的中断设置很简单,跟其他的单片机程序一样,主要有以下几部分,详细的介绍会结合案例分析,在下一节中介绍。
首先进行GPIO初始化,这个就不需要多说了。
其次进行中断的设置,如中断控制,全局中断允许等等,主要用了以下函数
XScuGic_LookupConfig //中断设置查找
XScuGic_CfgInitialize //GIC初始化
XScuGic_SetPriorityTriggerType //设置中断优先级及中断触发方式,笔者在这里有些疑问,手册上面说中断触发方式不可以更改这里为何有这个函数呢,还需要研究一下
XScuGic_Connect //设置中断服务程序入口地址
XScuGic_Enable //GIC允许
XGpio_InterruptGlobalEnable //GPIO全局中断允许
XGpio_InterruptEnable //相应GPIO中断允许
Xil_ExceptionInit// 异常处理函数
Xil_ExceptionRegisterHandler
Xil_ExceptionEnable
总结来看,由于SDK提供的库文件使得Zynq中断使用很方便简单,并且中断源很多,加上PS部分与PL部分的配合,使用非常灵活。