这一部分主要分为两个部分:
该部分控制7个LED灯组成流水灯,其中A5、A6、A7、B8、T16是PL端的GPIO口;C19、G17是PS端的GPIO口。
其中,由A5、A6、A7、B8、C19组成一组流水灯;由T16、G17组成另外一组。
主要更改两个部分的内容:
这里为了实验需要允许了双通道的GPIO,正常一个GPIO通道即可完成5路GPIO口的控制。
然后让Vivado自动连接填补剩余模块即可。具体完成后就是如下的样子。
led.xdc
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_rtl_0_tri_io[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_rtl_0_tri_io[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_rtl_0_tri_io[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {gpio_rtl_0_tri_io[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports gpio_rtl_1_tri_io]
set_property PACKAGE_PIN B8 [get_ports {gpio_rtl_0_tri_io[3]}]
set_property PACKAGE_PIN A6 [get_ports {gpio_rtl_0_tri_io[2]}]
set_property PACKAGE_PIN A7 [get_ports {gpio_rtl_0_tri_io[1]}]
set_property PACKAGE_PIN A5 [get_ports {gpio_rtl_0_tri_io[0]}]
set_property PACKAGE_PIN T16 [get_ports gpio_rtl_1_tri_io]
之后生成BitStream后导出硬件平台信息,由于这部分需要使用EMIO,需要包含bitstream库,之后可以征正常开始编写PS部分程序。
通过Launch SDK打开Xilinx SDK。创建一个空的应用项目。由于没有使用串口,这一部分不可以使用HelloWorld模板。
先引入一部分必须引入的模块
#include "parameters.h" // 常数模块
#include "sleep.h" // 延时模块
这一部分需要引入xgpio模块
#include "xgpio.h"
先实验一个基于PL部分的流水灯程序,这一部分主要是测试使用两个通道的GPIO口会有什么问题。测试下来,并没有什么问题。
用到的函数有
int XGpio_Initialize(
XGpio* InstancePtr,
u16 DeviceId
); //初始化
void XGpio_SetDataDirection(
XGpio *InstancePtr,
unsigned Channel,
u32 DirectionMask
); //设置GPIO口的读写方向
void XGpio_DiscreteWrite(
XGpio * InstancePtr,
unsigned Channel,
u32 Data
); //设置GPIO口的值
int usleep(
unsigned long useconds
); //设置延时时间
这些函数在官方文档以及官方例程里面给的比较详细,这里就无需说明。
针对PL口的流水灯的程序如下:
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"
#define GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define DELAY_LED 500000
#define LED_CHANNEL_1 1
#define LED_CHANNEL_2 2
#define LED0 0x01
#define LED1 0x02
#define LED2 0x04
#define LED3 0x08
#define LED4 0x01
XGpio gpio;
int main(){
int Status;
Status = XGpio_Initialize(&gpio, GPIO_DEVICE_ID);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
XGpio_SetDataDirection(&gpio, LED_CHANNEL_1, 0x00);
XGpio_SetDataDirection(&gpio, LED_CHANNEL_2, 0x00);
while(1){
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_1, (~LED0) | LED1 | LED2 | LED3);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_2, LED4);
usleep(DELAY_LED);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_1, LED0 | (~LED1) | LED2 | LED3);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_2, LED4);
usleep(DELAY_LED);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_1, LED0 | LED1 | (~LED2) | LED3);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_2, LED4);
usleep(DELAY_LED);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_1, LED0 | LED1 | LED2 | (~LED3));
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_2, LED4);
usleep(DELAY_LED);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_1, LED0 | LED1 | LED2 | LED3);
XGpio_DiscreteWrite(&gpio, LED_CHANNEL_2, ~LED4);
usleep(DELAY_LED);
}
return 0;
}
首先确定PS两个GPIO口对应的PS部分的编号。其中G17为MIO0,C19为MIO9。
实验一个基于PS部分的流水灯程序,这一部分主要是测试使用PS控制GPIO口是否有其他问题。测试下来,并没有什么问题。
用到的函数有:
XGpioPs_Config *XGpioPs_LookupConfig(
u16 DeviceId
); //根据设备ID查看配置文件
s32 XGpioPs_CfgInitialize(
XGpioPs *InstancePtr,
XGpioPs_Config *ConfigPtr,
u32 EffectiveAddr
); //初始化
void XGpioPs_SetDirection(
XGpioPs *InstancePtr,
u8 Bank,
u32 Direction
); //设置GPIO口读写方向,这里和PL部分相反
void XGpioPs_SetOutputEnable(
XGpioPs *InstancePtr,
u8 Bank,
u32 OpEnable
); //使能GPIO口输出
void XGpioPs_WritePin(
XGpioPs *InstancePtr,
u32 Pin,
u32 Data
); //写入一个GPIO口的值,这里需要注意,只有最低位有效
#include "xparameters.h"
#include "sleep.h"
#include "xgpiops.h"
#define PS_GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define DELAY_LED 500000
#define PS_GPIO_BANK XGPIOPS_BANK0
#define PS_LED0 0x09
#define PS_LED1 0x00
static XGpioPs psGpio;
int main(){
XGpioPs_Config *psConfigPtr;
psConfigPtr = XGpioPs_LookupConfig(PS_GPIO_DEVICE_ID);
if (psConfigPtr == NULL) {
return XST_FAILURE;
}
XGpioPs_CfgInitialize(&psGpio, psConfigPtr, psConfigPtr->BaseAddr);
XGpioPs_SetDirection(&psGpio, PS_GPIO_BANK, 0x201);
XGpioPs_SetOutputEnable(&psGpio, PS_GPIO_BANK, 0x201);
while(1){
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
}
return 0;
}
有了之前的基础,这一部分比较简单。由于需要控制两个部分的流水灯,感觉意义缺缺,之后再中断中再继续这一个项目的编写。
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"
#include "xgpiops.h"
#define PL_GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define PS_GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define DELAY_LED 500000
#define PL_LED_CHANNEL_1 0x01
#define PL_LED_CHANNEL_2 0x02
#define PS_GPIO_BANK XGPIOPS_BANK0
#define PL_LED0 0x01
#define PL_LED1 0x02
#define PL_LED2 0x04
#define PL_LED3 0x08
#define PL_LED4 0x01
#define PS_LED0 0x09
#define PS_LED1 0x00
static XGpio plGpio;
static XGpioPs psGpio;
int main(){
int Status;
Status = XGpio_Initialize(&plGpio, PL_GPIO_DEVICE_ID);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x00);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_Config *psConfigPtr;
psConfigPtr = XGpioPs_LookupConfig(PS_GPIO_DEVICE_ID);
if (psConfigPtr == NULL) {
return XST_FAILURE;
}
XGpioPs_CfgInitialize(&psGpio, psConfigPtr, psConfigPtr->BaseAddr);
XGpioPs_SetDirection(&psGpio, PS_GPIO_BANK, 0x201);
XGpioPs_SetOutputEnable(&psGpio, PS_GPIO_BANK, 0x201);
while(1){
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0E);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0D);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0B);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x07);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0F);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x00);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0E);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0D);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0B);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x07);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_1, 0x0F);
XGpioPs_WritePin(&psGpio, PS_LED0, 0x00);
XGpio_SetDataDirection(&plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(&psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
}
return 0;
}
有一个神奇的地方,实际上应该是一个bug,我现在还没有弄明白为什么。
即如果将psGpio和plGpio的声明换为
static XGpio* plGpio;
static XGpioPs* psGpio;
后面将&psGpio换为psGpio,&plGpio换为plGpio。程序在初始化的位置就不知道跑到哪里去了。无论怎么尝试都是错误的,我一直以为这样的修改是等价的,不知道为什么会有这样的问题。
即
#include "xparameters.h"
#include "sleep.h"
#include "xgpio.h"
#include "xgpiops.h"
#define PL_GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID
#define PS_GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
#define DELAY_LED 500000
#define PL_LED_CHANNEL_1 0x01
#define PL_LED_CHANNEL_2 0x02
#define PS_GPIO_BANK XGPIOPS_BANK0
#define PL_LED0 0x01
#define PL_LED1 0x02
#define PL_LED2 0x04
#define PL_LED3 0x08
#define PL_LED4 0x01
#define PS_LED0 0x09
#define PS_LED1 0x00
static XGpio* plGpio;
static XGpioPs* psGpio;
int main(){
int Status;
Status = XGpio_Initialize(plGpio, PL_GPIO_DEVICE_ID);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x00);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_Config *psConfigPtr;
psConfigPtr = XGpioPs_LookupConfig(PS_GPIO_DEVICE_ID);
if (psConfigPtr == NULL) {
return XST_FAILURE;
}
XGpioPs_CfgInitialize(psGpio, psConfigPtr, psConfigPtr->BaseAddr);
XGpioPs_SetDirection(psGpio, PS_GPIO_BANK, 0x201);
XGpioPs_SetOutputEnable(psGpio, PS_GPIO_BANK, 0x201);
while(1){
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0E);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0D);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0B);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x07);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0F);
XGpioPs_WritePin(psGpio, PS_LED0, 0x00);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0E);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0D);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0B);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x07);
XGpioPs_WritePin(psGpio, PS_LED0, 0x01);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x00);
XGpioPs_WritePin(psGpio, PS_LED1, 0x01);
usleep(DELAY_LED);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_1, 0x0F);
XGpioPs_WritePin(psGpio, PS_LED0, 0x00);
XGpio_SetDataDirection(plGpio, PL_LED_CHANNEL_2, 0x01);
XGpioPs_WritePin(psGpio, PS_LED1, 0x00);
usleep(DELAY_LED);
}
return 0;
}
无报错,无法正常运行。
以上,关于控制GPIO口的实验部分全部结束。