Enable the standard connectivity and feedback interfaces on the PYNQ-Z2 board:
By the end of this step, you will be able to:
/dev/spidev/dev/i2c-*┌─────────────────────────────────────────────────┐
│ Linux USB Subsystem │
│ (Storage, HID, Serial, Network drivers) │
├─────────────────────────────────────────────────┤
│ ChipIdea USB Host Controller Driver │
│ (ci_hdrc / USB EHCI) │
├─────────────────────────────────────────────────┤
│ ULPI PHY Interface │
│ (USB Low Pin Interface Protocol) │
├─────────────────────────────────────────────────┤
│ TUSB1210 USB PHY (Hardware) │
│ (MIO 28-39 + GPIO 46 reset) │
├─────────────────────────────────────────────────┤
│ USB Type-A Connector │
└─────────────────────────────────────────────────┘
Key Components:
Note: This step focuses on USB host support. Display functionality from Steps 7-8 is not modified. I2C/SPI peripheral support may be covered in future steps but is not included here.
Before starting:**
| Peripheral | Type | Location | Configuration Needed |
|---|---|---|---|
| USB | PS | MIO 28-39 + GPIO 46 | Verify in PS config (already done) |
| SPI | PS | EMIO → PL pins | Verify PS config + add constraints |
| I2C | PS | EMIO → PL pins | Verify PS config + add constraints |
| Activity LED | PL | AXI GPIO → LED pin | Add new IP + constraints |
Important Notes:
Important: USB on the Zynq-7000 is a Processing System (PS) peripheral, not a Programmable Logic (PL/FPGA) feature. The USB controller, PHY interface (ULPI), and MIO pins are all part of the PS silicon.
If you need to verify or modify the PS configuration in Vivado:
1. Open Block Design:
# In Vivado
Open Block Design → system_design.bd
2. Edit Zynq PS Block:
3. Verify USB Configuration:
4. Verify GPIO Configuration:
5. Check Clock Configuration:
6. Enable SPI and I2C via EMIO:
7. Apply Changes:
IIC_0 and SPI_0Create a GPIO controller in the PL for the activity LED.
1. Add AXI GPIO IP:
In the block design:
2. Configure AXI GPIO:
Double-click the AXI GPIO block:
3. Run Connection Automation:
/processing_system7_0/M_AXI_GP0This connects the GPIO control registers to the PS via AXI-Lite.
4. Make GPIO External:
gpio_io_o port on the AXI GPIO block (4-bit output)leds_4bits5. Make SPI and I2C External:
If not already done:
IIC_0 on Zynq PS block → Right-click → Make External → Rename to iic_0SPI_0 on Zynq PS block → Right-click → Make External → Rename to spi_0Map the abstract ports to physical PYNQ-Z2 pins.
1. Open Constraints File:
Open your existing constraints file (e.g., hdmi_pinout.xdc) or create a new one.
2. Add LED Constraints:
Add the following to constrain the 4 LEDs:
##################################################
# PYNQ-Z2 LED Constraints
##################################################
# LED 0 (LD0) - Red/Green bicolor LED, Red component
set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {leds_4bits[0]}]
# LED 1 (LD1) - Red/Green bicolor LED, Red component
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {leds_4bits[1]}]
# LED 2 (LD2) - Red/Green bicolor LED, Red component
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports {leds_4bits[2]}]
# LED 3 (LD3) - Red/Green bicolor LED, Red component
set_property -dict {PACKAGE_PIN M14 IOSTANDARD LVCMOS33} [get_ports {leds_4bits[3]}]
Note: PYNQ-Z2 has 4 bicolor LEDs (red/green). We’re using the red component here. Green components are on different pins if you want to expand later.
3. Add SPI Constraints (Arduino Header):
SPI is typically routed to Arduino-compatible pins:
##################################################
# SPI Interface (Arduino Header)
##################################################
# SPI Clock - Arduino D13
set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {spi_0_sck_io}]
# SPI MISO - Arduino D12
set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {spi_0_io0_io}]
# SPI MOSI - Arduino D11
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {spi_0_io1_io}]
# SPI SS (Chip Select) - Arduino D10
set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {spi_0_ss_io}]
4. Add I2C Constraints (Arduino Header):
I2C is typically routed to Arduino-compatible pins:
##################################################
# I2C Interface (Arduino Header)
##################################################
# I2C SCL (Clock) - Arduino A5
set_property -dict {PACKAGE_PIN Y11 IOSTANDARD LVCMOS33} [get_ports {iic_0_scl_io}]
# I2C SDA (Data) - Arduino A4
set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {iic_0_sda_io}]
Important: Verify these pin assignments match the PYNQ-Z2 schematic. Arduino header pinout may vary by board revision.
1. Validate Block Design:
2. Assign Addresses:
axi_gpio_0 has an assigned address (e.g., 0x4120_0000)3. Generate Bitstream:
# In Vivado
Generate Bitstream
Expected Duration: 15-30 minutes
4. Export Hardware:
File → Export → Export Hardware (Include Bitstream)
# Export to: project-spec/hw-description/system.xsa
If you regenerated the hardware:
cd ~/loopback_system/loopback_os
petalinux-config --get-hw-description=project-spec/hw-description/
# Just save and exit - this updates the device tree templates
Enable USB host support and all necessary device drivers.
Create a comprehensive kernel configuration file for USB support.
1. Create the Configuration File:
cd ~/loopback_system/loopback_os
vi project-spec/meta-user/recipes-kernel/linux/linux-xlnx/usb_input.cfg
2. Add Complete USB Configuration:
Copy the following configuration (this matches the actual tested configuration):
# USB Host Controller Support for Zynq-7000
CONFIG_USB_SUPPORT=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
# Host Controller Drivers (HCD)
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
# ChipIdea Driver (Zynq Hardware)
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_CHIPIDEA_GENERIC=y
# PHY Support (TUSB1210 ULPI)
CONFIG_USB_PHY=y
CONFIG_USB_ULPI_BUS=y
CONFIG_USB_ULPI=y
# SPI User Mode Driver
# we shouldn't need to set CONFIG_SPI and CONFIG_SPI_MASTER because they are already set by the base configuration, but CONFIG_SPI_SPIDEV depends on them and load order can be unpredictable
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
3. Save and Exit:
Save the file and exit the editor.
Configure the USB PHY and controller in the device tree.
cd ~/loopback_system/loopback_os
vi project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi
Add the following USB configuration to your device tree. This should be in addition to any video configuration from Step 8.
Complete USB Device Tree Configuration:
/* 8. Add USB PHY with TUSB1210 reset GPIO on MIO 46 */
/ {
usb_phy0: phy0 {
compatible = "ulpi-phy";
#phy-cells = <0>;
reg = <0xe0002000 0x1000>;
view-port = <0x170>;
reset-gpios = <&gpio0 46 1>; /* MIO 46, active-low */
drv-vbus;
};
};
/* 9. Configure USB0 Controller */
&usb0 {
status = "okay";
dr_mode = "host";
usb-phy = <&usb_phy0>;
};
/* 10. Configure SPI0 for userspace access */
&spi0 {
status = "okay";
is-decoded-cs = <0>;
num-cs = <1>;
spidev@0 {
compatible = "rohm,dh2228fv"; /* Generic spidev compatible string */
reg = <0>; /* Chip select 0 */
spi-max-frequency = <50000000>; /* 50 MHz max */
};
};
/* 11. Configure I2C0 for userspace access */
&i2c0 {
status = "okay";
clock-frequency = <100000>; /* 100 kHz standard mode */
/* I2C devices can be added here when connected */
/* Example:
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
};
*/
};
/* 12. Configure GPIO for LEDs with Activity Triggers */
/ {
leds {
compatible = "gpio-leds";
led0 {
label = "pynq:red:ld0";
gpios = <&axi_gpio_0 0 0>; /* GPIO 0, active high */
linux,default-trigger = "heartbeat"; /* CPU heartbeat pattern */
default-state = "off";
};
led1 {
label = "pynq:red:ld1";
gpios = <&axi_gpio_0 1 0>; /* GPIO 1, active high */
linux,default-trigger = "mmc0"; /* SD card activity */
default-state = "off";
};
led2 {
label = "pynq:red:ld2";
gpios = <&axi_gpio_0 2 0>; /* GPIO 2, active high */
linux,default-trigger = "cpu0"; /* CPU0 activity */
default-state = "off";
};
led3 {
label = "pynq:red:ld3";
gpios = <&axi_gpio_0 3 0>; /* GPIO 3, active high */
linux,default-trigger = "none"; /* Manual control */
default-state = "on"; /* Always on for power indicator */
};
};
};
Key Device Tree Elements:
USB Configuration:
usb_phy0):
compatible = "ulpi-phy": ULPI PHY driverreg = <0xe0002000 0x1000>: USB0 ULPI viewport register addressview-port = <0x170>: ULPI viewport register offsetreset-gpios = <&gpio0 46 1>: MIO pin 46 for PHY reset (active-low)drv-vbus: Enable VBUS power control&usb0):
status = "okay": Enable the controllerdr_mode = "host": Configure as USB host (not device/OTG)usb-phy = <&usb_phy0>: Link to the PHY nodeSPI Configuration:
&spi0):
status = "okay": Enable SPI0spidev@0: Creates /dev/spidev0.0 for userspace accesscompatible = "rohm,dh2228fv": Generic spidev compatible stringspi-max-frequency = <50000000>: 50 MHz maximumI2C Configuration:
&iic0):
status = "okay": Enable I2C0clock-frequency = <100000>: 100 kHz standard mode/dev/i2c-0 for userspace accessLED Configuration:
compatible = "gpio-leds": Use Linux LED subsystemgpios: Reference to AXI GPIO pinlinux,default-trigger: Activity trigger typedefault-state: Initial state at bootAvailable Triggers:
heartbeat: Rhythmic CPU heartbeat patternmmc0: Flashes on SD card activitycpu0: Flashes on CPU0 activitydisk-activity: Flashes on any disk I/Otimer: Configurable blink ratenone: Manual control via sysfsImportant Notes:
&gpio0 = PS GPIO controller (MIO pins)&axi_gpio_0 = PL GPIO controller (for LEDs)1 flag indicates active-low (reset by pulling low)drv-vbus enables 5V USB power outputiic, but Linux typically uses i2c in device nodes/sys/class/leds/*/trigger3. Verify Configuration:
Your complete system-user.dtsi should now include:
Build the updated kernel and device tree, then deploy to the board.
system_design_wrapper.xsa).
cd ~/projects/loopback_os
petalinux-config --get-hw-description=<path-to-folder-containing-xsa> --silentconfig
petalinux-build -c kernel
petalinux-build -c xlnx-dummy-connector
petalinux-build -c device-tree
BOOT.BIN that includes the new bitstream.
petalinux-package --boot --fsbl images/linux/zynq_fsbl.elf --fpga project-spec/hw-description/system_design_wrapper.bit --u-boot --force
Boot the system and verify USB functionality.
1. Boot the System:
2. Check Kernel Messages:
# Login via serial console
# Check USB initialization
dmesg | grep -i usb
# Expected output (example):
# ci_hdrc ci_hdrc.0: EHCI Host Controller
# ci_hdrc ci_hdrc.0: new USB bus registered, assigned bus 1
# hub 1-0:1.0: USB hub found
# usb 1-1: New USB device found, idVendor=XXXX, idProduct=XXXX
# Check PHY initialization
dmesg | grep -i phy
# Expected output:
# tusb1210 ci_hdrc.0:ulpi: USB PHY ... registered
1. Check USB Controller:
#install usbutils
sudo apt-get install usbutils
# List USB buses and devices
lsusb
# Expected output (with devices connected):
# Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
# Bus 001 Device 002: ID 046d:c077 Logitech, Inc. Mouse
# Bus 001 Device 003: ID 04d9:1603 Holtek Semiconductor Keyboard
2. Check USB Devices in Detail:
# Detailed device information
lsusb -v
# Tree view of USB topology
lsusb -t
# Expected output:
# /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ci_hdrc/1p, 480M
# |__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 12M
# |__ Port 1: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M
1. Check Input Device Nodes:
# List input devices
ls -l /dev/input/
# Expected output:
# event0 -> keyboard
# event1 -> mouse
# mice -> mouse pointer device
2. View Input Device Details:
# List all input devices with names
cat /proc/bus/input/devices
# Expected output:
# I: Bus=0003 Vendor=04d9 Product=1603 Version=0111
# N: Name="USB Keyboard"
# H: Handlers=sysrq kbd event0
# ...
# I: Bus=0003 Vendor=046d Product=c077 Version=0111
# N: Name="Logitech USB Mouse"
# H: Handlers=mouse0 event1
3. Test Keyboard Input:
# Install evtest utility (if not already installed)
apt install -y evtest
# Test keyboard
evtest /dev/input/event0
# Press keys, should see:
# Event: time 1234567.123456, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
# Event: time 1234567.123456, type 1 (EV_KEY), code 30 (KEY_A), value 1
4. Test Mouse Input:
# Test mouse
evtest /dev/input/event1
# Move mouse and click, should see events for:
# - REL_X, REL_Y (movement)
# - BTN_LEFT, BTN_RIGHT (clicks)
5. Simple Keyboard Test:
# Raw keyboard test (shows key events as hex)
cat /dev/input/event0 | hexdump -C
# Press keys, should see data streaming
# Press Ctrl+C to stop
1. Plug in USB Flash Drive:
Watch kernel messages in real-time:
# In one terminal, monitor kernel messages
dmesg -w
# In another terminal or after plugging in drive:
dmesg | tail -30
Expected messages:
usb 1-1: new high-speed USB device number 2 using ci_hdrc
usb-storage 1-1:1.0: USB Mass Storage device detected
scsi host0: usb-storage 1-1:1.0
scsi 0:0:0:0: Direct-Access SanDisk Cruzer Blade 1.00 PQ: 0 ANSI: 6
sd 0:0:0:0: [sda] 30842880 512-byte logical blocks: (15.8 GB/14.7 GiB)
sd 0:0:0:0: [sda] Write Protect is off
sda: sda1
sd 0:0:0:0: [sda] Attached SCSI removable disk
2. List Block Devices:
# Check for new storage device
lsblk
# Expected output:
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
# mmcblk0 179:0 0 14.9G 0 disk
# ├─mmcblk0p1 179:1 0 512M 0 part /boot
# └─mmcblk0p2 179:2 0 14.4G 0 part /
# sda 8:0 1 14.7G 0 disk
# └─sda1 8:1 1 14.7G 0 part
3. Mount USB Drive:
# Create mount point
mkdir -p /mnt/usb
# Mount the drive (adjust partition if needed)
mount /dev/sda1 /mnt/usb
# List contents
ls -lh /mnt/usb
# Test read
cat /mnt/usb/somefile.txt
# Test write
echo "USB test from PYNQ-Z2" > /mnt/usb/test.txt
sync
# Unmount
umount /mnt/usb
4. Test Transfer Speed:
# Write test (1GB)
dd if=/dev/zero of=/mnt/usb/testfile bs=1M count=1024
# Expected speed: 10-30 MB/s for USB 2.0 High-Speed
# Read test
dd if=/mnt/usb/testfile of=/dev/null bs=1M
# Clean up
rm /mnt/usb/testfile
umount /mnt/usb
1. Plug in USB Serial Adapter (FTDI, CP210x, etc.):
# Check device detection
dmesg | tail -20
# Expected for FTDI:
# ftdi_sio 1-1:1.0: FTDI USB Serial Device converter detected
# usb 1-1: FTDI USB Serial Device converter now attached to ttyUSB0
# Expected for CP210x:
# cp210x 1-1:1.0: cp210x converter detected
# usb 1-1: cp210x converter now attached to ttyUSB0
2. List Serial Devices:
ls -l /dev/ttyUSB*
# Expected output:
# /dev/ttyUSB0
3. Test Serial Communication:
# Install minicom or screen
apt install -y minicom
# Connect to serial device
minicom -D /dev/ttyUSB0 -b 115200
# Or using screen
screen /dev/ttyUSB0 115200
# Check USB-related kernel modules
lsmod | grep usb
# Expected modules:
# usbhid - USB HID support
# usb_storage - USB mass storage
# ci_hdrc - ChipIdea USB controller
# phy_tusb1210 - TUSB1210 PHY driver
# ulpi - ULPI interface
# Check HID modules
lsmod | grep hid
# Expected modules:
# hid_generic - Generic HID driver
# usbhid - USB HID
# hid - HID core
# View USB interrupt activity
cat /proc/interrupts | grep -i usb
# Should show interrupt counts for USB controller
1. Check SPI Device Node:
# List SPI devices
ls -l /dev/spidev*
# Expected output:
# /dev/spidev0.0
2. Check SPI Driver:
# Check SPI driver loaded
lsmod | grep spi
# Check kernel messages
dmesg | grep -i spi
# Expected output:
# spi_master spi0: registered child spi0.0
3. Test SPI Loopback (Hardware Required):
To test SPI, you need to physically connect MISO to MOSI (pins D11 and D12 on Arduino header).
Install SPI tools:
apt install -y python3-spidev
# Or install spi-tools
apt install -y spi-tools
Python SPI test script:
#!/usr/bin/env python3
import spidev
import time
# Open SPI bus 0, device 0
spi = spidev.SpiDev()
spi.open(0, 0)
# Configure SPI
spi.max_speed_hz = 1000000 # 1 MHz
spi.mode = 0
# Send and receive data (loopback test if MISO connected to MOSI)
tx_data = [0x12, 0x34, 0x56, 0x78]
rx_data = spi.xfer2(tx_data)
print(f"Sent: {[hex(x) for x in tx_data]}")
print(f"Received: {[hex(x) for x in rx_data]}")
if tx_data == rx_data:
print("✓ SPI loopback test PASSED")
else:
print("✗ SPI loopback test FAILED (MISO/MOSI not connected?)")
spi.close()
Save as test_spi.py and run:
chmod +x test_spi.py
./test_spi.py
4. Check SPI Kernel Interface:
# View SPI bus information
cat /sys/class/spi_master/spi0/uevent
# View SPI device information
cat /sys/bus/spi/devices/spi0.0/uevent
1. Check I2C Device Node:
# List I2C devices
ls -l /dev/i2c*
# Expected output:
# /dev/i2c-0
2. Check I2C Driver:
# Check I2C driver loaded
lsmod | grep i2c
# Check kernel messages
dmesg | grep -i i2c
# Expected output:
# i2c i2c-0: Xilinx I2C at 0xe0004000 mapped to 0x...
3. Install I2C Tools:
apt install -y i2c-tools
4. Detect I2C Devices:
# Scan I2C bus 0 for devices
i2cdetect -y 0
# Expected output (if no devices connected):
# 0 1 2 3 4 5 6 7 8 9 a b c d e f
# 00: -- -- -- -- -- -- -- -- -- -- -- -- --
# 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# 70: -- -- -- -- -- -- -- --
If devices are connected, their addresses will show as numbers instead of --.
5. Test I2C Read/Write (with device):
Example: Reading from an I2C EEPROM at address 0x50:
# Read 16 bytes starting from address 0x00
i2cdump -y 0 0x50 b
# Write a byte to address 0x00
i2cset -y 0 0x50 0x00 0x42
# Read back the byte
i2cget -y 0 0x50 0x00
6. Python I2C Test (if device connected):
#!/usr/bin/env python3
import smbus
import time
# Open I2C bus 0
bus = smbus.SMBus(0)
# Example: Read from device at address 0x50
device_addr = 0x50
try:
# Read a byte from register 0x00
data = bus.read_byte_data(device_addr, 0x00)
print(f"Read from 0x{device_addr:02x}: 0x{data:02x}")
except Exception as e:
print(f"Error: {e}")
print("No device at address 0x50 (this is normal if no I2C device connected)")
finally:
bus.close()
1. List LEDs:
# List all LEDs
ls /sys/class/leds/
# Expected output:
# pynq:red:ld0
# pynq:red:ld1
# pynq:red:ld2
# pynq:red:ld3
2. Check LED Triggers:
# View available triggers for LD0
cat /sys/class/leds/pynq:red:ld0/trigger
# Expected output (current trigger in brackets):
# none cpu0 cpu1 [heartbeat] timer oneshot disk-activity mmc0 mmc1 rfkill-any rfkill-none
3. Check Current State:
# Check if LED is on or off
cat /sys/class/leds/pynq:red:ld0/brightness
# 0 = off, 255 = on (full brightness)
Watch the LEDs on the board:
Generate activity to test:
# Turn LED on
echo 255 > /sys/class/leds/pynq:red:ld3/brightness
# Turn LED off
echo 0 > /sys/class/leds/pynq:red:ld3/brightness
2. Set Different Triggers:
# Change LD0 to timer mode
echo timer > /sys/class/leds/pynq:red:ld0/trigger
# Set blink rate (milliseconds)
echo 100 > /sys/class/leds/pyn
- ✅ SPI interface accessible via `/dev/spidev0.0`
- ✅ I2C interface accessible via `/dev/i2c-0`
- ✅ Activity LEDs with multiple trigger modes
- ✅ Visual system feedback (heartbeat, disk, CPU activity)q:red:ld0/delay_on
echo 100 > /sys/class/leds/pynq:red:ld0/delay_off
# Change to disk activity
echo disk-activity > /sys/class/leds/pynq:red:ld0/trigger
# Change back to heartbeat
echo heartbeat > /sys/class/leds/pynq:red:ld0/trigger
3. LED Brightness Control:
LEDs can have variable brightness (0-255):
# Set to manual control
echo none > /sys/class/leds/pynq:red:ld3/trigger
# Half brightness (if supported by hardware)
echo 128 > /sys/class/leds/pynq:red:ld3/brightness
# Full brightness
echo 255 > /sys/class/leds/pynq:red:ld3/brightness
Note: Simple on/off LEDs may only support 0 (off) and 255 (on), ignoring intermediate values.
Create a simSensor Integration**
Connect sensors and devices:
# I2C sensors (temperature, pressure, accelerometer)
i2cdetect -y 0
i2cget -y 0 0x48 0x00 # Example: TMP102 temperature sensor
# SPI devices (ADCs, DACs, displays)
# Use Python spidev library or C/C++ with /dev/spidev0.0
Option 4: Custom Applications
Develop embedded applications using:
Example: Combined System Application
#!/usr/bin/env python3
# Complete system status display
import os
import time
def set_led(num, state):
path = f"/sys/class/leds/pynq:red:ld{num}"
os.system(f"echo none > {path}/trigger")
os.system(f"echo {state} > {path}/brightness")
# Show boot sequence on LEDs
for i in range(4):
set_led(i, 255)
time.sleep(0.2)
# Restore activity triggers
os.system("echo heartbeat > /sys/class/leds/pynq:red:ld0/trigger")
os.system("echo mmc0 > /sys/class/leds/pynq:red:ld1/trigger")
os.system("echo cpu0 > /sys/class/leds/pynq:red:ld2/trigger")
set_led(3, 255) # Power indicator
print("System ready!")
print("- USB devices active")
print("- SPI available at /dev/spidev0.0")
print("- I2C available at /dev/i2c-0")
print("- Display output at 720p60")
print("- Activity LEDs configured")
"""
led_path = f"/sys/class/leds/pynq:red:ld{led_num}"
# Set to manual control
with open(f"{led_path}/trigger", "w") as f:
f.write("none")
# Set brightness
with open(f"{led_path}/brightness", "w") as f:
f.write(str(state))
print(“Blinking LEDs in sequence…”) for _ in range(3): for led in range(4): set_led(led, 255) time.sleep(0.2) set_led(led, 0) time.sleep(0.2)
print(“Restoring default triggers…”) os.system(“echo heartbeat > /sys/class/leds/pynq:red:ld0/trigger”) os.system(“echo mmc0 > /sys/class/leds/pynq:red:ld1/trigger”) os.system(“echo cpu0 > /sys/class/leds/pynq:red:ld2/trigger”) os.system(“echo 255 > /sys/class/leds/pynq:red:ld3/brightness”)
print(“Done!”)
Save as `led_test.py` and run:
```bash
chmod +x led_test.py
sudo ./led_test.py
Issue: No /dev/spidev* device
Diagnosis:
dmesg | grep -i spi
ls /sys/bus/spi/devices/
Common Causes:
Fix:
# Check device tree
dtc -I dtb -O dts /boot/system.dtb | grep -A 20 "spi0"
# Load SPI driver manually
modprobe spidev
# Check EMIO routing in Vivado (ensure SPI_0 is set to EMIO)
Issue: No /dev/i2c-* device
Diagnosis:
dmesg | grep -i i2c
ls /sys/bus/i2c/devices/
lsmod | grep i2c
Common Causes:
Fix:
# Check device tree
dtc -I dtb -O dts /boot/system.dtb | grep -A 20 "iic0"
# Load I2C driver manually
modprobe i2c-dev
modprobe i2c-xiic
# Check EMIO routing in Vivado (ensure IIC_0 is set to EMIO)
Issue: i2cdetect shows all addresses as busy
Cause: Wrong I2C mode or bus speed too high
Fix:
# Try slower speed in device tree:
# clock-frequency = <100000>; /* 100 kHz standard mode */
Issue: LEDs don’t light up
Diagnosis:
ls /sys/class/leds/
cat /sys/class/leds/pynq:red:ld0/brightness
dmesg | grep -i gpio
Common Causes:
Fix:
# Check GPIO device tree
dtc -I dtb -O dts /boot/system.dtb | grep -A 30 "axi_gpio"
# Verify GPIO exists in sysfs
ls /sys/class/gpio/
# Check constraints match LED pins (R14, P14, N16, M14)
Issue: LED trigger not working
Cause: Trigger module not loaded
Fix:
# Load trigger modules
modprobe ledtrig-heartbeat
modprobe ledtrig-cpu
modprobe ledtrig-disk
# Check available triggers
cat /sys/class/leds/pynq:red:ld0/trigger
Issue: Manual control doesn’t work
Cause: Trigger still active
Fix:
# Must set trigger to 'none' first
echo none > /sys/class/leds/pynq:red:ld0/trigger
echo 255 > /sys/class/leds/pynq:red:ld0/brightness
Symptoms: lsusb shows only root hub, no devices detected
Diagnosis:
dmesg | grep -i "usb\|phy\|ci_hdrc"
ls /sys/bus/usb/devices/
cat /sys/kernel/debug/usb/devices
Common Causes:
reset-gpios = <&gpio0 46 1> in device treedrv-vbus in device treedr_mode = "host" in device treeFix:
# Manually reset USB PHY via GPIO
echo 46 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio46/direction
echo 0 > /sys/class/gpio/gpio46/value
sleep 1
echo 1 > /sys/class/gpio/gpio46/value
# Check if PHY is now detected
dmesg | tail -20
# Reload USB controller driver
rmmod ci_hdrc_msm
modprobe ci_hdrc_msm
Symptoms: Device detected but no input events
Diagnosis:
ls /dev/input/
evtest
dmesg | grep -i hid
lsmod | grep hid
Common Causes:
modprobe usbhid
modprobe hid_generic
evtest to identify correct device/proc/bus/input/devices for device namesCONFIG_INPUT_EVDEV=y in kernel configCONFIG_USB_HID=yFix:
# Load HID modules
modprobe usbhid
modprobe hid_generic
# Test input
cat /dev/input/by-id/*-kbd | hexdump -C
# Press keys, should see data
Symptoms: Drive detected but no /dev/sda
Diagnosis:
dmesg | grep -E "sd|scsi"
ls /sys/block/
cat /proc/partitions
Common Causes:
modprobe usb_storage
fdisk -l /dev/sda
# Install filesystem support
apt install -y ntfs-3g exfat-fuse exfat-utils
Fix:
# Reload storage driver
modprobe -r usb_storage
modprobe usb_storage
# Force rescan
echo "- - -" > /sys/class/scsi_host/host0/scan
# Check partition table
fdisk -l /dev/sda
# Mount manually
mount -t vfat /dev/sda1 /mnt/usb
# or
mount -t ext4 /dev/sda1 /mnt/usb
Symptoms: Transfer speed < 5 MB/s
Cause: USB running in Full-Speed (12 Mbps) instead of High-Speed (480 Mbps)
Check:
lsusb -t
# Look for "480M" (High-Speed) vs "12M" (Full-Speed)
dmesg | grep "high-speed\|full-speed"
Fix:
Symptoms: Device plugged in but enumeration fails
Error in dmesg:
usb 1-1: device not accepting address 2, error -71
Common Causes:
Fix:
# Reset USB subsystem
echo -n "ci_hdrc.0" > /sys/bus/platform/drivers/ci_hdrc/unbind
sleep 1
echo -n "ci_hdrc.0" > /sys/bus/platform/drivers/ci_hdrc/bind
# Check power supply voltage
# Use multimeter on 5V USB pin
# Monitor USB events in real-time
udevadm monitor --kernel --subsystem-match=usb
# View USB device tree
lsusb -v | less
# Check USB power consumption
lsusb -v | grep -i "MaxPower"
# View USB controller status
cat /sys/bus/platform/drivers/ci_hdrc/ci_hdrc.0/power/runtime_status
# Enable USB debugging
echo 'module usbcore =p' > /sys/kernel/debug/dynamic_debug/control
echo 'module ci_hdrc =p' > /sys/kernel/debug/dynamic_debug/control
# View debugging messages
dmesg -w
✅ Configured Zynq PS USB controller with ULPI PHY support
✅ Created comprehensive kernel configuration for USB host, storage, HID, and serial
✅ Wrote device tree configuration for TUSB1210 PHY and USB controller
✅ Built and deployed updated kernel with USB support
✅ Tested USB functionality with keyboards, mice, storage, and serial adapters
✅ Verified driver operation with multiple device types
Your PYNQ-Z2 now supports:
🎉 Congratulations! Your PYNQ-Z2 is now a complete embedded computing platform with:
You have successfully integrated Processing System (PS) and Programmable Logic (PL) to create a versatile development
From previous steps:
/dev/fb0 (Step 8)From this step:
Option 1: Desktop Environment
Now that you have display output and USB input, install a full desktop:
# Install X11 and XFCE
apt install -y xserver-xorg-core xserver-xorg-video-fbdev
apt install -y xfce4 xfce4-terminal
Configure X11 to use the framebuffer. Edit /etc/X11/xorg.conf.
Section "ServerFlags"
Option "AutoAddGPU" "false"
EndSection
Section "Extensions"
Option "GLX" "Disable"
Option "Composite" "Disable"
EndSection
Section "Device"
Identifier "modesetting"
Driver "modesetting"
Option "kmsdev" "/dev/dri/card0"
Option "AccelMethod" "none"
Option "SWcursor" "true"
Option "PageFlip" "false"
Option "Atomic" "false"
EndSection
Section "Screen"
Identifier "Screen0"
Device "modesetting"
EndSection
Section "ServerLayout"
Identifier "Layout0"
Screen "Screen0"
EndSection
# Start desktop
startxfce4
Option 2: Networking
Add network connectivity:
# Wired Ethernet (if enabled in Zynq PS)
ip link set eth0 up
dhclient eth0
# WiFi USB adapter
apt install -y wpasupplicant wireless-tools
# Configure via /etc/wpa_supplicant/wpa_supplicant.conf
Option 3: Custom Applications
Develop embedded applications using:
Is the system booting slowly? Those 40-second pauses are annoying. Let’s fix them and polish the final system.
Proceed to Step 10: System Optimization
You have reached the end of the Pynq Learning Journey.
You started with a board that could only run Python notebooks. You have built a custom processor, a custom operating system, custom drivers, and a full desktop environment.