i2c SP1106 OLED Slow refresh on UNO

I need some advice on here with regards to display and refresh rate.

I’m on an Arduino Uno with the SH1106 OLED 128x64 I2C screen. I’m using the u8glib library and uploaded the “Hello World” example. Next I hooked up a variable resistor to pin A0 and defined it in the UNO sketch. I’m able to see the value on the screen and as I adjust the variable resistor, the values on the screen follows. The issue here is that it’s just way too slow and it took about 29kbyte of data. The uno can only hold 32k of data so I’m also out of data. Is there any way to increase the refresh rate and decrease the size of the file? It seems to only way to add more features is to use a bigger arduino unit.

#include "U8glib.h"
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);	// Display which does not send ACK


int var1 = 0;
void draw(void) {

  // graphic commands to redraw the complete screen should be placed here  
  u8g.setFont(u8g_font_unifont);
  //u8g.setFont(u8g_font_osb21);
  u8g.drawStr( 20, 10, "Hello World!");

    //u8g.drawStr( 40, 60, "15");

  if (var1 < 10) {
  u8g.setFont(u8g_font_fur30);
  u8g.setPrintPos(62, 60); 
  u8g.print(var1);
  u8g.setFont(u8g_font_unifont);
 
  }
  else {
  u8g.setFont(u8g_font_fur30);
  u8g.setPrintPos(40, 60); 
  u8g.print(var1,1);
  u8g.setFont(u8g_font_unifont);

  }
}

void setup(void) {
  Serial.begin(9600);
  
  pinMode(A0, INPUT);
  
  // flip screen, if required
  // u8g.setRot180();
  
  // set SPI backup if required
  //u8g.setHardwareBackup(u8g_backup_avr_spi);

  // 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);
  }
}

void loop(void) {



  // picture loop
  u8g.firstPage();
  
  var1 = map(analogRead(A0),0,1023,0,50);
  do {
    draw();
  } while( u8g.nextPage() );
  
  // rebuild the picture after some delay
  //delay(50);
}

Any replies?

paulsvang:
Any replies?

Clearly not....

Hi

The flash is probably occupied by the fonts. Try to use smaller fonts or fonts with lesser number of glyphs. For numerical data, instead of "u8g_font_fur30" you could use "u8g_font_fur30n".

For speed up, try to do most of the operations outside the "picture loop".
Also font switiching (u8g.setFont()) takes some time and should be avoided.

Oliver

Oliver,

Thanks for a great library. I'll make some adjustments and test it out again. I appreciate the help!

Paul

Oliver,

u8g_font_fur30n Helped a bit. It went from 29kbytes to 14kbytes. Now I can write more operation codes. I've also moved the operation outside of the picture loop. Is there anything else I can do to speed up the refresh rate? Would a SPI screen provide huge improvements over the i2c? You advise is greatly appreciated!

Regards,

Paul

In general SPI is indeed faster. Togehter with the Arduino Due it could be a significat speed improvement.

Recently, there was a speend comparison on youtube: Tested: Display Libraries - Adafruit, u8glib, Homebrew Code - YouTube
I think the problem is the tradeoff between functionality (lib functions) and speed....

Oliver

olikraus:
In general SPI is indeed faster. Togehter with the Arduino Due it could be a significat speed improvement.

Recently, there was a speend comparison on youtube: Tested: Display Libraries - Adafruit, u8glib, Homebrew Code - YouTube

The guy in that youtube video isn't using SPI. He's driving the OLED with "soft" SPI. The exact numbers depend on what you test. If you're doing lots of graphics operations the interface time becomes less significant.

I measured just the update time for SPI and "soft" SPI using the Adafruit library (128x64 OLED 1306)

26 ms - "soft" SPI -- this is in line with the youtube video
2.6 ms - SPI -- a 10X improvement

Here's a comparison between hardware SPI and I2C with Adafruit. This test included drawing two characters scaled up 3X in size:

44 ms - I2C
6 ms - SPI -- about 7X faster

It looks like the time spent doing the graphics processing was 6-2.6 = 3.4 ms. So that would mean that the I2C update period (at 400 KHz) is about 40ms.

Oliver & jboyton,

thanks for the input. I'm going to get an SPI screen and see if there's any improvement in terms of speed. Instead of a DUE, would a Mega 2560 work in it's place?

In the mean time, I've tried to display a floating value to 1 decimal point (ie 12.4) but is having an issue. It works on a 16x2 screen but fails on the OLED.

I tried something like this with var1 is the float variable

float var1 = (analogRead(A0)) / 10 *.1);
u8g.print(var1,1);

Please advise.

Paul

Any advice on the float issue I'm having? Is there a specific way to make it work with the library?

Hi

Although u8g.print is part of u8glib, the code behind .print is reused from the Arduino libraries (e.g. serial.print()). So i think it is best to look at the official documentation for .print ()http://arduino.cc/en/serial/print.

In fact, i would expect, that your code is correct, but maybe your calculation is wrong. Can you try with a constant value like "u8g.print(123.3,1);"?

Oliver

This is odd

This code did not work:

float var2 = 9 / 2;
  u8g.print(var2,1);

Result is 4

but it should be 4.5

However this code below is working:

float var2 = 9 * 2.15;
  u8g.print(var2,1);

Result is 19.3

It's very strange to me so I'll have to check it out to see what's causing it. The division function is not working like it should however multiplication works as intended.

Thanks Oliver!

Paul

I figured it out. It's an error on my part.

The code below works and that's how it should be coded.

  float var2 = (float)9 / 2;
  Serial.println(var2);

Yes, the "unexpected" behavior is caused by the type conversion in C and C++. Best is to do an explicit type cast as you did in your working example.

Oliver

Oliver,

Is it possible to use the library fast i2c with u8glib?

I ran across this site and it seems this library operates the i2c at a higher frequency which might help with the refresh rate on the screen.

It seems the i2c is operating at 100khz. Increasing it to 400khz might help

Paul

I once used a SSD1327 with more than 100kHz. It did not work.
So in the library, it is currently fixed to 100KHz.Not sure what is written in the datasheet for the SSD1306.

Oliver

I changed the frequency from the file u8g_com_i2c.c file on line 126 from 100khz to 400khz and that improved the refresh rate. It's running quite fast now.

TWBR = F_CPU/(2*400000)-8;

Thanks again Oliver for such a great library!

Paul

Both the 1306 and 1106 are rated to 400 KHz for the I2C clock.

ok, good to know that 400KHz are working.

Oliver

Edit: I have created an issue for this: https://code.google.com/p/u8glib/issues/detail?id=303

Jboyton / Oliver,

I have another question. Would it be possible for the numbers to be right aligned? I’m have an issue with the numbers shifting one point from 9.9 to 10.0.

I’m using the code below but if var1 hits the spot where it can’t make up it’s mind and is shifting from 9.9 to 10.0, the numbers shift back in forth. If it was aligned from the right side, I wouldn’t have this problem. Or if you know another way to adjust this issue, that would be great.

The setPrintPos is setup so that the decimal point is aligned when var1 is below 10 or above 10.

  if (var1 < 10) {
    u8g.setPrintPos(43, 64);
    u8g.print(var1,1);
  }    
  else {
    u8g.setPrintPos(20, 64);
    u8g.print(var1,1);
  }

Paul