Once I found and fixed a missing command within my initialization sequence, I have gained full programmatic control over the LCD screen of a control panel I salvaged from a Canon MX340 multi-function inkjet. The main point of the exercise was to learn, because it's a relatively simple black-and-white screen 196 pixels wide by 34 pixels tall and not terribly exciting on its own. Still, now that I know how to send it frame buffer data... what can I do with it?

I'm not interested in re-implementing standard graphics routines myself, so I went looking for one already available. While learning about MicroPython I recall coming across mention of a framebuf utility class for basic graphical operations on a frame buffer. As a fork of MicroPython, Adafruit has a corresponding CircuitPython implementation named adafruit_framebuf so I thought I'd take a look.

One of the frame buffer byte formats supported is called MVLSB. The M stands for monochrome, and the V means each byte represents a vertical column of eight pixels. LSB means least significant bit is the highest pixel, and the most significant bit is the lowest. This is very close to what I have on hand except for the bit order. On this screen, the least significant bit is the lowest pixel and they go up from there.

This is the result of drawing a diagonal line from upper left (0,0) to lower right (195,33). Since bit order is reversed within each byte, each horizontal stripe of data gets rendered vertically inverted from what they are supposed to be.

Drawing text results in gibberish when it crosses stripes. But if I position the text so it sits entirely within a single stripe, the result is legible as vertically inverted text. "Hello Framebuffer" in this case.

I could write some code to laboriously step through each bits in a byte and generate a bit-reversed counterpart value, but since there are only 256 possibilities, a lookup table would be much faster at the expense of a bit of memory. I went online looking for such a lookup table and found one in this Stack Overflow thread: Efficient Algorithm for Bit Reversal (from MSB->LSB to LSB->MSB) in C.

I modified that lookup table from C to Python syntax, and used it to reverse a stripe of frame buffer data before transmitting it to the LCD. Now my diagonal line renders as expected. Unfortunately, text rendering now fails with "RuntimeError: pystack exhausted". This was unexpected. The lookup table itself would have consumed at least 256 bytes, and there's an additional 196 bytes of working buffer for me to perform bit reversal on a single stripe. I didn't think I was skating close to RP2040 limits yet here we are. Also, it's not a general out of memory error, but specifically about call stack size and the bit reversal mechanism didn't increase the call depth at all. Weird!

Well, reversing bits was just a hack anyway. The right approach is to add support for this byte format directly so convoluted bit reversal workaround becomes unnecessary. And it restored text rendering, too.