Skip to content

Commit 19706a5

Browse files
committed
Fix for random uninitialized data in display RAM for displays less than 128 segments wide.
Bug was visible when scrolling. TDB: allow drawing outside visible area to exploit full 128 horizontal resolution in hardware scrolling.
1 parent 8d1eed6 commit 19706a5

File tree

2 files changed

+39
-43
lines changed

2 files changed

+39
-43
lines changed

Adafruit_SSD1306.cpp

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
463463
bool Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, bool reset,
464464
bool periphBegin) {
465465

466-
if ((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8))))
466+
if ((!buffer) && !(buffer = (uint8_t *)malloc(SSD1306_SEGMENTS * ((HEIGHT + 7) / 8))))
467467
return false;
468468

469469
clearDisplay();
@@ -632,16 +632,17 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
632632
y = HEIGHT - y - 1;
633633
break;
634634
}
635+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
635636
switch (color) {
636-
case SSD1306_WHITE:
637-
buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));
638-
break;
639-
case SSD1306_BLACK:
640-
buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));
641-
break;
642-
case SSD1306_INVERSE:
643-
buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));
644-
break;
637+
case SSD1306_WHITE:
638+
buffer[x + (y / 8) * SSD1306_SEGMENTS] |= (1 << (y & 7));
639+
break;
640+
case SSD1306_BLACK:
641+
buffer[x + (y / 8) * SSD1306_SEGMENTS] &= ~(1 << (y & 7));
642+
break;
643+
case SSD1306_INVERSE:
644+
buffer[x + (y / 8) * SSD1306_SEGMENTS] ^= (1 << (y & 7));
645+
break;
645646
}
646647
}
647648
}
@@ -654,7 +655,7 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
654655
commands as needed by one's own application.
655656
*/
656657
void Adafruit_SSD1306::clearDisplay(void) {
657-
memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8));
658+
memset(buffer, 0, SSD1306_SEGMENTS * ((HEIGHT + 7) / 8));
658659
}
659660

660661
/*!
@@ -717,7 +718,9 @@ void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
717718
w = (WIDTH - x);
718719
}
719720
if (w > 0) { // Proceed only if width is positive
720-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x], mask = 1 << (y & 7);
721+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
722+
uint8_t* pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
723+
uint8_t mask = 1 << (y & 7);
721724
switch (color) {
722725
case SSD1306_WHITE:
723726
while (w--) {
@@ -803,7 +806,8 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
803806
// this display doesn't need ints for coordinates,
804807
// use local byte registers for faster juggling
805808
uint8_t y = __y, h = __h;
806-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x];
809+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
810+
uint8_t *pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
807811

808812
// do the first partial byte, if necessary - this requires some masking
809813
uint8_t mod = (y & 7);
@@ -831,7 +835,7 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
831835
*pBuf ^= mask;
832836
break;
833837
}
834-
pBuf += WIDTH;
838+
pBuf += SSD1306_SEGMENTS;
835839
}
836840

837841
if (h >= mod) { // More to go?
@@ -843,15 +847,15 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
843847
// black/white write version with an extra comparison per loop
844848
do {
845849
*pBuf ^= 0xFF; // Invert byte
846-
pBuf += WIDTH; // Advance pointer 8 rows
850+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
847851
h -= 8; // Subtract 8 rows from height
848852
} while (h >= 8);
849853
} else {
850854
// store a local value to work with
851855
uint8_t val = (color != SSD1306_BLACK) ? 255 : 0;
852856
do {
853857
*pBuf = val; // Set byte
854-
pBuf += WIDTH; // Advance pointer 8 rows
858+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
855859
h -= 8; // Subtract 8 rows from height
856860
} while (h >= 8);
857861
}
@@ -912,7 +916,8 @@ bool Adafruit_SSD1306::getPixel(int16_t x, int16_t y) {
912916
y = HEIGHT - y - 1;
913917
break;
914918
}
915-
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
919+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
920+
return (buffer[x + (y / 8) * SSD1306_SEGMENTS] & (1 << (y & 7)));
916921
}
917922
return false; // Pixel out of bounds
918923
}
@@ -935,27 +940,16 @@ uint8_t *Adafruit_SSD1306::getBuffer(void) { return buffer; }
935940
*/
936941
void Adafruit_SSD1306::display(void) {
937942
TRANSACTION_START
938-
if ((WIDTH != 64) || (HEIGHT != 48)) {
939-
static const uint8_t PROGMEM dlist1a[] = {
940-
SSD1306_PAGEADDR,
941-
0, // Page start address
942-
0xFF, // Page end (not really, but works here)
943-
SSD1306_COLUMNADDR,
944-
0 }; // Column start address
945-
ssd1306_commandList(dlist1a, sizeof(dlist1a));
946-
ssd1306_command1(WIDTH - 1); // Column end address
947-
} else {
948-
static const uint8_t PROGMEM dlist1b[] = {
949-
SSD1306_PAGEADDR,
950-
0 }; // Page start address
951-
ssd1306_commandList(dlist1b, sizeof(dlist1b));
952-
ssd1306_command1((HEIGHT / 8) - 1); // Page end address
953-
static const uint8_t PROGMEM dlist2b[] = {
954-
SSD1306_COLUMNADDR,
955-
32 }; // Column start address
956-
ssd1306_commandList(dlist2b, sizeof(dlist2b));
957-
ssd1306_command1(32 + WIDTH - 1); // Column end address
958-
}
943+
static const uint8_t PROGMEM dlist1[] = {
944+
SSD1306_PAGEADDR,
945+
0 }; // Page start address
946+
ssd1306_commandList(dlist1, sizeof(dlist1));
947+
ssd1306_command1((HEIGHT + 7) / 8 - 1); // Page end address
948+
static const uint8_t PROGMEM dlist2[] = {
949+
SSD1306_COLUMNADDR,
950+
0 }; // Column start address
951+
ssd1306_commandList(dlist2, sizeof(dlist2));
952+
ssd1306_command1(SSD1306_SEGMENTS - 1); // Column end address
959953

960954
#if defined(ESP8266)
961955
// ESP8266 needs a periodic yield() call to avoid watchdog reset.
@@ -966,7 +960,7 @@ void Adafruit_SSD1306::display(void) {
966960
// 32-byte transfer condition below.
967961
yield();
968962
#endif
969-
uint16_t count = WIDTH * ((HEIGHT + 7) / 8);
963+
uint16_t count = SSD1306_SEGMENTS * ((HEIGHT + 7) / 8);
970964
uint8_t *ptr = buffer;
971965
if (wire) { // I2C
972966
wire->beginTransmission(i2caddr);

Adafruit_SSD1306.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ typedef uint32_t PortMask;
106106
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
107107
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range
108108

109+
#define SSD1306_SEGMENTS 128 ///< See datasheet
110+
109111
// Deprecated size stuff for backwards compatibility with old sketches
110112
#if defined SSD1306_128_64
111113
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
@@ -151,11 +153,11 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
151153
bool reset = true, bool periphBegin = true);
152154
void display(void);
153155
void clearDisplay(void);
154-
void invertDisplay(bool i);
156+
virtual void invertDisplay(bool i) override;
155157
void dim(bool dim);
156-
void drawPixel(int16_t x, int16_t y, uint16_t color);
157-
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
158-
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
158+
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) override;
159+
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
160+
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
159161
void startscrollright(uint8_t start, uint8_t stop);
160162
void startscrollleft(uint8_t start, uint8_t stop);
161163
void startscrolldiagright(uint8_t start, uint8_t stop);

0 commit comments

Comments
 (0)