One thing that is always important for engineers, is the need for us to deliver our projects on quality, schedule and budget. When it comes to developing embedded systems there are a number of lessons, learnt by embedded system developers over the years which can be used to ensure your embedded system achieves these. Let us explore some of the most important lessons learned in developing these.
Completing the RTL design is one part of getting
your FPGA design production-ready.
The next challenge is to ensure the design
meets its timing and performance requirements
in the silicon. To do this, you will often need to
define both timing and placement constraints.
Let’s take a look at how to create and use both
of these types of constraints when designing systems
around Xilinx® FPGAs and SoCs
Happy New Year! For the first blog of the year I thought we would combine the FreeRTOS and the XADC examples we had bbeen looking at previously.
This will enable me to show how we can do the following
- Configure the XADC
- Create a task to read from the XADC
- Create a second task to take action on the results from the first task
The intended functionality is the one task, once a second reads the XADC internal parameters and stores them within a array. This array is then communicated via a queue to the recieivng task which processes the results, for this example it just outputs them over the UART. If we wanted to this task could perform more detailed analysis or calcualtion on the results being provided to it.
We can easily modify the hello world example to perform this. If we wish to make it more complex and introduce more tasks which share resources, we must ensure they are properly managed and do not become deadlocked.
The first thing we need to do is include the proper header files such that we can use the API for the XADC we do this by including the “XSYSMON.H”.
Within the main function we are going to configure and initialise the XADC before we start the two tasks.
As we are going to be using the printf function and we are going to transfering data we need to ensure the stack size is correctly allocated. To prevent problems I decided to increase this to ensure there was sufficent for that requred for both tasks, when we create the tasks in the main() we are required to define the stack allocated to each task. For both tasks I decided to allocate 1000 bytes, I left the task pirorites as the receiving task being a higher priortiy than the transmitting task ensuring the data is transmitted as soon as it is received.
The next step was to create the queue, as I mentioned above due to the priorities of the RX and TX tasks there will only be one element in the queue, which will be the size of the size element XADC_Buf.
The final element is to start the scheduler and let the tasks run for ever well once we have written them.
We write each task as a we would any function in C, being careful to ensure we include the 1 second dealy within the transmitt task.
When I ran the code (which is available here) I got the following results.
As I explained in my previous column, the configuration of the Zynq is a little different from that of traditional FPGAs. At the end of the previous column, we were poised to begin using SDK to generate the boot image. So far in this series of blogs, I have created the PS (programmable system) and PL (programmable logic) sides of the device, created a simple C program, and demonstrated everything working using the JTAG interface.
The next step in creating a “boot image” is to create a first-stage boot loader (FSBL). Thankfully, the folks at Xilinx are kind enough to provide us with an FSBL that will load our application and configure our FPGA (you can, of course, customize the code provided to alter the boot sequence). Within the current SDK workspace (the one containing your C project), use “New > Application Project” to create a new project as illustrated below
Select whether you want to use C or C++, the board support package defined for your system, and the name of the project, which is “zynq_fsbl_0” in this case. On the next tab select the “Zynq FSBL” option, as illustrated below and your FSBL project will be created, at which point we are nearly ready to create the boot image
f you have “Compile Automatically” selected then the FSBL will be compiled; if not, it will be compiled on-demand later on.
However, we actually need to make a small change to the linker script provided with the FSBL, as it has no idea where the DDR memory is located in the processor address space. Therefore, we need to open the “lscrip.ld” file and add the DRR memory location into this file. This can be found in the linker script we created for the C application in Part 3 of this mini-series (it can also be found in the “system.xml” file under the hardware platform definition).
The following screenshot shows the FSBL “lscript.ld” file with the DDR address for the system added in. If you forget to do this, you will find that the boot loader will run and the FPGA will, but the application will not run because in Part 3 we configured the application to run from the DDR
Looking under the “Project Explorer,” you should hopefully now have the following modules (each should have a slightly different symbol identifying the type of module):
- proc_subsystem_hw_platform — named after the processing subsystem you created in PlanAhead, this is the hardware definition of your file
- zed_blog_0 — This is the board support package created in Part 3 of this mini-series
- zed_blog_C — The C application created earlier in Part 3 (a simple “Hello World” and LED flashing application)
- zynq_fsbl_0 — The first stage boot loader we have just created and modified
As we are creating a “bare metal” application (i.e., no operating system), we need the following files — in this specific order — to create a boot image:
- First-stage boot loader (as created in this column)
- FPGA programming bit file (created in Part 2)
- C application (created in Part 3)
We are now ready to generate the boot image, which can be created using the “Create Zynq Boot Image” option under the “Xilinx Tools” menu as illustrated below
This is where we need to select the ELF files (resulting from the compilation of the software projects) and the bit file for the FPGA as illustrated below
It is important to stress that the FPGA bit file must always follow the FSBL. Clicking on “Create Image” will create *.bin and *.mcs files, which can be programmed into the target device.
On the ZedBoard we have the option of booting from the QSPI (Queued Serial Peripheral Interface) or the SD (Secure Digital) card. I think QPSI is more likely to be used for robust applications than an SD card, so we will store our application there.
The QSPI interface was defined all the way back in Part 2 of this mini-series in the “System Assembly” view of Xilinx Platform Studio as illustrated below (click here to see a larger version of this image); hence, the hardware definition will contain the QSPI IP core and the location in the processor address map at which the QSPI resides.
Connect the ZedBoard to the PC via the JTAG interface and ensure the mode pins on jumpers 7 to 11 are set correctly. Select the “Program Flash” option from the Xilinx tools menu as illustrated below
Navigate and select the MCS file you generated and enter an offset of 0x0 in the dialog box that appears in the middle of the screen as illustrated below
It may take a few minutes for the device to be programmed (and verified if you ticked the “Verify” option). Once the programming is completed, power-down the ZedBoard and disconnect the JTAG cable such that the only connection the board has is the RS232 connection and the power cable. Set Jumpers 7 to 11 to configure from QSPI and power the board back on again. Congratulations! You have now created your very first, standalone, bare metal Zynq application.
If you read this mini-series, you know that I have reached the stage where I have a simple Hello World program running on my Zynq when it is connected to the software development kit. In reality, however, this is not much good. For a real-world use model, we will want to store our software program and configuration bitstream in nonvolatile memory and configure the device following power-on.
But how do we do this? For those used to a traditional FPGA development and configuration flow, this is a little different from what one might initially imagine. In fact, it will take me a couple of blogs to explain it all, but I promise this will be worthwhile, so please bear with me.
Before I jump into the tools and processes you need to follow to create the boot file, I had better explain the basics of the Zynq configuration. In a Zynq system, the processing system is the master and always configures the programmable logic side of things, unless the JTAG interface is used. This means that the processing system can be powered and operating while the programmable logic remains unpowered (unless secure configuration is used).
The processing system therefore follows a typical processor boot sequence, initially running from an internal nonmodifiable boot PROM. This boot PROM contains drivers for the supported nonvolatile memories, along with drivers for the programmable logic configuration. The boot PROM also loads in the next stage of the boot loader, the first stage boot loader (FSBL), which is user-provided. The FSBL can then configure the DDR memory and other peripherals on the processor before loading the software application and configuring the programmable logic (if desired) using the processor configuration access port. The PCAP allows both partial and full configuration of the programmable logic. This means the programmable logic can be programed at any time once the processing system is up and running. Also, the configuration can be read back and checked for errors.
The Zynq supports both secure and nonsecure methods of configuration. In the case of secure configuration, the programmable logic section of the device must be powered up as the hard macro. The advanced encryption standard and secure hash algorithm needed for decryption are located within the programmable logic side of the device.
The Zynq processing system can be configured via a number of different nonvolatile memories (Quad SPI Flash, NAND Flash, NOR Flash, or SD). The system can also be configured via JTAG, just like any other device. Like all other FPGAs from Xilinx (this site’s sponsor), the Zynq uses a number of mode pins to determine crucial system settings like the type of memory where the program is stored. These mode pins share the multiuse input/output pins on the processor system side of the device. In all, there are seven mode pins mapped to MIO[8:2]. The first four define the boot mode. The fifth defines whether the PLL is used, and the other two define the voltages on MIO bank 0 and bank 1 during power-up.
The FSBL can change the voltage standard defined on MIO bank 0 and 1 to the correct standard. However, if you are designing a system from scratch, you must ensure that the voltage used during power-up cannot damage the device connected to these pins.
On the ZedBoards, these mode pins can be changed via jumpers to facilitate configuration from the SD, JTAG, or Quad SPI memories that are available.
In my next blog, I will explain how we use the tools to generate the first stage boot loader and then tie everything together to generate the file required to program the Zynq.
For the majority of this blog, we will be using the Xilinx Software Development Kit (SDK). However, there is one last thing we need to do within PlanAhead first, and that is to export the hardware to the SDK. (Note that we will need to do this each time we make a change to the hardware.)
Actually, it might be worth taking a moment to explain this in a little more detail, because this is the sort of thing that can sneak up and bite you on the bottom later if you don’t fully understand what’s going on, so let’s take a small step back…
As we know, the Zynq-7000 All Programmable SoC powering the ZedBoard is composed of two distinct sections: the programmable logic (PL) section and the processing system (PS) section. What we’ve done in my previous blogs is to define the hardware portion of the system — specifically, we’ve established some simple functionality in the programmable logic that will drive some LEDs in the outside world; we’ve specified what we want to use in the processor subsystem (the ARM Cortex-A9, the DDR RAM, the SPI, etc.); and we’ve set up an AXI bus linking the PS and PL sections. Finally, we’ve generated the configuration bit-file that will be used to set up the hardware portion of the system.
When I say that we need to use PlanAhead to “export the hardware to the SDK,” I’m talking about informing the SDK as to the nitty-gritty details of our hardware configuration, including such things as the address ranges of any external memories and the register maps associated with any peripheral functions and hardware accelerators implemented in the programmable fabric (we don’t have any hardware accelerators at this time, but we may add some later).
OK, so we select the “Export Hardware to SDK…” menu item, as illustrated in the screenshot below.
This BSP will be specific to our hardware implementation. In addition to containing drivers for any of the peripherals we are using, it will also include a number of hardware-specific C header files, such as “xparameters.h,” which defines the memory map of the system along with other system configuration parameters. In the case of our example, when creating this BSP, we must make sure to select the target processing system and CPU0.
Now we are at the stage when we can finally start to create our software project, which will use the imported hardware and BSP, as illustrated in the screenshot below.
For the purposes of my first test case, I decided to create a very simple C application to send a message over the UART to the console and flash a pattern on the LEDs connected to the AXI port in the programmable logic side of the device. In order to do this, I selected the “Xilinx C Project” option, as illustrated in the screenshot below
The next step allows you to name the project and select if you want a basic template for a project. Since none of the provided templates offered what I was intending to implement, I opted to go with a blank template, as illustrated below
My goals for this first project were very simple. As I mentioned earlier, all I want to do is to send a message up to the console and flash a pattern on the LEDs, thereby proving to myself that I know how to get PS portion of the Zynq to communicate with its PL counterpart.
If you are unsure of the peripheral drivers within the system — or if you are not sure how to drive them — take a look at the “system.mss” file under your BSP within the project explorer. This also provides a list of helpful links to documentation and examples.
Next, we need to include a number of C header files that contain parameters and functions that can be used by the software developer. The header files I included in my project were as follows:
- Stdio.h — Defines the standard Input and Output (this should be familiar to anyone who has worked with C).
- Platform.h — Defines basic functions for the implementation and platform initialization and clean-up.
Xil_types.h — Defines a number of types needed for Xilinx IP cores.
- Xgpio.h — Defines the drivers for the AXI bus driving the general purpose input/output (GPIO) module we have connected to the LEDs in the outside world.
- Xparameters.h — Defines the hardware architecture and configuration for this implementation.
With these files included, I next wrote a small bit of C code to achieve my aims (click here to download a compressed ZIP file containing this C source code). Having written our code and having successfully compiled it, we next wish to download the application into our ZedBoard. In order to do this, we first need to create a linker file script that will specify where the executable is placed in the system memory. My program was tiny and would easily fit in the on-chip memory; however, I decided to place my executable in the external DDR memory so as to demonstrate that this interface was also configured correctly. We can create our linker script by right-clicking on our project and selecting the “Generate Linker Script” option, as illustrated in the screenshot below
We’re almost there. The next task we have to perform is to set up the run configurations using “Project Explorer -> Project -> Run -> Run” in the right-click menu. This is where we can define our STDIO connection to the serial port we are using for the STDIO. Once we are happy, we can apply the configuration and then close the dialog. (Do not click “Run” as we are not quite ready for that.) The final stage is to connect the ZedBoard board to our PC using both the UART USB cable and the programming USB cable. We should now be able to program the ZedBoard via the SDK, as illustrated in the screenshot below
Always make one last check that you are using the correct configuration bit-file (which tells you that I’ve slipped up myself on at least one occasion) and then program the device, as illustrated in the screenshot below
Once the configuration has completed successfully, you will see the “Done LED” illuminate on the ZedBoard. Having completed the configuration, you can now download the ELF file and try out your program. Doing this is as simple as selecting your project within the project explorer, right-clicking “Run As,” and then selecting the “Launch on Hardware” option, as illustrated in the screenshot below.
As you may recall, when we last parted company at the end of part 1 in this mini-series, we were just about to create the processing system.
Having clicked on the “Add or Create Embedded Sources” option, you will be presented with the ability to select a name for the processing system you will be creating, Being original as always, I chose to name mine “processor_subsystem,” as illustrated below:
Following this, you will be taken through a number of stages to create a Base System using what is called the “BSB wizard,” as illustrated below:
Next, you will be pseudo-prompted to select the bus structure you wish to use — AXI or PLB. The reason I say “pseudo-prompted” is that you really don’t have a choice here because the PLB option will be greyed out allowing only the selection of the AXI bus, as illustrated below
The next screen will ask you to confirm the version of the development board we are targeting. As I mentioned previosuly, for some reason or other there is no ZedBoard option at this time, so we shall instead target the Zynq ZC702 Evaluation Platform, as illustrated below.
his will result in the opening of Xilinx Platform Studio, at which time you will be presented with a graphical representation of the processing system within the devices. If, like me, you encounter any licensing issues, then please follow the steps outlined here.
At this stage, we have almost completed the implementation of the processing system. However, as I mentioned earlier, we are currently targeting the Zynq ZC702 Development Board and not the ZedBoard we are actually using. In order to correct this we first need to download the appropriate board definition file by clicking here.
Board definition files define how the Zynq’s processing system interfaces to the external world and includes things like DDR memory timing. If you were developing your own design with the Zynq on a custom PCB, this stage could be quite time consuming. Fortunately, the creators of the ZedBoard have already done this for us — thanks to the board definition file we can easily reconfigure the design for the ZedBoard environment. Having imported this file, you should see some obvious changes — particularly in the I/O peripheral column — as illustrated below.
While in the “System Assembly View” window, select the “Bus Interfaces” tab and check that the “LEDs_8Bits” show they are connected to the “axi4lite” bus — that is, they do not show “not connected” — as illustrated below.
Next, click on the “Ports” tab and check that the LED outputs are declared as external ports and are connected to the external pins, as illustrated below.
The final step within XPS is to run a design rule check to ensure we have created a system which complies with the design rules. We do this by clicking the “Project” menu and selecting the “Design Rule Check” item from the resulting options, as illustrated below.
Once everything has checked out, you can close XPS and return to PlanAhead, which we are going to use to generate the RTL netlist, pin constraints, and a configuration bitfile. At this point, we have defined what the processing system will contain:
- The processing system (PS) section with DDR, UART, Ethernet, USB,SD, GPIO, and Flash memory support.
- The programmable logic (PL) section containing one AXI slave connected to a GPIO module interfacing to the LEDs.
The final remaining steps before a configuration bitfile can be generated are to generate an HDL netlist and create a constraints file containing pin-out information for the PL side of the Zynq. This can be generated in either VHDL or Verilog as defined via the project settings. Generating this HDL file is as simple as right-clicking on your processing system name and selecting the “Create Top HDL” option, as illustrated below.
The constraints file can be created within PlanAhead by right-clicking on the “Constraints” option in the source window and selecting the “Add Sources” item. This will allow you to create the file. Within this file you will need to type the following to connect the GPIO slaves in the programmable logic section to the correct IO.
Note that you can obtain the schematics for the ZedBoard, along with a wealth of other information from the “Documentation” area on the ZedBoard.org website.
You can now use PlanAhead to generate the configuration bitstream. In order to do anything useful, however, we will first need to write some software — I will cover this topic in my next column
How exciting! I just took delivery of my very own ZedBoard — a low-cost development board for the Xilinx Zynq-7000 All Programmable SoC (AP SoC).
As I’m sure you will recall, the Zynq itself combines a full hard core implementation of a dual ARM Cortex-A9 microcontroller subsystem (running at up to 1GHz and including floating-point engines, on-chip cache, counters, timers, etc.), coupled with a wide range of hard core interface functions (SPI, I2C, CAN, etc.), and a hard core dynamic memory controller, all augmented with a large quantity of traditional programmable fabric, some programmable analog functionality, and a substantial number of general-purpose input/output (GPIO) pins. In addition to the Zynq, the ZedBoard contains everything necessary to create a Linux, Android, Windows, or other OS/RTOS-based design. Additionally, several expansion connectors expose the processing system and programmable logic I/Os for easy user access.
For my first blogs about the Zynq, I thought would write a simple guide explaining how the design tools integrate and what is needed to get the board up and running with a simple application that can be built upon in both software and hardware terms.
Creating an All Programmable SoC design requires a little more effort than developing a traditional logic-based FPGA design; however, it is still pretty straightforward and the tool chain provides good guidance. To create an All Programmable SoC design, you will need to use, as a minimum, the following:
- Xilinx Platform Studio: This is where you create you processing system, be it a PowerPC, Microblaze, or — in this case — the Zynq’s dual core ARM Cortex-A9. Here you define the configuration, interfaces, timing, and address ranges; everything needed to generate a processor system. The output from this process is an HDL netlist defining your system.
- Xilinx ISE: Most FPGA engineers are familiar with this tool, which takes your HDL design — including the XPS netlist — and generates the required BIT configuration file.
- Xilinx Software Development Kit (SDK): This is where the software that will run on the processing system is developed. To correctly generate the software, the SDK needs to be aware of the hardware configuration of the system.
- Impact: Performs the loading of the BIT configuration bitfile into the system.
All of these tools can be used in isolation to create an All Programmable SoC. Rather helpfully, however, Xilinx PlanAhead is capable of integrating them together, thereby allowing for a much simpler development process. It is using this PlanAhead approach that I will focus upon for the rest of this blog.
Zynq devices are split into two distinct sections: the programmable logic (PL) section and the processing system (PS) section. This blog will predominantly focus on implementing a PS system augmented with a simple logic design within the PL fabric, thereby allowing me to demonstrate an implementation that uses both sections of the Zynq.
The first step in this development is to open PlanAhead and create a new RTL project as shown in the following two images
This is fairly straightforward since — as you initially have no existing RTL, IP, or constraints — you can simply keep on selecting the “Next” option until you reach the “Device Selection” dialog. It is at this dialog that you should select the board option — not the device — and target the Xilinx ZC702 Evaluation board as shown below. Yes, I know that this is not the ZedBoard, but we will return to deal with this point in my next blog
Once the project has been created, you will be presented with the default screen in PlanAhead, at which point you need to add a source to the design. You can do this by selecting the “Add Sources” item under the “Project Manager” options in the “Flow Navigator” area, which should be on the left-hand side of the screen as shown below
As we are currently interested in getting the processing system side of the Zynq up and running, select the “Add or Create Embedded Sources” option as shown in the following image. As we shall see, the general-purpose input/output (I/O) for our programmable logic will be called up here as well
This will open yet another dialog, from which we can select the “Create Sub-Design” button as shown in the image below
OK, we’re almost there. Although this may seem a little complicated, it’s actually pretty easy once you get the hang of it. In my next blog we will complete the configuration and use PlanAhead to generate the bitstream and download it into the device.
One of the many benefits
of the Xilinx® Zynq®-7000
All Programmable SoC is
that it is has two ARM®
onboard. However, many
bare-metal applications and simpler operating
systems use only one of the two
ARM cores in the Zynq SoC’s processing
system (PS), a design choice that can potentially
limit system performance.
Depending upon the application in development,
there could, however, be a need
to have both processors running bare-metal
applications, or to run different operating
systems on each of the processors. For
instance, one side could be performing
critical calculations and hence running a
bare-metal/RTOS application while the second
processor is providing HMI and communications
Thanks to their flexibility and performance,
FPGAs have found
their way into a number of industrial,
science, military and other
applications that require the calculation
of complex mathematical problems
or transfer functions. It is not uncommon to
see tight accuracy and calculation latency
times in the more critical applications.
When using an FPGA to implement mathematical
functions, engineers normally
choose fixed-point mathematics (see Xcell
Journal issue 80, “The Basics of FPGA
Also, there are many algorithms, such as
CORDIC, that you can use to calculate transcendental
functions (see Xcell Journal issue
79, “How to Use the CORDIC Algorithm
in Your FPGA,” http://www.xilinx.com/
However, when confronting functions that
are very mathematically complex, there are
more efficient ways of dealing with them than
by implementing the exact demanding function
within the FPGA. To understand these
alternative approaches—especially one of
them, polynomial approximation—let us first
define the problem.