Showing results for 
Search instead for 
Did you mean: 

Booting a PL design from a PS-attached SPI flash in Zynq UltraScale+ devices

3 0 1,231


In Zynq UltraScale+ boards such as the Zynq UltraScale+ MPSoC ZCU102 Evaluation Kit, the QSPI Flash is connected to the PS portion of the device and does not have a direct physical connection to the PL side.

In such configurations, it is not possible to write a bitstream (.mcs file) directly to the flash via the Hardware Manager. In fact, when attempting to configure the bitstream to be loaded via QSPI, Vivado will only make the Boot via JTAG option available, as it knows that there is no flash available in the PL.

In order to configure and boot such devices via Flash, the PS portion of the device must be booted (even if it is not desired or will not be used in the actual project), in order to allow the bitstream to be transmitted from the Flash to the PS and to reach the PL through the MIO pins.

The process consists of creating a new Zynq MPSoC project in Vivado Block Design (or adding this block to an existing design) in order to include the PS in the project, and using the SDK to create a First Stage Boot Loader (FSBL) for the PS, an optional PS application, and finally creating the flash image which will contain the boot files for both the PS and PL.

The Vivado Design

In this example we are using a ZCU102 board and Vivado 2018.3. The process should be nearly seamless for any other type of board with a Zynq UltraScale+ device and a flash memory connected to the PS portion of the board.

If you already have a Vivado design that you wish to program into the PL side, open that project in Vivado.

In this example, we are using a Verilog design called gpio_leds, which receives a signal from a button connected to one of the PL GPIO pins and lights up an LED, which is also connected to the PL GPIO pins.

The two images below demonstrate the initial design sources and a schematic of the PL design:


In your current Vivado design, on the left-hand--side menu, click on Create Block Design. An empty canvas will be shown.

You will observe that on the Sources tab we now have a file named set as the top file.

We will start by adding the PL design into the block design canvas.

To do so, right-click on the Verilog file and select the option “Add Module to Block Design”.



The following block will be added to the canvas:


Although the Verilog file had already specified the module input and output ports, we will now need to associate these ports to physical FPGA pins. Right-click on each of the I/O pins in the module and select the option “Make External”.


The end results should be as follows:


Next, we need to add a Zynq MPSoC block so that we can include the PS in the design. This will allow the flash memory to be read by the PS and transferred to the PL.

Click on the “+” button, search for the IP Zynq UltraScale+ MPSoC and add it. The following block should be added to the canvas:


Observe that on the top of the canvas, Designer Assistance is now available.


Click on Run Block Automation, accept the presets suggested and click OK. This will configure the PS with the standard drivers and resources required for most applications, including the drivers and configurations for QSPI flash access.

In this design, we are not interested in having any communication between the designs/applications in the PS and PL, only the transference of files from the Flash memory. Therefore, we will disable all of the AXI, clock, and reset ports between the PS and PL.

Double click on the Zynq Block Design. In the configuration window, observe that several boxes are already check-marked, including the GPIO and QSPI block, which are required for this project.


On the left menu pane, click on PS-PL Configuration, expand the PS-PL interfaces and uncheck the boxes AXI HPM0 FPD and AXI HPM1 FPD.


Under General -> Interrupts, uncheck the box for Fabric Reset Enable.


Under General -> Interrupts -> PL to PS, set the IRQ0[0-7] to zero.


Finally, Under Clock Configuration -> PL Fabric Clocks, uncheck the box for PL0.


Click OK to update the Zynq UltraScale+ block. It should now be displaying no Input or Output ports.


At this point, the design is finalized. Before proceeding, click on the Validate Design button to have Vivado check if any connections were missed or misconfigurations were made. If all of the configurations were correctly made, a Validation Successful message is issued.


In the Sources window, right-click on the file and select the “Create HDL Wrapper” option.



As an add-on to allow us to verify the internal workings of the gpio_leds.v design, an Integrated Logic Analyzer (ILA) will be introduced in the project.

In the Flow Navigator, click on “Run Synthesis”. This process might take a few minutes to finish. Once completed, click on "Open Synthesized Design". If necessary, on the top-right corner, change the canvas view to "Debug" and the following schematic should be displayed:


Right-click on the nets GPIO_SW_C_0 and GPIO_LED_0_0 and select the option “Mark Debug”. This will flag these nets and facilitate their connection to ILA probes.

In the Flow Navigator, under Synthesis, click on “Set Up Debug” to launch the wizard. Note that the two nets from the previous step are now available to be connected to the ILA.


If the nets are flagged with undefined clock domain (as in the image above), click on the “more info” button, select “assign All Clock Domains” and in the new pop-up window, select the options as in the image below:


All of the nets should now have an assigned clock domain. Select both nets and click on the Next button. We will leave the other ILA options at  their defaults. Proceed to click Next and Finish to finalize the ILA insertion.

The schematic will be updated with the inclusion of the ILA. (closing and re-opening the synthesized design might be required to generate an updated schematic). Click the save button before proceeding.


In the Flow Navigator, click on “Generate Bitstream”. When prompted, allow Vivado to Run the Implementation.

Once the Bitstream has been successfully generated, we need to create the Hardware Description File (.hdf) which describes the hardware resources that were just built and will be used by PetaLinux to create a PS project.

To do so, Click on File -> Export -> Export Hardware. Make sure to mark the “Include Bitstream” box when prompted.


A file named design_1_wrapper.hdf should be present in the <project_name>.sdk directory within your Vivado Project.

Finally, select File -> Launch SDK.

At this point, SDK will be open and will read in the .hdf file. After a few seconds, the SDK should be loaded in a format similar as the one in the image below.


Leave the Vivado project open in the background. It will be used latter in this tutorial.

The SDK Project

With SDK open and the hardware definition file loaded, it is now possible to create a First Stage Bootloader (FSBL) to initialize the PS resources and an application for the A53 processor.

Click on File -> New -> Application Project. This will allow us to create a First Stage Bootloader (FSBL) to boot the PS.

Create a project named fsbl, click next, select the Zynq MP FSBL template, and click finish.

23.png  23_2.png

It will take a few minutes for this process to complete (keep an eye on the lower right corner for the percentage completed).

When the process above is complete, once again click on File -> New -> Application Project.

Create a project named hello_world, click next, select Hello World template, and click Finish.

24.png  24_2.png    

Again it will take a few minutes until this process is done.

When the process above is complete, the Project Explorer Tab should look like the image below:


Click on the my_hello_world project so that it is highlighted in blue and on the top menu, select Xilinx -> Create Boot Image.

It will open the Create Boot Image Wizard and will have pre-loaded all of the required files to boot both the PS and PL, in the correct order.

As we can verify in the image below, the boot image will contain an FSBL image to boot the PS, followed by the bit file to configure the PL, and finally the Hello World application files for the A53 processor.


Click on Create Image.

Once the image has been created, connect the ZCU102 board to your computer using two Digilent USB cables. Make sure to connect to both the JTAG and UART ports in order to be able to verify that the A53 application is running.

In addition, make sure that the board configuration pins are in JTAG mode (SW6 in position 1111 for the ZCU102).

On the top bar menu, select Xilinx -> Program Flash. Fill in the information for the BOOT.bin image file that was created in the previous step (it should be located inside the folder .sdk/hello_world/bootimage). In addition, add the location for the FSBL file fsbl.elf (it should be located inside the folder .sdk/fsbl/Debug).

Finally, make sure to select the correct Flash Type. For the ZCU102, it is QSPI x8 Dual Parallel. If you are using a different board, you will need to check its datasheet for the correct QSPI configuration.


Click on Program.

On the SDK console at the bottom of the screen, it is possible to verify the progress and status of the Flash configuration. The programming process can take several minutes to finish and, if successful, should output the following message:


ZCU102 Booting

The flash is now programmed and the ZCU102 is ready to boot. Power off the board and set the Boot Mode Pins (SW6) to QSPI, which is 1011.

Using TeraTerm (or your preferred terminal application) connect to the Serial Port COM5. Once connected, change the connection baud rate to 115200. Power on the ZCU102 and observe the TeraTerm window, where the First Stage Boot Loader and the A53 Hello World application should be initiated.


Connecting to the Hardware Server and verifying the ILA

If the programming was successful, the PL side of the Zynq UltraScale+ device should now be configured with the design previously created in Vivado. To verify the configuration, we will connect to the board using the Hardware Manager and verify if the ILA is functional and can collect data on the probes.

In Vivado, on the left hand side menu, click on Open Hardware Manager. Select Open target -> Open New Target -> Connect to Local Server. Verify that the ZCU102 (or your Zynq UltraScale+ device) is available for connection. Click Next to complete the connection.


Under the Hardware tab, the ILA should be visible and the ILA Waveform canvas should be loaded automatically.

Click on the ILA Trigger Immediate button to have the waveform canvas filled with waveforms and to confirm that the ILA is functional.