Subversion Repositories libSSD1306

Rev

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

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