zynq gpio mio emio简介 gpio寄存器
ZYNQ由两部分组成:PS 处理器系统,PL 可编程逻辑块(直接理解成FPGA即可)
PS(处理器系统)是 SOC ZYNQ 的核心,相当于zynq芯片以PS为中心,PL(FPGA)是他的外设。
PS:以RAM为核心的SOC,PL也是SOC中的一个外设而已
PS分为以下4部分: APU:应用处理单元,
memory interface :存储器接口
IOP:I/O外设(包含很多常用的接口协议)
interconnect:内部的互连
对架构进行划分,上为PS,下为PL。
GPIO 不针对某一特殊的设备进行连接,可连接一些通用的设备(按键,蜂鸣器,led这些简单的通用的设备都可以通过GPIO来连接)。我们也可以用GPIO来模拟一些协议(IIC协议,这样就可以连接一些IIC设备,uart不行,uart有一个串并转换过程)
GPIO是一个外设最主要的功能:通过MIO观测【input】(按键按下,引脚上电平的变化,从而观测到按键的状态)和控制【output】(控制引脚上的高低电平从而控制LED的亮灭) 54个引脚(provides software with observation and control of up to 54 device pins via the MIO module)【MIO是上图GPIO左边连接的】
MIO(多路复用I/O):PS端这边除去DDR的固定引脚外只有54个引脚可用,但是外设和存储器接口所需的引脚大于54,所以需要一个多路复用来完成这个功能,即通过MIO来实现。(例如现在PS只有两个空闲的引脚,此时UART和IIC都想使用这个引脚,僧多粥少。让 UART 和 IIC 都不要直接连接到引脚上面去,让它们先连接到MIO上,再通过MIO来连接到外部的引脚上去。)【目的是:实际上UART 和 IIC 连接到MIO 是可以通过软件编程的,用户可以通过软件去控制MIO来具体给哪个外设去使用,选择哪一个外设来连接外部的引脚,达到多路复用的功能】
MIO功能:把来自PS外设和静态存储器接口的访问给多路复用到器件的引脚上面去。
EMIO:(E是扩展的意思) 可以看到I/O外设可以通过MIO连接到PS的引脚,也可以通过EMIO连接到PL,连接到FPGA模块上或者直接连接到FPGA的引脚上。
EMIO更主要的功能:可以扩展PS端的引脚。PS端54个引脚,不够,我们可以通过EMIO 把 PL端的引脚来给 PS 使用。
不是所以io外设都可以通过EMIO扩展引脚,GPIO是可以的。
每一个GPIO都是动态可编程的,每一个GPIO都可作为输入,输出,或中断,软件可以通过一个LOAD指令来读取gpio在引脚上的值,也可以通过一个独立的store指令把数据写到器件的引脚上面去(输出)。
GPIO 基地址(base address)0XE000_A000。
软件通过 一组 存储映射寄存器(memory-mapped registers)控制GPIO。
存储映射:如果一个读写操作(会话)是存储映射的,那么无论是读操作还是写操作,其都会给定一个地址,这个地址相当于是存储空间里面的地址。即我们在进行读写操作的时候都要指定一个地址来说明这个读写操作具体的寄存器的位置,这种操作方式成为存储映射。存储是指操作对象位于存储空间里,映射是在读写操作的同时要给定一个地址。
在实际编程中,我们不会独立操作寄存器,而是调用一个个函数,了解GPIO寄存器目的:首先了解各个寄存器可以大致了解各个功能模块底层驱动的原理,包括这些寄存器之间的关系。在了解底层的寄存器之后,我们的上层编写代码的时候才更有逻辑性一些(不了解这些底层的寄存器,编写过程的一些操作就会不知所以然,都不知道函数是干什么用的)。
data_ro:寄存器不管GPIO是作为输入还是作为输出,一直反映GPIO引脚上的状态。即使我们把GPIO设置成输出来使用,data_ro仍然可以反应出当前引脚的状态。 这个寄存器可以让软件去观测器件引脚上的数值。该寄存器是只读寄存器,往这里面写数据是被忽略的。GPIO作为输出时,该寄存器显示期间引脚上的输出值。【如果MIO没有被配置成GPIO的引脚,那么该寄存器没法显示,就是用的UART或其他外设连引脚,没用GPIO连】
DATA寄存器:作为输出,我们可以往这里面写数据,控制我们需要输出到器件引脚的数值。(例如器件的引脚最终连接到led,那么通过往DATA寄存器里面写1开灯,写0关灯【这是抽象成1位的寄存器,实际上是32位的寄存器,相当于我们是一次性去操作一个32位的寄存器】)。 只有当GPIO被配置成输出的时候,才可以控制输出的数值。每次操作以32位为单位,不能单独操作其中的某一位(后面讲如何独立的控制DATA寄存器中的某一位,从而控制器件上特定的某一个引脚)。 如果我们读这个寄存器,它会返回上一次写到这个寄存器里边的数值,不会返回当前器件引脚的数值【如果我们想了解当前器件引脚什么状态,我们可以通过读DATA_RO寄存器】。
MASK_DATA_LSW寄存器(MASK 屏蔽【用mask这样的数据去屏蔽某一些位】):用来屏蔽低16位。给软件更多的选择性,可以改变特定的输出值。任何16位的组合都可以被写到这个寄存器里边去,没有写的那些位不会变,会保持先前的那些值。读的话返回先前的值,不返回当前的值。 这个寄存器可以避免read_modify_write的过程对于不需要改变的值。
例如: DATA :1010_0101_1010_0101 XXXX XXXX XXXX XXXX 32位 A5A5XXXX 假设用这个数值控制16个led 亮灭亮灭——灭亮灭亮——~——~ 如果我只想改变其中4个LED的状态,其他不变。 MASK :1111_0000_1111_1111
data :0000_1010_0000_0000 只关心想改变的值,其他值都屏蔽掉了
每次需要往DATA寄存器里写入32位的寄存器,当指向改变第8到第11位4个LED状态时:
(1)先把DATA寄存器值读出来 read
(2)改变需要修改的数值 modify 1010_1010_1010_0101 XXXX XXXX XXXX XXXX
(3)把改好的数据写到DATA寄存器里 write
用MASK 寄存器就可以避免 R-M-W过程。
MASK_DATA_MSW:用来屏蔽高16位。
DIRM寄存器:DIRECTION MODE(用来控制 I/O 作为输入还是输出) DIRM[X]=0 那么关闭输出驱动,此时作为输出来使用。为1时使能输出驱动。
OEN寄存器(OUTPUT ENABLE): 与DIRM类似的地方:只有当I/O被配置为输出的时候,它才会控制输出是否打开或是关闭。把DIRM配置为1配置为输出,此时再由OEN控制是打开还是关闭输出使能。当两个寄存器同时配置为1,输出使能信号才能打开,才能正常的输出一个信号。
区别 :DIRM:配置对应的I/O是作为输入还是作为输出。
OEN: 打开或关闭输出寄存器的使能,I/O配置成输入这个就没什么作用了
bank0的MIO[8],MIO[7] 是用来配置电压模式的
MIO也是分组的 MIO 0~15分一组(bank 0),MIO 16~53分一组(bank 1) 用MIO[8]控制bank1电压为多少。MIO[7]控制bank 0 电压多少。 根据MIO bank的电压 给输入的值进行配置 0/1。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)