Subversion Repositories chibiosIgnition

Rev

Rev 7 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 mjames 1
/*********************************************************************
2
 This 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
 
7
 These displays use SPI to communicate, 4 or 5 pins are required to
8
 interface
9
 
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!
13
 
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
17
 
18
 This code is taken from the ADAfruit library - it is used for playing with an OLED screen
19
 
20
 *********************************************************************/
21
 
22
#include "ch.h"
23
#include "hal.h"
24
 
25
#include <stdint.h>
26
#include <string.h>
27
#include "SSD1306.h"
28
#include "spiInterface.h"
29
 
30
#define swap(x,y) { typeof(x)t = x; x=y; y=t; }
31
#define abs(x)      ((x)>0?(x):-(x))
32
 
33
static uint8_t rotation = 0;
34
const uint16_t WIDTH = SSD1306_LCDWIDTH;
35
const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
36
 
37
// the memory buffer for the LCD
38
 
39
// pointer to the current display - affects buffer used and also chipselect
40
 
41
uint8_t display_buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH
42
                / 8];
43
 
44
inline uint8_t * display_address(void) {
45
        return (uint8_t *) (&display_buffer[0]);
46
}
47
 
48
inline uint8_t getRotation(void) {
49
        return rotation;
50
}
51
 
52
inline int16_t width(void) {
53
        switch (rotation) {
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;
66
        }
67
        return 0;
68
}
69
 
70
inline int16_t height(void) {
71
        switch (rotation) {
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;
84
        }
85
        return 0;
86
}
87
 
88
 
89
// the most basic function, set a single pixel
90
inline void drawPixel(int16_t x, int16_t y, uint16_t color) {
91
        if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
92
                return;
93
 
94
        // check rotation, move pixel around if necessary
95
        switch (getRotation()) {
96
        case 1:
97
                swap(x, y)
98
                ;
99
                x = WIDTH - x - 1;
100
                break;
101
        case 2:
102
                x = WIDTH - x - 1;
103
                y = HEIGHT - y - 1;
104
                break;
105
        case 3:
106
                swap(x, y)
107
                ;
108
                y = HEIGHT - y - 1;
109
                break;
110
        }
111
 
112
        // x is which column
113
        switch (color) {
114
        case BLACK:
115
                display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
116
                break;
117
 
118
        default:
119
        case WHITE:
120
                display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
121
                break;
122
 
123
        case INVERT:
124
                display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
125
                break;
126
        }
127
}
128
 
129
void ssd1306_begin(uint8_t vccstate, uint8_t i2caddr) {
130
 
131
        (void) i2caddr;
132
        ssd1306resetDisplay();
133
 
134
 
135
#if defined SSD1306_128_32
136
                // Init sequence for 128x32 OLED module
137
                ssd1306commandSPIwrite(SSD1306_DISPLAYOFF);// 0xAE
138
                ssd1306commandSPIwrite(SSD1306_SETDISPLAYCLOCKDIV);// 0xD5
139
                ssd1306commandSPIwrite(0x80);// the suggested ratio 0x80
140
                ssd1306commandSPIwrite(SSD1306_SETMULTIPLEX);// 0xA8
141
                ssd1306commandSPIwrite(0x1F);
142
                ssd1306commandSPIwrite(SSD1306_SETDISPLAYOFFSET);// 0xD3
143
                ssd1306commandSPIwrite(0x0);// no offset
144
                ssd1306commandSPIwrite(SSD1306_SETSTARTLINE | 0x0);// line #0
145
                ssd1306commandSPIwrite(SSD1306_CHARGEPUMP);// 0x8D
146
                if (vccstate == SSD1306_EXTERNALVCC)
147
                {       ssd1306commandSPIwrite(0x10);}
148
                else
149
                {       ssd1306commandSPIwrite(0x14);}
150
                ssd1306commandSPIwrite(SSD1306_MEMORYMODE);                    // 0x20
151
                ssd1306commandSPIwrite(0x00);// 0x0 act like ks0108
152
                ssd1306commandSPIwrite(SSD1306_SEGREMAP | 0x1);
153
                ssd1306commandSPIwrite(SSD1306_COMSCANDEC);
154
                ssd1306commandSPIwrite(SSD1306_SETCOMPINS);// 0xDA
155
                ssd1306commandSPIwrite(0x02);
156
                ssd1306commandSPIwrite(SSD1306_SETCONTRAST);// 0x81
157
                ssd1306commandSPIwrite(0x8F);
158
                ssd1306commandSPIwrite(SSD1306_SETPRECHARGE);// 0xd9
159
                if (vccstate == SSD1306_EXTERNALVCC)
160
                {       ssd1306commandSPIwrite(0x22);}
161
                else
162
                {       ssd1306commandSPIwrite(0xF1);}
163
                ssd1306commandSPIwrite(SSD1306_SETVCOMDETECT);                 // 0xDB
164
                ssd1306commandSPIwrite(0x40);
165
                ssd1306commandSPIwrite(SSD1306_DISPLAYALLON_RESUME);// 0xA4
166
                ssd1306commandSPIwrite(SSD1306_NORMALDISPLAY);// 0xA6
167
#endif
168
 
169
#if defined SSD1306_128_64
170
                // Init sequence for 128x64 OLED module
171
                ssd1306commandSPIwrite(SSD1306_DISPLAYOFF);                    // 0xAE
172
                ssd1306commandSPIwrite(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
173
                ssd1306commandSPIwrite(0x80);                                  // the suggested ratio 0x80
174
                ssd1306commandSPIwrite(SSD1306_SETMULTIPLEX);                  // 0xA8
175
                ssd1306commandSPIwrite(0x3F);
176
                ssd1306commandSPIwrite(SSD1306_SETDISPLAYOFFSET);              // 0xD3
177
                ssd1306commandSPIwrite(0x0);                                   // no offset
178
                ssd1306commandSPIwrite(SSD1306_SETSTARTLINE | 0x0);            // line #0
179
                ssd1306commandSPIwrite(SSD1306_CHARGEPUMP);                    // 0x8D
180
                if (vccstate == SSD1306_EXTERNALVCC) {
181
                        ssd1306commandSPIwrite(0x10);
182
                } else {
183
                        ssd1306commandSPIwrite(0x14);
184
                }
185
                ssd1306commandSPIwrite(SSD1306_MEMORYMODE);                    // 0x20
186
                ssd1306commandSPIwrite(0x00);                            // 0x0 act like ks0108
187
                ssd1306commandSPIwrite(SSD1306_SEGREMAP | 0x1);
188
                ssd1306commandSPIwrite(SSD1306_COMSCANDEC);
189
                ssd1306commandSPIwrite(SSD1306_SETCOMPINS);                    // 0xDA
190
                ssd1306commandSPIwrite(0x12);
191
                ssd1306commandSPIwrite(SSD1306_SETCONTRAST);                   // 0x81
192
                if (vccstate == SSD1306_EXTERNALVCC) {
193
                        ssd1306commandSPIwrite(0x9F);
194
                } else {
195
                        ssd1306commandSPIwrite(0xCF);
196
                }
197
                ssd1306commandSPIwrite(SSD1306_SETPRECHARGE);                  // 0xd9
198
                if (vccstate == SSD1306_EXTERNALVCC) {
199
                        ssd1306commandSPIwrite(0x22);
200
                } else {
201
                        ssd1306commandSPIwrite(0xF1);
202
                }
203
                ssd1306commandSPIwrite(SSD1306_SETVCOMDETECT);                 // 0xDB
204
                ssd1306commandSPIwrite(0x40);
205
                ssd1306commandSPIwrite(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
206
                ssd1306commandSPIwrite(SSD1306_NORMALDISPLAY);                 // 0xA6
207
#endif
208
 
209
                ssd1306commandSPIwrite(SSD1306_DISPLAYON);               //--turn on oled panel
210
 
211
}
212
 
213
void invertDisplay(uint8_t i) {
214
        if (i) {
215
                ssd1306commandSPIwrite(SSD1306_INVERTDISPLAY);
216
        } else {
217
                ssd1306commandSPIwrite(SSD1306_NORMALDISPLAY);
218
        }
219
}
220
 
221
 
222
// startscrollright
223
// Activate a right handed scroll for rows start through stop
224
// Hint, the display is 16 rows tall. To scroll the whole display, run:
225
// display.scrollright(0x00, 0x0F) 
226
void startscrollright(uint8_t start, uint8_t stop) {
227
        ssd1306commandSPIwrite(SSD1306_RIGHT_HORIZONTAL_SCROLL);
228
        ssd1306commandSPIwrite(0X00);
229
        ssd1306commandSPIwrite(start);
230
        ssd1306commandSPIwrite(0X00);
231
        ssd1306commandSPIwrite(stop);
232
        ssd1306commandSPIwrite(0X00);
233
        ssd1306commandSPIwrite(0XFF);
234
        ssd1306commandSPIwrite(SSD1306_ACTIVATE_SCROLL);
235
}
236
 
237
// startscrollleft
238
// Activate a right handed scroll for rows start through stop
239
// Hint, the display is 16 rows tall. To scroll the whole display, run:
240
// display.scrollright(0x00, 0x0F) 
241
void startscrollleft(uint8_t start, uint8_t stop) {
242
        ssd1306commandSPIwrite(SSD1306_LEFT_HORIZONTAL_SCROLL);
243
        ssd1306commandSPIwrite(0X00);
244
        ssd1306commandSPIwrite(start);
245
        ssd1306commandSPIwrite(0X00);
246
        ssd1306commandSPIwrite(stop);
247
        ssd1306commandSPIwrite(0X00);
248
        ssd1306commandSPIwrite(0XFF);
249
        ssd1306commandSPIwrite(SSD1306_ACTIVATE_SCROLL);
250
}
251
 
252
// startscrolldiagright
253
// Activate a diagonal scroll for rows start through stop
254
// Hint, the display is 16 rows tall. To scroll the whole display, run:
255
// display.scrollright(0x00, 0x0F) 
256
void startscrolldiagright(uint8_t start, uint8_t stop) {
257
        ssd1306commandSPIwrite(SSD1306_SET_VERTICAL_SCROLL_AREA);
258
        ssd1306commandSPIwrite(0X00);
259
        ssd1306commandSPIwrite(SSD1306_LCDHEIGHT);
260
        ssd1306commandSPIwrite(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
261
        ssd1306commandSPIwrite(0X00);
262
        ssd1306commandSPIwrite(start);
263
        ssd1306commandSPIwrite(0X00);
264
        ssd1306commandSPIwrite(stop);
265
        ssd1306commandSPIwrite(0X01);
266
        ssd1306commandSPIwrite(SSD1306_ACTIVATE_SCROLL);
267
}
268
 
269
// startscrolldiagleft
270
// Activate a diagonal scroll for rows start through stop
271
// Hint, the display is 16 rows tall. To scroll the whole display, run:
272
// display.scrollright(0x00, 0x0F) 
273
void startscrolldiagleft(uint8_t start, uint8_t stop) {
274
        ssd1306commandSPIwrite(SSD1306_SET_VERTICAL_SCROLL_AREA);
275
        ssd1306commandSPIwrite(0X00);
276
        ssd1306commandSPIwrite(SSD1306_LCDHEIGHT);
277
        ssd1306commandSPIwrite(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
278
        ssd1306commandSPIwrite(0X00);
279
        ssd1306commandSPIwrite(start);
280
        ssd1306commandSPIwrite(0X00);
281
        ssd1306commandSPIwrite(stop);
282
        ssd1306commandSPIwrite(0X01);
283
        ssd1306commandSPIwrite(SSD1306_ACTIVATE_SCROLL);
284
}
285
 
286
void stopscroll(void) {
287
        ssd1306commandSPIwrite(SSD1306_DEACTIVATE_SCROLL);
288
}
289
 
290
// Dim the display
291
// dim = true: display is dimmed
292
// dim = false: display is normal
293
void dim(uint8_t contrast) {
294
 
295
        // the range of contrast to too small to be really useful
296
        // it is useful to dim the display
297
        ssd1306commandSPIwrite(SSD1306_SETCONTRAST);
298
        ssd1306commandSPIwrite(contrast);
299
}
300
 
301
void display(void) {
302
 
303
 
304
        // select entire display as window to write into
305
        ssd1306commandSPIwrite(SSD1306_COLUMNADDR);
306
        ssd1306commandSPIwrite(0);   // Column start address (0 = reset)
307
        ssd1306commandSPIwrite(SSD1306_RAMWIDTH-1); // Column end address (127 = reset)
308
 
309
        ssd1306commandSPIwrite(SSD1306_PAGEADDR);
310
        ssd1306commandSPIwrite(0); // Page start address (0 = reset)
311
        ssd1306commandSPIwrite((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
312
 
313
        int row;
314
 
315
        int col = SSD1306_RAMWIDTH == 132 ? 2 : 0;
316
        for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++) {
317
                // set the cursor to
318
                ssd1306commandSPIwrite(0xB0 + row); //set page address
319
                ssd1306commandSPIwrite(col & 0xf); //set lower column address
320
                ssd1306commandSPIwrite(0x10 | (col >> 4)); //set higher column address
321
 
322
                ssd1306SendDisplay(
323
                                (uint8_t *) (&display_buffer[0]) + row * SSD1306_LCDWIDTH,
324
                                SSD1306_LCDWIDTH);
325
 
326
        }
327
 
328
}
329
 
330
// clear everything
331
void clearDisplay(void) {
332
        memset(&display_buffer, 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
333
}
334
 
335
 
336
/* using Bresenham draw algorithm */
337
void drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color) {
338
        int16_t x,   y,
339
                dx,  dy,    //deltas
340
                        dx2, dy2,       //scaled deltas
341
                    ix,  iy,    //increase rate on the x and y axis
342
                        err;    //the error term
343
        uint16_t i;             //looping variable
344
 
345
        // identify the first pixel
346
        x = x1;
347
        y = y1;
348
 
349
        // difference between starting and ending points
350
        dx = x2 - x1;
351
        dy = y2 - y1;
352
 
353
        // calculate direction of the vector and store in ix and iy
354
        if (dx >= 0)
355
                ix = 1;
356
 
357
        if (dx < 0) {
358
                ix = -1;
359
                dx = abs(dx);
360
        }
361
 
362
        if (dy >= 0)
363
                iy = 1;
364
 
365
        if (dy < 0) {
366
                iy = -1;
367
                dy = abs(dy);
368
        }
369
 
370
        // scale deltas and store in dx2 and dy2
371
        dx2 = dx * 2;
372
        dy2 = dy * 2;
373
 
374
// all  variables are set and it's time to enter the main loop.
375
 
376
        if (dx > dy)    // dx is the major axis
377
                        {
378
                // initialize the error term
379
                err = dy2 - dx;
380
 
381
                for (i = 0; i <= dx; i++) {
382
                        drawPixel(x, y, color);
383
                        if (err >= 0) {
384
                                err -= dx2;
385
                                y += iy;
386
                        }
387
                        err += dy2;
388
                        x += ix;
389
                }
390
        }
391
 
392
        else            // dy is the major axis
393
        {
394
                // initialize the error term
395
                err = dx2 - dy;
396
 
397
                for (i = 0; i <= dy; i++) {
398
                        drawPixel(x, y, color);
399
                        if (err >= 0) {
400
                                err -= dy2;
401
                                x += ix;
402
                        }
403
                        err += dx2;
404
                        y += iy;
405
                }
406
        }
407
}