本文主要是介绍AXI_GPIO,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
REVIEW
关于PS端已经学习过: zynq PS端 GPIO-CSDN博客 zynq PS点灯-CSDN博客 C基础与SDK调试方法-CSDN博客 |
Zynq上GPIO无论是MIO还是EMIO,都是属于PS侧的资源,相当于是硬核。 而作为一个PS与PL相互协作的平台,当PS侧的GPIO硬核不够用或者无法使用的场合,我们能否使用PL端的逻辑资源来构建一个或多个GPIO软核呢? AXI_GPIO |
1. 今日摸鱼任务
简单学习对 AXI GPIO 核, 并以 AXI GPIO 核为基础, 完成 EDA 拓展板上拨码开关控制 LED 亮灭实验。 |
小梅哥视频: 12A_AXI_GPIO原理与应用(一)_哔哩哔哩_bilibili 12B_AXI_GPIO原理与应用(二)_哔哩哔哩_bilibili |
小梅哥课程笔记:【zynq课程笔记】【裸机】【第12课 】【AXI_GPIO原理与应用】 - ACZ702开发板 - 芯路恒电子技术论坛 - Powered by Discuz! (corecourse.cn) |
小梅哥教材: 03_【裸机教程】基于C编程的Zynq裸机程序设计与应用教程v2.4.5.pdf 第三章 基于 AXI GPIO 的 LED 亮灭 |
2. AXI 总线接口
AXI ,即 Advanced Extensible Interface(高级可扩展接口),它是由 Arm 定义的接口协议,包含在“高级微控制器总线架构 AMBA”标准中。 AXI是一种总线协议,是一种面向高性能、高带宽、低延迟的片内总线。 它的地址/控制和数据相位是分离的,支持不对齐的数据传输,同时在突发传输中,只需要首地址,同时分离的读写数据通道、并支持 Outstanding 传输访问和乱序访问,并更加容易进行时序收敛。 | |
在 ZYNQ7000 系列开发板上 AXI 协议,通常指 AXI4 协议。该协议共包含三种接口,也可以说是三种总线,分别为 AXI4 、 AXI-Lite 、 AXI-Stream ,在 ZYNQ 内部实现着 PS 与 PL 之间的交互,不同接口面向不同的应用场景,分别如下: | |
AXI4: (AXI4-Full) | 主要面向 高性能地址映射 ( memory map)通信的需求,是面向地址映射的接口,在单地址传输的情况下最大允许 256 个时钟周期的数据突发长度。 AXI4 总线允许符合 AXI4 的系统实现非常高的数据吞吐量,同时还支持数据大小调整、多个 outstanding 操作和乱序事务处理。 在硬件级别, AXI4 允许为每个 AXI 主从对使用不同的时钟构建系统。 此外, AXI4 协议允许插入寄存器片(通常称为流水线级)以帮助时序收敛。 为了与 AXI4-Lite 区分, AXI4 也被叫作 AXI4-Full 。 |
AXI4-Lite: | 用于 简单、低吞吐量的内存映射 通信 (例如,与控制寄存器和状态寄存器之间的通信) 是一个轻量级的地址映射单次传输接口,占用很少的逻辑单元。 该接口是 AXI4 接口的简化版,突发长度从 256 被限制到 1, 也就意味着无法进行突发传输,逻辑资源的减少, 也就导致无法实现较为复杂功能。 |
AXI4-Stream: | 主要面向 高速流数据传输 与 AXI4 的区别是没有了地址接口,因此不涉及读写数据的概念,数据只是进行简单的接收与发送。 这种方式减少了传输时的延时,允许无限制的数据突发传输规模。 |
虽然 ZYNQ 支持这三种总线, 但是在 ZYNQ 的 PS 与 PL 之间仅支持 AXI4 与 AXI4-Lite 总线, AXI4-Stream 总线只能在 PL 中实现。 |
3. AXI_GPIO
Xilinx官方为我们提供了一个名为AXI GPIO的软核。该核使用标准的AXI总线与PS交互,用户可以通过AXI总线,控制AXI GPIO的输入输出模式、输出值、读取指定引脚等。该IP核的结构如下: |
从图中可以看出,最右侧有两个具有三态输出功能的端口,分别为GPIO和GPIO2,这也就意味着该控制器可以最多提供2个通道的GPIO。 |
每个通道的GPIO都有3个标准的信号,也就是输出值(GPIO_O)、输入值(GPIO_I)以及管脚输出使能控制信号(GPIO_T)。 |
输出值GPIO_O : 使用一个名为GPIO_DAT的寄存器/D触发器存储所需要输出的值 |
输入值GPIO_I : 使用一个名为GPIO_DATA_IN的寄存器/D触发器存储GPIO Pin管脚上的值 |
输出使能控制信号GPIO_T : 使用一个名为GPIO_TRI的寄存器/D触发器存储设置状态 |
这两个三态缓冲器工作时,其输入输出状态受GPIO_T信号控制。 当GPIO_T=0时,为输出态,三态缓冲器会输出GPIO_O的值; 当GPIO_T=1时,为输入态,此时GPIO_I的值会输入到AXI GPIO中。 |
因此,我们只需要通过对这3个寄存器进行读写,就能够实现对该Pin的状态的控制和读取。 这些寄存器由谁读写,又是通过什么方式读写呢? 这个就是我们刚刚提到的,PS通过AXI4-Lite总线来读写这些寄存器。 |
另外该控制器还提供了中断检测逻辑,以及中断控制寄存器, 用于中断检测以及中断使能/屏蔽/状态显示。 |
4. 设计流程
本次实验框图: |
①配置设置 |
基础流程可以参照:zynq PS点灯-CSDN博客 本次只记录一些重点: |
添加IP核:ZYNQ + AXI GPIO |
本次ZYNQ只需要配置DDR: |
配置AXI_GPIO核:两通道8位: |
快进到配置引脚:使用的是xc7z010clg400-1 + EDA扩展版 |
生成.xdc .bit .hdf文件 |
②Launch SDK |
打开 COMMON.h 文件: 添加 AXI_GPIO 的头文件声明: #include "AXI_GPIO.h" 随后在用户宏定义下添加 AXI GPIO 的器件 ID 宏定义: #define GPIO_0_ID XPAR_AXI_GPIO_0_DEVICE_ID |
main.c |
#include"COMMON.h" int main(void) { uint32_t State; AXI_GPIO_Init(&AXI_GPIO0,GPIO_0_ID); //初始化 AXI GPIO0 //设置通道 1 为输入 AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH1_MASK, 0xFF, 0); //设置通道 2为输出 AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH2_MASK, 0x00, 0); while(1) { //读取通道 1 输入的值 State = XGpio_DiscreteRead(&AXI_GPIO0,XGPIO_IR_CH1_MASK); //将通道 2 设置为输出,输出从通道 1 读取的值 AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH2_MASK, 0, State); } return 0; } |
在弹幕里面学到的,字体放大: Ctrl + Shift + '+' |
此时的效果: |
拨码开关可控制对应的LED亮灭 |
5. 代码解析
AXI_GPIO_Init(XGpio *InstPtr, uint16_t DeviceId) |
/***************************************************************************** ** @brief 初始化AXI_GPIO ** @param InstPtr GPIO实例指针 ** @param DeviceId GPIO设备ID ** Sample: AXI_GPIO_Init(&AXI_GPIO0,GPIO_0_ID); //初始化AXI GPIO0 *****************************************************************************/ void AXI_GPIO_Init(XGpio *InstPtr, uint16_t DeviceId) { XGpio_Initialize(InstPtr, DeviceId); } |
AXI_GPIO_Set_Channel(XGpio *InstPtr, uint8_t Channel, uint32_t Dri, uint32_t Data) |
/***************************************************************************** ** @brief 设定AXI GPIO某通道的模式与状态 ** @param InstPtr GPIO实例指针 ** @param Channel GPIO通道,1或2 ** @param Dir 输入/输出:0为输出,1为输入,每一位表示一个引脚 ** @param Data 输出电平高低:0为低,1为高,每一位表示一个引脚 ** Sample: //设置Gpio0的通道1全为输出模式,且全输出为低电平 ** AXI_GPIO_Set_Channel(&AXI_GPIO0, XGPIO_IR_CH1_MASK, 0, 0); *****************************************************************************/ void AXI_GPIO_Set_Channel(XGpio *InstPtr, uint8_t Channel, uint32_t Dri, uint32_t Data) { XGpio_SetDataDirection(InstPtr, Channel, Dri); XGpio_DiscreteWrite(InstPtr, Channel, Data); } |
XGpio_DiscreteRead(XGpio * InstancePtr, unsigned Channel) |
/****************************************************************************/ return XGpio_ReadReg(InstancePtr->BaseAddress, |
算法流程大致相同: |
初始化GPIO驱动程序 设置指定引脚方向 读/写指定管脚的值/状态 |
不同点 |
PS GPIO在输出指定管脚的值/状态时,需要先使能该引脚作为输出。 而在硬件逻辑系统设计方面,AXI GPIO则是与EMIO类似,由于使用的是PL端引脚,在导出后还需要进行管脚分配和约束。 |
尝试控制单个Pin |
#include"COMMON.h" return 0; |
6. 小作业
配置AXI GPIO为单通道16位位宽, 通过软件编程,将高8位配置为输入,获取拨码开关电平; 将低8位设置为输出,使用从拨码开关获取的电平控制LED, 实现拨码开关控制LED亮灭设计。 |
这篇关于AXI_GPIO的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!