SSD1306 OLED display driver  1.4.0
This library is developed to control SSD1306 i2c/spi OLED display
ssd1306.c
1 /*
2  MIT License
3 
4  Copyright (c) 2016-2018, Alexey Dynda
5 
6  Permission is hereby granted, free of charge, to any person obtaining a copy
7  of this software and associated documentation files (the "Software"), to deal
8  in the Software without restriction, including without limitation the rights
9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  copies of the Software, and to permit persons to whom the Software is
11  furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in all
14  copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  SOFTWARE.
23 */
24 
25 #include "font6x8.h"
26 #include "ssd1306.h"
27 #include "lcd/lcd_common.h"
28 #include "i2c/ssd1306_i2c.h"
29 #include "spi/ssd1306_spi.h"
30 #include "intf/ssd1306_interface.h"
31 #include <stdlib.h>
32 
33 // TODO: remove
34 #include "lcd/ssd1306_commands.h"
35 
39 static uint8_t s_invertByte = 0x00000000;
40 const uint8_t *s_font6x8 = &ssd1306xled_font6x8[3];
41 SFixedFontInfo s_fixedFont = { 0 };
42 
44 {
45  return s_displayHeight;
46 }
47 
49 {
50  return s_displayWidth;
51 }
52 
53 void ssd1306_fillScreen(uint8_t fill_Data)
54 {
55  fill_Data ^= s_invertByte;
56  ssd1306_setRamBlock(0, 0, 0);
58  for(uint8_t m=(s_displayHeight >> 3); m>0; m--)
59  {
60  for(uint8_t n=s_displayWidth; n>0; n--)
61  {
62  ssd1306_sendByte(fill_Data);
63  }
65  }
67 }
68 
70 {
71  ssd1306_setRamBlock(0, 0, 0);
73  for(uint8_t m=(s_displayHeight >> 3); m>0; m--)
74  {
75  for(uint8_t n=s_displayWidth; n>0; n--)
76  {
77  ssd1306_sendByte( s_invertByte );
78  }
80  }
82 }
83 
84 
86 {
87  ssd1306_sendCommand(SSD1306_DISPLAYOFF);
88 }
89 
90 
92 {
93  ssd1306_sendCommand(SSD1306_DISPLAYON);
94 }
95 
96 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
97 {
98  uint8_t i, j=0;
99  uint8_t text_index = 0;
100  uint8_t page_offset = 0;
101  uint8_t x = xpos;
102  y >>= 3;
103  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
105  for(;;)
106  {
107  if( (x > s_displayWidth - s_fixedFont.width) || (ch[j] == '\0') )
108  {
109  x = xpos;
110  y++;
111  if (y >= (s_displayHeight >> 3))
112  {
113  break;
114  }
115  page_offset++;
116  if (page_offset == s_fixedFont.pages)
117  {
118  text_index = j;
119  page_offset = 0;
120  if (ch[j] == '\0')
121  {
122  break;
123  }
124  }
125  else
126  {
127  j = text_index;
128  }
130  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
132  }
133  uint8_t c = ch[j] - 32;
134  if ( c > 224 )
135  {
136  c = 0;
137  }
138  uint8_t ldata = 0;
139  uint16_t offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.width;
140  for( i=0; i<s_fixedFont.width; i++)
141  {
142  uint8_t data;
143  if ( style == STYLE_NORMAL )
144  {
145  data = pgm_read_byte(&s_fixedFont.data[offset]);
146  }
147  else if ( style == STYLE_BOLD )
148  {
149  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset]);
150  data = temp | ldata;
151  ldata = temp;
152  }
153  else
154  {
155  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset + 1]);
156  data = (temp & 0xF0) | ldata;
157  ldata = (temp & 0x0F);
158  }
159  ssd1306_sendByte(data^s_invertByte);
160  offset++;
161  }
162  x += s_fixedFont.width;
163  j++;
164  }
166  return j;
167 }
168 
169 uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
170 {
171  uint8_t i, j=0;
172  uint8_t text_index = 0;
173  uint8_t page_offset = 0;
174  uint8_t x = xpos;
175  y >>= 3;
176  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
178  for(;;)
179  {
180  if( (x > s_displayWidth - (s_fixedFont.width << 1)) || (ch[j] == '\0') )
181  {
182  x = xpos;
183  y++;
184  if (y >= (s_displayHeight >> 3))
185  {
186  break;
187  }
188  page_offset++;
189  if (page_offset == (s_fixedFont.pages << 1))
190  {
191  text_index = j;
192  page_offset = 0;
193  if (ch[j] == '\0')
194  {
195  break;
196  }
197  }
198  else
199  {
200  j = text_index;
201  }
203  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
205  }
206  uint8_t c = ch[j] - 32;
207  if ( c > 224 )
208  {
209  c = 0;
210  }
211  uint8_t ldata = 0;
212  uint16_t offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.width;
213  for( i=0; i<s_fixedFont.width; i++)
214  {
215  uint8_t data;
216  if ( style == STYLE_NORMAL )
217  {
218  data = pgm_read_byte(&s_fixedFont.data[offset]);
219  }
220  else if ( style == STYLE_BOLD )
221  {
222  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset]);
223  data = temp | ldata;
224  ldata = temp;
225  }
226  else
227  {
228  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset + 1]);
229  data = (temp & 0xF0) | ldata;
230  ldata = (temp & 0x0F);
231  }
232  if (page_offset & 1) data >>= 4;
233  data = ((data & 0x01) ? 0x03: 0x00) |
234  ((data & 0x02) ? 0x0C: 0x00) |
235  ((data & 0x04) ? 0x30: 0x00) |
236  ((data & 0x08) ? 0xC0: 0x00);
237  ssd1306_sendByte(data^s_invertByte);
238  ssd1306_sendByte(data^s_invertByte);
239  offset++;
240  }
241  x += (s_fixedFont.width << 1);
242  j++;
243  }
245  return j;
246 }
247 
248 
249 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
250 {
251  uint8_t i, j=0;
254  while(ch[j] != '\0')
255  {
256  uint8_t c = ch[j] - 32;
257  if ( c > 224 )
258  {
259  c = 0;
260  }
261  if(x > s_displayWidth - 6)
262  {
263  x=0;
264  y++;
265  }
266  uint8_t ldata = 0;
267  for(i=0;i<6;i++)
268  {
269  uint8_t data;
270  if ( style == STYLE_NORMAL )
271  {
272  data = pgm_read_byte(&s_font6x8[c*6+i]);
273  }
274  else if ( style == STYLE_BOLD )
275  {
276  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
277  data = temp | ldata;
278  ldata = temp;
279  }
280  else
281  {
282  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
283  data = (temp & 0xF0) | ldata;
284  ldata = (temp & 0x0F);
285  }
286  ssd1306_sendByte(data^s_invertByte);
287  }
288  x += 6;
289  j++;
290  }
292  return j;
293 }
294 
295 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
296 {
297  uint8_t i, j=0;
298  uint8_t text_index = 0;
299  uint8_t odd = 0;
300  uint8_t x = xpos;
301  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
303  for(;;)
304  {
305  if( (x > s_displayWidth-12) || (ch[j] == '\0') )
306  {
307  x = xpos;
308  y++;
309  if (y >= (s_displayHeight >> 3))
310  {
311  break;
312  }
313  if (odd)
314  {
315  text_index = j;
316  if (ch[j] == '\0')
317  {
318  break;
319  }
320  }
321  else
322  {
323  j = text_index;
324  }
325  odd = !odd;
327  ssd1306_setRamBlock(xpos, y, s_displayWidth - xpos);
329  }
330  uint8_t c = ch[j] - 32;
331  if ( c > 224 )
332  {
333  c = 0;
334  }
335  uint8_t ldata = 0;
336  for(i=0;i<6;i++)
337  {
338  uint8_t data;
339  if ( style == STYLE_NORMAL )
340  {
341  data = pgm_read_byte(&s_font6x8[c*6+i]);
342  }
343  else if ( style == STYLE_BOLD )
344  {
345  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
346  data = temp | ldata;
347  ldata = temp;
348  }
349  else
350  {
351  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
352  data = (temp & 0xF0) | ldata;
353  ldata = (temp & 0x0F);
354  }
355  if (odd) data >>= 4;
356  data = ((data & 0x01) ? 0x03: 0x00) |
357  ((data & 0x02) ? 0x0C: 0x00) |
358  ((data & 0x04) ? 0x30: 0x00) |
359  ((data & 0x08) ? 0xC0: 0x00);
360  ssd1306_sendByte(data^s_invertByte);
361  ssd1306_sendByte(data^s_invertByte);
362  }
363  x += 12;
364  j++;
365  }
367  return j;
368 }
369 
370 uint8_t ssd1306_charF6x8_eol(uint8_t left,
371  uint8_t y,
372  const char ch[],
373  EFontStyle style,
374  uint8_t right)
375 {
376  uint8_t len = ssd1306_charF6x8(left, y, ch, style);
377  uint8_t text_end_pos = len * 6 + left;
378  if (text_end_pos <= right)
379  {
380  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
381  }
382  return len;
383 }
384 
385 void ssd1306_setFixedFont(const uint8_t * progmemFont)
386 {
387  s_fixedFont.width = pgm_read_byte(&progmemFont[1]);
388  s_fixedFont.pages = pgm_read_byte(&progmemFont[2]) >> 3;
389  s_fixedFont.data = progmemFont + 3;
390 }
391 
392 void ssd1306_setFont6x8(const uint8_t * progmemFont)
393 {
394  s_font6x8 = progmemFont;
395 }
396 
397 void ssd1306_putPixel(uint8_t x, uint8_t y)
398 {
399  ssd1306_setRamBlock(x, y >> 3, 1);
401  ssd1306_sendByte((1 << (y & 0x07))^s_invertByte);
403 }
404 
405 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
406 {
407  ssd1306_setRamBlock(x, y >> 3, 1);
409  ssd1306_sendByte(pixels^s_invertByte);
411 }
412 
413 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
414 {
415  ssd1306_setRamBlock(x1, y1 >> 3, x2 - x1 + 1);
417  for (uint8_t x = x1; x <= x2; x++)
418  {
419  ssd1306_sendByte((1 << (y1 & 0x07))^s_invertByte);
420  }
422 }
423 
424 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
425 {
426  uint8_t topPage = y1 >> 3;
427  uint8_t bottomPage = y2 >> 3;
428  uint8_t height = y2-y1;
429  ssd1306_setRamBlock(x1, topPage, 1);
431  if (topPage == bottomPage)
432  {
433  ssd1306_sendByte( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_invertByte );
435  return;
436  }
437  ssd1306_sendByte( (0xFF << (y1 & 0x07))^s_invertByte );
438  uint8_t y;
439  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
440  {
442  ssd1306_sendByte( 0xFF^s_invertByte );
443  }
445  ssd1306_sendByte( (0xFF >> (0x07 - (y2 & 0x07)))^s_invertByte );
447 }
448 
449 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
450 {
451  ssd1306_drawHLine(x1+1, y1, x2-1);
452  ssd1306_drawHLine(x1+1, y2, x2-1);
453  ssd1306_drawVLine(x1, y1, y2);
454  ssd1306_drawVLine(x2, y1, y2);
455 }
456 
457 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
458 {
459  uint8_t i, j;
460  ssd1306_setRamBlock(x, y, w);
462  for(j=0; j<(h >> 3); j++)
463  {
464  for(i=0;i<w;i++)
465  {
466  ssd1306_sendByte(s_invertByte^*buf++);
467  }
469  }
471 }
472 
473 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
474 {
475  uint8_t i, j;
476  ssd1306_setRamBlock(x, y, w);
478  for(j=0; j<(h >> 3); j++)
479  {
480  for(i=w;i>0;i--)
481  {
482  ssd1306_sendByte(s_invertByte^pgm_read_byte(buf++));
483  }
485  }
487 }
488 
489 
490 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
491 {
492  uint8_t i, j;
493  ssd1306_setRamBlock(x, y, w);
495  for(j=0; j<(h >> 3); j++)
496  {
497  for(i=w;i>0;i--)
498  {
499  ssd1306_sendByte(s_invertByte);
500  }
502  }
504 }
505 
506 
507 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
508 {
509  uint8_t i;
510  ssd1306_setRamBlock(x,y,w);
512  for(i=0;i<w;i++)
513  {
514  ssd1306_sendByte(s_invertByte^pgm_read_byte(&sprite[i]));
515  }
517 }
518 
519 
521 {
522  uint8_t offsety = sprite->y & 0x7;
523  if (sprite->y < s_displayHeight)
524  {
525  ssd1306_setRamBlock(sprite->x, sprite->y >> 3, sprite->w);
527  for (uint8_t i=0; i < sprite->w; i++)
528  {
529  ssd1306_sendByte( s_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
530  }
532  }
533  if (offsety && (sprite->y + 8 < s_displayHeight))
534  {
535  ssd1306_setRamBlock(sprite->x, (sprite->y >> 3) + 1, sprite->w);
537  for (uint8_t i=0; i < sprite->w; i++)
538  {
539  ssd1306_sendByte( s_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
540  }
541  }
543  sprite->lx = sprite->x;
544  sprite->ly = sprite->y;
545 }
546 
547 
549 {
550  uint8_t posy = sprite->y >> 3;
551  uint8_t offsety = sprite->y & 0x7;
552  ssd1306_setRamBlock(sprite->x, posy, sprite->w);
554  for (uint8_t i=0; i < sprite->w; i++)
555  {
556  ssd1306_sendByte( s_invertByte );
557  }
559  if (offsety)
560  {
561  ssd1306_setRamBlock(sprite->x, posy + 1, sprite->w);
563  for (uint8_t i=0; i < sprite->w; i++)
564  {
565  ssd1306_sendByte( s_invertByte );
566  }
567  }
569 }
570 
571 
573 {
574  uint8_t y1 = sprite->ly >> 3;
575  uint8_t y2 = (sprite->ly + 7) >> 3;
576  if (sprite->ly < sprite->y)
577  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
578  else
579  y1 = max(y1, (sprite->ly + 7) >> 3);
580  for(uint8_t y = y1; y <= y2; y++)
581  {
582  ssd1306_setRamBlock(sprite->lx, y, sprite->w);
584  for(uint8_t x = sprite->lx; x < sprite->lx + sprite->w; x++)
585  {
586  ssd1306_sendByte( s_invertByte );
587  }
589  }
590  if (sprite->lx != sprite->x)
591  {
592  uint8_t x1 = sprite->lx;
593  uint8_t x2 = sprite->lx + sprite->w - 1;
594  if (sprite->x < sprite->lx)
595  x1 = max(x1, sprite->x + sprite->w);
596  else
597  x2 = min((uint8_t)(sprite->x - 1), x2);
598  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
599  {
600  ssd1306_setRamBlock(x1, y, x2 - x1 +1 );
602  for(uint8_t x = x1; x <= x2; x++)
603  {
604  ssd1306_sendByte( s_invertByte );
605  }
607  }
608  }
609 }
610 
611 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
612 {
613  return (SPRITE){x,y,w,x,y,data,NULL};
614 }
615 
616 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
617 {
618  sprite->data = data;
619 }
620 
622 {
623  ssd1306_sendCommand(SSD1306_INVERTDISPLAY);
624 }
625 
627 {
628  ssd1306_sendCommand(SSD1306_NORMALDISPLAY);
629 }
630 
632 {
633  s_invertByte = 0xFF;
634 }
635 
637 {
638  s_invertByte = 0x00;
639 }
void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306.c:473
void ssd1306_negativeMode()
Definition: ssd1306.c:631
const uint8_t * data
Pointer to PROGMEM data, representing sprite image.
void(* ssd1306_sendByte)(uint8_t data)
void ssd1306_displayOff()
Definition: ssd1306.c:85
void(* ssd1306_dataStart)()
void(* ssd1306_endTransmission)()
uint8_t ssd1306_displayHeight()
Definition: ssd1306.c:43
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
Definition: ssd1306.c:616
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: ssd1306.c:413
void(* ssd1306_nextRamPage)()
void ssd1306_setFont6x8(const uint8_t *progmemFont)
Definition: ssd1306.c:392
uint8_t ssd1306_charF6x8_eol(uint8_t left, uint8_t y, const char ch[], EFontStyle style, uint8_t right)
Definition: ssd1306.c:370
void ssd1306_displayOn()
Definition: ssd1306.c:91
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: ssd1306.c:424
void ssd1306_positiveMode()
Definition: ssd1306.c:636
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
Definition: ssd1306.c:405
SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
Definition: ssd1306.c:611
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
Definition: ssd1306.c:507
void ssd1306_sendCommand(uint8_t command)
void ssd1306_fillScreen(uint8_t fill_Data)
Definition: ssd1306.c:53
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306.c:449
void ssd1306_clearScreen()
Definition: ssd1306.c:69
#define max(a, b)
uint8_t y
draw position Y on the screen
#define min(a, b)
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306.c:295
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306.c:249
void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Definition: ssd1306.c:490
void ssd1306_setFixedFont(const uint8_t *progmemFont)
Definition: ssd1306.c:385
uint8_t width
width in pixels
uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306.c:169
void ssd1306_invertMode()
Definition: ssd1306.c:621
uint8_t x
draw position X on the screen
uint8_t ssd1306_displayWidth()
Definition: ssd1306.c:48
void ssd1306_drawSprite(SPRITE *sprite)
Definition: ssd1306.c:520
void ssd1306_eraseTrace(SPRITE *sprite)
Definition: ssd1306.c:572
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306.c:457
void ssd1306_eraseSprite(SPRITE *sprite)
Definition: ssd1306.c:548
uint8_t g_lcd_type
Definition: ssd1306.c:38
uint8_t s_displayHeight
Definition: ssd1306.c:36
void ssd1306_normalMode()
Definition: ssd1306.c:626
uint8_t w
sprite width
void(* ssd1306_setRamBlock)(uint8_t x, uint8_t y, uint8_t w)
void ssd1306_putPixel(uint8_t x, uint8_t y)
Definition: ssd1306.c:397
uint8_t lx
last draw position X on the screen
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306.c:96
const uint8_t * data
font chars bits
EFontStyle
uint8_t pages
height in pages
uint8_t s_displayWidth
Definition: ssd1306.c:37
uint8_t ly
last draw position Y on the screen