一、GPIO简介
ZYNQ 的 IO包括对外连接的 GPIO 和内部 PS 与 PL 通信的 AXIO。其中对外的 GPIO 又分为
两种: MIO 和 EMIO。 MIO 和 EMIO 只是 GPIO 信号的两种接口, MIO 直连到PS(数量有限), EMIO 则是 PS 扩展到 PL,从 PL 接出的 I/O。 EMIO 依然属于 PS,只是连接到了 PL,再从 PL 输出信号。所以 MIO 不需要管脚约束,而 EMIO 需要管脚约束。
I/O控制器信号的 I/O复用是不同的, 也就是说,一些 IOP(I/O Peripheral)信号仅在 MIO 接口上可用,如 USB 外设信号; 一些信号在 MIO 或 EMIO 接口上可用,如 UART 信号; 而一些接口信号只能在 EMIO 接口上访问,如 UART的 Modem signals 接口信号。
MIO (54 个引脚)分配在 GPIO 的 Bank0(0~31,MIO7和MIO8只能输出) 和Bank1(32~53),属于 ZYNQ 的 PS 部分,支持三态输出。
EMIO(192个引脚) 64 个为 PL 到PS 的输入, 128 个为 PS 到 PL 的输出,分配在 GPIO 的 Bank2 和 Bank3。
IOP 接口 I/O 信号的路由必须作为一个组进行。也就是说,信号不能被分割并路由到不同的 MIO 引脚组。例如,如果 SPI_0_CLK 路由到 MIO 引脚 40,那么 SPI_0 接口的其他信号必须路由到 MIO 引脚 41 ~ 45。类似地, IOP 接口内的信号不能在 MIO 和 EMIO 之间分割。
注意:
二、GPIO特性(内存映射基地址:0xE000_A000)
- 每个 GPIO 可以单个或以组为单位进行动态编程;
- 支持使能、按 bit 写数据、按 bank 写数据、输出使能、方向控制功能;
- 每个 GPIO 都可配置为中断敏感,支持原始与屏蔽中断的状态读取,敏感源支持电平敏感(高电平或低电平)、边沿敏感(上升沿、下降沿或两者同时)。
EMIO区别:
- 输入是来自 PL 的连线,与输出值或 OEN 寄存器无关。若 DIRM 设置为 0,可以从 DATA_RO 寄存器中读取输入值。
- 输出不支持三态,因此不受 OEN 寄存器的控制。输出时将 DIRM 设置为 1,使用 DATA、 MASK_DATA_LSW、 MASK_DATA_MSK寄存器配置输出值。
- 输出使能线由 PS 输出到 PL,这些使能线受到 DIRM 和 OEN 寄存器的控制,如 EMIOGPIOTN[x]=DIRM[X]&OEN[X]。
EMIO 的 I/O 不能与 MIO 的 I/O 连接在一起的, EMIO 的输入不能与 MIO 的输出接在一起; MIO 的输入也不能与 EMIO 的输出连接在一起。
MIO 在 zynq 上的管脚是固定的,而 EMIO 是通过 PL 部分扩展的, 在使用EMIO 时候需要在约束文件中分配管脚。 设计 EMIO 的程序时,需要生成 PL 部分的 bit 文件,烧写到 FPGA 中
三、GPIO通道
DATA_RO: 当 GPIO 被配置成输出的时候,值会反映输出的 PIN 脚情况。需要注意的是,MIO 没有配置成为 GPIO 引脚,那么 DATA_RO 的状态是不可预测的,软件无法观察到非 GPIO 引脚上的值。
DATA:当 GPIO信号被配置为输出时,控制输出的值。该寄存器的所有 32 位是被同时写入的, 从这个寄存器中读取数据会返回先前写入 DATA或 MASK_DATA(LSW, MSW) 的值,但不会返回设备引脚上的当前值。
MASK_DATA_LSW:位操作寄存器,对期望的输出值进行更有选择性的更改。 该寄存器控制 Bank 的低 16bit ,最多可写入 16 位的任意组合,没有写入的位不会改变,并保持原来的值。读取数据会返回先前写入 DATA 或 MASK_DATA (LSW,MSW)的值, 但不会返回设备引脚上的当前值。
MASK_DATA_MSW:位操作寄存器,这个寄存器与 MASK_DATA_LSW 相同,不同的是它控制 Bank 的高 16 位。写入 GPIO 高 16bit ,其他没有改变的位置保存原先的状态。
DIRM:方 向 控 制 ,控 制 引 脚 是输入还是输出 。 当DIRM[x]==0 时候, 输出驱动被禁用。
OEN:输出使能,当 I/O 被配置为输出时,它控制输出是否被启用。当输出被禁用, PIN 脚处于三态。当 OEN[x]==0 时, 输出关闭。
因此,如果要读 IO 状态就得读 DATA_RO 的值,如果是对某一位进行操作就是MASK_DATA_LSW、MASK_DATA_MSW。
注意:如果 MIO TRI_ENABLE 设置为 1,启用三态并禁用驱动程序,那么OEN 将被忽略,输出为三态。
四、工程设计
hdf 文件为硬件资源描述文件,可以通过生成比特流(PL,PS)或生成模块设计(PS)产生。
实验目的:
实现功能:按下 PS 端的按键(S1), PL 端的小灯(D0)亮起,松开按键则小灯熄灭;按下PL 端的按键(S2), PS 端的小灯(D2)亮起,松开 PL 端的按键则 PL 端的小灯熄灭。
1、硬件逻辑系统设计
创建工程:Vivado创建工程
1.1 创建模块设计
点击“Create Block Design”创建一个模块设计,在弹出的窗口中对设计命名。按自己的习惯命名,但是不能使用中文以及空格命名。点击 OK 完成创建。
1.2 构建硬件系统
1.2.1 添加IP核
(1)点击“+”为设计添加 IP 核。
(2)在弹出的搜索栏中输入 zynq,可以看到下方出现了“ZYNQ7 Processing
System”,双击该IP核添加。
1.2.2 配置IP核(使能外设和配置 DDR型号)
(1)双击 zynq IP 核即可打开配置界面
- Zynq Block Design: 图形化向导界面,可以快速知道各部分功能使用情况,并能迅速跳转到对应项设置。
- PS-PL Configuration: PS-PL 接口配置界面,可以对 AXI, HP,DMA 等总线接口进行配置。
- Peripheral I/O Pins: I/O 外设引脚配置界面,可对 I/O 外设引脚进行MIO 以及 EMIO 的配置,配置时需要注意 Bank 电平。
- MIO Configuration: MIO 配置界面,相较于 I/O 外设引脚配置界面,功能更为复杂。
- Clock Configuration: 时钟配置界面,页面用来配置 PS 输入时钟、外设时钟,以及 DDR 和 CPU 时钟等。
- DDR Configuration: DDR 配置界面,控制 DDR 型号以及细节参数等。
- SMC Timing Calculation: SMC 时序计算界面,可进行 SMC 时序计算 。
- Interrupts: 中断控制界面,可对 PS 与 PL 间的中断进行配置。
(2)使能外设
(3)设置完成后,切换到Zynq Block Design可以看到GPIO后面打上了√。
(4)配置DDR(双速率同步动态随机存储器,Double Data Rate Synchronous Dynamic Random Access Memory)型号。基于 PS 端的应用,大部分都需要基于片外存储外设 DDR 上运行。
配置完 DDR 后即完成了本次 zynq IP 核的配置,点击 OK,多了一个 GPIO_0 端口。
1.2.3 导出引脚
(1)点击上方的蓝色小字“Run Block Automation”,其余部分保持默认,点击 OK
(2)导出完成后可以看到软件帮我们导出了 zynq 的两个引脚,但是 GPIO_0 还未导出,因此我们需要将其手动导出。
(3)首先点击 GPIO_0 引脚,然后右键点击 Make External 导出引脚。也可以选中 GPIO_0 引脚后用软件给出的 Ctrl+T 快捷键来导出引脚。
(4)对于需要导出全部引脚的 IP 核而言,在导出时,我们也可以先点击选中 IP核,然后右键点击 Make External 或者通过快捷键 Ctrl+T 一次性导出所有引脚。导出的引脚信号也支持重命名,只需点击信号名,然后在左侧的“ExternalInterface Propetirs”栏内的“Name”修改。
1.2.4 端口连接
- FCLK_RESET0_N:全局复位信号,低电平有效。
- M_AXI_GPIO:通用 AXI 接口信号, M 代表其作为主机信号。
- M_AXI_GPIO_ACLK: M_AXI_GPIO 的输入时钟信号。
- FCLK_CLK0: PS 输出时钟信号。
(1)将 FCLK_CLK0和 M_AXI_GPIO_ACLK 连接。选中其中一个引脚按住鼠标左键拖动到对应的引脚。
(2)在涉及到的模块较多的场合,系统会出现自动连接(Run ConnectionAutomation)的选项。点击该项并设置需要连接的模块后,软件便会自动生成 AXI 互联 IP 核(AXI Interconnect)和处理器系统复位 IP 核(Processor System Reset),并自动连接 AXI 信号,部分时钟信号和复位信号。但是软件在连接时,有时会将信号连接到用户期望之外的端口上。因此,对于连线复杂的设计通常需要手动对部分端口信号进行连接。
1.2.5 验证设计
(1)保存(Ctrl+S),点击上方的√对设计进行验证。
(2)设计无误。
1.3 生成封装
(1)点击 sources 资源栏下我们创建的 system 模块设计,单击右键,在展开的功
能中选择“Generate Output Products...”生成输出。
(2)接下来软件会弹出生成输出前的设置界面,如图 2-42 所示。在合成选项栏直接选择“Out Of context per IP”即可,下方的“Number of jobs”选项选择最大值。 该值会影响生成输出时的速度, 该值越大,生成输出的速度就越快, 最大值与电脑配置有关, 设置完成后点击“Generate”开始生成。
(3)点击 sources 资源栏下我们创建的 system 模块设计,单击右键,在展开的功能中选择“Create HDL Wrapper...”创建 HDL 封装。
在弹出的窗口中选择让 vivado 管理封装和自动更新,随后点击 OK 开始创建封装。
(4)工程资源栏的右上角出现 updating 的字样表明封装正在创建和更新中,当字样消失且 Sources 栏出现蓝色名为 system_wrapper的设计文件时,则代表封装已经创建和更新完成。
1.4 管脚约束
(1)点击左侧导航栏的“Open Elaborated Design”进行约束和分配。接下来软件会有个弹窗提醒,将鼠标放置在英文提示上便会出现中文翻译,这里直接点击 OK 进行下一步即可。
(2)打开后管脚约束界面。如果软件没有正确显示该界面,可以将右上角的下拉栏展开,打开 I/O Planning 皆可切换到该页面。
(3)完成分配后使用快捷键 Ctrl+S 对约束文件进行保存,此时软件会弹出弹窗
让用户进行命名,将光标停在英文上即可出现对应翻译。在下方 File name 中对
文件进行命名,这里读者可自行命名,只要符合命名规范即可。
1.5 生成比特流
软件右上角显示。
1.6 导出硬件
(1)首先点击 File,然后在展开的功能栏中选择 Export,最后在 Export 的多个选择项中选择“ExportHardware...”将硬件描述文件导出。
(2)勾选比特流后点击 OK 开始导出。
硬件导出完成。
1.7 启动SDK
点击 File,在展开的功能栏中选择“Launch SDK”。接下来软件会弹出弹窗让我们设置硬件描述文件和工作空间的路径,这里我们保持默认即可,点击 OK 运行 SDK。
2、CPU软件程序设计
工程路径发生改变时,system_wrapper_hw_platform_0会变成system_wrapper_hw_platform_1,解决办法如下:
【例程使用】ZYNQ开发板嵌入式ARM裸机例程使用指南 - 裸机编程相关问题 - 芯路恒电子技术论坛 - Powered by Discuz! (corecourse.cn)
2.1 创建SDK工程
点击软件左上方的 File,在展开的功能栏中依次选择 New/Application Project。选择 Empty Application。
2.2 添加应用库
(1)下载:小梅哥 ACZ7015 型 Zynq 开发板资料\盘 A_ACZ7015 开发板标准配套资料\02_设计实例\03_【裸机例程】基于 C 编程的 Zynq 裸机例程\ ACZ7015_Lib。
(2)解压,并找到下图相关的库文件。最终如下图所示。
2.3 添加头文件路径和声明
将PS_GPIO、 SCU、 src 的路径添加进工作空间。
在第6步的时候,点击“Yes”即可。
(2)最后打开COMMON.h在其中添加本次设计所使用库的头文件声明。
#include "PS_GPIO.h"
2.4 添加用户代码
2.4.1 编写main.c
(1)右键单击 src 文件夹,在弹出的功能栏中选择 New/Source File。命名为 main.c,其余部分保持默认即可。点击 Finish 完成创建。
(2)key_ctrl_led_bsp里
(3)在main.c,向其中添加以下代码:
/*
* 使用 PS_GPIO 实现了按键控制 LED 功能:
* PS 端按键按下→PL 端的灯亮起,松开熄灭
* PL 端按键按下→PS 端的灯亮起,松开熄灭
*/#include "COMMON.h"
int main(void)
{u8 State; //存放按键(MIO47)的电平状态, 0 为低电平, 1 为高电平PS_GPIO_Init(); //初始化 PS 端 MIO 和 EMIO//设置 PS_LED(MIO7)为输出并且初始为低电平PS_GPIO_SetMode(PS_LED, OUTPUT, 0);//设置 PL_LED(EMIO0)为输出并且初始为低电平PS_GPIO_SetMode(PL_LED, OUTPUT, 0);PS_GPIO_SetMode(PS_KEY, INPUT, 0); //设置 PS_KEY(MIO47)方向为输入PS_GPIO_SetMode(PL_KEY, INPUT, 0); //设置 PL_KEY(EMIO1)方向为输入while(1){//读取 PS_KEY 的电平值并存储到 State 变量里State = PS_GPIO_GetPort(PS_KEY);//将 State 变量的值取非赋予 PL_LED 来输出PS_GPIO_SetPort(PL_LED,!State);//读取 PL_KEY 的电平值并存储到 State 变量里State = PS_GPIO_GetPort(PL_KEY);//将 State 变量的值取非赋予 PS_LED 来输出PS_GPIO_SetPort(PS_LED,!State);}return 0;
}
(4)调节显示字体大小。(可做可不做)
2.4.2 添加用户宏定义
(1)COMMON.h 文件在用户宏定义下添加 GPIO 的定义。
//MIOn 对应的 GPIO 编号为 n
#define PS_LED 7 //MIO_LED 为 MIO7,对应的 GPIO 编号为 7
#define PS_KEY 47 //MIO_KEY 为 MIO47,对应的 GPIO 编号为 47
//EMIOn 对应的 GPIO 编号为 54+n,因为 MIO 总数为 54, EMIO 是从 54 开始算的
#define PL_LED (54 + 0) //EMIO_LED 为 EMIO0,对应的 GPIO 编号为 54+0=54
#define PL_KEY (54 + 1) //EMIO_KEY 为 EMIO1,对应的 GPIO 编号为 54+1=55
(2)保存,自动编译。
3、板级验证
1. ACZ7015 开发板一个
2. 电源线一根
3. Type-c 下载线一根
3.1 检查硬件连接
(1)首先打开 SDK,随后点击 Program FPGA 界面,即图 2-88 中的步骤 1;接下来点击 Select...进入到设备检测界面。
3.2 下载验证
(1)点击我们创建的 led 工程,随后点击上方菜单栏的 Run,在展开的功能选项中选择“Run Configurations...”。
(2)
实验现象:按S1,D0亮,松开熄灭。按S2,D2亮,松开熄灭。
4、板级调试
(1)启动调试程序和启动运行程序方法类似。 编译链接成功后在菜单栏依次点击【Run】 ->【Debug Configurations】。
(2)打开 Debug Configurations 配置界面后,选择之前创建好的 GDB 任务,然后点击 Debug 按钮即可开始下载程序。
点击 Yes 按钮即可进入调试界面。
(2)进入调试界面后,程序会自动运行到 main()函数的第一行停下来,等待用
户开始进行调试。