Skip to content

Commit e2d19fd

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 560dab4 commit e2d19fd

File tree

2 files changed

+33
-38
lines changed

2 files changed

+33
-38
lines changed

Adafruit_SSD1306.cpp

Lines changed: 27 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
454454
boolean Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, boolean reset,
455455
boolean periphBegin) {
456456

457-
if((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8))))
457+
if((!buffer) && !(buffer = (uint8_t *)malloc(SSD1306_SEGMENTS * ((HEIGHT + 7) / 8))))
458458
return false;
459459

460460
clearDisplay();
@@ -628,10 +628,11 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
628628
y = HEIGHT - y - 1;
629629
break;
630630
}
631+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
631632
switch(color) {
632-
case SSD1306_WHITE: buffer[x + (y/8)*WIDTH] |= (1 << (y&7)); break;
633-
case SSD1306_BLACK: buffer[x + (y/8)*WIDTH] &= ~(1 << (y&7)); break;
634-
case SSD1306_INVERSE: buffer[x + (y/8)*WIDTH] ^= (1 << (y&7)); break;
633+
case SSD1306_WHITE: buffer[x + (y/8)* SSD1306_SEGMENTS] |= (1 << (y&7)); break;
634+
case SSD1306_BLACK: buffer[x + (y/8)* SSD1306_SEGMENTS] &= ~(1 << (y&7)); break;
635+
case SSD1306_INVERSE: buffer[x + (y/8)* SSD1306_SEGMENTS] ^= (1 << (y&7)); break;
635636
}
636637
}
637638
}
@@ -644,7 +645,7 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
644645
commands as needed by one's own application.
645646
*/
646647
void Adafruit_SSD1306::clearDisplay(void) {
647-
memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8));
648+
memset(buffer, 0, SSD1306_SEGMENTS * ((HEIGHT + 7) / 8));
648649
}
649650

650651
/*!
@@ -705,8 +706,9 @@ void Adafruit_SSD1306::drawFastHLineInternal(
705706
w = (WIDTH - x);
706707
}
707708
if(w > 0) { // Proceed only if width is positive
708-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x],
709-
mask = 1 << (y & 7);
709+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
710+
uint8_t* pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
711+
uint8_t mask = 1 << (y & 7);
710712
switch(color) {
711713
case SSD1306_WHITE: while(w--) { *pBuf++ |= mask; }; break;
712714
case SSD1306_BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break;
@@ -777,7 +779,8 @@ void Adafruit_SSD1306::drawFastVLineInternal(
777779
// this display doesn't need ints for coordinates,
778780
// use local byte registers for faster juggling
779781
uint8_t y = __y, h = __h;
780-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x];
782+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
783+
uint8_t *pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
781784

782785
// do the first partial byte, if necessary - this requires some masking
783786
uint8_t mod = (y & 7);
@@ -798,7 +801,7 @@ void Adafruit_SSD1306::drawFastVLineInternal(
798801
case SSD1306_BLACK: *pBuf &= ~mask; break;
799802
case SSD1306_INVERSE: *pBuf ^= mask; break;
800803
}
801-
pBuf += WIDTH;
804+
pBuf += SSD1306_SEGMENTS;
802805
}
803806

804807
if(h >= mod) { // More to go?
@@ -810,15 +813,15 @@ void Adafruit_SSD1306::drawFastVLineInternal(
810813
// black/white write version with an extra comparison per loop
811814
do {
812815
*pBuf ^= 0xFF; // Invert byte
813-
pBuf += WIDTH; // Advance pointer 8 rows
816+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
814817
h -= 8; // Subtract 8 rows from height
815818
} while(h >= 8);
816819
} else {
817820
// store a local value to work with
818821
uint8_t val = (color != SSD1306_BLACK) ? 255 : 0;
819822
do {
820823
*pBuf = val; // Set byte
821-
pBuf += WIDTH; // Advance pointer 8 rows
824+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
822825
h -= 8; // Subtract 8 rows from height
823826
} while(h >= 8);
824827
}
@@ -873,7 +876,8 @@ boolean Adafruit_SSD1306::getPixel(int16_t x, int16_t y) {
873876
y = HEIGHT - y - 1;
874877
break;
875878
}
876-
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
879+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
880+
return (buffer[x + (y / 8) * SSD1306_SEGMENTS] & (1 << (y & 7)));
877881
}
878882
return false; // Pixel out of bounds
879883
}
@@ -898,27 +902,16 @@ uint8_t *Adafruit_SSD1306::getBuffer(void) {
898902
*/
899903
void Adafruit_SSD1306::display(void) {
900904
TRANSACTION_START
901-
if ((WIDTH != 64) || (HEIGHT != 48)) {
902-
static const uint8_t PROGMEM dlist1a[] = {
903-
SSD1306_PAGEADDR,
904-
0, // Page start address
905-
0xFF, // Page end (not really, but works here)
906-
SSD1306_COLUMNADDR,
907-
0 }; // Column start address
908-
ssd1306_commandList(dlist1a, sizeof(dlist1a));
909-
ssd1306_command1(WIDTH - 1); // Column end address
910-
} else {
911-
static const uint8_t PROGMEM dlist1b[] = {
912-
SSD1306_PAGEADDR,
913-
0 }; // Page start address
914-
ssd1306_commandList(dlist1b, sizeof(dlist1b));
915-
ssd1306_command1((HEIGHT / 8) - 1); // Page end address
916-
static const uint8_t PROGMEM dlist2b[] = {
917-
SSD1306_COLUMNADDR,
918-
32 }; // Column start address
919-
ssd1306_commandList(dlist2b, sizeof(dlist2b));
920-
ssd1306_command1(32 + WIDTH - 1); // Column end address
921-
}
905+
static const uint8_t PROGMEM dlist1[] = {
906+
SSD1306_PAGEADDR,
907+
0 }; // Page start address
908+
ssd1306_commandList(dlist1, sizeof(dlist1));
909+
ssd1306_command1((HEIGHT + 7) / 8 - 1); // Page end address
910+
static const uint8_t PROGMEM dlist2[] = {
911+
SSD1306_COLUMNADDR,
912+
0 }; // Column start address
913+
ssd1306_commandList(dlist2, sizeof(dlist2));
914+
ssd1306_command1(SSD1306_SEGMENTS - 1); // Column end address
922915

923916
#if defined(ESP8266)
924917
// ESP8266 needs a periodic yield() call to avoid watchdog reset.
@@ -929,7 +922,7 @@ void Adafruit_SSD1306::display(void) {
929922
// 32-byte transfer condition below.
930923
yield();
931924
#endif
932-
uint16_t count = WIDTH * ((HEIGHT + 7) / 8);
925+
uint16_t count = SSD1306_SEGMENTS * ((HEIGHT + 7) / 8);
933926
uint8_t *ptr = buffer;
934927
if(wire) { // I2C
935928
wire->beginTransmission(i2caddr);

Adafruit_SSD1306.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
105105
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range
106106

107+
#define SSD1306_SEGMENTS 128 ///< See datasheet
108+
107109
// Deprecated size stuff for backwards compatibility with old sketches
108110
#if defined SSD1306_128_64
109111
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
@@ -149,11 +151,11 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
149151
boolean periphBegin=true);
150152
void display(void);
151153
void clearDisplay(void);
152-
void invertDisplay(boolean i);
154+
virtual void invertDisplay(boolean i) override;
153155
void dim(boolean dim);
154-
void drawPixel(int16_t x, int16_t y, uint16_t color);
155-
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
156-
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
156+
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) override;
157+
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
158+
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
157159
void startscrollright(uint8_t start, uint8_t stop);
158160
void startscrollleft(uint8_t start, uint8_t stop);
159161
void startscrolldiagright(uint8_t start, uint8_t stop);

0 commit comments

Comments
 (0)