Adafruit_MonoOLED.cpp 14 KB

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