Adafruit_SSD1306.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. /*********************************************************************
  2. This is a library for our Monochrome OLEDs based on SSD1306 drivers
  3. Pick one up today in the adafruit shop!
  4. ------> http://www.adafruit.com/category/63_98
  5. These displays use SPI to communicate, 4 or 5 pins are required to
  6. interface
  7. Adafruit invests time and resources providing this open source code,
  8. please support Adafruit and open-source hardware by purchasing
  9. products from Adafruit!
  10. Written by Limor Fried/Ladyada for Adafruit Industries.
  11. BSD license, check license.txt for more information
  12. All text above, and the splash screen below must be included in any redistribution
  13. *********************************************************************/
  14. #ifdef __AVR__
  15. #include <avr/pgmspace.h>
  16. #elif defined(ESP8266) || defined(ESP32)
  17. #include <pgmspace.h>
  18. #else
  19. #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
  20. #endif
  21. #if !defined(__ARM_ARCH) && !defined(ENERGIA) && !defined(ESP8266) && !defined(ESP32) && !defined(__arc__)
  22. #include <util/delay.h>
  23. #endif
  24. #include <stdlib.h>
  25. #include <Wire.h>
  26. #include <SPI.h>
  27. #include "Adafruit_GFX.h"
  28. #include "Adafruit_SSD1306.h"
  29. // the memory buffer for the LCD
  30. static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = {
  31. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  32. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  33. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  34. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
  35. 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  36. 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  37. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  38. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  39. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  40. 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
  41. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
  42. 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF,
  43. #if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16)
  44. 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
  45. 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,
  46. 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8,
  47. 0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  48. 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,
  49. 0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
  50. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01,
  51. 0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF,
  52. 0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00,
  53. 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF,
  54. 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF,
  55. 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F,
  57. 0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC,
  58. 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03,
  59. 0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
  60. 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00,
  61. 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  62. 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
  63. 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  64. #if (SSD1306_LCDHEIGHT == 64)
  65. 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F,
  66. 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF,
  67. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00,
  68. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  69. 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  70. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00,
  71. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
  72. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  73. 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F,
  74. 0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,
  75. 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
  76. 0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E,
  77. 0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC,
  78. 0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06,
  79. 0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8,
  80. 0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80,
  81. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  82. 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03,
  83. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
  84. 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C,
  85. 0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F,
  86. 0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00,
  87. 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07,
  88. 0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07,
  89. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  90. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  91. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  92. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  93. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  94. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  95. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  96. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  97. #endif
  98. #endif
  99. };
  100. #define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; }
  101. // the most basic function, set a single pixel
  102. void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
  103. if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
  104. return;
  105. // check rotation, move pixel around if necessary
  106. switch (getRotation()) {
  107. case 1:
  108. ssd1306_swap(x, y);
  109. x = WIDTH - x - 1;
  110. break;
  111. case 2:
  112. x = WIDTH - x - 1;
  113. y = HEIGHT - y - 1;
  114. break;
  115. case 3:
  116. ssd1306_swap(x, y);
  117. y = HEIGHT - y - 1;
  118. break;
  119. }
  120. // x is which column
  121. switch (color)
  122. {
  123. case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break;
  124. case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break;
  125. case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break;
  126. }
  127. }
  128. Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
  129. cs = CS;
  130. rst = RST;
  131. dc = DC;
  132. sclk = SCLK;
  133. sid = SID;
  134. hwSPI = false;
  135. }
  136. // constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset
  137. Adafruit_SSD1306::Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
  138. dc = DC;
  139. rst = RST;
  140. cs = CS;
  141. hwSPI = true;
  142. }
  143. // initializer for I2C - we only indicate the reset pin!
  144. Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) :
  145. Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
  146. sclk = dc = cs = sid = -1;
  147. rst = reset;
  148. }
  149. void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) {
  150. _vccstate = vccstate;
  151. _i2caddr = i2caddr;
  152. // set pin directions
  153. if (sid != -1){
  154. pinMode(dc, OUTPUT);
  155. pinMode(cs, OUTPUT);
  156. #ifdef HAVE_PORTREG
  157. csport = portOutputRegister(digitalPinToPort(cs));
  158. cspinmask = digitalPinToBitMask(cs);
  159. dcport = portOutputRegister(digitalPinToPort(dc));
  160. dcpinmask = digitalPinToBitMask(dc);
  161. #endif
  162. if (!hwSPI){
  163. // set pins for software-SPI
  164. pinMode(sid, OUTPUT);
  165. pinMode(sclk, OUTPUT);
  166. #ifdef HAVE_PORTREG
  167. clkport = portOutputRegister(digitalPinToPort(sclk));
  168. clkpinmask = digitalPinToBitMask(sclk);
  169. mosiport = portOutputRegister(digitalPinToPort(sid));
  170. mosipinmask = digitalPinToBitMask(sid);
  171. #endif
  172. }
  173. if (hwSPI){
  174. SPI.begin();
  175. #ifdef SPI_HAS_TRANSACTION
  176. SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  177. #else
  178. SPI.setClockDivider (4);
  179. #endif
  180. }
  181. }
  182. else
  183. {
  184. // I2C Init
  185. Wire.begin();
  186. #ifdef __SAM3X8E__
  187. // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL)
  188. TWI1->TWI_CWGR = 0;
  189. TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101;
  190. #endif
  191. }
  192. if ((reset) && (rst >= 0)) {
  193. // Setup reset pin direction (used by both SPI and I2C)
  194. pinMode(rst, OUTPUT);
  195. digitalWrite(rst, HIGH);
  196. // VDD (3.3V) goes high at start, lets just chill for a ms
  197. delay(1);
  198. // bring reset low
  199. digitalWrite(rst, LOW);
  200. // wait 10ms
  201. delay(10);
  202. // bring out of reset
  203. digitalWrite(rst, HIGH);
  204. // turn on VCC (9V?)
  205. }
  206. // Init sequence
  207. ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
  208. ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
  209. ssd1306_command(0x80); // the suggested ratio 0x80
  210. ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
  211. ssd1306_command(SSD1306_LCDHEIGHT - 1);
  212. ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
  213. ssd1306_command(0x0); // no offset
  214. ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
  215. ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
  216. if (vccstate == SSD1306_EXTERNALVCC)
  217. { ssd1306_command(0x10); }
  218. else
  219. { ssd1306_command(0x14); }
  220. ssd1306_command(SSD1306_MEMORYMODE); // 0x20
  221. ssd1306_command(0x00); // 0x0 act like ks0108
  222. ssd1306_command(SSD1306_SEGREMAP | 0x1);
  223. ssd1306_command(SSD1306_COMSCANDEC);
  224. #if defined SSD1306_128_32
  225. ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
  226. ssd1306_command(0x02);
  227. ssd1306_command(SSD1306_SETCONTRAST); // 0x81
  228. ssd1306_command(0x8F);
  229. #elif defined SSD1306_128_64
  230. ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
  231. ssd1306_command(0x12);
  232. ssd1306_command(SSD1306_SETCONTRAST); // 0x81
  233. if (vccstate == SSD1306_EXTERNALVCC)
  234. { ssd1306_command(0x9F); }
  235. else
  236. { ssd1306_command(0xCF); }
  237. #elif defined SSD1306_96_16
  238. ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
  239. ssd1306_command(0x2); //ada x12
  240. ssd1306_command(SSD1306_SETCONTRAST); // 0x81
  241. if (vccstate == SSD1306_EXTERNALVCC)
  242. { ssd1306_command(0x10); }
  243. else
  244. { ssd1306_command(0xAF); }
  245. #endif
  246. ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
  247. if (vccstate == SSD1306_EXTERNALVCC)
  248. { ssd1306_command(0x22); }
  249. else
  250. { ssd1306_command(0xF1); }
  251. ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
  252. ssd1306_command(0x40);
  253. ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
  254. ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
  255. ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
  256. ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel
  257. }
  258. void Adafruit_SSD1306::invertDisplay(uint8_t i) {
  259. if (i) {
  260. ssd1306_command(SSD1306_INVERTDISPLAY);
  261. } else {
  262. ssd1306_command(SSD1306_NORMALDISPLAY);
  263. }
  264. }
  265. void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
  266. if (sid != -1)
  267. {
  268. // SPI
  269. #ifdef HAVE_PORTREG
  270. *csport |= cspinmask;
  271. *dcport &= ~dcpinmask;
  272. *csport &= ~cspinmask;
  273. #else
  274. digitalWrite(cs, HIGH);
  275. digitalWrite(dc, LOW);
  276. digitalWrite(cs, LOW);
  277. #endif
  278. fastSPIwrite(c);
  279. #ifdef HAVE_PORTREG
  280. *csport |= cspinmask;
  281. #else
  282. digitalWrite(cs, HIGH);
  283. #endif
  284. }
  285. else
  286. {
  287. // I2C
  288. uint8_t control = 0x00; // Co = 0, D/C = 0
  289. Wire.beginTransmission(_i2caddr);
  290. Wire.write(control);
  291. Wire.write(c);
  292. Wire.endTransmission();
  293. }
  294. }
  295. // startscrollright
  296. // Activate a right handed scroll for rows start through stop
  297. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  298. // display.scrollright(0x00, 0x0F)
  299. void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){
  300. ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
  301. ssd1306_command(0X00);
  302. ssd1306_command(start);
  303. ssd1306_command(0X00);
  304. ssd1306_command(stop);
  305. ssd1306_command(0X00);
  306. ssd1306_command(0XFF);
  307. ssd1306_command(SSD1306_ACTIVATE_SCROLL);
  308. }
  309. // startscrollleft
  310. // Activate a right handed scroll for rows start through stop
  311. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  312. // display.scrollright(0x00, 0x0F)
  313. void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){
  314. ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
  315. ssd1306_command(0X00);
  316. ssd1306_command(start);
  317. ssd1306_command(0X00);
  318. ssd1306_command(stop);
  319. ssd1306_command(0X00);
  320. ssd1306_command(0XFF);
  321. ssd1306_command(SSD1306_ACTIVATE_SCROLL);
  322. }
  323. // startscrolldiagright
  324. // Activate a diagonal scroll for rows start through stop
  325. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  326. // display.scrollright(0x00, 0x0F)
  327. void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){
  328. ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
  329. ssd1306_command(0X00);
  330. ssd1306_command(SSD1306_LCDHEIGHT);
  331. ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
  332. ssd1306_command(0X00);
  333. ssd1306_command(start);
  334. ssd1306_command(0X00);
  335. ssd1306_command(stop);
  336. ssd1306_command(0X01);
  337. ssd1306_command(SSD1306_ACTIVATE_SCROLL);
  338. }
  339. // startscrolldiagleft
  340. // Activate a diagonal scroll for rows start through stop
  341. // Hint, the display is 16 rows tall. To scroll the whole display, run:
  342. // display.scrollright(0x00, 0x0F)
  343. void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){
  344. ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
  345. ssd1306_command(0X00);
  346. ssd1306_command(SSD1306_LCDHEIGHT);
  347. ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
  348. ssd1306_command(0X00);
  349. ssd1306_command(start);
  350. ssd1306_command(0X00);
  351. ssd1306_command(stop);
  352. ssd1306_command(0X01);
  353. ssd1306_command(SSD1306_ACTIVATE_SCROLL);
  354. }
  355. void Adafruit_SSD1306::stopscroll(void){
  356. ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
  357. }
  358. // Dim the display
  359. // dim = true: display is dimmed
  360. // dim = false: display is normal
  361. void Adafruit_SSD1306::dim(boolean dim) {
  362. uint8_t contrast;
  363. if (dim) {
  364. contrast = 0; // Dimmed display
  365. } else {
  366. if (_vccstate == SSD1306_EXTERNALVCC) {
  367. contrast = 0x9F;
  368. } else {
  369. contrast = 0xCF;
  370. }
  371. }
  372. // the range of contrast to too small to be really useful
  373. // it is useful to dim the display
  374. ssd1306_command(SSD1306_SETCONTRAST);
  375. ssd1306_command(contrast);
  376. }
  377. void Adafruit_SSD1306::display(void) {
  378. ssd1306_command(SSD1306_COLUMNADDR);
  379. ssd1306_command(0); // Column start address (0 = reset)
  380. ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)
  381. ssd1306_command(SSD1306_PAGEADDR);
  382. ssd1306_command(0); // Page start address (0 = reset)
  383. #if SSD1306_LCDHEIGHT == 64
  384. ssd1306_command(7); // Page end address
  385. #endif
  386. #if SSD1306_LCDHEIGHT == 32
  387. ssd1306_command(3); // Page end address
  388. #endif
  389. #if SSD1306_LCDHEIGHT == 16
  390. ssd1306_command(1); // Page end address
  391. #endif
  392. if (sid != -1)
  393. {
  394. // SPI
  395. #ifdef HAVE_PORTREG
  396. *csport |= cspinmask;
  397. *dcport |= dcpinmask;
  398. *csport &= ~cspinmask;
  399. #else
  400. digitalWrite(cs, HIGH);
  401. digitalWrite(dc, HIGH);
  402. digitalWrite(cs, LOW);
  403. #endif
  404. for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
  405. fastSPIwrite(buffer[i]);
  406. }
  407. #ifdef HAVE_PORTREG
  408. *csport |= cspinmask;
  409. #else
  410. digitalWrite(cs, HIGH);
  411. #endif
  412. }
  413. else
  414. {
  415. // save I2C bitrate
  416. #ifdef TWBR
  417. uint8_t twbrbackup = TWBR;
  418. TWBR = 12; // upgrade to 400KHz!
  419. #endif
  420. //Serial.println(TWBR, DEC);
  421. //Serial.println(TWSR & 0x3, DEC);
  422. // I2C
  423. for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
  424. // send a bunch of data in one xmission
  425. Wire.beginTransmission(_i2caddr);
  426. WIRE_WRITE(0x40);
  427. for (uint8_t x=0; x<16; x++) {
  428. WIRE_WRITE(buffer[i]);
  429. i++;
  430. }
  431. i--;
  432. Wire.endTransmission();
  433. }
  434. #ifdef TWBR
  435. TWBR = twbrbackup;
  436. #endif
  437. }
  438. }
  439. // clear everything
  440. void Adafruit_SSD1306::clearDisplay(void) {
  441. memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8));
  442. }
  443. inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) {
  444. if(hwSPI) {
  445. (void)SPI.transfer(d);
  446. } else {
  447. for(uint8_t bit = 0x80; bit; bit >>= 1) {
  448. #ifdef HAVE_PORTREG
  449. *clkport &= ~clkpinmask;
  450. if(d & bit) *mosiport |= mosipinmask;
  451. else *mosiport &= ~mosipinmask;
  452. *clkport |= clkpinmask;
  453. #else
  454. digitalWrite(sclk, LOW);
  455. if(d & bit) digitalWrite(sid, HIGH);
  456. else digitalWrite(sid, LOW);
  457. digitalWrite(sclk, HIGH);
  458. #endif
  459. }
  460. }
  461. }
  462. void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
  463. boolean bSwap = false;
  464. switch(rotation) {
  465. case 0:
  466. // 0 degree rotation, do nothing
  467. break;
  468. case 1:
  469. // 90 degree rotation, swap x & y for rotation, then invert x
  470. bSwap = true;
  471. ssd1306_swap(x, y);
  472. x = WIDTH - x - 1;
  473. break;
  474. case 2:
  475. // 180 degree rotation, invert x and y - then shift y around for height.
  476. x = WIDTH - x - 1;
  477. y = HEIGHT - y - 1;
  478. x -= (w-1);
  479. break;
  480. case 3:
  481. // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h)
  482. bSwap = true;
  483. ssd1306_swap(x, y);
  484. y = HEIGHT - y - 1;
  485. y -= (w-1);
  486. break;
  487. }
  488. if(bSwap) {
  489. drawFastVLineInternal(x, y, w, color);
  490. } else {
  491. drawFastHLineInternal(x, y, w, color);
  492. }
  493. }
  494. void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) {
  495. // Do bounds/limit checks
  496. if(y < 0 || y >= HEIGHT) { return; }
  497. // make sure we don't try to draw below 0
  498. if(x < 0) {
  499. w += x;
  500. x = 0;
  501. }
  502. // make sure we don't go off the edge of the display
  503. if( (x + w) > WIDTH) {
  504. w = (WIDTH - x);
  505. }
  506. // if our width is now negative, punt
  507. if(w <= 0) { return; }
  508. // set up the pointer for movement through the buffer
  509. register uint8_t *pBuf = buffer;
  510. // adjust the buffer pointer for the current row
  511. pBuf += ((y/8) * SSD1306_LCDWIDTH);
  512. // and offset x columns in
  513. pBuf += x;
  514. register uint8_t mask = 1 << (y&7);
  515. switch (color)
  516. {
  517. case WHITE: while(w--) { *pBuf++ |= mask; }; break;
  518. case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break;
  519. case INVERSE: while(w--) { *pBuf++ ^= mask; }; break;
  520. }
  521. }
  522. void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
  523. bool bSwap = false;
  524. switch(rotation) {
  525. case 0:
  526. break;
  527. case 1:
  528. // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
  529. bSwap = true;
  530. ssd1306_swap(x, y);
  531. x = WIDTH - x - 1;
  532. x -= (h-1);
  533. break;
  534. case 2:
  535. // 180 degree rotation, invert x and y - then shift y around for height.
  536. x = WIDTH - x - 1;
  537. y = HEIGHT - y - 1;
  538. y -= (h-1);
  539. break;
  540. case 3:
  541. // 270 degree rotation, swap x & y for rotation, then invert y
  542. bSwap = true;
  543. ssd1306_swap(x, y);
  544. y = HEIGHT - y - 1;
  545. break;
  546. }
  547. if(bSwap) {
  548. drawFastHLineInternal(x, y, h, color);
  549. } else {
  550. drawFastVLineInternal(x, y, h, color);
  551. }
  552. }
  553. void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {
  554. // do nothing if we're off the left or right side of the screen
  555. if(x < 0 || x >= WIDTH) { return; }
  556. // make sure we don't try to draw below 0
  557. if(__y < 0) {
  558. // __y is negative, this will subtract enough from __h to account for __y being 0
  559. __h += __y;
  560. __y = 0;
  561. }
  562. // make sure we don't go past the height of the display
  563. if( (__y + __h) > HEIGHT) {
  564. __h = (HEIGHT - __y);
  565. }
  566. // if our height is now negative, punt
  567. if(__h <= 0) {
  568. return;
  569. }
  570. // this display doesn't need ints for coordinates, use local byte registers for faster juggling
  571. register uint8_t y = __y;
  572. register uint8_t h = __h;
  573. // set up the pointer for fast movement through the buffer
  574. register uint8_t *pBuf = buffer;
  575. // adjust the buffer pointer for the current row
  576. pBuf += ((y/8) * SSD1306_LCDWIDTH);
  577. // and offset x columns in
  578. pBuf += x;
  579. // do the first partial byte, if necessary - this requires some masking
  580. register uint8_t mod = (y&7);
  581. if(mod) {
  582. // mask off the high n bits we want to set
  583. mod = 8-mod;
  584. // note - lookup table results in a nearly 10% performance improvement in fill* functions
  585. // register uint8_t mask = ~(0xFF >> (mod));
  586. static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
  587. register uint8_t mask = premask[mod];
  588. // adjust the mask if we're not going to reach the end of this byte
  589. if( h < mod) {
  590. mask &= (0XFF >> (mod-h));
  591. }
  592. switch (color)
  593. {
  594. case WHITE: *pBuf |= mask; break;
  595. case BLACK: *pBuf &= ~mask; break;
  596. case INVERSE: *pBuf ^= mask; break;
  597. }
  598. // fast exit if we're done here!
  599. if(h<mod) { return; }
  600. h -= mod;
  601. pBuf += SSD1306_LCDWIDTH;
  602. }
  603. // write solid bytes while we can - effectively doing 8 rows at a time
  604. if(h >= 8) {
  605. if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop
  606. do {
  607. *pBuf=~(*pBuf);
  608. // adjust the buffer forward 8 rows worth of data
  609. pBuf += SSD1306_LCDWIDTH;
  610. // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
  611. h -= 8;
  612. } while(h >= 8);
  613. }
  614. else {
  615. // store a local value to work with
  616. register uint8_t val = (color == WHITE) ? 255 : 0;
  617. do {
  618. // write our value in
  619. *pBuf = val;
  620. // adjust the buffer forward 8 rows worth of data
  621. pBuf += SSD1306_LCDWIDTH;
  622. // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
  623. h -= 8;
  624. } while(h >= 8);
  625. }
  626. }
  627. // now do the final partial byte, if necessary
  628. if(h) {
  629. mod = h & 7;
  630. // this time we want to mask the low bits of the byte, vs the high bits we did above
  631. // register uint8_t mask = (1 << mod) - 1;
  632. // note - lookup table results in a nearly 10% performance improvement in fill* functions
  633. static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
  634. register uint8_t mask = postmask[mod];
  635. switch (color)
  636. {
  637. case WHITE: *pBuf |= mask; break;
  638. case BLACK: *pBuf &= ~mask; break;
  639. case INVERSE: *pBuf ^= mask; break;
  640. }
  641. }
  642. }