From 94040fa5c74c8bde346c969d14443f022e79994e Mon Sep 17 00:00:00 2001 From: penfold42 Date: Fri, 3 Aug 2018 15:38:07 +1000 Subject: [PATCH] Optimise OLED display updates --- src/SSD1306.cpp | 47 +++++++++++++++++++++++++++++++++++------------ src/SSD1306.h | 17 ++++++++++------- src/ScreenLCD.cpp | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/SSD1306.cpp b/src/SSD1306.cpp index 9e6728a..68ea99d 100644 --- a/src/SSD1306.cpp +++ b/src/SSD1306.cpp @@ -25,8 +25,6 @@ extern "C" #include "xga_font_data.h" } -unsigned char frame[SSD1306_128x64_BYTES]; - SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int flip, LCD_MODEL type) : BSCMaster(BSCMaster) , address(address) @@ -36,8 +34,10 @@ SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int , width(width) , height(height) { + sizeof_frame = width*height/8; + frame = (unsigned char *)malloc(sizeof_frame); + oldFrame = (unsigned char *)malloc(sizeof_frame); RPI_I2CInit(BSCMaster, 1); - InitHardware(); } @@ -117,10 +117,10 @@ void SSD1306::SendData(u8 data) void SSD1306::Home() { - MoveCursorByte(0, 0); + SetDataPointer(0, 0); } -void SSD1306::MoveCursorByte(u8 page, u8 col) +void SSD1306::SetDataPointer(u8 page, u8 col) { if (col > width-1) { col = width-1; } if (page > height/8-1) { page = height/8-1; } @@ -142,7 +142,8 @@ void SSD1306::RefreshScreen() } } -void SSD1306::RefreshRows(u32 start, u32 amountOfRows) +// assumes a text row is 16 bit high +void SSD1306::RefreshTextRows(u32 start, u32 amountOfRows) { unsigned int i; @@ -154,6 +155,10 @@ void SSD1306::RefreshRows(u32 start, u32 amountOfRows) } } +// Some very basic optimisation is implemented. +// it scans the page to work out the first (new_start) and last (new_end) changed bytes +// Only update that window on the OLED +// If someone is keen, a smarter algorithm could work out a series of ranges to update void SSD1306::RefreshPage(u32 page) { if (page >= height/8) @@ -170,16 +175,33 @@ void SSD1306::RefreshPage(u32 page) int start = page*width; int end = start + width; - MoveCursorByte(page, 0); + int new_start = -1; + int new_end = -1; for (i = start; i < end; i++) { - SendData(frame[i]); + if (oldFrame[i] ^ frame[i]) + { + if (new_start == -1) + new_start = i; + new_end = i; + } + } + + if (new_start >= 0) + { + SetDataPointer(page, new_start-start); + for (i = new_start; i <= new_end; i++) + { + SendData(frame[i]); + oldFrame[i] = frame[i]; + } } } void SSD1306::ClearScreen() { - memset(frame, 0, sizeof(frame)); + memset(frame, 0, sizeof_frame); + memset(oldFrame, 0xff, sizeof_frame); // to force update RefreshScreen(); } @@ -210,6 +232,7 @@ void SSD1306::SetVCOMDeselect(u8 value) void SSD1306::PlotText(int x, int y, char* str, bool inverse) { +// assumes 16 character width int i; i = 0; while (str[i] && x < 16) @@ -258,9 +281,9 @@ void SSD1306::PlotPixel(int x, int y, int c) { switch (c) { - case 1: frame[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; - case 0: frame[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; - case -1: frame[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; + case 1: frame[x+ (y/8)*width] |= (1 << (y&7)); break; + case 0: frame[x+ (y/8)*width] &= ~(1 << (y&7)); break; + case -1: frame[x+ (y/8)*width] ^= (1 << (y&7)); break; } } diff --git a/src/SSD1306.h b/src/SSD1306.h index 6ab245f..92c5473 100644 --- a/src/SSD1306.h +++ b/src/SSD1306.h @@ -18,6 +18,8 @@ #ifndef SSD1306_H #define SSD1306_H + +#include #include "types.h" extern "C" { @@ -66,10 +68,7 @@ extern "C" //0000000 | 0 //________________________________________________________ -#define SSD1306_LCDWIDTH 128 -#define SSD1306_LCDHEIGHT 64 - -#define SSD1306_128x64_BYTES ((SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT) / 8) +#define SSD1306_128x64_BYTES ((128 * 64) / 8) class SSD1306 { @@ -91,7 +90,7 @@ public: void ClearScreen(); void RefreshScreen(); void RefreshPage(u32 page); - void RefreshRows(u32 start, u32 amountOfRows); + void RefreshTextRows(u32 start, u32 amountOfRows); void SetDisplayWindow(u8 x1, u8 y1, u8 x2, u8 y2); void PlotPixel(int x, int y, int c); void PlotImage(const unsigned char * source); @@ -101,9 +100,13 @@ protected: void SendData(u8 data); void Home(); - void MoveCursorByte(u8 row, u8 col); + void SetDataPointer(u8 row, u8 col); - unsigned char frame[SSD1306_128x64_BYTES]; +// unsigned char frame[SSD1306_128x64_BYTES]; +// unsigned char oldFrame[SSD1306_128x64_BYTES]; + unsigned char * frame; + unsigned char * oldFrame; + unsigned sizeof_frame; int BSCMaster; u8 address; diff --git a/src/ScreenLCD.cpp b/src/ScreenLCD.cpp index 591422c..36b4a2f 100644 --- a/src/ScreenLCD.cpp +++ b/src/ScreenLCD.cpp @@ -127,5 +127,5 @@ void ScreenLCD::SwapBuffers() void ScreenLCD::RefreshRows(u32 start, u32 amountOfRows) { if (ssd1306) - ssd1306->RefreshRows(start, amountOfRows); + ssd1306->RefreshTextRows(start, amountOfRows); }