Zybo Linux
Zybo Linux
Pullman, WA 99163
509.334.6306
www.digilentinc.com
Overview
The purpose of this document is to provide step-by-step instructions for customizing your hardware, compiling the
Linux Kernel, and writing driver and user applications. This documentation intends to integrate knowledge and
skills in FPGA logic circuit design, standalone software programming, Linux operating system and user application
development, and apply them to the ZYBO. We will start from the ZYBO Base System Design (available on the ZYBO
product page of the Digilent website). The system architecture for the ZYBO Base System Design is shown in Fig. 1.
In the ZYBO Base System Design, we connect UART1 to USB-UART, SD0 to the SD Card Slot, USB0 to the USB-OTG
port, Enet0 to the Giga-bit Ethernet Port, and Quad SPI to the on-board QSPI Flash. These cores are hard IPs inside
the Processing System (PS) and connect to on-board peripherals via Multiplexed I/O (MIO) pins. The use of PS GPIO
is connected to Btn 4 and 5. In the Programmable Logic (PL), we have an HDMI TX Controller, VDMA, and GPIO IP
cores to talk to the ADV7511 HDMI transmitter chip and I2S and GPIO IP cores for ADAU1761 audio codec. More
details of the hardware design can be found in the documentation inside the ZYBO Base System Design package.
DOC#: 594-008
Page 1 of 37
Figure 2. Hardware System Architecture of the system we are going to implement in this Tutorial.
Before going through this tutorial, we recommend that you read Getting Started with Embedded Linux - ZYBO. You
can follow this tutorial with the Embedded Linux Development Guide (available on the Digilent website Embedded
Linux Page). The guide will provide you with the knowledge you may need in each step of the development.
In this tutorial, we are going to use Xilinx Vivado 2014.1 WebPACK in a Linux environment. All of the
screenshots and codes are done using Vivado Design Suite 2014.1 in CentOS 6 x86_64.
Thats it for the background information on this tutorial, now its time to get our hands dirty with some real design!
Page 2 of 37
Hardware Customization
1.1
Prerequisites
ZYBO Base System Design: available at the Digilent website on the ZYBO Page.
1.2
1.
Instructions
Download the ZYBO Base System Design from the Digilent website and unzip it into our working directory,
as in Fig. 3 (our working directory is named tutorial throughout this document). For more information on
the hardware design, please refer to Project Guide under doc folder.
2.
Source Vivado 2014.1 settings and open the design with Vivado Design Suite. You will see the Vivado
window pop up as shown in Fig. 4.
Note: There are four settings files available in the Vivado toolset: settings64.sh for use on 64-bit machines
with bash; settings32.sh for use on 32-bit machines with bash; settings32.csh for use on 32-bit machines
with C Shell; and settings64.csh for use on 64-bit machines with C Shell.
Page 3 of 37
3.
We are going to detach LEDs from the GPIO core in the PS first. So we need to click on the IP integrator
and open the Block Diagram as shown in Fig. 5. Then we need to delete the current LED IP as shown in Fig.
6. We will handle the modification of external pin location configuration (xdc file) in later steps.
Note: In Fig. 6 there is a yellow bar indicating the need for an upgrade. To upgrade, hit show IP status,
make sure all are selected and hit Upgrade Selected.
Page 4 of 37
(Vivado 2014.1 only) Before we can start implementing our myLed IP Core, we need to name the vendor
that will automatically be applied in the IP packager. In Vivado 2014.1, this is not automatically done for
the user. To do this, first go to the Project Settings under Project Manager on the left side of the window
(Fig. 7) and the project settings window will pop up. In the Project Settings window, select IP (Fig. 8).
Notice that the vendor is chosen as (none), this will cause a Vivado internal exception. You can name the
Vendor whatever you like (Fig. 9).
Page 5 of 37
5.
Now we can start implementing our myLed IP Core. Click Tools -> Create and Package IP from the menu
(as shown in Fig. 10). The Create and Package New IP window will pop up (as shown in Fig. 11), Click Next.
In the next window, name the new IP and click next again (Fig. 12).
Page 6 of 37
6.
The next window will be the Add Interfaces Window. This will create the AX14 Interface for the myLed
peripheral (Fig. 13). Make sure the interface type is Lite, the mode is Slave, the data width is 32 bits and
the number of registers is 4. Change the Name to S_AXI rather than S00_AXI. We only need 1 register but
the minimum we can select is 4. Click next to proceed.
Page 7 of 37
The next window will prompt the finishing steps to create the IP (Fig. 14). Change the Radio button to
select Edit IP and hit finish. We need to add user logic to the IP so that our slave is connected to the LED
output.
8.
After selecting finish, the Create and Package IP window will disappear and the next window you will see
is the edit_myLed window (Fig. 15). This is where we will add our user logic.
Page 8 of 37
9.
In the Project Manager, click the circle next to myLed_v1_0 and highlight myLed_v1_0_S_AXI (Fig. 16).
This contains the user logic inside of the myLed IP. We need to add two lines of code to complete the user
logic for this module. First, we need to create a user port called led (Fig. 17). Next, we need to connect the
internal slave to this user port. We will connect slv_reg0[3:0] as we have four LEDs (Fig. 18).
Page 9 of 37
10. Next, we need to connect the user logic to myLed. In the project manager select the file myLed_v_0. To
complete the IP, there are two lines of code we need to add to this file. Under the comment that says
Users to add ports here, add a port for the LEDs (Fig. 19). Connect the led output from the previous file
containing the user logic to myLed (Fig. 20).
11. Now that our IP is created and the user logic is defined, we need to package our IP. Under Project
Manager on the left side of the window, select Package IP. A new tab will open that is called Package IP.
On the left side of this tap there are a series of labels. We need to complete those that do not have green
check marks.
First, select IP customization Parameters. At the top of that window select the option to merge changes
from IP Customization Parameters Wizard, as in Fig. 21.
Page 10 of 37
Next, select the IP Ports and Interfaces. Notice that your new LED IP is there (Fig. 22).
Next, select IP GUI Customization. Our IP GUI is fine as is, so we wont make any changes here (Fig. 23).
Page 11 of 37
Now we can Review and Package our myLed IP. Select Review and Package IP and press the Re-Package
IP button. Our IP is now completed and packaged.
12. We are going to add our IP to our design. Right click anywhere on the block design and click Add IP (as
shown in Fig. 24). Select the correct IP, myLed_v1.0, and press enter (Fig. 23).
Page 12 of 37
13. The AXI4-Lite bus of myLed IP Core needs to be connected to the processing system. At the top of the
window, click the blue text that says Run connection automation (Fig. 26). This will connect the inputs of
the myLed IP Core. You should see that S_AXI is now connected to the first output of the AXI
Interconnect.
14. Next, we need to connect the myLed IP to an external port. The myLed IP Core that we implemented will
not connect to the existing LEDs_4Bits port, so we need to make a new external port called led. Click on
the existing LED port and press delete. To create the new port, right click and select create port (Fig. 27).
Name the port, select output, select vector [3:0] and press enter.
Copyright Digilent, Inc. All rights reserved.
Other product and company names mentioned may be trademarks of their respective owners.
Page 13 of 37
Next, connect the LED port to the myLed IP by clicking on the port and dragging a connection to myLed
(Fig. 28).
15. The final step is to specify the pin numbers for myled_0_LED_pin to physically connect our customized
IP Core to the on-board LEDs. In the Project Manager, expand the Constraints section and select the
base.xdc file (Fig. 29). Within that file, change the names of the external LED pins so that they match the
name of our external led port (Fig. 30).
Page 14 of 37
Figure 30. Connect Port led to the LEDs on the ZYBO Board.
16. Regenerate the bitstream for the hardware design by clicking on Generate Bitstream under Program and
Debug on the left side of the window.
Page 15 of 37
2.1
Prerequisites
ZYBO Base System Design: available at the Digilent Website on the ZYBO Page.
2.2
1.
Page 16 of 37
2.
To compile U-Boot, we need cross-compile tools which are provided by Vivado 2014.1. Those tools have a
prefix arm-xilinx-linux-gnueabi- to the standard names for the GCC tool chain. The prefix
references the platforms that are used. The ZYBO board has two arm cores, so we reference arm. In order
to use the cross-platform compilers, please make sure the Vivado 2014.1 settings have been sourced. If
not, please refer to step 1 above. To configure and build U-Boot for ZYBO, follow Fig. 34.
3.
After the compilation, the ELF (Executable and Linkable File) generated is named u-boot. We need to
add a .elf extension to the file name so that Xilinx SDK can read the file layout and generate
BOOT.BIN. In this tutorial, we are going to move the u-boot.elf to the sd_image folder and
substitute the u-boot.elf that comes along with the ZYBO Base System Design Package, as shown in
Fig. 35.
Page 17 of 37
Generate BOOT.BIN
3.1
Prerequisites
ZYBO Base System Design: available at the Digilent Website on the ZYBO Page.
Finished the hardware customization from Section 1 and u-boot.elf from Section 2 (Section 2
optional).
3.2
1.
Instructions
Export the hardware design (after Section 1, step 16) to Xilinx SDK by clicking on File -> Export -> Export
Hardware for SDK, as shown in Fig. 36.
2.
Leave the workspace as <Local to Project>.Make sure that the Launch SDK box is checked and click OK,
as shown in Fig. 37.
Note: If you are using Vivado 2014.1, you may have to export twice.
Page 18 of 37
3.
After SDK launches, the hardware platform project is already present in Project Explorer on the left of the
SDK main window, as shown in Fig. 38. We now need to create a First Stage Bootloader (FSBL). Click File>New->Project, as shown in Fig. 39.
Page 19 of 37
4.
In the New Project window, select Xilinx->Application Project, and then Click Next (Fig. 40).
5.
We will name the project FSBL. Select hw_platform_0 for Target Hardware because it is the hardware
project we just exported. Select standalone for OS Platform. Click Next, as shown in Fig. 41.
Page 20 of 37
6.
Select Zynq FSBL as template, and click Finish as shown in Fig. 42.
Page 21 of 37
For the ZYBO, we need to set the mac address for the Ethernet in the fsbl hook. We want the mac address
for the Ethernet to remain constant when we turn the ZYBO board off and on. You can swap the
fsbl_hooks.c file in the FSBL project with the fsbl_hooks.c under
source/vivado/SDK/fsbl in the ZYBO Base System Design (Fig. 43).
8.
After you have saved the changes to fsbl_hooks.c, the project will rebuild itself automatically. If it
does not rebuild, click Project->Clean to clean the project files, and Project->Build All to rebuild all the
projects. The compiled ELF file is located in:
ZYBO_base_system/source/vivado/hw/ZYBO_bsd.sdk/SDK/SDK_Export/FSBL/Debug
9.
Now we have all of the files ready to create BOOT.BIN. Click Xilinx Tools -> Create Zynq Boot Image, as
shown in Fig. 44.
Page 22 of 37
10. In the Create Zynq Boot Image window (as shown in Fig. 45), Click Browse to set the path for FSBL elf.
Click Add to add the system.bit file found at:
/ZYBO_base_system/source/vivado/hw/ZYBO_bsd/ZYBO_bsd.sdk/SDK/SDK_Export
/hw_platform_0/.Click Add to add the u-boot.elf file found at:
ZYBO_base_system/sd_image/. It is very important that the 3 files are added in this order, or else
the FSBL will not work properly (the proper order can be seen in Fig. 45). It is also very important that you
set FSBL.elf as the bootloader and system.bit and u-boot.elf as data files. In this tutorial, the
sd_image folder is set as output folder for the BIN file. Click Create Image.
Page 23 of 37
4.1
Prerequisites
ZYBO Base System Design: available at the Digilent Website on the ZYBO Page.
4.2
Get the Linux kernel source code from Digilent Git repository. There are two ways to retrieve the source
code:
Using git command: If you have Git installed in your distribution, you can clone the repository to your
computer by command git clone
https://github.com/DigilentInc/Linux-Digilent-Dev.git
The whole Git Repository is around 850MB, as shown in Fig. 46.
2.
We will start to configure the kernel with the default configuration for ZYBO. The configuration is
located at arch/arm/configs/xylinx_zynq_defconfig. To use the default configuration,
you can follow Fig. 47.
3.
Page 24 of 37
4.
After the compilation, the kernel image is located at arch/arm/boot/zImage. However, in this case the
kernel image has to be a uImage (unzipped) rather than a zimage. To make the uimage, follow Fig. 49.
Note: Depending on your distribution of Linux, you may get an error regarding the path of the mkimage. If
this is the case, you can change the path following Fig. 50.
5.1Prerequisites
Linux Kernel Source Code: available at Digilent GitHub repository https://github.com/DigilentInc/LinuxDigilent-Dev. (Use the Master-Next Branch Until Further Notice)
Pre-built File System Image: ramdisk Image is available in ZYBO Linux Reference Design.
5.2
Instructions
1.
To boot the Linux operating system on the ZYBO, you need BOOT.BIN, a Linux kernel image (uImage), a
device tree blob (DTB file), and a file system. BOOT.BIN has been created in Section 3 and uImage has
been compiled in Section 4. We will now compile the DTB file. The default device tree source file is
located in the Linux Kernel source at arch/arm/boot/dts/zynq-ZYBO.dts.
Page 25 of 37
48
49
chosen {
/* bootargs = "console=ttyPS0,115200 root=/dev/mmcblk0p2 rw earlyprintk
rootfstype=ext4 rootwait devtmpfs.mount=1"; */
bootargs = "console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M
init=/init earlyprintk rootwait devtmpfs.mount=1";
linux,stdout-path = "/axi@0/serial@e0001000";
};
50
51
52
2.
3.
(RAMDISK) Copy BOOT.BIN, devicetree.dtb, uImage and uramdisk.image.gz to the first partition of an
SD card, as shown in Fig. 54.
[kfranz@DIGILENT_LINUX Tutorial]$ ls
devicetree.dtb linux-digilent-dev u-boot-digilent ZYBO_base_system
[kfranz@DIGILENT_LINUX Tutorial]$ cp ZYBO_base_system/sd_image/BOOT.BIN /media/ZYBO_BOOT/
[kfranz@DIGILENT_LINUX Tutorial]$ cp ZYBO_base_system/sd_image/ uramdisk.image.gz /BOOT.BIN
/media/ZYBO_BOOT/
[kfranz@DIGILENT_LINUX Tutorial]$ cp ./devicetree.dtb /media/ZYBO_BOOT/
[kfranz@DIGILENT_LINUX Tutorial]$ cp Linux-Digilent-Dev/arch/arm/boot/uImage /media/ZYBO_BOOT/
[kfranz@DIGILENT_LINUX Tutorial]$
Figure 54. Ramdisk.
4.
Plug the SD card into the ZYBO. To boot from the SD card, jumper 7 needs to be configured for USB, as
shown on the ZYBO board, and Jumper 5 must be connected to SD. Connect UART port to PC with a
micro USB cable and set the UART terminal on PC to 115200 baud rate, 8 data bits, 1 stop bit, no parity,
and no flow control. After powering on the board, the console (shown in Fig. 55) should be seen at the
UART terminal if you use RamDisk. More information about these file systems can be found in Getting
Started with Embedded Linux - ZYBO.
Page 26 of 37
6.1
Prerequisites
Linux Kernel Source Code: available at Digilent GitHub repository https://github.com/Digilentinc/LinuxDigilent-Dev (Use the Master-Next Branch Until Further Notice)
6.2
Instructions
1.
Create a directory named drivers in the Tutorial folder, as shown in Fig. 56. Inside the drivers
directory, we will compose the driver for the myLed controller.
2.
We need a Makefile so that we can compile the driver. The Makefile is created in Fig. 57.
After creating the file, hit I to change to insert mode and insert the following text (Fig. 58).
Copyright Digilent, Inc. All rights reserved.
Other product and company names mentioned may be trademarks of their respective owners.
Page 27 of 37
obj-m := myled.o
all:
make -C ../Linux-Digilent-Dev/ M=$(PWD) modules
clean:
make -C ../Linux-Digilent-Dev/ M=$(PWD) clean
Figure 58. Makefile.
Note: make sure the spacing in the Makefile is made up of tabs, not spaces, where necessary. Then hit esc
to exit insert mode and :x to save the file and exit vim editor.
3.
We will start with a simple driver that creates a file named myled under the Linux /proc file system. The
status of the on-board LEDs can be changed by writing a number to the file. The driver is coded in Fig.
59.
Page 28 of 37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include
#include
#include
#include
#include
#include
#include
<linux/kernel.h>
<linux/module.h>
<asm/uaccess.h>
/* Needed for copy_from_user */
<asm/io.h>
/* Needed for IO Read/Write Functions */
<linux/proc_fs.h> /* Needed for Proc File System Functions */
<linux/seq_file.h> /* Needed for Sequence File Operations */
<linux/platform_device.h> /* Needed for Platform Driver Functions */
Page 29 of 37
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
Page 30 of 37
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
Page 31 of 37
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
Page 32 of 37
Compile and generate the driver module using make (as shown in Fig. 61). Dont forget to source Vivado
settings.
5.
We need to add the myLed device node into the device tree. Make a copy of the default device tree
source in the drivers folder, and modify it according to Fig. 62. The compatibility string of the node is
the same as we define in the driver source code (myled.c: line 182). The reg property defines the
physical address and size of the node. The address here should match with the address of the myLed IP
Core in the address editor tab of the Vivado design, as shown in Fig. 63.
Page 33 of 37
549
550
551
552
553
554
555
556
557
558
559 };
spi-speed-hz = <4000000>;
spi-sclk-gpio = <&ps7_gpio_0 59 0>;
spi-sdin-gpio = <&ps7_gpio_0 60 0>;
};
myled {
compatible = "dglnt,myled-1.00.a";
reg = <0x43c30000 0x10000>;
};
};
6.
7.
Copy these two files to the first partition of the SD card, as shown in Fig. 66. We are ready to test our
driver on-board now.
[kfranz@DIGILENT_LINUX drivers]$ ls
devicetree.dtb
Makefile
Module.symvers myled.ko
myled.mod.o
zynq-ZYBO.dts modules.order myled.c
myled.mod.c myled.o
[kfranz@DIGILENT_LINUX drivers]$ cp myled.ko /media/ZYBO_BOOT/d
[kfranz@DIGILENT_LINUX drivers]$ cp devicetree.dtb /media/ZYBO_BOOT/
[kfranz@DIGILENT_LINUX drivers]$
Figure 66. Copy files to SD.
8.
Plug the SD card into the ZYBO and we can start testing our driver. Use the insmod command to install
the driver module into the kernel. After the driver is installed, an entry named myled will be created
under the /proc file system. Writing 0x0F to /proc/myled will light up LED 0~3. You can either
remove the driver with command rmmod or power off the system by command poweroff. In both
cases, all of the LEDs will be turned off, as shown in Fig. 67. For instructions on using the terminal with
the ZYBO, please refer to Section 5, Step 4 or the Section Boot from SD in Getting Started with
Embedded Linux ZYBO.
Page 34 of 37
BOOT.BIN
myled.ko
devicetree.dtb
uImage
uramdisk.image.gz
partitions
scsi
self
slabinfo
softirqs
stat
swaps
sys
sysvipc
timer_list
tty
uptime
version
vmallocinfo
vmstat
zoneinfo
Page 35 of 37
User Application
7.1
Prerequisites
Vivado 2014.1 WebPACK: available at the Xilinx Website Download Page.
7.2
Instructions
1.
In this section, we will write a user application that makes the LEDs blink by writing to /proc/myled.
Create a directory named user_app in the Tutorial folder, as shown in Fig. 68. Inside the user_app
directory, we will compose the led_blink.c, as shown in Fig. 69.
user_app
ZYBO_base_system
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
FILE* fp;
while(1) {
fp = fopen("/proc/myled", "w");
if(fp == NULL) {
printf("Cannot open /proc/myled for write\n");
return -1;
}
fputs("0x0F\n", fp);
fclose(fp);
sleep(1);
fp = fopen("/proc/myled", "w");
if(fp == NULL) {
printf("Cannot open /proc/myled for write\n");
return -1;
}
fputs("0x00\n", fp);
fclose(fp);
sleep(1);
}
return 0;
}
Figure 70. led_blink.c
2.
Compose a Makefile and compile led_blink.c into led_blink.o, as shown in Figs. 71-73.
Page 36 of 37
1
2
3
4
5
6
7
8
9
10
11
12
13
CC = arm-xilinx-linux-gnueabi-gcc
CFLAGS = -g
all : led_blink
led_blink : led_blink.o
${CC} ${CFLAGS} $^ o
$@
clean :
rm rfv *.o
rm rfv led_blink
.PHONY : clean
Figure 72. Makefile.
3.
Insert the SD card into the computer, and copy the binary file led_blink onto the first partition of SD
card, as shown in Fig. 74.
...
rcS Complete
zynq> mount /dev/mmcblk0p1 /mnt/
zynq> cd /mnt/
zynq> ls
BOOT.BIN
myled.ko
devicetree.dtb
ramdisk8M.image.gz
led_blink
zImage
Page 37 of 37