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 128x64The 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 ( 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.


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_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.


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:

This SSD1306xLED library still needs more work and some improvements.


50 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.

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

  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.

  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.

  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


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


    void loop() {
    // put your main code here, to run repeatedly:
    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.

  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

  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
    — In your sketch folder use only what is in
    — 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.

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

    Thanks for the tech support.

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

    here is my example sketch


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


    void loop() {
    // put your main code here, to run repeatedly:
    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.

  10. I think I just realised I need 4.7k pull up resistors on the i2c pins???

  11. 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.

  12. 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.

  13. 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?

  14. 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 but I haven’t checked it.

  15. 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.

  16. 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.

  17. 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?

  18. 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.

  19. 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.

  20. 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.

  21. 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.

  22. 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] != ”)

  23. 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.

  24. 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.

  25. 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.

  26. 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.

  27. 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.

  28. Neven:
    What you get from Ebay will probably be a clone knock off – not the real 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 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.

  29. 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.

  30. 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.

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

  32. 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.

  33. 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.

  34. How can I control the brightness? My display is dimmed by default if compared when using another library.

  35. 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.

  36. 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)

  37. 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?

  38. 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?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s