Do you like my hacking? If so, please consider leaving something in the
Fediverse (Mastodon etc): @Sprite_tm@social. spritesmods.com
First of all: the hardware. I'm not even gonna draw up a schematic here: just take an Olinuxino Nano (or any other iMX233-based board on which you can free up the LCD bus pins) and connect every LCD data line (usually referred to as LCD_Dx) to the Din of a WS2811-based LED-strip. Power the LED-strips and the Olinuxino using a 5V power supply and you should be good. Officially, the WS2811 needs a 5V signal to work while the iMX233 only outputs 3.3V, but in practice the WS2811 seems happy with it. When in doubt, you may want to add some level-conversion logic.
Here's my implementation. As you can see, I only connected 4 short LED-strips, but the full 16-bit bus is
available on the Olinuxino pins, so I could have connected 12 strips more. Also, the length of the strips
was purely defined by what I had on my hands and not indicative for what the hardware can do:
Modern arm kernels have all the hardware dependencies defined in the device tree section. Ideally, those files perfectly define the hardware the kernel is going to run on, allowing the kernel to load the right drivers and attach them to the right peripherials, making everything work automatically. So, to add support for the specific flavour of framebuffer I needed, I only had to modify two files. The main iMX233 dts file didn't have an 16-bit LCD interface defined yet, so I added that to arch/arm/boot/dts/imx23.dtsi. Then, I needed to define the lcdif specifics in arch/arm/boot/dts/imx23-olinuxino.dts: I added a definition for the lcdif that uses the 16-bit mode, plus a display mode of 360x256 pixels with a dotclock of exactly 4MHz. You can grab a patch to do those things for you; please apply it after where the instructions tell you to apply i2c support patch. Note: this patch also disables the i2c bus because some of its pins overlap with the LCD-controller pins. You also need to configure the kernel to add support for the iMXs framebuffer: grab my kernel config as an example.
The way this patch configures the video hardware isn't completely ideal: it seems either the Linux driver
or the hardware itself refuses to have a front porch or hsync length of zero. That means the minimum
value for those is one, meaning after every line of pixels, we get 0.5uS where we can't output data and
the LCD bus is forced to all-zeroes. This messes up the timing a little bit. Fortunately, there's a
workaround. It seems the time between sending the last bit of a led and the first bit of the next led
isn't critical: there can be up to 20 cycles (5uS) before the LED-strip gets confused. I've chosen
360 pixels as the width of a line in the framebuffer The amount of pixels needed to set one led is
24 bit * 5 pixels for one bit = 120 pixels, so a single line will contain exactly the data needed
for three LEDs. That means the 2 hsync/frontporch pixels will be exactly in the bit of datastream
where the timing doesn't matter that much, making everything work anyway.
Now, all is left is a program to push the right bits into the framebuffer. I've written a small proof-of-concept program that pushes an animation to the LEDs. The animation is restricted to the physical LEDs I have but the routines that handle the data conversion from LED-colors to WS28110-signals assume there are 16 strips of 600 leds each connected to it. Even with the burden of generating signals for almost ten thousand LEDs, the program still gets framerates of 30fps, and this can probably be improved even more.