Controller
I will design the controller PCB to accept a DC input of 11~14V. From that it needs to supply the 3.5~4.3V @ 7.5A for the LEDs. It will also have the video processing logic on it. The video processing logic will require +/-5V and 3.3V analog supplies at about 40mA each. The microcontroller needs about 80mA at 3.3V. I will also use a Noritake VFD for debugging and test -- though it might make it into the final product. It will require 5V at 300mA. I've no case in mind - I'll probably just get a bit of acrylic laser cut and mount it on that below the TV. I figure the maximum DC current will be about 3.5A at 11V in, I'll probably power it from a 12V brick.
FPGAs are still new to me, and HDMI is a bit of a beast of a protocol plus will usually require an expensive PCB to use. I will be using VGA for the video input. This is fairly simple to understand, can be captured using a simple microcontroller, and my media PC, the source of almost all content displayed has a VGA port. For future use, I will want to add support for games consoles and OTA TV, so I will build a second revision with a HDMI port - or perhaps some plug in module for the current board. Alternatively I could also invest in a HDCP stripper and capture the HDMI video straight out of my AVR.
Maximum video input will be 1920x1080p at 60Hz which is a pixel clock of 165 MHz although the typical input will be 24Hz cinema video. I will be sampling at up to 2 MHz on this signal using sample and hold buffers to capture small area averages. I figure one possible way would be to capture a random scattering of pixels underneath each LED area. I could also do the capture deterministically on specific known pixels, making sure to get sufficient averages for each LED pixel. To simplify processing, I could compute only every 2nd LED, with the LED in between the two representing some kind of average, though if I can I'd like to avoid this. All video data to be captured on each VGA HSYNC. By counting HSYNC and VSYNC, it will be very easy to know what line we are on, and VGA is fairly clean for pixel timings, so we can probably get down to the resolution of about 5 pixels. I don't need pixel perfection. Interlaced video doesn't need to be supported.
I'll put an EDID EEPROM on the board for the PC to ID the widget - I'll copy the data my Kuro reports in a hope that this will keep the timings identical for both.
I'll also give the board an audio input so it can work in a solo manner with just an audio source and play patterns related to the music.
I use XBMC for my media PC. It's set up to change the display refresh rate to match the content. This is one easy way to detect if the content changes - with this I can set up a routine to look for 21:9 or 16:9 content and adjust the LED behaviour respectively (21:9 would dim the top and bottom LEDs.)
Data wise, I want each of the 210 LEDs to be able to accept an independent intensity level in R, G and B. Internally I will be using 12-bit data (the reason will become clear later.) The frame rate needs to be at least 60Hz, but ideally would be much higher- about 240Hz. From measurement of the current test board, it takes 277us to write 9 LEDs, so a reasonable estimate will be 6.46ms for 210 LEDs, excluding calculation time. I will therefore split the LED branches into two halves of 105 LEDs so the write time is shortened to about 3.2ms.
Memory wise, about 6 bytes are required per pixel (because 12-bit data), plus the SPI data generation requires another 9 bytes per pixel. Total memory ~3150 bytes - no problem for a TM4C123GH6PM with 32K of SRAM. With up to 10 subframes though, I might end up using another ~16.5K (I will need to buffer all 10 subframes per real video frame.)
Gamma Correction, Dithering, Subframes
The WS2812B LEDs only use 8-bit PWM, but that has poor low level detail. Plus, I need to gamma correct it by applying a CIE luminance curve. This reduces the effective video bits to about 6 bits, which is pretty poor. In particular on dark shades you can see an obvious stair-stepping effect and colour resolution is poor at low levels.
One solution is to use dithering - flicker the LED quickly between the two closest levels. This technique is also used by plasma displays, and when done correctly is essentially unnoticeable. Initially, I tried dithering with a PRNG - but the results were poor. The flicker is obvious. I then tried using dithering with a deterministic pattern - I made a few bit shift patterns which maximised available flicker frequency. This works surprisingly well - the human eye is good at integrating very short brightness events. I use 16 periods per frame for a prototype but in the real version I will switch to 4 periods per frame (for 60Hz) and 10 periods per frame (for 24Hz Cinema.) The increased effective bit depth for cinema viewing is nice and the dither rate will be about 240Hz so should be completely unnoticeable. The 12-bit gamma corrected data (from 8-bit linear source video) allows for up to 16 dither frames although that would be difficult to implement, so the dithering will be spread across different real frames, and spatially translated amongst each LED - so the LED dither pattern is constantly moving around making it even harder to perceive.