arduinoprojects

git clone https://git.tarina.org/arduinoprojects
Log | Files | Refs

Adafruit_GrayOLED.cpp (15385B)


      1 /*!
      2  * @file Adafruit_GrayOLED.cpp
      3  *
      4  * This is documentation for Adafruit's generic library for grayscale
      5  * OLED displays: http://www.adafruit.com/category/63_98
      6  *
      7  * These displays use I2C or SPI to communicate. I2C requires 2 pins
      8  * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK,
      9  * select, data/command) and optionally a reset pin. Hardware SPI or
     10  * 'bitbang' software SPI are both supported.
     11  *
     12  * Adafruit invests time and resources providing this open source code,
     13  * please support Adafruit and open-source hardware by purchasing
     14  * products from Adafruit!
     15  *
     16  */
     17 
     18 #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all
     19 
     20 #include "Adafruit_GrayOLED.h"
     21 #include <Adafruit_GFX.h>
     22 
     23 // SOME DEFINES AND STATIC VARIABLES USED INTERNALLY -----------------------
     24 
     25 #define grayoled_swap(a, b)                                                    \
     26   (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation
     27 
     28 // CONSTRUCTORS, DESTRUCTOR ------------------------------------------------
     29 
     30 /*!
     31     @brief  Constructor for I2C-interfaced OLED displays.
     32     @param  bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
     33     @param  w
     34             Display width in pixels
     35     @param  h
     36             Display height in pixels
     37     @param  twi
     38             Pointer to an existing TwoWire instance (e.g. &Wire, the
     39             microcontroller's primary I2C bus).
     40     @param  rst_pin
     41             Reset pin (using Arduino pin numbering), or -1 if not used
     42             (some displays might be wired to share the microcontroller's
     43             reset pin).
     44     @param  clkDuring
     45             Speed (in Hz) for Wire transmissions in library calls.
     46             Defaults to 400000 (400 KHz), a known 'safe' value for most
     47             microcontrollers, and meets the OLED datasheet spec.
     48             Some systems can operate I2C faster (800 KHz for ESP32, 1 MHz
     49             for many other 32-bit MCUs), and some (perhaps not all)
     50             Many OLED's can work with this -- so it's optionally be specified
     51             here and is not a default behavior. (Ignored if using pre-1.5.7
     52             Arduino software, which operates I2C at a fixed 100 KHz.)
     53     @param  clkAfter
     54             Speed (in Hz) for Wire transmissions following library
     55             calls. Defaults to 100000 (100 KHz), the default Arduino Wire
     56             speed. This is done rather than leaving it at the 'during' speed
     57             because other devices on the I2C bus might not be compatible
     58             with the faster rate. (Ignored if using pre-1.5.7 Arduino
     59             software, which operates I2C at a fixed 100 KHz.)
     60     @note   Call the object's begin() function before use -- buffer
     61             allocation is performed there!
     62 */
     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)
     66     : Adafruit_GFX(w, h), i2c_preclk(clkDuring), i2c_postclk(clkAfter),
     67       buffer(NULL), dcPin(-1), csPin(-1), rstPin(rst_pin), _bpp(bpp) {
     68   i2c_dev = NULL;
     69   _theWire = twi;
     70 }
     71 
     72 /*!
     73     @brief  Constructor for SPI GrayOLED displays, using software (bitbang)
     74             SPI.
     75     @param  bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
     76     @param  w
     77             Display width in pixels
     78     @param  h
     79             Display height in pixels
     80     @param  mosi_pin
     81             MOSI (master out, slave in) pin (using Arduino pin numbering).
     82             This transfers serial data from microcontroller to display.
     83     @param  sclk_pin
     84             SCLK (serial clock) pin (using Arduino pin numbering).
     85             This clocks each bit from MOSI.
     86     @param  dc_pin
     87             Data/command pin (using Arduino pin numbering), selects whether
     88             display is receiving commands (low) or data (high).
     89     @param  rst_pin
     90             Reset pin (using Arduino pin numbering), or -1 if not used
     91             (some displays might be wired to share the microcontroller's
     92             reset pin).
     93     @param  cs_pin
     94             Chip-select pin (using Arduino pin numbering) for sharing the
     95             bus with other devices. Active low.
     96     @note   Call the object's begin() function before use -- buffer
     97             allocation is performed there!
     98 */
     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) {
    105 
    106   spi_dev = new Adafruit_SPIDevice(cs_pin, sclk_pin, -1, mosi_pin, 1000000);
    107 }
    108 
    109 /*!
    110     @brief  Constructor for SPI GrayOLED displays, using native hardware SPI.
    111     @param  bpp Bits per pixel, 1 for monochrome, 4 for 16-gray
    112     @param  w
    113             Display width in pixels
    114     @param  h
    115             Display height in pixels
    116     @param  spi
    117             Pointer to an existing SPIClass instance (e.g. &SPI, the
    118             microcontroller's primary SPI bus).
    119     @param  dc_pin
    120             Data/command pin (using Arduino pin numbering), selects whether
    121             display is receiving commands (low) or data (high).
    122     @param  rst_pin
    123             Reset pin (using Arduino pin numbering), or -1 if not used
    124             (some displays might be wired to share the microcontroller's
    125             reset pin).
    126     @param  cs_pin
    127             Chip-select pin (using Arduino pin numbering) for sharing the
    128             bus with other devices. Active low.
    129     @param  bitrate
    130             SPI clock rate for transfers to this display. Default if
    131             unspecified is 8000000UL (8 MHz).
    132     @note   Call the object's begin() function before use -- buffer
    133             allocation is performed there!
    134 */
    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) {
    141 
    142   spi_dev = new Adafruit_SPIDevice(cs_pin, bitrate, SPI_BITORDER_MSBFIRST,
    143                                    SPI_MODE0, spi);
    144 }
    145 
    146 /*!
    147     @brief  Destructor for Adafruit_GrayOLED object.
    148 */
    149 Adafruit_GrayOLED::~Adafruit_GrayOLED(void) {
    150   if (buffer) {
    151     free(buffer);
    152     buffer = NULL;
    153   }
    154   if (spi_dev)
    155     delete spi_dev;
    156   if (i2c_dev)
    157     delete i2c_dev;
    158 }
    159 
    160 // LOW-LEVEL UTILS ---------------------------------------------------------
    161 
    162 /*!
    163     @brief Issue single command byte to OLED, using I2C or hard/soft SPI as
    164    needed.
    165     @param c The single byte command
    166 */
    167 void Adafruit_GrayOLED::oled_command(uint8_t c) {
    168   if (i2c_dev) {                // I2C
    169     uint8_t buf[2] = {0x00, c}; // Co = 0, D/C = 0
    170     i2c_dev->write(buf, 2);
    171   } else { // SPI (hw or soft) -- transaction started in calling function
    172     digitalWrite(dcPin, LOW);
    173     spi_dev->write(&c, 1);
    174   }
    175 }
    176 
    177 // Issue list of commands to GrayOLED
    178 /*!
    179     @brief Issue multiple bytes of commands OLED, using I2C or hard/soft SPI as
    180    needed.
    181     @param c Pointer to the command array
    182     @param n The number of bytes in the command array
    183     @returns True for success on ability to write the data in I2C.
    184 */
    185 
    186 bool Adafruit_GrayOLED::oled_commandList(const uint8_t *c, uint8_t n) {
    187   if (i2c_dev) {            // I2C
    188     uint8_t dc_byte = 0x00; // Co = 0, D/C = 0
    189     if (!i2c_dev->write((uint8_t *)c, n, true, &dc_byte, 1)) {
    190       return false;
    191     }
    192   } else { // SPI -- transaction started in calling function
    193     digitalWrite(dcPin, LOW);
    194     if (!spi_dev->write((uint8_t *)c, n)) {
    195       return false;
    196     }
    197   }
    198   return true;
    199 }
    200 
    201 // ALLOCATE & INIT DISPLAY -------------------------------------------------
    202 
    203 /*!
    204     @brief  Allocate RAM for image buffer, initialize peripherals and pins.
    205             Note that subclasses must call this before other begin() init
    206     @param  addr
    207             I2C address of corresponding oled display.
    208             SPI displays (hardware or software) do not use addresses, but
    209             this argument is still required. Default if unspecified is 0x3C.
    210     @param  reset
    211             If true, and if the reset pin passed to the constructor is
    212             valid, a hard reset will be performed before initializing the
    213             display. If using multiple oled displays on the same bus, and
    214             if they all share the same reset pin, you should only pass true
    215             on the first display being initialized, false on all others,
    216             else the already-initialized displays would be reset. Default if
    217             unspecified is true.
    218     @return true on successful allocation/init, false otherwise.
    219             Well-behaved code should check the return value before
    220             proceeding.
    221     @note   MUST call this function before any drawing or updates!
    222 */
    223 bool Adafruit_GrayOLED::_init(uint8_t addr, bool reset) {
    224 
    225   // attempt to malloc the bitmap framebuffer
    226   if ((!buffer) &&
    227       !(buffer = (uint8_t *)malloc(_bpp * WIDTH * ((HEIGHT + 7) / 8)))) {
    228     return false;
    229   }
    230 
    231   // Reset OLED if requested and reset pin specified in constructor
    232   if (reset && (rstPin >= 0)) {
    233     pinMode(rstPin, OUTPUT);
    234     digitalWrite(rstPin, HIGH);
    235     delay(10);                  // VDD goes high at start, pause
    236     digitalWrite(rstPin, LOW);  // Bring reset low
    237     delay(10);                  // Wait 10 ms
    238     digitalWrite(rstPin, HIGH); // Bring out of reset
    239     delay(10);
    240   }
    241 
    242   // Setup pin directions
    243   if (_theWire) { // using I2C
    244     i2c_dev = new Adafruit_I2CDevice(addr, _theWire);
    245     // look for i2c address:
    246     if (!i2c_dev || !i2c_dev->begin()) {
    247       return false;
    248     }
    249   } else { // Using one of the SPI modes, either soft or hardware
    250     if (!spi_dev || !spi_dev->begin()) {
    251       return false;
    252     }
    253     pinMode(dcPin, OUTPUT); // Set data/command pin as output
    254   }
    255 
    256   clearDisplay();
    257 
    258   // set max dirty window
    259   window_x1 = 0;
    260   window_y1 = 0;
    261   window_x2 = WIDTH - 1;
    262   window_y2 = HEIGHT - 1;
    263 
    264   return true; // Success
    265 }
    266 
    267 // DRAWING FUNCTIONS -------------------------------------------------------
    268 
    269 /*!
    270     @brief  Set/clear/invert a single pixel. This is also invoked by the
    271             Adafruit_GFX library in generating many higher-level graphics
    272             primitives.
    273     @param  x
    274             Column of display -- 0 at left to (screen width - 1) at right.
    275     @param  y
    276             Row of display -- 0 at top to (screen height -1) at bottom.
    277     @param  color
    278             Pixel color, one of: MONOOLED_BLACK, MONOOLED_WHITE or
    279    MONOOLED_INVERT.
    280     @note   Changes buffer contents only, no immediate effect on display.
    281             Follow up with a call to display(), or with other graphics
    282             commands as needed by one's own application.
    283 */
    284 void Adafruit_GrayOLED::drawPixel(int16_t x, int16_t y, uint16_t color) {
    285   if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
    286     // Pixel is in-bounds. Rotate coordinates if needed.
    287     switch (getRotation()) {
    288     case 1:
    289       grayoled_swap(x, y);
    290       x = WIDTH - x - 1;
    291       break;
    292     case 2:
    293       x = WIDTH - x - 1;
    294       y = HEIGHT - y - 1;
    295       break;
    296     case 3:
    297       grayoled_swap(x, y);
    298       y = HEIGHT - y - 1;
    299       break;
    300     }
    301 
    302     // adjust dirty window
    303     window_x1 = min(window_x1, x);
    304     window_y1 = min(window_y1, y);
    305     window_x2 = max(window_x2, x);
    306     window_y2 = max(window_y2, y);
    307 
    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       }
    333     }
    334   }
    335 }
    336 
    337 /*!
    338     @brief  Clear contents of display buffer (set all pixels to off).
    339     @note   Changes buffer contents only, no immediate effect on display.
    340             Follow up with a call to display(), or with other graphics
    341             commands as needed by one's own application.
    342 */
    343 void Adafruit_GrayOLED::clearDisplay(void) {
    344   memset(buffer, 0, _bpp * WIDTH * ((HEIGHT + 7) / 8));
    345   // set max dirty window
    346   window_x1 = 0;
    347   window_y1 = 0;
    348   window_x2 = WIDTH - 1;
    349   window_y2 = HEIGHT - 1;
    350 }
    351 
    352 /*!
    353     @brief  Return color of a single pixel in display buffer.
    354     @param  x
    355             Column of display -- 0 at left to (screen width - 1) at right.
    356     @param  y
    357             Row of display -- 0 at top to (screen height -1) at bottom.
    358     @return true if pixel is set (usually MONOOLED_WHITE, unless display invert
    359    mode is enabled), false if clear (MONOOLED_BLACK).
    360     @note   Reads from buffer contents; may not reflect current contents of
    361             screen if display() has not been called.
    362 */
    363 bool Adafruit_GrayOLED::getPixel(int16_t x, int16_t y) {
    364   if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
    365     // Pixel is in-bounds. Rotate coordinates if needed.
    366     switch (getRotation()) {
    367     case 1:
    368       grayoled_swap(x, y);
    369       x = WIDTH - x - 1;
    370       break;
    371     case 2:
    372       x = WIDTH - x - 1;
    373       y = HEIGHT - y - 1;
    374       break;
    375     case 3:
    376       grayoled_swap(x, y);
    377       y = HEIGHT - y - 1;
    378       break;
    379     }
    380     return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
    381   }
    382   return false; // Pixel out of bounds
    383 }
    384 
    385 /*!
    386     @brief  Get base address of display buffer for direct reading or writing.
    387     @return Pointer to an unsigned 8-bit array, column-major, columns padded
    388             to full byte boundary if needed.
    389 */
    390 uint8_t *Adafruit_GrayOLED::getBuffer(void) { return buffer; }
    391 
    392 // OTHER HARDWARE SETTINGS -------------------------------------------------
    393 
    394 /*!
    395     @brief  Enable or disable display invert mode (white-on-black vs
    396             black-on-white). Handy for testing!
    397     @param  i
    398             If true, switch to invert mode (black-on-white), else normal
    399             mode (white-on-black).
    400     @note   This has an immediate effect on the display, no need to call the
    401             display() function -- buffer contents are not changed, rather a
    402             different pixel mode of the display hardware is used. When
    403             enabled, drawing MONOOLED_BLACK (value 0) pixels will actually draw
    404    white, MONOOLED_WHITE (value 1) will draw black.
    405 */
    406 void Adafruit_GrayOLED::invertDisplay(bool i) {
    407   oled_command(i ? GRAYOLED_INVERTDISPLAY : GRAYOLED_NORMALDISPLAY);
    408 }
    409 
    410 /*!
    411     @brief  Adjust the display contrast.
    412     @param  level The contrast level from 0 to 0x7F
    413     @note   This has an immediate effect on the display, no need to call the
    414             display() function -- buffer contents are not changed.
    415 */
    416 void Adafruit_GrayOLED::setContrast(uint8_t level) {
    417   uint8_t cmd[] = {GRAYOLED_SETCONTRAST, level};
    418   oled_commandList(cmd, 2);
    419 }
    420 
    421 #endif /* ATTIN85 not supported */