Note: This is part 3 of a series on working with FPGAs and in particular the Xilinx Zynq-7000S Programmable System-on-Chip with ARM Cortex-A9 processing core.
For all parts, click here: Path to Programmable
For part 1, click here: Xilinx ZYNQ System-on-Chip - Getting to know the MiniZed Board
For part 2, click here: Xilinx ZYNQ - Blog 2 - Getting Code Running on the SoC
- Establishing a Design Process/Work Flow
- Configuring SPI Flash and USB
- Configuring eMMC (SDIO)
- Configuring Clocks for Peripherals
- Creating HDL Wrapper and Bitstream File
- Export Hardware and Launch the Xilinx SDK
- Creating and Running Example Application Software
- Running Memory and Peripheral Tests
The is a compact board containing a Xilinx Zynq-7000 series chip. This contains programmable logic (PL) functionality like any FPGA, as well as an ARM Cortex-A9 applications processor system (PS), all on the same chip. To complete the design, the MiniZed also contains memory chips on-board as well as various connections to the Zynq chip, such as USB, and Arduino headers.
This blog post documents my progress with training from element14 and Avnet, and shows how to get the Zynq chip (or system-on-chip or SoC) ARM processor configured and running sample code. No prior knowledge is needed, so if you have a MiniZed board, then it could be worth following along, there is plenty of material being blogged by the first Path to Programmable team!
Establishing a Design Process/Work Flow
To make use of the Zynq chip, it is necessary to configure it so that the processor system knows about what speed memory chips are connected to it, and bring out any peripherals (such as I2C) out of the chip on selected pins. All of that was covered in the previous blog post 2, which got to the stage that the ARM processor was successfully booted up and was able to use the serial UART peripheral to print Hello World messages over a FTDP chip USB UART connection to a PC.
This was great, because it showed me that the overall process looks currently something like this:
As the labs progress, this diagram may be tweaked to incorporate all the extra stuff. But for now, it is the minimal stuff needed to get the MiniZed up and running with functioning application code.
Starting from top-left and working down and to the right, the process starts off in the Vivado Design Suite, by creating a project, adding the processor system and then configuring it and any peripherals. Next, a HDL wrapper file is created for it, and then some files that describe the processor configuration detail that will be needed when the processor is powered on, to bring it up. Once all this is done, an application software development environment (called Xilinx SDK) is launched and the software developer is responsible for creating the board support package (which can act as a BIOS or real time operating system), create and compile an example project, and then push it into the MiniZed board for execution.
The diagram above can act as a quick reference, and the detail for each step is described in blog 2.
This blog post now covers how to configure additional peripherals for the processing system. As expected from the diagram above, most of the work will be done in the green area.
Configuring SPI Flash and USB
After opening up Vivado Design Studio and opening the project created in the last blog post, I moved onto the green area of the design process shown above, and configured SPI Flash and USB peripherals. The steps are in the diagram below if you want to follow along with a MiniZed board.
As can be seen, the main task is merely to enable these peripherals by checking the boxes for them. But there is also some mapping that needs to be done, to bring out the peripheral connections from the processing system out onto real pins on the Zynq chip.
The way the mapping works is described in some comments underneath blog 2. In short, the connections can come out of the processing system and be connected to dedicated pins called MIO (Multiplexed Input/Output). By doing that, the system behaves like any other typical ARM applications processor where one needs to perform some pin mapping based on what peripherals are desired, and what connections are allowed (because the multiplexing hardware and pads on the chip only provides finite combinations). For instance, Texas Instruments calls the process Pin Multiplexing, and the tool for their ARM processor chips has a similar concept, where peripherals can be selected and then the valid pin possibilities can be viewed to select specific pins.
The Zynq chip has some pins dedicated to MIO. But it is also possible to internally divert the connections to an area known as EMIO (Extended Multiplexed I/O) and from there the programmable logic portion of the chip can connect to it, or interconnections can be made to pins as available to the programmable logic.
The information to figure out which pins are available for which peripherals, and where these pins physically are located on the Zynq BGA package, and where they are wired to on the MiniZed board, is all described in the comments section in blog 2.
The settings in the screenshot above, show SPI Flash is mapped to pins MIO 1..6 and MIO 8, and USB is mapped to MIO 28..39.
These pins can be verified in the MiniZed schematic – MIO8 is part of the boot mode selection (and it pulled down), and is not shown in this snippet from the full MiniZed schematic:
The SPI Flash chip offers 128Mbit of NOR Flash storage, and it could be used for booting the Zynq chip if desired.
The USB schematic (based on USB3320 chip) is shown below.
Configuring eMMC (SDIO)
A few more clicks enabled the larger 8Gbyte Flash memory eMMC chip on the MiniZed board. It has an SDIO interface. This memory could be used to store the operating system and application software if desired. The schematic shows the relevant MIO pins:
The first step in the screenshots below shows how to enable the SDIO capability and the pin mapping. The clock detail is described next.
Configuring Clocks for Peripherals
Most chips that interface to the Zynq will have data buses synchronised with a clock pin. Different devices have different clock requirements. In blog 2, the processor system inside the Zynq chip was configured to run at a particular speed, and the external DDR memory clock was configured too, to have a minimal functioning system. Since more peripherals are now configured in this blog post, the clocks for them need configuring too. The steps to do that for the SPI and SDIO interfaces (used for the 128Mbit NOR Flash, and the 8Gbyte eMMC Flash respectively) are configured as shown in a couple of the screenshots above.
The SPI interface can be clocked to beyond 100MHz for the particular memory chip that is used on the MiniZed board, but the configuration is set to 200MHz because according to the PDF Zynq-7000 SoC Technical Reference Manual UG585 (in section 12.4.1), the clock is divided internally by a configurable value of at least 2 (the precise divider setting is set in a register, as part of the software board support package that is created using the Xilinx SDK just prior to writing the application code).
The SDIO speed is set to 25MHz, because the eMMC chip supports up to 26MHz in one mode (it also supports 52MHz, but I don’t know enough to be sure if that clock speed would work).
Some processor logic (PL) fabric clocks were also set, but disabled, and more about these will be explored in later labs – they are currently unused for the purposes of this blog post.
Creating HDL Wrapper and Bitstream File
We’re now in the center blue territory in the Design Process diagram shown at the beginning of this blog post.
Although in the previous blog post, the HDL wrapper was created by right-clicking on the source ...bd file and selecting 'Create HDL Wrapper', this time it just needs updating. To do that, this time Reset Output Products is selected followed by Generate Output Products, as shown in the screenshots below. The bitstream is generated in an identical manner as before. All the relevant steps are in the screenshots here. The bitstream generation takes a few minutes (some progress information is shown on the top-right of the Vivado Design Suite).
Just for interest, the Z_system_wrapper.vhd file didn’t actually change from the previous blog post, even though this time we added extra peripherals. This is because the wrapper file defines the entire MIO pins as part of the entity declaration and architecture body to be of type STD_LOGIC_VECTOR (31 downto 0) and doesn’t show the detail.
Export Hardware and Launch the Xilinx SDK
These are the last couple of stages before the software developer can start working on the project. The steps are very similar to those in Blog 2, except that this time a new folder is created for the files to be exported into, and the software development environment (Xilinx SDK) is invoked to use that folder for the software projects.
Creating and Running Example Application Software
We’re now in the red area in the Design Process diagram at the start of the blog post.
In order to create applications, first the board support package (BSP) needs to be created as before. This will take the files that were exported from Vivado, and combine them with a minimal BIOS or operating system software, to support running the user’s application code. The support includes things like setting up registers to enable peripherals, and providing serial UART console input/output functions so that C printf statements can be successfully used for instance.
It uses the File->New->Application Project wizard to create an example Hello World application in C.
The only difference was that in this case I entered a name Hello_World_lab3 in the Project Name field, to keep it separate from the blog 2 code. The project successfully ran (connect up the MiniZed, create a debug configuration, and run the project identically as described in blog 2).
Running Memory and Peripheral Tests
There was no need to type any code to test the memory and peripherals; the Application Project wizard was re-used, only this time instead of selecting Hello World for the sample code in the wizard, Memory Tests or Peripheral Tests was selected. A new project name was given for the code too.
Running Memory Tests
When the Memory Tests sample code was run, I observed this output to the console (via the serial, i.e. UART connection from the Zynq processor, over the USB JTAG+UART connector):
The output shows that a total of 511Mbytes of DDR RAM was tested (the lower 1Mbyte out of the 512Mbytes total was not tested) and it passed using various access methods. Next, some 64kbytes of some other RAM was tested, but I’ve not explored the memory addressing much yet. It is possibly internal RAM for the Cortex-A9 processor.
The actual algorithm used for the memory tests is part of the board support package; the sample Memory Tests app is calling memory test functions from the BSP.
Running Peripheral Tests
The Peripheral Tests code output is shown below:
Much like the memory tests, these peripheral tests also call functions from the BSP in order to perform the tests. For example, the QspiPsSelfTestExample output on the console refers to a test where the SPI peripheral was tested by reading and writing an internal register, to prove that the peripheral was correctly connected and functioning.
These test functions are really important for verifying that a board is functioning correctly. For a real-world scenario, diagnostics code could be written, extended from the sample code. It would do things like exercise the memory and peripherals inside the chip as well as external chips. Such code is handy for many tasks. As one of my first jobs, I had to test mobile phone base-station cards, and create diagnostics capability (not on a Zynq SoC at the time, but on a processor on the board). I used it to run extended diagnostics while the board was temperature-cycled in an oven, to see if/when failures occurred, to reduce failure rates in the field (it’s not always easy to access mobile phone base stations for repair!). In the case of the Zynq, the wizard is doing half the job, creating nice sample code!
The lab exercises this week allowed me to consolidate the learning so far, and an approximate Design Process chart was created, which will be improved/added to over time.
Additional peripherals were added to the Zynq SoC, and this time less ‘magic numbers’ were needed, since time was spent exploring datasheets and delving into code. There is still plenty to learn though, since this is a fairly massive exercise to familiarize with a SoC with an applications processor and programmable logic from scratch. I’m sure bringing up any typical single board computer (SBC) could have taken weeks to get this far – whereas with the training the we’ve all been able to achieve it extremely rapidly so far.
The training material was still good in week 3, and I look forward to continuing with it all.
Thanks for reading!