u8glib sdd1306 oled slow

Hi,
I just connected a 0.96" oled 128x64 display to arduino uno via i2c using the u8glib.
What I need to do is to display a range of numbers going from 0 to 100 according to a potentiometer value.

Even before adding the potentiometer, I did a test with a loop from 0 to 100 without delay(). It takes about 10-11 seconds to complete.

I uploaded a video (sorry quality is poor) and my code is following.

Is there a way to speed up this ? Would a MEGA be faster ?
I don't complain about flickering, that is not visible without camera

Thanks,
robse

Code:

#include "U8glib.h"

//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);	// I2C / TWI 
U8GLIB_SSD1306_128X64_2X u8g(U8G_I2C_OPT_NONE);

void draw(const char* what) {
  // graphic commands to redraw the complete screen should be placed here  
  u8g.setFont(u8g_font_osb35);
  u8g.drawStr( 0, 50, what);
}

void setup(void) {

  // assign default color value
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
    u8g.setColorIndex(255);     // white
  }
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
    u8g.setColorIndex(3);         // max intensity
  }
  else if ( u8g.getMode() == U8G_MODE_BW ) {
    u8g.setColorIndex(1);         // pixel on
  }
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
    Serial.begin(115200);        // init serial
}

void loop(void) {
  // picture loop
  int x = 0;
  char buf[5];
  int initial = 0;
  int final = 0;
  
  initial = micros();
  for (x=0; x<=100; x++) {
  u8g.firstPage();  
  do {
    draw(itoa(x, buf, 10));
  } while( u8g.nextPage() );
  
  }
  final = micros();
  Serial.print(final-initial);
  Serial.println("");
 delay(4000); 

}

Hi

You can calculate the string outside the do..while loop. Also a smaller font will improve speed.

Oliver

Calculating the string outside the loop doesn't improve performance in this case.

For the font, I need a big one.

Since I need only big numbers, a custom font or another drawing methong would speed up the application ? (I need about a 10x improvement)

Thanks

Hi

With I2C the SSD1306 does not support more than 100KHz. With the overhead (ACK), there might be some 90KHz for the pure bitrate. The display has 128x64 pixel, which are 8192 pixel. So you will get about 11 frames pre second maximum.

You already reached that maximum value in our initial example. It can not be much faster.

SPI might be faster. But you also need a faster controller like the Due or the upcoming Zero.

Oliver

I have that display but it's currently configured for hardware SPI, not I2C.

Using Adafruit's libraries I drew big numbers (8X size) from "00" to "99" and it took 596 milliseconds. This is with an Uno R3 board at 16 Mhz.

jboyton:
I have that display but it's currently configured for hardware SPI, not I2C.

Using Adafruit's libraries I drew big numbers (8X size) from "00" to "99" and it took 596 milliseconds. This is with an Uno R3 board at 16 Mhz.

Do you refer to this Monochrome 0.96 128x64 OLED Graphic Display - STEMMA QT : ID 326 : Adafruit Industries, Unique & fun DIY electronics and kits ?

I'm running on a duemilanove, I have a UNOr3 but It shouldn't be faster I think.

Since I have only 4 exposed pins, I can't modify my module.
You are tempting me to buy the SPI version :slight_smile:

olikraus: where do you find the sdd1306 speeds ? Can't see them on the datasheet

Thank you both,
Roberto Sebastiano

robse:
Do you refer to this Monochrome 0.96 128x64 OLED Graphic Display - STEMMA QT : ID 326 : Adafruit Industries, Unique & fun DIY electronics and kits ?

That's it. I could jumper it for I2C but I never tried that. Is I2C really 20X slower than SPI or is there something else going on as well? I don't know.

I jumpered my 128x64 1306 OLED and tested the I2C performance with the Adafruit libraries. Here are the times for display "00" through "99" as 8X scaled characters:

0.6 sec - SPI (Adafruit libraries)
4.4 sec - I2C (Adafruit libraries)

11 sec - I2C (u8glib) -- tested by robse

olikraus:
With I2C the SSD1306 does not support more than 100KHz. With the overhead (ACK), there might be some 90KHz for the pure bitrate. The display has 128x64 pixel, which are 8192 pixel. So you will get about 11 frames pre second maximum.

The Adafruit library for the SSD1306 does in fact set the bit rate to 400Khz.

The Adafruit library for the SSD1306 does in fact set the bit rate to 400Khz.

I had a OLED which stopped working at about 110KHz.

Performance measures are done with one of the u8glib examples. I might forgot to add this to the examples. But it is available here:
https://code.google.com/p/u8glib/source/browse/sys/arduino/FPS/FPS.pde

Oliver

olikraus:
I had a OLED which stopped working at about 110KHz.

Okay, but the 1306 data sheet specifies the minimum clock cycle at 2.5us, which is 400kHz. So if the refresh rate matters it's certainly worth a try if you're stuck using the I2C interface.

jboyton:
Okay, but the 1306 data sheet specifies the minimum clock cycle at 2.5us, which is 400kHz. So if the refresh rate matters it's certainly worth a try if you're stuck using the I2C interface.

If i remember correctly it had been a far east OLED with resistors as level shifters. Since that time i decided to implement the 100KHz interface only. Maybe i should reconsider this. But on the other side I always thought of u8glib be the library that is also able to deal with any kind of OLED. Adafruit has excellent products and their own lib should obviosly support their products as good as possible.

There is one more thing that reduces speed: U8glib has a different concept of creating the picture. Per definition it must be slower than the approach of the Adafruit library. However U8glib only uses a fraction of the RAM that is used by the Adafruit GFX lib.

Oliver

I understand. I'm just writing code for myself so I don't have to worry. :slight_smile:

I also timed the text-only library that I've been using to save ram. It was about 25% slower than the Adafruit library (5.5 vs 4.4 seconds), but still twice as fast as what robse experienced.

I haven't tried u8glib because I only want text. Is it worth a look? About how much ram and code does it require for text-only use?

As author of U8glib, i of course will say, that it is worth a look. Additional to some internal variables U8glib uses a buffer which has that number of bytes as the width of the display. Here the buffer would have 128 bytes (minimum configuration). There is also an option for a double sized buffer, which will increase speed a little bit. In prinziple the idea behind U8glib is to trade RAM against speed. You can spend more RAM to get better speed. But there are some limitations and i did not implement all trading options for all display types.

Another thing, which makes U8glib somehow unique, are the number of buildin fonts:
https://code.google.com/p/u8glib/wiki/fontsize

Each of the fonts occupies space, so again you can select a certain font to optimize the FlashROM consumption. The detailed description for the font includes the number of bytes required for the font.

I did install U8glib on a LPC810 controller (4K FlashROM).But that did not let much room for other code.

Oliver

olikraus:
As author of U8glib, i of course will say, that it is worth a look. Additional to some internal variables U8glib uses a buffer which has that number of bytes as the width of the display. Here the buffer would have 128 bytes (minimum configuration). There is also an option for a double sized buffer, which will increase speed a little bit. In prinziple the idea behind U8glib is to trade RAM against speed. You can spend more RAM to get better speed. But there are some limitations and i did not implement all trading options for all display types.

I see. You must draw everything screen_size / buffer_size times. That would certainly have an effect on speed, but with limited memory resources it is a worthwhile tradeoff in some cases.

Another thing, which makes U8glib somehow unique, are the number of buildin fonts

They are quite nice. The scaled up 5x7 fonts I've been using in order to save ram are kind of blocky.


I ran the "Hello world!" example sketch, using the 1306 128x64 display (H/W SPI mode) and compared it to the modified version of Bill Greiman's SSD1306ASCII library I've been using.

code ram
size used library


10.1 K 272 bytes u8glib
5.3 K 62 bytes modified SSD1306ASCII

Given my predicament of being so close to using all the code and ram space I have, I think I will live with the blockier characters in order to save the space.


I also ran robse's script (above).

[Rob: The function micros() returns a long type, so "initial" and "final" should be long also.]

With hardware SPI it took 2.8 seconds to count up to 100, about 4.6 times as long as with the Adafruit libraries and about twice as long as with the modified ASCII library.

Thank you guys for all this interest and great support

Tomorrow I'll give a try to the adafruit sdd1306 library (still in i2c mode)

Results follow soon

(Jboyton: thanks for the type mismatch fix)

Here we are.

Just tested the sdd1306 display with the adafruit library

from 0 to 100 it takes 4,3 seconds, half of the u8glib (well, the font is uglier)

I'll switch to SPI.

Code following below.

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

#define OLED_RESET 0
Adafruit_SSD1306 display(OLED_RESET);

void setup()   {                
  Serial.begin(9600);

  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
  // init done
  
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(2000);

  // Clear the buffer.
  display.clearDisplay();
}


void loop() {
  
  int x;
  char buf[5];
  unsigned int initial = 0;
  unsigned int final = 0;
  
  initial = millis();
  display.clearDisplay();
  for (x=0; x<=100; x++) {
    display.setTextSize(5);
    display.setTextColor(WHITE);
    display.setCursor(0,15);
    display.print(itoa(x, buf, 10));
    display.display();
    display.clearDisplay();
  }
  final = millis();
  Serial.println(final-initial);
  delay(4000);
}

robse:
from 0 to 100 it takes 4,3 seconds, half of the u8glib (well, the font is uglier)

I just found out that initializing with:
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_FAST); instead of U8G_I2C_OPT_NO_ACK make the test complete in 4,7 seconds, not much slower than the Adafruit library (that I can't use in real life due to SRAM Issue ..)

From Changelog:

  • 400KHz option for I2C with U8G_I2C_OPT_FAST available for Due and Uno (Issue 303)

Testing with an Arduino DuemilaNove. So far so good.

--
Robse

For what it's worth, I recently spent some time optimizing the text-only library I've been using. I was able to increase the speed of both SPI and I2C significantly, as well as add some new features and reduce the code size.

With the text-only library, the "robse test" of counting from 00 to 99 in a 40x56 font is now:

3.3 sec - I2C
277 ms - SPI

But the font is still butt ugly when enlarged to that size.

U8glib: Yes, I recently added I2C fast mode. Indeed this thread might have been the starting point for a discussion in this forum and the u8glib project pages on support for I2C fast mode.

Oliver

robse --

With my OLED I mainly display numeric characters '0'-'9' at 2X and 3X the small font size. I grew tired of the blocky looking fonts and added specific 10x14 and 15x21 size fonts for just those ten characters.

Anyway, I recently did the same with the 8X (40x56) font. So now the numbers look pretty clean. And it's a little faster than scaling the smaller fonts up. Counting to 100 takes 171ms with SPI and 2.9 seconds with I2C.

If you're curious give this a try.

EDIT 9 Jan: I found another optimization, speeding up the SPI example from 171ms to 150ms. I didn't test the I2C but it is probably about 2.5 seconds now.

9_January_I2C_8X.zip (11.6 KB)