程序中断(1)
这一部分用的都是基于PS的中断。
该部分中断分为两部分,
- 基于PL外设的中断,以方便之后PS与PL之后的同步使用。
- 基于PS内部的中断,比如定时器触发中断等等。
基于三种触发方式的流水灯
该部分最后会基于之前流水灯的实验继续展开:
- 利用PS内部的定时器触发中断完成流水灯流水的过程。
- 利用PL的按钮触发中断完成流水灯功能的开关。
- 利用PS的按钮触发中断完成流水灯方向的调整。
需要使用的GPIO口有以下4组:
- PL端LED: A5、A6、A7、B8、T16
- PS端LED:C19、G17
- PL端KEY:AB12
- PS端KEY:B19
和上一次的实验一样:由A5、A6、A7、B8、C19组成一组流水灯;由T16、G17组成另外一组。
并且C19 对应的是MIO9、G17对应的是MIO0、B19对应的是MIO11。
这里主要是先完成第一部分,即完成一个计时器控制一组流水灯。
1. 创建Block
1. 创建一个ZYNQ Processing System
这里需要修改的设置如下:
- Peripheral I/O Pins 使能GPIO MIO。
- DDR Configuration 此处按照板卡的类型选择自己DDR的型号。
- Interrupts 使能中断。
这里针对中断还需要一点说明,具体提供的中断如下图所示。
主要分为3类:
1 Software Interrupts(软件中断)。
2 Private Peripheral Interrupts(私有外设中断)。PPI
3 Shared Peripheral Interrupts(共享外设中断)。SPI
该3类中断均由Generic Interrupt Controller(中断控制器)进行控制,
[参考ZYNQ7000 TRM (Page.255-256)]
[参考Zynq中 PS接收PL中断]
2. 创建一个AXI GPIO
这里主要由两个部分需要修改:
- 使能6个引脚(A5、A6、A7、B8、T16、AB12)。
- 使能中断。
实际上没有必要,但是这部分我还是打算按照两个通道去使能GPIO口。
自动连接后,生成HDL Wrapper 文件,具体大概是这个样子。这里把GPIO口命名了一下,否则有点小乱。
2. 建立管脚约束文件
这一部分需要6个GPIO口。
具体文件如下:
set_property IOSTANDARD LVCMOS33 [get_ports {leds_tri_o[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_tri_o[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_tri_o[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_tri_o[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds_tri_o[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports key_tri_i]
set_property PACKAGE_PIN A5 [get_ports {leds_tri_o[0]}]
set_property PACKAGE_PIN A7 [get_ports {leds_tri_o[1]}]
set_property PACKAGE_PIN A6 [get_ports {leds_tri_o[2]}]
set_property PACKAGE_PIN B8 [get_ports {leds_tri_o[3]}]
set_property PACKAGE_PIN T16 [get_ports {leds_tri_o[4]}]
set_property PACKAGE_PIN AB12 [get_ports key_tri_i]
之后生成Bitstream文件后,导出硬件平台信息,开始编写ps程序。
3. PS程序编写
这里首先还是应该先叙述一下中断需要使用的资源与具体的流程,主要有:
- 初始化Xilinx中断
- 配置中断控制器
- 配置中断触发信号
- 配置中断操作函数
- 连接中断函数与触发信号
首先先引用一下必须引入的模块
#include "xparameters.h" // 常数模块
#include "xgpio.h" // PL GPIO模块
#include "xgpiops.h" // PS GPIO模块
#include "xscutimer.h" // 计时器模块
#include "xscugic.h" // 中断控制器模块
#include "xil_exception.h" // 中断模块
1. 内部定时器中断(1组)
由于有两组流水灯,这一部分需要两个定时器,两组中断。所以这里没有办法使用单独的29号中断,因为需要不止一个中断信号。这里仅仅是略微修改一下下xscutimer_intr_example的例程,首先完成一组流水灯。
[参考ZYNQ7000 TRM (Page.229)]
具体需要用的函数比较多,一股脑列出来会比较乱,这里分一下类:
- 与GPIO相关的:
初始化相关:
// PL GPIO口初始化
XGpio_Config *XGpio_LookupConfig(
u16 DeviceId
);
int XGpio_CfgInitialize(
XGpio * InstancePtr,
XGpio_Config * Config,
UINTPTR EffectiveAddr
);
//PS GPIO口初始化
XGpioPs_Config *XGpioPs_LookupConfig(
u16 DeviceId
);
s32 XGpioPs_CfgInitialize(
XGpioPs *InstancePtr,
XGpioPs_Config *ConfigPtr,
u32 EffectiveAddr
);
GPIO口配置
//PL GPIO口配置
void XGpio_SetDataDirection(
XGpio *InstancePtr,
unsigned Channel,
u32 DirectionMask
);
//PS GPIO口配置
void XGpioPs_SetDirection(
XGpioPs *InstancePtr,
u8 Bank,
u32 Direction
);
void XGpioPs_SetOutputEnable(
XGpioPs *InstancePtr,
u8 Bank,
u32 OpEnable
);
GPIO口写入
// PL GPIO写入
void XGpio_DiscreteWrite(
XGpio *InstancePtr,
unsigned Channel,
u32 Mask
);
// PS GPIO口写入
void XGpioPs_WritePin(
XGpioPs *InstancePtr,
u32 Pin