There’s no hardware documentation as such, but the Blinkt! is just a chain of 8 APA102 LED pixels, albeit ones with a particularly quirky implementation of the protocol, which can be driven by just toggling a couple of GPIO pins (data and clock).
It would be easy to, for example, create a C library you could bind into. I started with C for Blinkt!, intending to bind against it with Python, until I realized that it was simply overkill for most uses.
Anyway. The Blinkt! protocol is relatively straight forward. It’s just like driving a shift register, toggling the clock line and setting data bits in turn.
It comprises 8 APA102 pixels, the protocol of which is explored here: https://cpldcpu.com/2014/08/27/apa102/
The data line is connected to BCM 23
and the clock line to BCM 24
.
The pixels are 24bits, 8bits per colour and include an 8bit “start frame” that has a 5bit brightness value for a total of 32bits per pixel:
start blue green red
111 00000 00000000 00000000 00000000
^
5-bit brightness value
All of the important stuff happens here: https://github.com/pimoroni/blinkt/blob/master/library/blinkt.py#L62-L79
Here’s that chunk with just the interesting bits of code:
def show():
"""Output the buffer to Blinkt!"""
_sof()
for pixel in pixels:
r, g, b, brightness = pixel
_write_byte(0b11100000 | brightness)
_write_byte(b)
_write_byte(g)
_write_byte(r)
_eof()
For each pixel, you need to clock out the pixel start frame which is 0b11100000
plus a brightness value from 0 to 31.
Then the b, g and r values are clocked out in the same way.
_write_byte()
does simply that, it outputs each bit of a byte to the data line and pulses the clock: https://github.com/pimoroni/blinkt/blob/master/library/blinkt.py#L41-L46
It does this by clocking out the most significant bit of the byte and shifting that byte left once for each bit.
def _write_byte(byte):
for x in range(8):
GPIO.output(DAT, byte & 0b10000000)
GPIO.output(CLK, 1)
byte <<= 1
GPIO.output(CLK, 0)
_sof()
and _eof()
stand for Start Of Frame and End Of Frame, these are the data bits that reset and latch the APA102 pixels: https://github.com/pimoroni/blinkt/blob/master/library/blinkt.py#L50-L60
def _eof():
GPIO.output(DAT, 0)
for x in range(36):
GPIO.output(CLK, 1)
GPIO.output(CLK, 0)
def _sof():
GPIO.output(DAT,0)
for x in range(32):
GPIO.output(CLK, 1)
GPIO.output(CLK, 0)
In this case, they’re just setting the data line and pulsing the clock. _eof()
pulses the clock 36 times, clocking out 36 zeros. _sof()
pulses the clock 32 times, clocking out 32 zeros.
So to summarize, in order to drive Blintk! you should:
- Clock out 36 zeros
- Clock out 8 pixels, for each pixel:
- Clock out start frame with brightness from 0 to 31:
0b11100000 | brightness
- Bytes are clocked out most-significant-bit (the left-most bit) first
- Clock out blue byte
- Clock out red byte
- Clock out green byte
- Clock out 32 zeros