source: rtos_arduino/trunk/arduino_lib/libraries/LuckyShield/src/lib/Adafruit_SSD1306.cpp@ 175

Last change on this file since 175 was 175, checked in by ertl-honda, 8 years ago

ライブラリを Arduino IDE 1.7.9 にupdate

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