I have a small LCD display and a LED matrix. The matrix is playing an animation, but the issue is that whenever the LCD is updated, the animation stutters, which looks bad. I'm trying to see if I can optimize the screen drawing a little bit. While I do have working code to update the screen, I don't understand why it has to be done this way:
u8g.firstPage();
do
{
drawScreen();
}
while(u8g.nextPage());
I know that firstPage() starts "page loop" and nextPage() ends the "page loop" and returs 1, while updating screen is still going (the naming is confusing, why not use startPage() and endPage() or something similar?). Anyway, what's the point of the do {} while() loop? Doesn't it cause the screen update code to run multiple times? (Which sounds like a waste of time). Of course assuming that the screen update is still running by the time the while check is reached. Why can't we use this:
u8g.firstPage();
drawScreen();
u8g.nextPage();
Also, here is the drawScreen function in case there is something to optimize:
void drawScreen(void)
{
// Get current time
DateTime now = rtc.now();
uint8_t hh = now.hour();
uint8_t mm = now.minute();
uint8_t ss = now.second();
// Set font for screen
u8g.setFont(u8g_font_helvR08r);
// Update animation text
u8g.setPrintPos(0, 10);
u8g.print(F("Animation: "));
// Get text for animation displayed on LED matrix
switch(animId)
{
case 0:
u8g.print(F("Default"));
break;
case 1:
u8g.print(F("Scroll"));
break;
case 2:
u8g.print(F("Scan"));
break;
case 3:
u8g.print(F("Wave"));
break;
}
// Normally animation returns to default after few seconds
if(holdAnimation) u8g.print(F(" (Hold)"));
// Update sensor text
u8g.setPrintPos(0, 25);
u8g.print(F("Sensor: "));
if(sensorEnabled)
{
u8g.print(sensorState ? F("True") : F("False"));
}
else
{
u8g.print(F("Disabled"));
}
// Update time text
u8g.setPrintPos(0, 40);
if(hh < 10) u8g.print(F("0"));
u8g.print(hh);
u8g.print(F(":"));
if(mm < 10) u8g.print(F("0"));
u8g.print(mm);
u8g.print(F("."));
if(ss < 10) u8g.print(F("0"));
u8g.print(ss);
// Update temperature text
u8g.setPrintPos(0, 55);
u8g.print(F("Temp: "));
u8g.print(temperature);
u8g.print("'C");
}
The whole point of this library is that it doesn't have to have a memory buffer that takes up the whole of the screen. The buffer "can" be much smaller depending on how much memory you want to save.
Hence that structure and the naming convention it uses.
If you use a full size buffer there is no need to do this. But even if do use this then it will completely refresh the screen on the first pass.
The display is divided up into sections, referred to as "pages". The exact number of pages is dependent on the display hardware, but is known to the u8g library.
The display buffer is only large enough for a single page.
firstPage() tells the library to start at the first display page.
nextPage() sends the buffer to the portion of the physical display corresponding to the current page, and advances to the next page.
The display code located in the do/while loop is executed multiple times, once for each page of the display. This is necessary, because the buffer is only large enough to contain the pixel information for a single page, and there is no way to store the pixel information for the remainder of the display unless you use enough memory to buffer the entire display.
It is very important that you do not change any of the information being displayed inside the do/while loop, otherwise you can get errors in the displayed image if something like a line of text straddles two pages. In particular, in your code the RTC should not be read inside the do/while loop, this can lead to having the numbers change between pages.
You may need to carefully synchronize the display update and the LED matrix update to avoid the stutter. How often do you need to update the LED matrix, and how long does that take?
Is there a way to change the buffer size? And a way to calculate how much storage I'd need for a full screen? I'm using a SSD1306 128x64 display if that's relevant.
The u8g2 library has a full-buffer option.
Make sure you use the constructor for hardware I2C, software I2C is far slower.
If you can get a display that uses an SPI interface instead of I2C, that should be much faster.
The u8g2 library runs the I2C bus at 400KHz, and from my testing it takes about 44mS to refresh the display.