Arduino Nano + 0.96' OLED Display Issues

Hi Everyone,

I have been trying to get this OLED display to work properly, however when I try to display an image it ends up being slightly distorted. Instead of two separate eyes as shown in the first picture, the display has issues presenting it. I am using the U8G2 library I have included my code within this post. If anyone has any suggestions I would be very grateful!


1
Test1.ino (7.0 KB)

Please post your code here to remove the need for it to be downloaded

First off. It does not look like a 0.96" display.

It is always wise to post a link to the actual purchase. e.g. Ebay sale page.
Or post a photo of the pcb side of the module.

This means we can identify whether it is 0.96" SSD1306 or 1.3" SH1106. (or have a pretty good guess)

There are several tests that will distinguish different make and model of controller chip.

@ UKHeliBob,

The OP is using this constructor

U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 22, /* data=*/ 21);

David.

Hi David, I apologize for not being clearer on my situation I have confirmed that it uses the SH1106 as the SSD1306 causes a pixel shift resulting in noise on the right side and the left side not starting until 4 pixels in. As for the constructor I moved to an ESP32 which is giving me the exact same issue.
The link to where I purchased it is here:

I ran your program on a genuine 0.96 inch SSD1306. I get exactly the same picture as in #1.

The modules in your Geekcreit advert look like 0.96"
i.e. they do not look like the 1.3 inch SH1106 from your #1 photo.

Anyway, I suggest that you choose some better XBM bitmaps to illustrate what "problem" you have.
But first off, run all the U8g2 library examples with that SH1106 constructor.

David.

I have, and they all turn out perfect. I have a feeling that when I convert the image from an image to bitmap array, something is going wrong. I have used multiple sites and with no luck. If possible could you try converting the image I attached to this post and trying it on your 0.96 display? The size of the picture is 128x64 so it should fit perfectly. Please let me know if this works and how you did it!

1

The XBM format appears to have the bit patterns in reverse-order, with the MSB of one byte being next to the LSB of the subsequent byte. As such, 0x80, 0x01, would produce two adjacent pixels, not individual pixels with 14 background pixels in between.

static const unsigned char cross_bits[] U8X8_PROGMEM  = {
  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, 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, 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, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0x7F, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

It is straightforward. You have created a regular Adafruit Bitmap i.e. MSB on left.
However U8g2 only supports XBM format i.e. LSB on the left.

If you display your bitmap using Adafruit_GFX style libraries you can see the differences.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include "eyes.h"

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);

void setup() {
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.display();
    delay(2000); // show splash screen for 2 secs
}

void loop(void) {
    display.clearDisplay();
    display.drawBitmap(0, 0, cross_bits, 128, 64, 1);
    display.display();
    delay(1000);
    display.clearDisplay();
    display.drawXBitmap(0, 0, cross_bits, 128, 64, 1);
    display.display();
    delay(1000);
}

If you are using U8g2 remember to convert bitmaps to XBM format.
U8g2 accepts both formats from SRAM. Only XBM format from PROGMEM.
GFX only accepts bitmap format from SRAM, but both formats from PROGMEM.

Since you have a MEGA2560 with plenty of SRAM you can just copy the bitmap from PROGMEM to SRAM before displaying it with U8g2.

David.

Is that "little-endian" or "big-endian"? :thinking:

Neither I would think, I've always understood endianness to refer to byte order, not bit order.

The code I posted has the bit order reversed from the OP's original image, so that it will display correctly. With that simple image it was easy to correct in a text editor.

Byte order is bit order. :roll_eyes:

Writing "0x80, 0x01" means that "0x80" is at the lower address and if it is the less significant byte of a 16 bit value, then according to Wikipedia, it is little-endian (Intel).

Endian refers to the byte order in a multi-byte storage. e.g. a uint32_t

bit-order refers to the order of a serial stream. e.g. UART sends lsb first.
Most other peripherals like SPI or I2C send msb first.

Regarding bitmaps. The msb on the left format (msb first) means that you can visualise a bitmap array by writing with binary constants.

The XBM format (lsb first) means that humans can't read the Font or Icon data from an array. Which is why God gave you Irfanview and GIMP.
Let's face it. Editing the letter A in a 5x7 bitmap is convenient. Editing a 1024x1024 bitmap by hand would make your head hurt. (especially in XBM format)

David.

If I recall correctly, I once edited some images to convert from BMP to XBM using a text editor and regular expressions, by converting all the hex numbers to binary, reversing the bit order of each 8-bit group, and converting back to hex. May have used a script file to do the conversions, would be tedious by hand. The purpose was to change the code from Adafruit's library to U8g2 because there was not sufficient ram for a full display buffer.

Go on. You simply read the XBM array one byte at a time, reverse the bit-order, write it back to your new C array in the Serial Terminal.

When done, you copy-paste the new array from the Serial Terminal to an H file tab e.g. bitmap.h
There is zero effort involved. (apart from writing the XBM_to_BMP() function)

You can create any C arrays that you like. e.g. from the display buffer.

Of course it is MUCH more convenient to use GIMP in the first place. Since your original letter, Icon, picture, ... is probably a large JPG on your PC. (that might need scaling, anti-aliasing, ...)

David.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.