[SOLVED] Problem drawing BMP in OLED I2C SSD1306 with ESP8266

Hi,

I'm putting together a OLED I2C SSD1306 with an ESP8266 in order to show temperature and himidity values from a DHT22.

I'm trying to draw some BMP images (battery, termomenter...), but my problem is when they're showed on the OLED, they looks like a split image... you can see it at the attached picture.

For this ESP8266 project, I'm using the Adafruit-GFX-Library and esp8266-oled-ssd1306 (GitHub - ThingPulse/esp8266-oled-ssd1306: Driver for the SSD1306 and SH1106 based 128x64, 128x32, 64x48 pixel OLED display running on ESP8266/ESP32).

The code of my images (battery i.e.) is:

#define batt_high_width 16
#define batt_high_height 8
const char batt_high_bits[] PROGMEM = {
0xFF, 0xFE, 0x80, 0x02, 0xBF, 0xC3, 0xBF, 0xC3, 0xBF, 0xC3, 0xBF, 0xC3, 0x80, 0x02, 0xFF, 0xFE,
};

and this is the code to draw it:

display->drawXbm(0, 0, batt_high_width, batt_high_height, batt_high_bits);

where:

void drawXbm(int16_t x, int16_t y, int16_t width, int16_t height, const char *xbm);

The first test that I tryed was an example from this esp8266 where a WiFi logo is drawed, and it workd fine, but my attempts no.

The code for draw this WiFi logo is (if you want to check it):

#define WiFi_Logo_width 60
#define WiFi_Logo_height 36
const char WiFi_Logo_bits[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
  0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
  0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF,
  0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00,
  0xC0, 0xFF, 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C,
  0xFC, 0x77, 0x08, 0x00, 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00,
  0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C,
  0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00,
  0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C,
  0x1C, 0x70, 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00,
  0xC0, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F,
  0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00,
  0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF8, 0xFF, 0xFF,
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00,
  0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF,
  0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };
display->drawXbm(x + 34, y + 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);

Have you any thoughts why this is hapenning to my bmp images?

Thank you for your time.

The problem is the bit order. The bitmap is painted on the screen from left to right starting with the least significant bit of each byte. You have assumed the most significant bit is painted first.

Thus the bit order in each byte needs to be reversed, for example:

const char batt_high_bits[] PROGMEM = {
0xFF, 0x7F, 0x01, 0x40, 0xFD, 0xC3, 0xFD, 0xC3, 0xFD, 0xC3, 0xFD, 0xC3, 0x01, 0x40, 0xFF, 0x7F,
};

Thanks bodmer, it works!! Now my battery bmp is showed correctly!

But... I can't understand how I have to do for calculate this reverse order...

I spent several hours trying to understand how you calculate this bits in order to obtain yours, trying to find some logical, but I didn't succeed.

Please, could you explain to me how can I obtain this reverse order of the bits?

Thank you so much.

@luisbcn

You need to think in binary. For example

0xFE, 0x80, 0x02,... in binary is:

11111110, 10000000, 00000010

became:

0x7F, 0x01, 0x40,... which is:

01111111, 00000001, 01000000

Notice how the binary is a "mirror" as if it has been turned end for end. Clearly 0xC3 and similar patterns which is 11000011 does not change as the mirror image is the same.

I made the transformation in my head as I know what the binary patterns are. You could do it with pencil and paper or write a sketch to do it. An alternative is to write the drawing function yourself to work with the format you already have.

Finally I understood the way to do this transformation.
@bodmer, Thank you so much!

I developed a php function in order to do this conversion (hex2bin, flip bin string, bin2hex).

Now my Bitmaps are showing correctly on the OLED!!

1 Like

Sorry,

I know it's an old post but I just wanted to thanks bodmer...
I've been struggling with this for days and now everything is clear (and working)...

So, I just created an account to say (write) thank you :wink:

Kind regards.

@luisbcn could you send me your PHP program? I really need this... Thanks :slight_smile:

Hi everyone,

For those who are facing this kind of problem, here is a simples code that I used to test and fixed this bit flipping at SSD1306 OLED display.

I created a 8-bit bitmap from:
http://javl.github.io/image2cpp/

Upload the code to arduino and used the functions below to fix the bit shifting (LSB first instead of MSB):

byte flipByte(byte c){
char r=0;
for(byte i = 0; i < 8; i++){
r <<= 1;
r |= c & 1;
c >>= 1;
}
return r;
}

void revertBits(uint8_t src, uint8_t dst, int iSize) {
for (int i = 0; i < iSize; i++) {
dst _= flipByte(src
); _
_
} _
_
}
_

luca670:
@luisbcn could you send me your PHP program? I really need this... Thanks :slight_smile:

@luca670
Did you make this work with PHP? If yes, please can you share how :slight_smile:

Hello everyone,

the easy way to fix that is to use XBM files.

The function tells you explicitly, to use XBM:

 display->drawXbm

you can either create them trough GIMP or convert any format to XBM Convertir PNG en XBM (En ligne et Gratuit) — Convertio

It will give you the width/height and the uint8_t

#define lightOn_width 56
#define lightOn_height 60
const uint8_t lightsOn [] PROGMEM = {
  0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x8E, 0x03, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x01, 0x00, 0x00, (...)

No need to flipbytes and anything else :slight_smile:

Regards,

HugoL

I maked the code in C to revert each value from the array and this is working.
Please use it.

I use image2cpp to generate the array from a png file an later I put this array into my code.

#include <stdio.h>

const char myBitmap[] = { //this is the array char
0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3c, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x1f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xc3, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x01, 0xc7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x00, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc6, 0x3c, 0x63,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0x7e, 0x23, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcc, 0x7e, 0x33,
0xff, 0xc7, 0xff, 0xff, 0xff, 0xcc, 0x7e, 0x33, 0xff, 0x83, 0xff, 0xff, 0xff, 0xcc, 0x7e, 0x33,
0xff, 0x01, 0xff, 0xff, 0xff, 0xce, 0x3c, 0x73, 0xfe, 0x38, 0xff, 0xff, 0xff, 0xc6, 0x00, 0xe3,
0xfc, 0x3c, 0x7f, 0xff, 0xff, 0xe7, 0x01, 0xe7, 0xf8, 0x3e, 0x3f, 0xfe, 0x7f, 0xe3, 0xc3, 0xc7,
0xf0, 0x1f, 0x1f, 0xfc, 0x3f, 0xe3, 0xff, 0xc7, 0xe3, 0x8f, 0x0f, 0xfc, 0x0f, 0xf1, 0xff, 0x8f,
0xe3, 0xc7, 0x07, 0xfc, 0x07, 0xf8, 0xff, 0x1f, 0xe3, 0xe0, 0x03, 0xf8, 0xc3, 0xfc, 0x7e, 0x3f,
0xf1, 0xf0, 0x31, 0xf0, 0x61, 0xfe, 0x3c, 0x7f, 0xf8, 0xf8, 0x78, 0xe0, 0x30, 0xff, 0x18, 0xff,
0xfc, 0x30, 0x7c, 0x46, 0x18, 0x7f, 0x81, 0xff, 0xfe, 0x00, 0x3e, 0x0f, 0x0c, 0x3f, 0xc3, 0xff,
0xff, 0x03, 0x1e, 0x0f, 0x86, 0x1f, 0xe7, 0xff, 0xff, 0x87, 0x8e, 0x0f, 0xc3, 0x0f, 0xff, 0xff,
0xff, 0xc3, 0xc4, 0x07, 0xe1, 0x87, 0xff, 0xff, 0xff, 0xe1, 0xe0, 0xe3, 0xf0, 0xc3, 0xff, 0xff,
0xff, 0xf0, 0xf0, 0xf1, 0xf8, 0x63, 0xff, 0xff, 0xff, 0xf8, 0x61, 0xf9, 0xfc, 0x31, 0xff, 0xff,
0xff, 0xfc, 0x03, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x07, 0xff, 0xff, 0x01, 0xff, 0xff,
0xff, 0xff, 0x0f, 0xff, 0x9e, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0x9e, 0x3f, 0xff, 0xff,
0xff, 0xfe, 0x3c, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x70, 0x3f, 0xf8, 0xff, 0xff, 0xff,
0xff, 0xfc, 0xe0, 0x1f, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xc7, 0x9f, 0xc0, 0xff, 0xff, 0xff,
0xff, 0xf8, 0xc7, 0x8f, 0x80, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0xcf, 0x8f, 0x0e, 0x3f, 0xff, 0xff,
0xff, 0xfc, 0xc7, 0x9e, 0x1f, 0x1f, 0xff, 0xff, 0xff, 0xfc, 0xe2, 0x1c, 0x0f, 0x8f, 0xff, 0xff,
0xff, 0xfc, 0x60, 0x38, 0x47, 0xc7, 0xff, 0xff, 0xff, 0xfc, 0x78, 0x70, 0xe3, 0xc3, 0xff, 0xff,
0xff, 0xfe, 0x3f, 0xe0, 0xf1, 0x81, 0xff, 0xff, 0xef, 0x3e, 0x0f, 0xc0, 0x78, 0x00, 0xff, 0xff,
0xcf, 0x3c, 0x00, 0x04, 0x3c, 0x1c, 0x7f, 0xff, 0xc7, 0x1c, 0xe0, 0x1e, 0x1c, 0x1e, 0x3f, 0xff,
0xc7, 0x1f, 0xfd, 0xff, 0x08, 0x1f, 0x1f, 0xff, 0xe7, 0x8f, 0xff, 0xff, 0x80, 0x8f, 0x8f, 0xff,
0xe3, 0xc7, 0xff, 0xff, 0xc1, 0xc7, 0x8f, 0xff, 0xf3, 0xe1, 0xff, 0xff, 0xe1, 0xe3, 0x8f, 0xff,
0xf1, 0xf0, 0x7f, 0xff, 0xf0, 0xf0, 0x1f, 0xff, 0xf8, 0xf8, 0x7f, 0xff, 0xf8, 0xf8, 0x3f, 0xff,
0xfc, 0x7f, 0xff, 0xff, 0xfc, 0x78, 0x7f, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfe, 0x38, 0xff, 0xff,
0xff, 0x0f, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff,
0xff, 0xc0, 0x7f, 0xff, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
char inverter(char val){ // this function invert the value
char a = (val & 0x01)<<7;
char b = (val & 0x02)<<5;
char c = (val & 0x04)<<3;
char d = (val & 0x08)<<1;
char e = (val & 0x10)>>1;
char f = (val & 0x20)>>3;
char g = (val & 0x40)>>5;
char h = (val & 0x80)>>7;

val = a|b|c|d|e|f|g|h;
return val;
}
int main(void){

int size = sizeof(myBitmap);// myBitmap is the name for our array char
char values;

for(int i = 0 ; i < size; i++){
values = inverter(myBitmap*); // here we revert each value;*
}
int count = 0;
for(int j = 0; j < size; j++){
printf("0x%x",values[j]);
if(count == 16){
printf(",\n");
count = 0;
} else if(j == size-1){
printf("\n");
} else {
printf(", ");
count++;
}
}
}