DIY hand-held games console: Faster GUI
Last updated: April 19, 2023, 10:19 p.m.
It's been a while since I got anything done on the Noodle Game console, but I found it on my desk and had a few minutes to spare so thought I'd have a crack at upgrading the screen driver code. It was a little bit of a disappointing exercise but at least I've learned some things.
Stuck in 24 bit
The screen supposedly supports a bunch of different colour depths including 18 bit (6 bits of each colour) note that this isn't a nice multiple of 8, a 16 bit mode where green has 6 bits but red and blue only 5 and apparently even a 3 bit mode where it has just one bit per colour like a Sinclair Spectrum. Unfortunately in SPI mode it only supports either the 8 bit or the full 18 bit modes. In 18 bit mode the colours are padded to a full byte each and so need three bytes per pixel.
Slow clock
The screen module I've got is hard-wired to SPI mode. The module can do parallel RGB, host bus or even MIPI-DSI apparently all of which offer faster data transfers and a choice of colour depths but only SPI pins are broken out on the PCB I got. The SPI interface is limited to just over 15MHz (see page 301 of the controller datasheet) Here it says the write clock cycle time must be at least 66ns. But that's just one bit and we need to transfer 24 for each pixel. For a 320 x 480 pixel display that means a full screen refresh will take 320 x 480 x 24 x 66ns = 0.24 seconds which means an absolute maximum frame rate of 4 fps.
Annoying clock restrictions
On the STM32F429 the SPI clock is decided by a power-of-two divider from the system clock which means you have quite coarse control of the frequency. The nearest I could get to the limit without exceeding it was about 10.5MHz. That means our refresh has gone down to about 3fps.
Making the best of it
I did what I could and prepared the screen in a 24bit buffer (not directly supported by LVGL yet although it's on its way apparently) I could accelerate this with the DMA2D peripheral in the STM32F429 but it wasn't really a bottleneck compared with the SPI bus. I then used DMA to write the data to the screen as fast as possible. DMA transfers are limited to 64kB so it takes a number of transfers to get the whole display updated which is probably adding to the redraw time. In the end the refresh is still painfully slow to watch.
Have a look at the code at this point on GitHub
Comments
Posting comments is not currently possible. If you want to discuss this article you can reach me on twitter or via email.