Deploying 4.3” TFT LCD screen on ArtyZ7

With this blog entry, we officially launch this new category “Tutorial”. Our intention is to propose and support tips & tricks around embedded programming (and far more). Technical suggestions for developers and makers, whom may face similar challenges.

Thanks to Federico for his first contribution, first of a series.

Read more by clicking on the title…

This tutorial will explain how to drive a 4.3” TFT LCD using a Digilent ArtyZ7 based on Xilinx Zynq programmable SoC. The LCD screen is driven through the SPI interface instantiated on the FPGA and controlled by the processing system. In particular, we will see how to instantiate both the SPI on EMIO and the axi quad SPI IP core.

The devices used for this tutorial are listed below:

  1. Digilent Arty Z7
  2. EastRising 4.3″LCD Touch Screen Module Display based on RA8875 controller
  3. Micro USB cable to connect the Arty to the PC
  4. 5V power supply for the Arty
  5. Prototype Cables (Male to Female)
  6. Strip 2×4 (pitch 2.54 mm) to be soldered on the screen to export the SPI pins


Vivado 2016.3

SDK 2016.3


We start creating a new project from Vivado: go to File -> New Project and select the Arty Z7 board when the Default Part window appears (see the following image).

Once the project is created, we can create the block design. Under IP integrator field on the left menu, select “Create Block Design”.

Thus, we have to add the necessary blocks for our purpose. First of all, we add the ZYNQ7 Processing System block. Doble click on the instance created to re-customize the IP, click on the Peripheral I/O when the window appears and set the SPI0 as EMIO (see the following image).

We also have to create another instance of the SPI based on the axi_quad_spi IP core. This is the SPI implemented in the programmable logic (FPGA). Instead, the EMIO SPI is directly implemented on the processing system (ARM Cortex A9) even if it uses the FPGA pins.

We have to instantiate the AXI Quad SPI block on the design and re-customize the IP by doing double-click on the instance (as we have done for the ZYNQ7 Processing System block). Under IP configuration, we have to set the following parametrer (see also the figure):

  • Mode: Standard
  • Transaction Width: 8
  • Frequency ratio: 8×1
  • Enable master mode
  • Enable FIFO
  • FiFo depth: 16

After this step, we can select the “Run Block Automation” and “Run Connection Automation” to automate the connections.

A little explanation in depth is necessary for the Frequency ratio: the Zynq FPGA bus frequency is 100MHz (as set in the Zynq clock configuration) while the LCD needs at maximum 5 MHz SPI clock, thus we have to scale the frequency. For this reason, we put a PLL (clock_wizard IP) between the Fabric clock and the AXI Quad SPI clock. The output of the PLL will be 40 MHz, which corresponds to the input clock of the SPI block. As described above, we have set the frequency ratio of the AXI Quad SPI at 8, which means that the output clock of the SPI towards the LCD screen will be 5 MHz (40/8=5).

The last steps to perform is to add a constant block which is connected to both SPI0_SS_I and ss_i[0:0] pins of the SPI interfaces created (value and width of the constant are 1).

The final block design is depicted in the figure below.

Note that the clk_wiz_0 block (PLL) is connected to FCLK_CLK0 (input) and ext_spi_clk (output).

Once the block design is completed, we have to move on IP sources in the Sources window, right click on the design that we have created and select Create HDL Wrapper.. (referred to the figure below, our design is named design_1, highlighted in yellow on the top left, and it is necessary to right click on it to select Create HDL Wrapper.. )

Now we have to map the signals exported in HDL wrapper to the physical pins of the board (in this tutorial, PMOD A and PMOD B headers of the Arty are considered). In the following, we listed the changes that we have done in the artyz7_golden.xdc file located in Constraints directory under Sources window.


##Pmod Header JA (in this header, we map both EMIO SPI and Axi quad spi)

set_property dict { PACKAGE_PIN Y18   IOSTANDARD LVCMOS33 } [get_ports { spi_0_io0_io }];

set_property dict { PACKAGE_PIN Y19   IOSTANDARD LVCMOS33 } [get_ports { spi_0_io1_io }];

set_property dict { PACKAGE_PIN Y16   IOSTANDARD LVCMOS33 } [get_ports { spi_0_sck_io }];

set_property dict { PACKAGE_PIN Y17   IOSTANDARD LVCMOS33 } [get_ports { spi_0_ss_o }];

set_property dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports { spi_io0_io }];

set_property dict { PACKAGE_PIN U19   IOSTANDARD LVCMOS33 } [get_ports { spi_io1_io }];

set_property dict { PACKAGE_PIN W18   IOSTANDARD LVCMOS33 } [get_ports { spi_sck_io }];

set_property dict { PACKAGE_PIN W19   IOSTANDARD LVCMOS33 } [get_ports { spi_ss_o  }];


##Pmod Header JB (we can map the following pins to PMOD B header or leave floating) 

set_property dict { PACKAGE_PIN Y14   IOSTANDARD LVCMOS33 } [get_ports { spi_0_ss1_o }];

set_property dict { PACKAGE_PIN W14   IOSTANDARD LVCMOS33 } [get_ports { spi_0_ss2_o }];

set_property dict { PACKAGE_PIN T10   IOSTANDARD LVCMOS33 } [get_ports { spi_0_ss_t }];


Finally we are ready to generate the bitstream!!!

While Vivado compiles the bitstream, we can launch SDK tool.

Generate a Device Tree Source (.dts/.dtsi) files from SDK

  1. Going to Vivado Menu, select File > Launch SDK
  2. The Device Tree Generator Git repository needs to be cloned from the Xilinx. See the Fetch Sources page for more information on Git. Otherwise, for SDK 2014.2 use this repo: git clone git://
  3. Add the BSP repository in SDK (for SDK 2014.2 and later select “device-tree-xlnx” from the checked out git area) going to SDK Menu: Xilinx Tools > Repositories > New… (<bsp repo>) > OK
  4. Create a Device Tree Board Support Package (BSP) from SDK Menu: File > New > Board Support Package > Board Support Package OS: device-tree > Finish
  5. These steps create a .dtsi and programmable logic dts and processing system dts under .sdk directory in the workspace, all included in a system-top.dts that has to be compiled with: 

dtc -I dts -O dtb -o <dtb_name>.dtb system-top.dts


Generate FSBL from SDK

  1. Click File > New > Application Project. Note: This is equivalent to click on File > New > Project to open the New Project wizard, selecting Xilinx > Application Project, and clicking Next.
  2. The New Application Project dialog box appears (see the following image)
  3. In the Project Name field, type a name for the new project.
  4. Select the location for the project. To use the default location as displayed in the “Location” field, leave the “Use default location” check box selected. Otherwise, click to unselect the checkbox, then type or browse to the directory location.
  5. The Hardware Platform is related to the wrapper created in Vivado
  6. Leave the Target software as is
  7. Click Next.
  8. In the Templates dialog box that appears, select the Zynq FSBL template.
  9. Click Finish to create your application project and board support package.


Compile U-boot

Open a terminal and execute the following instructions:

  • git clone u-boot-digilent
  • cd u-boot-digilent
  • move to the newest branch using the git checkout command
  • source <path_to_Vivado_folder>/<Vivado_version>/
  • export ARCH=arm
  • export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
  • make zynq_artyz7_defconfig
  • make

The u-boot.elf compiled after the make command will be in the current folder.


Create BOOT image from SDK

  1. On SDK menu, click Xilinx tools > create boot image.
  2. Create New BIF file and set the path for the output BIF and BIN
  3. Add the FSBL, the bitstream and the u-boot.elf (add the files in this order!!)
  4. Click create image: the image created will be named BOOT.bin


Compile kernel

Open a terminal and execute the following instructions:

  • git clone linux-xlnx
  • cd linux-xlnx
  • move to the newest branch using the git checkout command
  • source <path_to_Vivado_folder>/<Vivado_version>/
  • export ARCH=arm
  • export CROSS_COMPILE=arm-xilinx-linux-gnueabi-
  • make xilinx_zynq_defconfig
  • make xconfig
  • Add the TFT LCD display support and check SPI support (see the images below) Note: we prefer to load the kernel module for the generic FB driver for TFT LCD display as external module. The TFT LCD support can be added to the kernel following this steps:                                                            
    • cd drivers/video/
    • git clone 
    • echo “obj-y += fbtft/” >> Makefile
    • sed -i ‘s/endmenu/source “drivers\/video\/fbtft\/Kconfig”\n\nendmenu/’ Kconfig
  • save configuration
  • make UIMAGE_LOADADDR=0x8000 uImage


Compile the rootfs

  1. Debian rootfs can be downloaded from:
  2. With QEMU, it can be cross compiled for the ARM architecture with: qemu-debootstrap –no-check-gpg –arch=armhf sid /chroots/sid-armhf
  3. At the end of this process, in /chroots/sid-armhf you might find the ARM-compiled root filesystem. Just a copy and paste into the target rootfs folder will do the rest.


Create the SD for ArtyZ7

Note: we use a 8 GB SD

  1. Create a BOOT partition (FAT32) of 200MB
  2. Create a rootfs partition (ext4) with the rest of SD space
  3. Copy on the BOOT partition the BOOT.bin, the dtb and the uImage create previously plus the uramdisk.image.gz that can be downloaded online
  4. For the rootfs, see step 3 on “compile the rootfs”

Last steps…

We are ready to plug the sdcard on the ArtyZ7. Remember to import the fbtft_device.ko kernel module once the system is up on the Arty. You can use a scp command or a memory stick to import the module. It is located under the linux-xilinx/drivers/video/fbtft folder.

Choose the EMIO SPI or AXI Quad SPI interface and connect the correct pins to the TFT LCD screen, using the prototype cables.

Load the kernel module for the TFT LCD considered for this tutorial with the command:

sudo insmod fbtft_device.ko busnum=<spi_number> name=er_tftm050_2

And that’s all! Have fun!

For more information or details, drop us an email at  We are happy to help you.

Elios  — Leading embedded innovation