您的位置:首页 > 产品设计 > UI/UE

GPIO Product Guide笔记(Xilinx)

2017-01-30 21:23 483 查看
GPIO是通用并行IO接口的简称。他将总线信号转化为IO设备要求的信号类型,实现地址译码输出数据,锁定输入数据缓冲的功能。GPIO控制器的基本结构如图1所示。



总线接口模块实现地址译码,并将特定总线信号转化为内部总线;中断逻辑模块,根据中断控制以及中断产生条件产生中断请求信号。输入/输出控制模块将内部总线信号转化为基本的输入/输出引线,并实现输出数据锁定,输入数据暂存的功能。

图中只画出1位数据的原理图,多位数据需要多组都同样的结构。输入/输出控制模块包括内部译码控制模块。输出使能控制寄存器(GPIO_TRI),输入数据输出寄存器数据输入寄存器(GPIO_DATA),数据采样寄存器(GPIO_IN)。需要首先向(GPIO_TRI) 写入零。然后再向 GPIO_DATA写数据。数据才能传输到外部引脚上。如果要输入外部引脚的数据,那么必须同时使能 GPIO_DATA_IN和 READ_REG_IN。并且使得MUX选择GPIO_IO的数据。同样可以通过控制MUX读取使能状态GPIO_TRI,由输入输出模块的原理图,可知程序可以先通过读取什么状态,了解外部引脚信号再根据需要修改输出到GPIO_IO上。

以下以赛灵思AXI总线GPIO IP核为例来介绍GPIO控制器的具体应用。该 GPIO控制器IP核支持两个独立的 GPIO通道,并且每个通道可以支持1-32位的数据输入/输出,可配置为单,输入单输出或双向输入输出。

控制器包括接口总线模块,中断产生逻辑模块以及双通道输入输出模块。双通道输入输出模块的原理框图2如下,该GPIO包括两个通道,并且独立工作,只有中断信号由同一个一个引脚输出,两个通道都可以输入输出,但是任意时刻仅作为输入或输出接口使用,其数据的传输方向通过什么控制,当输出低电平时,数据输出,反之则输入。



GPIO内部寄存器如表所示,所有寄存器采用小字节序,即数据的第一位对应引脚的地位。 GPIO的各部分分别控制 GPIO的各位为输入或输出,当 GPIO_TRI末位为0时,GPS对应的IO配置为输出。当GPIO_TRI某位为1,相应的IO配置为输入。如果我们只是配置 GPIO,作为简单的输出接口,不需要使用中断机制,那么对 GPIO编程控制,只需要先写GPIO_TRI,然后再输出数据到 GPIO_DATA就可以了。



2.具体实现

Tips:这次演示一个Microblaze的流水灯

* background:首先你要在你的FPGA开发板(比如ZYBO)搭建好软核
* Add IP ->gpio
* 选择你要用的通道,比如我有7个LED,都为OUTPUT,你可以选择All output或者不选择(会作为inout)之后在SDK调用时对GPIO_TRI写0作为输出端口,连接好GPIO的时钟、控制线、复位(可以选择自动连接)




* 修改顶层模块的端口定义,加上LED

* 修改XDC文件

* 综合编译工程,生成bit文件

* Export Hardware->Launch SDK

* 编写C语言程序(这个就很简单了。。。)首先你要看看你的GPIO BASE Address是多少,每个外设都有自己的地址,学过微机原理的童鞋都好理解。如图所示,我的是0x40010000(记得去掉中间的”_”,SDK会报错)



我们先介绍一下GPIO外设常用的几个函数(学过51单片机,或者是STM32的童鞋就非常容易上手)

其实这是直接对寄存器操作的函数,并不是GPIO外设特有的。(详细定义参考xil_
b709
io.h头文件)

*
#define Xil_In8(Addr)  (*(volatile u8  *)(Addr))

*
#define Xil_In16(Addr) (*(volatile u16 *)(Addr))

*
#define Xil_In32(Addr) (*(volatile u32 *)(Addr))


Perform an input operation for a xx-bit memory location by reading from the

specified address and returning the value read from that address.

*

@param Addr contains the address to perform the input operation at.

*

@return The value read from the specified input address.

以上是读GPIO数据的函数,使用前确保你设置GPIO_TRI对应的那1位为1(或者你已经配置了all input) ,否则no effect

#define Xil_Out8(Addr, Value)  \
(*(volatile u8  *)((Addr)) = (Value))
#define Xil_Out16(Addr, Value)  \
(*(volatile u16  *)((Addr)) = (Value))
#define Xil_Out32(Addr, Value)  \
(*(volatile u32  *)((Addr)) = (Value))


Perform an output operation for a xx-bit memory location by writing the

specified value to the specified address.

以上是写GPIO数据的函数,使用前确保你设置GPIO_TRI对应的那1位为0(或者你已经配置了all output),否则no effect

打开system.mss,还可以看到peripheral Drivers里面有GPIO外设提供的API函数

实质就是把Xil_Out这样的函数封装了罢了,本次例子较为简单,就不用了(而且每次调用这些函数都要Initialize,有点麻烦)请自己打开页面去查看函数功能



附送代码:(均在FPGA开发板成功验证)

1.直接写寄存器的方法

#include <stdio.h>
#include <xparameters.h>
#include <xgpio.h>
#include <xintc.h>
#include <xtmrctr.h>
#include <xuartlite.h>
#include "platform.h"
#include "keys/keys.h"
#include "queue/queue.h"
#include <microblaze_sleep.h>
#define LED_BASE           0x40010000
#define LED_BASE_TRI       0x40010000 + 0x04
int main()
{
int i=1;
Xil_Out8(LED_BASE_TRI,0x00); //设置为输出
while(1)
{
//MB_Sleep(1000);
for( ;i<=0x80;i=i<<1)
{
Xil_Out8(LED_BASE,i); //写数据
MB_Sleep(10);
}
i = 0x01;
}
cleanup_platform();
return 0;
}


2.使用GPIO的API函数方法

#include <stdio.h>
#include <xparameters.h>
#include <xgpio.h>
#include <xintc.h>
#include <xtmrctr.h>
#include <xuartlite.h>
#include "platform.h"
#include "keys/keys.h"
#include "queue/queue.h"
#include <microblaze_sleep.h>
int main()
{
int sts;
int i;

init_platform();

sts=XGpio_Initialize (&gpioLed, XPAR_HIER_PERIPH_GPIO_LEDS_DEVICE_ID);
if(sts != XST_SUCCESS) printf("pgio led init error!\n");
while(1)
{
for( i=0x01;i<=0x80;i=i<<1)
{
XGpio_DiscreteWrite (&gpioLed, 1, i);//led hign is effective
MB_Sleep(500);
}
i=0x01;
}


反思:学习FPGA不自己去阅读英文文档是不行的,有问题可以去Xilinx英文论坛讨论。总而言之,官方的文档还是比较重要的第一手资料吧(By华科Peter)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: