Skip to content

Commit

Permalink
Fix for random uninitialized data in display RAM for displays less th…
Browse files Browse the repository at this point in the history
…an 128 segments wide.

Bug was visible when scrolling.
TDB: allow drawing outside visible area to exploit full 128 horizontal resolution in hardware scrolling.
  • Loading branch information
dok-net committed Oct 7, 2020
1 parent 477579d commit afa1a93
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 43 deletions.
72 changes: 33 additions & 39 deletions Adafruit_SSD1306.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
bool Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, bool reset,
bool periphBegin) {

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

clearDisplay();
Expand Down Expand Up @@ -631,16 +631,17 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
y = HEIGHT - y - 1;
break;
}
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
switch (color) {
case SSD1306_WHITE:
buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));
break;
case SSD1306_BLACK:
buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));
break;
case SSD1306_INVERSE:
buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));
break;
case SSD1306_WHITE:
buffer[x + (y / 8) * SSD1306_SEGMENTS] |= (1 << (y & 7));
break;
case SSD1306_BLACK:
buffer[x + (y / 8) * SSD1306_SEGMENTS] &= ~(1 << (y & 7));
break;
case SSD1306_INVERSE:
buffer[x + (y / 8) * SSD1306_SEGMENTS] ^= (1 << (y & 7));
break;
}
}
}
Expand All @@ -653,7 +654,7 @@ void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
commands as needed by one's own application.
*/
void Adafruit_SSD1306::clearDisplay(void) {
memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8));
memset(buffer, 0, SSD1306_SEGMENTS * ((HEIGHT + 7) / 8));
}

/*!
Expand Down Expand Up @@ -716,7 +717,9 @@ void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w,
w = (WIDTH - x);
}
if (w > 0) { // Proceed only if width is positive
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x], mask = 1 << (y & 7);
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
uint8_t* pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];
uint8_t mask = 1 << (y & 7);
switch (color) {
case SSD1306_WHITE:
while (w--) {
Expand Down Expand Up @@ -802,7 +805,8 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
// this display doesn't need ints for coordinates,
// use local byte registers for faster juggling
uint8_t y = __y, h = __h;
uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x];
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
uint8_t *pBuf = &buffer[x + (y / 8) * SSD1306_SEGMENTS];

// do the first partial byte, if necessary - this requires some masking
uint8_t mod = (y & 7);
Expand Down Expand Up @@ -830,7 +834,7 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
*pBuf ^= mask;
break;
}
pBuf += WIDTH;
pBuf += SSD1306_SEGMENTS;
}

if (h >= mod) { // More to go?
Expand All @@ -842,15 +846,15 @@ void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y,
// black/white write version with an extra comparison per loop
do {
*pBuf ^= 0xFF; // Invert byte
pBuf += WIDTH; // Advance pointer 8 rows
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
h -= 8; // Subtract 8 rows from height
} while (h >= 8);
} else {
// store a local value to work with
uint8_t val = (color != SSD1306_BLACK) ? 255 : 0;
do {
*pBuf = val; // Set byte
pBuf += WIDTH; // Advance pointer 8 rows
pBuf += SSD1306_SEGMENTS; // Advance pointer 8 rows
h -= 8; // Subtract 8 rows from height
} while (h >= 8);
}
Expand Down Expand Up @@ -911,7 +915,8 @@ bool Adafruit_SSD1306::getPixel(int16_t x, int16_t y) {
y = HEIGHT - y - 1;
break;
}
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
if ((WIDTH == 64) && (HEIGHT == 48)) x += 32;
return (buffer[x + (y / 8) * SSD1306_SEGMENTS] & (1 << (y & 7)));
}
return false; // Pixel out of bounds
}
Expand All @@ -934,27 +939,16 @@ uint8_t *Adafruit_SSD1306::getBuffer(void) { return buffer; }
*/
void Adafruit_SSD1306::display(void) {
TRANSACTION_START
if ((WIDTH != 64) || (HEIGHT != 48)) {
static const uint8_t PROGMEM dlist1a[] = {
SSD1306_PAGEADDR,
0, // Page start address
0xFF, // Page end (not really, but works here)
SSD1306_COLUMNADDR,
0 }; // Column start address
ssd1306_commandList(dlist1a, sizeof(dlist1a));
ssd1306_command1(WIDTH - 1); // Column end address
} else {
static const uint8_t PROGMEM dlist1b[] = {
SSD1306_PAGEADDR,
0 }; // Page start address
ssd1306_commandList(dlist1b, sizeof(dlist1b));
ssd1306_command1((HEIGHT / 8) - 1); // Page end address
static const uint8_t PROGMEM dlist2b[] = {
SSD1306_COLUMNADDR,
32 }; // Column start address
ssd1306_commandList(dlist2b, sizeof(dlist2b));
ssd1306_command1(32 + WIDTH - 1); // Column end address
}
static const uint8_t PROGMEM dlist1[] = {
SSD1306_PAGEADDR,
0 }; // Page start address
ssd1306_commandList(dlist1, sizeof(dlist1));
ssd1306_command1((HEIGHT + 7) / 8 - 1); // Page end address
static const uint8_t PROGMEM dlist2[] = {
SSD1306_COLUMNADDR,
0 }; // Column start address
ssd1306_commandList(dlist2, sizeof(dlist2));
ssd1306_command1(SSD1306_SEGMENTS - 1); // Column end address

#if defined(ESP8266)
// ESP8266 needs a periodic yield() call to avoid watchdog reset.
Expand All @@ -965,7 +959,7 @@ void Adafruit_SSD1306::display(void) {
// 32-byte transfer condition below.
yield();
#endif
uint16_t count = WIDTH * ((HEIGHT + 7) / 8);
uint16_t count = SSD1306_SEGMENTS * ((HEIGHT + 7) / 8);
uint8_t *ptr = buffer;
if (wire) { // I2C
wire->beginTransmission(i2caddr);
Expand Down
10 changes: 6 additions & 4 deletions Adafruit_SSD1306.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ typedef uint32_t PortMask;
#define SSD1306_ACTIVATE_SCROLL 0x2F ///< Start scroll
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 ///< Set scroll range

#define SSD1306_SEGMENTS 128 ///< See datasheet

// Deprecated size stuff for backwards compatibility with old sketches
#if defined SSD1306_128_64
#define SSD1306_LCDWIDTH 128 ///< DEPRECATED: width w/SSD1306_128_64 defined
Expand Down Expand Up @@ -151,11 +153,11 @@ class Adafruit_SSD1306 : public Adafruit_GFX {
bool reset = true, bool periphBegin = true);
void display(void);
void clearDisplay(void);
void invertDisplay(bool i);
virtual void invertDisplay(bool i) override;
void dim(bool dim);
void drawPixel(int16_t x, int16_t y, uint16_t color);
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) override;
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
void startscrollright(uint8_t start, uint8_t stop);
void startscrollleft(uint8_t start, uint8_t stop);
void startscrolldiagright(uint8_t start, uint8_t stop);
Expand Down

0 comments on commit afa1a93

Please sign in to comment.