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