Merge pull request #120 from gbouille/SSD1306_improvment

A little improvment on SSD refresh
This commit is contained in:
Stephen White 2019-01-02 11:54:47 +11:00 committed by GitHub
commit dba374593e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 479 additions and 455 deletions

View file

@ -1,309 +1,332 @@
// Pi1541 - A Commodore 1541 disk drive emulator // Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White // Copyright(C) 2018 Stephen White
// //
// This file is part of Pi1541. // This file is part of Pi1541.
// //
// Pi1541 is free software : you can redistribute it and/or modify // Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// Pi1541 is distributed in the hope that it will be useful, // Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>. // along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#include "SSD1306.h" #include "SSD1306.h"
#include "debug.h" #include "debug.h"
#include <string.h> #include <string.h>
#include "Petscii.h" #include "Petscii.h"
extern "C" extern "C"
{ {
#include "xga_font_data.h" #include "xga_font_data.h"
} }
extern unsigned char* CBMFont; extern unsigned char* CBMFont;
SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int flip, LCD_MODEL type) SSD1306::SSD1306(int BSCMaster, u8 address, unsigned width, unsigned height, int flip, LCD_MODEL type)
: BSCMaster(BSCMaster) : BSCMaster(BSCMaster)
, address(address) , address(address)
, type(type) , type(type)
, flip(flip) , flip(flip)
, contrast(127) , contrast(127)
, width(width) , width(width)
, height(height) , height(height)
{ {
sizeof_frame = width*height/8; sizeof_frame = width*height/8;
frame = (unsigned char *)malloc(sizeof_frame); frame = (unsigned char *)malloc(sizeof_frame);
oldFrame = (unsigned char *)malloc(sizeof_frame); oldFrame = (unsigned char *)malloc(sizeof_frame);
RPI_I2CInit(BSCMaster, 1); RPI_I2CInit(BSCMaster, 1);
InitHardware(); InitHardware();
} }
void SSD1306::InitHardware() void SSD1306::InitHardware()
{ {
// SSD1306 data sheet configuration flow // SSD1306 data sheet configuration flow
SendCommand(SSD1306_CMD_DISPLAY_OFF); // 0xAE SendCommand(SSD1306_CMD_DISPLAY_OFF); // 0xAE
SendCommand(SSD1306_CMD_MULTIPLEX_RATIO); // 0xA8 SendCommand(SSD1306_CMD_MULTIPLEX_RATIO); // 0xA8
SendCommand(height-1); // SSD1306_LCDHEIGHT - 1 SendCommand(height-1); // SSD1306_LCDHEIGHT - 1
SendCommand(SSD1306_CMD_SET_DISPLAY_OFFSET); // 0xD3 Vertical scroll position SendCommand(SSD1306_CMD_SET_DISPLAY_OFFSET); // 0xD3 Vertical scroll position
SendCommand(0x00); // no Offset SendCommand(0x00); // no Offset
SendCommand(SSD1306_CMD_SET_START_LINE | 0x0); // 0x40 SendCommand(SSD1306_CMD_SET_START_LINE | 0x0); // 0x40
if (flip) { if (flip) {
SendCommand(0xA0); // No Segment Re-Map SendCommand(0xA0); // No Segment Re-Map
SendCommand(0xC0); // No COM Output Scan Direction SendCommand(0xC0); // No COM Output Scan Direction
} else { } else {
SendCommand(0xA1); // Set Segment Re-Map (horizontal flip) SendCommand(0xA1); // Set Segment Re-Map (horizontal flip)
SendCommand(0xC8); // Set COM Output Scan Direction (vertical flip) SendCommand(0xC8); // Set COM Output Scan Direction (vertical flip)
} }
SendCommand(SSD1306_CMD_SET_COM_PINS); // 0xDA Layout and direction SendCommand(SSD1306_CMD_SET_COM_PINS); // 0xDA Layout and direction
if (type == LCD_1306_128x32) if (type == LCD_1306_128x32)
SendCommand(0x02); SendCommand(0x02);
else else
SendCommand(0x12); SendCommand(0x12);
SetContrast(GetContrast()); SetContrast(GetContrast());
SendCommand(SSD1306_CMD_TEST_DISPLAY_OFF); // 0xA4 - DONT force entire display on SendCommand(SSD1306_CMD_TEST_DISPLAY_OFF); // 0xA4 - DONT force entire display on
SendCommand(SSD1306_CMD_NORMAL_DISPLAY); // 0xA6 = non inverted SendCommand(SSD1306_CMD_NORMAL_DISPLAY); // 0xA6 = non inverted
SendCommand(SSD1306_CMD_SET_PRE_CHARGE_PERIOD); // 0xD9 SendCommand(SSD1306_CMD_SET_PRE_CHARGE_PERIOD); // 0xD9
SendCommand(0xF1); SendCommand(0xF1);
SendCommand(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL); // 0xDB SendCommand(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL); // 0xDB
SendCommand(0x40); SendCommand(0x40);
SendCommand(SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO); // 0xD5 SendCommand(SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO); // 0xD5
SendCommand(0x80); // upper nibble is rate, lower nibble is divisor SendCommand(0x80); // upper nibble is rate, lower nibble is divisor
SendCommand(SSD1306_ENABLE_CHARGE_PUMP); // 0x8D Enable charge pump regulator SendCommand(SSD1306_ENABLE_CHARGE_PUMP); // 0x8D Enable charge pump regulator
SendCommand(0x14); // external = 0x10 internal = 0x14 SendCommand(0x14); // external = 0x10 internal = 0x14
SendCommand(SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE); // 0x20 Set Memory Addressing Mode SendCommand(SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE); // 0x20 Set Memory Addressing Mode
SendCommand(0x10); // 10 - Page Addressing Mode for SH1106 compatibility SendCommand(0x10); // 10 - Page Addressing Mode for SH1106 compatibility
Home(); Home();
if (type != LCD_1106_128x64) if (type != LCD_1106_128x64)
SendCommand(SSD1306_CMD_DEACTIVATE_SCROLL); // 0x2E SendCommand(SSD1306_CMD_DEACTIVATE_SCROLL); // 0x2E
} }
void SSD1306::SendCommand(u8 command) void SSD1306::SendCommand(u8 command)
{ {
char buffer[2]; char buffer[2];
buffer[0] = SSD1306_CONTROL_REG; buffer[0] = SSD1306_CONTROL_REG;
buffer[1] = command; buffer[1] = command;
RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer)); RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer));
} }
void SSD1306::SendData(u8 data) void SSD1306::SendData(u8 data)
{ {
char buffer[2]; char buffer[2];
buffer[0] = SSD1306_DATA_REG; buffer[0] = SSD1306_DATA_REG;
buffer[1] = data; buffer[1] = data;
RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer)); RPI_I2CWrite(BSCMaster, address, buffer, sizeof(buffer));
} }
void SSD1306::Home() //We can send up to 16 bytes to the i2c bus
{ void SSD1306::SendDataLong(void* data, u8 length)
SetDataPointer(0, 0); {
} char buffer[15];
void SSD1306::SetDataPointer(u8 page, u8 col) buffer[0] = SSD1306_DATA_REG;
{ memcpy(&buffer[1], data, length);
if (col > width-1) { col = width-1; }
if (page > height/8-1) { page = height/8-1; } RPI_I2CWrite(BSCMaster, address, buffer, ++length);
}
if (type == LCD_1106_128x64)
col += 2; // sh1106 uses columns 2..129 void SSD1306::Home()
{
SendCommand(SSD1306_CMD_SET_PAGE | page); // 0xB0 page address SetDataPointer(0, 0);
SendCommand(SSD1306_CMD_SET_COLUMN_LOW | (col & 0xf)); // 0x00 column address lower bits }
SendCommand(SSD1306_CMD_SET_COLUMN_HIGH | (col >> 4)); // 0x10 column address upper bits
} void SSD1306::SetDataPointer(u8 page, u8 col)
{
void SSD1306::RefreshScreen() if (col > width-1) { col = width-1; }
{ if (page > height/8-1) { page = height/8-1; }
unsigned i;
for (i = 0; i < height/8; i++) if (type == LCD_1106_128x64)
{ col += 2; // sh1106 uses columns 2..129
RefreshPage(i);
} SendCommand(SSD1306_CMD_SET_PAGE | page); // 0xB0 page address
} SendCommand(SSD1306_CMD_SET_COLUMN_LOW | (col & 0xf)); // 0x00 column address lower bits
SendCommand(SSD1306_CMD_SET_COLUMN_HIGH | (col >> 4)); // 0x10 column address upper bits
// assumes a text row is 8 bit high }
void SSD1306::RefreshTextRows(u32 start, u32 amountOfRows)
{ void SSD1306::RefreshScreen()
unsigned int i; {
unsigned i;
//start <<= 1; for (i = 0; i < height/8; i++)
//amountOfRows <<= 1; {
for (i = start; i < start+amountOfRows; i++) RefreshPage(i);
{ }
RefreshPage(i); }
}
} // assumes a text row is 8 bit high
void SSD1306::RefreshTextRows(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 unsigned int i;
// Only update that window on the OLED
// If someone is keen, a smarter algorithm could work out a series of ranges to update //start <<= 1;
void SSD1306::RefreshPage(u32 page) //amountOfRows <<= 1;
{ for (i = start; i < start+amountOfRows; i++)
if (page >= height/8) {
return; RefreshPage(i);
}
// x32 displays use lower half (pages 2 and 3) }
if (type == LCD_1306_128x32)
{ // Some very basic optimisation is implemented.
page = page+4; // 0,1,2,3 -> 4,5,6,7 // it scans the page to work out the first (new_start) and last (new_end) changed bytes
page = page%4; // and wrap it so 4,5 -> 0,1 // 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)
int i; {
int start = page*width; if (page >= height/8)
int end = start + width; return;
int new_start = -1; // x32 displays use lower half (pages 2 and 3)
int new_end = -1; if (type == LCD_1306_128x32)
for (i = start; i < end; i++) {
{ page = page+4; // 0,1,2,3 -> 4,5,6,7
if (oldFrame[i] ^ frame[i]) page = page%4; // and wrap it so 4,5 -> 0,1
{ }
if (new_start == -1)
new_start = i; int i;
new_end = i; int start = page*width;
} int end = start + width;
}
int new_start = -1;
if (new_start >= 0) int new_end = -1;
{ for (i = start; i < end; i++)
SetDataPointer(page, new_start-start); {
for (i = new_start; i <= new_end; i++) if (oldFrame[i] ^ frame[i])
{ {
SendData(frame[i]); if (new_start == -1)
oldFrame[i] = frame[i]; new_start = i;
} new_end = i;
} }
} }
void SSD1306::ClearScreen() if (new_start >= 0)
{ {
memset(frame, 0, sizeof_frame); SetDataPointer(page, new_start-start);
memset(oldFrame, 0xff, sizeof_frame); // to force update new_end++;
RefreshScreen(); while (new_start < new_end)
} {
i = (new_end-new_start < 15) ? new_end-new_start : 15;
void SSD1306::DisplayOn() if (i == 1)
{ {
SendCommand(SSD1306_CMD_DISPLAY_ON); // 0xAF SendData(frame[new_start]);
} oldFrame[new_start] = frame[new_start];
}
void SSD1306::DisplayOff() else // Use the ability to send up to 16 byte in a row
{ // (1 for command and 15 for data)
SendCommand(SSD1306_CMD_DISPLAY_OFF); // 0xAE {
} SendDataLong(&frame[new_start],i);
memcpy(&oldFrame[new_start], &frame[new_start],i);
void SSD1306::SetContrast(u8 value) }
{ new_start += i;
contrast = value; }
SendCommand(SSD1306_CMD_SET_CONTRAST_CONTROL); }
SendCommand(value); }
if (type != LCD_1106_128x64) // dont fiddle vcomdeselect on 1106 displays
SetVCOMDeselect( value >> 8); void SSD1306::ClearScreen()
} {
memset(frame, 0, sizeof_frame);
void SSD1306::SetVCOMDeselect(u8 value) //memset(oldFrame, 0xff, sizeof_frame); // to force update
{ RefreshScreen();
SendCommand(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL); }
SendCommand( (value & 7) << 4 );
} void SSD1306::DisplayOn()
{
void SSD1306::PlotText(bool useCBMFont, bool petscii, int x, int y, char* str, bool inverse) SendCommand(SSD1306_CMD_DISPLAY_ON); // 0xAF
{ }
// assumes 16 character width
int i; void SSD1306::DisplayOff()
i = 0; {
while (str[i] && x < 16) SendCommand(SSD1306_CMD_DISPLAY_OFF); // 0xAE
{ }
PlotCharacter(useCBMFont, petscii, x++, y, str[i++], inverse);
} void SSD1306::SetContrast(u8 value)
} {
contrast = value;
// Pg 143 - 145. Transposing an 8x8 bit matrix. Hacker's Delight SendCommand(SSD1306_CMD_SET_CONTRAST_CONTROL);
void transpose8(unsigned char* B, const unsigned char* A, bool inverse) SendCommand(value);
{ if (type != LCD_1106_128x64) // dont fiddle vcomdeselect on 1106 displays
unsigned x, y, t; SetVCOMDeselect( value >> 8);
x = (A[7] << 24) | (A[6] << 16) | (A[5] << 8) | A[4]; }
y = (A[3] << 24) | (A[2] << 16) | (A[1] << 8) | A[0];
if (inverse) void SSD1306::SetVCOMDeselect(u8 value)
{ {
x = ~x; SendCommand(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL);
y = ~y; SendCommand( (value & 7) << 4 );
} }
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); void SSD1306::PlotText(bool useCBMFont, bool petscii, int x, int y, char* str, bool inverse)
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); {
// assumes 16 character width
t = (x ^ (x >> 14)) & 0x0000CCCC; x = x ^ t ^ (t << 14); int i;
t = (y ^ (y >> 14)) & 0x0000CCCC; y = y ^ t ^ (t << 14); i = 0;
while (str[i] && x < 16)
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); {
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); PlotCharacter(useCBMFont, petscii, x++, y, str[i++], inverse);
x = t; }
}
B[0] = x >> 24; B[1] = x >> 16; B[2] = x >> 8; B[3] = x; // Pg 143 - 145. Transposing an 8x8 bit matrix. Hacker's Delight
B[4] = y >> 24; B[5] = y >> 16; B[6] = y >> 8; B[7] = y; void transpose8(unsigned char* B, const unsigned char* A, bool inverse)
} {
unsigned x, y, t;
void SSD1306::PlotCharacter(bool useCBMFont, bool petscii, int x, int y, char c, bool inverse) x = (A[7] << 24) | (A[6] << 16) | (A[5] << 8) | A[4];
{ y = (A[3] << 24) | (A[2] << 16) | (A[1] << 8) | A[0];
unsigned char a[8], b[8]; if (inverse)
if (useCBMFont && CBMFont) {
{ x = ~x;
if (! petscii) y = ~y;
c = ascii2petscii(c); }
c = petscii2screen(c);
transpose8(a, CBMFont + ((c+256) * 8), inverse); // 256 byte shift to use the maj/min bank t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
memcpy(frame + (y * 128) + (x * 8), a, 8); t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
}
else t = (x ^ (x >> 14)) & 0x0000CCCC; x = x ^ t ^ (t << 14);
{ t = (y ^ (y >> 14)) & 0x0000CCCC; y = y ^ t ^ (t << 14);
transpose8(a, avpriv_vga16_font + (c * 16), inverse);
transpose8(b, avpriv_vga16_font + (c * 16) + 8, inverse); t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
memcpy(frame + (y * 256) + (x * 8), a, 8); y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
memcpy(frame + (y * 256) + (x * 8) + 128, b, 8); x = t;
}
} B[0] = x >> 24; B[1] = x >> 16; B[2] = x >> 8; B[3] = x;
B[4] = y >> 24; B[5] = y >> 16; B[6] = y >> 8; B[7] = y;
void SSD1306::PlotPixel(int x, int y, int c) }
{
switch (c) void SSD1306::PlotCharacter(bool useCBMFont, bool petscii, int x, int y, char c, bool inverse)
{ {
case 1: frame[x+ (y/8)*width] |= (1 << (y&7)); break; unsigned char a[8], b[8];
case 0: frame[x+ (y/8)*width] &= ~(1 << (y&7)); break; if (useCBMFont && CBMFont)
case -1: frame[x+ (y/8)*width] ^= (1 << (y&7)); break; {
} if (! petscii)
} c = ascii2petscii(c);
c = petscii2screen(c);
// expects source in ssd1306 native vertical byte format transpose8(a, CBMFont + ((c+256) * 8), inverse); // 256 byte shift to use the maj/min bank
void SSD1306::PlotImage(const unsigned char * source) memcpy(frame + (y * 128) + (x * 8), a, 8);
{ }
memcpy (frame, source, SSD1306_128x64_BYTES); else
} {
transpose8(a, avpriv_vga16_font + (c * 16), inverse);
transpose8(b, avpriv_vga16_font + (c * 16) + 8, inverse);
memcpy(frame + (y * 256) + (x * 8), a, 8);
memcpy(frame + (y * 256) + (x * 8) + 128, b, 8);
}
}
void SSD1306::PlotPixel(int x, int y, int c)
{
switch (c)
{
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;
}
}
// expects source in ssd1306 native vertical byte format
void SSD1306::PlotImage(const unsigned char * source)
{
memcpy (frame, source, SSD1306_128x64_BYTES);
}

View file

@ -1,146 +1,147 @@
// Pi1541 - A Commodore 1541 disk drive emulator // Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White // Copyright(C) 2018 Stephen White
// //
// This file is part of Pi1541. // This file is part of Pi1541.
// //
// Pi1541 is free software : you can redistribute it and/or modify // Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// Pi1541 is distributed in the hope that it will be useful, // Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>. // along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#ifndef SSD1306_H #ifndef SSD1306_H
#define SSD1306_H #define SSD1306_H
#include <stdlib.h> #include <stdlib.h>
#include "types.h" #include "types.h"
extern "C" extern "C"
{ {
#include "rpi-i2c.h" #include "rpi-i2c.h"
} }
// 8 pages * (128 columns * 8 bits) // 8 pages * (128 columns * 8 bits)
//0 127 0 127 //0 127 0 127
//0 127 0 127 //0 127 0 127
//0 127 0 127 //0 127 0 127
//________________________________________________________ //________________________________________________________
//7777777 | 7 //7777777 | 7
//6666666 | 6 //6666666 | 6
//5555555 | 5 //5555555 | 5
//4444444 PG(ROW)0 | PG(ROW)1 4 //4444444 PG(ROW)0 | PG(ROW)1 4
//3333333 | 3 //3333333 | 3
//2222222 | 2 //2222222 | 2
//1111111 | 1 //1111111 | 1
//0000000 | 0 //0000000 | 0
//________________________________________________________ //________________________________________________________
//7777777 | 7 //7777777 | 7
//6666666 | 6 //6666666 | 6
//5555555 | 5 //5555555 | 5
//4444444 PG(ROW)2 | PG(ROW)3 4 //4444444 PG(ROW)2 | PG(ROW)3 4
//3333333 | 3 //3333333 | 3
//2222222 | 2 //2222222 | 2
//1111111 | 1 //1111111 | 1
//0000000 | 0 //0000000 | 0
//________________________________________________________ //________________________________________________________
//7777777 | 7 //7777777 | 7
//6666666 | 6 //6666666 | 6
//5555555 | 5 //5555555 | 5
//4444444 PG(ROW)4 | PG(ROW)5 4 //4444444 PG(ROW)4 | PG(ROW)5 4
//3333333 | 3 //3333333 | 3
//2222222 | 2 //2222222 | 2
//1111111 | 1 //1111111 | 1
//0000000 | 0 //0000000 | 0
//________________________________________________________ //________________________________________________________
//7777777 | 7 //7777777 | 7
//6666666 | 6 //6666666 | 6
//5555555 | 5 //5555555 | 5
//4444444 PG(ROW)6 | PG(ROW)7 4 //4444444 PG(ROW)6 | PG(ROW)7 4
//3333333 | 3 //3333333 | 3
//2222222 | 2 //2222222 | 2
//1111111 | 1 //1111111 | 1
//0000000 | 0 //0000000 | 0
//________________________________________________________ //________________________________________________________
#define SSD1306_128x64_BYTES ((128 * 64) / 8) #define SSD1306_128x64_BYTES ((128 * 64) / 8)
class SSD1306 class SSD1306
{ {
public: public:
// 128x32 0x3C // 128x32 0x3C
// 128x64 0x3D or 0x3C (if SA0 is grounded) // 128x64 0x3D or 0x3C (if SA0 is grounded)
SSD1306(int BSCMaster = 1, u8 address = 0x3C, unsigned width = 128, unsigned height = 64, int flip = 0, LCD_MODEL type=LCD_UNKNOWN); SSD1306(int BSCMaster = 1, u8 address = 0x3C, unsigned width = 128, unsigned height = 64, int flip = 0, LCD_MODEL type=LCD_UNKNOWN);
void PlotCharacter(bool useCBMFont, bool petscii, int x, int y, char ascii, bool inverse); void PlotCharacter(bool useCBMFont, bool petscii, int x, int y, char ascii, bool inverse);
void PlotText(bool useCBMFont, bool petscii, int x, int y, char* str, bool inverse); void PlotText(bool useCBMFont, bool petscii, int x, int y, char* str, bool inverse);
void InitHardware(); void InitHardware();
void DisplayOn(); void DisplayOn();
void DisplayOff(); void DisplayOff();
void SetContrast(u8 value); void SetContrast(u8 value);
u8 GetContrast() { return contrast; } u8 GetContrast() { return contrast; }
void SetVCOMDeselect(u8 value); void SetVCOMDeselect(u8 value);
void ClearScreen(); void ClearScreen();
void RefreshScreen(); void RefreshScreen();
void RefreshPage(u32 page); void RefreshPage(u32 page);
void RefreshTextRows(u32 start, u32 amountOfRows); void RefreshTextRows(u32 start, u32 amountOfRows);
void SetDisplayWindow(u8 x1, u8 y1, u8 x2, u8 y2); void SetDisplayWindow(u8 x1, u8 y1, u8 x2, u8 y2);
void PlotPixel(int x, int y, int c); void PlotPixel(int x, int y, int c);
void PlotImage(const unsigned char * source); void PlotImage(const unsigned char * source);
protected: protected:
void SendCommand(u8 command); void SendCommand(u8 command);
void SendData(u8 data); void SendData(u8 data);
void SendDataLong(void* data, u8 length);
void Home();
void SetDataPointer(u8 row, u8 col); void Home();
void SetDataPointer(u8 row, u8 col);
// unsigned char frame[SSD1306_128x64_BYTES];
// unsigned char oldFrame[SSD1306_128x64_BYTES]; // unsigned char frame[SSD1306_128x64_BYTES];
unsigned char * frame; // unsigned char oldFrame[SSD1306_128x64_BYTES];
unsigned char * oldFrame; unsigned char * frame;
unsigned sizeof_frame; unsigned char * oldFrame;
unsigned sizeof_frame;
int BSCMaster;
u8 address; int BSCMaster;
int type; u8 address;
int flip; int type;
int contrast; int flip;
unsigned width; int contrast;
unsigned height; unsigned width;
}; unsigned height;
#endif };
#endif
#define SSD1306_CMD_SET_COLUMN_LOW 0x00
#define SSD1306_CMD_SET_COLUMN_HIGH 0x10 #define SSD1306_CMD_SET_COLUMN_LOW 0x00
#define SSD1306_CMD_SET_PAGE 0xB0 #define SSD1306_CMD_SET_COLUMN_HIGH 0x10
#define SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE 0x20 #define SSD1306_CMD_SET_PAGE 0xB0
#define SSD1306_CMD_SET_COLUMN_ADDRESS 0x21 #define SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE 0x20
#define SSD1306_CMD_SET_PAGE_ADDRESS 0x22 #define SSD1306_CMD_SET_COLUMN_ADDRESS 0x21
#define SSD1306_CMD_DEACTIVATE_SCROLL 0x2E #define SSD1306_CMD_SET_PAGE_ADDRESS 0x22
#define SSD1306_CMD_ACTIVATE_SCROLL 0x2F #define SSD1306_CMD_DEACTIVATE_SCROLL 0x2E
#define SSD1306_CMD_SET_CONTRAST_CONTROL 0x81 // Set Contrast Control for BANK0 #define SSD1306_CMD_ACTIVATE_SCROLL 0x2F
#define SSD1306_ENABLE_CHARGE_PUMP 0x8D #define SSD1306_CMD_SET_CONTRAST_CONTROL 0x81 // Set Contrast Control for BANK0
#define SSD1306_CMD_TEST_DISPLAY_OFF 0xA4 #define SSD1306_ENABLE_CHARGE_PUMP 0x8D
#define SSD1306_CMD_TEST_DISPLAY_ON 0xA5 #define SSD1306_CMD_TEST_DISPLAY_OFF 0xA4
#define SSD1306_CMD_NORMAL_DISPLAY 0xA6 // 1 = on pixel #define SSD1306_CMD_TEST_DISPLAY_ON 0xA5
#define SSD1306_CMD_INVERT_DISPLAY 0xA7 // 0 = on pixel #define SSD1306_CMD_NORMAL_DISPLAY 0xA6 // 1 = on pixel
#define SSD1306_CMD_DISPLAY_OFF 0xAE #define SSD1306_CMD_INVERT_DISPLAY 0xA7 // 0 = on pixel
#define SSD1306_CMD_DISPLAY_ON 0xAF #define SSD1306_CMD_DISPLAY_OFF 0xAE
#define SSD1306_CMD_MULTIPLEX_RATIO 0xA8 #define SSD1306_CMD_DISPLAY_ON 0xAF
#define SSD1306_CMD_SET_START_LINE 0x40 #define SSD1306_CMD_MULTIPLEX_RATIO 0xA8
#define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3 #define SSD1306_CMD_SET_START_LINE 0x40
#define SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO 0xD5 #define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3
#define SSD1306_CMD_SET_PRE_CHARGE_PERIOD 0xD9 #define SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO 0xD5
#define SSD1306_CMD_SET_COM_PINS 0xDA #define SSD1306_CMD_SET_PRE_CHARGE_PERIOD 0xD9
#define SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL 0xDB #define SSD1306_CMD_SET_COM_PINS 0xDA
#define SSD1306_CONTROL_REG 0x00 #define SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL 0xDB
#define SSD1306_DATA_REG 0x40 #define SSD1306_CONTROL_REG 0x00
#define SSD1306_DATA_REG 0x40