Interface a cheap OLED (SSD1306) from eBay with an Arduino
There are a couple of cheap OLED displays available on eBay and I really struggled to get them to work with the Arduino. Some of them have the manufacturer “Heltec” printed on the circuitboard and most of them use the SSD1306 display driver which can communicate with the Two-Wire-Interface or I2C (its the same, only different names due to licensing-blabla) bus.
They are nice and cheap BUT they do not send an ACK-bit to the I2C master. So the I2C code needs to support communication without an ACK signal (more on that later). That is making interfacing this cute display a little harder and thats why the common Adafruit library does not work. 🙁
Whats the matter with this crazy ACK-bit?
ACK stands for “Acknowledge“. Imagine the ACK bit as “Thanks-Done!” during a communication between the I2C master and slave. As mentioned, the cheap ones from eBay dont communicate with an ACK. Lucky us: its also possible to do so.
Wiring
The wiring is pretty simple. The hardware I2C interafce on the Arduino is available on the analog A4 and A5 pins. A5 is the SCL line (Clock), A4 is the SDA line (Data) of the I2C bus.
So you wiring is: A5 -> SCL, A4 -> SDA, GND -> GND, 5V -> VCC
Please double check the supply voltage that is needed for your display (3.3V or 5V). Supplying a wrong voltage can destroy your display!
You can download the Fritzing part here:
OLED Screen SSD1306
The Code
Im using the u8glib universal graphics library to communicate with this display. You can get this library here. Its a nice library that makes life a little easier. We like that very much.
A very basic communication can be done like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// OLED SCL -> A5, SDA -> A4 #include <U8glib.h> U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); void setup() { delay(10); } void loop(void) { u8g.firstPage(); do { draw(); } while( u8g.nextPage() ); } void draw(void) { u8g.setFont(u8g_font_04b_03r); u8g.drawStr( 15, 30, "SCRIBLAB"); } |
The magic happens within the u8glib constructor. Its initialised like this:
1 |
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); |
(UPDATE 09.10.2016: It seems like that with version v1.14 of the U8glib this also works: U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE))
This tells the class to init with the explicit option to not use the ACK bit during communication and finally, we can use the 100 cheap OLEDs we bought. 😉 Hurray!
A more complex example with basic opperations with the OLED with drawing bitmaps, graphics changing fonts, using built in icons etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
// Heltec OLED (eBay!) SCL -> A5, SDA -> A4 #include <U8glib.h> U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK); const uint8_t rook_bitmap[] U8G_PROGMEM = { 0x00, // 00000000 0x55, // 01010101 0x7f, // 01111111 0x3e, // 00111110 0x3e, // 00111110 0x3e, // 00111110 0x3e, // 00111110 0x7f // 01111111 }; void setup() { delay(10); } char val[3] = "27"; void loop(void) { // picture loop u8g.firstPage(); do { draw(); } while( u8g.nextPage() ); delay(500); } void draw(void) { // Draw some Icons u8g.setFont(u8g_font_m2icon_9); u8g.drawStr( 17, 45, "ABCD"); // Draw the bitmap u8g.drawBitmapP(28,15,1,8, rook_bitmap); u8g.setFont(u8g_font_04b_03r); // Draw some text u8g.drawStr( 15, 30, "SCRIBLAB"); u8g.setFont(u8g_font_u8glib_4); u8g.drawStr( 70, 48, "MEASUREMENT"); // Draw graphics u8g.drawBox(0,51,128,20); // Invert the color u8g.setColorIndex(0); u8g.drawStr( 20, 59, "THIS IS A TEST SCREEN"); // Invert the color again u8g.setColorIndex(1); // Some big text u8g.setFont(u8g_font_fub30r); u8g.drawStr( 70, 40, val); } |
Conclusion
Allthough it has been some hassle to get this OLED to work, the u8glib made this pretty straight forward. Looking forward to use this nice little OLED in a next project. 🙂
Further reading
u8glib – Universal Graphics Library
The I2C-Bus
OLED Displays
Freeware OLED pixel generation software