Skip to content

Commit d9220ba

Browse files
authored
Gray oled support (#317)
rename monooled to grayoled and support 1 or 4 bpp - backtested with SH110x and also new SSD1327 bump too
1 parent 0752d4b commit d9220ba

File tree

3 files changed

+93
-75
lines changed

3 files changed

+93
-75
lines changed

Adafruit_MonoOLED.cpp renamed to Adafruit_GrayOLED.cpp

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*!
2-
* @file Adafruit_MonoOLED.cpp
2+
* @file Adafruit_GrayOLED.cpp
33
*
4-
* This is documentation for Adafruit's generic library for monochrome
4+
* This is documentation for Adafruit's generic library for grayscale
55
* OLED displays: http://www.adafruit.com/category/63_98
66
*
77
* These displays use I2C or SPI to communicate. I2C requires 2 pins
@@ -17,18 +17,19 @@
1717

1818
#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
1919

20-
#include "Adafruit_MonoOLED.h"
20+
#include "Adafruit_GrayOLED.h"
2121
#include <Adafruit_GFX.h>
2222

2323
// SOME DEFINES AND STATIC VARIABLES USED INTERNALLY -----------------------
2424

25-
#define monooled_swap(a, b) \
25+
#define grayoled_swap(a, b) \
2626
(((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation
2727

2828
// CONSTRUCTORS, DESTRUCTOR ------------------------------------------------
2929

3030
/*!
3131
@brief Constructor for I2C-interfaced OLED displays.
32+
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
3233
@param w
3334
Display width in pixels
3435
@param h
@@ -59,18 +60,19 @@
5960
@note Call the object's begin() function before use -- buffer
6061
allocation is performed there!
6162
*/
62-
Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, TwoWire *twi,
63-
int8_t rst_pin, uint32_t clkDuring,
64-
uint32_t clkAfter)
63+
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
64+
TwoWire *twi, int8_t rst_pin,
65+
uint32_t clkDuring, uint32_t clkAfter)
6566
: Adafruit_GFX(w, h), i2c_preclk(clkDuring), i2c_postclk(clkAfter),
66-
buffer(NULL), dcPin(-1), csPin(-1), rstPin(rst_pin) {
67+
buffer(NULL), dcPin(-1), csPin(-1), rstPin(rst_pin), _bpp(bpp) {
6768
i2c_dev = NULL;
6869
_theWire = twi;
6970
}
7071

7172
/*!
72-
@brief Constructor for SPI MonoOLED displays, using software (bitbang)
73+
@brief Constructor for SPI GrayOLED displays, using software (bitbang)
7374
SPI.
75+
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
7476
@param w
7577
Display width in pixels
7678
@param h
@@ -94,16 +96,19 @@ Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, TwoWire *twi,
9496
@note Call the object's begin() function before use -- buffer
9597
allocation is performed there!
9698
*/
97-
Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, int8_t mosi_pin,
98-
int8_t sclk_pin, int8_t dc_pin,
99-
int8_t rst_pin, int8_t cs_pin)
100-
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) {
99+
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
100+
int8_t mosi_pin, int8_t sclk_pin,
101+
int8_t dc_pin, int8_t rst_pin,
102+
int8_t cs_pin)
103+
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
104+
_bpp(bpp) {
101105

102106
spi_dev = new Adafruit_SPIDevice(cs_pin, sclk_pin, -1, mosi_pin, 1000000);
103107
}
104108

105109
/*!
106-
@brief Constructor for SPI MonoOLED displays, using native hardware SPI.
110+
@brief Constructor for SPI GrayOLED displays, using native hardware SPI.
111+
@param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
107112
@param w
108113
Display width in pixels
109114
@param h
@@ -127,19 +132,21 @@ Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, int8_t mosi_pin,
127132
@note Call the object's begin() function before use -- buffer
128133
allocation is performed there!
129134
*/
130-
Adafruit_MonoOLED::Adafruit_MonoOLED(uint16_t w, uint16_t h, SPIClass *spi,
131-
int8_t dc_pin, int8_t rst_pin,
132-
int8_t cs_pin, uint32_t bitrate)
133-
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) {
135+
Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h,
136+
SPIClass *spi, int8_t dc_pin,
137+
int8_t rst_pin, int8_t cs_pin,
138+
uint32_t bitrate)
139+
: Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin),
140+
_bpp(bpp) {
134141

135142
spi_dev = new Adafruit_SPIDevice(cs_pin, bitrate, SPI_BITORDER_MSBFIRST,
136143
SPI_MODE0, spi);
137144
}
138145

139146
/*!
140-
@brief Destructor for Adafruit_MonoOLED object.
147+
@brief Destructor for Adafruit_GrayOLED object.
141148
*/
142-
Adafruit_MonoOLED::~Adafruit_MonoOLED(void) {
149+
Adafruit_GrayOLED::~Adafruit_GrayOLED(void) {
143150
if (buffer) {
144151
free(buffer);
145152
buffer = NULL;
@@ -157,7 +164,7 @@ Adafruit_MonoOLED::~Adafruit_MonoOLED(void) {
157164
needed.
158165
@param c The single byte command
159166
*/
160-
void Adafruit_MonoOLED::oled_command(uint8_t c) {
167+
void Adafruit_GrayOLED::oled_command(uint8_t c) {
161168
if (i2c_dev) { // I2C
162169
uint8_t buf[2] = {0x00, c}; // Co = 0, D/C = 0
163170
i2c_dev->write(buf, 2);
@@ -167,7 +174,7 @@ void Adafruit_MonoOLED::oled_command(uint8_t c) {
167174
}
168175
}
169176

170-
// Issue list of commands to MonoOLED
177+
// Issue list of commands to GrayOLED
171178
/*!
172179
@brief Issue multiple bytes of commands OLED, using I2C or hard/soft SPI as
173180
needed.
@@ -176,7 +183,7 @@ void Adafruit_MonoOLED::oled_command(uint8_t c) {
176183
@returns True for success on ability to write the data in I2C.
177184
*/
178185

179-
bool Adafruit_MonoOLED::oled_commandList(const uint8_t *c, uint8_t n) {
186+
bool Adafruit_GrayOLED::oled_commandList(const uint8_t *c, uint8_t n) {
180187
if (i2c_dev) { // I2C
181188
uint8_t dc_byte = 0x00; // Co = 0, D/C = 0
182189
if (!i2c_dev->write((uint8_t *)c, n, true, &dc_byte, 1)) {
@@ -213,10 +220,11 @@ bool Adafruit_MonoOLED::oled_commandList(const uint8_t *c, uint8_t n) {
213220
proceeding.
214221
@note MUST call this function before any drawing or updates!
215222
*/
216-
bool Adafruit_MonoOLED::_init(uint8_t addr, bool reset) {
223+
bool Adafruit_GrayOLED::_init(uint8_t addr, bool reset) {
217224

218225
// attempt to malloc the bitmap framebuffer
219-
if ((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8)))) {
226+
if ((!buffer) &&
227+
!(buffer = (uint8_t *)malloc(_bpp * WIDTH * ((HEIGHT + 7) / 8)))) {
220228
return false;
221229
}
222230

@@ -269,25 +277,24 @@ bool Adafruit_MonoOLED::_init(uint8_t addr, bool reset) {
269277
@param color
270278
Pixel color, one of: MONOOLED_BLACK, MONOOLED_WHITE or
271279
MONOOLED_INVERT.
272-
@return None (void).
273280
@note Changes buffer contents only, no immediate effect on display.
274281
Follow up with a call to display(), or with other graphics
275282
commands as needed by one's own application.
276283
*/
277-
void Adafruit_MonoOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
284+
void Adafruit_GrayOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
278285
if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
279286
// Pixel is in-bounds. Rotate coordinates if needed.
280287
switch (getRotation()) {
281288
case 1:
282-
monooled_swap(x, y);
289+
grayoled_swap(x, y);
283290
x = WIDTH - x - 1;
284291
break;
285292
case 2:
286293
x = WIDTH - x - 1;
287294
y = HEIGHT - y - 1;
288295
break;
289296
case 3:
290-
monooled_swap(x, y);
297+
grayoled_swap(x, y);
291298
y = HEIGHT - y - 1;
292299
break;
293300
}
@@ -298,29 +305,43 @@ void Adafruit_MonoOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
298305
window_x2 = max(window_x2, x);
299306
window_y2 = max(window_y2, y);
300307

301-
switch (color) {
302-
case MONOOLED_WHITE:
303-
buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));
304-
break;
305-
case MONOOLED_BLACK:
306-
buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));
307-
break;
308-
case MONOOLED_INVERSE:
309-
buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));
310-
break;
308+
if (_bpp == 1) {
309+
switch (color) {
310+
case MONOOLED_WHITE:
311+
buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7));
312+
break;
313+
case MONOOLED_BLACK:
314+
buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7));
315+
break;
316+
case MONOOLED_INVERSE:
317+
buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7));
318+
break;
319+
}
320+
}
321+
if (_bpp == 4) {
322+
uint8_t *pixelptr = &buffer[x / 2 + (y * WIDTH / 2)];
323+
// Serial.printf("(%d, %d) -> offset %d\n", x, y, x/2 + (y * WIDTH / 2));
324+
if (x % 2 == 0) { // even, left nibble
325+
uint8_t t = pixelptr[0] & 0x0F;
326+
t |= (color & 0xF) << 4;
327+
pixelptr[0] = t;
328+
} else { // odd, right lower nibble
329+
uint8_t t = pixelptr[0] & 0xF0;
330+
t |= color & 0xF;
331+
pixelptr[0] = t;
332+
}
311333
}
312334
}
313335
}
314336

315337
/*!
316338
@brief Clear contents of display buffer (set all pixels to off).
317-
@return None (void).
318339
@note Changes buffer contents only, no immediate effect on display.
319340
Follow up with a call to display(), or with other graphics
320341
commands as needed by one's own application.
321342
*/
322-
void Adafruit_MonoOLED::clearDisplay(void) {
323-
memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8));
343+
void Adafruit_GrayOLED::clearDisplay(void) {
344+
memset(buffer, 0, _bpp * WIDTH * ((HEIGHT + 7) / 8));
324345
// set max dirty window
325346
window_x1 = 0;
326347
window_y1 = 0;
@@ -339,20 +360,20 @@ void Adafruit_MonoOLED::clearDisplay(void) {
339360
@note Reads from buffer contents; may not reflect current contents of
340361
screen if display() has not been called.
341362
*/
342-
bool Adafruit_MonoOLED::getPixel(int16_t x, int16_t y) {
363+
bool Adafruit_GrayOLED::getPixel(int16_t x, int16_t y) {
343364
if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
344365
// Pixel is in-bounds. Rotate coordinates if needed.
345366
switch (getRotation()) {
346367
case 1:
347-
monooled_swap(x, y);
368+
grayoled_swap(x, y);
348369
x = WIDTH - x - 1;
349370
break;
350371
case 2:
351372
x = WIDTH - x - 1;
352373
y = HEIGHT - y - 1;
353374
break;
354375
case 3:
355-
monooled_swap(x, y);
376+
grayoled_swap(x, y);
356377
y = HEIGHT - y - 1;
357378
break;
358379
}
@@ -366,7 +387,7 @@ bool Adafruit_MonoOLED::getPixel(int16_t x, int16_t y) {
366387
@return Pointer to an unsigned 8-bit array, column-major, columns padded
367388
to full byte boundary if needed.
368389
*/
369-
uint8_t *Adafruit_MonoOLED::getBuffer(void) { return buffer; }
390+
uint8_t *Adafruit_GrayOLED::getBuffer(void) { return buffer; }
370391

371392
// OTHER HARDWARE SETTINGS -------------------------------------------------
372393

@@ -376,26 +397,24 @@ uint8_t *Adafruit_MonoOLED::getBuffer(void) { return buffer; }
376397
@param i
377398
If true, switch to invert mode (black-on-white), else normal
378399
mode (white-on-black).
379-
@return None (void).
380400
@note This has an immediate effect on the display, no need to call the
381401
display() function -- buffer contents are not changed, rather a
382402
different pixel mode of the display hardware is used. When
383403
enabled, drawing MONOOLED_BLACK (value 0) pixels will actually draw
384404
white, MONOOLED_WHITE (value 1) will draw black.
385405
*/
386-
void Adafruit_MonoOLED::invertDisplay(bool i) {
387-
oled_command(i ? MONOOLED_INVERTDISPLAY : MONOOLED_NORMALDISPLAY);
406+
void Adafruit_GrayOLED::invertDisplay(bool i) {
407+
oled_command(i ? GRAYOLED_INVERTDISPLAY : GRAYOLED_NORMALDISPLAY);
388408
}
389409

390410
/*!
391411
@brief Adjust the display contrast.
392412
@param level The contrast level from 0 to 0x7F
393-
@return None (void).
394413
@note This has an immediate effect on the display, no need to call the
395414
display() function -- buffer contents are not changed.
396415
*/
397-
void Adafruit_MonoOLED::setContrast(uint8_t level) {
398-
uint8_t cmd[] = {MONOOLED_SETCONTRAST, level};
416+
void Adafruit_GrayOLED::setContrast(uint8_t level) {
417+
uint8_t cmd[] = {GRAYOLED_SETCONTRAST, level};
399418
oled_commandList(cmd, 2);
400419
}
401420

Adafruit_MonoOLED.h renamed to Adafruit_GrayOLED.h

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*!
2-
* @file Adafruit_MonoOLED.h
2+
* @file Adafruit_GrayOLED.h
33
*
44
* This is part of for Adafruit's GFX library, supplying generic support
5-
* for monochrome OLED displays: http://www.adafruit.com/category/63_98
5+
* for grayscale OLED displays: http://www.adafruit.com/category/63_98
66
*
77
* These displays use I2C or SPI to communicate. I2C requires 2 pins
88
* (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
@@ -21,8 +21,8 @@
2121
*
2222
*/
2323

24-
#ifndef _Adafruit_MONOOLED_H_
25-
#define _Adafruit_MONOOLED_H_
24+
#ifndef _Adafruit_GRAYOLED_H_
25+
#define _Adafruit_GRAYOLED_H_
2626

2727
#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
2828

@@ -32,33 +32,31 @@
3232
#include <SPI.h>
3333
#include <Wire.h>
3434

35-
#define MONOOLED_BLACK 0 ///< Draw 'off' pixels
36-
#define MONOOLED_WHITE 1 ///< Draw 'on' pixels
37-
#define MONOOLED_INVERSE 2 ///< Invert pixels
35+
#define GRAYOLED_SETCONTRAST 0x81 ///< Generic contrast for almost all OLEDs
36+
#define GRAYOLED_NORMALDISPLAY 0xA6 ///< Generic non-invert for almost all OLEDs
37+
#define GRAYOLED_INVERTDISPLAY 0xA7 ///< Generic invert for almost all OLEDs
3838

39-
/// These seem to be common commands for OLEDs
40-
#define MONOOLED_SETCONTRAST 0x81 ///< See datasheet
41-
#define MONOOLED_NORMALDISPLAY 0xA6 ///< See datasheet
42-
#define MONOOLED_INVERTDISPLAY 0xA7 ///< See datasheet
43-
#define MONOOLED_DISPLAYOFF 0xAE ///< See datasheet
44-
#define MONOOLED_DISPLAYON 0xAF ///< See datasheet
39+
#define MONOOLED_BLACK 0 ///< Default black 'color' for monochrome OLEDS
40+
#define MONOOLED_WHITE 1 ///< Default white 'color' for monochrome OLEDS
41+
#define MONOOLED_INVERSE 2 ///< Default inversion command for monochrome OLEDS
4542

4643
/*!
4744
@brief Class that stores state and functions for interacting with
48-
generic monochrome OLED displays.
45+
generic grayscale OLED displays.
4946
*/
50-
class Adafruit_MonoOLED : public Adafruit_GFX {
47+
class Adafruit_GrayOLED : public Adafruit_GFX {
5148
public:
52-
Adafruit_MonoOLED(uint16_t w, uint16_t h, TwoWire *twi = &Wire,
49+
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, TwoWire *twi = &Wire,
5350
int8_t rst_pin = -1, uint32_t preclk = 400000,
5451
uint32_t postclk = 100000);
55-
Adafruit_MonoOLED(uint16_t w, uint16_t h, int8_t mosi_pin, int8_t sclk_pin,
56-
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin);
57-
Adafruit_MonoOLED(uint16_t w, uint16_t h, SPIClass *spi, int8_t dc_pin,
58-
int8_t rst_pin, int8_t cs_pin,
52+
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, int8_t mosi_pin,
53+
int8_t sclk_pin, int8_t dc_pin, int8_t rst_pin,
54+
int8_t cs_pin);
55+
Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, SPIClass *spi,
56+
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin,
5957
uint32_t bitrate = 8000000UL);
6058

61-
~Adafruit_MonoOLED(void);
59+
~Adafruit_GrayOLED(void);
6260

6361
/**
6462
@brief The function that sub-classes define that writes out the buffer to
@@ -93,9 +91,10 @@ class Adafruit_MonoOLED : public Adafruit_GFX {
9391
csPin, ///< The Arduino pin connected to CS (for SPI)
9492
rstPin; ///< The Arduino pin connected to reset (-1 if unused)
9593

94+
uint8_t _bpp = 1; ///< Bits per pixel color for this display
9695
private:
9796
TwoWire *_theWire = NULL; ///< The underlying hardware I2C
9897
};
9998

10099
#endif // end __AVR_ATtiny85__
101-
#endif // _Adafruit_MonoOLED_H_
100+
#endif // _Adafruit_GrayOLED_H_

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Adafruit GFX Library
2-
version=1.9.0
2+
version=1.10.0
33
author=Adafruit
44
maintainer=Adafruit <[email protected]>
55
sentence=Adafruit GFX graphics core library, this is the 'core' class that all our other graphics libraries derive from.

0 commit comments

Comments
 (0)