Author Topic: TE0722 step by step  (Read 1960 times)


  • Active Member
  • *
  • Posts: 19
TE0722 step by step
« on: June 15, 2019, 03:42:43 PM »
"Small step for man. Huge leap for Frodo"

Not being a Zynq guru, it took a surprisingly long time to bring up this little board without "shortcuts" so that I understand (or at least believe I do...) what is happening.
This quick write-up is meant both for myself later, maybe also for others who are running into the same issues (but it's not supposed to be a "recipe" to be followed through blindly). And if I'm getting something wrong, please do comment.

The approach here is pretty much the opposite of embedded Linux with all bells and whistles on board - the option still remains. The spirit here is that for an FPGA-designer, an ARM core (or two) at 600+ MHz with huge (compared to BRAM) OCM plus cache is something Big and Shiny...

Specific challenges with this board:
- DDR-less operation: Xilinx considers this "non-mainstream" and it requires a few manual tweaks
- FSBL integration: Because of above, the arguably easiest way to integrate user ARM code is to put it into the FSBL
- However, debugging FSBL code is not as straightforward as having a regular application
- The UART needs to be routed through PL, so it is only available after the bitstream has loaded (FSBL running from flash cannot print debug info until almost the handover point)
- reportedly, it can be soft-bricked for lack of a boot mode jumper. It never happened to me on this board (fingers crossed) but some care is advised. See [1] for recovery

TE0790 preparation:
- DIP switches "1-4: off off on on" for flashing
- Diamond should autodetect the LCMX02-256HC device
- add filename xmod_DIP40_rev01.jed
- click "program"
- Output: INFO - Operation successful (no errors)
- in case of "CHECK_SECURITY_PROTECT_KEY", check that above version is used (do not install service pack over it)
- DIP switches "1-4: on off on on" for regular operation

The supply via TE0790 worked fine in my experiments to power the board, also for flashing the TE0790 CPLD. There once was a shutdown after a minute or so when the RGB LED was on. I'm not paranoid about breaking a two-digit-priced board, but be aware that there is a risk of e.g. burning a regulator.

Following this walkthrough should lead to a PL / PS design that boots from SPI with following features:
- control of the on-board LED (via MIO, does not require PL and is very useful for debugging FSBL via blink codes)
- control of the RGB LED (via PL)
- UART (requires routing through the PL)

1) implementation of PL part in Vivado (leads to bitstream and board support files)
2) auto-generation of a FSBL project in SDK and modification for no-DDR operation
3) add blink codes for FSBL debugging
4) control the RGB LED once the bootloader has brought up PL and AXI interface
5) print "Hello world" through the UART

Vivado 2019.1 webedition was used but earlier versions should work just as well

1) PL implementation
- Start Vivado. File/Project/New (Wizard). Select component "XC7Z010CLG225-1" (use schematic or a magnifying glass on the board to determine the Zynq version).
- Flow manager: IP integrator: Create block design. Click on the "+" button to "add IP" and add ZYNQ processing system (hint: use search box)

we now configure the Zynq processing system:
- double-click the "processing_system7_0 component"
- Page navigator / "DDR configuration": disable the "enable DDR" checkbox. This reflects the fact that there is no DDR chip on the TE0722 board.
- Page navigator / clock configuration / Basic clocking / PL fabric clocks:
- - note (default) that input frequency / MHz is 33.3 MHz. This corresponds to the oscillator in the schematic (U8) that feeds into the Zynq chip at pad C7, PS_CLK_500
- - note (default) that "processor / memory clocks" : CPU : ARM PLL is set to 666.6 MHz. This sets the processor's clock to the maximum value allowed.
- - note that FCLK_CLK0 is be checked (default).
This provides a clock from PS to PL. Note that this clock requires the ARM processor to be configured (it's not available if loading the bitstream to PL via Vivado)
- enable "MIO configuration / Memory interfaces / Quad SPI flash" checkbox and set to Single SS 4-bit IO with MIO 1..6
This enables access to the flash chip, to be able to load the FPGA bitstream later in the FSBL. The settings (4 bits, MIO 1..6) correspond to the schematic.
- enable "MIO configuration / I/O peripherals / UART 0" and set IO to EMIO.
This provides a UART for xil_printf() later. As there are no suitable MIO pins routed on this board, EMIO makes the UART signals accessible to the PL (they appear in the schematic component after closing the dialog)
- note (default) "PS-PL Configuration: General: UART0 baud rate" is 115200. This is the baudrate we need later to connect to the UART with a terminal program.
- enable "MIO configuration: GPIO : GPIO MIO (with IO = "MIO") with all other GPIO/* boxes cleared
This allows software control of MIO7 (see schematic), which drives the green on-board LED
- note (default) PS-PL configuration / GP Master AXI interface / M_AXI GPO interface checkbox ("enables General purpose AXI master interface 0") is enabled.
This provides the bus where we will attach a GPIO component for the RGB LED.
Close the "Zynq 7 processing system" dialog with OK.

For demo / debug purposes we want to add control of the RGB LED, using a GPIO block.
- In the block diagram, right click background, "add IP", locate "AXI GPIO" (hint: use search box)
- in the newly created "axi_gpio_0" component, right-click the "GPIO" label, then "make external"
- click on the newly created "GPIO_0" pin, and rename it via the "External interface properties" window to "RGB_LED" (we are hereby defining the arbitrary signal name)
- double-click the axi_gpio_0 component, click "all outputs" and set GPIO width to 3. Set "default output value" to 0x7 (this turns the LED off when the bitstream is loaded to the FPGA)
- right click the background, "run connection automation". This will add AXI bus infrastructure for the GPIO block.
- at this point, the block diagram should have a single "RGB_LED" outbound pin.
- in "processing_system7_0", click on UART0 to open the group showing UART0_TX and UART0_RX
- right-click on UART0_TX, "make external"
- right-click on UART0_RX, "make external"

Now go to "block design / sources / Constraints / constrs_1"
- right click "add sources" "add or create constraints", "create file" (enter some name)
- right-click the file, under "Source file properties" disable "Used in: Synthesis"
- open that file and copy the following lines into it:

Code: [Select]
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property CFGBVS VCCO [current_design]
set_property BITSTREAM.CONFIG.UNUSEDPIN PULLUP [current_design]

set_property PACKAGE_PIN J15 [get_ports {RGB_LED_tri_o[0]}]
set_property PACKAGE_PIN L14 [get_ports {RGB_LED_tri_o[1]}]
set_property PACKAGE_PIN K12 [get_ports {RGB_LED_tri_o[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGB_LED_tri_o[*]}]

set_property PACKAGE_PIN K15 [get_ports UART0_TX_0]
set_property PACKAGE_PIN L13  [get_ports UART0_RX_0]

set_property IOSTANDARD LVCMOS33 [get_ports UART0_TX_0]
set_property IOSTANDARD LVCMOS33 [get_ports UART0_RX_0]
The first part sets general configuration options (bank voltages, see schematic, and to use weak pull-up on unused pins)
Signals are connected ("constrained") to specific FPGA pins (PACKAGE_PIN), and IO levels are set ("IOSTANDARD").
Note, the names match those in the block diagram with some name mangling (_0 and _tri_o attached), e.g. found from error messages.

Then, in Sources/Design Sources/(name of the toplevel block design), right-click "create HDL wrapper" ("let Vivado manage").
PROGRAM AND DEBUG/Generate Bitstream. This will take a minute, now the HW design is built.

At this point, double-check the warnings. I got about 100 critical warnings from a generated .xdc file used in synthesis when it shouldn't ("because the property does not exist for objects of type "pin")
There are 336 regular warnings, but nothing that relates directly to the design (unconnected pins, no constraints selected for write, deprecated options yabbadabba)

Now, "File, Export hardware", enable "include bitstream".

Optional bitstream upload (debug)
Uploading the FPGA design can rule out some errors even though debugging is rather limited
PROGRAM AND DEBUG, "open hardware manager", "Program device". The small red LED should turn off if the bitstream is recognized. If in doubt, rebuild with a default output value of 0x6 for the RGB LED GPO, this will enable the red RGB LED on bitstream loading.

2) Auto-generation of a FSBL project in SDK

(Make sure that Vivado's hardware manager is disconnected, also the other way around that SDK debugger is disconnected before using the Vivado programmer. The two don't get along too well...)
Vivado: File / launch SDK
SDK: File / new / Application project. Enter a name e.g. I will use "walkthrough". Click Next, select ZYNQ FSBL, click Finish.

- disable DDR check: edit walkthrough/src/main.c
Locate this block

Code: [Select]

     * DDR Read/write test
Status = DDRInitCheck();
if (Status == XST_FAILURE) {
fsbl_printf(DEBUG_GENERAL,"DDR_INIT_FAIL \r\n");
/* Error Handling here */
* Calling FsblHookFallback instead of Fallback
* since, devcfg driver is not yet initialized

and change into

Code: [Select]
(in other words, the DDRInitCheck() call and its return value check are deleted)

Reason: There is no DDR, so the check would fail.

3) Add blink code for FSBL debugging (see [5])

As there is no UART, we add a simple blink code debug function.
Insert this in walkthrough/src/main.c, for example right before int main(void)

Code: [Select]
#include "xgpiops.h"
#include "sleep.h"
XGpioPs_Config* mioGpioConfig = NULL;
XGpioPs mioGpio;
// this is the MIO number of the green LED (see schematic)
#define ledpin 7
void doblink(int n){
  if (!mioGpioConfig){
    mioGpioConfig = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
    u32 Status = XGpioPs_CfgInitialize(&mioGpio, mioGpioConfig, mioGpioConfig->BaseAddr);
    if (Status != XST_SUCCESS){
      xil_printf("failed to initialize MIO_GPIO");
    XGpioPs_SetDirectionPin(&mioGpio, ledpin, 1);
    XGpioPs_SetOutputEnablePin(&mioGpio, ledpin, 1);
  } // if startup

  for (int ix = 0; ix < n; ++ix){
    XGpioPs_WritePin(&mioGpio, ledpin, 0x1);
    XGpioPs_WritePin(&mioGpio, ledpin, 0x0);
We make it blink once at startup ...
Code: [Select]
fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r");
... twice before and three times after loading the boot image (FPGA bitstream)
Code: [Select]
HandoffAddress = LoadBootImage();
Now the code should be functional already:
In "Project explorer", right-click "walkthrough", "create boot image".
Change output format to "MCS", "Create image".

Flashing requires the fsbl_flash bootloader that comes with the pre-built TE0722 reference design:
Click Xilinx/Program Flash
For "Image file", select the mcs file that was just created (hint: the file selector is dangerous, may want to go to another project...)
For "bootloader", select the one from the prebuilt distribution (this is only a tool for flashing).
E.g. \prebuilt\software\10\zynq_fsbl_flash.elf

With the flashed design, power-cycling should show the following LED pattern:
- initially RED (no PL bitstream)
- green blinks once (FSBL enters)
- green blinks twice (before image load)
- RED goes dark (PL was configured)
- green blinks three times

4) control the RGB LED once the bootloader has brought up PL and AXI interface
This is very similar to 3) but note that the GPIO write will lock up if the AXI interface hasn't been woken up by the FSBL
At this point, we're also done editing the FSBL and start putting the user code into the place where it is supposed to go:

- open src/fsbl_hooks.c
- at the function FsblHookBeforeHandoff(), add

Code: [Select]
#include "xgpio.h"
#include "sleep.h"
(before the function) and
Code: [Select]
XGpio Gpio; /* The Instance of the GPIO Driver */

Status = XGpio_Initialize(&Gpio, XPAR_GPIO_0_DEVICE_ID);
if (Status != XST_SUCCESS) {
  xil_printf("Gpio Initialization Failed\r\n");
XGpio_DiscreteWrite(&Gpio, 1, 6);
XGpio_DiscreteWrite(&Gpio, 1, 5);
XGpio_DiscreteWrite(&Gpio, 1, 3);
XGpio_DiscreteWrite(&Gpio, 1, 7);

into the function (note, the LED is turned on with a logical 0. The above sequence is ~1, ~2, ~4, ~0 for red, green, blue, off)

5) Hello world
Finally, add

Code: [Select]
while (1){
xil_printf("Hello world\r\n");
at the same location as in 4)

Download Teraterm and open
File/New connection, select the COM port that corresponds to the TE0790 serial port
Setup / serial port: Set baud rate to 115200


Following the above discussion should result in a PL/PS design that loads from flash and is reduced to the essentials.
There are many follow-up topics that come to mind, especially when reading the documentation (e.g. using the cache for memory, execute-in-place for FLASH code) but it's getting late and those are questions for another day :)


« Last Edit: June 15, 2019, 04:19:29 PM by offroad »


  • Active Member
  • *
  • Posts: 19
Re: TE0722 step by step
« Reply #1 on: June 15, 2019, 03:51:55 PM »
the complete design with some redundant folders deleted for Vivado 2019.1