Go Down

Topic: Performance advice for random noise on 128x32px OLED display (Read 93 times) previous topic - next topic

iskelderon

Hi! 

I'm trying to display random noise on one of those I2C 0.91 inch 128x32 OLED screens and with my current code I seem to have so much overhead that I can only refresh it about every 450 ms.

Right now I'm using an Arduino Uno for development, but ideally I'd later convert it for use on an ATTiny.

Any chance that someone could point me in a direction of how I can optimize my code to get more refreshes per second out of it? Purpose of this is for a small table-top Star Wars droid. 

Thanks in advance for any help!

Source code backup: https://pastebin.com/Y6421Dri
Code: [Select]

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

int OLED_RESET = 4;
Adafruit_SSD1306 display(OLED_RESET);

void setup() {
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  delay(1000);
  display.clearDisplay();
 
  Serial.print("Display: ");
  Serial.print(display.width());
  Serial.print("x");
  Serial.println(display.height());
}

void loop() {
  drawRandomBitmap();
}

void  drawRandomBitmap() {
  for (int x = 0; x < display.width(); x++) {
    for (int y = 0; y < display.height(); y++) {
      display.drawPixel(x, y, ((rand() & 0x01) == 0) ? WHITE : BLACK);
    }
  }
  display.display();
  Serial.println("refreshed");
}

david_prentice

First off.  You should use W, H arguments in the constructor.

You have chosen a convoluted way to create random pixels.  i.e. 8192 calls to rand()
Note that your cut-price constructor expects 128x64 screen.

Since a 128x32 screen uses a 512 byte buffer,  you could just call random() 512 times using a range of 0, 255 and store each 8-pixel byte directly in the buffer.

David.

iskelderon

Since a 128x32 screen uses a 512 byte buffer,  you could just call random() 512 times using a range of 0, 255 and store each 8-pixel byte directly in the buffer.
Thanks!

That sounds a lot more efficient.
I'm not sure how to populate the buffer directly, but your advice and a look at the documentation already brought me a lot closer, practically halved the execution time per frame.

Had to define the bitmap array in the utility function, because defining it at the top led to
"image_generator:11:35: error: array bound is not an integer constant before ']' token".
I want to keep it as flexible as possible, so I'm not hardcoding the width/height/buffer size.

Code: [Select]

const uint8_t  OLED_RESET = 4;
Adafruit_SSD1306 display(OLED_RESET);
const uint8_t  display_width = display.width();
const uint8_t  display_height = display.height();
const int display_buffer_size = (display_width * display_height) / 8;


and

Code: [Select]

void  drawRandomBitmap() {
  display.clearDisplay();
  for (int i = 0; i < display_buffer_size; i++) {
    bitmap[i] = random(0, 255);
  }
  display.drawBitmap (0, 0, bitmap, display_width, display_height, WHITE);

  display.display();
  Serial.println("refreshed");
}

david_prentice

#3
Jan 13, 2021, 11:07 pm Last Edit: Jan 13, 2021, 11:08 pm by david_prentice
Code: [Select]

Adafruit_SSD1306 display(128, 32, &Wire);  //use accurate constructor
...

void  drawRandomBitmap()
{
    int display_buffer_size = (display.width() * display.height()) / 8;
    uint8_t *p = display.getBuffer();
    for (int i = 0; i < display_buffer_size; i++) {
        p[i] = random(0, 255); //write 8-pixels direct to buffer
    }
    display.display();   //sends the buffer to the OLED
    Serial.println("refreshed");
}



I guess that this will be at least 16x faster than your previous function.
Untested.  I just typed into the Browser.

iskelderon

Thanks!

The constructor alone already halved it again (no idea why) and your function (which worked out of the box) then halved it once again.

Thanks to all of these steps this went from roughly 450 ms to around 60-70 ms and now the output looks like convincing static noise.

Couldn't have done it without your help!

david_prentice

If you want to change an image quickly,  you can load the buffer directly.

For example,   you can draw a screen with regular graphics e.g. drawBitmap()
Read the buffer, and write as a C array to Serial Terminal.

Copy the Serial Terminal to a tab in your sketch.
Subsequent programs can copy the PROGMEM array directly to the buffer.

This gives you fast animations.

David.

iskelderon

Thanks again!

In case anyone else comes across this thread looking for an Arduino static noise display, here's the resulting code:
Code: [Select]
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const uint8_t  display_width = 128;
const uint8_t  display_height = 32;
const int display_buffer_size = (display_width * display_height) / 8;
Adafruit_SSD1306 display(display_width, display_height, &Wire);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  delay(1000);
  display.clearDisplay();
}

void loop() {
  drawRandomBitmap();
}

void  drawRandomBitmap(){
    uint8_t *p = display.getBuffer();
    for (int i = 0; i < display_buffer_size; i++) {
        p[i] = random(0, 255); //write 8-pixels direct to buffer
    }
    display.display();   //sends the buffer to the OLED
}

Go Up