LED blinker


For my experiments with the Red Pitaya, I’d like to have the following development environment:

Here is how I set it all up.


My development machine has the following installed:

Here are the commands to install all the other required packages:

sudo apt-get update

sudo apt-get --no-install-recommends install \
  bc binfmt-support bison build-essential ca-certificates curl \
  debootstrap device-tree-compiler dosfstools flex fontconfig git \
  libgtk-3-0 libncurses-dev libssl-dev libtinfo5 parted qemu-user-static \
  squashfs-tools sudo u-boot-tools x11-utils xvfb zerofree zip

Source code

The source code is available at


This repository contains the following components:

More details about the directory structure and about the toolchain can be found in the slides of my presentation at Club Vivado 2016.

Syntactic sugar for IP cores

The projects/led_blinker directory contains one Tcl file block_design.tcl that instantiates, configures and interconnects all the needed IP cores.

By default, the IP core instantiation and configuration commands are quite verbose:

create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 ps_0

set_property CONFIG.PCW_IMPORT_BOARD_PRESET cfg/red_pitaya.xml [get_bd_cells ps_0]

connect_bd_net [get_bd_pins ps_0/FCLK_CLK0] [get_bd_pins ps_0/M_AXI_GP0_ACLK]

With the Tcl’s flexibility, it’s easy to define a less verbose command that looks similar to the module instantiation in Verilog:

cell xilinx.com:ip:processing_system7:5.5 ps_0 {
  PCW_IMPORT_BOARD_PRESET cfg/red_pitaya.xml
} {

The cell command is defined in the scripts/project.tcl script as follows:

proc cell {cell_vlnv cell_name {cell_props {}} {cell_ports {}}} {
  set cell [create_bd_cell -type ip -vlnv $cell_vlnv $cell_name]
  set prop_list {}
  foreach {prop_name prop_value} [uplevel 1 [list subst $cell_props]] {
    lappend prop_list CONFIG.$prop_name $prop_value
  if {[llength $prop_list] > 1} {
    set_property -dict $prop_list $cell
  foreach {local_name remote_name} [uplevel 1 [list subst $cell_ports]] {
    set local_port [get_bd_pins $cell_name/$local_name]
    set remote_port [get_bd_pins $remote_name]
    if {[llength $local_port] == 1 && [llength $remote_port] == 1} {
      connect_bd_net $local_port $remote_port
    set local_port [get_bd_intf_pins $cell_name/$local_name]
    set remote_port [get_bd_intf_pins $remote_name]
    if {[llength $local_port] == 1 && [llength $remote_port] == 1} {
      connect_bd_intf_net $local_port $remote_port
    error "** ERROR: can't connect $cell_name/$local_name and $remote_name"

Getting started

Setting up the Vitis and Vivado environment:

source /opt/Xilinx/Vitis/2020.2/settings64.sh

Cloning the source code repository:

git clone https://github.com/pavel-demin/red-pitaya-notes
cd red-pitaya-notes

Building boot.bin, devicetree.dtb and uImage:

make NAME=led_blinker all

Building a bootable SD card:

sudo sh scripts/debian.sh /dev/mmcblk0

SD card image

Building a bootable SD card image:

sudo sh scripts/image.sh scripts/debian.sh red-pitaya-debian-11.3-armhf.img 1024

The SD card image size is 1 GB, so it should fit on any SD card starting from 2 GB.

To write the image to a SD card, the dd command-line utility can be used on GNU/Linux and Mac OS X or Win32 Disk Imager can be used on MS Windows.

The default password for the root account is changeme.

A pre-built SD card image can be downloaded from this link.

Resizing SD card partitions on running Red Pitaya:

# delete second partition
echo -e "d\n2\nw" | fdisk /dev/mmcblk0
# recreate partition
parted -s /dev/mmcblk0 mkpart primary ext4 16MiB 100%
# resize partition
resize2fs /dev/mmcblk0p2

Reprogramming FPGA

It’s possible to reprogram the FPGA by loading the bitstream file into /dev/xdevcfg:

cat led_blinker.bit > /dev/xdevcfg