Subversion Repositories DashDisplay

Rev

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