MIO控制LED
ZYNQ PS 中包含一组丰富的外设,如 USB 控制器、UART 控制器、I2C 控制器以及 GPIO 等等。
GPIO可以作为输出,也可以作为输入。
GPIO 可以通过 MIO 连接到 PS 端的引脚,也可以通过 EMIO 连接到 PL。
硬件平台
正点原子启明星开发板v2
- xc7z010clg400-1
- DDR: MT41J128M16 HA-125
简介
ZYNQ 分为 PS 和 PL 两部分,器件的引脚(Pin)资源同样也分成了两部分。
ZYNQ PS 中的外设 可以通过 MIO(Multiuse I/O,多用输入/输出)模块连接到 PS 端的引脚上,也可以通过 EMIO 连接到 PL 端的引脚。
Zynq-7000 系列芯片一般有 54 个 MIO,个别芯片如 7z007s 只有 32 个。
GPIO 的框图
GPIO 分为 4 个 Bank
- 其中 Bank0 和 Bank1 连接到 MIO
- Bank2 和 Bank3 连接到 EMIO。
除 Bank1 之外的 Bank 都具有 32bit,Bank1 只具有 22bit
32bit 的 Bank0 控制了 MIO[0~31],剩下的 MIO[31~53]就由 22bit 的 Bank1 控制
Bank2 和 Bank3 用于控制扩展的 MIO ,即 EMIO
PS 所有的外设都可以通过 MIO 访问,这些外设也是与 MIO 进行连接
每个 MIO 虽然可以独立控制, 以及独立驱动单个引脚的外设,但对于 QSPI、USB、以太网等这些外设,其于 MIO 的连接有着特殊的要求
设计 PS 的外设时要合理分配 MIO
MIO 一但选定,引脚位置就已经确定下来了,不需要添加引脚约束
MIO 的 PS 外设的大多数 I/O 信号(USB 除外)可以通过 MIO 路由到 PS 引脚,或通过 EMIO 路由到 PL 引脚。
PS 通过 APB 总线对控制、状态寄存器的读写实现对 GPIO 的驱动
寄存器说明:
- DATA_RO 数据只读寄存器,通过该寄存器可以观察器件引脚上的值
- DATA 数据寄存器,控制GPIO信号配置为输出时要输出的值,32位时一次写入的
- DIRM 是方向模式寄存器,用于控制 I/O 引脚是用作输入还是输出。当 DIRM [x] == 0 时,输出驱动器被禁用,该引脚作为输入引脚使用。
- OEN 是使能输出寄存器。将 I/O 配置为输出时,该寄存器控制是否启用输出。禁用输出时,引脚为3态。当 OEN [x] == 0 时,输出被禁用。
配置MIO需要 : 设置方向,使能输出
MIO 信号对 PL 部分是透明的,所以对 MIO 的操作是纯 PS 的操作,且每个 GPIO 都可独立动态编程为输入、输出或中断检测
此处需要注意的是 MIO7 和 8 脚仅能作为输出 IO 使用
硬件设计
LED电路
系统框图
DDR3中存放和运行程序、UART 打印信息、MIO 驱动 LED 外设
LED引脚绑定
Ctrl+S 快捷键保存 Diagram
生成顶层 HDL
创建顶层 HDL Wrapper
生成 Bitstream 文件并导出到 SDK
实验未用到 PL 部分,所以无需生成 Bitstream 文件,只需导出到 SDK 即可。如果使用到 PL,则需要添加引脚约束以及对该系统进行综合、实现并生成 Bitstream 文件。
菜单 File->Launch SDK,如下图所示,启动 SDK 开发环境
软件设计
示例
在 SDK 中创建应用工程
帮助文档
在_bsp/system.mss中可以查看帮助文档
示例程序
GPIO相关例程
自行编写
驱动 MIO 的代码
新建源文件。首先在 gpio_mio/src 目录上右键,选择 New->Source File, 命名并保存。
/* * main.c * Created on: 2022年7月13日 */ #include "xparameters.h" //器件参数信息 #include "xstatus.h" //包含 XST_FAILURE 和 XST_SUCCESS 的宏定义 #include "xil_printf.h" //包含 print()函数 #include "xgpiops.h" //包含 PS GPIO 的函数声明 #include "sleep.h" //包含 sleep()函数 //宏定义 GPIO_DEVICE_ID #define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //连接到 MIO 的 LED #define MIOLED0 7 //连接到 MIO7 #define MIOLED1 8 //连接到 MIO8 #define MIOLED2 0 //连接到 MIO0 XGpioPs Gpio; // GPIO 设备的驱动程序实例 int main(){ int Status; XGpioPs_Config *ConfigPtr; //获取 GPIO 的 ID 和基址信息并初始化其配置,以及判断是否初始化成功 print("MIO Test! \n\r"); ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID); Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr); if (Status != XST_SUCCESS){ return XST_FAILURE; } //设置 GPIO 的方向(输入还是输出)函数和使能输出函数 //设置指定引脚的方向:0 输入,1 输出 XGpioPs_SetDirectionPin(&Gpio, MIOLED0, 1); XGpioPs_SetDirectionPin(&Gpio, MIOLED1, 1); XGpioPs_SetDirectionPin(&Gpio, MIOLED2, 1); //使能指定引脚输出:0 禁止输出使能,1 使能输出 XGpioPs_SetOutputEnablePin(&Gpio, MIOLED0, 1); XGpioPs_SetOutputEnablePin(&Gpio, MIOLED1, 1); XGpioPs_SetOutputEnablePin(&Gpio, MIOLED2, 1); while (1) { //向指定 GPIO 引脚写入数据 XGpioPs_WritePin(&Gpio, MIOLED0, 0x00); //向指定引脚写入数据:0 或 1 XGpioPs_WritePin(&Gpio, MIOLED1, 0x00); XGpioPs_WritePin(&Gpio, MIOLED2, 0x00); sleep(1); //延时 1 秒 XGpioPs_WritePin(&Gpio, MIOLED0, 0x01); XGpioPs_WritePin(&Gpio, MIOLED1, 0x01); XGpioPs_WritePin(&Gpio, MIOLED2, 0x01); sleep(1); } return XST_SUCCESS; }
说明
- GPIO_DEVICE_ID,使其为 XPAR_XGPIOPS_0_DEVICE_ID
- xparameters.h 文件定义了各个外设的基地址、器件 ID、中断
- 宏定义了 MIOLED0,其值为 7,因为其连接到 PS 的 MIO7 引脚。一般对于这种 MIO 的使用,驱动某一引脚,在代码中使用该引脚对应的 MIO 数字标号即可
- sleep 函数为秒延时函数,延时 m 秒就使用 sleep(m)语句。微秒延时函数 usleep(m),延时 m 微秒。
- Binaries 目录,看到有 elf 文件,说明工程已经编译通过
参考
正点原子–2_启明星ZYNQ之嵌入式SDK开发指南_V2.0