One of the great things about many of the Zynq SoC’s PS (processing system) peripherals is that we can break them out via the PL (programmable logic) I/O. This capability provides us with great flexibility at the system level as we can implement more peripherals than can be supported over the Zynq SoC’s MIO on its own. However, during the years of writing the MicroZed Chronicles, I have been asked questions by a few readers’ about mapping from the PS to the PL I/O using EMIO and how to map when using PS GPIO. So in this post, I am going to address those questions and provide a nice simple reference for how to do it.
We can break out many of the PS peripherals into the PL using EMIO. The exceptions are the USB ports, the SMC (static memory controller), and the QSPI Flash controller. There may be some performance degradation when the EMIO is used. For example, SDcard controller I/O operates at 50MHz when routed to the MIO and 25MHz when routed to the EMIO.
Peripheral and Routing to the EMIO
When we route signals to the EMIO, we will see the appropriate port appear at the top level of the Zynq IP block within Vivado. To enable these signals, we need to configure the SPI to use the EMIO, which is done on the MIO configuration tab of the Zynq IP Configuration Wizard. We can enable the SPI and from the IO drop down select EMIO. This will create a SPI port at the top level of the design.
Selecting the EMIO for SPI
Resultant SPI port on the Zynq Block with port added
We can then use the standard XDC constraints file to route the I/O to any of the PL pins as we would for a normal element within the PL design.
Where it gets slightly more complicated is when we are using the GPIO and decide to extend that using EMIO. Suddenly, we need to understand GPIO banks and GPIO Numbers and IO pins.
The Zynq-7000 series provides 54 GPIO signals in two banks dedicated the MIO (although if you use all 54 pins you cannot use any other peripherals). These banks consist of a 32-bit bank 0 and a 22-bit bank 1. Additionally, there are also two EMIO-only banks. Both are 32 bits wide. Within the EMIO, these banks provide 64 inputs, 64 outputs, and another 64 output enables that can be used as outputs, giving us a total of 192 I/O signals (64 Inputs, 128 Outputs).
These GPIO signals are numbered from 0 to 53, for banks within the PS MIO, and 54 to 117 for GPIO within the EMIO region. When we break these signals out into the EMIO, the Zynq IP block will show them on the Zynq IP block. Note that GPIO 0 on the Zynq port is Pin 54 for the ARM cores. These IO signals can then be routed to the PL IO as we would any other signal and tied to a specific IO pin and standard using the XDC file. The diagram below shows the relationship between the different elements:
It does get slightly confusing however when we use software to drive the GPIO signals within SDK. To drive the desired GPIO pin, we must use either the bank or the pin number. For GPIO signals, the pin numbers range from 0 and 53. For the EMIO signals, pin numbers range from 54 to 117. Once we understand this and that we route the signals in the PL just like we do any other signal, we can quickly use the EMIO using the XGPIOPS library provided with the BSP.
Hopefully this makes things a little clearer to those still starting out the relationships among the Zynq software, the Zynq SoC’s PL, and the XDC file.