一、前言
Xlinx的ZYNQ系列SOC集成了APU、各种专用外设资源和传统的FPGA逻辑,为ARM+FPGA的应用提供助力,降低功耗和硬件设计难度的同时极大提高两者间传输的带宽。之前在研究生课题中使用过ZYNQ搭建环路系统对算法进行板级验证,但并没有深入使用和理解这个异构平台,今天算是对入门的总结。一款SOC的入门必然是GPIO的使用,而中断则是MCU能保证实时性的必杀武器。硬件调试难度高一直是FPGA的痛点,集成ARM的FPGA更是如此,cross-trigger调试有效地解决了这一问题,所以它也作为入门ZYNQ的必要技能。
二、硬件系统搭建
ZYNQ的三种GPIO分别是MIO、EMIO和AXI-GPIO。PS部分直接连接到芯片引脚的IO叫MIO,经过FPGA再连接到引脚的是EMIO。EMIO可以通过硬件约束指定不同的端口号和电压标准,提高了ARM IO的灵活性。而AXI-GPIO相当于是对ARM IO的补充,通过调用AXI-GPIO IP核与外部通信。以下通过一个实例来说明三种IO的使用方式。
系统功能:使用一个MIO使连接其上的LED闪烁,使用8个EMIO同样与LED连接构成流水灯效果,另外再调用一个5bit位宽的AXI-GPIO IP核以终端模式响应电路板上5个按键。
平台:米联客 MIZ702N (ZYNQ-7020)
配置ZYNQ IP,使能MIO和EMIO,配置EMIO位宽是8bit。
使能Cross Trigger和共享中断。
之后添加AXI-GPIO IP Core,配置位宽并使能其中断功能:
运行Run Automatic Connection最终block design系统结构:
这里使用ILA抓取AXI-GPIO的中断信号。
三、软件编程与AXI-GPIO中断模式解析
Implementation,export hardware with bitstream, launch SDK. BSP中自带了硬件系统所使用到的IP的一些示例代码和文档,为入门提供了很好的帮助。
为了方便复用,对Xilinx提供的API做进一步封装,生成gpiops.h gpiops.c gpio.h gpio.c和gic.h文件。接下来重点讲述GIC相关的代码原理。若要使用中断系统,首先要初始化GIC,和其他IP一样包括查找配置和初始赋值两个步骤,分别由LookupConfig和CfgInitialize两个函数完成。后者实际上初始化了中断处理句柄使其指向了一个空结构。要理解内部原理,需要弄清楚XScuGic的数据结构。
其中Handler实际上是一个函数指针类型,用于定义中断产生时的回调函数。而CallBackRef用于传入InstancePtr,即Gic Instance Pointer。GIC初始化完,要将GIC与中断ID和自定义中断回调函数绑定。
内部的核心代码依然和初始化时一致,只不过换成了输入参数:
下一步该使能中断了,一方面是使用GIC对GPIO中断ID的响应,另一方面是使能AXI-GPIO的中断信号。最后是系统对异常的处理函数,这里将其封装在exception_enable中:
总结来看,中断系统建立的步骤为:
1 初始化GIC
2 连接GIC与中断ID和回调函数
3 使能中断
4 使能异常处理
那么为什么完成上述操作后,中断事件发生会立即执行自定义中断回调函数GpioHandler呢?CPU会将中断向量表存储在特定的寄存器中,读取该寄存器可以获取中断向量表内容,里边存放着各个中断ID对应的中断函数入口地址。跳转指令则有中断控制器完成。
接下来是各个文件的软件代码: