赛灵思ZYNQ官方文档UG585自学翻译笔记:General Purpose I/O (GPIO)通用输入 / 输出,LED控制亮灭,按键控制,中断控制
该文档主要围绕 Zynq-7000 AP SoC 的通用目的 I/O(GPIO)展开,内容如下:
ZYNQ GPIO 相关技术文档总结
一、GPIO 概述
(一)基本定义
GPIO(General Purpose I/O,通用输入输出)是 ZYNQ 芯片中用于实现外部设备与芯片间数据交互的重要接口。它允许软件通过编程控制引脚的输入、输出状态,以及检测中断信号,广泛应用于各类电子系统中对外部设备的控制与状态监测。
在 ZYNQ 系列芯片中,GPIO 主要分为两类:一类是集成在 PS(Processing System,处理系统)中的硬核 GPIO,另一类是通过 PL(Programmable Logic,可编程逻辑)实现的 AXI GPIO 软核。硬核 GPIO 通过 MIO(Multiplexed I/O,多路复用 IO)和 EMIO(Extended MIO,扩展 MIO)与外部连接,而 AXI GPIO 则是基于 AXI 协议在 PL 端实现的通用输入输出接口。
(二)核心功能
- 引脚控制:支持对多个引脚进行独立的输入、输出配置,满足不同外部设备的连接需求。
- 中断检测:可配置为电平敏感(高电平或低电平)或边沿敏感(上升沿、下降沿或双边沿),实现对外部事件的实时响应。
- 数据读写:通过寄存器操作实现对引脚状态的读取和输出值的设置,支持批量操作以提高效率。
- 扩展功能:当 PS 端引脚不足时,可通过 EMIO 扩展 PL 端的 IO 资源,或使用 AXI GPIO 进一步扩展接口。
二、MIO 与 EMIO
(一)MIO
- 定义:MIO 是 PS 端的多路复用 IO,将 PS 外设和静态存储器接口的访问多路复用到 PS 引脚上,可直接连接外部设备。
- 特点:
- 属于硬核资源,直接集成在 PS 中。
- Zynq-7000 系列最多支持 54 个 MIO 引脚,MPSoC 系列则根据型号不同有所差异(如部分型号支持 78 个 MIO 引脚)。
- 每个 MIO 引脚可通过配置寄存器选择不同的功能,如作为 GPIO、UART、SPI 等接口。
- 分组情况(以 Zynq-7000 为例):
- Bank0:32 位,控制 MIO 引脚 [31:0]。
- Bank1:22 位,控制 MIO 引脚 [53:32](因总共有 54 个 MIO 引脚,故 Bank1 为 22 位)。
- 应用场景:适用于直接连接外部简单设备,如 LED、按键、传感器等,无需经过 PL 端,响应速度较快。
(二)EMIO
- 定义:EMIO 是扩展的 MIO,当 PS 端的 MIO 引脚不足时,用于扩展 PL 端的 IO 资源,实现 PS 与 PL 之间的接口扩展。
- 特点:
- 属于 PS 与 PL 之间的接口,通过 PL 端的 IO 引脚实现扩展。
- Zynq-7000 系列支持 192 个 EMIO 信号(64 个输入、128 个输出),MPSoC 系列支持更多(如部分型号支持 96 个 EMIO 信号)。
- 输出不支持三态,不受 OEN(输出使能)寄存器影响,其输出使能由 DIRM(方向模式)和 OEN 寄存器共同控制,即 EMIOGPIOTN [x] = DIRM [x] & OEN [x]。
- 分组情况(以 Zynq-7000 为例):
- Bank2:32 位,控制 EMIO 信号 [31:0]。
- Bank3:32 位,控制 EMIO 信号 [63:32]。
- 应用场景:当 PS 端引脚不足以连接所有外部设备时,通过 EMIO 扩展 PL 端的 IO 资源,适用于需要较多接口的场景。
(三)MIO 与 EMIO 的区别
对比项 | GPIO(MIO 对应的硬核 GPIO) | EMIO |
---|---|---|
资源类型 | 硬核(集成在 PS 中) | PS 与 PL 的接口扩展(依赖 PL 资源) |
连接 I/O | 直接连接 PS 引脚 | 连接 PL 引脚 |
三态支持 | MIO 输出支持三态 | EMIO 输出不支持三态 |
独立性 | MIO 与 EMIO 的 I/O 无直接连接,各自独立工作 | / |
三、AXI GPIO
(一)基本概念
AXI GPIO 是 ZYNQ PL 部分的 IP 软核,通过 AXI 协议与 PS 进行通信,实现通用输入输出接口功能。它不依赖 PS 端的硬核资源,而是完全由 PL 端的逻辑资源实现。
(二)与硬核 GPIO 的区别
对比项 | 硬核 GPIO(MIO/EMIO) | AXI GPIO |
---|---|---|
资源类型 | 硬核(PS 端) | 软核(PL 端资源实现) |
连接 I/O | 可连接 PS IO(MIO)或 PL IO(EMIO) | 只能连接 PL 端 IO |
通信协议 | 通过 APB 总线控制 | 通过 AXI4-Lite 协议与 PS 通信 |
灵活性和可扩展性 | 较低(引脚数量和功能受硬件限制) | 较高(可根据需求配置通道数和位宽) |
(三)主要特性
- 支持 AXI4-Lite 接口配置,适用于低速、简单的存储器映射通信。
- 可配置为单通道或双通道模式,每个通道支持 1~32 位的数据位宽。
- 支持动态配置每个通道为输入或输出,满足不同的数据传输需求。
- 支持单独配置每个通道,可独立设置中断等功能。
- 支持产生中断请求信号,可配置为电平或边沿敏感,实现对外部事件的响应。
(四)结构框图
AXI GPIO 的结构框图主要包含以下部分(结合文档中图片描述):
- AXI 接口模块:实现与 PS 端的 AXI4-Lite 协议通信,包括地址、数据、控制信号的交互。
- 寄存器组:用于配置 GPIO 的方向、输出值、中断参数等,如 DATA(数据寄存器)、DIRM(方向寄存器)、INT_TYPE(中断类型寄存器)等。
- 输入 / 输出缓冲:用于接收外部输入信号和输出内部数据,实现与 PL 端 IO 引脚的连接。
- 中断逻辑:根据配置检测输入信号的电平或边沿变化,产生中断请求信号并发送给中断控制器。
四、GPIO 寄存器详解
(一)数据读写相关寄存器
- DATA_RO(数据读出寄存器):
- 功能:用于观测器件引脚的状态,无论 GPIO 被配置为输入还是输出,均可读取引脚的当前值。
- 特性:只读寄存器,写入操作被忽略。若引脚未配置为 GPIO,则其值不可预测。
- DATA(数据写入寄存器):
- 功能:当 GPIO 被配置为输出时,用于设置引脚的输出值。
- 特性:32 位寄存器,写入时一次性写入所有位;读取时返回之前写入的值(非引脚当前值)。
- MASK_DATA_LSW(低 16 位带屏蔽数据寄存器):
- 功能:实现对低 16 位输出值的选择性修改,未被屏蔽的位可被更新,屏蔽位保持原值。
- 特性:避免了对未修改位的读 - 改 - 写操作,提高效率;读取时返回之前写入的值。
- MASK_DATA_MSW(高 16 位带屏蔽数据寄存器):
- 功能:与 MASK_DATA_LSW 类似,用于对高 16 位输出值的选择性修改。
(二)I/O 缓冲控制寄存器
- DIRM(方向模式寄存器):
- 功能:控制 I/O 引脚的方向,即配置为输入或输出。
- 特性:每一位对应一个引脚,DIRM [x] = 1 时,引脚为输出;DIRM [x] = 0 时,引脚为输入(输出驱动禁用)。
- OEN(输出使能寄存器):
- 功能:当引脚被配置为输出时,控制输出是否使能。
- 特性:每一位对应一个引脚,OEN [x] = 1 时,输出使能;OEN [x] = 0 时,输出禁用(引脚为三态)。对于 MIO,若 TRI_ENABLE = 1,则 OEN 被忽略,输出强制为三态。
(三)中断控制寄存器
- INT_MASK(中断掩码寄存器):
- 功能:显示哪些引脚的中断被屏蔽(未启用)或未被屏蔽(已启用)。
- 特性:只读寄存器,每一位对应一个引脚,INT_MASK [x] = 1 时,中断被屏蔽;INT_MASK [x] = 0 时,中断未被屏蔽。
- INT_EN(中断使能寄存器):
- 功能:启用(解除屏蔽)指定引脚的中断。
- 特性:只写寄存器,写入 1 到某一位时,对应引脚的中断被启用;读取时返回值不可预测。
- INT_DIS(中断禁用寄存器):
- 功能:禁用(屏蔽)指定引脚的中断。
- 特性:只写寄存器,写入 1 到某一位时,对应引脚的中断被禁用;读取时返回值不可预测。
- INT_STAT(中断状态寄存器):
- 功能:显示哪些引脚发生了中断事件。
- 特性:可读可写(写 1 清除),INT_STAT [x] = 1 时,对应引脚发生中断;写入 1 到某一位时,清除该引脚的中断状态,写入 0 无效。
- INT_TYPE(中断类型寄存器):
- 功能:控制中断的敏感类型(电平敏感或边沿敏感)。
- 特性:每一位对应一个引脚,INT_TYPE [x] = 1 时,为边沿敏感;INT_TYPE [x] = 0 时,为电平敏感。
- INT_POLARITY(中断极性寄存器):
- 功能:控制中断的极性(高 / 低电平或上升 / 下降沿)。
- 特性:对于电平敏感,INT_POLARITY [x] = 1 时为高电平敏感,INT_POLARITY [x] = 0 时为低电平敏感;对于边沿敏感,INT_POLARITY [x] = 1 时为上升沿敏感,INT_POLARITY [x] = 0 时为下降沿敏感。
- INT_ANY(双边沿中断寄存器):
- 功能:当 INT_TYPE 为边沿敏感时,控制是否允许双边沿(上升沿和下降沿)触发中断。
- 特性:INT_ANY [x] = 1 时,允许双边沿触发;INT_ANY [x] = 0 时,仅允许指定的单边沿触发(由 INT_POLARITY 决定)。该寄存器在电平敏感时被忽略。
(四)寄存器地址映射
Zynq-7000 系列中,GPIO 控制和状态寄存器的存储器映射基地址为 0xE000_A000;MPSoC 系列中,基地址为 0xFF0A_0000。各寄存器在基地址上的偏移量可参考文档中的寄存器详细说明。
五、中断功能
(一)中断的基本概念
中断是指在 CPU 执行正常程序时,外部事件(如按键按下、传感器触发等)请求 CPU 暂停当前程序,转而处理该事件,处理完成后再返回原程序继续执行的机制。它能使 CPU 高效响应外部事件,无需持续轮询,提高系统效率。
(二)GPIO 中断的工作原理
结合文档中 GPIO 中断逻辑框图(如图 14-2 中中断部分),GPIO 中断的工作流程如下:
- 中断检测:中断检测逻辑持续监测 GPIO 输入信号,根据 INT_TYPE、INT_POLARITY 和 INT_ANY 寄存器的配置,判断是否发生中断事件(如上升沿、高电平等)。
- 中断状态设置:当检测到中断事件时,INT_STAT 寄存器中对应位被置 1,表示该引脚发生中断。
- 中断屏蔽判断:若该引脚的中断未被屏蔽(INT_MASK [x] = 0),则中断信号通过 OR 门合并为 IRQ #52,发送给中断控制器(GIC)。
- 中断处理:CPU 响应中断请求,执行对应的中断服务程序,处理完成后清除 INT_STAT 寄存器中的对应位(写 1 清除),并返回原程序。
(三)中断触发配置
不同的中断触发方式可通过寄存器组合配置,如下表所示(以 Zynq-7000 为例):
触发类型 | INT_TYPE | INT_POLARITY | INT_ANY |
---|---|---|---|
上升沿敏感 | 1 | 1 | 0 |
下降沿敏感 | 1 | 0 | 0 |
双边沿敏感 | 1 | X(任意) | 1 |
电平敏感(高电平) | 0 | 1 | X(任意) |
电平敏感(低电平) | 0 | 0 | X(任意) |
(四)中断配置步骤
- 配置引脚为输入:通过 DIRM 寄存器设置引脚为输入(DIRM [x] = 0)。
- 设置中断类型:通过 INT_TYPE 寄存器配置为电平或边沿敏感。
- 设置中断极性:通过 INT_POLARITY 寄存器配置中断的极性(高 / 低电平或上升 / 下降沿)。
- 配置双边沿中断(可选):若为边沿敏感且需要双边沿触发,通过 INT_ANY 寄存器设置。
- 启用中断:通过 INT_EN 寄存器启用对应引脚的中断(写入 1 到对应位)。
- 处理中断:在中断服务程序中,通过读取 INT_STAT 寄存器判断中断源,处理完成后写 1 清除 INT_STAT 中的对应位。
- 禁用中断(可选):若需关闭中断,通过 INT_DIS 寄存器禁用(写入 1 到对应位)。
六、实验设计
(一)MIO 控制 LED 灯实验
- 实验任务:使用 PS 端的 MIO 控制两个 LED 灯,实现 1 秒间隔的闪烁效果。
- 硬件设计:
- 原理图(结合文档中 LED 原理图描述):LED 的阳极通过限流电阻(如 470Ω)连接到 PS 的 MIO 引脚,阴极接地。当 MIO 引脚输出高电平时,LED 点亮;输出低电平时,LED 熄灭。
- 系统框图(以 Zynq-7000 为例):PS 通过 GPIO 模块控制 MIO 引脚,连接到 LED,同时 PS 与 DDR3 存储器连接用于程序运行,通过 UART 实现调试信息输出。
- 软件设计步骤:
- 初始化 GPIO:设置 MIO 引脚为输出(DIRM [x] = 1),并使能输出(OEN [x] = 1)。
- 循环控制 LED:在主循环中,通过 DATA 或 MASK_DATA 寄存器设置 MIO 引脚的输出值,使 LED 交替点亮和熄灭,每次切换后延时 1 秒。
- 延时函数:使用定时器或系统延时函数实现 1 秒的精确延时。
- 关键代码示例(伪代码):
c
运行
// 初始化MIO引脚10和11为输出 XGpio_Config *ConfigPtr; ConfigPtr = XGpio_LookupConfig(XPAR_AXI_GPIO_0_DEVICE_ID); XGpio_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddress); XGpio_SetDataDirection(&Gpio, 1, 0xFFFFFBFF); // 引脚10和11为输出(bit10和bit11设为1) XGpio_SetOutputEnable(&Gpio, 1, 0x00000600); // 使能输出while(1) {// 点亮LED(引脚10和11输出高电平)XGpio_DiscreteWrite(&Gpio, 1, 0x00000600);sleep(1); // 延时1秒// 熄灭LED(引脚10和11输出低电平)XGpio_DiscreteWrite(&Gpio, 1, 0x00000000);sleep(1); }
(二)MIO 按键中断实验
- 实验任务:使用 GPIO 的 MIO 中断功能,通过按键控制 LED 灯的亮灭(按键按下时切换 LED 状态)。
- 硬件设计:
- 原理图(结合文档中按键原理图描述):按键一端连接到 PS 的 MIO 引脚,另一端接地,同时引脚通过上拉电阻(如 10KΩ)连接到 3.3V。按键未按下时,引脚为高电平;按下时,引脚为低电平。LED 连接方式同前。
- 系统框图:PS 的 MIO 引脚连接按键和 LED,按键产生的中断信号通过 GPIO 模块发送到 GIC,再由 CPU 处理。
- 软件设计步骤:
- 初始化 GPIO 和中断:配置按键对应的 MIO 引脚为输入(DIRM [x] = 0),设置中断为下降沿敏感(INT_TYPE [x] = 1,INT_POLARITY [x] = 0,INT_ANY [x] = 0),启用中断(INT_EN [x] = 1)。
- 注册中断服务程序:将中断服务函数与 IRQ #52 绑定,当按键按下时触发中断服务程序。
- 中断服务程序:在程序中读取 INT_STAT 寄存器判断中断源,切换 LED 的状态(通过 DATA 寄存器修改输出值),清除中断状态(INT_STAT [x] = 1)。
- 关键代码示例(伪代码):
c
运行
// 初始化中断 XScuGic_Config *GicConfig; GicConfig = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID); XScuGic_CfgInitialize(&Gic, GicConfig, GicConfig->CpuBaseAddress); Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &Gic); Xil_ExceptionEnable();// 配置按键中断(引脚12) XGpio_SetDataDirection(&Gpio, 1, 0xFFFFF0FF); // 引脚12为输入 XGpio_InterruptEnable(&Gpio, 0x00000800); // 启用引脚12中断 XGpio_InterruptGlobalEnable(&Gpio); XScuGic_Connect(&Gic, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, (Xil_InterruptHandler)Key_InterruptHandler, &Gpio); XScuGic_Enable(&Gic, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);// 中断服务程序 void Key_InterruptHandler(void *CallBackRef) {XGpio *GpioPtr = (XGpio *)CallBackRef;// 清除中断XGpio_InterruptClear(GpioPtr, 0x00000800);// 切换LED状态led_state ^= 0x00000600;XGpio_DiscreteWrite(GpioPtr, 1, led_state); }
(三)EMIO 按键控制 LED 灯实验
- 实验任务:使用两个按键分别控制 PS 端的两个 LED 灯,其中一个按键通过 EMIO 扩展(连接到 PL 端 IO)。
- 硬件设计:
- 原理图:一个按键连接到 PS 的 MIO 引脚(直接控制),另一个按键连接到 PL 的 IO 引脚(通过 EMIO 扩展),LED 连接到 PS 的 MIO 引脚。
- 系统框图(以 Zynq-7000 为例):PS 通过 EMIO 接口连接 PL 端的按键,PS 的 MIO 引脚连接另一个按键和 LED,PS 与 PL 之间通过 EMIO 实现通信。
- 软件设计步骤:
- 初始化 MIO 和 EMIO:配置 MIO 按键引脚为输入,EMIO 按键引脚为输入(DIRM [x] = 0),LED 引脚为输出(DIRM [x] = 1,OEN [x] = 1)。
- 轮询按键状态:在主循环中,通过 DATA_RO 寄存器读取 MIO 和 EMIO 按键的状态(低电平表示按下)。
- 控制 LED:根据按键状态控制 LED 的亮灭(如 MIO 按键按下时点亮 LED1,EMIO 按键按下时点亮 LED2)。
- 关键代码示例(伪代码):
c
运行
// 初始化EMIO引脚(Bank2,引脚0)为输入 XGpio_SetDataDirection(&Gpio, 2, 0xFFFFFFFE); // EMIO引脚0为输入while(1) {// 读取MIO按键(引脚10)状态mio_key = XGpio_DiscreteRead(&Gpio, 1) & 0x00000400;// 读取EMIO按键(Bank2,引脚0)状态emio_key = XGpio_DiscreteRead(&Gpio, 2) & 0x00000001;// 控制LEDif (mio_key == 0) { // MIO按键按下XGpio_DiscreteWrite(&Gpio, 1, 0x00000400); // 点亮LED1} else {XGpio_DiscreteWrite(&Gpio, 1, 0x00000000); // 熄灭LED1}if (emio_key == 0) { // EMIO按键按下XGpio_DiscreteWrite(&Gpio, 1, 0x00000800); // 点亮LED2} else {XGpio_DiscreteWrite(&Gpio, 1, 0x00000000); // 熄灭LED2} }
(四)AXI GPIO 按键控制 LED 实验
- 实验任务:通过调用 AXI GPIO IP 核,使用中断机制实现 PL 端按键控制 PS 端 LED 灯的亮灭。
- 硬件设计:
- 系统框图(以 Zynq-7000 为例):PS 通过 AXI4-Lite 总线连接 AXI GPIO IP 核,AXI GPIO 连接 PL 端的按键和 LED,中断信号从 AXI GPIO 发送到 GIC。
- IP 核配置:AXI GPIO 配置为双通道,通道 1 连接按键(输入),通道 2 连接 LED(输出),启用通道 1 的中断功能。
- 软件设计步骤:
- 初始化 AXI GPIO:配置通道 1 为输入(按键),通道 2 为输出(LED),设置通道 1 的中断为下降沿敏感。
- 配置中断:将 AXI GPIO 的中断信号连接到 GIC,注册中断服务程序,启用中断。
- 中断服务程序:当按键按下时,中断触发,程序中读取按键状态,控制 LED 的亮灭(如切换状态),清除中断标志。
- 关键代码示例(伪代码):
c
运行
// 初始化AXI GPIO XAxiGpio_Config *AxiGpioConfig; AxiGpioConfig = XAxiGpio_LookupConfig(XPAR_AXI_GPIO_0_DEVICE_ID); XAxiGpio_CfgInitialize(&AxiGpio, AxiGpioConfig, AxiGpioConfig->BaseAddress); XAxiGpio_SetDataDirection(&AxiGpio, 1, 0xFFFFFFFF); // 通道1为输入(按键) XAxiGpio_SetDataDirection(&AxiGpio, 2, 0x00000000); // 通道2为输出(LED)// 配置中断 XAxiGpio_InterruptEnable(&AxiGpio, XAXIGPIO_IRQ_ALL_MASK); XAxiGpio_InterruptGlobalEnable(&AxiGpio); XScuGic_Connect(&Gic, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, (Xil_InterruptHandler)AxiGpio_InterruptHandler, &AxiGpio); XScuGic_Enable(&Gic, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);// 中断服务程序 void AxiGpio_InterruptHandler(void *CallBackRef) {XAxiGpio *AxiGpioPtr = (XAxiGpio *)CallBackRef;// 清除中断XAxiGpio_InterruptClear(AxiGpioPtr, XAXIGPIO_IRQ_ALL_MASK);// 切换LED状态led_state ^= 0x00000001;XAxiGpio_DiscreteWrite(AxiGpioPtr, 2, led_state); }
七、系统功能与接口
(一)时钟
- 时钟源:GPIO 控制器由 APB 接口的 CPU_1x 时钟驱动,所有输出和输入采样均使用该时钟。
- 时钟管理:为实现电源管理,可通过 slcr.APER_CLK_CTRL 寄存器中的 GPIO_CPU_1XCLKACT 位对 GPIO 控制器时钟进行门控(开启或关闭时钟)。
(二)复位
GPIO 控制器由 slcr.GPIO_RST_CTRL 寄存器中的 GPIO_CPU1X_RST 位控制复位,该复位仅影响总线接口,不影响控制器内部逻辑。复位后,寄存器恢复默认值,需重新配置。
(三)AXI 接口
- AXI 协议:AXI(Advanced Extensible Interface)是 ARM 公司 AMBA 总线协议的一部分,ZYNQ 中支持 AXI4、AXI4-Lite 和 AXI4-Stream 三种类型:
- AXI4:高性能接口,适用于高带宽存储器映射通信,支持最多 256 个数据传输。
- AXI4-Lite:轻量级接口,用于简单的存储器映射通信,占用 PL 资源少,AXI GPIO 即使用该协议。
- AXI4-Stream:无地址的流数据传输接口,适用于高速数据传输(如视频、图像)。
- Zynq-7000 的 AXI 接口:包括 M_AXI_GP0/1(PS 作为主机连接 PL)、S_AXI_GP0/1(PL 作为主机连接 PS)、S_AXI_ACP(加速器一致性端口)、S_AXI_HP0~3(高性能端口)等。
- MPSoC 的 AXI 接口:在 Zynq-7000 基础上扩展,如 S_AXI_HP [0:3]_FPD、S_AXI_LPD、S_AXI_ACE_FPD 等,支持更高的数据宽度和一致性功能。
(四)MIO 编程注意事项
- 引脚配置:通过 slcr.MIO_PIN_xx 寄存器配置 MIO 引脚的功能,包括选择 GPIO 模块(通过 L0_SEL、L1_SEL 等字段)、设置 I/O 类型(IO_Type)、上拉(PULLUP)、接收器禁用(DisableRcvr)、速度(Speed)等参数。
- 三态控制:TRI_ENABLE 字段需设置为 0,使 GPIO 能控制 I/O 的三态模式;若 TRI_ENABLE = 1,则输出强制为三态,不受 GPIO 的 OEN 寄存器控制。
- 电压设置:根据外部设备需求,通过寄存器设置 MIO 引脚的电压模式(如 LVCMOS18、LVCMOS33 等)。
八、总结与扩展
(一)总结
本文档详细介绍了 ZYNQ 系列芯片中 GPIO 的相关知识,包括 MIO 与 EMIO 的区别、AXI GPIO 的特性、寄存器功能、中断机制以及多个实验设计。通过这些内容,可掌握 GPIO 的基本原理和应用方法,实现对外部设备的控制与监测。
(二)扩展应用
- 多设备控制:结合 GPIO 的批量操作功能,可同时控制多个 LED、传感器等设备,实现复杂的系统功能。
- 中断嵌套:在实际应用中,可配置多个中断源,通过优先级管理实现中断嵌套,确保高优先级事件优先处理。
- 低功耗设计:利用时钟门控和复位功能,在不需要 GPIO 工作时关闭时钟或复位控制器,降低系统功耗。
- 与其他接口结合:将 GPIO 与 UART、SPI 等接口结合,实现更复杂的数据传输和控制功能,如通过按键配置 UART 的波特率等。
通过深入理解和灵活运用 GPIO 相关技术,可为各类电子系统设计提供坚实的基础,满足不同场景的应用需求。
详细总结
1. GPIO 概述
- 基本功能:提供软件对设备引脚和 PS 与 PL 间信号的观察与控制,支持动态编程为输入、输出或中断感应,可通过单指令读写同一组内的 GPIO 值。
- 寄存器组:共 4 个,分别为 Bank0、Bank1、Bank2、Bank3,控制不同的 MIO 和 EMIO 信号。
- 基地址:控制和状态寄存器 memory 映射在 0xE000_A000。
2. 组成与信号
- MIO:包含 54 个 GPIO 信号,通过 MIO 多路复用器路由,输出具备三态能力。
- EMIO:提供 PS 与 PL 间的 192 个 GPIO 信号,其中 64 个为输入,128 个为输出(64 个真实输出和 64 个输出使能)。
- 寄存器组划分:
- Bank0:32 位,控制 MIO 引脚 [31:0]
- Bank1:22 位,控制 MIO 引脚 [53:32](因 MIO 共 54 个引脚,故 Bank1 仅 22 位)
- Bank2:32 位,控制 EMIO 信号 [31:0]
- Bank3:32 位,控制 EMIO 信号 [63:32]
3. 功能描述
- 设备引脚控制(Bank0、Bank1)
- 关键寄存器:
- DATA_RO:用于观察设备引脚值,写入无效;若引脚未配置为 GPIO,其值不可预测。
- DATA:控制输出值,32 位同时写入,读取返回之前写入值(非引脚当前值)。
- MASK_DATA_LSW/MSW:实现选择性修改输出值,分别控制组内低 16 位和高 16 位,避免对未修改位的读 - 改 - 写操作。
- DIRM:控制 I/O 方向,DIRM [x]==0 时输出驱动禁用(为输入)。
- OEN:控制输出使能,OEN [x]==0 时输出驱动禁用(引脚三态);若 MIO 的 TRI_ENABLE 设为 1,OEN 被忽略,输出强制三态。
- 输出同步:需同时切换的多个 GPIO 需来自同一 16 位半组,以通过 MASK_DATA 寄存器单指令写入。
- 关键寄存器:
- EMIO 信号(Bank2、Bank3)
- 寄存器接口与 MIO 组相同,但存在差异:输入为来自 PL 的线,与输出值和 OEN 无关,DIRM 设为 0 时可通过 DATA_RO 读取;输出无三态能力,不受 OEN 影响,DIRM 需设为 1,值通过 DATA 等寄存器编程;输出使能线为 PS 输出,EMIOGPIOTN [x] = DIRM [x] & OEN [x]。
- EMIO 与 MIO 的 I/O 无连接,各组独立。
- Bank0 特殊引脚:Bank0 的 [8:7] 位为输出,对应控制 I/O 缓冲电压模式的引脚,复位时输出驱动禁用,系统启动读取电压模式后可作为通用输出,不可作为通用输入。
- 中断功能
- 触发方式:支持电平敏感(高 / 低)或边沿敏感(上升、下降、双边沿),由 INT_TYPE、INT_POLARITY 和 INT_ANY 寄存器编程。
- 中断处理:检测到中断后 INT_STAT 置位,若未被屏蔽(INT_MASK=0),则通过 OR 函数合并为 IRQ #52 到中断控制器;中断屏蔽由 INT_EN(写 1 禁用屏蔽)和 INT_DIS(写 1 启用屏蔽)控制;边沿敏感中断的 INT 状态可通过写 1 到 INT_STAT 清除,电平敏感中断需清除源或屏蔽输入。
- 关键寄存器:
- INT_MASK:只读,显示哪些位被屏蔽 / 启用。
- INT_EN/INT_DIS:写 1 分别启用 / 禁用中断屏蔽,读取值不可预测。
- INT_STAT:显示中断事件是否发生,写 1 清除对应位状态,写 0 无效。
- INT_TYPE/INT_POLARITY/INT_ANY:分别控制中断类型、极性和是否双边沿触发(仅边沿敏感时有效)。
- 中断触发设置表:
触发类型 | gpio.INT_TYPE_0 | gpio.INT_POLARITY_0 | gpio.INT_ANY_0 |
---|---|---|---|
上升沿敏感 | 1 | 1 | 0 |
下降沿敏感 | 1 | 0 | 0 |
双边沿敏感 | 1 | X | 1 |
电平敏感(高有效) | 0 | 1 | X |
电平敏感(低有效) | 0 | 0 | X |
4. 编程指南
- 启动序列:包括复位(见 14.4.2)、时钟(见 14.4.1)、GPIO 引脚配置、写入输出数据、读取输入数据、设置唤醒事件等步骤。
- GPIO 引脚配置:可单独配置每个引脚为输入或输出,Bank0 [8:7] 必须为输出。
- 示例:配置 MIO 引脚 10 为输出,需写 0x0000_0400 到 gpio.DIRM_0(设方向)和 gpio.OEN_0(设输出使能);配置为输入,写 0x0 到 gpio.DIRM_0。
- 写入输出数据:
- 方法 1:通过 DATA 寄存器,先读当前值,修改目标位后写回。
- 方法 2:通过 MASK_DATA_x_MSW/LSW 寄存器,直接设置掩码和数据值进行选择性修改。
- 读取输入数据:
- 方法 1:使用各 bank 的 DATA_RO_x 寄存器。
- 方法 2:利用中断逻辑,配置触发方式并使能中断,通过 INT_STAT 查看状态。
- GPIO 作为唤醒事件:需正确设置 GIC,启用对应 GPIO 引脚中断,且不关闭相关时钟。
5. 系统功能
- 时钟:由 APB 接口的 CPU_1x 时钟驱动,可通过 slcr.APER_CLK_CTRL [GPIO_CPU_1XCLKACT] 进行时钟门控以管理功耗。
- 复位:由 slcr.GPIO_RST_CTRL [GPIO_CPU1X_RST] 位控制,仅影响总线接口,不影响控制器逻辑本身。
- 中断:所有 GPIO 中断路由到 IRQ #52 至 GIC。
6. I/O 接口
- MIO 编程:Bank0 和 Bank1 引脚通过 MIO 模块路由到设备引脚,需通过 slcr.MIO_PIN_xx 寄存器配置,包括选择 GPIO 模块、设置 TRI_ENABLE(0 时由 GPIO 的 OEN 控制三态,1 时强制三态)、I/O 类型等参数。
- 示例:配置 MIO 引脚 6 为 GPIO,需设置选择字段为 0、TRI_ENABLE=0、指定电压模式等。
关键问题
问题:Zynq-7000 的 GPIO 分为哪几个寄存器组,各自控制哪些信号?
答案:分为 4 个寄存器组。Bank0 为 32 位,控制 MIO 引脚 [31:0];Bank1 为 22 位,控制 MIO 引脚 [53:32];Bank2 为 32 位,控制 EMIO 信号 [31:0];Bank3 为 32 位,控制 EMIO 信号 [63:32]。问题:GPIO 的中断功能支持哪些触发方式,如何通过寄存器配置上升沿敏感中断?
答案:支持电平敏感(高或低)和边沿敏感(上升、下降、双边沿)。配置上升沿敏感中断需:写 1 到 gpio.INT_TYPE_0 对应位,写 1 到 gpio.INT_POLARITY_0 对应位,写 0 到 gpio.INT_ANY_0 对应位,再通过 gpio.INT_EN 寄存器启用中断。问题:在 GPIO 中,写入输出数据有哪些方法,各有什么特点?
答案:有两种方法。方法 1:使用 DATA 寄存器,需先读取当前值、修改目标位再写回,适用于需整体更新输出值的场景,但操作相对繁琐;方法 2:使用 MASK_DATA_x_MSW/LSW 寄存器,可直接设置掩码和数据值进行选择性修改,避免对未修改位的读 - 改 - 写操作,更高效。
文档中未直接提供可直接运行的完整代码,主要以伪代码形式展示了不同实验的软件设计思路。以下是根据文档内容提炼的核心代码逻辑框架,涵盖 MIO 控制 LED、MIO 按键中断、EMIO 按键控制 LED、AXI GPIO 按键控制 LED 等实验,可根据实际开发环境(如 Xilinx SDK)进行调整和完善:
一、MIO 控制 LED 灯实验代码框架
功能:通过 PS 端 MIO 引脚控制 LED 灯 1 秒间隔闪烁
c
运行
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_printf.h"
#include "sleep.h"// 设备ID和引脚定义(根据实际硬件修改)
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define MIO_LED0 10 // 连接LED0的MIO引脚
#define MIO_LED1 11 // 连接LED1的MIO引脚XGpioPs Gpio; // GPIO驱动实例int main(void) {XGpioPs_Config *ConfigPtr;int Status;// 初始化GPIO配置ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);if (NULL == ConfigPtr) {return XST_FAILURE;}Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);if (Status != XST_SUCCESS) {return XST_FAILURE;}// 配置LED引脚为输出XGpioPs_SetDirectionPin(&Gpio, MIO_LED0, 1); // 1=输出,0=输入XGpioPs_SetDirectionPin(&Gpio, MIO_LED1, 1);XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED0, 1); // 使能输出XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED1, 1);// 循环控制LED闪烁while (1) {// 点亮LEDXGpioPs_WritePin(&Gpio, MIO_LED0, 1); // 1=高电平(点亮)XGpioPs_WritePin(&Gpio, MIO_LED1, 1);sleep(1); // 延时1秒// 熄灭LEDXGpioPs_WritePin(&Gpio, MIO_LED0, 0); // 0=低电平(熄灭)XGpioPs_WritePin(&Gpio, MIO_LED1, 0);sleep(1);}return XST_SUCCESS;
}
二、MIO 按键中断实验代码框架
功能:通过 MIO 按键中断控制 LED 灯亮灭(按键按下切换状态)
c
运行
#include "xparameters.h"
#include "xgpiops.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xil_printf.h"// 设备ID和引脚定义
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define MIO_KEY 12 // 连接按键的MIO引脚
#define MIO_LED 13 // 连接LED的MIO引脚
#define GPIO_INT_IRQ_ID XPAR_XGPIOPS_0_INTRXGpioPs Gpio; // GPIO实例
XScuGic Intc; // 中断控制器实例
volatile u32 led_state = 0; // LED状态(0=灭,1=亮)// 中断服务函数
void GpioIntrHandler(void *CallBackRef) {XGpioPs *GpioInstancePtr = (XGpioPs *)CallBackRef;// 清除中断标志XGpioPs_IntrClearPin(GpioInstancePtr, MIO_KEY);// 切换LED状态led_state ^= 1; // 0→1,1→0XGpioPs_WritePin(GpioInstancePtr, MIO_LED, led_state);
}// 中断初始化
int IntcInitFunction(u16 DeviceId, XGpioPs *GpioInstancePtr) {XScuGic_Config *IntcConfig;int Status;IntcConfig = XScuGic_LookupConfig(DeviceId);Status = XScuGic_CfgInitialize(&Intc, IntcConfig, IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return Status;}// 注册中断处理函数XScuGic_Connect(&Intc, GPIO_INT_IRQ_ID,(Xil_ExceptionHandler)GpioIntrHandler,(void *)GpioInstancePtr);// 配置按键引脚为输入,并启用中断XGpioPs_SetDirectionPin(GpioInstancePtr, MIO_KEY, 0); // 0=输入XGpioPs_SetIntrTypePin(GpioInstancePtr, MIO_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING); // 下降沿触发XGpioPs_IntrEnablePin(GpioInstancePtr, MIO_KEY);// 启用中断控制器XScuGic_Enable(&Intc, GPIO_INT_IRQ_ID);// 初始化异常处理Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,&Intc);Xil_ExceptionEnable();return XST_SUCCESS;
}int main(void) {XGpioPs_Config *ConfigPtr;int Status;// 初始化GPIOConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);if (Status != XST_SUCCESS) {return XST_FAILURE;}// 配置LED引脚为输出XGpioPs_SetDirectionPin(&Gpio, MIO_LED, 1);XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED, 1);XGpioPs_WritePin(&Gpio, MIO_LED, 0); // 初始熄灭// 初始化中断Status = IntcInitFunction(INTC_DEVICE_ID, &Gpio);if (Status != XST_SUCCESS) {return XST_FAILURE;}while (1); // 等待中断return XST_SUCCESS;
}
三、EMIO 按键控制 LED 灯实验代码框架
功能:通过 MIO 按键和 EMIO 扩展的 PL 按键分别控制两个 LED 灯
c
运行
#include "xparameters.h"
#include "xgpiops.h"
#include "xil_printf.h"
#include "sleep.h"// 设备ID和引脚定义
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define MIO_KEY 14 // MIO按键引脚
#define EMIO_KEY 54 // EMIO按键引脚(MIO共54个,EMIO从54开始)
#define MIO_LED0 15 // MIO控制的LED引脚
#define MIO_LED1 16 // EMIO控制的LED引脚XGpioPs Gpio;int main(void) {XGpioPs_Config *ConfigPtr;int Status;u32 mio_key_val, emio_key_val;// 初始化GPIOConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);Status = XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);if (Status != XST_SUCCESS) {return XST_FAILURE;}// 配置引脚方向:按键为输入,LED为输出XGpioPs_SetDirectionPin(&Gpio, MIO_KEY, 0); // MIO按键输入XGpioPs_SetDirectionPin(&Gpio, EMIO_KEY, 0); // EMIO按键输入XGpioPs_SetDirectionPin(&Gpio, MIO_LED0, 1); // LED0输出XGpioPs_SetDirectionPin(&Gpio, MIO_LED1, 1); // LED1输出// 使能LED输出XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED0, 1);XGpioPs_SetOutputEnablePin(&Gpio, MIO_LED1, 1);while (1) {// 读取MIO按键状态(按下为0,未按下为1)mio_key_val = XGpioPs_ReadPin(&Gpio, MIO_KEY);// 读取EMIO按键状态emio_key_val = XGpioPs_ReadPin(&Gpio, EMIO_KEY);// 控制LED0(MIO按键)if (mio_key_val == 0) { // 按键按下XGpioPs_WritePin(&Gpio, MIO_LED0, 1); // 点亮} else {XGpioPs_WritePin(&Gpio, MIO_LED0, 0); // 熄灭}// 控制LED1(EMIO按键)if (emio_key_val == 0) { // 按键按下XGpioPs_WritePin(&Gpio, MIO_LED1, 1); // 点亮} else {XGpioPs_WritePin(&Gpio, MIO_LED1, 0); // 熄灭}usleep(100000); // 延时100ms,降低CPU占用}return XST_SUCCESS;
}
四、AXI GPIO 按键控制 LED 实验代码框架
功能:通过 PL 端 AXI GPIO IP 核,实现按键中断控制 PS 端 LED
c
运行
#include "xparameters.h"
#include "xaxigpio.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xil_printf.h"// 设备ID定义
#define AXI_GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define AXI_GPIO_IRQ_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR
#define LED_CHANNEL 1 // AXI GPIO输出通道(控制LED)
#define KEY_CHANNEL 2 // AXI GPIO输入通道(连接按键)XAxiGpio AxiGpio; // AXI GPIO实例
XScuGic Intc; // 中断控制器实例
volatile u32 led_state = 0;// 中断服务函数
void AxiGpioIntrHandler(void *CallBackRef) {XAxiGpio *GpioInstancePtr = (XAxiGpio *)CallBackRef;// 清除中断XAxiGpio_InterruptClear(GpioInstancePtr, XAxiGpio_GetData(GpioInstancePtr, KEY_CHANNEL));// 切换LED状态led_state ^= 1;XAxiGpio_WriteReg(GpioInstancePtr->BaseAddr, XAXIGPIO_DATA_OFFSET + (LED_CHANNEL-1)*4, led_state);
}// 中断初始化
int IntcInitFunction(XScuGic *IntcInstancePtr, XAxiGpio *GpioInstancePtr, u16 IntcDeviceId, u16 GpioIrqId) {XScuGic_Config *IntcConfig;int Status;IntcConfig = XScuGic_LookupConfig(IntcDeviceId);Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);if (Status != XST_SUCCESS) {return Status;}// 注册中断处理函数XScuGic_Connect(IntcInstancePtr, GpioIrqId,(Xil_ExceptionHandler)AxiGpioIntrHandler,(void *)GpioInstancePtr);// 启用AXI GPIO中断XAxiGpio_InterruptEnable(GpioInstancePtr, 1 << 0); // 使能第0位中断XAxiGpio_InterruptGlobalEnable(GpioInstancePtr);// 启用中断控制器XScuGic_Enable(IntcInstancePtr, GpioIrqId);// 初始化异常处理Xil_ExceptionInit();Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler)XScuGic_InterruptHandler,IntcInstancePtr);Xil_ExceptionEnable();return XST_SUCCESS;
}int main(void) {XAxiGpio_Config *ConfigPtr;int Status;// 初始化AXI GPIOConfigPtr = XAxiGpio_LookupConfig(AXI_GPIO_DEVICE_ID);Status = XAxiGpio_CfgInitialize(&AxiGpio, ConfigPtr, ConfigPtr->BaseAddr);if (Status != XST_SUCCESS) {return XST_FAILURE;}// 配置通道:按键为输入,LED为输出XAxiGpio_SetDataDirection(&AxiGpio, KEY_CHANNEL, 0xFFFFFFFF); // 输入XAxiGpio_SetDataDirection(&AxiGpio, LED_CHANNEL, 0x00000000); // 输出// 初始化中断Status = IntcInitFunction(&Intc, &AxiGpio, INTC_DEVICE_ID, AXI_GPIO_IRQ_ID);if (Status != XST_SUCCESS) {return XST_FAILURE;}while (1); // 等待中断return XST_SUCCESS;
}
代码使用说明
- 硬件关联:代码中引脚编号(如
MIO_LED0
、EMIO_KEY
)需根据实际硬件原理图修改,确保与开发板引脚对应。 - 设备 ID:
XPAR_XXX_DEVICE_ID
需与工程中的硬件平台(.xsa 文件)定义一致,可通过 Xilinx SDK 自动生成。 - 中断配置:中断类型(边沿 / 电平触发)、中断号需根据 GPIO 引脚和 IP 核配置调整。
- 延时函数:
sleep()
(秒级)和usleep()
(微秒级)需包含对应头文件,部分环境可能需要替换为系统定时器实现。
以上代码框架覆盖了文档中所有实验的核心逻辑,实际开发时需结合具体开发环境和硬件配置进行调试。
1. 概述
- GPIO 外设通过 MIO 模块提供对多达 54 个设备引脚的观测和控制,还通过 EMIO 接口提供与可编程逻辑(PL)间的 192 个 GPIO 信号(64 个输入、128 个输出)。
- GPIO 按寄存器组分为四个 bank,控制不同范围的 MIO 和 EMIO 信号,由软件通过一系列内存映射寄存器控制。
2. 关键特性
- 54 个用于设备引脚的 GPIO 信号(通过 MIO 多路复用器路由),输出支持三态。
- 192 个 PS 与 PL 间的 EMIO GPIO 信号,包括 64 个输入和 128 个输出(64 个真实输出和 64 个输出使能)。
- 每个 GPIO 可独立动态编程为输入、输出或中断感应模式。
- 支持可编程中断,可选择电平敏感(高 / 低)或边沿敏感(上升沿、下降沿、双边沿),能读取原始和屏蔽的中断状态。
3. 框图与 bank 划分
- Bank0:32 位,控制 MIO 引脚 [31:0]。
- Bank1:22 位,控制 MIO 引脚 [53:32](因 MIO 共 54 个引脚,故 Bank1 限制为 22 位)。
- Bank2:32 位,控制 EMIO 信号 [31:0]。
- Bank3:32 位,控制 EMIO 信号 [63:32]。
4. 注意事项
- 7z007s 和 7z010 CLG225 器件的可用 MIO 引脚减至 32 个,仅特定引脚可作为 GPIO,其他 MIO 引脚未连接。
- MIO 的 Bank0 和 Bank1 通过 MIO 模块路由到设备引脚,需通过 slcr.MIO_PIN_xx 寄存器选择合适的 I/O 类型、使能 GPIO 模块等,TRI_ENABLE 应设为 0 以让 GPIO 控制三态模式。
5. 功能描述
- MIO 引脚的 GPIO 控制:软件配置 GPIO 为输入或输出,DATA_RO 寄存器始终返回 GPIO 引脚状态,DATA 寄存器控制输出值,MASK_DATA_LSW 和 MASK_DATA_MSW 寄存器支持选择性更改输出值,DIRM 控制方向,OEN 控制输出使能。
- EMIO 信号:寄存器接口与 MIO 银行相同,但 EMIO 是 PS 与 PL 间的连线,输入与输出值和 OEN 寄存器无关,输出无三态功能,输出使能线由 DIRM 和 OEN 寄存器控制。
- Bank0 的 Bits [8:7]:对应控制 I/O 缓冲区电压模式的引脚,不能作为通用输入,可作为通用输出(复位时输出驱动禁用)。
- 中断功能:中断检测逻辑监控 GPIO 输入信号,触发方式可配置,中断状态存于 INT_STAT,通过 INT_EN 和 INT_DIS 控制中断屏蔽,所有 GPIO 共享 IRQ ID#52 中断。
6. 编程指南
- 启动序列:包括复位、时钟、GPIO 引脚配置、向输出引脚写数据、从输入引脚读数据、设置 GPIO 引脚为唤醒事件。
- GPIO 引脚配置:可将引脚配置为输入或输出,Bank0 的 [8:7] 引脚必须配置为输出。
- 向输出引脚写数据:可通过 DATA 寄存器(读 - 修改 - 更新)或 MASK_DATA_x_MSW/LSW 寄存器(选择性更新)。
- 从输入引脚读数据:可使用 DATA_RO_x 寄存器或中断逻辑。
- GPIO 作为唤醒事件:需在 GIC 中启用 GPIO 中断,启用特定引脚的 GPIO 中断,且不关闭任何 GPIO 相关时钟。
7. 寄存器概览
- 数据读写相关:MASK_DATA_{3:0}{MSW,LSW}、DATA{3:0}、DATA_{3:0}_RO。
- I/O 缓冲区控制相关:DIRM_{3:0}、OEN_{3:0}。
- 中断控制相关:INT_MASK_{3:0}、INT_EN_{3:0}、INT_DIS_{3:0}、INT_STAT_{3:0}、INT_TYPE_{3:0}、INT_POLARITY_{3:0}、INT_ANY_{3:0}。
8. 系统功能
- 时钟:由 APB 接口的 CPU_1x 时钟驱动,可通过 slcr.APER_CLK_CTRL [GPIO_CPU_1XCLKACT] 进行时钟门控实现电源管理。
- 复位:由 slcr.GPIO_RST_CTRL [GPIO_CPU1X_RST] 位复位,仅影响总线接口。
- 中断:所有 GPIO 控制器产生的中断路由到 IRQ 52。
9. I/O 接口
- MIO 编程:Bank0 和 Bank1 引脚通过 MIO 路由,可通过 slcr.MIO_PIN_XX 寄存器配置为 GPIO,需正确设置相关参数。
第 14 章 通用输入 / 输出(GPIO)
14.1 简介
通用输入 / 输出(GPIO)外设通过 MIO 模块为软件提供对多达 54 个设备引脚的观测和控制功能。它还通过 EMIO 接口提供来自可编程逻辑(PL)的 64 个输入和到 PL 的 128 个输出的访问。GPIO 分为四个寄存器组,每组对相关的接口信号进行分组管理1。
每个 GPIO 可独立且动态地编程为输入、输出或中断感应模式。软件可使用单条加载指令读取一个组内的所有 GPIO 值,或使用单条存储指令向一个或多个 GPIO(在 GPIO 的一定范围内)写入数据。GPIO 控制和状态寄存器的内存映射基地址为 0xE000_A0002。
14.1.1 特性
GPIO 外设的主要特性总结如下:
- 54 个用于设备引脚的 GPIO 信号(通过 MIO 多路复用器路由)
- 输出支持三态
- 通过 EMIO 接口在 PS 和 PL 之间有 192 个 GPIO 信号
- 64 个输入、128 个输出(64 个真实输出和 64 个输出使能)
- 每个 GPIO 的功能可单独或成组动态编程
- 使能、位或组数据写入、输出使能和方向控制
- 可在单个 GPIO 基础上进行可编程中断
- 可读取原始和屏蔽中断的状态
- 可选择的灵敏度:电平敏感(高或低)或边沿敏感(上升沿、下降沿或两者皆有)3至4
14.1.2 框图
如图 14-1 所示,GPIO 模块分为四个组:
- Bank0:32 位组,控制 MIO 引脚 [31:0]
- Bank1:22 位组,控制 MIO 引脚 [53:32]
- Bank2:32 位组,控制 EMIO 信号 [31:0]
- Bank3:32 位组,控制 EMIO 信号 [63:32]
注:由于 MIO 总共有 54 个引脚,因此 Bank1 限制为 22 位。
GPIO 通过一系列内存映射寄存器由软件控制。每个组的控制方式相同,但由于 MIO 组和 EMIO 组的功能不同,两者之间存在细微差异5至6。
14.1.3 注意事项
7z007s 和 7z010 CLG225 器件
7z007s 单核和 7z010 双核 CLG225 器件将可用的 MIO 引脚减少到 32 个,如 2.5.4 节 “MIO 一览表格” 中的 MIO 表所示。因此,在这些器件中,仅 15:0、39:28、48、49、52 和 53 号 MIO 引脚可作为 GPIO 引脚使用。其他 MIO 引脚未连接,不应使用。所有 EMIO 信号均可使用7至8。
MIO 注意事项
GPIO 外设模块的 Bank0 和 Bank1 通过 MIO 模块路由到设备引脚。有关 MIO 操作的完整描述,请参阅 2.5 节 “PS-PL MIO-EMIO 信号和接口”。MIO 的主要控制通过 slcr.MIO_PIN_xx 寄存器实现。请注意以下几点:
- 用户必须根据自身系统,使用 IO_Type、PULLUP、DisableRcvr 和 Speed 字段选择合适的 I/O 类型。
- 用户必须通过多路复用器控制字段 L0_SEL、L1_SEL、L2_SEL 和 L3_SEL 选择 GPIO 模块。请注意,每个 I/O 引脚可单独选择。当 MIO 引脚用于 IOP 设备时,它不能作为 GPIO 使用。
- TRI_ENABLE 应设置为 0。这使 GPIO 能够控制 I/O 的三态模式。如果 MIO 中的 TRI_ENABLE 设置为 1,则无论 GPIO 设置如何,输出驱动器都将处于三态9至10。
14.2 功能描述
14.2.1 设备引脚的 GPIO 控制
本节描述 Bank0 和 Bank1 的操作(见图 14-2)11。
软件将 GPIO 配置为输出或输入。无论 GPIO 设置为输入(OE 信号为假)还是输出(OE 信号为真),DATA_RO 寄存器始终返回 GPIO 引脚的状态。要生成输出波形,软件需反复向一个或多个 GPIO 写入数据(通常使用 MASK_DATA 寄存器)12。
应用可能需要同时切换多个 GPIO(两个 I/O 缓冲区之间的固有偏斜时间较小)。在这种情况下,所有需要同时切换的 GPIO 必须来自同一个 16 位半组(即最高有效 16 位或最低有效 16 位)的 GPIO,以便 MASK_DATA 寄存器能在一条存储指令中向它们写入数据13。
GPIO 组控制(针对 Bank0 和 Bank1)总结如下:
- DATA_RO:该寄存器使软件能够观测设备引脚上的值。如果 GPIO 信号配置为输出,则该寄存器通常会反映输出上驱动的值。向该寄存器写入数据将被忽略。
注:如果 MIO 未配置为启用该引脚作为 GPIO 引脚,则 DATA_RO 是不可预测的,因为软件无法通过 GPIO 寄存器观测非 GPIO 引脚上的值14至15。 - DATA:当 GPIO 信号配置为输出时,该寄存器控制要输出的值。该寄存器的所有 32 位将同时写入。从该寄存器读取将返回之前写入 DATA 或 MASK_DATA_{LSW,MSW} 的值;它不会返回设备引脚上的当前值16。
- MASK_DATA_LSW:该寄存器能够更有选择性地更改所需的输出值。最多可写入 16 位的任意组合。未写入的位将保持不变,保留其先前的值。从该寄存器读取将返回之前写入 DATA 或 MASK_DATA_{LSW,MSW} 的值;它不会返回设备引脚上的当前值。该寄存器避免了对未更改的位进行读 - 修改 - 写操作的需求17。
- MASK_DATA_MSW:该寄存器与 MASK_DATA_LSW 相同,但它控制组的高 16 位18。
- DIRM(方向模式):这控制 I/O 引脚是作为输入还是输出。由于输入逻辑始终启用,这实际上是启用 / 禁用输出驱动器。当 DIRM [x]==0 时,输出驱动器禁用19。
- OEN(输出使能):当 I/O 配置为输出时,这控制输出是否启用。当输出禁用时,引脚处于三态。当 OEN [x]==0 时,输出驱动器禁用20。
注:如果 MIO TRI_ENABLE 设置为 1,启用三态并禁用驱动器,则 OEN 将被忽略,输出处于三态21。
14.2.2 EMIO 信号
本节描述 Bank2 和 Bank3 的操作(见图 14-2)22。
EMIO 组的寄存器接口与上一节中描述的 MIO 组相同。然而,EMIO 接口只是 PS 和 PL 之间的连线,因此存在一些差异:
- 输入是来自 PL 的连线,与输出值或 OEN 寄存器无关。当 DIRM 设置为 0(使其成为输入)时,可从 DATA_RO 寄存器读取它们。
- 输出连线不支持三态,因此它们不受 OEN 的影响。要输出的值使用 DATA、MASK_DATA_LSW 和 MASK_DATA_MSW 寄存器进行编程。DIRM 必须设置为 1(使其成为输出)。
- 输出使能连线只是来自 PS 的输出。它们由 DIRM/OEN 寄存器控制,如下所示:EMIOGPIOTN [x] = DIRM [x] & OEN [x]
- EMIO I/O 与 MIO I/O 没有任何连接。EMIO 输入不能连接到 MIO 输出,MIO 输入也不能连接到 EMIO 输出。每个组都是独立的,只能用作软件可观测 / 控制的信号23至24。
14.2.3 Bank0 的位 [8:7] 为输出
Bank0 的 GPIO 位 [8:7] 对应于在复位期间用于控制 I/O 缓冲区自身电压模式的封装引脚。这些引脚称为 MIO 组的 VMODE 引脚带(参见 “引导模式引脚设置” 部分,第 165 页)。它们必须由外部系统根据适当的电压模式驱动。为防止它们被其他系统逻辑驱动,它们不能用作通用输入25至26。
由于复位时输出驱动器禁用,这些位可用作通用输出。系统在系统引导期间读取电压模式后,可以开始将这些位用作输出27。
14.2.4 中断功能
中断检测逻辑监控 GPIO 输入信号。中断触发可以是上升沿、下降沿、任一沿、低电平或高电平。触发灵敏度通过 INT_TYPE、INT_POLARITY 和 INT_ANY 寄存器进行编程28。
如果检测到中断,中断检测逻辑会将 GPIO 的 INT_STAT 状态设置为真。如果 INT_STAT 状态被启用(未屏蔽),则中断会传播到一个大型 OR 函数。该函数将所有四个组中所有 GPIO 的所有中断组合为一个输出(IRQ ID#52)到中断控制器。如果中断被禁用(屏蔽),则 INT_STAT 状态会保持到被清除,但除非 INT_EN 随后被写入以禁用屏蔽,否则它不会传播到中断控制器。由于所有 GPIO 共享同一个中断,软件必须同时考虑 INT_MASK 和 INT_STAT 来确定哪个 GPIO 引起了中断29。
中断屏蔽状态通过向 INT_EN 和 INT_DIS 寄存器写入 1 来控制。向 INT_EN 寄存器写入 1 会禁用屏蔽,允许活动中断传播到中断控制器。向 INT_DIS 寄存器写入 1 会启用屏蔽。可使用 INT_MASK 寄存器读取中断屏蔽的状态30。
如果 GPIO 中断是边沿敏感的,则检测逻辑会锁存 INT 状态。通过向 INT_STAT 寄存器写入 1 来清除 INT 锁存。对于电平敏感的中断,必须清除到 GPIO 的中断输入源才能清除中断信号。或者,软件可以使用 INT_DIS 寄存器屏蔽该输入31。
可以通过读取 INT_STAT 和 INT_MASK 寄存器来推断发送到中断控制器的中断信号的状态。如果 INT_STAT=1 且 INT_MASK=0,则该中断信号被断言32。
GPIO 组控制总结如下:
- INT_MASK:该寄存器为只读,显示当前哪些位被屏蔽以及哪些位未被屏蔽 / 启用。
- INT_EN:向该寄存器的任何位写入 1 会启用 / 取消屏蔽该信号的中断。从该寄存器读取将返回不可预测的值。
- INT_DIS:向该寄存器的任何位写入 1 会屏蔽该信号的中断。从该寄存器读取将返回不可预测的值。
- INT_STAT:该寄存器显示是否发生了中断事件。向该寄存器的某位写入 1 会清除该位的中断状态。向该寄存器的某位写入 0 会被忽略。
- INT_TYPE:该寄存器控制中断是边沿敏感还是电平敏感。
- INT_POLARITY:该寄存器控制中断是低电平有效还是高电平有效(或下降沿敏感还是上升沿敏感)。
- INT_ON_ANY:如果 INT_TYPE 设置为边沿敏感,则该寄存器允许在上升沿和下降沿发生中断事件。如果 INT_TYPE 设置为电平敏感,则该寄存器被忽略33至34。
14.3 编程指南
GPIO 控制器有四个组,MIO 和 EMIO 各两个。每个 GPIO 引脚可以单独编程。如 14.2.1 节 “设备引脚的 GPIO 控制” 中所述,可通过单次写入对多个引脚进行编程35至36。
14.3.1 启动序列
主要示例:启动序列
- 复位:复位选项在 14.4.2 节 “复位” 中描述。
- 时钟:时钟在 14.4.1 节 “时钟” 中描述。
- GPIO 引脚配置:将引脚配置为输入 / 输出在 14.3.2 节 “GPIO 引脚配置” 中描述。
- 向 GPIO 输出引脚写入数据:参见 14.3.3 节 “向 GPIO 输出引脚写入数据” 中的示例。
- 从 GPIO 输入引脚读取数据:参见 14.3.4 节 “从 GPIO 输入引脚读取数据” 中的示例。
- 将 GPIO 引脚设置为唤醒事件:参见 “GPIO 作为唤醒事件” 部分中的示例37至38。
14.3.2 GPIO 引脚配置
每个单独的 GPIO 引脚可配置为输入 / 输出。但是,bank0 的 [8:7] 引脚必须配置为输出。有关更多详细信息,请参阅 14.2.3 节 “Bank0 的位 [8:7] 为输出”39至40。
示例:将 MIO 引脚 10 配置为输出
- 将方向设置为输出:向 gpio.DIRM_0 寄存器写入 0x0000_0400。
- 设置输出使能:向 gpio.OEN_0 寄存器写入 0x0000_0400。
注:输出使能仅在 GPIO 引脚配置为输出时才有意义41至42。
示例:将 MIO 引脚 10 配置为输入
- 将方向设置为输入:向 gpio.DIRM_0 寄存器写入 0x0。这将 gpio.DIRM_0 [10] 设置为 043至44。
14.3.3 向 GPIO 输出引脚写入数据
对于配置为输出的 GPIO 引脚,有两种方法可对所需值进行编程45至46。
选项 1:使用 gpio.DATA_0 寄存器读取、修改和更新 GPIO 引脚。
示例:使用 DATA_0 寄存器设置 GPIO 输出引脚 10。
- 读取 gpio.DATA_0 寄存器:将 gpio.DATA_0 寄存器读取到 reg_val 变量。
- 修改值:设置 reg_val [10]=1。
- 向输出引脚写入更新后的值:将 reg_val 写入 gpio.DATA_0 寄存器47至48。
选项 2:使用 MASK_DATA_x_MSW/LSW 寄存器更新一个或多个 GPIO 引脚。
示例:使用 MASK_DATA_0_MSW 寄存器将输出引脚 20、25 和 30 设置为 1。
- 生成引脚 20、25 和 30 的掩码值:要驱动引脚 20、25 和 30,0xBDEF 是 gpio.MASK_DATA_0_MSW [MASK_0_MSW] 的掩码值。
- 生成引脚 20、25、30 的数据值:要在引脚 20、25 和 30 上驱动 1,0x4210 是 gpio.MASK_DATA_0_MSW [DATA_0_MSW] 的数据值。
- 向 MASK_DATA_x_MSW 寄存器写入掩码和数据:向 gpio.MASK_DATA_0_MSW 寄存器写入 0xBDEF_421049至50。
14.3.4 从 GPIO 输入引脚读取数据
对于配置为输入的 GPIO 引脚,有两种方法可监控输入51至52。
选项 1:使用每个组的 gpio.DATA_RO_x 寄存器。
示例:使用 DATA_RO_0 寄存器读取 bank 0 中所有 GPIO 输入引脚的状态。
- 读取输入 Bank 0:读取 gpio.DATA_0 寄存器53至54。
选项 2:在输入引脚上使用中断逻辑(参见 14.2.4 节 “中断功能”)。
示例:将 MIO 引脚 12 配置为上升沿触发。
- 将触发设置为上升沿:向 gpio.INT_TYPE_0 [12] 写入 1。向 gpio.INT_POLARITY_0 [12] 写入 1。向 gpio.INT_ANY_0 [12] 写入 0。
- 启用中断:向 gpio.INT_EN_0 [12] 写入 1。
- 输入引脚的状态:gpio.INT_STAT_0 [12] =1 表示发生了中断事件。
- 禁用中断:向 gpio.INT_DIS_0 [12] 写入 155至56。
14.3.5 GPIO 作为唤醒事件
GPIO 可配置为唤醒设备。
重要提示:必须正确设置 GIC。
- 在 GIC 中启用 GPIO 中断。
- 使用 gpio.INT_EN_{0..3} 寄存器启用所需引脚的 GPIO 中断。向 gpio.INT_EN_0 [10] 设置 1 以启用 GPIO10 中断。
- 不要关闭任何与 GPIO 相关的时钟57至58。
14.3.6 寄存器概述
GPIO 寄存器的概述如表 14-2 所示(另请参见 14.2.1 节 “设备引脚的 GPIO 控制”)。寄存器的详细信息在附录 B “寄存器详细信息” 中提供59至60。
14.4 系统功能
本节描述控制器的时钟和复位。GPIO 控制器中生成的所有中断都路由到 IRQ 52。GPIO I/O 信号路由到 MIO 或 EMIO61至62。
14.4.1 时钟
控制器由来自 APB 接口的 CPU_1x 时钟提供时钟。所有输出和输入采样都使用 CPU_1x 时钟进行63至64。
为了进行电源管理,可以使用 slcr.APER_CLK_CTRL [GPIO_CPU_1XCLKACT] 对 GPIO 控制器时钟采用时钟门控65。
14.4.2 复位
控制器由 slcr.GPIO_RST_CTRL [GPIO_CPU1X_RST] 位复位。有关更多信息,请参阅第 26 章 “复位系统”。此复位仅影响总线接口,不影响控制器逻辑本身66至67。
14.4.3 中断
控制器中断在 14.2.4 节 “中断功能” 中说明。控制器向 GIC 断言 IRQ #52。编程示例在 14.3.4 节 “从 GPIO 输入引脚读取数据” 中描述68至69。
14.5 I/O 接口
14.5.1 MIO 编程
Bank0 和 Bank1 引脚通过 MIO 路由。这些引脚可使用 slcr.MIO_PIN_XX 寄存器配置为 GPIO70至71。
示例:将 MIO 引脚 6 配置为 GPIO 信号
- 选择 MIO 引脚作为 GPIO:设置 L0_SEL、L1_SEL、L2_SEL、L3_SEL = L3_SEL =0。
- 设置 TRI_ENABLE =0。
- LVCMOS18(有关其他电压选项,请参阅寄存器定义)。
- 慢 CMOS 边沿。
- 启用内部上拉电阻。
- 禁用 HSTL 接收器。
注:如果 TRI_ENABLE=1,则无论任何 GPIO 设置如何,输出都处于三态。如果 TRI_ENABLE =0,则三态由 gpio.OEN_x 寄存器控制72至73。