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.
Over the last few blogs we have written software which runs on the MicroBlaze and reads the XADC, to do this we have not used an operating system instead using a bare metal approach. However as we wish to develop more complex systems, we need to introduce an operating system, so over the next few blogs we will be looking at how we can do just that.
However first I think it is a good idea to talk a little about operating systems and real time operating systems in particular. What differentiates an RTOS from a generic operating system? An RTOS is deterministic, that means the response of the system will meet a defined deadline.
But does the system have to always meet these deadlines to be classed a real-time system?
Actually, no it does not.
There are three RTOS categories that address deadlines differently:
Hard RTOS – Missing a deadline is classified as a system failure.
Firm RTOS – Occasionally missing a deadline is acceptable and is not classified as a failure.
Soft RTOS – Missing a deadline simply reduces the usefulness of the results.
An RTOS operates around the concept of running tasks (sometimes called processes). Each of these tasks performs a required system function. For example, a task might read data from an interface or perform a calculation. A very simple real-time system may use just one task, but it is more likely that multiple tasks will be running on the processor at any one time. Switching between these tasks is referred to as “context switching” and requires that the RTOS saves the processor state for each task before the context switch starts the next task. The RTOS saves this processor state on a task stack.
Determining which task to run next is controlled by the RTOS kernel and this decision can be complicated—especially if we want to avoid deadlock where tasks lock each other out—but the two basic decision methods are:
Time sharing – Each task gets a dedicated time slot on the processor. Tasks with higher priority can have multiple time slots. Time slicing is controlled via a regular interrupt or timer. This method is often called Round Robin scheduling.
Event Driven – Tasks are only switched when a task finishes or when a higher priority task must be run. This method is often called pre-emptive scheduling
When two or more tasks want to share a resource— the XADC for example—it is possible that the tasks might request the resource at the same time. Resource access needs to be controlled to prevent contention and this is one of the operating system’s most important duties. Without the correct resource management, deadlock or starvation might occur.
Here are the definitions we’ll use for deadlock and starvation:
Deadlock – Occurs when a task holds a resource, cannot release it until the task completes, and is currently unable to complete because it requires another resource currently held by another task. If that second task requires a resource held by the first task, the system will never exit this deadlocked state. Deadlock is a bad situation for an RTOS to find itself in.
Starvation – Occurs when a task cannot run because the resources it needs are always allocated to another task. The task starves because of a lack of resources.
As you can imagine, much has been written on the subjects of deadlock and starvation over the years and there are many proposed solutions. For example, there’s Dekker’s algorithm, which was the first known correct solution to mutual exclusion. It is a shared-memory mechanism that does not require a special “test and set” instruction (but is therefore limited to managing two competing tasks) and is attributed to the Dutch mathematician Theodorus Dekker. The most commonly used method to handle deadlock is the use of semaphores, which commonly come into two types: binary semaphores and counting semaphores. A binary semaphore controls access to one resource—for example a hardware resource. Counting semaphores control access to a pool of identical, interchangeable resources such as memory buffers.
Typically each resource has a binary semaphore allocated to it. A requesting task will wait for the resource to become available before executing and once the task completes, it releases the resource. Binary semaphores commonly use WAIT and SIGNAL operations. A task will WAIT on a semaphore. When the resource is free, which could be immediately (or not), the operating system will give control of the resource to the task. When the task completes, it will SIGNAL completion and free the resource. However, if the resource is occupied when the task WAITs on the semaphore, the operating system suspends that task until the resource is free. The WAITing task might have to wait until the the currently executing task is finished with the resource or the WAIT might take longer if it is pre-empted by a higher priority task.
Introducing the concept of task priority also brings up the problem of priority inversion. There is a more flexible class of binary semaphores called mutex’s (the word “mutex” is an abbreviation for “mutual exclusion”) and these are often used by modern operating systems to prevent priority inversion.
Counting semaphores work in the same way as binary semaphores however they are used when more than one resource is available—data stores for instance. As each of the resources is allocated to requesting tasks, the count is reduced to show the number of free resources remaining. When the semaphore count reaches zero, there are no more resources available and any processes requesting one or more of these resources after the count reaches zero will be suspended until the requisite number of resources is released.
Tasks often need to communicate with each other and there are a number of methods to accomplish this. The simplest method is to use a data store managed with semaphores as described above. More complex communication methods include message queues.
When using message queues, a task that wishes to send information to another task POSTs a message to the queue. When a task wishes to receive a message from a queue, it PENDs on the queue. Message queues therefore work like FIFOs
Over the next few blogs we will look at using FreeRTOS and Micrium uc/OSiii
This is the last Arty blog of 2015 , so have a Merry Christmas and and a Happy New Year.
One of the most common uses of the XADC is for health monitoring of the FPGA and the wider system to that mind the XADC has a number of useful features which can be used.
- Trigger and Reset Threshold Alarm registers for the Internal voltages and temperature parameters
- Over Temp Monitoring – Maximum junction operating temperature allowable for the device – Auto shut down is possible.
- Maximum and Minimum values – Registers which contain the lowest and highest sampled values for each of the voltages and device temperature.
These three elements make for a very useful health monitoring system, of course the alarms and the over temperature must be correctly configured and enabled first. This can be achieved in one of two ways, either via the XADC wizard within Vivado or via our software application.
There are seven possible alarms we can configure on the XADC, however we cannot use all of them on the Artix Silicon as some alarms as dedicated to the Zynq (Alarm 6 Vccddro, Alarm 5 Vccpaux and Alarm 4 Vccpint). There is also an eighth alarm bit which is the logical OR of the seven alarm bits and acts as an overall alarm.
We can see if an alarm has occurred via either the Alarm Status Output Register or configure an interrupt to occur should an alarm condition occur such that it can be immediately dealt with.
These trigger and reset values allow us to define values which align with our worst case analysis of supply voltages and junction temperature, ensuring we can protect the system properly.
Each alarm also has an associated output which can be used in the wider system either to indicate via a LED a issue has occurred or to take further action e.g. graceful system degradation.
The over temperature alarm is slightly different in that it can be configured to trigger an automatic shutdown of the device. To set automatic shut down the four LSB’s of the over temperature register must be set high. Doing this means that 10 ms after the trigger level is reached a shut down occurs. This prevents re -configuration of the device until the reset level is reached.
It is intended that the temperature alarm is used to act as a pre-warning that the temperature has exceed what the design has calculated as its maximum. This way the system can take action to prevent the shut down e.g. turning on fans, reducing processing etc.
While the maximum and minimum registers provide the system with a simple methodology of quickly and easily checking the worst case values as currently observed by the system during its period of operation. These registers can also be of good use in system commissioning to record supply voltages and temperatures across worst case environmental conditions for example.
There is also one last issue which must be addressed when using the XADC on the Arty board and that is we need to correctly set up the board to use the internal VRefp. Failure to do this results in a inaccurate conversions. The Arty board is configured such that you can use either the internal or external reference.
We can ensure the internal reference is used by grounding the XADCVREF input, as such the internal reference will be used. This can be confirmed by reading the flag register which also helpfully contains information on any alarms as well
With the XADC configured to correctly monitor the internal signals with suitable alarm levels we can look at how we can use the XADC to receive analogue signals from the real world
When we left the hardware build we had just exported the HDF and bit file to SDK, initially this will have exported the required information to a directory local to the Vivado project.
With the project exported we can close down Vivado and open SDK, if this is the first time you have opened SDK you will be asked for the workspace you wish to use. The workspace is the area where your projects and associated software projects like Board Support Packages (BSP) and copies of the hardware definition will be stored.
Within SDK to get this up and running we need to do the following
- Create a hardware definition project
- Create a Board Support Package for the hardware definition
- Create our application – in this case a simple hello world
- Build the application – this is the simple part
- Define the debug environment such that we can run the application on the Arty board over the JTAG link.
The first step is to import the hardware definition we just exported from Vivado to do this select file->new-> other from the SDK menu this will open a dialog box, beneath the Xilinx folder as shown below select new Hardware Platform Specification
On the next dialog box enter your project name, I always prefer to call it project_HW to be clear what it is and browse to the directory within your Vivado project which contains the HDF file. Note this is within the .sdk folder under your Vivado project.
This will create the hardware specification which, will appear under the project explorer on the left side of SDK, as shown below (this does show all three of the elements we need to create a project)
We are now in a position that we can create a BSP for the hardware platform, this contains the drivers necessary for the hardware. We can create the BSP by selecting file->new->board support package this will open a dialog box like below
Enter a project name, notice how it has picked up the hardware platform we just created, for this example we will use the standalone operating system.
This will a settings pop up for the BSP there are no changes we need to make here but this is where we can add in additional options if needed e.g. light weight IP stack etc
We can also on the standalone page select the stdin and stdout for the compiler make sure this is set to uart lite as below.
With this verified you can close the BSP settings and you will see a progress box appear while the software generates the BSP files for your system.
At this point we can then create our application, for this example I am going to use the simple hello world template. We can create the application project by selecting file->new->application project this will open a dialog box where we can select the BSP we previously created the hardware definition and the processor we are targeting (in this case there is only one)
This will create a simple application which will output hello world over the USB-UART, selecting build all will then enable us to build the BSP and the application project such that we get an ELF file which can be downloaded and run on the hardware. The project is built using the project->build all settings and you will see the ELF file appear under your application project as below
The next stage is to run it on the Arty board, this requires that we remove the jumper on J1 on the arty board such that we do not load the design example already loaded within the QSPI flash.
To run the example we need to do the following
- Programme the FPGA
- Download the ELF
Before we can download the ELF we need to create a debug environment such that when we click on it we can download the elf. To do this right click on your application project and select Debug As -> Debug Configurations as below
This will open a dialog box where we can create a new debug environment, we wish to create a new GBD debug application
One you have selected new you will see the dialog box below, you should only need to change the information on page one (most should be auto populated)
Provide a name and If not selected select the Rest Processor from the drop down menu close to the bottom, we also need to click on the Debugger applications tab and uncheck the option ”stop at main() when debugging” this ensures the application will run automatically on download finally then click on apply not debug and then close.
With this completed it is time to connect the arty board to the USB of your PC, this will auto detect and install any software required when it is completed we can progress and test our application. Note it should only ever need to install once.
The first thing to do is programme the FPGA we do this under the Xilinx Tools -> Programme FPGA which will open the following dialog box (you should not need to change anything)
Click on program and you will see the FPGA is programmed, you can confirm this on your Arty board as the done LED will illuminate green.
We are now ready to download our ELF file, click on the bug icon on the top menu and this will use the debug configuration we just created to download the application
Once downloaded you will notice the software runs and the message “hello world” will appear in your chosen terminal programme.
You can find part one here
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.