# Optimizing display code

Hi all,

I'm actually working on a small project with an Oled 128x64 display.
Here is the picture of the final display and the related code:

``````display.setRotation(1); //change display orientation
display.clearDisplay(); //clear screen
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(3, 1); //set cursor for unit display
if (unit_PSI == true)
{
display.println("PSI");
}
else
{
display.println("Bars");
}
//draw basic display
display.drawRect(0, 10, 64, 115, 1);
display.drawRect(1, 11, 62, 113, 1);
display.drawFastHLine(0, 48, 64, 1);
display.drawFastHLine(0, 49, 64, 1);
display.drawFastHLine(0, 86, 64, 1);
display.drawFastHLine(0, 87, 64, 1);

for (int i=0; i<3; i++) // display RPMs
{
display.setCursor(5, 36+(36*i));
display.print("rpm: ");
display.print(rpm[i]);
}

display.setTextSize(2);
if (unit_PSI == true) //Display pressure using PSI
{
for (int i=0; i<3; i++)
{
display.setCursor(5, 17+(36*i));
if (max_pressure_PSI[i] == sensor_range+1) //Overrange
{
display.print("OR");
}
else
{
display.print(max_pressure_PSI[i]);
}
}
}
else //Display pressure using BARs
{
for (int i=0; i<3; i++)
{
display.setCursor(5, 17+(36*i));
if ((max_pressure_bars[i]*14.503) >= sensor_range+1) //Overrange
{
display.print("OR");
}
else
{
display.print(max_pressure_bars[i], 1);
}
}
}
display.display();
``````

So at each loop the arduino clear the dispay and restart everything.

I'm not sure it's the most optimized way to do this.

Another option will be:
Draw everything one time, never clear the display but draw 'BLACK' rectangle to erase the values which needs to be updated.

I'm aware of any advice about display optimizing, what is the best way to organize it or to think it ?

Ony writing the data that is updated sounds best to me.

However you decide to code it. do yourself (and us) a favour and use the Auto Format tool in the IDE to indent the code which makes it so much easier to read.

You only need to set the color and orientation once so you could move those calls to setup().

You could also try what UKHeliBob suggests. Do that by first drawing the graphics and any fixed text in setup(). Then in your loop, instead of clearing the screen each time, move the cursor to the locations where you want to update text and first write spaces, then move the cursor back and write the text.

But since the clear screen and straight line graphics all occur in sram and the update over SPI happens in total whether you change the screen a little or a lot it's probably not worth it.

In setup set orientation, colours and even draw your pretty boxes.

Then whenever you're updating a value, pad it with spaces so it fills the area where you want to print it.

BTW. Looks like a nice display. I like the look of that.

You
might
give
some
thought
to
actually
indenting
your
code
to
make
it
easier
to

PaulS:
You
might
give
some
thought
to
actually
indenting
your
code
to
make
it
easier
to

It's also far from complete. Hence only getting generalised advice.

May I suggest: re-write the old data in black, then write the new data in white

KenF:
Then whenever you're updating a value, pad it with spaces so it fills the area where you want to print it.

It's not enough to simply pad with spaces; the bits in sram that represent the pixels of the previously drawn characters have to be set to zero.

walshlg:
May I suggest: re-write the old data in black, then write the new data in white

That's less efficient than writing blank characters.

What are you trying to optimize? Refresh rate? Code size? Remaining processor bandwidth?

jboyton:
It's not enough to simply pad with spaces; the bits in sram that represent the pixels of the previously drawn characters have to be set to zero.

Usually characters are built out of an array of bytes that include 1s and 0s. Padding with spaces would imply that those 0s are there. It depends on the logic implemented by the display.

coincidentally, I'm working on the ardafruit 1.7 inch tft right now! These things are slow all right. If you look at the libraries, afaict everything you do uses tft.drawPixel. Consequently, the fewer the pixels you draw, the faster it draws. BUT, there is the time it takes to lookup the pixels that have to be drawn.

So I would love to see you give it a try: try tft.drawRectangles and then try re-writing the data in black and let us know which is faster.

I'll go test how fast it takes to fill the screen on mine. Please let us know what you figure out.

if you are interested, it takes 161 msec to just execute tft.fillScreen on the 121x160 screens

The screen can be configured for use in two ways. One is to use an Arduino's hardware SPI interface. The other is to declare all the pins manually. There is no difference in the functionality of the screen between the two methods, but using hardware SPI is significantly faster.

Which did you choose?

Well, that's a lot of replies. And good feedback from all, thank you

First of all, I'm using Notepad++ to edit the code and auto format is not working. I'll try to put it in the Arduino IDE before posting next time.

It looks everyone is agree with the idea of refreshing only the changing part.
I can't put the basic display in setup() because I have different ones, but I guess I can make an display_init() to initialize the display and keep only the update in the actual function.

I can make some tests with blank char, black rect and black identical char to see what is the quickest way to erase the screen.

But my main goal is to learn to optimize code in a global way, which include speed if possible. Every display time is not a time the Arduino can use to really work

I'm also using Hardware SPI, previously I was using software and the refresh speed is 3 or 4 times faster with hardware SPI.

But my main goal is to learn to optimize code in a global way, which include speed if possible. Every display time is not a time the Arduino can use to really work

Does it matter how fast it is? If it isn't fast enough then you already have some suggestions regarding how to address that, but it sounds like you're going down the path of premature optimization and looking for better performance before you know whether you need it.

Optimized code can be less clear than the simpler stuff it replaced. It's not inevitable of course, but it has that tendency and then you're scratching your head six months later trying to figure out what on earth you did & why.

Sometimes your project really needs more speed & optimization can get it for you but I'd suggest you're better off getting it working first.

Don't ignore the simple solution of upgrading to faster hardware either.

Of course I've ignored the piece about your goal being learning about optimizing, so in that light, have fun. The issues with optimizing & when to do it are explored nicely in Jon Bentley's Programming Pearls.

You're right, too much optimization is sometimes worst than doing it the simple way. And the project goal is driving the way you have to code it.

But here I really want to improve my work and see how other guys see my work.

wildbill:
It sounds like you're going down the path of premature optimization

I've heard some guys suffer with this. Can't say it's ever happened to me

KenF:
Usually characters are built out of an array of bytes that include 1s and 0s. Padding with spaces would imply that those 0s are there. It depends on the logic implemented by the display.

This display memory for this device is not readable when connected via I2C or SPI interface. So the library keeps the entire pixel map in the microprocessor RAM (1K for the 128x64). Nothing is actually sent to the display until the display() method is called, at which point the entire pixel map is transmitted. Since the library supports text and graphics it only writes the pixels that are part of the character, by default.

There is a way to do what you're talking about though. The default is to draw transparent characters so that graphics and text can share the same 5x7 text box non-destructively. But this can be overridden by changing the background color from WHITE to BLACK. Then the character drawing method will write to every "pixel". In the case of characters larger than 5x7 each pixel is actually a rectangle that is drawn. So drawing every pixel in the character is expensive.

The other way is to keep track of the previously written values and overwrite them with a BLACK foreground as was suggested earlier.

The third way is to do what M4vrick is doing now.

I tried all three (Uno R3, OLED 1306 128x64, hardware SPI interface):

31.1 ms - M4vrick's current method of erasing and redrawing everything each time
46.0 ms - Drawing the fixed part once and erasing the characters by using a BLACK foreground
57.1 ms - Fixed part once, erasing the characters with a BLACK background on each update

jboyton:
I tried all three (Uno R3, OLED 1306 128x64, hardware SPI interface):

31.1 ms - M4vrick's current method of erasing and redrawing everything each time
46.0 ms - Drawing the fixed part once and erasing the characters by using a BLACK foreground
57.1 ms - Fixed part once, erasing the characters with a BLACK background on each update

Interesting. It looks like no optimization is necessary -- any "improvements" just slows things down?

Drawing everything every time also gives the cleanest and easiest to follow code, and should therefore be the easiest to maintain.

Very interesting feedback !
And uncommon result, surprising.

Which library did you use to do the tests ?
I'm actually have the exact same configuration: R3, Oled 1306 128x64 and hardware SPI.

It seems I try to complicate too much instead of optimizing...

I used the Adafruit_GFX and Adafruit_SSD1306 libraries straight out of the box.

When I timed just doing a display() update it took only a few milliseconds. A screen clear should be even faster. So that means the vast majority of the time is spent drawing characters in the buffer.

Drawing scaled characters takes a lot of time. The 90 degree orientation probably adds to this since the characters don't fit into the bytes as evenly. Since most of what you're doing is drawing these characters, doing it twice (first erase, then draw) increases the time. The straight lines probably are drawn faster than the characters.

You should check it yourself though. I sometimes do stupid things.