[X]关闭
2

S02-CH04 PS MIO 实验

摘要: 软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! 4.1 概述 本课对ZYNQ芯片的GPIO进行介绍,通过设 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

4.1 概述

        本课对ZYNQ芯片的GPIO进行介绍,通过设计PS端点亮LED的功能,讲解了PS端MIO使用方法。

4.2 GPIO简介

       Zynq7000系列芯片有54个MIO(multiuse I/O),它们分配在 GPIO 的Bank0 和Bank1隶属于PS部分,这些IO与PS直接相连。不需要添加引脚约束,MIO信号对PL部分是透明的,不可见。所以对MIO的操作可以看作是纯PS的操作。

        GPIO的控制和状态寄存器基地址为:0xE000_A000,SDK软件底层操作是对于内存地址空间的操作。

Bank0:MIO [31:0]  GPIO PIN脚号:0~31

Bank1:MIO[32:53]  GPIO PIN脚号:32~53

以上描述和我们原理图中和VIVADO  ZYNQ IP中定义的有冲突,这个留给大家去讨论,下图中,是ZYNQ IP部分MIO电压分配,从这个软件上看,BANK0 IO 是0~15,BANK1 IO是16~53,这个是奇怪的事情,笔者现在还没搞懂。实际应用以软件设定和原理图为准。

Bank2:EMIO [31 : 0] GPIO PIN脚号:54~85

Bank3:EMIO [63:32] GPIO PIN脚号:86~ 117

4.2.1 GPIO的控制寄存器地址空间

SDK软件下的底层操作是对这些寄存器的操作,具体的相关参数请参考技术手册ug585-Zynq-7000-TRM.pdf

4.2.2 MIO内部构造分析

DATA_RO: 此寄存器使能软件观察PIN脚,当GPIO被配置成输出的时候,这个寄存器的值会反应输出的PIN脚情况。

DATA:此寄存器控制输出到GPIO的值,读这个寄存器的值可以读到最后一次写入该寄存器的值。  

MASK_DATA_LSW:位操作寄存器,写入GPIO 低16bit 其他没有改变的位置保存原先的状态

MASK_DATA_MSW:位操作寄存器,写入GPIO 高16bit 其他没有改变的位置保存原先的状态

DIRM:此寄存器控制输出的开关,当DIRM[x]==0时候,禁止输出

OEN: 输出使能,当OEN[x]==0 的时候输出关闭,PIN脚处于三态

因此,如果要读IO状态就得读DATA_RO的值,如果是对某一位进行操作就是写MASK_DATA_LSW/MASK_DATA_MSW

具体的相关参数请参考技术手册ug585-Zynq-7000-TRM.pdf

4.2.3 EMIO的特性

与MIO大部分类似但是一下几点需要注意下

• EMIO在PL部分,输入与OEN寄存器无关,当DIRM设置为0的时候设置为输入可以读DATA_RO寄存器获取数据。

• 输出不能设置成三态,当DIRM设置为1的时候为输出,写入DATA寄存器或者MASK_DATA_LSW/MASK_DATA_MSW寄存器

• EMIOGPIOTN[x]=DIRM[x] & OEN[x],实现输出的控制。

具体的相关参数请参考技术手册ug585-Zynq-7000-TRM.pdf

4.3 电路分析及实验预期

        开发板上有一个MIO是与开发板上的一个LD9相连的,这个MIO就是MIO7。实验通过操作该MIO来实现LD9的闪烁。

原理图

4.4 搭建BD工程

Step1:新建一个名为为Miz_sys的工程。

Step2:创建一个BD文件,并命名为system,添加并且配置好ZYNQ IP。读者需要根据自己的硬件类型配置好输入时钟频率、内存型号、串口,连接时钟等。新手不清楚这些内容个,请参考“CH01 HelloWold/DDR/网口测试及固化”这一节课。

Step3:ZYNQ IP MIO配置

MIO部分其他功能的配置可以参考参考“CH01 HelloWold/DDR/网口测试及固化”这一节课

Step2:建立一个空的工程

Step3: 在我们提供例程的文件夹中找到main.c文件,并进行复制。

Step4: 点击MIO_Test旁边的箭头使其展开,然后选中src,按下Ctrl+V快捷键,粘贴main.c文件

Step5:右击工程,选择Debug as ->Debug configurations。

Step6:选中system Debugger,双击创建一个系统调试,点击Apply,点击Debug。

Step7:单击窗口上的运行按钮,运行程序

4.7 测试结果

可看到核心板LD9闪烁

4.8 程序分析

接下来对程序进行分析。

分析1

语句:static XGpioPs psGpioInstancePtr;

含义:这是一个指针实例,指向添加的GPIO端口。

具体分析:

XGpiops:绿色标识的一个结构体。SDK中结构体都用绿色标识。

将鼠标停留在XGpiops上或右键Open Declaration,查看这个结构体所包含的内容。

分析2

语句:XGpioPs_Config* GpioConfigPtr

含义:这是一个指针实例。

具体分析

XGpioPs_Config:绿色标识的一个结构体。

将鼠标停留在XGpiops上或右键Open Declaration,查看这个结构体所包含的内容。

          此结构体存放的是GPIO的设备地址和基地址。

分析3

语句:int iPinNumber= 7;

含义:参数

具体分析:iPinNumber这个参数,是告知程序,操作的MIO是哪一个,因为我们要操作的是MIO7,所以这里所以这里的iPinNumber等于7。(在第三章EMIO中也使用了这个参数,具体请参看下一节内容,这里仅作铺垫)

分析4

语句:GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);

          if(GpioConfigPtr == NULL)

              return XST_FAILURE;

含义:查找GPIO配置程序。此处用到xparameters.h中XPAR_PS7_GPIO_0_DEVICE_ID。这段话的整体意思为查找GPIO的配置,判断其是否为空,若为空则返回查找失败。

具体分析

分析5

语句:

       xStatus=XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr,GpioConfigPtr->BaseAddr);

       if(XST_SUCCESS != xStatus)

       print(" PS GPIO INIT FAILED \n\r");

含义: 完成gpio配置的初始化工作,如果初始化不成功,将通过串口打印出初始化失败的信息。

分析6

语句:XGpioPs_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection)

含义:指定pin脚的方向设置。

具体分析:

程序完成指定pin脚的方向设置。程序首先读取bank号,对应的子程序:

        /* Get the Bank number and Pin number within the bank. */

            XGpioPs_GetBankPin((u8)Pin, &Bank, &PinNumber);

将鼠标停留在XGpioPs_GetBankPin函数上,按F3查看下其功能。

       图中画红框部分为程序查找bank号对应代码。程序首先判断ZYNQ的类型,本课第一节GPIO简介介绍7010和7020有四个bank,因此当程序执行后,程序首先执行else部分的程序。此时看else部分程序。程序给出了四个bank的bank号的最大值,初始化bank号为0,while语句限制了bank的最大数量为4。然后用pin的序号从bank0到bank3逐个比对,若是此时pin的序号小于或等于当前bank的最大值,则可以判断出pin是属于这个bank的,跳出while语句,否则bank号进行自加操作直到得出符合的bank号。接下来if语句,判断bank号是否为bank0,若是则将PinNumber直接赋值,否则经过计算一段公式得出PinNumber。

接下来回到XGpioPs_SetDirectionPin函数分析其他的子程序。获取了bank号后,开始读取寄存器,程序如下:

              DirModeReg = XGpioPs_ReadReg(InstancePtr->GpioConfig.BaseAddr,

                          ((u32)(Bank) * XGPIOPS_REG_MASK_OFFSET) +

                                XGPIOPS_DIRM_OFFSET);

      这里重点观察第二个参数,这是一个任务寄存器偏移+DIRM_OFFSET的参数。此时打开xilinx的编程手册ug585-zynq-7000-TRM(接下来的内容中我们将将其简称为ug585),来具体看看这个参数含义。

      复制DIRM,在ug585中查找到这么一段话:

      此时得知这是一个方向寄存器,当它等于0的时候输出被禁止,只有输入进行,即此时为输入功能。等于1时做输出使用。在GPIO的通道示意图中也能发现有这个部分构成。

       回到XGpioPs_SetDirectionPin的分析,再得到了bank号与要写哪个寄存器的地址后,接下来的if else语句就是对这对pinbumer这一位单独做一些操作,最后把方向寄存器的值写入到读出的那个寄存器当中。

分析7

语句:XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);

含义:配置输出

分析8

语句:XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 1)

含义:写数据到pin脚

具体分析:

XGpioPs_WritePin的参数分别为gpio的基地址、要操作的MIO号和写入的数据。定义如下:

观察图中方框圈起来部分,此处观测到有两个陌生的偏移,此时可在ug585中查看其具体含义。

       此时可以得知,语句是要写入数据的高16位偏移量和低16位偏移量。程序是通过判断PinNumber的值来决定寄存器偏移量是用高16位偏移量还是低16位偏移量。

       此时再看XGpioPs_WritePin函数的接下来的这段程序:

       这段程序完成向指定MIO写入某个值的操作。分析这段程序,如果要向MIO7写入1,程序一开始已经把要写入的值赋值给了DataVar,此段程序又将DataVar与0x01与操作,操作后DataVar的值还是为1。

       接下来的value就是要写入寄存器的值。~ ((u32)1 << (u32)PinNumber):表示把PinNumber加上16(也就是把pinNumber移到高16位)赋值为1,然后再取反,执行完后这一段的值为~(80000)h,也就是(FFF7FFFF)h。

       ((DataVar << PinNumber) | 0xFFFF0000U):已经得到DataVar的值为1,因此这里的意思为把pinNumber位赋值为1,再与FFFF0000或操作,执行完这一段的值为(80)h | (FFFF0000)h,也就是(FFFF0080)h,整句执行完之后就是(FFF7FFF)h & (FFFF0080)h=(FFF70080)h。也就是此时Value的值为FFF70080。

       XGpioPs_WriteReg这个函数功能是往寄存器中写入数据。

从图上可知,第一个参数为设备的基地址, 第二个参数为偏移量,此处为0,第三个参数为要写入寄存器的数据。另外程序还可直接使用寄存器函数对MIO进行操作,其用法参照之前的分析,寄存器函数操作如下所示:

XGpioPs_WriteReg(0xE000A000,0x00000000, 0xFF7FFFFF&0xFFFF0080);

usleep(500000); //延时

XGpioPs_WriteReg(0xE000A000,0x00000000, 0xFF7FFFFF&0xFFFF0000);

usleep(500000); //

按照之前讲解的方法,开发人员可自行对库函数进行学习分析。


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 彭先生 2020-11-20 21:32
使用GPIO不需要在XDC定义管脚的
引用 惊蛰 2020-3-24 20:22
请问下提供的代码在哪

查看全部评论(2)

本文作者
2019-9-6 19:15
  • 7
    粉丝
  • 2744
    阅读
  • 2
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜