[HN Gopher] SSD1306 display drivers and font rendering
       ___________________________________________________________________
        
       SSD1306 display drivers and font rendering
        
       Author : todsacerdoti
       Score  : 45 points
       Date   : 2025-04-14 17:08 UTC (5 hours ago)
        
 (HTM) web link (subalpinecircuits.com)
 (TXT) w3m dump (subalpinecircuits.com)
        
       | kaycebasques wrote:
       | I really love the SSD1306 for its educational value. If you've
       | bought a sensor kit for Arduino or ESP32 or Pico or whatever,
       | chances are decent that you already have an SSD1306 lying around.
       | There's so much example code for it. And the datasheet was pretty
       | easy to grok IMO. My first exposure to it was in the pico-
       | examples repo: https://github.com/raspberrypi/pico-
       | examples/tree/master/i2c...
       | 
       | There's a few Rust libraries for it, too. And it's supported in
       | Wokwi! https://wokwi.com/projects/425067706980448257
        
         | hadlock wrote:
         | I love the SSD1306 simply because a simple arduino can drive it
         | at ~150fps making for some _really_ smooth graphics. 1 bit per
         | pixel monochrome OLED means it 's got a tiny frame-buffer, and
         | you can drive it ridiculously fast especially over SPI. It's
         | really great for stuff like realtime gauges etc.
        
       | 4gotunameagain wrote:
       | That's one of the biggest shaving the yak tangents I've seen.
       | 
       | Love it.
        
       | foldr wrote:
       | It's generally quite easy to use these over I2C without a driver.
       | You can crib the sequence of initialization commands from the
       | example code supplied by the manufacturer (or loads of examples
       | on GitHub), and then the commands to draw to the screen are
       | pretty straightforward. The chip has its own display RAM, so you
       | don't need to worry about redrawing every time the display
       | refreshes or anything as low-level as that.
        
         | grmnygrmny2 wrote:
         | Interesting! That could be good way to boost the speeds here
         | for sure, as I'm still pushing out a full framebuffer out with
         | every update and am not usually updating the whole screen.
        
       | arghwhat wrote:
       | Go for the SPI version, which is the same chip but just s
       | different breakout board.
       | 
       | Many ESP32's can only do 400kHz I2C, whereas their SPI peripheral
       | can often do 80 MHz or more (although you wouldn't want to go
       | _that_ fast here). 400kHz sort of works, but if you also want to
       | handle other I2C devices it can easily become a problem.
        
         | grmnygrmny2 wrote:
         | (author here) I've been pondering this, yeah. I'm currently
         | sharing the I2C bus with a DAC and that's working alright, but
         | the refresh rate issue is enough to make me consider SPI. I
         | know the SPI peripheral supports DMA as well, and the I2C one
         | doesn't (sort of? I know there's "async" transmit now but can't
         | tell if that's really doing DMA)
        
           | arghwhat wrote:
           | The I2C peripheral is DMA - a write just queues an operation
           | descriptor in a hardware FIFO, and interrupts fire whenever
           | something exciting happens or the FIFO is drained. The
           | synchronous implementation is just blocking on a condition
           | set by the interrupt handler.
           | 
           | But this is exactly the kind of thing the SPI peripheral is
           | meant for. This cannot be said for the I2C peripheral, with
           | its measly fast mode support.
           | 
           | Depending on the chip and your usecase, you might also want
           | to use I2S for your DAC.
        
             | grmnygrmny2 wrote:
             | Ah! That makes sense, thanks!
             | 
             | And yes, the audio data runs over I2S - the chip I'm using
             | just uses I2C for control.
        
         | generj wrote:
         | I2C is nice because it is (with Adafruit and Sparkfun's Stemma
         | QT/Qwiik) literally plug and play for beginners, with a wide
         | variety of sensors available.
         | 
         | Plus not needing to dedicate a control pin per device added to
         | the bus. Though of course if data throughout is an issue SPI is
         | better than I2C.
        
           | arghwhat wrote:
           | I2C is fine for sensors and other low-bandwidth devices, but
           | inappropriate for displays and other high-bandwidth devices.
           | 
           | When used with those kits, you'd use the QWIIC/whatever
           | connector for all the sensors and other low-bandwidth things
           | like I2C is meant for, while the display would be connected
           | with SPI.
           | 
           | (I2C isn't more plug and play than SPI though, and a
           | preterminated plug shouldn't be a big deal.)
        
           | hadlock wrote:
           | If you're going to do I2C just get an LCD display. This OLED
           | can be driven at 150fps by simple devices like an ardunio
           | which is where it really shines - super crisp, high contrast,
           | smoove as buttah graphics for realtime readouts etc. OLED
           | over SPI is really visually impressive stuff and effectively
           | 0 latency. Using the SSD1306 for static displays over I2C is
           | almost a crime.
        
       | generj wrote:
       | This display is the modern 16x2 display for hardware hackers:
       | cheap and versatile.
       | 
       | One of my favorite hacks is running this display over HDMI [0].
       | 
       | Note that it's possible to refresh it at higher rates by using
       | partial refreshes. Or even higher to 150 fps [1].
       | 
       | [0] https://hackaday.com/2022/04/01/making-your-own-
       | technically-...
       | 
       | [1] https://hackaday.com/2018/05/08/push-it-to-the-limit-
       | ssd1306...
        
         | analog31 wrote:
         | I switched from 16x2 to SSD1306 because the latter runs on 3.3
         | V, and is thus more friendly to battery power.
        
       | mikeInAlaska wrote:
       | Here's a rust version i made with bitmapped fonts for both i2c
       | and SPI https://github.com/scopenews/minimalSSD1306driver/ I was
       | running this on my pi as a demo.
       | 
       | I normally work with C++ on esp32 for these little displays, and
       | in there I use a screen buffer for partial refreshes which makes
       | them very fast !!
        
         | grmnygrmny2 wrote:
         | That's very cool - I definitely gotta work on adding partial
         | refreshes. Thanks for sharing!
        
       | Graziano_M wrote:
       | To embed a binary in esp-idf I believe you need something like:
       | create_resources(${CMAKE_CURRENT_LIST_DIR}/../../binaries/RAM_APP
       | ${CMAKE_BINARY_DIR}/binaries.c)         set_property(SOURCE
       | ${CMAKE_BINARY_DIR}/binaries.c PROPERTY GENERATED 1)
       | 
       | Or using `EMBED_FILES`
       | 
       | I just happened to be looking at this very thing today that had
       | to do this: https://github.com/espressif/esp-serial-
       | flasher/blob/master/...
        
         | grmnygrmny2 wrote:
         | Amazing! Thank you!
        
       | qwe----3 wrote:
       | The SH1106 (1.3 inch) is a better option now. You can get them
       | for 1.50$ on aliexpress sometimes
        
       | atVelocet wrote:
       | There is also https://github.com/pioarduino/platform-espressif32
       | which allows one to use _Arduino > 3.2_ and _IDF > 5.4_. If you
       | use _PlatformIO_ put this into your _platformio.ini_
       | [espressif32] ; PLATFORM       platform = espressif32
       | board_build.embed_txtfiles = folder/file.ext ; embed null-
       | terminated file(s)
       | 
       | Also have a look at
       | https://docs.platformio.org/en/latest/platforms/espressif32.....
        
       | peteforde wrote:
       | I really love the u8g2 library, but unfortunately I love my
       | SSD1327 OLED even more. It supports 16-tone greyscale (which u8g2
       | cannot do) allowing 80s/90s video game style image dithering.
       | 
       | Getting up and running with lvgl was honestly kind of brutal, but
       | now that it's done, I am generally happy with it. As you
       | determined, it's much more of a UI toolkit than u8g2; the sort of
       | thing designed with fancy thermostats and smart watches in mind.
       | u8g2 has a menu toolkit but it is pretty narrow in scope.
       | 
       | I am planning on releasing a bare bones IDF-SDK v5.4 + lvgl 9.x +
       | SSD1327 starter project soon so that I can hopefully save future
       | travelers some pain.
        
       | kevin_thibedeau wrote:
       | LVGL works better on slow displays with internal video memory if
       | you minimize the vertical height of widgets. That allows the
       | library to update smaller strips of the display as widgets are
       | redrawn.
        
       | bmink wrote:
       | I'm actually working on code for esp-idf / SSD1309 right now, a
       | little bigger than the 1306. I went through a similar arc as OP.
       | 
       | I was actually surprised / disappointed by the poor quality of
       | the drivers out there. If you instrument and log the bytes u8g2
       | sends to the device and how the buffer is sent, you see it's
       | pretty messy, inefficient and hacky. Seems like everyone
       | copy+pasting everyone else's code, without understanding fully.
       | 
       | So in the end I just decided to draw into a local buffer and then
       | send that buffer in one single transaction to the display.
       | 
       | Once you figure out the data sheet it's actually very easy to
       | program these displays. For example, to test any SSDxxxx display,
       | you need to send all of two bytes: 0xaf (display on), 0xa5 (all
       | pixels on)
       | 
       | I am now looking at SSD1322, which is both grayscale and has
       | enough internal RAM for two buffers for even smoother drawing
       | (write into a non-displayed region of the RAM and then change the
       | display offset)
        
         | grmnygrmny2 wrote:
         | I discovered the same thing with u8g2, and digging through the
         | abstraction layers it felt like improving it was going to be
         | impossible. Sending a single transaction with a framebuffer is
         | so much simpler and faster.
         | 
         | SSD1322 looks great and might be something I look at for the
         | future..
        
       | userbinator wrote:
       | It's worth noting that the controllers for these small displays
       | and their instruction sets have a common lineage that goes back
       | to the 90s --- the SSD1306's looks very much like the Epson
       | S1D15300 series, for example. From a quick search, other
       | controllers with a similar instruction set are ST7565 and UC1601.
        
       ___________________________________________________________________
       (page generated 2025-04-14 23:00 UTC)