基于Lemon ZYNQ的PS实验二 GPIO之用AXI-GPIO方式点亮LED (完整图文)

在上一节中,我们介绍了如何通过 EMIO 方式调用 GPIO 来点亮 LED。本节将转向使用 AXI GPIO 方式来实现相同的功能。

  • 此章节内容适用于Lemon ZYNQ主板,如是其他板子请看对应板子目录
  • 本文在 vivado2018.3版本上演示

一、创建Vivado工程

1) 具体步骤 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”,最后点击“Next” 备注,所有的路径均不能出现中文名称

3)点击 RTL PROJECT 选项,点击NEXT

4) 第四步Add Sources 选项直接留空,NEXT

5)第五步Add Constraints 选项直接留空,NEXT

6) 选择芯片型号  板子的芯片型号为 XC7Z020 封装是CLG484 所以型号我们选择 xc7z020clg400-1 (如果是XA7Z020的车规级芯片版本,这里也选xc7z020clg400-1)

7)确认所选信息 点击“Finish”,完成vivado的工程创建

二、创建一个BLOCK设计

1)IP INTEGRATOR→Create Block Design,在弹出的对话框中输入设计名,最后点击“OK”,如下图所示

2)在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM ,双击并打开

3)软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核

4)依次在弹窗里找到DDR Configuration→DDR Controller Configuration→DDR3,在Memory Part下拉菜单中根据自己板子上的DDR来选择相应的DDR3,本实验所用到型号:MT41K256M16RE-125,数据位宽选择16bit 最后点击“OK”,如下图所示。

5) 因为Lemon ZYNQ主板的PS时钟是50M的晶振输入的,所以这里需要把默认的PS输入时钟33.33M改成50M

6)点击“Run Block Automation”如下图所示。在弹出的选项中保持默认,点击“OK”,即可完成对ZYNQ7 Processing System的配置

7)用同样的方法增加AXI GPIO资源 点击加号,在设置里搜索GPIO并添加,然后双击并打开生成的AXI GPIO资源进行设置

8)在GPIO的设置栏里将输入输出属性改成全部输出ALL Outputs ,因为我们板子上只有2个LED灯,所以将GPIO Width位宽设置成2位,点击OK

9)点击 上方的Run Connection Automation ,并将GPIO 和S_AXI前面的勾都选中,如下图所示 点击OK

10)软件将自动帮我们完整所有必要的连线,以及添加必要的模块

11)在框图中双击GPIO输出的管脚,并重新命名为LED,方便后面软件编程

12)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper如下图所示。

在弹出的对话框里保持默认

软件自动为我们生成HDL文件

三、创建约束文件,并且定义管脚

1)Add Source → Add or create constraints 点Next

因为这个项目没有创建过约束文件 所以这里创建一个约束文件,并在File name 里设置约束文件的名称,并且点击FINISH 完成约束文件的创建

2)Sources → Constraints 里找到刚才创建的约束文件 双击并打开该XDC约束文件

在约束文件里面复制下面代码来对输出的GPIO进行管脚(所有的管脚转接板上丝印都有实际标注对应的IO)

set_property IOSTANDARD LVCMOS33 [get_ports LED_tri_o[0]]
set_property IOSTANDARD LVCMOS33 [get_ports LED_tri_o[1]]

set_property PACKAGE_PIN R14 [get_ports LED_tri_o[0]]
set_property PACKAGE_PIN P14 [get_ports LED_tri_o[1]]

四、生成bit文件

1) 按下绿色箭头对工程进行编译

2) 按下Generate Bitstream 完成综合以及生成bit文件

五、SDK程序编写

1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。

2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。

系统将自动打开SDK开发环境

3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。

4)在新建工程名中输入自己的工程名称,点击NEXT

5)选择空工程,点击完成FINISH

6)选择创建的LED_CODE_bsp → system.mss → axi_gpio_0 gpio → import Examples(上一节中我们用的是自己手动编写的代码,这一节中我们就尝试直接调用SDK自带的AXI-GPIO DEMO)

7)选择 xgpio_example

8)这样系统就自动创建了一个参考例程

六、下载到板子上进行验证

选中工程中的硬件平台,并点击右键→Program FPGA,在弹出的对话框中选择默认,点击“program”,完成FPGA PL部分的Program工作

2)选中我们生成的GPIO工程 展开绿色箭头(RUN)右边的图标,选择Run As→1 Launch on Hardware(System Debugger)

可以看到板子上的LED1灯在闪烁

备注 :如果 RUN 的时候弹出错误 可以按照下面的操作 进行设置 再进行DEBUG

之后点 APPLY 然后 再选择Run As→1 Launch on Hardware(System Debugger)看是否下载成功。

七、代码解读

XGpio_SetDataDirection 设置GPIO为输入/输出
XGpio_DiscreteWrite    置位GPIO
XGpio_DiscreteClear    拉低GPIO

#define LED 0x01
继续看代码,LED在代码中的定义为 0X01  即代表 LED 在LED_CHANNEL中代表最低位 BIT0

看懂了上面这些 就很容易看懂程序里的代码  
XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED); //代表拉低GPIO LED_CHANNEL中的 第0位
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED); //代表拉高GPIO LED_CHANNEL中的 第0位
XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~LED); //设置为输出模式

for (Delay = 0; Delay < LED_DELAY; Delay++); //这是一个耗费系统资源的delay函数的简写

所以整个程序的效果就是LED 不停的点亮熄灭,反复循环。 

八、代码改编

上面的DEMO是只点亮一个灯,我们的vivado 里添加的AXIGPIO是添加了两个输出口,如果我们要同时控制两个LED灯,这里我们只需要对代码进行改编即可。

1) 我们对LED定义的部分更改:

#define LED1 0x01 即可 0X01代表 0000_0001
#define LED2 0x02 即可 0X02代表 0000_0010

初始化的时候
XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~(LED1|LED2));

赋值的时候LED1和LED2单独用 XGpio_DiscreteClear(赋值0),XGpio_DiscreteWrite(赋值1)

2) 我们对DEMO代码进行改编,调整后的main 函数如下:

#define LED1 0x01
#define LED2 0x02

int main(void)
{
int Status;
volatile int Delay;

/* Initialize the GPIO driver */
Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);
if (Status != XST_SUCCESS) {
xil_printf("Gpio Initialization Failed\r\n");
return XST_FAILURE;
}

/* Set the direction for all signals as inputs except the LED output */
XGpio_SetDataDirection(&Gpio, LED_CHANNEL, ~(LED1|LED2));

/* Loop forever blinking the LED */

while (1) {
/* Set the LED to High */
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED1);
XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED2);

/* Wait a small amount of time so the LED is visible */
for (Delay = 0; Delay < LED_DELAY; Delay++);

/* Clear the LED bit */
XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED1);
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED2);

/* Wait a small amount of time so the LED is visible */
for (Delay = 0; Delay < LED_DELAY; Delay++);
}

xil_printf("Successfully ran Gpio Example\r\n");
return XST_SUCCESS;
}

按第六部分的方式重新下载到板子上进行测试,可以看到LED1和LED2在交替的反复闪烁,代码功能验证成功。

看懂这些 就可以像实验一那样,自己创建一个main函数 然后在里面参考这个官方的例子写驱动LED的代码了。其实包括UART,USB之类的 都是可以用这个方式来进行开发,官方都有已经调试好的DEMO可供测试。

以上是完整的AXI-GPIO调用调试过程,不过在PS控制PL管脚的方式中,更推荐实验一中的EMIO方式,更加简洁也更省FPGA逻辑资源。

  • 本文的完整工程下载02_PS_LED_TEST_AXI_GPIO
  • VIVADO的版本:2018.3
  • 工程创建目录: E:\Lemon_ZYNQ\SDK\02_PS_LED_TEST_AXI_GPIO

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注