source: azure_iot_hub/trunk/asp3_dcre/gdic/adafruit_ssd1306/adafruit_ssd1306.c@ 389

Last change on this file since 389 was 389, checked in by coas-nagasima, 5 years ago

ビルドが通るよう更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 23.1 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
19#include <string.h>
20#include <kernel.h>
21#include <t_syslog.h>
22#include <t_stdlib.h>
23#include <target_syssvc.h>
24#include "syssvc/serial.h"
25#include "syssvc/syslog.h"
26#include "adafruit_ssd1306.h"
27
28#define HIGH 1
29#define LOW 0
30
31uint16_t lcd_init_height = SSD1306_LCDHEIGHT;
32uint16_t lcd_init_width = SSD1306_LCDWIDTH;
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
107void lcd_fastSPIwrite(LCD_Handler_t *lcd, uint8_t d);
108#define lcd_swap(a, b) { int16_t t = a; a = b; b = t; }
109
110// the most basic function, set a single pixel
111void lcd_drawPixel(LCD_Handler_t *lcd, int16_t x, int16_t y, uint16_t color) {
112 if ((x < 0) || (x >= lcd->_width) || (y < 0) || (y >= lcd->_height))
113 return;
114
115 // check rotation, move pixel around if necessary
116 switch (lcd->rotation) {
117 case 1:
118 lcd_swap(x, y);
119 x = lcd->_width - x - 1;
120 break;
121 case 2:
122 x = lcd->_width - x - 1;
123 y = lcd->_height - y - 1;
124 break;
125 case 3:
126 lcd_swap(x, y);
127 y = lcd->_height - y - 1;
128 break;
129 }
130
131 // x is which column
132 switch (color)
133 {
134 case WHITE: buffer[x + (y / 8)*SSD1306_LCDWIDTH] |= (1 << (y & 7)); break;
135 case BLACK: buffer[x + (y / 8)*SSD1306_LCDWIDTH] &= ~(1 << (y & 7)); break;
136 case INVERSE: buffer[x + (y / 8)*SSD1306_LCDWIDTH] ^= (1 << (y & 7)); break;
137 }
138}
139
140void lcd_init1(LCD_Handler_t *lcd, int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS)
141{
142 lcd->_width = SSD1306_LCDWIDTH;
143 lcd->_height = SSD1306_LCDHEIGHT;
144 gpio_init(&lcd->cs, CS);
145 gpio_init(&lcd->rst, RST);
146 gpio_init(&lcd->dc, DC);
147 gpio_init(&lcd->sclk, SCLK);
148 gpio_init(&lcd->sid, SID);
149 lcd->hwSPI = false;
150}
151
152// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset
153void lcd_init2(LCD_Handler_t *lcd, int8_t DC, int8_t RST, int8_t CS)
154{
155 lcd->_width = SSD1306_LCDWIDTH;
156 lcd->_height = SSD1306_LCDHEIGHT;
157 gpio_init(&lcd->dc, DC);
158 gpio_init(&lcd->rst, RST);
159 gpio_init(&lcd->cs, CS);
160 lcd->hwSPI = true;
161}
162
163// initializer for I2C - we only indicate the reset pin!
164void lcd_init3(LCD_Handler_t *lcd, int8_t reset)
165{
166 lcd->_width = SSD1306_LCDWIDTH;
167 lcd->_height = SSD1306_LCDHEIGHT;
168 gpio_init(&lcd->sclk, NC);
169 gpio_init(&lcd->dc, NC);
170 gpio_init(&lcd->cs, NC);
171 gpio_init(&lcd->sid, NC);
172 gpio_init(&lcd->rst, reset);
173}
174
175void lcd_begin(LCD_Handler_t *lcd, uint8_t vccstate, uint8_t i2caddr, bool reset) {
176 lcd->_vccstate = vccstate;
177 lcd->_i2caddr = i2caddr;
178
179 // set pin directions
180 if (lcd->sid.pin != NC) {
181 gpio_dir(&lcd->dc, PIN_OUTPUT);
182 gpio_dir(&lcd->cs, PIN_OUTPUT);
183 if (!lcd->hwSPI) {
184 // set pins for software-SPI
185 gpio_dir(&lcd->sid, PIN_OUTPUT);
186 gpio_dir(&lcd->sclk, PIN_OUTPUT);
187 }
188 if (lcd->hwSPI) {
189 spi_format(&lcd->spi, 8, 0, 0);
190 spi_master_write(&lcd->spi, 8000000);
191 }
192 }
193 else
194 {
195 // I2C Init
196 //i2c_begin(&lcd->i2c);
197#ifdef __SAM3X8E__
198 // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL)
199 TWI1->TWI_CWGR = 0;
200 TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101;
201#endif
202 }
203 if ((reset) && (lcd->rst.pin != NC)) {
204 // Setup reset pin direction (used by both SPI and I2C)
205 gpio_dir(&lcd->rst, PIN_OUTPUT);
206 gpio_write(&lcd->rst, HIGH);
207 // VDD (3.3V) goes high at start, lets just chill for a ms
208 dly_tsk(1 * 1000);
209 // bring reset low
210 gpio_write(&lcd->rst, LOW);
211 // wait 10ms
212 dly_tsk(10 * 1000);
213 // bring out of reset
214 gpio_write(&lcd->rst, HIGH);
215 // turn on VCC (9V?)
216 }
217
218 // Init sequence
219 lcd_command(lcd, SSD1306_DISPLAYOFF); // 0xAE
220 lcd_command(lcd, SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
221 lcd_command(lcd, 0x80); // the suggested ratio 0x80
222
223 lcd_command(lcd, SSD1306_SETMULTIPLEX); // 0xA8
224 lcd_command(lcd, SSD1306_LCDHEIGHT - 1);
225
226 lcd_command(lcd, SSD1306_SETDISPLAYOFFSET); // 0xD3
227 lcd_command(lcd, 0x0); // no offset
228 lcd_command(lcd, SSD1306_SETSTARTLINE | 0x0); // line #0
229 lcd_command(lcd, SSD1306_CHARGEPUMP); // 0x8D
230 if (vccstate == SSD1306_EXTERNALVCC)
231 {
232 lcd_command(lcd, 0x10);
233 }
234 else
235 {
236 lcd_command(lcd, 0x14);
237 }
238 lcd_command(lcd, SSD1306_MEMORYMODE); // 0x20
239 lcd_command(lcd, 0x00); // 0x0 act like ks0108
240 lcd_command(lcd, SSD1306_SEGREMAP | 0x1);
241 lcd_command(lcd, SSD1306_COMSCANDEC);
242
243#if defined SSD1306_128_32
244 lcd_command(lcd, SSD1306_SETCOMPINS); // 0xDA
245 lcd_command(lcd, 0x02);
246 lcd_command(lcd, SSD1306_SETCONTRAST); // 0x81
247 lcd_command(lcd, 0x8F);
248
249#elif defined SSD1306_128_64
250 lcd_command(lcd, SSD1306_SETCOMPINS); // 0xDA
251 lcd_command(lcd, 0x12);
252 lcd_command(lcd, SSD1306_SETCONTRAST); // 0x81
253 if (vccstate == SSD1306_EXTERNALVCC)
254 {
255 lcd_command(lcd, 0x9F);
256 }
257 else
258 {
259 lcd_command(lcd, 0xCF);
260 }
261
262#elif defined SSD1306_96_16
263 lcd_command(lcd, SSD1306_SETCOMPINS); // 0xDA
264 lcd_command(lcd, 0x2); //ada x12
265 lcd_command(lcd, SSD1306_SETCONTRAST); // 0x81
266 if (vccstate == SSD1306_EXTERNALVCC)
267 {
268 lcd_command(lcd, 0x10);
269 }
270 else
271 {
272 lcd_command(lcd, 0xAF);
273 }
274
275#endif
276
277 lcd_command(lcd, SSD1306_SETPRECHARGE); // 0xd9
278 if (vccstate == SSD1306_EXTERNALVCC)
279 {
280 lcd_command(lcd, 0x22);
281 }
282 else
283 {
284 lcd_command(lcd, 0xF1);
285 }
286 lcd_command(lcd, SSD1306_SETVCOMDETECT); // 0xDB
287 lcd_command(lcd, 0x40);
288 lcd_command(lcd, SSD1306_DISPLAYALLON_RESUME); // 0xA4
289 lcd_command(lcd, SSD1306_NORMALDISPLAY); // 0xA6
290
291 lcd_command(lcd, SSD1306_DEACTIVATE_SCROLL);
292
293 lcd_command(lcd, SSD1306_DISPLAYON);//--turn on oled panel
294}
295
296
297void lcd_invertDisplay(LCD_Handler_t *lcd, uint8_t i) {
298 if (i) {
299 lcd_command(lcd, SSD1306_INVERTDISPLAY);
300 }
301 else {
302 lcd_command(lcd, SSD1306_NORMALDISPLAY);
303 }
304}
305
306void lcd_command(LCD_Handler_t *lcd, uint8_t c) {
307 if (lcd->sid.pin != NC)
308 {
309 // SPI
310 gpio_write(&lcd->cs, HIGH);
311 gpio_write(&lcd->dc, LOW);
312 gpio_write(&lcd->cs, LOW);
313 lcd_fastSPIwrite(lcd, c);
314 gpio_write(&lcd->cs, HIGH);
315 }
316 else
317 {
318 // I2C
319 uint8_t data[2] = { 0x00/* Co = 0, D/C = 0*/, c };
320 i2c_write(&lcd->i2c, lcd->_i2caddr, data, sizeof(data), 1);
321 }
322}
323
324// startscrollright
325// Activate a right handed scroll for rows start through stop
326// Hint, the display is 16 rows tall. To scroll the whole display, run:
327// display.scrollright(0x00, 0x0F)
328void lcd_startscrollright(LCD_Handler_t *lcd, uint8_t start, uint8_t stop) {
329 lcd_command(lcd, SSD1306_RIGHT_HORIZONTAL_SCROLL);
330 lcd_command(lcd, 0X00);
331 lcd_command(lcd, start);
332 lcd_command(lcd, 0X00);
333 lcd_command(lcd, stop);
334 lcd_command(lcd, 0X00);
335 lcd_command(lcd, 0XFF);
336 lcd_command(lcd, SSD1306_ACTIVATE_SCROLL);
337}
338
339// startscrollleft
340// Activate a right handed scroll for rows start through stop
341// Hint, the display is 16 rows tall. To scroll the whole display, run:
342// display.scrollright(0x00, 0x0F)
343void lcd_startscrollleft(LCD_Handler_t *lcd, uint8_t start, uint8_t stop) {
344 lcd_command(lcd, SSD1306_LEFT_HORIZONTAL_SCROLL);
345 lcd_command(lcd, 0X00);
346 lcd_command(lcd, start);
347 lcd_command(lcd, 0X00);
348 lcd_command(lcd, stop);
349 lcd_command(lcd, 0X00);
350 lcd_command(lcd, 0XFF);
351 lcd_command(lcd, SSD1306_ACTIVATE_SCROLL);
352}
353
354// startscrolldiagright
355// Activate a diagonal scroll for rows start through stop
356// Hint, the display is 16 rows tall. To scroll the whole display, run:
357// display.scrollright(0x00, 0x0F)
358void lcd_startscrolldiagright(LCD_Handler_t *lcd, uint8_t start, uint8_t stop) {
359 lcd_command(lcd, SSD1306_SET_VERTICAL_SCROLL_AREA);
360 lcd_command(lcd, 0X00);
361 lcd_command(lcd, SSD1306_LCDHEIGHT);
362 lcd_command(lcd, SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
363 lcd_command(lcd, 0X00);
364 lcd_command(lcd, start);
365 lcd_command(lcd, 0X00);
366 lcd_command(lcd, stop);
367 lcd_command(lcd, 0X01);
368 lcd_command(lcd, SSD1306_ACTIVATE_SCROLL);
369}
370
371// startscrolldiagleft
372// Activate a diagonal scroll for rows start through stop
373// Hint, the display is 16 rows tall. To scroll the whole display, run:
374// display.scrollright(0x00, 0x0F)
375void lcd_startscrolldiagleft(LCD_Handler_t *lcd, uint8_t start, uint8_t stop) {
376 lcd_command(lcd, SSD1306_SET_VERTICAL_SCROLL_AREA);
377 lcd_command(lcd, 0X00);
378 lcd_command(lcd, SSD1306_LCDHEIGHT);
379 lcd_command(lcd, SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
380 lcd_command(lcd, 0X00);
381 lcd_command(lcd, start);
382 lcd_command(lcd, 0X00);
383 lcd_command(lcd, stop);
384 lcd_command(lcd, 0X01);
385 lcd_command(lcd, SSD1306_ACTIVATE_SCROLL);
386}
387
388void lcd_stopscroll(LCD_Handler_t *lcd) {
389 lcd_command(lcd, SSD1306_DEACTIVATE_SCROLL);
390}
391
392// Dim the display
393// dim = true: display is dimmed
394// dim = false: display is normal
395void lcd_dim(LCD_Handler_t *lcd, bool dim) {
396 uint8_t contrast;
397
398 if (dim) {
399 contrast = 0; // Dimmed display
400 }
401 else {
402 if (lcd->_vccstate == SSD1306_EXTERNALVCC) {
403 contrast = 0x9F;
404 }
405 else {
406 contrast = 0xCF;
407 }
408 }
409 // the range of contrast to too small to be really useful
410 // it is useful to dim the display
411 lcd_command(lcd, SSD1306_SETCONTRAST);
412 lcd_command(lcd, contrast);
413}
414
415void lcd_display(LCD_Handler_t *lcd) {
416 lcd_command(lcd, SSD1306_COLUMNADDR);
417 lcd_command(lcd, 0); // Column start address (0 = reset)
418 lcd_command(lcd, SSD1306_LCDWIDTH - 1); // Column end address (127 = reset)
419
420 lcd_command(lcd, SSD1306_PAGEADDR);
421 lcd_command(lcd, 0); // Page start address (0 = reset)
422#if SSD1306_LCDHEIGHT == 64
423 lcd_command(lcd, 7); // Page end address
424#endif
425#if SSD1306_LCDHEIGHT == 32
426 lcd_command(lcd, 3); // Page end address
427#endif
428#if SSD1306_LCDHEIGHT == 16
429 lcd_command(lcd, 1); // Page end address
430#endif
431
432 if (lcd->sid.pin != NC)
433 {
434 // SPI
435 gpio_write(&lcd->cs, HIGH);
436 gpio_write(&lcd->dc, HIGH);
437 gpio_write(&lcd->cs, LOW);
438
439 for (uint16_t i = 0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT / 8); i++) {
440 lcd_fastSPIwrite(lcd, buffer[i]);
441 }
442 gpio_write(&lcd->cs, HIGH);
443 }
444 else
445 {
446 // save I2C bitrate
447#ifdef TWBR
448 uint8_t twbrbackup = TWBR;
449 TWBR = 12; // upgrade to 400KHz!
450#endif
451 //Serial.println(TWBR, DEC);
452 //Serial.println(TWSR & 0x3, DEC);
453
454 // I2C
455 uint8_t data[17] = { 0x40, };
456 for (uint16_t i = 0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT / 8); i+=16) {
457 // send a bunch of data in one xmission
458 memcpy(&data[1], &buffer[i], 16);
459 i2c_write(&lcd->i2c, lcd->_i2caddr, data, sizeof(data), 1);
460 }
461#ifdef TWBR
462 TWBR = twbrbackup;
463#endif
464 }
465}
466
467// clear everything
468void lcd_clearDisplay(LCD_Handler_t *lcd) {
469 memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT / 8));
470}
471
472void lcd_fastSPIwrite(LCD_Handler_t *lcd, uint8_t d)
473{
474 if (lcd->hwSPI) {
475 spi_master_write(&lcd->spi, d);
476 }
477 else {
478 for (uint8_t bit = 0x80; bit; bit >>= 1) {
479 gpio_write(&lcd->sclk, LOW);
480 if (d & bit) gpio_write(&lcd->sid, HIGH);
481 else gpio_write(&lcd->sid, LOW);
482 gpio_write(&lcd->sclk, HIGH);
483 }
484 }
485}
486
487void lcd_drawFastHLine(LCD_Handler_t *lcd, int16_t x, int16_t y, int16_t w, uint16_t color) {
488 bool bSwap = false;
489 switch (lcd->rotation) {
490 case 0:
491 // 0 degree rotation, do nothing
492 break;
493 case 1:
494 // 90 degree rotation, swap x & y for rotation, then invert x
495 bSwap = true;
496 lcd_swap(x, y);
497 x = lcd->_width - x - 1;
498 break;
499 case 2:
500 // 180 degree rotation, invert x and y - then shift y around for height.
501 x = lcd->_width - x - 1;
502 y = lcd->_height - y - 1;
503 x -= (w - 1);
504 break;
505 case 3:
506 // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h)
507 bSwap = true;
508 lcd_swap(x, y);
509 y = lcd->_height - y - 1;
510 y -= (w - 1);
511 break;
512 }
513
514 if (bSwap) {
515 lcd_drawFastVLineInternal(lcd, x, y, w, color);
516 }
517 else {
518 lcd_drawFastHLineInternal(lcd, x, y, w, color);
519 }
520}
521
522void lcd_drawFastHLineInternal(LCD_Handler_t *lcd, int16_t x, int16_t y, int16_t w, uint16_t color) {
523 // Do bounds/limit checks
524 if (y < 0 || y >= lcd->_height) { return; }
525
526 // make sure we don't try to draw below 0
527 if (x < 0) {
528 w += x;
529 x = 0;
530 }
531
532 // make sure we don't go off the edge of the display
533 if ((x + w) > lcd->_width) {
534 w = (lcd->_width - x);
535 }
536
537 // if our width is now negative, punt
538 if (w <= 0) { return; }
539
540 // set up the pointer for movement through the buffer
541 register uint8_t *pBuf = buffer;
542 // adjust the buffer pointer for the current row
543 pBuf += ((y / 8) * SSD1306_LCDWIDTH);
544 // and offset x columns in
545 pBuf += x;
546
547 register uint8_t mask = 1 << (y & 7);
548
549 switch (color)
550 {
551 case WHITE: while (w--) { *pBuf++ |= mask; }; break;
552 case BLACK: mask = ~mask; while (w--) { *pBuf++ &= mask; }; break;
553 case INVERSE: while (w--) { *pBuf++ ^= mask; }; break;
554 }
555}
556
557void lcd_drawFastVLine(LCD_Handler_t *lcd, int16_t x, int16_t y, int16_t h, uint16_t color) {
558 bool bSwap = false;
559 switch (lcd->rotation) {
560 case 0:
561 break;
562 case 1:
563 // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
564 bSwap = true;
565 lcd_swap(x, y);
566 x = lcd->_width - x - 1;
567 x -= (h - 1);
568 break;
569 case 2:
570 // 180 degree rotation, invert x and y - then shift y around for height.
571 x = lcd->_width - x - 1;
572 y = lcd->_height - y - 1;
573 y -= (h - 1);
574 break;
575 case 3:
576 // 270 degree rotation, swap x & y for rotation, then invert y
577 bSwap = true;
578 lcd_swap(x, y);
579 y = lcd->_height - y - 1;
580 break;
581 }
582
583 if (bSwap) {
584 lcd_drawFastHLineInternal(lcd, x, y, h, color);
585 }
586 else {
587 lcd_drawFastVLineInternal(lcd, x, y, h, color);
588 }
589}
590
591
592void lcd_drawFastVLineInternal(LCD_Handler_t *lcd, int16_t x, int16_t __y, int16_t __h, uint16_t color) {
593
594 // do nothing if we're off the left or right side of the screen
595 if (x < 0 || x >= lcd->_width) { return; }
596
597 // make sure we don't try to draw below 0
598 if (__y < 0) {
599 // __y is negative, this will subtract enough from __h to account for __y being 0
600 __h += __y;
601 __y = 0;
602
603 }
604
605 // make sure we don't go past the height of the display
606 if ((__y + __h) > lcd->_height) {
607 __h = (lcd->_height - __y);
608 }
609
610 // if our height is now negative, punt
611 if (__h <= 0) {
612 return;
613 }
614
615 // this display doesn't need ints for coordinates, use local byte registers for faster juggling
616 register uint8_t y = __y;
617 register uint8_t h = __h;
618
619
620 // set up the pointer for fast movement through the buffer
621 register uint8_t *pBuf = buffer;
622 // adjust the buffer pointer for the current row
623 pBuf += ((y / 8) * SSD1306_LCDWIDTH);
624 // and offset x columns in
625 pBuf += x;
626
627 // do the first partial byte, if necessary - this requires some masking
628 register uint8_t mod = (y & 7);
629 if (mod) {
630 // mask off the high n bits we want to set
631 mod = 8 - mod;
632
633 // note - lookup table results in a nearly 10% performance improvement in fill* functions
634 // register uint8_t mask = ~(0xFF >> (mod));
635 static uint8_t premask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
636 register uint8_t mask = premask[mod];
637
638 // adjust the mask if we're not going to reach the end of this byte
639 if (h < mod) {
640 mask &= (0XFF >> (mod - h));
641 }
642
643 switch (color)
644 {
645 case WHITE: *pBuf |= mask; break;
646 case BLACK: *pBuf &= ~mask; break;
647 case INVERSE: *pBuf ^= mask; break;
648 }
649
650 // fast exit if we're done here!
651 if (h < mod) { return; }
652
653 h -= mod;
654
655 pBuf += SSD1306_LCDWIDTH;
656 }
657
658 // write solid bytes while we can - effectively doing 8 rows at a time
659 if (h >= 8) {
660 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
661 do {
662 *pBuf = ~(*pBuf);
663
664 // adjust the buffer forward 8 rows worth of data
665 pBuf += SSD1306_LCDWIDTH;
666
667 // 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)
668 h -= 8;
669 } while (h >= 8);
670 }
671 else {
672 // store a local value to work with
673 register uint8_t val = (color == WHITE) ? 255 : 0;
674
675 do {
676 // write our value in
677 *pBuf = val;
678
679 // adjust the buffer forward 8 rows worth of data
680 pBuf += SSD1306_LCDWIDTH;
681
682 // 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)
683 h -= 8;
684 } while (h >= 8);
685 }
686 }
687
688 // now do the final partial byte, if necessary
689 if (h) {
690 mod = h & 7;
691 // this time we want to mask the low bits of the byte, vs the high bits we did above
692 // register uint8_t mask = (1 << mod) - 1;
693 // note - lookup table results in a nearly 10% performance improvement in fill* functions
694 static uint8_t postmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
695 register uint8_t mask = postmask[mod];
696 switch (color)
697 {
698 case WHITE: *pBuf |= mask; break;
699 case BLACK: *pBuf &= ~mask; break;
700 case INVERSE: *pBuf ^= mask; break;
701 }
702 }
703}
Note: See TracBrowser for help on using the repository browser.