TTGO ESP32 board with OLED display and Adafruit library

These days, there’s a huge amount of support out there for virtually any device you can buy. But every now and again you need to do a bit of head-scratching. So this post is simply my way of helping out anyone who’s going through the same process I just did.

I bought a couple of cheap ESP32 boards that have 128×64 pixel OLED displays mounted to them. At $10 a pop, I thought they were good value and would make excellent Internet of Things (IoT) thermometers when coupled with the right sensor.

I’ve got experience with ESP8266 boards – and, indeed, have already made IoT thermometers with them. But these boards would be far more compact.

All I needed to do, I thought, is load up the Adafruit_SSD1306 library (available via the IDE’s ‘manage libraries’ function) into the Arduino IDE and I’d be off and running.

But I hit a snag right away. It wouldn’t work. The manufacturer, TTGO, took it upon itself to use non-standard pins for the I2C bus connections.

You can always write your own code to control the display. And there are many libraries out there for the SSD1306 (none of which I got to work). But I really wanted to use the Adafruit library because … well, it’s good.

It turns out this isn’t a problem, but it took quite a lot of googling, and a small amount of experimentation, to find that out. For example, even on Adafruit’s own tutorial on using the library, it says that you can’t change the SDA and SCL pin assignments. It turns out, that information is out of date – the library has been updated to allow it – but I had to dig down into comments on forums to find this out.

This is what you do…

So here’s what you need to do to use these boards – or, for that matter, any SSD1306 OLED display with non-standard I2C pin assignments – with the Adafruit_SSD1306 library.

I’m basing this on the example code – ssd1306_128x64_i2c – provided with the Adafruit library. I find that library examples like this are always a good starting point in understanding both libraries and the devices they support.

You need to make five changes:

  • Change the display reset pin to 16 (the example default is 4).
  • Declare your own TwoWire instance.
  • Pass that instance as a parameter in the instantiation of the Adafruit_SSD1306 object.
  • Begin your TwoWire instance with the SDA and SCL pins used by the TTGO board.
  • Change the address of the display.

Let’s go through those in detail.

The easy one first

First, the simplest. In the Adafruit library example code, it has pin 4 set as the reset pin for the display. We need to change that to 16.

#define OLED_RESET 16 // Reset pin - was 4

An instance of your own

Normally, the Adafruit_SSD1306 instance is created by passing Wire (by reference) as a parameter. The default code looks like this:


But that’s not going to give us any chance to change the pins. So, instead of passing &Wire as a parameter, let’s create our own I2C object and pass that instead.

TwoWire twi = TwoWire(1); // our own TwoWire instance on bus 1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &twi, OLED_RESET);


Now we head down to the setup() section. In the Adafruit example, this looks like this:

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3D)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever 

It’s working!

Note the 0x3D parameter. This is the address normally used by these 128×64 OLED displays. The 128×32 versions typically use 0x3C. But, for some reason, the display on these boards, while being 128×64, uses 0x3C. So we’ll need to change that.

But before we do, we need to address something else – those SDA and SCL pin assignments. The TTGO board uses pin 4 for SDA and pin 15 for SCL. If we used the display.begin(…) code above, even with the altered address, it would still be trying to use the default I2C pins. So we need to begin our TwoWire instance with the correct pins before we get to display.begin(…). So the altered code looks like this:

void setup() {
    /* ... some stuff omitted ... */
    twi.begin(4,15);  // Needs to come before display.begin is used
    if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
    /* ... lots of stuff omitted ... */

And we’re done! You can now use the Adafruit library, and the Adafruit GFX library with all its lovely fonts.

[UPDATE – later that day] And now it’s working beautifully with the Adafruit GFX fonts, which make all the difference.

It’s connected to the home wifi, getting time and date from my IoT server (the PiDP), and making regular temperature reports to the server. Except that the temperatures are currently fake because there’s no sensor attached. So that’s the next decision – which temperature sensor to use.

[UPDATE TO THE UPDATE] I had to take this post down after adding the above update. I’d originally created the post in WordPress’ new block editor – which is all very whizzy but actually a pain in the ass.

For a start, it wouldn’t let me type an ampersand without converting it to the relevant HTML entity, ‘&amp;’. That sounds like it’s a good thing. But in program listings, sometimes you want an ampersand to just be an ampersand, for cut & paste purposes. Even working in the ‘code’ mode, and in text defined as preformatted (using the <pre> tags). every time I saved the post, plain ampersands were converted to HTML entities. Gah!

So I reverted to the ‘classic’ editor. But, when I added the update sections above (two pars and a picture), it added them four times to the post. And it moved one of the original paragraphs (and not even the last one) to the bottom. Why?

I tried switching back to the block editor, but things just started going downhill. It was now telling me that there were ‘problems’ with many of the pars. And it added more copies of the additional section.

So back to the classic editor and a few minutes stripping out all the formatting tags the block editor had added to the post.

This is classic feature bloat. What was a perfectly fine editor has been replaced with something not nearly as clever as it thinks it is. And buggy as hell. So much for progress.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.