跳转到主要内容

UltraZed-EG PCIe Carrier Card 开发纪录: Hello Cortex-A53

joycha 提交于

<p>在<a href="http://xilinx.eetrend.com/blog/2019/100017230.html">&nbsp;UltraZed-EG PCIe Carrier Card 开发纪录: 硬件认识</a>&nbsp;一文中我们了解了&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a>&nbsp;这一块开发板的一些信息后,是时候来开发点项目啦~ </p>

在这篇文章中,我们将让这块开发板的 Cortex-A53 透过 AXIO_GPIO 模块,点亮板子上的 LED 灯,并且透过 ps_uart0 输出一些讯息。
(本文以 Vivado 2018.2 进行开发)

<strong>开发目标</strong>
我们这次的开发目标是这样子的,除了透过 ps_uart0 输出讯息外,顺便验证如何透过 AXI_GPIO 去控制 User Leds D12 ~ D19 这些位于可程序逻辑区 (Programmable Logic, PL) 上的 LED 们。

由于单纯点亮点暗太无聊了,所以就写成跑马灯的形式吧 (也是蛮无聊的 Orz…)
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>建立项目</strong>
<p>首先让我们打开 Vivado 吧~ 不过在进行这一步之前,请先确定你有依照&nbsp;<a href="http://xilinx.eetrend.com/blog/2019/100017279.html">让 Vivado 有 UltraZed-EG PCIe Carrier Card 的配置文件</a>&nbsp;一文的说明,让我们在建立项目的时候可以找到&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a>&nbsp;这块板子。 </p>

启动了 Vivado 后,点选 Create New Project
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

接下来指定好项目路径和名称
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

选择 RTL Project
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<p>选择&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a></p>
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>完成项目的建立</strong>
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>建立 Block Design</strong>
由于我们的设计需要用到 Xilinx 一些现成的 IP 的时候,就会需要透过 Block Design 来建立我们的电路设计。

首先点选 IP Integrator -> Create Block Design
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

接着点选 OK 建立我们的 Block Design
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

点选 Add IP 按钮去增加我们需要的 IP 核
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

我们首先寻找 Zynq UltraScale+ MPSoC 并将它加入到我们的 Block Design,并点选 Run BLock Automation 对该 IP 做一些设定
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

进入到 Run BLock Automation 的设定页面后,确认 zynq_ultra_ps_e_0 有被勾选到,并且 Apply Board Preset 有被设定起来。

点选 OK 完成设定。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<p>接下来,我们根据我们的&nbsp;<a href="https://coldnew.github.io/501bf2ae/#org81bde65">开发目标</a>&nbsp;来加入 LED 的接线 </p>

点选 Board ,将 LED 拖曳到 Diagram 内
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

于是我们的 Block Design 就会变成这个样子
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

点选 Run Connection Automation 进行联机,会进入到以下窗口,这边直接点选 OK 即可
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

我们已经完成我们的设计啰,点选 Validate Design 按钮来确认设计没问题
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

没问题的话,就让我们来结束 Block Design 的工作吧
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>产生 HDL Wrapper</strong>
接下来我们要将刚刚用 Block Design 建立的电路变成 verilog 程序代码,因此会需要进行产生 HDL Wrapper 这个步骤。

对你的 Block Design 档案点选右键,选择 Create HDL Wrapper ,它会根据你项目设定的语言 (VHDL 或是 Verilog) 来产生相对的 HDL 程序代码。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

由于这次我们不需要对产出来的东西进行修改,因此选 Let Vivado manage wrapper and auto-update 即可
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

好了后,假设你的 Block Design 档案叫做 design_1.bd ,那就会产生 design_1_wrapper.v 或是 design_1_wrapper.vhdl 这样的档案。

<strong>产生比特流 (bitstream)</strong>
前面的处理都好了后,接下来点选 Program and Debug -> Generate Bitstream 去让 Viavado 将这个项目产生出 比特流 (bitstream) ,Zynq UltraScale+ 会在开机的时候根据 bitstream 的信息对 FPGA 进行设定。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

这个产生的过程视你的计算机强度如何而决定花多少时间,总之先来泡杯茶吧~

当 bitstream 完成后,我们准备执行 Xilinx SDK 来透过写 C 语言项目来让 Cortex-A53 可以透过 AXI_GPIO 对 LED 进行控制,因此要先将刚刚产生的硬件信息输出给 Xilinx SDK 去。

点选 File -> Export -> Export Hardware
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

确定你有勾选 Include bitstream 后,点选 OK
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

完成后,执行 Xilinx SDK
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>Xilinx SDK</strong>
启动 Xilinx SDK 后,点选 File -> New -> Application Project 去建立新的项目
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

这边我命名这个项目为 hello ,并指定为 standalone 的程序,该程序将运作在 Cortex-A53 的 CPU0 上。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

由于我们很懒,因此这次选用预设的样板 Hello World 来建立我们的项目,好了后点选 Finish
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

当项目建立完成后,会自动打开 hello_bsp 里面的 system.mss ,里面会显示我所使用的外围文件链接或是加入范例程序代码,比如我们如果要了解 axi_gpio 怎样使用的话,可以点选它的手册。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<p>这样就会透过浏览器打开如以下的页面 (或是到&nbsp;<a href="https://xilinx.github.io/embeddedsw.github.io/gpio/doc/html/api/group__…; target="_blank">这个网址</a>&nbsp;看在线文件) </p>
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

<strong>打开 helloworld.c</strong>
由于我们是使用样板 Hello World 去建立我们的项目的,因此默认的程序是 helloworld.c ,我们打开它可以看到以下内容
* helloworld.c: simple test application
*
* This application configures UART 16550 to baud rate 9600.
* PS7 UART (Zynq) is not initialized by this application, since
* bootrom/bsp configures it to baud rate 115200
*
* ------------------------------------------------
* | UART TYPE BAUD RATE |
* ------------------------------------------------
* uartns550 9600
* uartlite Configurable only in HW design
* ps7_uart 115200 (configured by bootrom/bsp)
*/

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
int main()
{
init_platform();

print("Hello World\n\r");

cleanup_platform();
return 0;
}

这个程序会自动透过 ps_uart0 输出 Hello World 讯息,而由于我们将使用的是 ps7_uart ,因此 baudrate 会是 115200 。

<p>接下来我们的任务就是加入 LED 的控制功能了,不过在这之前,也许读一下&nbsp;<a href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/os…; target="_blank">UG643 (2018.2): Xilinx Standalone Library Documentation - OS and Libraries Document Collection.pdf</a>&nbsp;这份文件可以让我们对 Xilinx 的函式库有所了解些。 </p>

<strong>加入 LED 控制</strong>
我们基于刚刚打开的 helloworld.c 来加入我们对 AXI_GPIO 的控制,首先先加入两个 header file。
#include "sleep.h" // for usleep()
#include "xgpio.h" // for gpio control

<p>每个&nbsp;<a href="https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841921/AXI+gpio…; target="_blank">AXI_GPIO</a>&nbsp;模块都会有两个 channel 作为输出,由于这边我们走得是预设的,也就是第一个 channel,因此先做个 macro 好方便后续的程序撰写。 </p>
* The following constant is used to determine which channel of the GPIO is
* used for the LED if there are 2 channels supported.
*/
#define LED_CHANNEL 1

接下来,在 main() 里面,执行 init_platform(); 后面的位置加入我们对 GPIO 的初始化,假设初始化失败的话,则透过 xil_printf() 输出错误讯息并回传 XST_FAILURE 。

其中 XPAR_GPIO_0_DEVICE_ID 定义在 xparameter.h 里面,为 Xilinx SDK 自动产生出来的档案,你可以将其对应回我们的 Block Design 里面的 axi_gpio_0 。
XGpio Gpio; /* The Instance of the GPIO Driver */

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

初始化完成后,由于 LED 是属于 GPIO 的输出功能,因此要指定这些 GPIO 为 Output

Set the direction for all signals as LED output */
XGpio_SetDataDirection(&Gpio, LED_CHANNEL, 0);

接着我们定义两个变量,一个是用来控制 LED 当前状态的变量,另外一个则是控制我们跑马灯的方向
* D12 is ON by default, D13 ~ D19 are OFF
*
* D19, D18, D17, D16, D15, D14, D13, D12
*
* 0 0 0 0 0 0 0 1
*/
int LED = 0b00000001;
* 0: left to right (D12 -> D19)
* 1: right to left (D19 -> D12)
*/
int direction = 0;

最后则是我们的循环,我们透过 XGpio_DiscreteWrite() 去对我们的 LED_CHANNEL 写入当前 LED 的输出状态,并透过定义在 sleep.h 里面的 usleep() 来做点延迟,避免因为视觉暂留效应而导致我们肉眼以为 LED 没有在闪烁。

当 LED 为 0b10000000 时,也就是 D19 为 ON 的情况,修改我们的 direction 变量,让原本对 LED 变量进行左移的运作改成右移。

当 LED 为 0b00000001 时则相反,让 LED 变量变成左移运算。
Loop forever blinking the LED */
while (1) {
/* Set the LED to High */
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL, LED);

/* Wait a small amount of time so the LED is visible */
usleep(20 * 1000); /* delay 20ms */

/* Clear the LED bit *

XGpio_DiscreteClear(&Gpio, LED_CHANNEL, LED);

/* Wait a small amount of time so the LED is visible */
usleep(20 * 1000); /* delay 20ms */

/* When D19 is ON, change direction */
if (LED == 0b1000000)
direction = 1; /* 1: right to left (D19 -> D12) */
/* When D12 is ON, change direction */
if (LED == 0b0000001)
direction = 0; /* 0: left to right (D12 -> D19) */

/* Change LED status according to direction */
if (direction == 0)
LED = LED << 1; /* shift left */
else
LED = LED >> 1; /* shift right */
}

就这样,我们的程序完成了,可以开始进行刻录啰~

<strong>设定 JTAG 下载</strong>
<p>为了透过 Micro USB 连接到&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a>&nbsp;上的 JTAG 来进行下载,我们需要对&nbsp;<a href="http://zedboard.org/product/ultrazed-EG&quot; target="_blank">UltraZed-EG</a>上的&nbsp;SW2&nbsp;要进行一些调整,变成下图这样。 </p>
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

这样子就可以透过 Micro USB 走 JTAG 下载的路线,将程序下载下去

<strong>下载到开发板 (FPGA)</strong>
<p>由于我们到目前为止还没有将编译好的比特流 (bitstream) 下载到我们的&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a>&nbsp;去,因此先来下载吧。 </p>

点选 Xilinx -> Program FPGA 进入到下载页面
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

点选 Program 将我们的比特流 (bitstream) 下载下去
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

下载好了后,由于我们的程序还没烧到 Cortex-A53 上,因此要进行下载 ELF 的动作

<strong>下载到开发板 (ELF)</strong>
点选 Run -> Run Configuration 去建立我们新的执行目标
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

对 Xilinx C/C++ Application (GDB) 点两下,建立执行目标,并确认 Run psu_init 和 PL Powerup 有被勾选起来。
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

点选 Application 确认我们的下载目标是 psu_cortexa53_0 ,并且下载的 elf 档案没有错
<center><img src="http://xilinx.eetrend.com/files/2019-01/%E5%8D%9A%E5%AE%A2/100017367-58…; alt=""></center>

点选 Run 即开始下载啰,希望一切顺利 ~

<strong>结果</strong>
<p>按照本篇文章的设定,你的&nbsp;<a href="http://ultrazed.org/product/ultrazed-eg-pcie-carrier-card&quot; target="_blank">UltraZed-EG PCIe Carrier Card</a>&nbsp;显示应该如以下影片: </p>
<iframe src='https://coldnew.github.io/501bf2ae/video.mp4&#039; allowfullscreen frameborder=0 width="600" height="400"></iframe>

另外,我们也可以透过 minicom, emacs, tio, gtkterm 等终端机软件,连接上 /dev/ttyUSB1 来查看透过 printf() 输出的讯息。

<strong>取得程序代码</strong>
<p>本文的范例已经上传到&nbsp;<a href="https://github.com/coldnew-examples/ultrazed_pciecc_helloA53&quot; target="_blank">coldnew/ultrazed_pciecc_helloA53</a>&nbsp;,你可以透过以下命令获得 </p>

git clone https://github.com/coldnew-examples/ultrazed_pciecc_helloA53.git

<strong>延伸阅读</strong>
<body>
<ul type="circle">
<li><a href="https://coldnew.github.io/dec85bd3/">zybo board 开发记录: Zynq 与 LED 闪烁控制</a></li>
<li><a href="https://ece.gmu.edu/coursewebpages/ECE/ECE699_SW_HW/S15/viewgraphs/ECE6…; target="_blank">ECE699: Lecture 4 - Intrrrupts AXI GPIO and AXI Timer.pdf</a></li>
<li><a href="https://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/…; target="_blank">AXI GPIO v2.0 LogiCORE IP Product Guide.pdf</a></li>
<li><a href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/os…; target="_blank">UG643 (v2018.2): Xilinx Standalone Library Documentation - OS and Libraries Document Collection.pdf</a></li>
<li><a href="https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841921/AXI+gpio…; target="_blank">Xilinx Wiki: AXI gpio standalone driver</a></li>
<li><a href="https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_2/ug…; target="_blank">UG1209 (v2018.2): Zynq UltraScale+ MPSoC: Embedded Design Tutorial.pdf</a></li>
</ul>
</body>

本文转载自:<a href="https://coldnew.github.io/&quot; rel="start">coldnew's blog</a>