Objective: This three-part series is focused on creating a custom Embedded Linux image for a Zynq MPSoC based board. The board utilized here is the Ultra96 v2 from Avnet. Nevertheless, the steps followed can easily be applied to other Zynq UltraScale+ MPSoC boards such as the Xilinx ZCU102 and ZCU104.
Recommended Prerequisite articles to read:
- Ultra96-V2 Vivado and Vitis Development Workflow
- Vitis and Vivado 2019.2 Installation on Ubuntu 18.04 LTS
Successfully bringing up Xilinx boards with a custom PL hardware design and custom Linux OS can be a daunting task with numerous potential break points. There are many fragmented pieces of information online regarding this task and sometimes this information can be overwhelming. This series hopes to put into perspective a comprehensive flow on how to accomplish such a task and to present two main ways of building a custom image for the Zynq device.
Whilst there are possibly more ways to build a custom OS for Zynq UltraScale+ MPSoC, I will focus on two main approaches. One of them is to use a Xilinx tool called Petalinux to configure and build your custom image targeting Xilinx devices. Since this tool has been developed by Xilinx themselves, it has been greatly customized to handle virtually all the edge cases that you may encounter in creating a custom image for a Xilinx device. This includes a GUI that eases the selection and inclusion of different image features, packages and settings. Whilst this highly configurable setup may appeal to some, it can prove a mouthful for others.
It locks you into a Xilinx-specific flow that can curtail your freedom in utilizing the full spectra of open source embedded Linux development. Hence the other method I will be presenting is the Yocto tool/approach. This gives you lower level custom configuration options that aren’t limited and abstracted by Xilinx tools. In my opinion, Petalinux is to FPGA embedded Linux what Arduino is to Microcontroller programming. Nevertheless, both Yocto and Petalinux flows can be used together for a more effective development flow as I will present in the third part of this series.
Programmable Logic Hardware Design
This stage is common to both ways. Recall that the Zynq MPSoC board is different from Single Board Computers such as the Raspberry Pi in that the former contains a PL system (FPGA) part. Therefore, we need to define what logic is present in the PL fabric before we can build an OS for it. In essence, the Zynq hardware is not yet complete in a way; and that is the whole point of the Zynq UltraScale+ MPSoC devices. It allows us to customize the device not only at the software level but significantly at the hardware level as well. Xilinx provides the Vivado Design Suite to configure the PL hardware part of the Zynq MPSoC. This flow was presented in the earlier Ultra96-V2 Vivado and Vitis Development Workflow tutorial.
For purpose of completeness, I will present the hardware configuration in Vivado. These steps have also been covered at length by Adam Taylor in this tutorial.
1. Configure the project in Vivado
Create a new project and select the Ultra96 board as the platform for development as shown below. If the board is not in the list of boards, follow my tutorial here to include it. This will be the case if it’s your first time to use the board.
2. Block Design
In the Vivado environment, create a block design where we will incorporate various IPs.
In this particular series, we are interested in a minimum hardware design upon which we can successfully run a custom Linux Operating System. In more advanced applications, there will be additional IPs instantiated that fulfill the project’s requirements. For our minimum system however, the following are the IPs we will be instantiating.
i) Zynq UltraScale+ MPSoC
This can be confusing as one may think the physical Zynq device on the board is empty. However, the PS and a few peripherals have already been instantiated in the device from factory. MPSoC IP in Vivado is generally to give a visual overview of the interaction between the PS and PL systems. It also offers GUI to adapt various configurations for the PS and PL. Most significantly however, is that this IP allows us to incorporate / instantiate other IPs into the PL fabric.
ii) Clock Wizard
The clock wizard core generates RTL code to implement the desired clocking network and circuit. We will configure 5 clock outputs that will provide frequencies ranging from 100 MHz to 600 MHz. It is worth noting here that all these clocks are not really necessary. Nevertheless, this gives us flexibility in deciding the frequencies under which the board will run.
iii) Processor System Reset
This soft IP handles system reset requirements including Power On Reset generation and sequencing of reset signals coming out of reset. For proper functioning, each of the clock outputs instantiated in the clock wizard need an associated reset. Hence we will instantiate 5 processor system reset IP cores, one for each of the clock outputs.
3. IP Connections
The connection automation should be run with the following selections that match the slowest sync clock of each of the reset blocks with one of the clocking wizard clocks.
The dcm_locked inputs on the reset blocks should be connected manually to the clocking wizard locked output as shown below:
We need to connect to the Zynq MPSoC IP interrupt port via a Concat IP. The idea behind this is that the interrupt controller (GIC) takes a bus as its input. The Concat is a general purpose block that combines multiple inputs into single bus outputs; in this case it concatenates the individual interrupt signals into the bus. Since we don’t actually have any interrupt to feed into the MPSoC interrupt port (ps_pl_irq), we provide a single input concat block that we leave unconnected at its input. This is just (a dummy?) to ensure that bitstream is generated without any errors.
4. Design validation and Bitstream Generation
Validate the block design to check for critical warnings and errors.
If the block design validates without errors, proceed to create HDL wrapper and generate the bitstream.
Once the bitstream has been generated, export the hardware design so that we can use it as the base in the custom Linux image creation. This will be covered in the next article.