Optimise OLED display updates
This commit is contained in:
parent
bae47c0157
commit
94040fa5c7
3 changed files with 46 additions and 20 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#ifndef SSD1306_H
|
||||
#define SSD1306_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
|
|
|
@ -127,5 +127,5 @@ void ScreenLCD::SwapBuffers()
|
|||
void ScreenLCD::RefreshRows(u32 start, u32 amountOfRows)
|
||||
{
|
||||
if (ssd1306)
|
||||
ssd1306->RefreshRows(start, amountOfRows);
|
||||
ssd1306->RefreshTextRows(start, amountOfRows);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue