source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/gdic/adafruit_ssd1306/adafruit_ssd1306.c@ 364

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

TINETとSocket APIなどを更新

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