Adafruit_SSD1306.cpp (42599B)
1 /*! 2 * @file Adafruit_SSD1306.cpp 3 * 4 * @mainpage Arduino library for monochrome OLEDs based on SSD1306 drivers. 5 * 6 * @section intro_sec Introduction 7 * 8 * This is documentation for Adafruit's SSD1306 library for monochrome 9 * OLED displays: http://www.adafruit.com/category/63_98 10 * 11 * These displays use I2C or SPI to communicate. I2C requires 2 pins 12 * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK, 13 * select, data/command) and optionally a reset pin. Hardware SPI or 14 * 'bitbang' software SPI are both supported. 15 * 16 * Adafruit invests time and resources providing this open source code, 17 * please support Adafruit and open-source hardware by purchasing 18 * products from Adafruit! 19 * 20 * @section dependencies Dependencies 21 * 22 * This library depends on <a 23 * href="https://github.com/adafruit/Adafruit-GFX-Library"> Adafruit_GFX</a> 24 * being present on your system. Please make sure you have installed the latest 25 * version before using this library. 26 * 27 * @section author Author 28 * 29 * Written by Limor Fried/Ladyada for Adafruit Industries, with 30 * contributions from the open source community. 31 * 32 * @section license License 33 * 34 * BSD license, all text above, and the splash screen included below, 35 * must be included in any redistribution. 36 * 37 */ 38 39 #ifdef __AVR__ 40 #include <avr/pgmspace.h> 41 #elif defined(ESP8266) || defined(ESP32) 42 #include <pgmspace.h> 43 #else 44 #define pgm_read_byte(addr) \ 45 (*(const unsigned char *)(addr)) ///< PROGMEM workaround for non-AVR 46 #endif 47 48 #if !defined(__ARM_ARCH) && !defined(ENERGIA) && !defined(ESP8266) && \ 49 !defined(ESP32) && !defined(__arc__) 50 #include <util/delay.h> 51 #endif 52 53 #include "Adafruit_SSD1306.h" 54 #include "splash.h" 55 #include <Adafruit_GFX.h> 56 57 // SOME DEFINES AND STATIC VARIABLES USED INTERNALLY ----------------------- 58 59 #if defined(I2C_BUFFER_LENGTH) 60 #define WIRE_MAX min(256, I2C_BUFFER_LENGTH) ///< Particle or similar Wire lib 61 #elif defined(BUFFER_LENGTH) 62 #define WIRE_MAX min(256, BUFFER_LENGTH) ///< AVR or similar Wire lib 63 #elif defined(SERIAL_BUFFER_SIZE) 64 #define WIRE_MAX \ 65 min(255, SERIAL_BUFFER_SIZE - 1) ///< Newer Wire uses RingBuffer 66 #else 67 #define WIRE_MAX 32 ///< Use common Arduino core default 68 #endif 69 70 #define ssd1306_swap(a, b) \ 71 (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation 72 73 #if ARDUINO >= 100 74 #define WIRE_WRITE wire->write ///< Wire write function in recent Arduino lib 75 #else 76 #define WIRE_WRITE wire->send ///< Wire write function in older Arduino lib 77 #endif 78 79 #ifdef HAVE_PORTREG 80 #define SSD1306_SELECT *csPort &= ~csPinMask; ///< Device select 81 #define SSD1306_DESELECT *csPort |= csPinMask; ///< Device deselect 82 #define SSD1306_MODE_COMMAND *dcPort &= ~dcPinMask; ///< Command mode 83 #define SSD1306_MODE_DATA *dcPort |= dcPinMask; ///< Data mode 84 #else 85 #define SSD1306_SELECT digitalWrite(csPin, LOW); ///< Device select 86 #define SSD1306_DESELECT digitalWrite(csPin, HIGH); ///< Device deselect 87 #define SSD1306_MODE_COMMAND digitalWrite(dcPin, LOW); ///< Command mode 88 #define SSD1306_MODE_DATA digitalWrite(dcPin, HIGH); ///< Data mode 89 #endif 90 91 #if (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) 92 #define SETWIRECLOCK wire->setClock(wireClk) ///< Set before I2C transfer 93 #define RESWIRECLOCK wire->setClock(restoreClk) ///< Restore after I2C xfer 94 #else // setClock() is not present in older Arduino Wire lib (or WICED) 95 #define SETWIRECLOCK ///< Dummy stand-in define 96 #define RESWIRECLOCK ///< keeps compiler happy 97 #endif 98 99 #if defined(SPI_HAS_TRANSACTION) 100 #define SPI_TRANSACTION_START spi->beginTransaction(spiSettings) ///< Pre-SPI 101 #define SPI_TRANSACTION_END spi->endTransaction() ///< Post-SPI 102 #else // SPI transactions likewise not present in older Arduino SPI lib 103 #define SPI_TRANSACTION_START ///< Dummy stand-in define 104 #define SPI_TRANSACTION_END ///< keeps compiler happy 105 #endif 106 107 // The definition of 'transaction' is broadened a bit in the context of 108 // this library -- referring not just to SPI transactions (if supported 109 // in the version of the SPI library being used), but also chip select 110 // (if SPI is being used, whether hardware or soft), and also to the 111 // beginning and end of I2C transfers (the Wire clock may be sped up before 112 // issuing data to the display, then restored to the default rate afterward 113 // so other I2C device types still work). All of these are encapsulated 114 // in the TRANSACTION_* macros. 115 116 // Check first if Wire, then hardware SPI, then soft SPI: 117 #define TRANSACTION_START \ 118 if (wire) { \ 119 SETWIRECLOCK; \ 120 } else { \ 121 if (spi) { \ 122 SPI_TRANSACTION_START; \ 123 } \ 124 SSD1306_SELECT; \ 125 } ///< Wire, SPI or bitbang transfer setup 126 #define TRANSACTION_END \ 127 if (wire) { \ 128 RESWIRECLOCK; \ 129 } else { \ 130 SSD1306_DESELECT; \ 131 if (spi) { \ 132 SPI_TRANSACTION_END; \ 133 } \ 134 } ///< Wire, SPI or bitbang transfer end 135 136 // CONSTRUCTORS, DESTRUCTOR ------------------------------------------------ 137 138 /*! 139 @brief Constructor for I2C-interfaced SSD1306 displays. 140 @param w 141 Display width in pixels 142 @param h 143 Display height in pixels 144 @param twi 145 Pointer to an existing TwoWire instance (e.g. &Wire, the 146 microcontroller's primary I2C bus). 147 @param rst_pin 148 Reset pin (using Arduino pin numbering), or -1 if not used 149 (some displays might be wired to share the microcontroller's 150 reset pin). 151 @param clkDuring 152 Speed (in Hz) for Wire transmissions in SSD1306 library calls. 153 Defaults to 400000 (400 KHz), a known 'safe' value for most 154 microcontrollers, and meets the SSD1306 datasheet spec. 155 Some systems can operate I2C faster (800 KHz for ESP32, 1 MHz 156 for many other 32-bit MCUs), and some (perhaps not all) 157 SSD1306's can work with this -- so it's optionally be specified 158 here and is not a default behavior. (Ignored if using pre-1.5.7 159 Arduino software, which operates I2C at a fixed 100 KHz.) 160 @param clkAfter 161 Speed (in Hz) for Wire transmissions following SSD1306 library 162 calls. Defaults to 100000 (100 KHz), the default Arduino Wire 163 speed. This is done rather than leaving it at the 'during' speed 164 because other devices on the I2C bus might not be compatible 165 with the faster rate. (Ignored if using pre-1.5.7 Arduino 166 software, which operates I2C at a fixed 100 KHz.) 167 @return Adafruit_SSD1306 object. 168 @note Call the object's begin() function before use -- buffer 169 allocation is performed there! 170 */ 171 Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, TwoWire *twi, 172 int8_t rst_pin, uint32_t clkDuring, 173 uint32_t clkAfter) 174 : Adafruit_GFX(w, h), spi(NULL), wire(twi ? twi : &Wire), buffer(NULL), 175 mosiPin(-1), clkPin(-1), dcPin(-1), csPin(-1), rstPin(rst_pin) 176 #if ARDUINO >= 157 177 , 178 wireClk(clkDuring), restoreClk(clkAfter) 179 #endif 180 { 181 } 182 183 /*! 184 @brief Constructor for SPI SSD1306 displays, using software (bitbang) 185 SPI. 186 @param w 187 Display width in pixels 188 @param h 189 Display height in pixels 190 @param mosi_pin 191 MOSI (master out, slave in) pin (using Arduino pin numbering). 192 This transfers serial data from microcontroller to display. 193 @param sclk_pin 194 SCLK (serial clock) pin (using Arduino pin numbering). 195 This clocks each bit from MOSI. 196 @param dc_pin 197 Data/command pin (using Arduino pin numbering), selects whether 198 display is receiving commands (low) or data (high). 199 @param rst_pin 200 Reset pin (using Arduino pin numbering), or -1 if not used 201 (some displays might be wired to share the microcontroller's 202 reset pin). 203 @param cs_pin 204 Chip-select pin (using Arduino pin numbering) for sharing the 205 bus with other devices. Active low. 206 @return Adafruit_SSD1306 object. 207 @note Call the object's begin() function before use -- buffer 208 allocation is performed there! 209 */ 210 Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, int8_t mosi_pin, 211 int8_t sclk_pin, int8_t dc_pin, 212 int8_t rst_pin, int8_t cs_pin) 213 : Adafruit_GFX(w, h), spi(NULL), wire(NULL), buffer(NULL), 214 mosiPin(mosi_pin), clkPin(sclk_pin), dcPin(dc_pin), csPin(cs_pin), 215 rstPin(rst_pin) {} 216 217 /*! 218 @brief Constructor for SPI SSD1306 displays, using native hardware SPI. 219 @param w 220 Display width in pixels 221 @param h 222 Display height in pixels 223 @param spi 224 Pointer to an existing SPIClass instance (e.g. &SPI, the 225 microcontroller's primary SPI bus). 226 @param dc_pin 227 Data/command pin (using Arduino pin numbering), selects whether 228 display is receiving commands (low) or data (high). 229 @param rst_pin 230 Reset pin (using Arduino pin numbering), or -1 if not used 231 (some displays might be wired to share the microcontroller's 232 reset pin). 233 @param cs_pin 234 Chip-select pin (using Arduino pin numbering) for sharing the 235 bus with other devices. Active low. 236 @param bitrate 237 SPI clock rate for transfers to this display. Default if 238 unspecified is 8000000UL (8 MHz). 239 @return Adafruit_SSD1306 object. 240 @note Call the object's begin() function before use -- buffer 241 allocation is performed there! 242 */ 243 Adafruit_SSD1306::Adafruit_SSD1306(uint8_t w, uint8_t h, SPIClass *spi, 244 int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, 245 uint32_t bitrate) 246 : Adafruit_GFX(w, h), spi(spi ? spi : &SPI), wire(NULL), buffer(NULL), 247 mosiPin(-1), clkPin(-1), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) { 248 #ifdef SPI_HAS_TRANSACTION 249 spiSettings = SPISettings(bitrate, MSBFIRST, SPI_MODE0); 250 #endif 251 } 252 253 /*! 254 @brief DEPRECATED constructor for SPI SSD1306 displays, using software 255 (bitbang) SPI. Provided for older code to maintain compatibility 256 with the current library. Screen size is determined by enabling 257 one of the SSD1306_* size defines in Adafruit_SSD1306.h. New 258 code should NOT use this. 259 @param mosi_pin 260 MOSI (master out, slave in) pin (using Arduino pin numbering). 261 This transfers serial data from microcontroller to display. 262 @param sclk_pin 263 SCLK (serial clock) pin (using Arduino pin numbering). 264 This clocks each bit from MOSI. 265 @param dc_pin 266 Data/command pin (using Arduino pin numbering), selects whether 267 display is receiving commands (low) or data (high). 268 @param rst_pin 269 Reset pin (using Arduino pin numbering), or -1 if not used 270 (some displays might be wired to share the microcontroller's 271 reset pin). 272 @param cs_pin 273 Chip-select pin (using Arduino pin numbering) for sharing the 274 bus with other devices. Active low. 275 @return Adafruit_SSD1306 object. 276 @note Call the object's begin() function before use -- buffer 277 allocation is performed there! 278 */ 279 Adafruit_SSD1306::Adafruit_SSD1306(int8_t mosi_pin, int8_t sclk_pin, 280 int8_t dc_pin, int8_t rst_pin, int8_t cs_pin) 281 : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), spi(NULL), wire(NULL), 282 buffer(NULL), mosiPin(mosi_pin), clkPin(sclk_pin), dcPin(dc_pin), 283 csPin(cs_pin), rstPin(rst_pin) {} 284 285 /*! 286 @brief DEPRECATED constructor for SPI SSD1306 displays, using native 287 hardware SPI. Provided for older code to maintain compatibility 288 with the current library. Screen size is determined by enabling 289 one of the SSD1306_* size defines in Adafruit_SSD1306.h. New 290 code should NOT use this. Only the primary SPI bus is supported, 291 and bitrate is fixed at 8 MHz. 292 @param dc_pin 293 Data/command pin (using Arduino pin numbering), selects whether 294 display is receiving commands (low) or data (high). 295 @param rst_pin 296 Reset pin (using Arduino pin numbering), or -1 if not used 297 (some displays might be wired to share the microcontroller's 298 reset pin). 299 @param cs_pin 300 Chip-select pin (using Arduino pin numbering) for sharing the 301 bus with other devices. Active low. 302 @return Adafruit_SSD1306 object. 303 @note Call the object's begin() function before use -- buffer 304 allocation is performed there! 305 */ 306 Adafruit_SSD1306::Adafruit_SSD1306(int8_t dc_pin, int8_t rst_pin, int8_t cs_pin) 307 : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), spi(&SPI), wire(NULL), 308 buffer(NULL), mosiPin(-1), clkPin(-1), dcPin(dc_pin), csPin(cs_pin), 309 rstPin(rst_pin) { 310 #ifdef SPI_HAS_TRANSACTION 311 spiSettings = SPISettings(8000000, MSBFIRST, SPI_MODE0); 312 #endif 313 } 314 315 /*! 316 @brief DEPRECATED constructor for I2C SSD1306 displays. Provided for 317 older code to maintain compatibility with the current library. 318 Screen size is determined by enabling one of the SSD1306_* size 319 defines in Adafruit_SSD1306.h. New code should NOT use this. 320 Only the primary I2C bus is supported. 321 @param rst_pin 322 Reset pin (using Arduino pin numbering), or -1 if not used 323 (some displays might be wired to share the microcontroller's 324 reset pin). 325 @return Adafruit_SSD1306 object. 326 @note Call the object's begin() function before use -- buffer 327 allocation is performed there! 328 */ 329 Adafruit_SSD1306::Adafruit_SSD1306(int8_t rst_pin) 330 : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT), spi(NULL), wire(&Wire), 331 buffer(NULL), mosiPin(-1), clkPin(-1), dcPin(-1), csPin(-1), 332 rstPin(rst_pin) {} 333 334 /*! 335 @brief Destructor for Adafruit_SSD1306 object. 336 */ 337 Adafruit_SSD1306::~Adafruit_SSD1306(void) { 338 if (buffer) { 339 free(buffer); 340 buffer = NULL; 341 } 342 } 343 344 // LOW-LEVEL UTILS --------------------------------------------------------- 345 346 // Issue single byte out SPI, either soft or hardware as appropriate. 347 // SPI transaction/selection must be performed in calling function. 348 inline void Adafruit_SSD1306::SPIwrite(uint8_t d) { 349 if (spi) { 350 (void)spi->transfer(d); 351 } else { 352 for (uint8_t bit = 0x80; bit; bit >>= 1) { 353 #ifdef HAVE_PORTREG 354 if (d & bit) 355 *mosiPort |= mosiPinMask; 356 else 357 *mosiPort &= ~mosiPinMask; 358 *clkPort |= clkPinMask; // Clock high 359 *clkPort &= ~clkPinMask; // Clock low 360 #else 361 digitalWrite(mosiPin, d & bit); 362 digitalWrite(clkPin, HIGH); 363 digitalWrite(clkPin, LOW); 364 #endif 365 } 366 } 367 } 368 369 // Issue single command to SSD1306, using I2C or hard/soft SPI as needed. 370 // Because command calls are often grouped, SPI transaction and selection 371 // must be started/ended in calling function for efficiency. 372 // This is a private function, not exposed (see ssd1306_command() instead). 373 void Adafruit_SSD1306::ssd1306_command1(uint8_t c) { 374 if (wire) { // I2C 375 wire->beginTransmission(i2caddr); 376 WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 377 WIRE_WRITE(c); 378 wire->endTransmission(); 379 } else { // SPI (hw or soft) -- transaction started in calling function 380 SSD1306_MODE_COMMAND 381 SPIwrite(c); 382 } 383 } 384 385 // Issue list of commands to SSD1306, same rules as above re: transactions. 386 // This is a private function, not exposed. 387 void Adafruit_SSD1306::ssd1306_commandList(const uint8_t *c, uint8_t n) { 388 if (wire) { // I2C 389 wire->beginTransmission(i2caddr); 390 WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 391 uint16_t bytesOut = 1; 392 while (n--) { 393 if (bytesOut >= WIRE_MAX) { 394 wire->endTransmission(); 395 wire->beginTransmission(i2caddr); 396 WIRE_WRITE((uint8_t)0x00); // Co = 0, D/C = 0 397 bytesOut = 1; 398 } 399 WIRE_WRITE(pgm_read_byte(c++)); 400 bytesOut++; 401 } 402 wire->endTransmission(); 403 } else { // SPI -- transaction started in calling function 404 SSD1306_MODE_COMMAND 405 while (n--) 406 SPIwrite(pgm_read_byte(c++)); 407 } 408 } 409 410 // A public version of ssd1306_command1(), for existing user code that 411 // might rely on that function. This encapsulates the command transfer 412 // in a transaction start/end, similar to old library's handling of it. 413 /*! 414 @brief Issue a single low-level command directly to the SSD1306 415 display, bypassing the library. 416 @param c 417 Command to issue (0x00 to 0xFF, see datasheet). 418 @return None (void). 419 */ 420 void Adafruit_SSD1306::ssd1306_command(uint8_t c) { 421 TRANSACTION_START 422 ssd1306_command1(c); 423 TRANSACTION_END 424 } 425 426 // ALLOCATE & INIT DISPLAY ------------------------------------------------- 427 428 /*! 429 @brief Allocate RAM for image buffer, initialize peripherals and pins. 430 @param vcs 431 VCC selection. Pass SSD1306_SWITCHCAPVCC to generate the display 432 voltage (step up) from the 3.3V source, or SSD1306_EXTERNALVCC 433 otherwise. Most situations with Adafruit SSD1306 breakouts will 434 want SSD1306_SWITCHCAPVCC. 435 @param addr 436 I2C address of corresponding SSD1306 display (or pass 0 to use 437 default of 0x3C for 128x32 display, 0x3D for all others). 438 SPI displays (hardware or software) do not use addresses, but 439 this argument is still required (pass 0 or any value really, 440 it will simply be ignored). Default if unspecified is 0. 441 @param reset 442 If true, and if the reset pin passed to the constructor is 443 valid, a hard reset will be performed before initializing the 444 display. If using multiple SSD1306 displays on the same bus, and 445 if they all share the same reset pin, you should only pass true 446 on the first display being initialized, false on all others, 447 else the already-initialized displays would be reset. Default if 448 unspecified is true. 449 @param periphBegin 450 If true, and if a hardware peripheral is being used (I2C or SPI, 451 but not software SPI), call that peripheral's begin() function, 452 else (false) it has already been done in one's sketch code. 453 Cases where false might be used include multiple displays or 454 other devices sharing a common bus, or situations on some 455 platforms where a nonstandard begin() function is available 456 (e.g. a TwoWire interface on non-default pins, as can be done 457 on the ESP8266 and perhaps others). 458 @return true on successful allocation/init, false otherwise. 459 Well-behaved code should check the return value before 460 proceeding. 461 @note MUST call this function before any drawing or updates! 462 */ 463 bool Adafruit_SSD1306::begin(uint8_t vcs, uint8_t addr, bool reset, 464 bool periphBegin) { 465 466 if ((!buffer) && !(buffer = (uint8_t *)malloc(WIDTH * ((HEIGHT + 7) / 8)))) 467 return false; 468 469 clearDisplay(); 470 if (HEIGHT > 32) { 471 drawBitmap((WIDTH - splash1_width) / 2, (HEIGHT - splash1_height) / 2, 472 splash1_data, splash1_width, splash1_height, 1); 473 } else { 474 drawBitmap((WIDTH - splash2_width) / 2, (HEIGHT - splash2_height) / 2, 475 splash2_data, splash2_width, splash2_height, 1); 476 } 477 478 vccstate = vcs; 479 480 // Setup pin directions 481 if (wire) { // Using I2C 482 // If I2C address is unspecified, use default 483 // (0x3C for 32-pixel-tall displays, 0x3D for all others). 484 i2caddr = addr ? addr : ((HEIGHT == 32) ? 0x3C : 0x3D); 485 // TwoWire begin() function might be already performed by the calling 486 // function if it has unusual circumstances (e.g. TWI variants that 487 // can accept different SDA/SCL pins, or if two SSD1306 instances 488 // with different addresses -- only a single begin() is needed). 489 if (periphBegin) 490 wire->begin(); 491 } else { // Using one of the SPI modes, either soft or hardware 492 pinMode(dcPin, OUTPUT); // Set data/command pin as output 493 pinMode(csPin, OUTPUT); // Same for chip select 494 #ifdef HAVE_PORTREG 495 dcPort = (PortReg *)portOutputRegister(digitalPinToPort(dcPin)); 496 dcPinMask = digitalPinToBitMask(dcPin); 497 csPort = (PortReg *)portOutputRegister(digitalPinToPort(csPin)); 498 csPinMask = digitalPinToBitMask(csPin); 499 #endif 500 SSD1306_DESELECT 501 if (spi) { // Hardware SPI 502 // SPI peripheral begin same as wire check above. 503 if (periphBegin) 504 spi->begin(); 505 } else { // Soft SPI 506 pinMode(mosiPin, OUTPUT); // MOSI and SCLK outputs 507 pinMode(clkPin, OUTPUT); 508 #ifdef HAVE_PORTREG 509 mosiPort = (PortReg *)portOutputRegister(digitalPinToPort(mosiPin)); 510 mosiPinMask = digitalPinToBitMask(mosiPin); 511 clkPort = (PortReg *)portOutputRegister(digitalPinToPort(clkPin)); 512 clkPinMask = digitalPinToBitMask(clkPin); 513 *clkPort &= ~clkPinMask; // Clock low 514 #else 515 digitalWrite(clkPin, LOW); // Clock low 516 #endif 517 } 518 } 519 520 // Reset SSD1306 if requested and reset pin specified in constructor 521 if (reset && (rstPin >= 0)) { 522 pinMode(rstPin, OUTPUT); 523 digitalWrite(rstPin, HIGH); 524 delay(1); // VDD goes high at start, pause for 1 ms 525 digitalWrite(rstPin, LOW); // Bring reset low 526 delay(10); // Wait 10 ms 527 digitalWrite(rstPin, HIGH); // Bring out of reset 528 } 529 530 TRANSACTION_START 531 532 // Init sequence 533 static const uint8_t PROGMEM init1[] = {SSD1306_DISPLAYOFF, // 0xAE 534 SSD1306_SETDISPLAYCLOCKDIV, // 0xD5 535 0x80, // the suggested ratio 0x80 536 SSD1306_SETMULTIPLEX}; // 0xA8 537 ssd1306_commandList(init1, sizeof(init1)); 538 ssd1306_command1(HEIGHT - 1); 539 540 static const uint8_t PROGMEM init2[] = {SSD1306_SETDISPLAYOFFSET, // 0xD3 541 0x0, // no offset 542 SSD1306_SETSTARTLINE | 0x0, // line #0 543 SSD1306_CHARGEPUMP}; // 0x8D 544 ssd1306_commandList(init2, sizeof(init2)); 545 546 ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x10 : 0x14); 547 548 static const uint8_t PROGMEM init3[] = {SSD1306_MEMORYMODE, // 0x20 549 0x00, // 0x0 act like ks0108 550 SSD1306_SEGREMAP | 0x1, 551 SSD1306_COMSCANDEC}; 552 ssd1306_commandList(init3, sizeof(init3)); 553 554 uint8_t comPins = 0x02; 555 contrast = 0x8F; 556 557 if ((WIDTH == 128) && (HEIGHT == 32)) { 558 comPins = 0x02; 559 contrast = 0x8F; 560 } else if ((WIDTH == 128) && (HEIGHT == 64)) { 561 comPins = 0x12; 562 contrast = (vccstate == SSD1306_EXTERNALVCC) ? 0x9F : 0xCF; 563 } else if ((WIDTH == 96) && (HEIGHT == 16)) { 564 comPins = 0x2; // ada x12 565 contrast = (vccstate == SSD1306_EXTERNALVCC) ? 0x10 : 0xAF; 566 } else { 567 // Other screen varieties -- TBD 568 } 569 570 ssd1306_command1(SSD1306_SETCOMPINS); 571 ssd1306_command1(comPins); 572 ssd1306_command1(SSD1306_SETCONTRAST); 573 ssd1306_command1(contrast); 574 575 ssd1306_command1(SSD1306_SETPRECHARGE); // 0xd9 576 ssd1306_command1((vccstate == SSD1306_EXTERNALVCC) ? 0x22 : 0xF1); 577 static const uint8_t PROGMEM init5[] = { 578 SSD1306_SETVCOMDETECT, // 0xDB 579 0x40, 580 SSD1306_DISPLAYALLON_RESUME, // 0xA4 581 SSD1306_NORMALDISPLAY, // 0xA6 582 SSD1306_DEACTIVATE_SCROLL, 583 SSD1306_DISPLAYON}; // Main screen turn on 584 ssd1306_commandList(init5, sizeof(init5)); 585 586 TRANSACTION_END 587 588 return true; // Success 589 } 590 591 // DRAWING FUNCTIONS ------------------------------------------------------- 592 593 /*! 594 @brief Set/clear/invert a single pixel. This is also invoked by the 595 Adafruit_GFX library in generating many higher-level graphics 596 primitives. 597 @param x 598 Column of display -- 0 at left to (screen width - 1) at right. 599 @param y 600 Row of display -- 0 at top to (screen height -1) at bottom. 601 @param color 602 Pixel color, one of: SSD1306_BLACK, SSD1306_WHITE or SSD1306_INVERT. 603 @return None (void). 604 @note Changes buffer contents only, no immediate effect on display. 605 Follow up with a call to display(), or with other graphics 606 commands as needed by one's own application. 607 */ 608 void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { 609 if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { 610 // Pixel is in-bounds. Rotate coordinates if needed. 611 switch (getRotation()) { 612 case 1: 613 ssd1306_swap(x, y); 614 x = WIDTH - x - 1; 615 break; 616 case 2: 617 x = WIDTH - x - 1; 618 y = HEIGHT - y - 1; 619 break; 620 case 3: 621 ssd1306_swap(x, y); 622 y = HEIGHT - y - 1; 623 break; 624 } 625 switch (color) { 626 case SSD1306_WHITE: 627 buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7)); 628 break; 629 case SSD1306_BLACK: 630 buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7)); 631 break; 632 case SSD1306_INVERSE: 633 buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7)); 634 break; 635 } 636 } 637 } 638 639 /*! 640 @brief Clear contents of display buffer (set all pixels to off). 641 @return None (void). 642 @note Changes buffer contents only, no immediate effect on display. 643 Follow up with a call to display(), or with other graphics 644 commands as needed by one's own application. 645 */ 646 void Adafruit_SSD1306::clearDisplay(void) { 647 memset(buffer, 0, WIDTH * ((HEIGHT + 7) / 8)); 648 } 649 650 /*! 651 @brief Draw a horizontal line. This is also invoked by the Adafruit_GFX 652 library in generating many higher-level graphics primitives. 653 @param x 654 Leftmost column -- 0 at left to (screen width - 1) at right. 655 @param y 656 Row of display -- 0 at top to (screen height -1) at bottom. 657 @param w 658 Width of line, in pixels. 659 @param color 660 Line color, one of: SSD1306_BLACK, SSD1306_WHITE or SSD1306_INVERT. 661 @return None (void). 662 @note Changes buffer contents only, no immediate effect on display. 663 Follow up with a call to display(), or with other graphics 664 commands as needed by one's own application. 665 */ 666 void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, 667 uint16_t color) { 668 bool bSwap = false; 669 switch (rotation) { 670 case 1: 671 // 90 degree rotation, swap x & y for rotation, then invert x 672 bSwap = true; 673 ssd1306_swap(x, y); 674 x = WIDTH - x - 1; 675 break; 676 case 2: 677 // 180 degree rotation, invert x and y, then shift y around for height. 678 x = WIDTH - x - 1; 679 y = HEIGHT - y - 1; 680 x -= (w - 1); 681 break; 682 case 3: 683 // 270 degree rotation, swap x & y for rotation, 684 // then invert y and adjust y for w (not to become h) 685 bSwap = true; 686 ssd1306_swap(x, y); 687 y = HEIGHT - y - 1; 688 y -= (w - 1); 689 break; 690 } 691 692 if (bSwap) 693 drawFastVLineInternal(x, y, w, color); 694 else 695 drawFastHLineInternal(x, y, w, color); 696 } 697 698 void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, 699 uint16_t color) { 700 701 if ((y >= 0) && (y < HEIGHT)) { // Y coord in bounds? 702 if (x < 0) { // Clip left 703 w += x; 704 x = 0; 705 } 706 if ((x + w) > WIDTH) { // Clip right 707 w = (WIDTH - x); 708 } 709 if (w > 0) { // Proceed only if width is positive 710 uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x], mask = 1 << (y & 7); 711 switch (color) { 712 case SSD1306_WHITE: 713 while (w--) { 714 *pBuf++ |= mask; 715 }; 716 break; 717 case SSD1306_BLACK: 718 mask = ~mask; 719 while (w--) { 720 *pBuf++ &= mask; 721 }; 722 break; 723 case SSD1306_INVERSE: 724 while (w--) { 725 *pBuf++ ^= mask; 726 }; 727 break; 728 } 729 } 730 } 731 } 732 733 /*! 734 @brief Draw a vertical line. This is also invoked by the Adafruit_GFX 735 library in generating many higher-level graphics primitives. 736 @param x 737 Column of display -- 0 at left to (screen width -1) at right. 738 @param y 739 Topmost row -- 0 at top to (screen height - 1) at bottom. 740 @param h 741 Height of line, in pixels. 742 @param color 743 Line color, one of: SSD1306_BLACK, SSD1306_WHITE or SSD1306_INVERT. 744 @return None (void). 745 @note Changes buffer contents only, no immediate effect on display. 746 Follow up with a call to display(), or with other graphics 747 commands as needed by one's own application. 748 */ 749 void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, 750 uint16_t color) { 751 bool bSwap = false; 752 switch (rotation) { 753 case 1: 754 // 90 degree rotation, swap x & y for rotation, 755 // then invert x and adjust x for h (now to become w) 756 bSwap = true; 757 ssd1306_swap(x, y); 758 x = WIDTH - x - 1; 759 x -= (h - 1); 760 break; 761 case 2: 762 // 180 degree rotation, invert x and y, then shift y around for height. 763 x = WIDTH - x - 1; 764 y = HEIGHT - y - 1; 765 y -= (h - 1); 766 break; 767 case 3: 768 // 270 degree rotation, swap x & y for rotation, then invert y 769 bSwap = true; 770 ssd1306_swap(x, y); 771 y = HEIGHT - y - 1; 772 break; 773 } 774 775 if (bSwap) 776 drawFastHLineInternal(x, y, h, color); 777 else 778 drawFastVLineInternal(x, y, h, color); 779 } 780 781 void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, 782 int16_t __h, uint16_t color) { 783 784 if ((x >= 0) && (x < WIDTH)) { // X coord in bounds? 785 if (__y < 0) { // Clip top 786 __h += __y; 787 __y = 0; 788 } 789 if ((__y + __h) > HEIGHT) { // Clip bottom 790 __h = (HEIGHT - __y); 791 } 792 if (__h > 0) { // Proceed only if height is now positive 793 // this display doesn't need ints for coordinates, 794 // use local byte registers for faster juggling 795 uint8_t y = __y, h = __h; 796 uint8_t *pBuf = &buffer[(y / 8) * WIDTH + x]; 797 798 // do the first partial byte, if necessary - this requires some masking 799 uint8_t mod = (y & 7); 800 if (mod) { 801 // mask off the high n bits we want to set 802 mod = 8 - mod; 803 // note - lookup table results in a nearly 10% performance 804 // improvement in fill* functions 805 // uint8_t mask = ~(0xFF >> mod); 806 static const uint8_t PROGMEM premask[8] = {0x00, 0x80, 0xC0, 0xE0, 807 0xF0, 0xF8, 0xFC, 0xFE}; 808 uint8_t mask = pgm_read_byte(&premask[mod]); 809 // adjust the mask if we're not going to reach the end of this byte 810 if (h < mod) 811 mask &= (0XFF >> (mod - h)); 812 813 switch (color) { 814 case SSD1306_WHITE: 815 *pBuf |= mask; 816 break; 817 case SSD1306_BLACK: 818 *pBuf &= ~mask; 819 break; 820 case SSD1306_INVERSE: 821 *pBuf ^= mask; 822 break; 823 } 824 pBuf += WIDTH; 825 } 826 827 if (h >= mod) { // More to go? 828 h -= mod; 829 // Write solid bytes while we can - effectively 8 rows at a time 830 if (h >= 8) { 831 if (color == SSD1306_INVERSE) { 832 // separate copy of the code so we don't impact performance of 833 // black/white write version with an extra comparison per loop 834 do { 835 *pBuf ^= 0xFF; // Invert byte 836 pBuf += WIDTH; // Advance pointer 8 rows 837 h -= 8; // Subtract 8 rows from height 838 } while (h >= 8); 839 } else { 840 // store a local value to work with 841 uint8_t val = (color != SSD1306_BLACK) ? 255 : 0; 842 do { 843 *pBuf = val; // Set byte 844 pBuf += WIDTH; // Advance pointer 8 rows 845 h -= 8; // Subtract 8 rows from height 846 } while (h >= 8); 847 } 848 } 849 850 if (h) { // Do the final partial byte, if necessary 851 mod = h & 7; 852 // this time we want to mask the low bits of the byte, 853 // vs the high bits we did above 854 // uint8_t mask = (1 << mod) - 1; 855 // note - lookup table results in a nearly 10% performance 856 // improvement in fill* functions 857 static const uint8_t PROGMEM postmask[8] = {0x00, 0x01, 0x03, 0x07, 858 0x0F, 0x1F, 0x3F, 0x7F}; 859 uint8_t mask = pgm_read_byte(&postmask[mod]); 860 switch (color) { 861 case SSD1306_WHITE: 862 *pBuf |= mask; 863 break; 864 case SSD1306_BLACK: 865 *pBuf &= ~mask; 866 break; 867 case SSD1306_INVERSE: 868 *pBuf ^= mask; 869 break; 870 } 871 } 872 } 873 } // endif positive height 874 } // endif x in bounds 875 } 876 877 /*! 878 @brief Return color of a single pixel in display buffer. 879 @param x 880 Column of display -- 0 at left to (screen width - 1) at right. 881 @param y 882 Row of display -- 0 at top to (screen height -1) at bottom. 883 @return true if pixel is set (usually SSD1306_WHITE, unless display invert 884 mode is enabled), false if clear (SSD1306_BLACK). 885 @note Reads from buffer contents; may not reflect current contents of 886 screen if display() has not been called. 887 */ 888 bool Adafruit_SSD1306::getPixel(int16_t x, int16_t y) { 889 if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { 890 // Pixel is in-bounds. Rotate coordinates if needed. 891 switch (getRotation()) { 892 case 1: 893 ssd1306_swap(x, y); 894 x = WIDTH - x - 1; 895 break; 896 case 2: 897 x = WIDTH - x - 1; 898 y = HEIGHT - y - 1; 899 break; 900 case 3: 901 ssd1306_swap(x, y); 902 y = HEIGHT - y - 1; 903 break; 904 } 905 return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7))); 906 } 907 return false; // Pixel out of bounds 908 } 909 910 /*! 911 @brief Get base address of display buffer for direct reading or writing. 912 @return Pointer to an unsigned 8-bit array, column-major, columns padded 913 to full byte boundary if needed. 914 */ 915 uint8_t *Adafruit_SSD1306::getBuffer(void) { return buffer; } 916 917 // REFRESH DISPLAY --------------------------------------------------------- 918 919 /*! 920 @brief Push data currently in RAM to SSD1306 display. 921 @return None (void). 922 @note Drawing operations are not visible until this function is 923 called. Call after each graphics command, or after a whole set 924 of graphics commands, as best needed by one's own application. 925 */ 926 void Adafruit_SSD1306::display(void) { 927 TRANSACTION_START 928 static const uint8_t PROGMEM dlist1[] = { 929 SSD1306_PAGEADDR, 930 0, // Page start address 931 0xFF, // Page end (not really, but works here) 932 SSD1306_COLUMNADDR, 0}; // Column start address 933 ssd1306_commandList(dlist1, sizeof(dlist1)); 934 ssd1306_command1(WIDTH - 1); // Column end address 935 936 #if defined(ESP8266) 937 // ESP8266 needs a periodic yield() call to avoid watchdog reset. 938 // With the limited size of SSD1306 displays, and the fast bitrate 939 // being used (1 MHz or more), I think one yield() immediately before 940 // a screen write and one immediately after should cover it. But if 941 // not, if this becomes a problem, yields() might be added in the 942 // 32-byte transfer condition below. 943 yield(); 944 #endif 945 uint16_t count = WIDTH * ((HEIGHT + 7) / 8); 946 uint8_t *ptr = buffer; 947 if (wire) { // I2C 948 wire->beginTransmission(i2caddr); 949 WIRE_WRITE((uint8_t)0x40); 950 uint16_t bytesOut = 1; 951 while (count--) { 952 if (bytesOut >= WIRE_MAX) { 953 wire->endTransmission(); 954 wire->beginTransmission(i2caddr); 955 WIRE_WRITE((uint8_t)0x40); 956 bytesOut = 1; 957 } 958 WIRE_WRITE(*ptr++); 959 bytesOut++; 960 } 961 wire->endTransmission(); 962 } else { // SPI 963 SSD1306_MODE_DATA 964 while (count--) 965 SPIwrite(*ptr++); 966 } 967 TRANSACTION_END 968 #if defined(ESP8266) 969 yield(); 970 #endif 971 } 972 973 // SCROLLING FUNCTIONS ----------------------------------------------------- 974 975 /*! 976 @brief Activate a right-handed scroll for all or part of the display. 977 @param start 978 First row. 979 @param stop 980 Last row. 981 @return None (void). 982 */ 983 // To scroll the whole display, run: display.startscrollright(0x00, 0x0F) 984 void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop) { 985 TRANSACTION_START 986 static const uint8_t PROGMEM scrollList1a[] = { 987 SSD1306_RIGHT_HORIZONTAL_SCROLL, 0X00}; 988 ssd1306_commandList(scrollList1a, sizeof(scrollList1a)); 989 ssd1306_command1(start); 990 ssd1306_command1(0X00); 991 ssd1306_command1(stop); 992 static const uint8_t PROGMEM scrollList1b[] = {0X00, 0XFF, 993 SSD1306_ACTIVATE_SCROLL}; 994 ssd1306_commandList(scrollList1b, sizeof(scrollList1b)); 995 TRANSACTION_END 996 } 997 998 /*! 999 @brief Activate a left-handed scroll for all or part of the display. 1000 @param start 1001 First row. 1002 @param stop 1003 Last row. 1004 @return None (void). 1005 */ 1006 // To scroll the whole display, run: display.startscrollleft(0x00, 0x0F) 1007 void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop) { 1008 TRANSACTION_START 1009 static const uint8_t PROGMEM scrollList2a[] = {SSD1306_LEFT_HORIZONTAL_SCROLL, 1010 0X00}; 1011 ssd1306_commandList(scrollList2a, sizeof(scrollList2a)); 1012 ssd1306_command1(start); 1013 ssd1306_command1(0X00); 1014 ssd1306_command1(stop); 1015 static const uint8_t PROGMEM scrollList2b[] = {0X00, 0XFF, 1016 SSD1306_ACTIVATE_SCROLL}; 1017 ssd1306_commandList(scrollList2b, sizeof(scrollList2b)); 1018 TRANSACTION_END 1019 } 1020 1021 /*! 1022 @brief Activate a diagonal scroll for all or part of the display. 1023 @param start 1024 First row. 1025 @param stop 1026 Last row. 1027 @return None (void). 1028 */ 1029 // display.startscrolldiagright(0x00, 0x0F) 1030 void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop) { 1031 TRANSACTION_START 1032 static const uint8_t PROGMEM scrollList3a[] = { 1033 SSD1306_SET_VERTICAL_SCROLL_AREA, 0X00}; 1034 ssd1306_commandList(scrollList3a, sizeof(scrollList3a)); 1035 ssd1306_command1(HEIGHT); 1036 static const uint8_t PROGMEM scrollList3b[] = { 1037 SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL, 0X00}; 1038 ssd1306_commandList(scrollList3b, sizeof(scrollList3b)); 1039 ssd1306_command1(start); 1040 ssd1306_command1(0X00); 1041 ssd1306_command1(stop); 1042 static const uint8_t PROGMEM scrollList3c[] = {0X01, SSD1306_ACTIVATE_SCROLL}; 1043 ssd1306_commandList(scrollList3c, sizeof(scrollList3c)); 1044 TRANSACTION_END 1045 } 1046 1047 /*! 1048 @brief Activate alternate diagonal scroll for all or part of the display. 1049 @param start 1050 First row. 1051 @param stop 1052 Last row. 1053 @return None (void). 1054 */ 1055 // To scroll the whole display, run: display.startscrolldiagleft(0x00, 0x0F) 1056 void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop) { 1057 TRANSACTION_START 1058 static const uint8_t PROGMEM scrollList4a[] = { 1059 SSD1306_SET_VERTICAL_SCROLL_AREA, 0X00}; 1060 ssd1306_commandList(scrollList4a, sizeof(scrollList4a)); 1061 ssd1306_command1(HEIGHT); 1062 static const uint8_t PROGMEM scrollList4b[] = { 1063 SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL, 0X00}; 1064 ssd1306_commandList(scrollList4b, sizeof(scrollList4b)); 1065 ssd1306_command1(start); 1066 ssd1306_command1(0X00); 1067 ssd1306_command1(stop); 1068 static const uint8_t PROGMEM scrollList4c[] = {0X01, SSD1306_ACTIVATE_SCROLL}; 1069 ssd1306_commandList(scrollList4c, sizeof(scrollList4c)); 1070 TRANSACTION_END 1071 } 1072 1073 /*! 1074 @brief Cease a previously-begun scrolling action. 1075 @return None (void). 1076 */ 1077 void Adafruit_SSD1306::stopscroll(void) { 1078 TRANSACTION_START 1079 ssd1306_command1(SSD1306_DEACTIVATE_SCROLL); 1080 TRANSACTION_END 1081 } 1082 1083 // OTHER HARDWARE SETTINGS ------------------------------------------------- 1084 1085 /*! 1086 @brief Enable or disable display invert mode (white-on-black vs 1087 black-on-white). 1088 @param i 1089 If true, switch to invert mode (black-on-white), else normal 1090 mode (white-on-black). 1091 @return None (void). 1092 @note This has an immediate effect on the display, no need to call the 1093 display() function -- buffer contents are not changed, rather a 1094 different pixel mode of the display hardware is used. When 1095 enabled, drawing SSD1306_BLACK (value 0) pixels will actually draw 1096 white, SSD1306_WHITE (value 1) will draw black. 1097 */ 1098 void Adafruit_SSD1306::invertDisplay(bool i) { 1099 TRANSACTION_START 1100 ssd1306_command1(i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); 1101 TRANSACTION_END 1102 } 1103 1104 /*! 1105 @brief Dim the display. 1106 @param dim 1107 true to enable lower brightness mode, false for full brightness. 1108 @return None (void). 1109 @note This has an immediate effect on the display, no need to call the 1110 display() function -- buffer contents are not changed. 1111 */ 1112 void Adafruit_SSD1306::dim(bool dim) { 1113 // the range of contrast to too small to be really useful 1114 // it is useful to dim the display 1115 TRANSACTION_START 1116 ssd1306_command1(SSD1306_SETCONTRAST); 1117 ssd1306_command1(dim ? 0 : contrast); 1118 TRANSACTION_END 1119 }