Using C++ for bare metal Xilinx Zynq applications

Introduction

Xilinx SDK offers a range of example applications (11 to be precise) for bare metal projects created using C language. Unfortunately, there is only an Empty project option for C++ applications. In this post I will show how to start working with C++ in Xilinx SDK. In addition, this guide can be useful as a general starting point for Zynq projects as it is based on Zynq XC7Z020 device. Lets get to work!

Software tools used:

Vivado 2014.4, Xilinx SDK 2014.4

Hardware platform: Zedboard

Generating the hardware platform

Start the Vivado and create a new project (all defaults, except the location – your choice and target platform – Zedboard). After that, create a block design (Flow navigator tab, under IP Integrator section) and add the ZYNQ7 Processing Platform IP. Use Block Automation to add FIXEDIO and DDR. Disable M AXI GP0 interface from ZYNQ7 Processing Platform PS-PL configuration (Figure 1).

diasble_m_axi_gp

Figure 1 – disabling M AXI GP interface from ZYNQ7 Procesing Platform PS-PL configuration

Save the diagram and create HDL wrapper (Figure 2). Now generate the bitstream (Flow navigator tab, under Program and Debug section). Wait until it is finished and export (menu File->Export->Export Hardware, tick the Include bitstream option). Launch the SDK (menu File->Launch SDK) and choose the location provided in the exporting step.

create_hdl_wrapper

Figure 2 – creation of HDL wrapper

 

Side note – choosing the project name and SDK location

Naming – try to avoid and special characters (like polish ą / ę / ć / ł) and the space bar character. My advice is to use only letters, capital letters and underscore for all projects names and locations (especially those that target hardware, the tools usually offer way worse support than eg. Visual Studio).

SDK project location – I preferred separating the SDK project from the Vivado project, so more than one hardware project can use the same code.  It should be noted that the same thing can be achieved by using a remote directory for storing the source files. In this example, the mixed solutions was used – the SDK project is in a different location than the Vivado project and is using remote files.

Software

Create new project (menu File->New->Application Project). The details are shown in figure below (Figure 3).

new_cplusplus_app

Figure 3 – new C++ application

Unfortunately, there are no examples for C++ language, so choose the empty project.

I prepared the hello_world example here:

https://github.com/PUTvision/Xilinx_code_templates

The first thing I do for every project is to set the linker script. To do modify it, click Generate linker script (show in figure below).

generate_linker_script

Figure 4 – generate linker script

Set the Code, Data, Heap and Stack sections to ps7_ddr_0_S_AXI_BASEADDR, and choose 10MB size for stack and heap.

Side note – 10 MB – how many bytes is it?

It is really simple to remember how much bytes is in 10 MB. Start with 10 (like the number of megabytes you are using) then two pairs of digits that sum up to 12 – 4, 8 (4+8 = 12), 5, 7 (5+7 = 12) and finish it with 6 (6×2 = 12 or 6+6=12) and 0 (for 10MB), 00 (100 MB). So finally it is 10485760! You know, it’s that simple!

Alternatively you can use the linker script provided on github. To use it, you have to specify its location in project C/C++ Build Settings in section ARM g++ linker->Linker Script.

After that step we have to add the code from the github to the project. There are two ways of achieving this. The first one involves creating appropriate files locally to the project and pasting the code. The more elegant (IMHO) solution is to put the code somewhere in the file system and then add this remote location to the project. The second solution will be described in details:

  1. Remove all the source files (main.cc) from the project.
  2. Right click on the src folder in project and choose import. Choose General->File System.
  3. Next dialog box should be filled according to the Figure 5 (but choose location where you have the code, in my case it is X:\p\sdk\_code_templates). Pay attention to tick all the boxes as shown!
  4. We have to tell the SDK where to look for the header files. Launch project C/C++ Build Settings (Figure 6).
  5. In ARM g++ compiler->Directories section add the directory where you placed the code downloaded from github (in my case it’s X:\p\sdk\_code_templates).
  6. As a result you get all the code necessary to launch the project! It should compile without any errors.
import_code_new

Figure 5 – import code to project

C_Cplusplus_build_settings

Figure 6 – project C/C++ Build settings

 Side note – project location

As I had some problems with Xilinx tools not liking long file locations currently I’m using virtual drive for storing all the projects (it’s name is X!). I suggest everybody that is working with Xilinx tools to do the same thing 🙂 On Windows machine of course 🙂

Code explanation

The main file (app_hello_world.cc) contains the main functions. I guess it’s really simple and does not need any explanation. Additional files (in platform folder) are copied from simple example app for C project and are responsible for initializing the cache and UART (necessary for printf functions).

Running the project

The last thing to do is to run our project. Connect the Zedboard to power and to computer (it’s necessary to connect two microusb cables – to PROG and UART connectors on the board. Both are located close to the power connector – on the left and right). Power on the board and check if all the drivers (for programmer and virtual com port) were loaded. Open the serial port, all the parameters are given in Figure 7 (the port number is dependent on your system!).

open_serial_port

Figure 7 – opening the serial port

After that write the bitstream to the board (menu Xilinx Tools -> Program FPGA). Start the application by using menu Run -> Debug As -> Launch on Hardware (System Debugger). In debug mode, the application will stop at the beginning of a the main function. Let it go by pressing F8 (or menu Run -> Resume). The result should be visible in Terminal window (Figure 8).

application_running

Figure 8 – application running

 

Thats all for today! Next time, we will write a peripheral driver in C++! See you soon!

Michał Fularz

Acknowledge

This research was financed by the Polish National Science Centre grant funded according to the decision DEC-2011/03/N/ST6/03022, which is gratefully acknowledged.

More info:
http://www.vision.put.poznan.pl/?page_id=237

Leave a Reply

Your email address will not be published. Required fields are marked *