Subversion Repositories libOLED

Rev

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

Rev Author Line No. Line
2 mjames 1
/*
2
 * displayclass.cpp
3
 *
4
 *  Created on: 31 Oct 2020
5
 *      Author: mike
6
 */
7
 
8
#include "libOLED/displayclass.H"
9
 
10
#include <cstring>
11
#include <cstdlib>
12
namespace
13
{
14
  uint8_t const SSD1306_SETCONTRAST = 0x81;
15
  uint8_t const SSD1306_DISPLAYALLON_RESUME = 0xA4;
16
  uint8_t const SSD1306_DISPLAYALLON = 0xA5;
17
  uint8_t const SSD1306_NORMALDISPLAY = 0xA6;
18
  uint8_t const SSD1306_INVERTDISPLAY = 0xA7;
19
  uint8_t const SSD1306_DISPLAYOFF = 0xAE;
20
  uint8_t const SSD1306_DISPLAYON = 0xAF;
21
 
22
  uint8_t const SSD1306_SETDISPLAYOFFSET = 0xD3;
23
  uint8_t const SSD1306_SETCOMPINS = 0xDA;
24
 
25
  uint8_t const SSD1306_SETVCOMDETECT = 0xDB;
26
 
27
  uint8_t const SSD1306_SETDISPLAYCLOCKDIV = 0xD5;
28
  uint8_t const SSD1306_SETPRECHARGE = 0xD9;
29
 
30
  uint8_t const SSD1306_SETMULTIPLEX = 0xA8;
31
 
32
  uint8_t const SSD1306_SETLOWCOLUMN = 0x00;
33
  uint8_t const SSD1306_SETHIGHCOLUMN = 0x10;
34
 
35
  uint8_t const SSD1306_SETSTARTLINE = 0x40;
36
 
37
  uint8_t const SSD1306_MEMORYMODE = 0x20;
38
  uint8_t const SSD1306_COLUMNADDR = 0x21;
39
  uint8_t const SSD1306_PAGEADDR = 0x22;
40
 
41
  uint8_t const SSD1306_COMSCANINC = 0xC0;
42
  uint8_t const SSD1306_COMSCANDEC = 0xC8;
43
 
44
  uint8_t const SSD1306_SEGREMAP = 0xA0;
45
 
46
  uint8_t const SSD1306_CHARGEPUMP = 0x8D;
47
 
48
  uint8_t const SSD1306_EXTERNALVCC = 0x1;
49
  uint8_t const SSD1306_SWITCHCAPVCC = 0x2;
50
 
51
// Scrolling #defines
52
  uint8_t const SSD1306_ACTIVATE_SCROLL = 0x2F;
53
  uint8_t const SSD1306_DEACTIVATE_SCROLL = 0x2E;
54
  uint8_t const SSD1306_SET_VERTICAL_SCROLL_AREA = 0xA3;
55
  uint8_t const SSD1306_RIGHT_HORIZONTAL_SCROLL = 0x26;
56
  uint8_t const SSD1306_LEFT_HORIZONTAL_SCROLL = 0x27;
57
  uint8_t const SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL = 0x29;
58
  uint8_t const SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL = 0x2A;
59
 
60
  template<class T>
61
    void
62
    swap (T &x, T &y)
63
    {
64
      T temp = x;
65
      x = y;
66
      y = temp;
67
    }
68
 
69
  template<class T>
70
    T
71
    abs (T x)
72
    {
73
      return x < 0 ? -x : x;
74
    }
75
 
76
 
77
 
78
}
79
// provided to allow a destructor to destroy something not deleted
80
// this is only OK because destructors shouldnt be needed
81
void operator delete(void * data, unsigned int f)
82
 {
83
   (void)data;
84
   (void)f;
85
 }
86
 
87
// provided to implement an "error handler" on pure virtual
88
extern "C" void __cxa_pure_virtual()
89
{
90
  while(1);
91
}
92
 
93
display_t::display_t (int const width, int const height, int const ramwidth,
94
                      uint8_t *const data) :
95
    m_width (width), m_height (height), m_ramwidth (ramwidth), m_cursor_x (0), m_cursor_y (
96
        0), m_rotation (0), m_data (data)
97
{
98
}
99
 
100
display_t::~display_t()
101
{
102
 
103
}
104
 
105
void
106
display_t::display_t::init ()
107
{
108
  uint8_t const vccstate = SSD1306_EXTERNALVCC;
109
 
110
  oledReset ();
111
 
112
  oledSetCD (0);
113
 
114
  // Init sequence for 128x32 or 128x64  OLED module
115
  oledWrite (SSD1306_DISPLAYOFF); // 0xAE
116
  oledWrite (SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
117
  oledWrite (0x80); // the suggested ratio 0x80
118
  oledWrite (SSD1306_SETMULTIPLEX); // 0xA8
119
  oledWrite (m_height - 1);
120
  oledWrite (SSD1306_SETDISPLAYOFFSET); // 0xD3
121
  oledWrite (0x0); // no offset
122
  oledWrite (SSD1306_SETSTARTLINE | 0x0); // line #0
123
  oledWrite (SSD1306_CHARGEPUMP); // 0x8D
124
  oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x10 : 0x14);
125
  oledWrite (SSD1306_MEMORYMODE);                    // 0x20
126
  oledWrite (0x00);                    // 0x0 act like ks0108
127
  oledWrite (SSD1306_SEGREMAP | 0x1);
128
  oledWrite (SSD1306_COMSCANDEC);
129
  oledWrite (SSD1306_SETCOMPINS);                    // 0xDA
130
  oledWrite (m_height == 32 ? 0x02 : 0x12);
131
  oledWrite (SSD1306_SETCONTRAST);                    // 0x81
132
  oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x9F : 0xCF);
133
  oledWrite (SSD1306_SETPRECHARGE);                    // 0xd9
134
  oledWrite (vccstate == SSD1306_EXTERNALVCC ? 0x22 : 0xF1);
135
  oledWrite (SSD1306_SETVCOMDETECT);                 // 0xDB
136
  oledWrite (0x40);
137
  oledWrite (SSD1306_DISPLAYALLON_RESUME);                 // 0xA4
138
  oledWrite (SSD1306_NORMALDISPLAY);                 // 0xA6
139
 
140
  oledWrite (SSD1306_DISPLAYON);             //--turn on oled panel
141
 
142
  clearDisplay ();
143
 
144
}
145
 
146
uint8_t
147
display_t::getRotation (void)
148
{
149
  return m_rotation;
150
}
151
 
152
int16_t
153
display_t::width (void)
154
{
155
  switch (m_rotation)
156
    {
157
    case 0:
158
      return m_width;
159
      break;
160
    case 1:
161
      return m_width;
162
      break;
163
    case 2:
164
      return m_height;
165
      break;
166
    case 3:
167
      return -m_width;
168
      break;
169
    }
170
  return 0;
171
}
172
 
173
int16_t
174
display_t::height (void)
175
{
176
  switch (m_rotation)
177
    {
178
    case 0:
179
      return m_height;
180
      break;
181
    case 1:
182
      return m_height;
183
      break;
184
    case 2:
185
      return m_width;
186
      break;
187
    case 3:
188
      return -m_height;
189
      break;
190
    }
191
  return 0;
192
}
193
 
194
// the most basic function, set a single pixel
3 mjames 195
void
2 mjames 196
display_t::drawPixel (int16_t x, int16_t y, colour_t color)
197
{
198
  if ((x < 0) || (x >= m_width) || (y < 0) || (y >= m_height))
199
    return;
200
 
201
  // check rotation, move pixel around if necessary
202
  switch (m_rotation)
203
    {
204
    case 1:
205
      swap (x, y);
206
      x = m_width - x - 1;
207
      break;
208
    case 2:
209
      x = m_width - x - 1;
210
      y = m_height - y - 1;
211
      break;
212
    case 3:
213
      swap (x, y);
214
      y = m_height - y - 1;
215
      break;
216
    }
217
 
218
  // x is which column
219
  switch (color)
220
    {
221
    case BLACK:
222
      m_data[x + (y / 8) * m_width] &= ~(1 << (y & 7));
223
      break;
224
 
225
    default:
226
    case WHITE:
227
      m_data[x + (y / 8) * m_width] |= (1 << (y & 7));
228
      break;
229
 
230
    case INVERT:
231
      m_data[x + (y / 8) * m_width] ^= (1 << (y & 7));
232
      break;
233
    }
234
}
235
 
236
void
237
display_t::invertDisplay (uint8_t i)
238
{
239
  oledSetCD (0);
240
  oledWrite (i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
241
}
242
 
243
// startscrollright
244
// Activate a right handed 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)
247
void
248
display_t::startscrollright (uint8_t start, uint8_t stop)
249
{
250
  oledSetCD (0);
251
  oledWrite (SSD1306_RIGHT_HORIZONTAL_SCROLL);
252
  oledWrite (0X00);
253
  oledWrite (start);
254
  oledWrite (0X00);
255
  oledWrite (stop);
256
  oledWrite (0X00);
257
  oledWrite (0XFF);
258
  oledWrite (SSD1306_ACTIVATE_SCROLL);
259
}
260
 
261
// startscrollleft
262
// Activate a right handed scroll for rows start through stop
263
// Hint, the display is 16 rows tall. To scroll the whole display, run:
264
// display.scrollright(0x00, 0x0F)
265
void
266
display_t::startscrollleft (uint8_t start, uint8_t stop)
267
{
268
  oledSetCD (0);
269
  oledWrite (SSD1306_LEFT_HORIZONTAL_SCROLL);
270
  oledWrite (0X00);
271
  oledWrite (start);
272
  oledWrite (0X00);
273
  oledWrite (stop);
274
  oledWrite (0X00);
275
  oledWrite (0XFF);
276
  oledWrite (SSD1306_ACTIVATE_SCROLL);
277
}
278
 
279
// startscrolldiagright
280
// Activate a diagonal scroll for rows start through stop
281
// Hint, the display is 16 rows tall. To scroll the whole display, run:
282
// display.scrollright(0x00, 0x0F)
283
void
284
display_t::startscrolldiagright (uint8_t start, uint8_t stop)
285
{
286
  oledSetCD (0);
287
  oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
288
  oledWrite (0X00);
289
  oledWrite (m_height);
290
  oledWrite (SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
291
  oledWrite (0X00);
292
  oledWrite (start);
293
  oledWrite (0X00);
294
  oledWrite (stop);
295
  oledWrite (0X01);
296
  oledWrite (SSD1306_ACTIVATE_SCROLL);
297
}
298
 
299
// startscrolldiagleft
300
// Activate a diagonal scroll for rows start through stop
301
// Hint, the display is 16 rows tall. To scroll the whole display, run:
302
// display.scrollright(0x00, 0x0F)
303
void
304
display_t::startscrolldiagleft (uint8_t start, uint8_t stop)
305
{
306
  oledSetCD (0);
307
  oledWrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
308
  oledWrite (0X00);
309
  oledWrite (m_height);
310
  oledWrite (SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
311
  oledWrite (0X00);
312
  oledWrite (start);
313
  oledWrite (0X00);
314
  oledWrite (stop);
315
  oledWrite (0X01);
316
  oledWrite (SSD1306_ACTIVATE_SCROLL);
317
}
318
 
319
void
320
display_t::stopscroll (void)
321
{
322
  oledSetCD (0);
323
  oledWrite (SSD1306_DEACTIVATE_SCROLL);
324
}
325
 
326
// Dim the display
327
// dim = true: display is dimmed
328
// dim = false: display is normal
329
void
330
display_t::dim (uint8_t contrast)
331
{
332
 
333
  // the range of contrast to too small to be really useful
334
  // it is useful to dim the display
335
 
336
  oledSetCD (0);
337
  oledWrite (SSD1306_SETCONTRAST);
338
  oledWrite (contrast);
339
}
340
 
341
void
342
display_t::display (void)
343
{
344
  oledSetCD (0);
345
  // select entire display as window to write into
346
  oledWrite (SSD1306_COLUMNADDR);
347
  oledWrite (0);   // Column start address (0 = reset)
348
  oledWrite (m_ramwidth - 1); // Column end address (127 = reset)
349
 
350
  oledWrite (SSD1306_PAGEADDR);
351
  oledWrite (0); // Page start address (0 = reset)
352
  oledWrite ((m_height == 64) ? 7 : 3); // Page end address
353
 
354
  int row;
355
 
356
  int col = m_ramwidth == 132 ? 2 : 0;
357
  for (row = 0; row < m_height / 8; row++)
358
    {
359
      oledSetCD (0);
360
      // set the cursor to
361
      oledWrite (0xB0 + row); //set page address
362
      oledWrite (col & 0xf); //set lower column address
363
      oledWrite (0x10 | (col >> 4)); //set higher column address
364
 
365
      oledSetCD (1);
366
      oledWrite (m_data + row * m_width, m_width);
367
 
368
    }
369
 
370
}
371
 
372
// clear everything
373
void
374
display_t::clearDisplay (void)
375
{
376
  memset (m_data, 0, dataSize (m_width, m_height));
377
}
378
 
379
/* using Bresenham draw algorithm */
380
void
381
display_t::drawLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2,
382
                     colour_t color)
383
{
384
  int16_t x, y, dx, dy,    //deltas
385
      dx2, dy2, //scaled deltas
386
      ix, iy,   //increase rate on the x and y axis
387
      err;      //the error term
388
  uint16_t i;           //looping variable
389
 
390
  // identify the first pixel
391
  x = x1;
392
  y = y1;
393
 
394
  // difference between starting and ending points
395
  dx = x2 - x1;
396
  dy = y2 - y1;
397
 
398
  // calculate direction of the vector and store in ix and iy
399
  if (dx >= 0)
400
    ix = 1;
401
 
402
  if (dx < 0)
403
    {
404
      ix = -1;
405
      dx = abs (dx);
406
    }
407
 
408
  if (dy >= 0)
409
    iy = 1;
410
 
411
  if (dy < 0)
412
    {
413
      iy = -1;
414
      dy = abs (dy);
415
    }
416
 
417
  // scale deltas and store in dx2 and dy2
418
  dx2 = dx * 2;
419
  dy2 = dy * 2;
420
 
421
// all  variables are set and it's time to enter the main loop.
422
 
423
  if (dx > dy)  // dx is the major axis
424
    {
425
      // initialize the error term
426
      err = dy2 - dx;
427
 
428
      for (i = 0; i <= dx; i++)
429
        {
430
          drawPixel (x, y, color);
431
          if (err >= 0)
432
            {
433
              err -= dx2;
434
              y += iy;
435
            }
436
          err += dy2;
437
          x += ix;
438
        }
439
    }
440
 
441
  else          // dy is the major axis
442
    {
443
      // initialize the error term
444
      err = dx2 - dy;
445
 
446
      for (i = 0; i <= dy; i++)
447
        {
448
          drawPixel (x, y, color);
449
          if (err >= 0)
450
            {
451
              err -= dy2;
452
              x += ix;
453
            }
454
          err += dx2;
455
          y += iy;
456
        }
457
    }
458
}
459