本文参考正点原子嵌入式视频
与其说是笔记,不如说是赛灵思文档翻译
1.GPIO
本文参考UG585 chapter 14
GPIO定义
指的是general purpose I/O ,它是zynq7000系列中MIO的一部分,它是一个外设(peripheral),是用来对器件的引脚作观测(input)以及控制(output)。GPIO的起始地址在0XE000_A000。
MIO定义
是指multiuse I/O,即多路复用,将来自PS外设以及静态存储器接口进行多路复用到ps的引脚上去。
EMIO定义
是用来将ps连接到fpga的引脚,从而来扩展pl的引脚到ps端。
GPIO功能
GPIO可以独立动态编程,作为输入输出以及中断模式,它有四个Bank,其中Bank0,Bank2,Bank3为32b,而Bank1只有22b,这是因为zynq给予GPIO的引脚只有54个(图中的34和35可以用来作为GPIO的引脚,而501 502 503 只能用在pl侧)。
很明显能看出,Bank0和Bank1组成了54b用来连接MIO,而Bank2与Bank3则用来与EMIO连接,用来连接PL侧的引脚来扩展引脚数目。软件可以通过一组存储映射(memory-mapped)的寄存器来控制GPIO。
但是在Bank0中,Bits[8:7]在系统复位中作为VMODE引脚,用于MIO的Bank电压控制,在复位结束后只能作为输出信号。MIO[8]对应VMODE[1],MIO[7]对应VMODE[0]。
(在MIO中Bank0对应的pins为0到15,Bank1对应的pins为16到53,不要混淆MIO和GMIO的Bank,这是两个完全不一样的东西。)
GPIO实现
可以看到GPIO使用很多寄存器,其中:
DATA_RO
(read only)用来反映控制的引脚数值,无论作为输入或者输出都会反映出来引脚的电平状态。
DATA
一次性操作32位,如果用来输出,可以显示输出的引脚电平;如果作为输入,可以用来显示之前的引脚电平数值,但是它不能显示current实时的引脚电平,事实上实时的电平在DATA_RO中已经实现了这个功能。
MASK_DATA_LSW/MASK_DATA_LSW
低16位屏蔽以及高十六位屏蔽
(???比如现在我想改变引脚数值,那么我必须一次性操作32位,并且使用read-modify-write三步骤
DATA0: 1010_0101_1010_0101_xxxx_xxxx_xxxx_xxxx
修改为
DATA1: 1010_1010_1010_0101_xxxx_xxxx_xxxx_xxxx
1.先读取DATA的数值(read)
2.改变需要改变的数值(modify)
3.将修改的数据写入DATA中(read)
如果我们使用屏蔽,就可以只用一个MASK来改变DATA中16位数值,而不是改变全部的32位。该寄存器允许对所需的输出值进行更有选择性的改变,最多可写入16位的任意组合,那些未被写入的位保持不变,并保持其先前的值。该寄存器避免了对未改变位的读-修改-写序列的需要。)
DIRM
Direction Mode.用于控制I/O引脚作为输入还是输出,但是由于因为输入永远是有效的,实际是用来控制输出的驱动,如果为0那么输出驱动被关掉,只能作为输入来进行使用。
OEN
Output Enable.控制输出使能,如果为1打开输出使能,如果为0关闭输出使能。
GPIO编程(zynq7000)
使用zynq7000系列型号搭建SDK,其中需要配置DDR3,UART,GPIO。然后在SDK中创建c工程,并使用下面的代码实现LED灯的闪烁现象。
#include "stdio.h"
#include "xparameters.h"
#include "xgpiops.h" //XGpioPs_LookupConfig所在的文件夹
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
//核心板上LED
#define MIO0_LED 0
XGpioPs_Config* ConfigPtr;
XGpioPs Gpio;
int main()
{
printf("GPIO MIO TEST!\n\r");
//初始化GPIO的驱动
//Initialize the GPIO driver
//根据器件的ID ,来找到器件的配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//初始化GPIO驱动 ,函数return XST_SUCCESS always,所以这里可以不返回
XGpioPs_CfgInitialize(&Gpio, ConfigPtr,ConfigPtr->BaseAddr);
//把GPIO的方向设置为输出 (0输入/1输出)
XGpioPs_SetDirectionPin(&Gpio, MIO0_LED, 1);
//设置输出使能(0输入/1输出)
XGpioPs_SetOutputEnablePin(&Gpio, MIO0_LED, 1);
//写数据到GPIO的输出引脚(0X1高电位/0X0低电位)
//XGpioPs_WritePin(&Gpio, MIO0_LED, 0x1);
while(1){
//点亮
XGpioPs_WritePin(&Gpio, MIO0_LED, 0x1);
//延时
//sleep(1); sleep单位是s,usleep是us
usleep(500000); //延时0.5s
//熄灭
XGpioPs_WritePin(&Gpio, MIO0_LED, 0x0);
//延时
usleep(500000);
}
return 0;
}