# ebaz4205-hdmi-demo
Firmware for the EBAZ4205 with HDMI extension board that implements DMA transfers to an HDMI sink.

![EBAZ4205 board](doc/ebaz1.jpg?raw=true "EBAZ4205 board")
![Image sent over HDMI](doc/ebaz2.jpg?raw=true "Image sent over HDMI")

This repository structure is based on the [plutosdr-fw](https://github.com/analogdevicesinc/plutosdr-fw/) repository. Since I really appreciate the way it's structured, I decided to use all the established best practices for integrated bitstream and Linux image generation. This build generates content only for SD-card storage, as the NAND ROM is not utilized.

It's designed for the EBAZ4205 board (a bitcoin miner that serves as a very affordable board with a Zynq7010 SoC) together with an HDMI expansion board (available on popular Chinese retail marketplaces). You can find board and expansion board schematics in [doc/](doc/) directory.

It was tested on the variant with a crystal oscillator attached to the Ethernet PHY - however, the 25MHz clock is also generated by the FPGA, so the current build _should_ also work on the basic variant without a crystal oscillator.

## Repository Contents

`buildroot` - this is a fork of the official [buildroot](https://github.com/buildroot/buildroot) repository, which implements new packages, downgrades Python to version 3.12 (because of compatibility issues with some packages), fixes builds of `python-scipy` and `python-numpy`, and adds the `ebaz4205` [configuration](https://github.com/m1nl/buildroot/blob/ebaz4205/configs/zynq_ebaz4205_defconfig) together with [board-specific files](https://github.com/m1nl/buildroot/blob/ebaz4205/board/ebaz4205)

`hdl` - this is a fork of the official [Analog Devices HDL Reference Designs](https://github.com/analogdevicesinc/hdl) repository with the `ebaz4205` project definition, `hdmi` and `hdmi_generator` IP cores; it defines a basic HDL design to drive components on the expansion boards and establishes the DMA setup for the HDMI sink

`hdl/projects/ebaz4205` - main project directory with hardware design; Vivado project is generated with TCL scripts, main block diagram is defined in [system_bd.tcl](https://github.com/m1nl/analogdevicesinc-hdl/blob/ebaz4205/projects/ebaz4205/system_bd.tcl), XDC constraints in [system_constr.xdc](https://github.com/m1nl/analogdevicesinc-hdl/blob/ebaz4205/projects/ebaz4205/system_constr.xdc); if you include Vivado environment in your terminal session (`$ source /opt/Xilinx/Vivado/2023.2/settings64.sh`) you should be able to generate Vivado project files by issuing `make` command in the project directory

`hdl/library/hdmi` - HDMI IP created using [sameer's HDMI](https://github.com/hdl-util/hdmi) SystemVerilog code; to make IP packaging possible for Vivado, the [top design file](https://github.com/m1nl/analogdevicesinc-hdl/blob/ebaz4205/library/hdmi/hdmi.v) was converted from SystemVerilog to Verilog

`hdl/library/hdmi_generator` - custom HDMI generator IP which adapts 64-bit width AXI Stream to 24-bit RGB stream for the HDMI IP with some logic to keep RGB data synchronized and generates pixel clock for HDMI IP

`linux` - this is a fork of [Analog Devices Linux Kernel](https://github.com/analogdevicesinc/linux) variant (from `adi-6.12.0` branch) rebased over latest 6.12 LTS kernel variant from Xilinx (`xlnx_rebase_v6.12_LTS_2025.1_update_merge_6.12.40`); I decided to use this combination to maintain compatibility with `libiio` and to use MathWorks drivers for DMA transfers; MathWorks drivers were slightly modified so they could be used to work exclusively with the ADI DMAC IP without requiring a custom IP core from MathWorks; dedicated [config file](https://github.com/m1nl/analogdevicesinc-linux/blob/ebaz4205/arch/arm/configs/zynq_ebaz4205_defconfig) for `ebaz4205` board is included

`u-boot-xlnx` - [Xilinx U-Boot](https://github.com/Xilinx/u-boot-xlnx) variant with [DTS (Device Tree Source)](https://github.com/m1nl/u-boot-xlnx/blob/ebaz4205/arch/arm/dts/zynq-ebaz4205.dts) and [configuration](https://github.com/m1nl/u-boot-xlnx/blob/ebaz4205/configs/zynq_ebaz4205_defconfig) for the `ebaz4205` board

## Build Instructions

You need to install Vivado 2023.2 from Xilinx (you can download it from their webpage for free). I recommend installing it to `/opt/Xilinx` - if you choose a different location, you'll need to modify the Makefile or provide the `VIVADO_SETTINGS` environment variable.

```bash
 sudo apt-get install git build-essential fakeroot libncurses5-dev libssl-dev ccache
 sudo apt-get install u-boot-tools device-tree-compiler libssl1.0-dev mtools
 sudo apt-get install bc python cpio zip unzip rsync file wget
 git clone --recursive https://github.com/m1nl/ebaz4205-hdmi-demo.git
 cd ebaz4205-hdmi-demo
 make
```

This project uses the latest GCC toolchain and binutils available in `buildroot` and Linux kernel version 6.12.x (rebased `adi-6.12.0` branch over tag `xlnx_rebase_v6.12_LTS_2025.1_update1` from the Xilinx Linux Kernel variant).

The Linux boot command line is configured in the DTS file `u-boot-xlnx/arch/arm/dts/zynq-ebaz4205.dts`.

HDL utilizes Vivado and Analog Devices TCL commands to define the block design. If you wish to open the project in Vivado, build it first and then you'll be able to open the generated XPR file `hdl/projects/ebaz4205/ebaz4205.xpr`.

## SD-card Setup

1. Build the project or download binary release
2. Create two partitions on the SD-card
3. Format first partiton as `vfat` and copy all files from `build_sdimg` directory (or `boot` when using binary release)
4. Copy contents of `rootfs.ext4` to the other partition
```
 dd if=build/rootfs.ext4 of=/dev/mmcblk0p2 bs=16M
```

## Updating Local Repository 

```bash 
 git pull
 git submodule update --init --recursive
```

## HDMI Sink Implementation

Currently, the supported video format is **640×480@60Hz** (Video ID Code 1): 25.2MHz pixel clock.

#### System Integration (`hdl/projects/ebaz4205/system_bd.tcl`)

**HDMI Subsystem Configuration**:
```tcl
# HDMI IP instantiation
ad_ip_instance hdmi hdmi_0
ad_ip_instance hdmi_generator hdmi_generator_0

# HDMI port connections
ad_connect hdmi_0/tmds_0 hdmi_d0
ad_connect hdmi_0/tmds_1 hdmi_d1
ad_connect hdmi_0/tmds_2 hdmi_d2
ad_connect hdmi_0/tmds_clock hdmi_clk

# Clock domain connections
ad_connect sys_cpu_clk hdmi_generator_0/clk_100m
ad_connect sys_cpu_reset hdmi_generator_0/reset_100m

ad_connect hdmi_generator_0/pixel_reset hdmi_0/reset

ad_connect hdmi_generator_0/pixel_clk hdmi_0/clk_pixel
ad_connect hdmi_generator_0/pixel_x5_clk hdmi_0/clk_pixel_x5
ad_connect GND hdmi_0/clk_audio

# Data path connections
ad_connect hdmi_0/cx hdmi_generator_0/cx
ad_connect hdmi_0/cy hdmi_generator_0/cy
ad_connect hdmi_0/screen_width hdmi_generator_0/screen_width
ad_connect hdmi_0/screen_height hdmi_generator_0/screen_height
ad_connect hdmi_generator_0/rgb hdmi_0/rgb

ad_ip_instance xlconstant audio_sample_word_GND
ad_ip_parameter audio_sample_word_GND CONFIG.CONST_VAL 0
ad_ip_parameter audio_sample_word_GND CONFIG.CONST_WIDTH 16

ad_connect audio_sample_word_GND/dout hdmi_0/audio_sample_word_0
ad_connect audio_sample_word_GND/dout hdmi_0/audio_sample_word_1
```

### DMA Controller Configuration and Connections
The system employs the Analog Devices DMA Controller (ADI DMAC) for high-performance video data transfer:

```tcl
# DMA IP instantiation
ad_ip_instance axi_dmac hdmi_sink_dma
ad_ip_parameter hdmi_sink_dma CONFIG.DMA_TYPE_SRC 0          # AXI-MM source
ad_ip_parameter hdmi_sink_dma CONFIG.DMA_TYPE_DEST 1         # AXI-Streaming destination
ad_ip_parameter hdmi_sink_dma CONFIG.CYCLIC 1                # Enable cyclic transfers
ad_ip_parameter hdmi_sink_dma CONFIG.DMA_DATA_WIDTH_DEST 64  # 64-bit data path

# Clock domain connections
ad_connect hdmi_generator_0/pixel_clk hdmi_sink_dma/m_axis_aclk

ad_connect sys_cpu_clk hdmi_sink_dma/m_src_axi_aclk
ad_connect sys_cpu_resetn hdmi_sink_dma/m_src_axi_aresetn

# Data path connections
ad_connect hdmi_generator_0/s_axis_rgb hdmi_sink_dma/m_axis

# CPU interconnect
ad_cpu_interconnect 0x7c420000 hdmi_sink_dma

ad_ip_parameter sys_ps7 CONFIG.PCW_USE_S_AXI_HP0 {1}
ad_connect sys_cpu_clk sys_ps7/S_AXI_HP0_ACLK
ad_connect hdmi_sink_dma/m_src_axi sys_ps7/S_AXI_HP0

create_bd_addr_seg -range 0x20000000 -offset 0x00000000 \
                    [get_bd_addr_spaces hdmi_sink_dma/m_src_axi] \
                    [get_bd_addr_segs sys_ps7/S_AXI_HP0/HP0_DDR_LOWOCM] \
                    SEG_sys_ps7_HP0_DDR_LOWOCM

# Interrupt
ad_cpu_interrupt ps-12 mb-12 hdmi_sink_dma/irq
```

### Data Flow Architecture

1. **Memory Interface**: 
   - Source: DDR3 system memory via AXI HP0 port
   - Bus width: 64-bit for optimal bandwidth utilization

2. **Streaming Interface**:
   - Protocol: AXI4-Stream
   - Data width: 64-bit parallel data
   - Clock domain: Pixel clock (25.2MHz for 640x480@60Hz)

3. **RGB Conversion**:
   - Input: 64-bit AXI Stream data packets
   - Output: 24-bit RGB pixel data (8-bit per channel)
   - Buffering: LUTRAM for frame synchronization

**Bandwidth Requirements (640x480@60Hz)**:
- Pixel clock rate: 25.2 MHz
- DMA data rate: 640 x 480 x 3 x 8 x 60 bps ~= 442.4 Mbps
- Buffer depth: 64-bit words transferred over DMA
    
### Clock Domain Management

**Primary Clock Domains**:
1. **System Clock**: 100MHz (PS7 FCLK_CLK0)
   - CPU, DMA controller, AXI interconnect
2. **Pixel Clock**: 25.2MHz (generated by MMCME2_ADV PLL)
   - HDMI timing generation, RGB data output
3. **Serializer Clock**: 126MHz (pixel_clock × 5)
   - TMDS serialization, high-speed I/O

**Clock Generation** (in `hdmi_generator.v`):
```verilog
MMCME2_ADV #(
    .CLKIN1_PERIOD(10.000),        // 100MHz input
    .DIVCLK_DIVIDE(5),             // Pre-divider
    .CLKFBOUT_MULT_F(50.500),      // VCO multiplication
    .CLKOUT0_DIVIDE_F(40.000),     // 25.2MHz pixel clock
    .CLKOUT1_DIVIDE(8)             // 126MHz serializer clock
) mmcm_adv_inst;
```

### Serial Console

By default, `Serial1` is used for FSBL and U-Boot to make it possible to access the board bootloader without the expansion board - you can interact with U-Boot by connecting a serial converter to the pin header on the main board. Buildroot is configured to use `Serial0` for Linux console, which is set up to work with the expansion board attached - use a serial converter from the board over a USB cable to interact with the Linux console. You can change the default Linux console to `Serial1` by modifying the board configuration file `buildroot/configs/zynq_ebaz4205_defconfig` and setting `BR2_TARGET_GENERIC_GETTY_PORT` to `ttyS0`.
 
### Network Access

The default IP address is `192.168.2.99`, the username is `root` and the password is `toor`. This configuration is set up in the `buildroot/board/ebaz4205/interfaces` file.

## Using Expansion Board Components

- **HDMI**: there are three examples under `/root` (`hdmi_test.py`, `hdmi_test_2.py` and `hdmi_test_3.py`) - you can simply run them to see output on the HDMI screen. They use libiio Python bindings to set up cyclic and non-cyclic buffers and transfer frame data to the HDMI sink
- **SPI Display**: it's mapped as a Linux framebuffer with the staging `fbtft` driver - interact with the `/dev/fb0` device to use it; you can use the example provided under `/root` (`fb_test.py`)
- **Buzzer**: it uses the Zynq TTC peripheral, use the `beep` utility to generate sounds (`beep -f 2400`)
- **Buttons**: the main board button will reboot the board when pushed; other buttons are mapped with device tree to keys, but they don't trigger any action by default.

## Support and Further Development

Feel free to open an issue if you have any problems building the project. Pull requests are welcome if you'd like to add support for more components or improve the DMA data path.

## Licensing and Compliance

### Software Licensing
- **Project Code**: MIT License (custom components)
- **Buildroot**: GPL v2 (inherited)
- **Linux Kernel**: GPL v2 (inherited)
- **U-Boot**: GPL v2 (inherited)
- **HDMI SystemVerilog Code** (https://github.com/hdl-util/hdmi): MIT License (inherited)

### HDMI Compliance
- **Development/Testing**: No restrictions for non-commercial use
- **Commercial Deployment**: HDMI Licensing Administrator compliance required
- **Alternative**: Enable `DVI_OUTPUT` parameter for license-free DVI compatibility

## Technical References

### Hardware Documentation
- [Zynq-7000 Technical Reference Manual](https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-SoC-TRM.pdf)
- [HDMI 1.4b Specification](https://www.hdmi.org/spec/hdmi1_4b)

### Software References
- [Analog Devices HDL User Guide](https://wiki.analog.com/resources/fpga/docs/hdl)
- [Buildroot User Manual](https://buildroot.org/downloads/manual/manual.html)
- [libiio Documentation](https://analogdevicesinc.github.io/libiio/)

---
