Skip to content

Commit 3cfcc9a

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 a838bcd commit 3cfcc9a

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
@@ -451,7 +451,7 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
451451
boolean Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, boolean reset,
452452
boolean periphBegin) {
453453

454-
if((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8))))
454+
if((!buffer) && !(buffer = (uint8_t *)malloc(SSD1306_SEGMENTS * ((HEIGHT + 7) / 8))))
455455
return false;
456456

457457
clearDisplay();
@@ -625,10 +625,11 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
625625
y = HEIGHT - y - 1;
626626
break;
627627
}
628+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
628629
switch(color) {
629-
case WHITE: buffer[x + (y/8)*WIDTH] |= (1 << (y&7)); break;
630-
case BLACK: buffer[x + (y/8)*WIDTH] &= ~(1 << (y&7)); break;
631-
case INVERSE: buffer[x + (y/8)*WIDTH] ^= (1 << (y&7)); break;
630+
case WHITE: buffer[x + (y/8)* SSD1306_SEGMENTS] |= (1 << (y&7)); break;
631+
case BLACK: buffer[x + (y/8)* SSD1306_SEGMENTS] &= ~(1 << (y&7)); break;
632+
case INVERSE: buffer[x + (y/8)* SSD1306_SEGMENTS] ^= (1 << (y&7)); break;
632633
}
633634
}
634635
}
@@ -641,7 +642,7 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
641642
commands as needed by one's own application.
642643
*/
643644
void Adafruit_SSD1306::clearDisplay(void) {
644-
memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8));
645+
memset(buffer, 0, SSD1306_SEGMENTS * ((HEIGHT + 7) / 8));
645646
}
646647

647648
/*!
@@ -702,8 +703,9 @@ void Adafruit_SSD1306::drawFastHLineInternal(
702703
w = (WIDTH - x);
703704
}
704705
if(w > 0) { // Proceed only if width is positive
705-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x],
706-
mask = 1 << (y & 7);
706+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
707+
uint8_t* pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
708+
uint8_t mask = 1 << (y & 7);
707709
switch(color) {
708710
case WHITE: while(w--) { *pBuf++ |= mask; }; break;
709711
case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break;
@@ -774,7 +776,8 @@ void Adafruit_SSD1306::drawFastVLineInternal(
774776
// this display doesn't need ints for coordinates,
775777
// use local byte registers for faster juggling
776778
uint8_t y = __y, h = __h;
777-
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x];
779+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
780+
uint8_t *pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
778781

779782
// do the first partial byte, if necessary - this requires some masking
780783
uint8_t mod = (y & 7);
@@ -795,7 +798,7 @@ void Adafruit_SSD1306::drawFastVLineInternal(
795798
case BLACK: *pBuf &= ~mask; break;
796799
case INVERSE: *pBuf ^= mask; break;
797800
}
798-
pBuf += WIDTH;
801+
pBuf += SSD1306_SEGMENTS;
799802
}
800803

801804
if(h >= mod) { // More to go?
@@ -807,15 +810,15 @@ void Adafruit_SSD1306::drawFastVLineInternal(
807810
// black/white write version with an extra comparison per loop
808811
do {
809812
*pBuf ^= 0xFF; // Invert byte
810-
pBuf += WIDTH; // Advance pointer 8 rows
813+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
811814
h -= 8; // Subtract 8 rows from height
812815
} while(h >= 8);
813816
} else {
814817
// store a local value to work with
815818
uint8_t val = (color != BLACK) ? 255 : 0;
816819
do {
817820
*pBuf = val; // Set byte
818-
pBuf += WIDTH; // Advance pointer 8 rows
821+
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
819822
h -= 8; // Subtract 8 rows from height
820823
} while(h >= 8);
821824
}
@@ -870,7 +873,8 @@ boolean Adafruit_SSD1306::getPixel(int16_t x, int16_t y) {
870873
y = HEIGHT - y - 1;
871874
break;
872875
}
873-
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
876+
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
877+
return (buffer[x + (y / 8) * SSD1306_SEGMENTS] & (1 << (y & 7)));
874878
}
875879
return false; // Pixel out of bounds
876880
}
@@ -895,27 +899,16 @@ uint8_t *Adafruit_SSD1306::getBuffer(void) {
895899
*/
896900
void Adafruit_SSD1306::display(void) {
897901
TRANSACTION_START
898-
if ((WIDTH != 64) || (HEIGHT != 48)) {
899-
static const uint8_t PROGMEM dlist1a[] = {
900-
SSD1306_PAGEADDR,
901-
0, // Page start address
902-
0xFF, // Page end (not really, but works here)
903-
SSD1306_COLUMNADDR,
904-
0 }; // Column start address
905-
ssd1306_commandList(dlist1a, sizeof(dlist1a));
906-
ssd1306_command1(WIDTH - 1); // Column end address
907-
} else {
908-
static const uint8_t PROGMEM dlist1b[] = {
909-
SSD1306_PAGEADDR,
910-
0 }; // Page start address
911-
ssd1306_commandList(dlist1b, sizeof(dlist1b));
912-
ssd1306_command1((HEIGHT / 8) - 1); // Page end address
913-
static const uint8_t PROGMEM dlist2b[] = {
914-
SSD1306_COLUMNADDR,
915-
32 }; // Column start address
916-
ssd1306_commandList(dlist2b, sizeof(dlist2b));
917-
ssd1306_command1(32 + WIDTH - 1); // Column end address
918-
}
902+
static const uint8_t PROGMEM dlist1[] = {
903+
SSD1306_PAGEADDR,
904+
0 }; // Page start address
905+
ssd1306_commandList(dlist1, sizeof(dlist1));
906+
ssd1306_command1((HEIGHT + 7) / 8 - 1); // Page end address
907+
static const uint8_t PROGMEM dlist2[] = {
908+
SSD1306_COLUMNADDR,
909+
0 }; // Column start address
910+
ssd1306_commandList(dlist2, sizeof(dlist2));
911+
ssd1306_command1(SSD1306_SEGMENTS - 1); // Column end address
919912

920913
#if defined(ESP8266)
921914
// ESP8266 needs a periodic yield() call to avoid watchdog reset.
@@ -926,7 +919,7 @@ void Adafruit_SSD1306::display(void) {
926919
// 32-byte transfer condition below.
927920
yield();
928921
#endif
929-
uint16_t count = WIDTH * ((HEIGHT + 7) / 8);
922+
uint16_t count = SSD1306_SEGMENTS * ((HEIGHT + 7) / 8);
930923
uint8_t *ptr = buffer;
931924
if(wire) { // I2C
932925
wire->beginTransmission(i2caddr);

Adafruit_SSD1306.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
9696
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range
9797

98+
#define SSD1306_SEGMENTS 128 ///< See datasheet
99+
98100
// Deprecated size stuff for backwards compatibility with old sketches
99101
#if defined SSD1306_128_64
100102
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
@@ -140,11 +142,11 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
140142
boolean periphBegin=true);
141143
void display(void);
142144
void clearDisplay(void);
143-
void invertDisplay(boolean i);
145+
virtual void invertDisplay(boolean i) override;
144146
void dim(boolean dim);
145-
void drawPixel(int16_t x, int16_t y, uint16_t color);
146-
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
147-
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
147+
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) override;
148+
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
149+
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
148150
void startscrollright(uint8_t start, uint8_t stop);
149151
void startscrollleft(uint8_t start, uint8_t stop);
150152
void startscrolldiagright(uint8_t start, uint8_t stop);

0 commit comments

Comments
 (0)