├── ESP_Adafruit_SSD1306.h └── ESP_Adafruit_SSD1306.cpp /ESP_Adafruit_SSD1306.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen must be included in any redistribution 17 | *********************************************************************/ 18 | 19 | #if ARDUINO >= 100 20 | #include "Arduino.h" 21 | #define WIRE_WRITE Wire.write 22 | #else 23 | #include "WProgram.h" 24 | #define WIRE_WRITE Wire.send 25 | #endif 26 | 27 | typedef volatile uint8_t PortReg; 28 | typedef uint8_t PortMask; 29 | 30 | 31 | #include 32 | 33 | #define BLACK 0 34 | #define WHITE 1 35 | #define INVERSE 2 36 | 37 | #define SSD1306_I2C_ADDRESS 0x78 // 011110+SA0+RW - 0x3C or 0x3D 38 | // Address for 128x32 is 0x3C 39 | // Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded) 40 | 41 | /*========================================================================= 42 | SSD1306 Displays 43 | ----------------------------------------------------------------------- 44 | The driver is used in multiple displays (128x64, 128x32, etc.). 45 | Select the appropriate display below to create an appropriately 46 | sized framebuffer, etc. 47 | 48 | SSD1306_128_64 128x64 pixel display 49 | 50 | SSD1306_128_32 128x32 pixel display 51 | 52 | SSD1306_96_16 53 | 54 | -----------------------------------------------------------------------*/ 55 | #define SSD1306_128_64 56 | // #define SSD1306_128_32 57 | // #define SSD1306_96_16 58 | /*=========================================================================*/ 59 | 60 | #if defined SSD1306_128_64 && defined SSD1306_128_32 61 | #error "Only one SSD1306 display can be specified at once in SSD1306.h" 62 | #endif 63 | #if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 64 | #error "At least one SSD1306 display must be specified in SSD1306.h" 65 | #endif 66 | 67 | #if defined SSD1306_128_64 68 | #define SSD1306_LCDWIDTH 128 69 | #define SSD1306_LCDHEIGHT 64 70 | #endif 71 | #if defined SSD1306_128_32 72 | #define SSD1306_LCDWIDTH 128 73 | #define SSD1306_LCDHEIGHT 32 74 | #endif 75 | #if defined SSD1306_96_16 76 | #define SSD1306_LCDWIDTH 96 77 | #define SSD1306_LCDHEIGHT 16 78 | #endif 79 | 80 | #define SSD1306_SETCONTRAST 0x81 81 | #define SSD1306_DISPLAYALLON_RESUME 0xA4 82 | #define SSD1306_DISPLAYALLON 0xA5 83 | #define SSD1306_NORMALDISPLAY 0xA6 84 | #define SSD1306_INVERTDISPLAY 0xA7 85 | #define SSD1306_DISPLAYOFF 0xAE 86 | #define SSD1306_DISPLAYON 0xAF 87 | 88 | #define SSD1306_SETDISPLAYOFFSET 0xD3 89 | #define SSD1306_SETCOMPINS 0xDA 90 | 91 | #define SSD1306_SETVCOMDETECT 0xDB 92 | 93 | #define SSD1306_SETDISPLAYCLOCKDIV 0xD5 94 | #define SSD1306_SETPRECHARGE 0xD9 95 | 96 | #define SSD1306_SETMULTIPLEX 0xA8 97 | 98 | #define SSD1306_SETLOWCOLUMN 0x00 99 | #define SSD1306_SETHIGHCOLUMN 0x10 100 | 101 | #define SSD1306_SETSTARTLINE 0x40 102 | 103 | #define SSD1306_MEMORYMODE 0x20 104 | #define SSD1306_COLUMNADDR 0x21 105 | #define SSD1306_PAGEADDR 0x22 106 | 107 | #define SSD1306_COMSCANINC 0xC0 108 | #define SSD1306_COMSCANDEC 0xC8 109 | 110 | #define SSD1306_SEGREMAP 0xA0 111 | 112 | #define SSD1306_CHARGEPUMP 0x8D 113 | 114 | #define SSD1306_EXTERNALVCC 0x1 115 | #define SSD1306_SWITCHCAPVCC 0x2 116 | 117 | // Scrolling #defines 118 | #define SSD1306_ACTIVATE_SCROLL 0x2F 119 | #define SSD1306_DEACTIVATE_SCROLL 0x2E 120 | #define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 121 | #define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 122 | #define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 123 | #define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 124 | #define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A 125 | 126 | class Adafruit_SSD1306 : public Adafruit_GFX { 127 | public: 128 | Adafruit_SSD1306(int8_t RST); 129 | 130 | void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS, bool reset=true); 131 | void ssd1306_command(uint8_t c); 132 | void ssd1306_data(uint8_t c); 133 | 134 | void clearDisplay(void); 135 | void invertDisplay(uint8_t i); 136 | void display(); 137 | 138 | void startscrollright(uint8_t start, uint8_t stop); 139 | void startscrollleft(uint8_t start, uint8_t stop); 140 | 141 | void startscrolldiagright(uint8_t start, uint8_t stop); 142 | void startscrolldiagleft(uint8_t start, uint8_t stop); 143 | void stopscroll(void); 144 | 145 | void dim(boolean dim); 146 | 147 | void drawPixel(int16_t x, int16_t y, uint16_t color); 148 | 149 | virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); 150 | virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); 151 | 152 | private: 153 | int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs; 154 | void fastSPIwrite(uint8_t c); 155 | 156 | boolean hwSPI; 157 | PortReg *mosiport, *clkport, *csport, *dcport; 158 | PortMask mosipinmask, clkpinmask, cspinmask, dcpinmask; 159 | 160 | inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)); 161 | inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)); 162 | 163 | }; 164 | -------------------------------------------------------------------------------- /ESP_Adafruit_SSD1306.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | This is a library for our Monochrome OLEDs based on SSD1306 drivers 3 | 4 | Pick one up today in the adafruit shop! 5 | ------> http://www.adafruit.com/category/63_98 6 | 7 | These displays use SPI to communicate, 4 or 5 pins are required to 8 | interface 9 | 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing 12 | products from Adafruit! 13 | 14 | Written by Limor Fried/Ladyada for Adafruit Industries. 15 | BSD license, check license.txt for more information 16 | All text above, and the splash screen below must be included in any redistribution 17 | *********************************************************************/ 18 | #define TWI_FREQ 400000L // define i2c CLK speed 400k Hz 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | #include "Adafruit_GFX.h" 25 | #include "ESP_Adafruit_SSD1306.h" 26 | 27 | // the memory buffer for the LCD 28 | 29 | // static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { 30 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x80, 34 | // 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 | // 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | // 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, 40 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 41 | // 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, 42 | // #if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16) 43 | // 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 44 | // 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 45 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8, 46 | // 0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | // 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, 48 | // 0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 49 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01, 50 | // 0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF, 51 | // 0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00, 52 | // 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF, 53 | // 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, 54 | // 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | // 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F, 56 | // 0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 57 | // 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03, 58 | // 0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 59 | // 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, 60 | // 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 61 | // 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, 62 | // 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | // #if (SSD1306_LCDHEIGHT == 64) 64 | // 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, 65 | // 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, 66 | // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, 67 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 68 | // 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 69 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, 70 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 71 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 72 | // 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, 73 | // 0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, 74 | // 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 75 | // 0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E, 76 | // 0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC, 77 | // 0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06, 78 | // 0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8, 79 | // 0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80, 80 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | // 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03, 82 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 83 | // 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C, 84 | // 0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 85 | // 0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 86 | // 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07, 87 | // 0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 88 | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 | // #endif 97 | // #endif 98 | // }; 99 | 100 | static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { 101 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 102 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 103 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 104 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 105 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 106 | 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 107 | 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x1F, 108 | 0x1F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 109 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 110 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 111 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 112 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 113 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 114 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 115 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 116 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 117 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 118 | 0xFF, 0xFF, 0x7F, 0x0F, 0x07, 0x03, 0x01, 0x00, 0xC0, 0xF0, 119 | 0xF8, 0xF8, 0xFC, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 120 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFC, 0xF8, 121 | 0xF0, 0xE0, 0x00, 0x00, 0x01, 0x03, 0x0F, 0x1F, 0x1F, 0x1F, 122 | 0x3F, 0x3F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 123 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 124 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 125 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 126 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 127 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 128 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 129 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 130 | 0xFF, 0x7F, 0x1F, 0x0F, 0x0F, 0x07, 0x03, 0x83, 0xC1, 0xC1, 131 | 0xE0, 0xE0, 0xF0, 0xF0, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 132 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 133 | 0x7F, 0xFF, 0xFF, 0x7F, 0x7F, 0x7F, 0x3F, 0x1F, 0x1F, 0x07, 134 | 0x00, 0x00, 0x80, 0xC0, 0xF0, 0xFE, 0xFE, 0xFC, 0xFC, 0xF8, 135 | 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x01, 0x03, 0x07, 0x0F, 0x3F, 136 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 137 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 138 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 139 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 140 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 141 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 142 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0x00, 0x00, 143 | 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 144 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 145 | 0xC1, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 146 | 0x80, 0xC0, 0xF0, 0xF8, 0xF8, 0xF8, 0xFC, 0xFC, 0xFE, 0xFF, 147 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 148 | 0xFF, 0xFF, 0xFF, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 149 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 150 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 151 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 152 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 153 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 154 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 155 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xF0, 0xE0, 156 | 0xC0, 0x80, 0x03, 0x07, 0x0F, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 157 | 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 158 | 0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1F, 0x1F, 0x3F, 159 | 0x3F, 0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 160 | 0x7F, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x0F, 0x0F, 0x07, 0x03, 161 | 0x80, 0xC0, 0xC0, 0xE0, 0xF8, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 162 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 163 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 164 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 165 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 166 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 167 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 168 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 169 | 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 170 | 0xFC, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 171 | 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xFC, 172 | 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 173 | 0xFC, 0xFC, 0xFC, 0xFC, 0xFE, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 174 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 175 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 176 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 177 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 178 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 179 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 180 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 181 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x01, 182 | 0xEC, 0xEC, 0xEC, 0xE9, 0xE1, 0xEF, 0xFF, 0xF3, 0xE1, 0xE4, 183 | 0xCC, 0xCC, 0x1D, 0x3F, 0xFF, 0xFF, 0x00, 0x01, 0x7D, 0xFC, 184 | 0xFC, 0x78, 0x01, 0x03, 0xFF, 0xFF, 0x03, 0x01, 0xEC, 0xEC, 185 | 0xEC, 0xE9, 0xE1, 0xE7, 0xFF, 0xFF, 0x00, 0x01, 0xF9, 0xFC, 186 | 0xFC, 0xFF, 0xFD, 0x00, 0x00, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 187 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 188 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 189 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 190 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 191 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 192 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 193 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 194 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 195 | 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFC, 0xFC, 196 | 0xFE, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0xFE, 0xFC, 0xFC, 0xFE, 197 | 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 198 | 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 199 | 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 200 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 201 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 202 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 203 | 0xFF, 0xFF, 0xFF, 0xFF 204 | }; 205 | 206 | 207 | 208 | // the most basic function, set a single pixel 209 | void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { 210 | if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) 211 | return; 212 | 213 | // check rotation, move pixel around if necessary 214 | switch (getRotation()) { 215 | case 1: 216 | // swap(x, y); 217 | x = WIDTH - x - 1; 218 | break; 219 | case 2: 220 | x = WIDTH - x - 1; 221 | y = HEIGHT - y - 1; 222 | break; 223 | case 3: 224 | // swap(x, y); 225 | y = HEIGHT - y - 1; 226 | break; 227 | } 228 | 229 | // x is which column 230 | switch (color) 231 | { 232 | case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; 233 | case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; 234 | case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; 235 | } 236 | 237 | } 238 | 239 | // initializer for I2C - we only indicate the reset pin! 240 | Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) : 241 | Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { 242 | sclk = dc = cs = sid = -1; 243 | rst = reset; 244 | } 245 | 246 | 247 | void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { 248 | _vccstate = vccstate; 249 | _i2caddr = i2caddr; 250 | // I2C Init 251 | // ESP.wdtDisable(); 252 | Wire.begin(); 253 | Wire.setClock(450000); // maximum 254 | /* if (reset) { 255 | // Setup reset pin direction (used by both SPI and I2C) 256 | pinMode(rst, OUTPUT); 257 | digitalWrite(rst, HIGH); 258 | // VDD (3.3V) goes high at start, lets just chill for a ms 259 | delay(1); 260 | // bring reset low 261 | digitalWrite(rst, LOW); 262 | // wait 10ms 263 | delay(10); 264 | // bring out of reset 265 | digitalWrite(rst, HIGH); 266 | // turn on VCC (9V?) 267 | } */ 268 | 269 | #if defined SSD1306_128_32 270 | // Init sequence for 128x32 OLED module 271 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 272 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 273 | ssd1306_command(0x80); // the suggested ratio 0x80 274 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 275 | ssd1306_command(0x1F); 276 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 277 | ssd1306_command(0x0); // no offset 278 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 279 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 280 | if (vccstate == SSD1306_EXTERNALVCC) 281 | { ssd1306_command(0x10); } 282 | else 283 | { ssd1306_command(0x14); } 284 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 285 | ssd1306_command(0x00); // 0x0 act like ks0108 286 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 287 | ssd1306_command(SSD1306_COMSCANDEC); 288 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 289 | ssd1306_command(0x02); 290 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 291 | ssd1306_command(0x8F); 292 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 293 | if (vccstate == SSD1306_EXTERNALVCC) 294 | { ssd1306_command(0x22); } 295 | else 296 | { ssd1306_command(0xF1); } 297 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 298 | ssd1306_command(0x40); 299 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 300 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 301 | #endif 302 | 303 | #if defined SSD1306_128_64 304 | // Init sequence for 128x64 OLED module 305 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 306 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 307 | ssd1306_command(0x80); // the suggested ratio 0x80 308 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 309 | ssd1306_command(0x3F); 310 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 311 | ssd1306_command(0x0); // no offset 312 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 313 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 314 | if (vccstate == SSD1306_EXTERNALVCC) 315 | { ssd1306_command(0x10); } 316 | else 317 | { ssd1306_command(0x14); } 318 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 319 | ssd1306_command(0x00); // 0x0 act like ks0108 320 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 321 | ssd1306_command(SSD1306_COMSCANDEC); 322 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 323 | ssd1306_command(0x12); 324 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 325 | if (vccstate == SSD1306_EXTERNALVCC) 326 | { ssd1306_command(0x9F); } 327 | else 328 | { ssd1306_command(0xCF); } 329 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 330 | if (vccstate == SSD1306_EXTERNALVCC) 331 | { ssd1306_command(0x22); } 332 | else 333 | { ssd1306_command(0xF1); } 334 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 335 | ssd1306_command(0x40); 336 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 337 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 338 | #endif 339 | 340 | #if defined SSD1306_96_16 341 | // Init sequence for 96x16 OLED module 342 | ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE 343 | ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 344 | ssd1306_command(0x80); // the suggested ratio 0x80 345 | ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 346 | ssd1306_command(0x0F); 347 | ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 348 | ssd1306_command(0x00); // no offset 349 | ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 350 | ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D 351 | if (vccstate == SSD1306_EXTERNALVCC) 352 | { ssd1306_command(0x10); } 353 | else 354 | { ssd1306_command(0x14); } 355 | ssd1306_command(SSD1306_MEMORYMODE); // 0x20 356 | ssd1306_command(0x00); // 0x0 act like ks0108 357 | ssd1306_command(SSD1306_SEGREMAP | 0x1); 358 | ssd1306_command(SSD1306_COMSCANDEC); 359 | ssd1306_command(SSD1306_SETCOMPINS); // 0xDA 360 | ssd1306_command(0x2); //ada x12 361 | ssd1306_command(SSD1306_SETCONTRAST); // 0x81 362 | if (vccstate == SSD1306_EXTERNALVCC) 363 | { ssd1306_command(0x10); } 364 | else 365 | { ssd1306_command(0xAF); } 366 | ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 367 | if (vccstate == SSD1306_EXTERNALVCC) 368 | { ssd1306_command(0x22); } 369 | else 370 | { ssd1306_command(0xF1); } 371 | ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB 372 | ssd1306_command(0x40); 373 | ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 374 | ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 375 | #endif 376 | 377 | ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel 378 | } 379 | 380 | 381 | void Adafruit_SSD1306::invertDisplay(uint8_t i) { 382 | if (i) { 383 | ssd1306_command(SSD1306_INVERTDISPLAY); 384 | } else { 385 | ssd1306_command(SSD1306_NORMALDISPLAY); 386 | } 387 | } 388 | 389 | void Adafruit_SSD1306::ssd1306_command(uint8_t c) { 390 | // I2C 391 | uint8_t control = 0x00; // Co = 0, D/C = 0 392 | Wire.beginTransmission(_i2caddr); 393 | WIRE_WRITE(control); 394 | WIRE_WRITE(c); 395 | Wire.endTransmission(); 396 | 397 | } 398 | 399 | // startscrollright 400 | // Activate a right handed scroll for rows start through stop 401 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 402 | // display.scrollright(0x00, 0x0F) 403 | void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){ 404 | ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL); 405 | ssd1306_command(0X00); 406 | ssd1306_command(start); 407 | ssd1306_command(0X00); 408 | ssd1306_command(stop); 409 | ssd1306_command(0X00); 410 | ssd1306_command(0XFF); 411 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 412 | } 413 | 414 | // startscrollleft 415 | // Activate a right handed scroll for rows start through stop 416 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 417 | // display.scrollright(0x00, 0x0F) 418 | void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){ 419 | ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL); 420 | ssd1306_command(0X00); 421 | ssd1306_command(start); 422 | ssd1306_command(0X00); 423 | ssd1306_command(stop); 424 | ssd1306_command(0X00); 425 | ssd1306_command(0XFF); 426 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 427 | } 428 | 429 | // startscrolldiagright 430 | // Activate a diagonal scroll for rows start through stop 431 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 432 | // display.scrollright(0x00, 0x0F) 433 | void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ 434 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 435 | ssd1306_command(0X00); 436 | ssd1306_command(SSD1306_LCDHEIGHT); 437 | ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); 438 | ssd1306_command(0X00); 439 | ssd1306_command(start); 440 | ssd1306_command(0X00); 441 | ssd1306_command(stop); 442 | ssd1306_command(0X01); 443 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 444 | } 445 | 446 | // startscrolldiagleft 447 | // Activate a diagonal scroll for rows start through stop 448 | // Hint, the display is 16 rows tall. To scroll the whole display, run: 449 | // display.scrollright(0x00, 0x0F) 450 | void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ 451 | ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); 452 | ssd1306_command(0X00); 453 | ssd1306_command(SSD1306_LCDHEIGHT); 454 | ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); 455 | ssd1306_command(0X00); 456 | ssd1306_command(start); 457 | ssd1306_command(0X00); 458 | ssd1306_command(stop); 459 | ssd1306_command(0X01); 460 | ssd1306_command(SSD1306_ACTIVATE_SCROLL); 461 | } 462 | 463 | void Adafruit_SSD1306::stopscroll(void){ 464 | ssd1306_command(SSD1306_DEACTIVATE_SCROLL); 465 | } 466 | 467 | // Dim the display 468 | // dim = true: display is dimmed 469 | // dim = false: display is normal 470 | void Adafruit_SSD1306::dim(boolean dim) { 471 | uint8_t contrast; 472 | 473 | if (dim) { 474 | contrast = 0; // Dimmed display 475 | } else { 476 | if (_vccstate == SSD1306_EXTERNALVCC) { 477 | contrast = 0x9F; 478 | } else { 479 | contrast = 0xCF; 480 | } 481 | } 482 | // the range of contrast to too small to be really useful 483 | // it is useful to dim the display 484 | ssd1306_command(SSD1306_SETCONTRAST); 485 | ssd1306_command(contrast); 486 | } 487 | 488 | void Adafruit_SSD1306::ssd1306_data(uint8_t c) { 489 | // I2C 490 | uint8_t control = 0x40; // Co = 0, D/C = 1 491 | Wire.beginTransmission(_i2caddr); 492 | WIRE_WRITE(control); 493 | WIRE_WRITE(c); 494 | Wire.endTransmission(); 495 | 496 | } 497 | 498 | void Adafruit_SSD1306::display(void) { 499 | ssd1306_command(SSD1306_COLUMNADDR); 500 | ssd1306_command(0); // Column start address (0 = reset) 501 | ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) 502 | 503 | ssd1306_command(SSD1306_PAGEADDR); 504 | ssd1306_command(0); // Page start address (0 = reset) 505 | #if SSD1306_LCDHEIGHT == 64 506 | ssd1306_command(7); // Page end address 507 | #endif 508 | #if SSD1306_LCDHEIGHT == 32 509 | ssd1306_command(3); // Page end address 510 | #endif 511 | #if SSD1306_LCDHEIGHT == 16 512 | ssd1306_command(1); // Page end address 513 | #endif 514 | 515 | // I2C 516 | for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { 517 | // send a bunch of data in one xmission 518 | Wire.beginTransmission(_i2caddr); 519 | WIRE_WRITE(0x40); 520 | for (uint8_t x=0; x<16; x++) { 521 | WIRE_WRITE(buffer[i]); 522 | i++; 523 | } 524 | i--; 525 | Wire.endTransmission(); 526 | } 527 | } 528 | 529 | // clear everything 530 | void Adafruit_SSD1306::clearDisplay(void) { 531 | memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); 532 | } 533 | 534 | 535 | inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) { 536 | 537 | /* if(hwSPI) { 538 | (void)SPI.transfer(d); 539 | } else { 540 | for(uint8_t bit = 0x80; bit; bit >>= 1) { 541 | *clkport &= ~clkpinmask; 542 | if(d & bit) *mosiport |= mosipinmask; 543 | else *mosiport &= ~mosipinmask; 544 | *clkport |= clkpinmask; 545 | } 546 | } 547 | //*csport |= cspinmask; */ 548 | } 549 | 550 | void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { 551 | boolean bSwap = false; 552 | switch(rotation) { 553 | case 0: 554 | // 0 degree rotation, do nothing 555 | break; 556 | case 1: 557 | // 90 degree rotation, swap x & y for rotation, then invert x 558 | bSwap = true; 559 | // swap(x, y); 560 | x = WIDTH - x - 1; 561 | break; 562 | case 2: 563 | // 180 degree rotation, invert x and y - then shift y around for height. 564 | x = WIDTH - x - 1; 565 | y = HEIGHT - y - 1; 566 | x -= (w-1); 567 | break; 568 | case 3: 569 | // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h) 570 | bSwap = true; 571 | //swap(x, y); 572 | y = HEIGHT - y - 1; 573 | y -= (w-1); 574 | break; 575 | } 576 | 577 | if(bSwap) { 578 | drawFastVLineInternal(x, y, w, color); 579 | } else { 580 | drawFastHLineInternal(x, y, w, color); 581 | } 582 | } 583 | 584 | void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) { 585 | // Do bounds/limit checks 586 | if(y < 0 || y >= HEIGHT) { return; } 587 | 588 | // make sure we don't try to draw below 0 589 | if(x < 0) { 590 | w += x; 591 | x = 0; 592 | } 593 | 594 | // make sure we don't go off the edge of the display 595 | if( (x + w) > WIDTH) { 596 | w = (WIDTH - x); 597 | } 598 | 599 | // if our width is now negative, punt 600 | if(w <= 0) { return; } 601 | 602 | // set up the pointer for movement through the buffer 603 | register uint8_t *pBuf = buffer; 604 | // adjust the buffer pointer for the current row 605 | pBuf += ((y/8) * SSD1306_LCDWIDTH); 606 | // and offset x columns in 607 | pBuf += x; 608 | 609 | register uint8_t mask = 1 << (y&7); 610 | 611 | switch (color) 612 | { 613 | case WHITE: while(w--) { *pBuf++ |= mask; }; break; 614 | case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break; 615 | case INVERSE: while(w--) { *pBuf++ ^= mask; }; break; 616 | } 617 | } 618 | 619 | void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { 620 | bool bSwap = false; 621 | switch(rotation) { 622 | case 0: 623 | break; 624 | case 1: 625 | // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w) 626 | bSwap = true; 627 | // swap(x, y); 628 | x = WIDTH - x - 1; 629 | x -= (h-1); 630 | break; 631 | case 2: 632 | // 180 degree rotation, invert x and y - then shift y around for height. 633 | x = WIDTH - x - 1; 634 | y = HEIGHT - y - 1; 635 | y -= (h-1); 636 | break; 637 | case 3: 638 | // 270 degree rotation, swap x & y for rotation, then invert y 639 | bSwap = true; 640 | //swap(x, y); 641 | y = HEIGHT - y - 1; 642 | break; 643 | } 644 | 645 | if(bSwap) { 646 | drawFastHLineInternal(x, y, h, color); 647 | } else { 648 | drawFastVLineInternal(x, y, h, color); 649 | } 650 | } 651 | 652 | 653 | void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) { 654 | 655 | // do nothing if we're off the left or right side of the screen 656 | if(x < 0 || x >= WIDTH) { return; } 657 | 658 | // make sure we don't try to draw below 0 659 | if(__y < 0) { 660 | // __y is negative, this will subtract enough from __h to account for __y being 0 661 | __h += __y; 662 | __y = 0; 663 | 664 | } 665 | 666 | // make sure we don't go past the height of the display 667 | if( (__y + __h) > HEIGHT) { 668 | __h = (HEIGHT - __y); 669 | } 670 | 671 | // if our height is now negative, punt 672 | if(__h <= 0) { 673 | return; 674 | } 675 | 676 | // this display doesn't need ints for coordinates, use local byte registers for faster juggling 677 | register uint8_t y = __y; 678 | register uint8_t h = __h; 679 | 680 | 681 | // set up the pointer for fast movement through the buffer 682 | register uint8_t *pBuf = buffer; 683 | // adjust the buffer pointer for the current row 684 | pBuf += ((y/8) * SSD1306_LCDWIDTH); 685 | // and offset x columns in 686 | pBuf += x; 687 | 688 | // do the first partial byte, if necessary - this requires some masking 689 | register uint8_t mod = (y&7); 690 | if(mod) { 691 | // mask off the high n bits we want to set 692 | mod = 8-mod; 693 | 694 | // note - lookup table results in a nearly 10% performance improvement in fill* functions 695 | // register uint8_t mask = ~(0xFF >> (mod)); 696 | static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; 697 | register uint8_t mask = premask[mod]; 698 | 699 | // adjust the mask if we're not going to reach the end of this byte 700 | if( h < mod) { 701 | mask &= (0XFF >> (mod-h)); 702 | } 703 | 704 | switch (color) 705 | { 706 | case WHITE: *pBuf |= mask; break; 707 | case BLACK: *pBuf &= ~mask; break; 708 | case INVERSE: *pBuf ^= mask; break; 709 | } 710 | 711 | // fast exit if we're done here! 712 | if(h= 8) { 722 | 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 723 | do { 724 | *pBuf=~(*pBuf); 725 | 726 | // adjust the buffer forward 8 rows worth of data 727 | pBuf += SSD1306_LCDWIDTH; 728 | 729 | // 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) 730 | h -= 8; 731 | } while(h >= 8); 732 | } 733 | else { 734 | // store a local value to work with 735 | register uint8_t val = (color == WHITE) ? 255 : 0; 736 | 737 | do { 738 | // write our value in 739 | *pBuf = val; 740 | 741 | // adjust the buffer forward 8 rows worth of data 742 | pBuf += SSD1306_LCDWIDTH; 743 | 744 | // 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) 745 | h -= 8; 746 | } while(h >= 8); 747 | } 748 | } 749 | 750 | // now do the final partial byte, if necessary 751 | if(h) { 752 | mod = h & 7; 753 | // this time we want to mask the low bits of the byte, vs the high bits we did above 754 | // register uint8_t mask = (1 << mod) - 1; 755 | // note - lookup table results in a nearly 10% performance improvement in fill* functions 756 | static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; 757 | register uint8_t mask = postmask[mod]; 758 | switch (color) 759 | { 760 | case WHITE: *pBuf |= mask; break; 761 | case BLACK: *pBuf &= ~mask; break; 762 | case INVERSE: *pBuf ^= mask; break; 763 | } 764 | } 765 | } 766 | --------------------------------------------------------------------------------