Petalinux Bringup on Cora Z7-10 Zynq Board
By Richard
- 12 minutes read - 2493 wordsThis post contains notes that I generated while bringing up Petalinux on my Cora Z7-10 Zynq board. First I get Petalinux working and do a couple of hello world examples. It can serve as a companion to the following resources:
In the second section, Petalinux is built from scratch, and I implement custom AXI-compliant IP on the FPGA fabric. A Xilinx tutorial is followed (with extra notes) to write a Linux device driver and an app to leverage the driver. The result? AXI-controlled blinky LEDs from Linux.
Topics covered:
- SSH connections to the board
- Adapting Xilinx tutorials for different target dev boards
- Cross-compiling apps on the desktop and copying them to the board
- Petalinux build and installation notes
- Notes where existing tutorials weren’t correct (for my particular setup, anyway)
As usual, this article is not a standalone tutorial. It’s a supplement to the linked resources.
Note: some links are to Cora Z7-10 specific resources. If you have a different board, be sure to poke around and see if a similar resource exists for your platform.
Section 1 - Petalinux Bringup
Petalinux Install
I started by following the readme instructions in the repo linked below. I was not able to execute the petalinux installer from my root account, I had to make a new user, chmod +w the installation directory from the new user, and then run the installation script.
I also added the source petalinux script call to the bottom of my .cshrc file so it will be sourced every time I make a new terminal. You could also make it an alias, since the command takes a couple of seconds to run, which is annoying when you want to bring up a new terminal quickly.
SD Card Partitioning
I partitioned my SD card with the following partitions:
- Name: fpga, format: FAT, size: 1 GB
- Name: bulk, format: EXT4, size: 7 GB
Go App
These notes accompany the Hackster.io article. I thought it would be interesting to write the first example in go, so I tried it out. Once I understood the flow, I went back to writing things in C.
- Make a new folder with
main.go
inside it. Note that the final executable will have the same name as this directory. cd
into the directory you placedmain.go
in.- Run this command to compile:
GOARCH=arm go build
- An executable will be generated with the name of the current directory.
- Copy it into the “bulk” partition on the SD card.
Petalinux Bringup
I used a pre-built Petalinux image from Digilent. As I learned later, this was a good call. Building Petalinux takes about an hour for me, so using the pre-compiled package made the process much quicker for an initial bringup.
- Download the board support package from github, then place it in a directory called bsp somewhere.
- Make a new directory to contain the petalinux project and cd into it.
- Run the following command to generate the project:
petalinux-create -t project -s <path to .bsp file>
- As per the instructions, I copied the boot files onto the first partition of my microSD card and made the MAC address file. The MAC address on the board sticker needs a colon between every set of 2 characters in the file.
- Plug in the SD card to the Cora, short jumper JP2.
- Connected a terminal to /dev/ttyUSB1 at 115200 baud, 8-N-1.
- Press SRST. I was soon greeted with a
Zynq:
prompt, which has several low-level commands that you can see by enteringhelp
. It was proving difficult to navigate and enter commands in this mode. I was getting filesystem configuration errors. So I cycled power and SRST. I was greeted with aroot@Cora-Z7-10:
prompt. Great, it’s working! In this mode, commands likels
work without error. - The bulk of my filesystem is on a 2nd partition of the SD card, which is also where I placed the demo go app executable.
- Enter the following commands to mount to the partition:
mkdir SDFS
mount /dev/mmcblk0p2 ./SDFS
cd SDFS
- Now you can run the go app executable as usual:
./test-app
- There was an issue with the demo app where it was set to run a huge number of iterations, so the app appears to do nothing after the initial print. Whoops. Don’t believe everything you see on the internet. However, the print worked, so at least we know the app worked.
C Hello World
GCC is installed under petalinux, so may as well make an app in C and check that it works too.
Still in the SDFS directory, I wrote a hello world file in c:
// hello.c
#include <stdio.h>
int main(){
printf("Hello, world!\n");
return 0;
}
Note that you’ll need to use vim to write the code since the only interface is a command prompt over a UART. I discuss writing apps on the PC and transferring them over a couple sections down in this article.
Compile it with: gcc hello.c
.
Run it with: ./a.out
.
SSH
Let’s SSH into the board so that files can be edited and compiled on the desktop, and then executables copied over over Ethernet.
- Plug the board into your router with an Ethernet cable.
- You should see a “link up” message soonafter
- On the terminal connected over the UART, run
ifconfig
- The first
inet addr
is the ip address of the board, 192.168.1.69 for me. I will use this address throughout this article. If you’re following along, always replace it with the IP address your board is given.
Above: output from ifconfig
command
- On the PC in a new terminal, SSH into the board using the following command:
ssh [email protected]
(replacing with the IP address you just determined). - You will be prompted for a password, it was
root
for me.
By now, you should see a command prompt appear for the board. SSH success! Use the logout
command to close the SSH connection when you’re done.
SSH and Cross-compile Flow
Now let’s test out a more reasonable development flow where we write an app on the PC, cross-compile it there, then copy the executable to the device over ssh.
- Make a new directory on your PC called
zynq-apps
- Inside, make an app project directory
hello-world
- Inside the
hello-world
directory, add the following makefile:
# Cross compiler prefix: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842547/Install+Xilinx+Tools#InstallXilinxTools-XilinxVivadoandPetaLinuxTools
# many existing tutorials are not updated for Vivado
CC = arm-linux-gnueabihf-gcc
CFLAGS = -lm
all : hello-world
hello-world : hello-world.o
${CC} ${CFLAGS} $^ -o $@
clean :
rm -rfv *.o
rm -rf hello-world
uplink:
# this target will upload the executable to the board. Change to an IP address assigned to your board.
scp hello-world [email protected]:
.PHONY : clean
- Add the hello-world.c code from above, or add something more complex.
- Make the app with
make
- Upload the app to the board using the
uplink
target with this command:make uplink
. This will usescp
to copy the executable over to the board. You will need to enter the passwordroot
when you run this command. - SSH into the board again:
ssh [email protected]
- The hello-world app was copied into the root directory, so it can be executed with the following command:
./hello-world
Section 2: Connecting the ARM Cores and FPGA
The best tutorial I found for connecting the ARM cores and FPGA is this one from Xilinx. In this section, I include some notes for section 7 of the linked document, as I had to modify the process slightly to work with the Cora board.
The tutorial walks you through building an AXI-controlled IP block, adding a device driver to the petalinux build, and writing and running an application that uses the petalinux device driver.
Above: the block diagram for the system that will be created.
Prerequisites
You should already have the Digilent board files installed, and you should be able to create a simple RTL project and load the bitstream on to the Cora board from Vivado. You should also be familiar with the Petalinux procedure discussed above, as it is used in this part too.
Writing HW Drivers
These notes correspond to the Creating Peripheral IP section of the tutorial linked above.
- Create a new vivado project and select the Cora board. This assumes that you’ve got the Digilent board descriptions installed.
- In the IP integrator, create a new block design. Add the Zynq PS IP to it.
- Double click the Zynq block, in the re-customize IP window, click Import XPS settings.
- Navigate to
vivado-boards-master/new/board_files/cora-z7-10/B.0
and selectpreset.xml
. Click OK.
Above: setting up the XPS settings for the ARM processing subsystem.
This file comes from the vivado-boards
repo from Digilent and allows the Zynq to be configured with all of the other hardware on the board.
- Run block automation.
- Connect the clocks (fig 2-8 in the tutorial). I get some warnings about negative clock skew. This is a known issue and can be ignored, apparently.
- Continue until step 10 of the Integrating Peripheral IP with PS GP Master Port section where the LED port settings are configured.
- Search for “leds” in the port list of the elaborated design. Refer to the Cora reference manual and set the Package pin for each bit of the led port. Set the IO standard to
LVCMOS33
.
- As per the tutorial, open up SDK.
Petalinux Driver Setup
- Execute the petalinux module creation commands in the Device Driver Development section.
- Copy the provided blink.c and blink.h files into project-spec/meta-user/recipes-modules/blink/files and update the .bb file. Don’t forget the trailing slash in the bb file, or the build process will throw an error.
- Run the command
petalinux-build
, notpetalinux build
as stated in the tutorial. - Time for coffee! The build process took quite a while on my i5 machine, approximately an hour. It includes some very large file downloads - I guess this is where the 100 GB (!) free space requirement comes from.
- Generate the boot image from the command in the cora petalinux repo:
petalinux-package --boot --force --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/cora_z7_10_wrapper.bit --u-boot
- As described in the repo readme above, copy the newly generated image on to the SD card in the correct location.
- Insert the SD card into the board.
Above: a preview of the working blinky app
SDK and FPGA Programming
These notes are for the Example Project: Loading a Module into Kernel and Executing the Application section.
- Open SDK, skip the TCF agent on the host machine step. I won’t be using the debugger right now.
- Make a new SDK project, set Linux as the OS in the wizard. I skipped the toolchain and system root configurations because the directories in the tooltips were not present on my system.
- Import the
blink.h
andlinux_blinkled_app.c
file from theLKM_App
directory in the example code download from the Xilinx tutorial. Delete thehelloworld.c
file that’s included by default. It should automatically build without errors. The .elf file generated by SDK will be copied over to the board in a later step. - Program the FPGA with
Xilinx > Program FPGA
. The board was auto-detected for me.
Testing out the Device
Now that everything is built and programmed, let’s try to run the app and communicate to custom hardware from a Linux device driver!
- With the new linux image set, cycle power and connect up to the serial port.
- Run the
mknod
commands on the board as described in the tutorial. - Create a directory
/Apps
I decided to skip using the Xilinx tools for navigating on the device, and do it through SSH/the UART connection instead.
- scp the
.elf
file from.sdk/linux-blinkled-app/Debug/linux-blinkled-app.elf
from the PC onto the board in the/Apps
directory using the following command on the PC:scp <path to elf file> [email protected]:
I had to remove the old SSH key stored for this IP address, since it changed when petalinux was rebuilt. Then I SSH’d into the board again.
I moved the .elf file into the Apps directory I made earlier, chmod +777’d it as is done in the tutorial, and executed. To my great surprise, the example fired right up and lights started blinking!
Above: blinking LEDs controlled by an AXI-enabled peripheral from a Petalinux device driver.
To recap, from scratch, we did the following:
- built Petalinux
- installed a custom device driver
- implemented an AXI-compliant IP block and hooked it up to the Zynq processing system
- implemented and built an app to use the driver to interface to the custom IP
- learned the build flows, practiced communicating with the target board
That’s pretty good! All of the building blocks of a really interesting project are in place now. It’s time to look at the example code and examine how it can be used to bootstrap a more complex application and more complex custom IP.
Custom AXI IP [WIP]
- make folder for IP in project directory
- tools > create and package IP
- setup the IP settings
- If you don’t choose edit now, you can just click “add IP” in the block diagram and search for the IP name you just created. It will show up and then you can edit it.
- Add it to the diagram
- Edit in IP packager
- Make the changes to the IP
- In the IP packager flow, update the ports (should be an auto thing to do this). This occurs in the
Package IP <IP Name>
tab. Make your way down the left hand bar with all of the steps in it. - Re-Package IP
Now go back to the main design and re-sync with the IP. Now is also a good time to run connection and block automation.
- Right click at the top of the
sources
tab and choosegenerate HDL wrapper
.
Hook up IO Ports
- RTL Analysis > Open Elabrorated Design // hookup-io picture
- At the top, click the IO Ports
- Near the bottom there is a search icon
- Search for
led
and the pins will show up - Set the package pins to
N15
,G17
,L15
,M15
and LVCMOS33. Which LED is assigned which pin doesn’t really matter.
Using a Project From Git
- Open up the project in Vivado
- Generate bitstream
- When that’s done,
File > Export Hardware
to send the design to SDK File > Launch SDK
- When SDK opens,
File > Import Projects From Filesystem
Navigate to repo_base/project_name.sdk/sdk_project_name and select it. SDK should automatically detect that a project is present. Click OK to open up the project.
- Right click on the SDK project in the sidebar and choose
Debug As > Debug Configurations...
- Select a Xilinx System Debugger type
- In the target setup tab, make sure the following settings are there:
- Debug Type: Linux Application Debug
- Connection: click the new button and enter the IP address of the board in the
Host
field.
- Press the
Test Connection
button. It should succeed. - All good, time to flash the bitstream! Click the
Program FPGA
button. - Once that’s done, you can debug the software application. Simply hit the
Debug
button and the debugger perspective should open up. Click theStart
button when you are ready to run the code.