SSD1306xLED

IMPORTANT UPDATE:

We are launching a crowdfunding campaign for the Tinusaur OLED Kit based on the SSD1306 displays and this its page: https://www.crowdsupply.com/tinusaur/oled-display-kit.

There is also a short video explaining what is this new kit about:

Original page content below …


SSD1306xLED is a C library for working with the SSD1306 display driver to control dot matrix OLED/PLED 128×64 displays. It is intended to be used with the Tinusaur board but should also work with any other board based on ATtiny85 or similar microcontroller.

SSD1306xLED library for OLED/PLED 128x64

The 128×64 OLED is controlled by a SSD1306 circuit and could be interfaced over I²C.

The code could be divided in 3 pieces:

  1. Communication over I²C with the SSD1306;
  2. Sending graphical commands to the display;
  3. High-level functions such as printing characters.

The I²C communication part is based on a code from the IIC_wtihout_ACK library that is available on the Internet but its original website (http://www.14blog.com/archives/1358) is no longer functional. Basically, the SSD1306xLED library  makes SSD1306 to work with ATtiny85 and Tinusaur.

How to use it

Using this library to control an OLDE display is very easy. The necessary header files that should be included with the program could be found in the source code repository – the link is at the bottom of this document.

First, the controlling PINs should be specified in the source code:

#define SSD1306_SCL PB2 // SCL, Pin 3 on SSD1306 Board
#define SSD1306_SDA PB0 // SDA, Pin 4 on SSD1306 Board

There are defaults, of course, but make sure they work for you.

There is also I2C slave address specified in the source code but you probably don’t want to change that.

Second, the display controller should be initialized.

_delay_ms(40);
ssd1306_init();

The delay is necessary if the initialization is at the beginning of the program. This is required by the SSD1306 circuit as it needs time to initialize itself after power-on.

Then, the simplest example would be to clear the screen (fill it out with blanks) and output some text.

ssd1306_fillscreen(0x00);
ssd1306_setpos(0, 10);
ssd1306_string_font6x8("Hello World!");

The ssd1306_string_font6x8 function call will output at the specified by the ssd1306_setpos function coordinates the provided text using 6×8 character font.

Similarly, a bitmap could be output on the screen with the following code:

ssd1306_draw_bmp(0,0,128,8, img1_128x64c1);

The above function call specifies (0,0) coordinates, width of 128 pixels and height of 8 bytes – 64 pixels.

Documentation

This project often changes so more current information could be found in the source code repository – in the text files and source files as well.

Source code

The source code along with very simple example is available on Bitbucket at this address: https://bitbucket.org/tinusaur/ssd1306xled

This SSD1306xLED library still needs more work and some improvements.

https://vine.co/v/OBuvIuhYdT7

63 thoughts on “SSD1306xLED”

  1. If this works I will owe you a beer (or whatever else you like to drink). I too purchased an OLED display and have been looking for a C library with which to run from an Attiny85. Come this weekend I will try it out and report back.

    Reply
  2. Thank you Tinusaur team for this terrific AVR library. The code is very well structured and commented. Cheers! –tim from Portland OR

    Reply
  3. I am struggling with getting this library to work. Firstly I got errors that the variables must be const to be read only. After some research this turned out to be to do with the way they are declared. So I added const to them and those errors when away. Now I get unint8 was not declared in this scope and so on. I really want to get this library to work but I think it needs updating to support the later versions of arduino.

    Reply
  4. Hi Karl,

    For which variables you had to add “const” for them to work? Let me know and I’ll fix that in the source code.

    BTW, there is pull request in Bitbucket that I have to review before accepting it – that may fix the issue as well.

    If you’re referring to the uint8_t type you may need to include the “stdint.h” library in the source code.

    Let me know if that solves your issue.

    Reply
  5. Just checked and the pull request you mentioned fixes that issue. The only problem I have now is. I think I am doing something wrong.

    Here is my code

    #include
    #include
    #include
    #include

    void setup() {
    // put your setup code here, to run once:
    delay(40);
    ssd1306_init();

    }

    void loop() {
    // put your main code here, to run repeatedly:
    ssd1306_fillscreen(0x00);
    ssd1306_char_f6x8(0, 0, “Hello World!”);

    }

    but I get these errors when compiling

    sketch_jan09a.cpp.o: In function `setup’:
    /home/karlhunt/Downloads/arduino-1.5.8-64bit/sketch_jan09a.ino:10: undefined reference to `ssd1306_init()’
    sketch_jan09a.cpp.o: In function `loop’:
    /home/karlhunt/Downloads/arduino-1.5.8-64bit/sketch_jan09a.ino:16: undefined reference to `ssd1306_fillscreen(unsigned char)’
    /home/karlhunt/Downloads/arduino-1.5.8-64bit/sketch_jan09a.ino:17: undefined reference to `ssd1306_char_f6x8(unsigned char, unsigned char, char const*)’
    collect2: error: ld returned 1 exit status
    Error compiling.

    I f I use your delay function I get this message.

    sketch_jan09a.ino:9:15: error: ‘_delay_ms’ was not declared in this scope

    I am so close I can taste it!!

    Great work by the way the adafruit library and any others I found simply will not work on an ATTINY85.

    Reply
  6. It looks like wordpress removed the library imports but they are there lol.

    #include font16x16cn.h
    #include ssd1306xled.h
    #include font6x8.h
    #include font8X16.h

    I removed the braces

    Reply
  7. I see now what’s your problem.
    There is that file “ssd1306xled.c” that needs to be compiled too as part of your project – this is where the mentioned in the error messages functions are – ssd1306_init(), etc. …
    I do not use Arduino for this particular library and I’m not sure what’s the best way of adding it in the Arduino IDE.
    Bur here is an idea …
    — Got to C:\Users\YOUR_USER_NAME\Documents\Arduino\libraries (this under MS Windows 8.1)
    and create new folder “ssd1306xled”.
    — Put in that folder everything that is in the https://bitbucket.org/tinusaur/ssd1306xled/src/default/ssd1306xled/
    — In your sketch folder use only what is in https://bitbucket.org/tinusaur/ssd1306xled/src/default/ssd1306xled_test/
    — Close all Arduino IDE instances and open your sketch again.

    This should add the library to the Arduino IDE.

    Let me know if it works.

    Reply
  8. Ill have a bash at this later. I’m using arduino 1.5.8 with a digispark.

    Thanks for the tech support.

    Reply
  9. Fixed it! All I had to to is rename the .c file to .cpp

    here is my example sketch

    #include
    #include
    #include
    #include

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

    ssd1306_init();
    }

    void loop() {
    // put your main code here, to run repeatedly:
    ssd1306_fillscreen(0x00);
    ssd1306_char_f6x8(0, 0, “Hello World!”);
    }

    This compiles fine It just doesn’t do anything on the screen yet.. I have SDA on the lcd going to P0 (SCL) on the digispark and scl going to P2 (SCK)

    Not sure what’s going on here I might check the i2c address.

    Reply
  10. I don’t think you need a pull-up resistor.
    Also, make sure the display is powered on 3.3V.

    If you happen to have an oscilloscope you may check is any signal is coming out of the pins.

    The other thing is that the Digispark, as far as I know, works on 16MHz while this library was tested (by me) on Tinusaur that runs on 1 MHz. That could be an issue as well.
    (I don’t have a DigiSpark so can’t test it)

    There are some updates from today in the repository – check the log – they may solve your issue.
    One of the changes is that the default pins for SDA and SCL are different – actually they are the same as on ATtiny85 TWI: PB0=SDA; PB2=SCL.

    Also, I’m using a 4-pin OLED module – if you have more pins you may need to control those extra as well.

    Anyways, if you find a solution let us know.

    Reply
  11. I am using the same Chinese display that you posted with 4 pins. It works on my uno when I power it with 5v and the adafruit library. But the adafruit library will not work the the 85 it needs to much space and SRAM. I think these screens are 3v/5v but so far I have only powered mine on 5v. My project will be 3v though. I think I will provably use a bare attiny chip anyway.

    Also if I use the i2c scanner digispark example it picks up a device.

    Reply
  12. I just ported the TinuSaur code to a working Arduino library that is working to run your existing sample code for the DigiSpark Pro.

    I’d like to share it with the DigiSpark community – I don’t see any restrictions on code re-use but want to be sure. If you have any interest in the Arduino library, please let me know. I forked it on BitBucket but haven’t done anything with my changes yet.

    I ported another library that seems much bigger and slower and this would be an great improvement.

    Also, what do you use to create your bitmap data?

    Reply
  13. Hey defragster, great news!

    Please, feel free to share you port. In fact, I will be glad if you do. I haven’t chosen a license for the source code yet but it should be more like BSD or LGPL so the only thing I can ask is mention me and my library within your derivative and as a favor have a reference to this website. If you have any concerns – let me know.

    Also, have you checked the most recent version in the repository? I optimized it little and I believe it is 50-60 bytes smaller now.

    For bitmap data – in one of the RAR files (i2c_OLED.rar) that I found on Internet as part of my research for similar libraries there was that LCDAssistant.exe program. It loads plain BMP files, has nice preview and exports the bitmap as C/C++ files. In the app it says their website is http://www.wide.hk but I haven’t checked it.

    Reply
  14. That is great news, if you have an update to the header comment I can get it in what I share, the bitbucket link could be confusing with the port to Arduino – maybe a link here would be better. I see K_Hunt above is also from the same platform.

    Thanks to for the link to the bitmap converter. I need to check your latest BitBucket – I think I may have to get the latest changes merged.

    Reply
  15. the latest version now gives me this on compile

    Arduino: 1.5.8 (Linux), Board: “Digispark (Default – 16.5mhz)”

    In file included from sketch_jan11a.ino:1:0:
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled8x16.h:16:25: error: variable or field ‘ssd1306_char_f8x16’ declared void
    void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled8x16.h:16:25: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled8x16.h:16:36: error: ‘uint8_t’ was not declared in this scope
    void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled8x16.h:16:47: error: expected primary-expression before ‘const’
    void ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[]);
    ^
    In file included from sketch_jan11a.ino:2:0:
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:33:24: error: variable or field ‘ssd1306_send_byte’ declared void
    void ssd1306_send_byte(uint8_t byte);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:33:24: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:34:27: error: variable or field ‘ssd1306_send_command’ declared void
    void ssd1306_send_command(uint8_t command);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:34:27: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:37:21: error: variable or field ‘ssd1306_setpos’ declared void
    void ssd1306_setpos(uint8_t x, uint8_t y);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:37:21: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:37:32: error: ‘uint8_t’ was not declared in this scope
    void ssd1306_setpos(uint8_t x, uint8_t y);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:38:25: error: variable or field ‘ssd1306_fillscreen’ declared void
    void ssd1306_fillscreen(uint8_t fill);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:38:25: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:23: error: variable or field ‘ssd1306_draw_bmp’ declared void
    void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:23: error: ‘uint8_t’ was not declared in this scope
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:35: error: ‘uint8_t’ was not declared in this scope
    void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:47: error: ‘uint8_t’ was not declared in this scope
    void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:59: error: ‘uint8_t’ was not declared in this scope
    void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
    ^
    /home/karlhunt/Arduino/libraries/ssd1306xled/ssd1306xled.h:41:71: error: expected primary-expression before ‘const’
    void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]);
    ^
    Error compiling.

    This report would have more information with
    “Show verbose output during compilation”
    enabled in File > Preferences.

    Reply
  16. ignore above. I just need to rename the .c files to cpp and also include stdint.h. Defragster will you form work on the normal digispark?

    Reply
  17. I have not tried on the Original spark but I got a minimal sample coded in like 2K with 10 bytes RAM so it should load there just fine as it uses the same ATtiny85 and has the SDA@pin0 & SCL@pin2 lines exposed.

    Reply
  18. Neven / Karl:
    Created a BitBucket Project – not yet populated – but with the file name changes and systems CPP additions the trees won’t diff or compare ever again. It looks like I took my fork after your latest changes last night as my source fork shows no updates as I should be good to start.

    Reply
  19. What changes did you make to the library? I have it working on my digispark now although I need the pull ups I think as I get corruption here and there. I have created a fork with the changes I have made and also I added the example in Arduino format so it shows in the IDE. The example takes ~4k? Doesn’t leave me much but I can work with that.

    Reply
  20. I made no changes other than the interface to CPP to get Arduino to compile and link with it. You can find me on the FORUM over there as defragster as well. The Pull ups must be in the chain somewhere and if the OLED is your only I2C then it needs it. I started on a breadboard with them and then got the shield and had no issues. For the Arduino IDE I used the TinuSaur demo as written and it works well.

    Reply
  21. Neven:
    Just looking at `SSD13068x16.c’ and I see ‘j’ used in a while() with no initialization to zero?

    void SSD1306Device::ssd1306_char_f8x16(uint8_t x, uint8_t y, const char ch[])
    {
    uint8_t c, j, i = 0;
    while (ch[j] != ”)

    Reply
  22. defragster,

    Looks like you’re using code from the first commit of the project – things have changed since. You should probably do a diff file-by-file – the file names are different now, well just “.c” is “.cpp” in your repo, but still.

    I just checked the ssd1306xled8x16.c in my repository – there’s no uninitialized index variable.
    Also, I added the licensing clause that should make it possible for other people to share it without any concerns.

    Reply
  23. You are right about current source – will pick up the current code and updated headers.
    Thanks, again the speed is impressive. Small size leaves out lots of useful fluff, but that is a better place to start from.

    Reply
  24. Neven:
    It works on ATtiny167 – though the fast I2C you implemented doesn’t allow for multiple devices – it gets slowed down in rewriting using the wire library so it can use display and other I2C device together.

    Reply
  25. defragster, the I2C part is not real implementation of the I2C protocol – it serves only the purpose of this particular library, that’s why it’s so small and fast. So it may conflict with other libraries that handle I2C communication especially in cases where they work asynchronously.

    Reply
  26. Karl, as I said, I don’t have DigiSpark board to test the library but last week I ordered a couple of them from eBay so soon I’ll be able to give it a try.

    If you still see errors on the screen that could be noise if the cables to OLED are too long. I noticed that if I touch the back of the OLED board I get errors in the screen drawing too.

    I doubt it, but it’s also possible that at 16MHz your board sends the I2C commands and data to the OLED controller too fast and it cannot handle them properly.

    Reply
  27. Neven:
    What you get from Ebay will probably be a clone knock off – not the real digistump.com product. Karl (if I read right) and I are working with the new Pro that just came off KickStarter. Karl I’ve never seen oddities on my Pro&Oled combo – but I have it on a PCB from the KS (socketed and soldered pull ups). Karl if you head over to the digistump.com/board/ the new release includes a rewritten version of Neven’s great work that uses the common wire library that is compatible with multiple devices (9DOF), though it runs slower. I’m finding it to be very stable.

    Reply
  28. I have both the original digispark from kick starter and a couple of Chinese ones and they seem to perform the same. I actually preferr the Chinese ones as the USB connector is more practical. I dont have a pro though. I just bought a couple of bare 85 chips I intend to use . I dont have a pro though I have banks an uno and a Leonardo.

    Reply
  29. On the tiny 85 then you will be good with this smaller faster TinuSaur based code, rather than the ‘I2C spec compatible’ version. The Pro with 16KB of code space invites more than one device.

    Ick – Chinese knockoffs – rude that they put DigiSpark in the name – the micro USB is better in some ways and that is something I saw – the Pro went to the micro – but it wasn’t meant to plug right into the computer. There are some of those knockoffs with bad component configurations and they are unreliable.

    Reply
  30. Does this library support the UNO?
    If so, what about a drawPixel()-routine? That way, one could possibly use the Adafruit GFX library.

    Reply
  31. This library is very specific for the SSD1306 chip combined with the ATtiny85 microcontroller – it is not universal. That’s why it works faster … with some limitations, of course – like not being universal.

    Reply
  32. Thank you very much for sharing this!!! But how can I control the display’s brightness? This library seems to dim the display, when I use U8glib on another board other than Attiny85 it works way brighter… I need it to shine a lot because I’m going to use it outdoors.

    Reply
  33. Hi caiopoit,
    There is initialization procedure at the beginning that sets some parameters “Initialization Sequence” in the ssd1306xled.c file. I’m not sure which register is for the brightness. You could check the datasheet.

    Reply
  34. Thank you VERY much!!!! It’s perfect now, thanks for your work with this tiny library!! Here’s what I changed: 0x81, 0xFF, // Set contrast control register (it originally was 0x3F)

    Reply
  35. Hello, how could I draw two images one on the other, at the same time making them transparent? I think i must ignore 0x00 somehow?

    Reply
  36. Hi,
    i recently bought similar 1.3″ module but with SH1106 driver.
    The SH1106 controller has an internal RAM of 132×64 pixel (while the SSD1306 has 128×64 pixel).
    The result is mostly junk with some fragment of the real picture.
    Can someone help to modify the code?

    Reply
  37. Ol´á,

    How do I use this SSD1306xLED library for my 6-pin display?

    OLED_MOSI 9 //=> SDA
    OLED_CLK 10 //=> SCK = SCL
    OLED_DC 11 //=> A0 = D/C
    OLED_CS 12 //=> não usa
    OLED_RESET 13 //=> Reset

    It is possible?

    Reply
  38. Olá,

    How do I use this SSD1306xLED library for my 6-pin display?

    OLED_MOSI 9 //=> SDA
    OLED_CLK 10 //=> SCK = SCL
    OLED_DC 11 //=> A0 = D/C
    OLED_CS 12 //=> não usa
    OLED_RESET 13 //=> Reset

    It is possible?

    Reply
  39. You should first verify if your display has the I2C interface or not. The SSD1306xLED library is specifically developed for the I2C interface – that’s why it runs so fast.

    You’ve got a “MOSI” pin and that may mean that it is serial OLED which means that it will not be supported by the library.

    Reply
  40. I am using i2c OLED and ATtiny85; I’ve tried to use this library with Arduino IDE with no luck! IDE won’t recognize the commands, I’m guessing, since the library is written in C and not in CPP. Right?

    Please let me know how could I use this library with Arduino IDE or should I just try WinAVR or similar?

    Reply
  41. Hi Carlos,
    Yes, the issue is that the library is in C bu the Arduino IDE expects it to be C++.

    Bellow is a fragment of code that I used in another project to make it work with Arduino IDE …

    extern “C” { // BEGIN: Needed to work with Ardiuno IDE
    #include “tinyavrlib/scheduler.h”
    #include “max7219led8x8/max7219led8x8.h”
    } // END: Needed to work with Ardiuno IDE

    Reply
  42. Hi everyone! I must have been doing something wrong in the beginning, but as promised following my findings:

    I coded it both ways: via WinAVR (using pure C programming) and via Arduino IDE. Why? You know…just for the heck of it! And it worked both ways.
    Use of WinAVR is straight forward since the library is C based. For Arduino IDE I renamed the library from .c to .cpp and copied them in the libraries folder of my sketchbook usually in “..\\My documents\Arduino\libraries”.

    I’ve modified: main() to setup() and for(;;) to loop(); I didn’t have to include “Arduino.h” nor included extern”C”. Beware, as Naven pointed out, that there might be sketches were you might need to do this.

    At the beginning of the sketch I just included the following header files:
    #include “ssd1306xled.h”
    #include “ssd1306xled8x16.h”

    in my sketch folder I’ve included the following files:
    cpufreq.h
    img0_128x64c1.h
    img1_128x64c1.h

    And it worked!
    Thanks and happy hacking!

    Reply
  43. Hi Neven! I’ve run test1 code in my attiny85 and works flawless. Now, I am trying to port the test1 code into an Arduino UNO (Atmega328P) and I’m failing to do so. This is what I tried so far:

    SSD1306_SCL PC5 // Used to be PB2
    SSD1306_SDA PC4//Used to be PB0

    I did include a 16Mhz option in the cpufreq.h file (since it was expecting 8Mhz).

    It compiles just fine but cannot see anything in the OLED display. Any ideas of what I could be missing? Do I need to change anything in the ssd1306_init() function?

    Reply
  44. Hi, I have problems compiling your code. I get this error:

    sketch/num2str.c: In function ‘usint2decascii’:
    num2str.c:32: error: ‘for’ loop initial declarations are only allowed in C99 mode
    for (uint8_t pos = 0; pos < 5; pos++) // "pos" is index in array, so should be of type int.
    ^
    sketch/num2str.c:32:2: note: use option -std=c99 or -std=gnu99 to compile your code
    sketch/num2str.c: In function 'usint2binascii':
    num2str.c:89: error: 'for' loop initial declarations are only allowed in C99 mode
    for (uint8_t pos = 0; pos < USINT2BINASCII_MAX_DIGITS; pos++) { // "pos" is index in an array.
    ^
    exit status 1
    'for' loop initial declarations are only allowed in C99 mode

    How can I fix this. (Board DigisparkPro)

    Reply
  45. Hi. The execution gives this error in Atmel Studio7.

    Done executing task “RunCompilerTask” — FAILED.
    Done building target “CoreBuild” in project “GccApplication1.cproj” — FAILED.
    Done building project “GccApplication1.cproj” — FAILED.

    Build FAILED.
    ========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

    And Is it necessary to include cpufreq.h file.

    Reply

Leave a Comment