Questions on ssd1306 i2c screens.

Hey everyone, I've used these little .96 oled screens in the past using spi, but recently got some that use i2c. I have a couple questions regarding which library to use in order to display a bitmap (u8g2 or adafruit ssd1306) depending which might be better, as well as how to put the image in a format the library can use. But since I also had questions about the i2c part, I wanted to address that as well (though that might be better fit in another sub forum).

The two screens have four pins- gnd, vcc, scl, and SDA. I'm using an Uno r3, which requires the use of A4 and a5, and possibly the two unlabelled pins above aref and gnd, for scl and SDA as per the pinout. The power can be either 3.3v or 5v (which will depend on other peripherals in this project).

Where I'm stuck is in finding the i2c address of each screen (or assigning it based on soldering/desoldering respective resistor bridges). I will attach a picture of the back where you can see it has two i2c addresses, but I've never done resistor bridges before- can you just desolder and solder with regular solder? Coming factory made it looks like something more specific, but I'm not sure if I'm mistaken.

Thanks!

Here's a good one

You just unsolder the 0x3C resistor. Believe me. You will lose it.

Then solder across the 0x3D pads. Either hold a single strand of wire or just with a big blob of solder.

If you used the single strand method, clip the ends off to leave a tiny 0R resistor (plain wire).

Soldering real resistors is hard. But holding a length of fine wire in your fingers is easier than tweezers.

Now you can connect two OLED to the I2C bus and access one with 0x3c and the other with 0x3d.

Ah, thanks so much! I was just confused because the addresses were numbered/labelled differently. In a tutorial about using i2c with the adafruit library, it mentioned using an i2c scanner to find the address. Eventually ill be connecting this to a larger project using i2c as well, to communicate to a pi. I would imagine I'd have to find this device using the scanner, but are 0x3C/D just standard, or the name of the resistor? Just want to be sure I'm following what's going on correctly

And thanks, good to know about the soldering part as well!

SSD1306 always has 0x3C and 0x3D as I2C addresses.

Resistors have values like 10k, 1k, 47R, 0R. Either with coloured bands or printed numbers if big enough e.g. 103, 102, 47, 0

Schematics have component numbers like R5 or C6.

I am sure Wilipedia can explain.

Awesome, thanks! That explains well enough, appreciate it! Now that I know that, just takes some tooling around with the bitmap function in whichever library I choose, so I suppose now I'll just mess around with that. Thanks!

Alright, I'm back for more! It seems that in both the u8g2 and adafruit ssd1306 libraries, both require the use of PROGMEM for the bitmap functions. Does anyone know of any reference material regarding this? I can follow along well enough with the respective libraries' bitmap formats, but my understanding falls short here. Thanks!

Adafruit_GFX style libraries have several overloaded drawBitmap() methods. Look in the header file.
They plot one pixel at a time.

Of course a hardware library might replace some methods but otherwise you simply fall back on the inherited drawBitmap()

As a general rule you would always want logos to be in Flash. Otherwise you waste SRAM.
You must be meticulous with your types especially for external references to separately compiled C or C++ files. Even INO files require care when you have multiple tabs in a sketch.

David.

Oh alright, thanks! And yeah, sorry, I meant the adafruit gfx library was what I was using for reference, I'd mistakenly said adafruit ssd1306 (which uses the gfx library). My question was in reference to it though, as in the reference material it says I can use something like gimp to use an xbm file, but I need to use progmem (and I'm not sure how). But I would imagine this may take up a lot of sram, and I need to display three different images for what im doing. I think I see what you mean (somewhat). Thanks!

If you own a Mcufriend style TFT, I have put a drawBitmap_kbv example in the latest version. This might help you.

If you only have a 128x64 OLED, the principles are the same.

  1. go to an online tool e.g. http://skaarhoj.com/FreeStuff/GraphicDisplayImageConverter.php
  2. browse for a PNG or JPG of your logo on your PC
  3. adjust pixel dimensions if necessary
  4. copy/paste the result to your sketch

Personally, I put data like this in a separate H file in a sketch tab. Then include the local H file.

There are several different PC programs that can create the bitmap array for you. And several online programs. Some are easier to use than others.

If you are having difficulties, post a link or attach a JPG of the logo that you want to use.

David.

CatDadJynx:
Oh alright, thanks! And yeah, sorry, I meant the adafruit gfx library was what I was using for reference, I'd mistakenly said adafruit ssd1306 (which uses the gfx library). My question was in reference to it though, as in the reference material it says I can use something like gimp to use an xbm file, but I need to use progmem (and I'm not sure how). But I would imagine this may take up a lot of sram, and I need to display three different images for what im doing. I think I see what you mean (somewhat). Thanks!

U8g2 supports XBM format: u8g2reference · olikraus/u8g2 Wiki · GitHub

Someone else also create a detailed tutorial on this: https://sandhansblog.wordpress.com/2017/04/16/interfacing-displaying-a-custom-graphic-on-an-0-96-i2c-oled/

Oliver

Oh awesome, thanks so much guys! That is incredibly helpful

Alright, sorry for the confusion, but heres where im sort of stuck. As of right now, im going along with the u8g2 library. Ive gotten my code better organized as mentioned above, converting the file to an xbm, placing it where it seems it should be in the code, then using the draw function to call it, im just confused as to whether the draw function replaces setup or main, or what should go in thise places. Additionally, I would prefer to place the image in a separate tab, as i have two other images id also like to display in this program. My code is as follows, Thanks!

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
const long screenInterval = 1000;           // interval at which to buffer (milliseconds)
unsigned long sensorInterval;
unsigned long previousMillis;

// Copy the contents of your .xbm file below
#define eyesstraight_width 65
#define eyesstraight_height 64
static unsigned char eyesstraight_bits[] = {
   0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x7f, 0x01, 0x5f, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xae, 0x7f, 0x01, 0xb7, 0x7f, 0x00, 0x00, 0x00, 0x00,
   0xb6, 0xff, 0x00, 0xaf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xbf, 0x01,
   0xb7, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x7f, 0x01, 0xfe, 0xed, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xed, 0x01, 0xfd, 0xdb, 0x00, 0x00, 0x00, 0x00,
   0xfe, 0xdb, 0x01, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xea, 0x01,
   0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xfd, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xfa, 0x01, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xea, 0x01, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01,
   0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xaf, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x7e, 0x01, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xde, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xbf, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xd7, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xea, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xed, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xd5, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xdf, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x57, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x7f, 0x01,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x01, 0xdf, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xfe, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x01,
   0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xfe, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xea, 0x01, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xd6, 0x01, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x01,
   0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x01, 0xfd, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xf5, 0x01, 0xfb, 0xeb, 0x00, 0x00, 0x00, 0x00,
   0xfe, 0xeb, 0x01, 0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x01,
   0xdf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbf, 0x01, 0xaf, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xaa, 0x7f, 0x01, 0xb7, 0x7e, 0x00, 0x00, 0x00, 0x00,
   0xde, 0x7f, 0x01, 0xaf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x56, 0x7f, 0x01 };


void draw(void) {
// graphic commands to redraw the complete screen should be placed here
u8g2.drawXBM( 0, 0, eyesstraight_width, eyesstraight_height, eyesstraight_bits);
}

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

Also, what my program will ultimately do is display a bitmap of an eye facing left, right, or center based on where an object is relative to sensor readings, hence the premature millis.

Your data arrays need to have the PROGMEM qualifier. Otherwise they get copied to SRAM which is in short supply.
Look at the tutorial that Oliver pointed to.

Yes, it is easier to manage in a separate tab. Then you can concentrate on the program logic.

David.

This is true for AVR architectures only:
u8g2.drawXBM() --> The bitmap must be in SRAM area, the declaration does not require the U8X8_PROGMEM attribute.
u8g2.drawXBMP() --> The bitmap must be in Flash ROM area, the declaration requires the U8X8_PROGMEM attribute.

Oliver

olikraus:
This is true for AVR architectures only:
u8g2.drawXBM() --> The bitmap must be in SRAM area, the declaration does not require the U8X8_PROGMEM attribute.
u8g2.drawXBMP() --> The bitmap must be in Flash ROM area, the declaration requires the U8X8_PROGMEM attribute.

Oliver

Ahh, okay, the reference manual said

Note: The XBMP version requires, that the bitmap array is defined in this way:

static const unsigned char u8g_logo_bits[] U8X8_PROGMEM = { ...

And then, comparably, the tutorial just said to change

static unsigned char bitmap_bits[]

to

static const unsigned char bitmap_bits[] PROGMEM

But Id just forgotten to ask for more information on that as well, so thank you for clarifying! Now I see what you mean. Ive also made a few additional changes i saw later on in the tutorial, which answered my question about setup and loop as well. My updated code looks like this (but I have not yet replaced the delay with mills, or put the bitmap in a separate tab as im still not sure which parts to use to do so (or is it just the things before setup?) Anyway, my updated code is here:

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
const long screenInterval = 1000;           // interval at which to buffer (milliseconds)
unsigned long sensorInterval;
unsigned long previousMillis;

// Copy the contents of your .xbm file below
#define eyesstraight_width 65
#define eyesstraight_height 64
static unsigned char eyesstraight_bits[] PROGMEM = {
   0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x7f, 0x01, 0x5f, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xae, 0x7f, 0x01, 0xb7, 0x7f, 0x00, 0x00, 0x00, 0x00,
   0xb6, 0xff, 0x00, 0xaf, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xbf, 0x01,
   0xb7, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x7f, 0x01, 0xfe, 0xed, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xed, 0x01, 0xfd, 0xdb, 0x00, 0x00, 0x00, 0x00,
   0xfe, 0xdb, 0x01, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xea, 0x01,
   0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0xfd, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xfa, 0x01, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xea, 0x01, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01,
   0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xaf, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x7e, 0x01, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xde, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xbf, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xd7, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xea, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xed, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xfc, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xd5, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xdf, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x57, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x7f, 0x01,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0xff, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x01, 0xdf, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xfe, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x01,
   0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0xfe, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xea, 0x01, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0xd6, 0x01, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x01,
   0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x01, 0xfd, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xfe, 0xf5, 0x01, 0xfb, 0xeb, 0x00, 0x00, 0x00, 0x00,
   0xfe, 0xeb, 0x01, 0x6f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x01,
   0xdf, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbf, 0x01, 0xaf, 0xff, 0x00,
   0x00, 0x00, 0x00, 0xaa, 0x7f, 0x01, 0xb7, 0x7e, 0x00, 0x00, 0x00, 0x00,
   0xde, 0x7f, 0x01, 0xaf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x56, 0x7f, 0x01 };


void draw(void) {
// graphic commands to redraw the complete screen should be placed here
u8g2.drawXBM( 0, 0, eyesstraight_width, eyesstraight_height, eyesstraight_bits);
}

void setup(void) {
 u8g2.begin();
}

void loop(void) {
 // picture loop
 u8g2.firstPage();
 do {
     draw();
    } while( u8g2.nextPage() );

 // rebuild the picture after some delay
 delay(1000);
}

sooo... does it work?
Oliver

olikraus:
sooo... does it work?
Oliver

Sorry, I wasnt sure if I was on the right track or not so didnt test it. But I just did, and unfortunately it doesnt work yet. It compiles and uploads just fine, but the display is simply blank (no pixels are lit at all).

At least the code looks correct...

Oliver

Hmm... I'm thinking because the bitmap is different than the screen size maybe I'm drawing it in the wrong location and it isn't displaying? Might just mess with it and see if I can't get it working somehow then, I suppose