Greyscale 2bit 4 Colour success with SSD1306

Here’s a sample pic of 2bit 4 colour greyscale pattern obtained syncronizing with FR pin on SSD1306.
Cool huh ? It’s a bit tricky getting a good photo due to camera out of sync with SSD1306.


Looks awesome. Now @bateske needs a serious talk with some manufactures :wink:

1 Like

It looks good I would love to see some the quality of some images on it.
If Arduboy cannot produce the numbers to be taken seriously for numbers maybe it’s something that can be pushed by the tech community as a whole.


Imagine an Arduboy with 4 colors… :heart_eyes: :heart_eyes: An Arduboy with more space could really take advantage of it the grayscale. :heart_eyes: :heart_eyes:

Just curious, is this what @bateske is talking about with the vsync signal, or is this something else?


Just to make things crystal clear – is the trick here that you are painting the brightest pixels 4 times every 4 passes, and lower intensity pixels less frequently? And frame sync is needed so that you can control every pixel update on every pass?

There’s only 3 passes with 4 colours.
OK … How it works:
If you want to display a single mid grey colour, you just alternate 2 images. A black image then a white one, then the black one again etc. For a lighter colour grey you use 3 images and display black, white, white etc
Lighter grey again - black, white, white, white etc.
Important info:
Everytime you add an extra image, you effectively reduce the frame rate to ‘Max FPS / Number of images’. If you go too far you start to get flicker on the screen.
So if you started out with, in my case a maximum frame rate of 128 FPS, as soon as you add a second image, you have effectively reduced the frame rate by half to 64 FPS. Note that the true frame rate is still 128FPS, but the effect is like 64FPS. 3 images gives us 128 / 3 = 42.66 FPS. 4 images = 32 FPS etc…
At 4 images, the flicker starts to appear especially with full black / white transitions. Small sprites or whatever wouldn’t be a problem though.
The FR signal gives you the true display update frequency. It doesn’t lie. A quick scope view or frequency counter test gives us this info.
I’ve tested a couple of these displays and there can be a large difference in maximum frame rate between them, which is what the spec sheet advises too. One of my display’s maximum frame rate is 165 FPS. The one in the pic above will only max out at 128 FPS. The faster the max frame rate - the less flicker you’ll get.
So my 4 colour image above is created with the following images:
Image 1 BBBW
Image 2 BBWW
Image 3 BWWW
Number of colours possible = Number of images +1

My 5 Colour test used:

So with the FR signal available, I just wait for it to transition low to high and then write the first image to SSD1306.
Wait for next low to high transistion and write second image, and so on. Pretty simple.
So with a frame rate of 128 FPS I have 1/128 = 7.8125 ms to get each image written, which is heaps of time with a 4Mhz SPI clock. So you’re actually writing to memory just ahead of SSD1306’s read of memory which is a pulse width difference (270us) at the start . The gap increases as we go, because I’m writing faster than SSD1306 is reading. Cheers

Here’s 5 Colour sample:

Hi Scott, If you want to produce some sample images for me, I’m happy to display and post a demo here.
You might want to read my post above to see how they’re created. Cheers

Yes … this what bateske is talking about.

Dang, then the factories won’t help us. :’(

so for a stable framerate CL and CLS would need to be broken out also for a games frame rate to stay in synch with the display framerate.

The frame rate is stable already. You just can’t rely on its maximum rate from chip to chip. Or is this what you meant ?
Using CL and CLS is a preferable option when it comes to maximum frame rate of course, because YOU choose the maximum clock rate and consequential frame rate and we don’t yet know what the max freq is there. I’ll have to have a look.
CL and CLS is not the whole solution because we still need the FR sync signal. You may be in time and in phase using CL and CLS but you have no idea where in time FR signal happens, so it’s still needed.
That’s 3 damn lines that would have to brought out !

1 Like

What I was trying to say is that there are two frame rates to deal with. One is the MCU rendering frame rate and the other the display frame rate. There is no space for double buffering so for smooth animations the display frame rate has to be the same or a multiple of the rendering framerate otherwise there will be the odd frame skip.

the MCU and display need to stay in sync.

That’s what I was trying to so say.

Yo @ADI8421 this is nice! Your epoxy blob mod is incredible. :heart_eyes:

Can you make a video? :pleading_face:

Does anyone know anyone in Taiwan?

I understand exactly what you’re saying. I guess you currently just write to the display memory whenever you’re MCU rendering is done? Would that be correct ?
And the problem with that, if it is what you do, is that some of the written data may get over written before it even gets to the screen.
I’ve read online in other places, people thumping their chests because they’ve managed to write to the display at some rediculous frame rate. It means absolutely nothing if you can write to the graphic display ram at 10 times the display update rate because the first 90% of that data isn’t going to make it to the screen, because it’s been over written before it got there. I can write to display ram using an 8Mhz SPI clock rate if I want to, but still have to wait for the frame sync before I write anything more. Nothing to gain.

It’s just black nail laquer. No mixing to do. You can even put it on your nails if you have a special bar to go to tonight.

Note quite after the rendering is done and the buffer is copied to the display a timer is queried to see if enough time has passed before the next frame is rendered.

That would most likely cause flicker / tearing

There is a big advantage on doing that: there is more MCU time for more time consuming rendering code.

The current copy to display code implementation is able to push the 1K display data in ~1.15mSec (18 cycles / byte) so theres a lot of MCU time available to draw something fancy in the display buffer.

SPI clock at fastest speed of 8Mhz = 1 / 8000,000 = 125ns x 8bits x 1024 bytes = 1.024ms to write 1K data. That leaves 126us for code overhead, which is 2016 16Mhz MCU clock cycles left. Not enough time to load each byte into the SPDR register and check SPIF flag for each byte.
Someone’s having you on I think, unless you’re running at higher than 8Mhz SPI clock speed.

Video as requested. Didn’t come out too good due to frame rate differences with camera.
Youtube Link:
Greyscale 4 Colour SSD1306

Nice! Any chance you’ve got one of the new fancy phones that can do slo-mo? :smiley:

The code is here. It is designed to run “open loop” (i.e. no SPIF flag check) and is tuned for 32u4 running at 16MHz with an 8MHz SPI clock. This is the relevant conversation and measurements taken by @Mr.Blinky.

FR is sufficient to sync MCU rendering with the display. i.e. all you need to sync a clock domain to another is a pulse signal at a regular interval (like PPS). For this kind of application (frame sync) you can ignore drift between the clocks involved.