Subversion Repositories DashDisplay

Rev

Rev 28 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
/*********************************************************************
4 mjames 2
 This is a library for our Monochrome OLEDs based on SSD1306 drivers
2 mjames 3
 
4 mjames 4
 Pick one up today in the adafruit shop!
5
 ------> http://www.adafruit.com/category/63_98
2 mjames 6
 
4 mjames 7
 These displays use SPI to communicate, 4 or 5 pins are required to
8
 interface
2 mjames 9
 
4 mjames 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!
2 mjames 13
 
4 mjames 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
2 mjames 17
 
4 mjames 18
 This code is taken from the ADAfruit library - it is used for playing with an OLED screen
2 mjames 19
 
4 mjames 20
 *********************************************************************/
2 mjames 21
#include <stdint.h>
22
#include <string.h>
5 mjames 23
#include "SSD1306.h"
30 mjames 24
#include "stm32l1xx_hal.h"
2 mjames 25
 
5 mjames 26
 
2 mjames 27
#define swap(x,y) { typeof(x)t = x; x=y; y=t; }
28
#define abs(x)      ((x)>0?(x):-(x))
29
 
30
static uint8_t rotation = 0;
4 mjames 31
const uint16_t WIDTH = SSD1306_LCDWIDTH;
2 mjames 32
const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
33
 
34
extern SPI_HandleTypeDef hspi1;
35
 
36
// the memory buffer for the LCD
37
 
38
// pointer to the current display - affects buffer used and also chipselect
39
static int cd = 0;
40
 
4 mjames 41
uint8_t display_buffer[MAX_PHYS_DISPLAYS][SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH
42
                / 8];
2 mjames 43
 
4 mjames 44
inline uint8_t * display_address(void) {
45
        return (uint8_t *) (&display_buffer[cd]);
2 mjames 46
}
47
 
4 mjames 48
inline uint8_t getRotation(void) {
2 mjames 49
        return rotation;
50
}
51
 
4 mjames 52
inline int16_t width(void) {
53
        switch (rotation) {
2 mjames 54
        case 0:
55
                return WIDTH;
56
                break;
57
        case 1:
58
                return WIDTH;
59
                break;
60
        case 2:
61
                return HEIGHT;
62
                break;
63
        case 3:
64
                return -WIDTH;
65
                break;
4 mjames 66
        }
67
        return 0;
2 mjames 68
}
69
 
4 mjames 70
inline int16_t height(void) {
71
        switch (rotation) {
2 mjames 72
        case 0:
73
                return HEIGHT;
74
                break;
75
        case 1:
76
                return HEIGHT;
77
                break;
78
        case 2:
79
                return WIDTH;
80
                break;
81
        case 3:
82
                return -HEIGHT;
83
                break;
4 mjames 84
        }
2 mjames 85
        return 0;
86
}
87
 
4 mjames 88
inline void fastSPIwrite(uint8_t d) {
89
        uint8_t buffer[1];
90
        buffer[0] = d;
2 mjames 91
// todo chipselect based on 'cd' buffer choice
5 mjames 92
   if(cd==0)
93
   {
94
           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
95
   }
96
   if(cd==1)
97
   {
98
           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
99
   }
2 mjames 100
 
5 mjames 101
 
4 mjames 102
        HAL_SPI_Transmit(&hspi1, buffer, 1, 2);
2 mjames 103
 
5 mjames 104
           if(cd==0)
105
           {
106
                   HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
107
           }
108
           if(cd==1)
109
           {
110
                   HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
111
           }
112
 
113
 
114
 
2 mjames 115
}
116
 
117
// the most basic function, set a single pixel
118
inline void drawPixel(int16_t x, int16_t y, uint16_t color) {
4 mjames 119
        if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
120
                return;
2 mjames 121
 
4 mjames 122
        // check rotation, move pixel around if necessary
123
        switch (getRotation()) {
124
        case 1:
125
                swap(x, y)
126
                ;
127
                x = WIDTH - x - 1;
128
                break;
129
        case 2:
130
                x = WIDTH - x - 1;
131
                y = HEIGHT - y - 1;
132
                break;
133
        case 3:
134
                swap(x, y)
135
                ;
136
                y = HEIGHT - y - 1;
137
                break;
138
        }
2 mjames 139
 
4 mjames 140
        // x is which column
141
        switch (color) {
142
        case BLACK:
143
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
144
                break;
2 mjames 145
 
4 mjames 146
        default:
147
        case WHITE:
148
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
149
                break;
2 mjames 150
 
4 mjames 151
        case INVERT:
152
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
153
                break;
154
        }
2 mjames 155
}
156
 
157
void ssd1306_begin(uint8_t vccstate, uint8_t i2caddr) {
158
 
4 mjames 159
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
2 mjames 160
 
4 mjames 161
        // VDD (3.3V) goes high at start, lets just chill for a ms
162
        HAL_Delay(1);
163
        // bring reset low
164
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_RESET);
165
        // wait 10ms
166
        HAL_Delay(10);
167
        // bring out of reset
168
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
169
        // turn on VCC (9V?)
2 mjames 170
 
4 mjames 171
        for (cd = 0; cd < 2; cd++) {
5 mjames 172
                select_display(cd);
4 mjames 173
#if defined SSD1306_128_32
174
                // Init sequence for 128x32 OLED module
175
                ssd1306_command(SSD1306_DISPLAYOFF);// 0xAE
176
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);// 0xD5
177
                ssd1306_command(0x80);// the suggested ratio 0x80
178
                ssd1306_command(SSD1306_SETMULTIPLEX);// 0xA8
179
                ssd1306_command(0x1F);
180
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);// 0xD3
181
                ssd1306_command(0x0);// no offset
182
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);// line #0
183
                ssd1306_command(SSD1306_CHARGEPUMP);// 0x8D
184
                if (vccstate == SSD1306_EXTERNALVCC)
185
                {       ssd1306_command(0x10);}
186
                else
187
                {       ssd1306_command(0x14);}
188
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
189
                ssd1306_command(0x00);// 0x0 act like ks0108
190
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
191
                ssd1306_command(SSD1306_COMSCANDEC);
192
                ssd1306_command(SSD1306_SETCOMPINS);// 0xDA
193
                ssd1306_command(0x02);
194
                ssd1306_command(SSD1306_SETCONTRAST);// 0x81
195
                ssd1306_command(0x8F);
196
                ssd1306_command(SSD1306_SETPRECHARGE);// 0xd9
197
                if (vccstate == SSD1306_EXTERNALVCC)
198
                {       ssd1306_command(0x22);}
199
                else
200
                {       ssd1306_command(0xF1);}
201
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
202
                ssd1306_command(0x40);
203
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);// 0xA4
204
                ssd1306_command(SSD1306_NORMALDISPLAY);// 0xA6
205
#endif
2 mjames 206
 
4 mjames 207
#if defined SSD1306_128_64
208
                // Init sequence for 128x64 OLED module
209
                ssd1306_command(SSD1306_DISPLAYOFF);                    // 0xAE
210
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
211
                ssd1306_command(0x80);                       // the suggested ratio 0x80
212
                ssd1306_command(SSD1306_SETMULTIPLEX);                  // 0xA8
213
                ssd1306_command(0x3F);
214
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);              // 0xD3
215
                ssd1306_command(0x0);                                   // no offset
216
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);            // line #0
217
                ssd1306_command(SSD1306_CHARGEPUMP);                    // 0x8D
218
                if (vccstate == SSD1306_EXTERNALVCC) {
219
                        ssd1306_command(0x10);
220
                } else {
221
                        ssd1306_command(0x14);
222
                }
223
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
224
                ssd1306_command(0x00);                            // 0x0 act like ks0108
225
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
226
                ssd1306_command(SSD1306_COMSCANDEC);
227
                ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
228
                ssd1306_command(0x12);
229
                ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
230
                if (vccstate == SSD1306_EXTERNALVCC) {
231
                        ssd1306_command(0x9F);
232
                } else {
233
                        ssd1306_command(0xCF);
234
                }
235
                ssd1306_command(SSD1306_SETPRECHARGE);                  // 0xd9
236
                if (vccstate == SSD1306_EXTERNALVCC) {
237
                        ssd1306_command(0x22);
238
                } else {
239
                        ssd1306_command(0xF1);
240
                }
241
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
242
                ssd1306_command(0x40);
243
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
244
                ssd1306_command(SSD1306_NORMALDISPLAY);                 // 0xA6
245
#endif
2 mjames 246
 
4 mjames 247
                ssd1306_command(SSD1306_DISPLAYON);               //--turn on oled panel
248
        }
5 mjames 249
        select_display(0);
2 mjames 250
}
251
 
252
void invertDisplay(uint8_t i) {
4 mjames 253
        if (i) {
254
                ssd1306_command(SSD1306_INVERTDISPLAY);
255
        } else {
256
                ssd1306_command(SSD1306_NORMALDISPLAY);
257
        }
2 mjames 258
}
259
 
4 mjames 260
void ssd1306_command(uint8_t c) {
261
        HAL_GPIO_WritePin(SPI1CD_GPIO_Port, SPI1CD_Pin, GPIO_PIN_RESET);
2 mjames 262
 
4 mjames 263
        fastSPIwrite(c);
2 mjames 264
 
265
}
266
 
267
// startscrollright
268
// Activate a right handed scroll for rows start through stop
269
// Hint, the display is 16 rows tall. To scroll the whole display, run:
270
// display.scrollright(0x00, 0x0F) 
4 mjames 271
void startscrollright(uint8_t start, uint8_t stop) {
2 mjames 272
        ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
273
        ssd1306_command(0X00);
274
        ssd1306_command(start);
275
        ssd1306_command(0X00);
276
        ssd1306_command(stop);
277
        ssd1306_command(0X00);
278
        ssd1306_command(0XFF);
279
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
280
}
281
 
282
// startscrollleft
283
// Activate a right handed scroll for rows start through stop
284
// Hint, the display is 16 rows tall. To scroll the whole display, run:
285
// display.scrollright(0x00, 0x0F) 
4 mjames 286
void startscrollleft(uint8_t start, uint8_t stop) {
2 mjames 287
        ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
288
        ssd1306_command(0X00);
289
        ssd1306_command(start);
290
        ssd1306_command(0X00);
291
        ssd1306_command(stop);
292
        ssd1306_command(0X00);
293
        ssd1306_command(0XFF);
294
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
295
}
296
 
297
// startscrolldiagright
298
// Activate a diagonal scroll for rows start through stop
299
// Hint, the display is 16 rows tall. To scroll the whole display, run:
300
// display.scrollright(0x00, 0x0F) 
4 mjames 301
void startscrolldiagright(uint8_t start, uint8_t stop) {
302
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
2 mjames 303
        ssd1306_command(0X00);
304
        ssd1306_command(SSD1306_LCDHEIGHT);
305
        ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
306
        ssd1306_command(0X00);
307
        ssd1306_command(start);
308
        ssd1306_command(0X00);
309
        ssd1306_command(stop);
310
        ssd1306_command(0X01);
311
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
312
}
313
 
314
// startscrolldiagleft
315
// Activate a diagonal scroll for rows start through stop
316
// Hint, the display is 16 rows tall. To scroll the whole display, run:
317
// display.scrollright(0x00, 0x0F) 
4 mjames 318
void startscrolldiagleft(uint8_t start, uint8_t stop) {
319
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
2 mjames 320
        ssd1306_command(0X00);
321
        ssd1306_command(SSD1306_LCDHEIGHT);
322
        ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
323
        ssd1306_command(0X00);
324
        ssd1306_command(start);
325
        ssd1306_command(0X00);
326
        ssd1306_command(stop);
327
        ssd1306_command(0X01);
328
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
329
}
330
 
4 mjames 331
void stopscroll(void) {
2 mjames 332
        ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
333
}
334
 
335
// Dim the display
336
// dim = true: display is dimmed
337
// dim = false: display is normal
4 mjames 338
void dim(uint8_t dim) {
339
        uint8_t contrast;
2 mjames 340
 
4 mjames 341
        if (dim) {
342
                contrast = 0; // Dimmed display
343
        } else {
344
                contrast = 0xCF;
345
        }
346
        // the range of contrast to too small to be really useful
347
        // it is useful to dim the display
348
        ssd1306_command(SSD1306_SETCONTRAST);
349
        ssd1306_command(contrast);
2 mjames 350
}
351
 
352
void display(void) {
4 mjames 353
        ssd1306_command(SSD1306_COLUMNADDR);
354
        ssd1306_command(0);   // Column start address (0 = reset)
355
        ssd1306_command(131); // Column end address (127 = reset)
2 mjames 356
 
4 mjames 357
        ssd1306_command(SSD1306_PAGEADDR);
358
        ssd1306_command(0); // Page start address (0 = reset)
359
        ssd1306_command((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
2 mjames 360
 
4 mjames 361
        int row;
362
        int col = 2;
363
        for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++) {
364
                // set the cursor to
365
                ssd1306_command(0xB0 + row); //set page address
366
                ssd1306_command(col & 0xf); //set lower column address
367
                ssd1306_command(0x10 | (col >> 4)); //set higher column address
2 mjames 368
 
5 mjames 369
 
4 mjames 370
                HAL_GPIO_WritePin(SPI1CD_GPIO_Port, SPI1CD_Pin, GPIO_PIN_SET);
5 mjames 371
                   if(cd==0)
372
                   {
373
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
374
                   }
375
                   if(cd==1)
376
                   {
377
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
378
                   }
379
 
380
 
381
 
382
 
4 mjames 383
                HAL_SPI_Transmit(&hspi1,
384
                                (uint8_t *) (&display_buffer[cd]) + row * SSD1306_LCDWIDTH,
385
                                SSD1306_LCDWIDTH, 100);
5 mjames 386
                   if(cd==0)
387
                   {
388
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
389
                   }
390
                   if(cd==1)
391
                   {
392
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
393
                   }
7 mjames 394
                        HAL_GPIO_WritePin(SPI1CD_GPIO_Port, SPI1CD_Pin, GPIO_PIN_RESET);
5 mjames 395
 
4 mjames 396
        }
2 mjames 397
 
398
}
399
 
400
// clear everything
401
void clearDisplay(void) {
4 mjames 402
        memset(&display_buffer[cd], 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
2 mjames 403
}
404
 
405
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
4 mjames 406
        boolean bSwap = false;
407
        switch (rotation) {
408
        case 0:
409
                // 0 degree rotation, do nothing
410
                break;
411
        case 1:
412
                // 90 degree rotation, swap x & y for rotation, then invert x
413
                bSwap = true;
414
                swap(x, y)
415
                ;
416
                x = WIDTH - x - 1;
417
                break;
418
        case 2:
419
                // 180 degree rotation, invert x and y - then shift y around for height.
420
                x = WIDTH - x - 1;
421
                y = HEIGHT - y - 1;
422
                x -= (w - 1);
423
                break;
424
        case 3:
425
                // 270 degree rotation, swap x & y for rotation, then invert y  and adjust y for w (not to become h)
426
                bSwap = true;
427
                swap(x, y)
428
                ;
429
                y = HEIGHT - y - 1;
430
                y -= (w - 1);
431
                break;
432
        }
2 mjames 433
 
4 mjames 434
        if (bSwap) {
435
                drawFastVLineInternal(x, y, w, color);
436
        } else {
437
                drawFastHLineInternal(x, y, w, color);
438
        }
2 mjames 439
}
440
 
441
void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) {
4 mjames 442
        // Do bounds/limit checks
443
        if (y < 0 || y >= HEIGHT) {
444
                return;
445
        }
2 mjames 446
 
4 mjames 447
        // make sure we don't try to draw below 0
448
        if (x < 0) {
449
                w += x;
450
                x = 0;
451
        }
2 mjames 452
 
4 mjames 453
        // make sure we don't go off the edge of the display
454
        if ((x + w) > WIDTH) {
455
                w = (HEIGHT - x);
456
        }
2 mjames 457
 
4 mjames 458
        // if our width is now negative, punt
459
        if (w <= 0) {
460
                return;
461
        }
2 mjames 462
 
4 mjames 463
        // set up the pointer for  movement through the buffer
464
        register uint8_t *pBuf = display_address();
465
        // adjust the buffer pointer for the current row
466
        pBuf += ((y / 8) * SSD1306_LCDWIDTH);
467
        // and offset x columns in
468
        pBuf += x;
2 mjames 469
 
4 mjames 470
        register uint8_t mask = 1 << (y & 7);
2 mjames 471
 
4 mjames 472
        if (color == WHITE) {
473
                while (w--) {
474
                        *pBuf++ |= mask;
475
                }
476
        } else {
477
                mask = ~mask;
478
                while (w--) {
479
                        *pBuf++ &= mask;
480
                }
481
        }
2 mjames 482
}
483
 
484
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
4 mjames 485
        boolean bSwap = false;
486
        switch (rotation) {
487
        case 0:
488
                break;
489
        case 1:
490
                // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
491
                bSwap = true;
492
                swap(x, y)
493
                ;
494
                x = WIDTH - x - 1;
495
                x -= (h - 1);
496
                break;
497
        case 2:
498
                // 180 degree rotation, invert x and y - then shift y around for height.
499
                x = WIDTH - x - 1;
500
                y = HEIGHT - y - 1;
501
                y -= (h - 1);
502
                break;
503
        case 3:
504
                // 270 degree rotation, swap x & y for rotation, then invert y
505
                bSwap = true;
506
                swap(x, y)
507
                ;
508
                y = HEIGHT - y - 1;
509
                break;
510
        }
2 mjames 511
 
4 mjames 512
        if (bSwap) {
513
                drawFastHLineInternal(x, y, h, color);
514
        } else {
515
                drawFastVLineInternal(x, y, h, color);
516
        }
2 mjames 517
}
518
 
519
void drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {
520
 
4 mjames 521
        // do nothing if we're off the left or right side of the screen
522
        if (x < 0 || x >= WIDTH) {
523
                return;
524
        }
2 mjames 525
 
4 mjames 526
        // make sure we don't try to draw below 0
527
        if (__y < 0) {
528
                // __y is negative, this will subtract enough from __h to account for __y being 0
529
                __h += __y;
530
                __y = 0;
2 mjames 531
 
4 mjames 532
        }
2 mjames 533
 
4 mjames 534
        // make sure we don't go past the height of the display
535
        if ((__y + __h) > HEIGHT) {
536
                __h = (HEIGHT - __y);
537
        }
2 mjames 538
 
4 mjames 539
        // if our height is now negative, punt
540
        if (__h <= 0) {
541
                return;
542
        }
2 mjames 543
 
4 mjames 544
        // this display doesn't need ints for coordinates, use local byte registers for faster juggling
545
        register uint8_t y = __y;
546
        register uint8_t h = __h;
2 mjames 547
 
4 mjames 548
        // set up the pointer for fast movement through the buffer
549
        register uint8_t *pBuf = display_address();
550
        // adjust the buffer pointer for the current row
551
        pBuf += ((y / 8) * SSD1306_LCDWIDTH);
552
        // and offset x columns in
553
        pBuf += x;
2 mjames 554
 
4 mjames 555
        // do the first partial byte, if necessary - this requires some masking
556
        register uint8_t mod = (y & 7);
557
        if (mod) {
558
                // mask off the high n bits we want to set
559
                mod = 8 - mod;
2 mjames 560
 
4 mjames 561
                // note - lookup table results in a nearly 10% performance improvement in fill* functions
562
                // register uint8_t mask = ~(0xFF >> (mod));
563
                static uint8_t premask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC,
564
                                0xFE };
565
                register uint8_t mask = premask[mod];
2 mjames 566
 
4 mjames 567
                // adjust the mask if we're not going to reach the end of this byte
568
                if (h < mod) {
569
                        mask &= (0XFF >> (mod - h));
570
                }
2 mjames 571
 
4 mjames 572
                if (color == WHITE) {
573
                        *pBuf |= mask;
574
                } else {
575
                        *pBuf &= ~mask;
576
                }
2 mjames 577
 
4 mjames 578
                // fast exit if we're done here!
579
                if (h < mod) {
580
                        return;
581
                }
2 mjames 582
 
4 mjames 583
                h -= mod;
2 mjames 584
 
4 mjames 585
                pBuf += SSD1306_LCDWIDTH;
586
        }
2 mjames 587
 
4 mjames 588
        // write solid bytes while we can - effectively doing 8 rows at a time
589
        if (h >= 8) {
590
                // store a local value to work with
591
                register uint8_t val = (color == WHITE) ? 255 : 0;
2 mjames 592
 
4 mjames 593
                do {
594
                        // write our value in
595
                        *pBuf = val;
2 mjames 596
 
4 mjames 597
                        // adjust the buffer forward 8 rows worth of data
598
                        pBuf += SSD1306_LCDWIDTH;
2 mjames 599
 
4 mjames 600
                        // 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)
601
                        h -= 8;
602
                } while (h >= 8);
603
        }
2 mjames 604
 
4 mjames 605
        // now do the final partial byte, if necessary
606
        if (h) {
607
                mod = h & 7;
608
                // this time we want to mask the low bits of the byte, vs the high bits we did above
609
                // register uint8_t mask = (1 << mod) - 1;
610
                // note - lookup table results in a nearly 10% performance improvement in fill* functions
611
                static uint8_t postmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,
612
                                0x7F };
613
                register uint8_t mask = postmask[mod];
614
                if (color == WHITE) {
615
                        *pBuf |= mask;
616
                } else {
617
                        *pBuf &= ~mask;
618
                }
619
        }
2 mjames 620
}
621
 
622
/* using Bresenham draw algorithm */
4 mjames 623
void drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color) {
624
        int16_t x, y, dx,               //deltas
625
                        dy, dx2,        //scaled deltas
626
                        dy2, ix,                //increase rate on the x axis
627
                        iy,             //increase rate on the y axis
628
                        err;    //the error term
629
        uint16_t i;             //looping variable
2 mjames 630
 
631
        // identify the first pixel
4 mjames 632
        x = x1;
633
        y = y1;
2 mjames 634
 
635
        // difference between starting and ending points
636
        dx = x2 - x1;
637
        dy = y2 - y1;
638
 
639
        // calculate direction of the vector and store in ix and iy
640
        if (dx >= 0)
641
                ix = 1;
642
 
4 mjames 643
        if (dx < 0) {
2 mjames 644
                ix = -1;
645
                dx = abs(dx);
646
        }
647
 
648
        if (dy >= 0)
649
                iy = 1;
650
 
4 mjames 651
        if (dy < 0) {
2 mjames 652
                iy = -1;
653
                dy = abs(dy);
654
        }
655
 
656
        // scale deltas and store in dx2 and dy2
657
        dx2 = dx * 2;
658
        dy2 = dy * 2;
659
 
660
// all  variables are set and it's time to enter the main loop.
661
 
662
        if (dx > dy)    // dx is the major axis
4 mjames 663
                        {
2 mjames 664
                // initialize the error term
665
                err = dy2 - dx;
666
 
4 mjames 667
                for (i = 0; i <= dx; i++) {
2 mjames 668
                        drawPixel(x, y, color);
4 mjames 669
                        if (err >= 0) {
2 mjames 670
                                err -= dx2;
671
                                y += iy;
672
                        }
673
                        err += dy2;
674
                        x += ix;
675
                }
676
        }
677
 
678
        else            // dy is the major axis
679
        {
680
                // initialize the error term
681
                err = dx2 - dy;
682
 
4 mjames 683
                for (i = 0; i <= dy; i++) {
2 mjames 684
                        drawPixel(x, y, color);
4 mjames 685
                        if (err >= 0) {
2 mjames 686
                                err -= dy2;
687
                                x += ix;
688
                        }
689
                        err += dx2;
690
                        y += iy;
691
                }
692
        }
693
}
694
 
4 mjames 695
void select_display(int i) {
696
        if (i < MAX_PHYS_DISPLAYS) {
2 mjames 697
                cd = i;
698
        }
699
}