This month's Project14 | Build Projects that Use a Programmable Logic Device such as FPGA or CPLD! theme comes after almost a year since I first started working with FPGAs.
While the project at its current stage does not make use of the ARM core in the Zynq, I managed to make use of a lot of what I learnt in Path to Programmable.
My entry for this month's Project14 contest is an FPGA based HDMI to FPD-Link converter - a device that takes video from a HDMI source, decodes it, encodes it and sends it to a LCD panel over FPD-Link (commonly referred to as LVDS).
I completed this project around 4 months ago, but I decided to enter it into this month's contest for two reasons:
- it's a good example of a project that cannot be done using a microcontroller, and makes good use of FPGA capabilities.
- it's got the right mix of Project14 material: a little reverse engineering, pushing hardware to its limits, overcoming obstacles, a mix of hardware & software HDL and the right about of duct tape holding all of this together.
For those who want to dive into the details of how this was done, I've published 2 blog posts:
- Driving a Laptop LCD using an FPGA is the first part which goes over the process of figuring out the LCD panel's connections, turning on the backlight, building the TMDS to LVDS conversion circuit, and most importantly, the FPGA gateware modules that generate a test pattern, convert RGB data into the format required by the panel and transmit it to the panel via the LVDS interface using the output SERDES blocks on the FPGA. While this didn't seem to complex at first, there were two major hurdles: generating a DC biased LVDS signal using the FPGA's single-ended I/O without using a dedicated CMOS to LVDS converter IC, and serializing the data stream at a rate that exceeded the clocking capabilities of the FPGA speed grade that I was using.
- LCD panel + FPGA with an HDMI sink = External Display is the second part which details how the RGB test pattern was replaced with data from a HDMI source. I started with Digilent's DVI-to-RGB IP, which decodes the HDMI stream into RGB, and later made a couple of changes to it due to issues with having multiple clock domains, and replaced the default EDID with the EDID of the panel I was using so that the HDMI source can recognize the supported display modes and set the clocks & resolution appropriately. This post also describes how I debugged a color channel swap issue using the Vivado logic analyzer and solved some interference related video signal distortion using.. aluminium foil.
I've been using this as an external monitor for over 3 months, and it works pretty reliably (except for when it blanks out for a couple of seconds when a tubelight is turned on, which is probably due to the lack of shielding on the back).
There isn't much to see since it's just a panel displaying video, but here's a short demo as proof that it works:
The HDMI cable is connected to the 'sink' port towards the upper right of the Zybo Z7 (near the yellow 'HDMI Hot Plug Detect' LED. The microUSB cable powers the Zybo Z7, and the Zynq-7000 boots from a bootimage that is on a microSD card (so that I do not need to open Vivado to program the bitstream every time I turn on the PC) that's attached to the underside of the Zybo. The PS (ARM Cortex-A9) of the Zynq doesn't process the video stream since that's handled entirely by the PL (FPGA fabric), so it's configured to run everything (CPU, PLLs & DDR) at the lowest possible clocks to reduce the power consumption, and mainly the heat generated since I noticed that the tiny heatsink on the Zybo Z7 was getting warm. I also execute a wfi() instruction to put the ARM core to sleep.
4 differential pairs (covered in foil) carry the serialized signal from the PMOD connectors to the panel's LCD controller on its PCB via the perfboard which has pullup resistors connected to 1.5V (which converts TMDS to LVDS). I also taped the CFL inverter, voltage regulator (which generates 1.5V from 3.3V) and a power distribution PCB which has screw terminals to which I connect the 12V, 3.3V & ground from a power supply.
Additional features like a configurable overlay and ambient back-lighting using a WS2812 strip are a work in progress. They're taking a little more time than I expected since it requires figuring out how to use Xilinx IP, DMA engines, the AXI interconnect and the external DDR3 DRAM connected to the PS.