U8G2 direct buffer access?

I'm using the U8G2 library to drive an SH1106 display over hardware I2C in full frame buffer mode, and it's working great.

I've got a function that paints the display using a timer, and in this function I clear the buffer, repaint all the data, and then send that to the display. My display is fairly static, doesn't change very much, so I end up spending a lot of time pushing out I2C data that is the same over and over again.

Is there a way to look at the contents of the frame buffer? I've been using the Adafruit SSH1306 library and I was able to modify the library to make the buffer public. That allows me to do this:

Clear the display buffer
Use the draw / print functions to build the display contents
Compare the display buffer with the display history buffer
If they differ, send the display and put the display buffer in the history buffer

So is there a way to read out the U8G2 display buffer? Or is there another way to only send the display buffer data when it has changed?

I've been using the Adafruit SSH1306 library and I was able to modify the library to make the buffer public.

What is this?
I only know Adafruit_SSD1306 library. Which has a public oled.getBuffer() method:

  uint8_t *getBuffer(void);

Adafruit does not support SH1106 as far as I know. There is a third party library that uses "Adafruit_SH1106" name.

Both of these libraries do all their "drawing" into a buffer. And the oled.display() method sends the whole buffer contents to the physical OLED.
The display() is very quick. Obviously there is no point in calling display() if the buffer is unchanged.

You should "know" when you have written something new to the buffer (or not). Hence whether you need to call display() (or not).

If you have a spare 1024 bytes of SRAM, you could copy the buffer every time you call display(). And memcmp() the history copy to check for subsequent changes.

Alternatively, you could write a user function that just send a minimal section of the buffer.

I presume that you can do the same sort of thing with U8g2. i.e. "know" or memcmp(buffer, history, 1024)

U8g2 has

getBufferPtr

C++/Arduino Prototype:

uint8_t *U8G2::getBufferPtr(void)

C Prototype:

uint8_t *u8g2_GetBufferPtr(u8g2_t *u8g2)

Description: Return the address of the start of the buffer. This is a also the address of the leftmost tile of the current page (Byte 0 in the above memory structure). The total memory size of the buffer is 8 * u8g2.getBufferTileHeight() * u8g2.getBufferTileWidth(). The size may also be received by calling u8g2.getBufferSize(). The buffer can be erased with u8g2.clearBuffer().
Arguments:
u8g2: A pointer to the u8g2 structure.
Returns: Address of the internal page buffer.
See also: getBufferTileHeight, getBufferTileWidth, clearBuffer, getBufferSize

David.

Your'e totally correct, I meant to type SSD1306, and I'm using an older version that works with my SH1106 display. It did not have the getBuffer call, which is why I needed to modify it. Updating the library to the latest broke support for my display and I'd rather not refactor the code on that project to use u8g2.

You mention display() being pretty quick, but using I2C at 400kHz I can get approx. 25fps, meaning it takes 40ms to do each update, and during that time I2C is blocking. Not appealing to me.

As for the problem at hand, thank you for the pointer (no pun intended) to the getBufferPtr method.

This works:

byte history[1024];

if (memcmp(history, display.getBufferPtr(), 1024) ) { // compare the history buffer with the current buffer
memcpy(history, display.getBufferPtr(), 1024); // if it's changed, copy the display to history
display.sendBuffer(); // and send to the display
}

You mention display() being pretty quick, but using I2C at 400kHz I can get approx. 25fps, meaning it takes 40ms to do each update, and during that time I2C is blocking.

Yes, sending the SH1106 buffer to the physical display shows practical limits with I2C.
The SH1106 is slightly more complicated to send than the SSD1306 but it is still ~ 1024 bytes @ 400kHz i.e. at least ~23ms. Wire.h has a hefty overhead too.
This is noticeable on animations but not significant for regular applications. Especially if you check for changed buffer. The SH1106 and the SSD1306 are rated for 400kHz. They fail if you attempt > 600kHz.

Updating the library to the latest broke support for my display and I'd rather not refactor the code on that project to use u8g2.

Personally, I find GFX more intuitive than U8g2. However U8g2 has far better Fonts, text, ...

Are you saying that Adafruit updates have broken your application?
You can try GitHub - prenticedavid/Adafruit_SH1106_kbv: SH1106 oled driver library for monochrome 128x64 and 128x32 displays
It is not a publicly released library i.e. not available through IDE Library Manager

What are you doing that requires a fast frame rate?
You can always send a minimal changed rectangle (as a user function) instead of the full 1024 byte buffer

David.

This topic was automatically closed after 89 days. New replies are no longer allowed.