Subversion Repositories DashDisplay

Rev

Rev 4 | 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"
24
#include "stm32f1xx_hal_conf.h"
2 mjames 25
#include "stm32f1xx_hal.h"
26
 
5 mjames 27
 
2 mjames 28
#define swap(x,y) { typeof(x)t = x; x=y; y=t; }
29
#define abs(x)      ((x)>0?(x):-(x))
30
 
31
static uint8_t rotation = 0;
4 mjames 32
const uint16_t WIDTH = SSD1306_LCDWIDTH;
2 mjames 33
const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
34
 
35
extern SPI_HandleTypeDef hspi1;
36
 
37
// the memory buffer for the LCD
38
 
39
// pointer to the current display - affects buffer used and also chipselect
40
static int cd = 0;
41
 
4 mjames 42
uint8_t display_buffer[MAX_PHYS_DISPLAYS][SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH
43
                / 8];
2 mjames 44
 
4 mjames 45
inline uint8_t * display_address(void) {
46
        return (uint8_t *) (&display_buffer[cd]);
2 mjames 47
}
48
 
4 mjames 49
inline uint8_t getRotation(void) {
2 mjames 50
        return rotation;
51
}
52
 
4 mjames 53
inline int16_t width(void) {
54
        switch (rotation) {
2 mjames 55
        case 0:
56
                return WIDTH;
57
                break;
58
        case 1:
59
                return WIDTH;
60
                break;
61
        case 2:
62
                return HEIGHT;
63
                break;
64
        case 3:
65
                return -WIDTH;
66
                break;
4 mjames 67
        }
68
        return 0;
2 mjames 69
}
70
 
4 mjames 71
inline int16_t height(void) {
72
        switch (rotation) {
2 mjames 73
        case 0:
74
                return HEIGHT;
75
                break;
76
        case 1:
77
                return HEIGHT;
78
                break;
79
        case 2:
80
                return WIDTH;
81
                break;
82
        case 3:
83
                return -HEIGHT;
84
                break;
4 mjames 85
        }
2 mjames 86
        return 0;
87
}
88
 
4 mjames 89
inline void fastSPIwrite(uint8_t d) {
90
        uint8_t buffer[1];
91
        buffer[0] = d;
2 mjames 92
// todo chipselect based on 'cd' buffer choice
5 mjames 93
   if(cd==0)
94
   {
95
           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
96
   }
97
   if(cd==1)
98
   {
99
           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
100
   }
2 mjames 101
 
5 mjames 102
 
4 mjames 103
        HAL_SPI_Transmit(&hspi1, buffer, 1, 2);
2 mjames 104
 
5 mjames 105
           if(cd==0)
106
           {
107
                   HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
108
           }
109
           if(cd==1)
110
           {
111
                   HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
112
           }
113
 
114
 
115
 
2 mjames 116
}
117
 
118
// the most basic function, set a single pixel
119
inline void drawPixel(int16_t x, int16_t y, uint16_t color) {
4 mjames 120
        if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
121
                return;
2 mjames 122
 
4 mjames 123
        // check rotation, move pixel around if necessary
124
        switch (getRotation()) {
125
        case 1:
126
                swap(x, y)
127
                ;
128
                x = WIDTH - x - 1;
129
                break;
130
        case 2:
131
                x = WIDTH - x - 1;
132
                y = HEIGHT - y - 1;
133
                break;
134
        case 3:
135
                swap(x, y)
136
                ;
137
                y = HEIGHT - y - 1;
138
                break;
139
        }
2 mjames 140
 
4 mjames 141
        // x is which column
142
        switch (color) {
143
        case BLACK:
144
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
145
                break;
2 mjames 146
 
4 mjames 147
        default:
148
        case WHITE:
149
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
150
                break;
2 mjames 151
 
4 mjames 152
        case INVERT:
153
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
154
                break;
155
        }
2 mjames 156
}
157
 
158
void ssd1306_begin(uint8_t vccstate, uint8_t i2caddr) {
159
 
4 mjames 160
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
2 mjames 161
 
4 mjames 162
        // VDD (3.3V) goes high at start, lets just chill for a ms
163
        HAL_Delay(1);
164
        // bring reset low
165
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_RESET);
166
        // wait 10ms
167
        HAL_Delay(10);
168
        // bring out of reset
169
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
170
        // turn on VCC (9V?)
2 mjames 171
 
4 mjames 172
        for (cd = 0; cd < 2; cd++) {
5 mjames 173
                select_display(cd);
4 mjames 174
#if defined SSD1306_128_32
175
                // Init sequence for 128x32 OLED module
176
                ssd1306_command(SSD1306_DISPLAYOFF);// 0xAE
177
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);// 0xD5
178
                ssd1306_command(0x80);// the suggested ratio 0x80
179
                ssd1306_command(SSD1306_SETMULTIPLEX);// 0xA8
180
                ssd1306_command(0x1F);
181
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);// 0xD3
182
                ssd1306_command(0x0);// no offset
183
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);// line #0
184
                ssd1306_command(SSD1306_CHARGEPUMP);// 0x8D
185
                if (vccstate == SSD1306_EXTERNALVCC)
186
                {       ssd1306_command(0x10);}
187
                else
188
                {       ssd1306_command(0x14);}
189
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
190
                ssd1306_command(0x00);// 0x0 act like ks0108
191
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
192
                ssd1306_command(SSD1306_COMSCANDEC);
193
                ssd1306_command(SSD1306_SETCOMPINS);// 0xDA
194
                ssd1306_command(0x02);
195
                ssd1306_command(SSD1306_SETCONTRAST);// 0x81
196
                ssd1306_command(0x8F);
197
                ssd1306_command(SSD1306_SETPRECHARGE);// 0xd9
198
                if (vccstate == SSD1306_EXTERNALVCC)
199
                {       ssd1306_command(0x22);}
200
                else
201
                {       ssd1306_command(0xF1);}
202
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
203
                ssd1306_command(0x40);
204
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);// 0xA4
205
                ssd1306_command(SSD1306_NORMALDISPLAY);// 0xA6
206
#endif
2 mjames 207
 
4 mjames 208
#if defined SSD1306_128_64
209
                // Init sequence for 128x64 OLED module
210
                ssd1306_command(SSD1306_DISPLAYOFF);                    // 0xAE
211
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
212
                ssd1306_command(0x80);                       // the suggested ratio 0x80
213
                ssd1306_command(SSD1306_SETMULTIPLEX);                  // 0xA8
214
                ssd1306_command(0x3F);
215
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);              // 0xD3
216
                ssd1306_command(0x0);                                   // no offset
217
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);            // line #0
218
                ssd1306_command(SSD1306_CHARGEPUMP);                    // 0x8D
219
                if (vccstate == SSD1306_EXTERNALVCC) {
220
                        ssd1306_command(0x10);
221
                } else {
222
                        ssd1306_command(0x14);
223
                }
224
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
225
                ssd1306_command(0x00);                            // 0x0 act like ks0108
226
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
227
                ssd1306_command(SSD1306_COMSCANDEC);
228
                ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
229
                ssd1306_command(0x12);
230
                ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
231
                if (vccstate == SSD1306_EXTERNALVCC) {
232
                        ssd1306_command(0x9F);
233
                } else {
234
                        ssd1306_command(0xCF);
235
                }
236
                ssd1306_command(SSD1306_SETPRECHARGE);                  // 0xd9
237
                if (vccstate == SSD1306_EXTERNALVCC) {
238
                        ssd1306_command(0x22);
239
                } else {
240
                        ssd1306_command(0xF1);
241
                }
242
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
243
                ssd1306_command(0x40);
244
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
245
                ssd1306_command(SSD1306_NORMALDISPLAY);                 // 0xA6
246
#endif
2 mjames 247
 
4 mjames 248
                ssd1306_command(SSD1306_DISPLAYON);               //--turn on oled panel
249
        }
5 mjames 250
        select_display(0);
2 mjames 251
}
252
 
253
void invertDisplay(uint8_t i) {
4 mjames 254
        if (i) {
255
                ssd1306_command(SSD1306_INVERTDISPLAY);
256
        } else {
257
                ssd1306_command(SSD1306_NORMALDISPLAY);
258
        }
2 mjames 259
}
260
 
4 mjames 261
void ssd1306_command(uint8_t c) {
262
        HAL_GPIO_WritePin(SPI1CD_GPIO_Port, SPI1CD_Pin, GPIO_PIN_RESET);
2 mjames 263
 
4 mjames 264
        fastSPIwrite(c);
2 mjames 265
 
266
}
267
 
268
// startscrollright
269
// Activate a right handed scroll for rows start through stop
270
// Hint, the display is 16 rows tall. To scroll the whole display, run:
271
// display.scrollright(0x00, 0x0F) 
4 mjames 272
void startscrollright(uint8_t start, uint8_t stop) {
2 mjames 273
        ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
274
        ssd1306_command(0X00);
275
        ssd1306_command(start);
276
        ssd1306_command(0X00);
277
        ssd1306_command(stop);
278
        ssd1306_command(0X00);
279
        ssd1306_command(0XFF);
280
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
281
}
282
 
283
// startscrollleft
284
// Activate a right handed scroll for rows start through stop
285
// Hint, the display is 16 rows tall. To scroll the whole display, run:
286
// display.scrollright(0x00, 0x0F) 
4 mjames 287
void startscrollleft(uint8_t start, uint8_t stop) {
2 mjames 288
        ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
289
        ssd1306_command(0X00);
290
        ssd1306_command(start);
291
        ssd1306_command(0X00);
292
        ssd1306_command(stop);
293
        ssd1306_command(0X00);
294
        ssd1306_command(0XFF);
295
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
296
}
297
 
298
// startscrolldiagright
299
// Activate a diagonal scroll for rows start through stop
300
// Hint, the display is 16 rows tall. To scroll the whole display, run:
301
// display.scrollright(0x00, 0x0F) 
4 mjames 302
void startscrolldiagright(uint8_t start, uint8_t stop) {
303
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
2 mjames 304
        ssd1306_command(0X00);
305
        ssd1306_command(SSD1306_LCDHEIGHT);
306
        ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
307
        ssd1306_command(0X00);
308
        ssd1306_command(start);
309
        ssd1306_command(0X00);
310
        ssd1306_command(stop);
311
        ssd1306_command(0X01);
312
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
313
}
314
 
315
// startscrolldiagleft
316
// Activate a diagonal scroll for rows start through stop
317
// Hint, the display is 16 rows tall. To scroll the whole display, run:
318
// display.scrollright(0x00, 0x0F) 
4 mjames 319
void startscrolldiagleft(uint8_t start, uint8_t stop) {
320
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
2 mjames 321
        ssd1306_command(0X00);
322
        ssd1306_command(SSD1306_LCDHEIGHT);
323
        ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
324
        ssd1306_command(0X00);
325
        ssd1306_command(start);
326
        ssd1306_command(0X00);
327
        ssd1306_command(stop);
328
        ssd1306_command(0X01);
329
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
330
}
331
 
4 mjames 332
void stopscroll(void) {
2 mjames 333
        ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
334
}
335
 
336
// Dim the display
337
// dim = true: display is dimmed
338
// dim = false: display is normal
4 mjames 339
void dim(uint8_t dim) {
340
        uint8_t contrast;
2 mjames 341
 
4 mjames 342
        if (dim) {
343
                contrast = 0; // Dimmed display
344
        } else {
345
                contrast = 0xCF;
346
        }
347
        // the range of contrast to too small to be really useful
348
        // it is useful to dim the display
349
        ssd1306_command(SSD1306_SETCONTRAST);
350
        ssd1306_command(contrast);
2 mjames 351
}
352
 
353
void display(void) {
4 mjames 354
        ssd1306_command(SSD1306_COLUMNADDR);
355
        ssd1306_command(0);   // Column start address (0 = reset)
356
        ssd1306_command(131); // Column end address (127 = reset)
2 mjames 357
 
4 mjames 358
        ssd1306_command(SSD1306_PAGEADDR);
359
        ssd1306_command(0); // Page start address (0 = reset)
360
        ssd1306_command((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
2 mjames 361
 
4 mjames 362
        int row;
363
        int col = 2;
364
        for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++) {
365
                // set the cursor to
366
                ssd1306_command(0xB0 + row); //set page address
367
                ssd1306_command(col & 0xf); //set lower column address
368
                ssd1306_command(0x10 | (col >> 4)); //set higher column address
2 mjames 369
 
5 mjames 370
 
4 mjames 371
                HAL_GPIO_WritePin(SPI1CD_GPIO_Port, SPI1CD_Pin, GPIO_PIN_SET);
5 mjames 372
                   if(cd==0)
373
                   {
374
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
375
                   }
376
                   if(cd==1)
377
                   {
378
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
379
                   }
380
 
381
 
382
 
383
 
4 mjames 384
                HAL_SPI_Transmit(&hspi1,
385
                                (uint8_t *) (&display_buffer[cd]) + row * SSD1306_LCDWIDTH,
386
                                SSD1306_LCDWIDTH, 100);
5 mjames 387
                   if(cd==0)
388
                   {
389
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
390
                   }
391
                   if(cd==1)
392
                   {
393
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
394
                   }
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
}