SSD1306 OLED display driver  1.8.2
This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_1bit.c
1 /*
2  MIT License
3 
4  Copyright (c) 2016-2019, 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 
28 
29 #include "ssd1306.h"
30 #include "ssd1306_fonts.h"
31 #include "lcd/lcd_common.h"
32 #include "intf/i2c/ssd1306_i2c.h"
33 #include "intf/spi/ssd1306_spi.h"
34 #include "intf/ssd1306_interface.h"
35 #include "ssd1306_hal/io.h"
36 
37 // TODO: remove
38 #include "lcd/ssd1306_commands.h"
39 
40 uint8_t s_ssd1306_invertByte = 0x00000000;
41 extern uint16_t ssd1306_color;
42 const uint8_t *s_font6x8 = &ssd1306xled_font6x8[4];
43 extern lcduint_t ssd1306_cursorX;
44 extern lcduint_t ssd1306_cursorY;
46 #ifdef CONFIG_SSD1306_UNICODE_ENABLE
47 extern uint8_t g_ssd1306_unicode;
48 #endif
49 
50 void ssd1306_fillScreen(uint8_t fill_Data)
51 {
52  fill_Data ^= s_ssd1306_invertByte;
53  ssd1306_lcd.set_block(0, 0, 0);
54  for(lcduint_t m=(ssd1306_lcd.height >> 3); m>0; m--)
55  {
56  for(lcduint_t n=ssd1306_lcd.width; n>0; n--)
57  {
58  ssd1306_lcd.send_pixels1(fill_Data);
59  }
61  }
63 }
64 
66 {
67  ssd1306_lcd.set_block(0, 0, 0);
68  for(lcduint_t m=(ssd1306_lcd.height >> 3); m>0; m--)
69  {
70  for(lcduint_t n=ssd1306_lcd.width; n>0; n--)
71  {
72  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
73  }
75  }
77 }
78 
79 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
80 {
81  uint8_t i, j=0;
82  uint8_t text_index = 0;
83  uint8_t page_offset = 0;
84  uint8_t x = xpos;
85  y >>= 3;
86  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
87  for(;;)
88  {
89  uint8_t ldata;
90  if ((x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0'))
91  {
92  x = xpos;
93  y++;
94  if (y >= (ssd1306_lcd.height >> 3))
95  {
96  break;
97  }
98  page_offset++;
99  if (page_offset == s_fixedFont.pages)
100  {
101  text_index = j;
102  page_offset = 0;
103  if (ch[j] == '\0')
104  {
105  break;
106  }
107  }
108  else
109  {
110  j = text_index;
111  }
112  ssd1306_intf.stop();
113  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
114  }
115  uint16_t unicode;
116  do
117  {
118  unicode = ssd1306_unicode16FromUtf8(ch[j]);
119  j++;
120  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
121  SCharInfo char_info;
122  ssd1306_getCharBitmap(unicode, &char_info);
123  ldata = 0;
124  x += char_info.width + char_info.spacing;
125  if (char_info.height > page_offset * 8)
126  {
127  char_info.glyph += page_offset * char_info.width;
128  for( i = char_info.width; i>0; i--)
129  {
130  uint8_t data;
131  if ( style == STYLE_NORMAL )
132  {
133  data = pgm_read_byte(&char_info.glyph[0]);
134  }
135  else if ( style == STYLE_BOLD )
136  {
137  uint8_t temp = pgm_read_byte(&char_info.glyph[0]);
138  data = temp | ldata;
139  ldata = temp;
140  }
141  else
142  {
143  uint8_t temp = pgm_read_byte(&char_info.glyph[1]);
144  data = (temp & 0xF0) | ldata;
145  ldata = (temp & 0x0F);
146  }
147  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
148  char_info.glyph++;
149  }
150  }
151  else
152  {
153  char_info.spacing += char_info.width;
154  }
155  for (i = 0; i < char_info.spacing; i++)
156  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
157  }
158  ssd1306_intf.stop();
159  return j;
160 }
161 
162 uint8_t ssd1306_printFixed_oldStyle(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
163 {
164  uint8_t i, j=0;
165  uint8_t text_index = 0;
166  uint8_t page_offset = 0;
167  uint8_t x = xpos;
168  y >>= 3;
169  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
170  for(;;)
171  {
172  uint8_t c;
173  uint8_t ldata;
174  uint16_t offset;
175  if( (x > ssd1306_lcd.width - s_fixedFont.h.width) || (ch[j] == '\0') )
176  {
177  x = xpos;
178  y++;
179  if (y >= (ssd1306_lcd.height >> 3))
180  {
181  break;
182  }
183  page_offset++;
184  if (page_offset == s_fixedFont.pages)
185  {
186  text_index = j;
187  page_offset = 0;
188  if (ch[j] == '\0')
189  {
190  break;
191  }
192  }
193  else
194  {
195  j = text_index;
196  }
197  ssd1306_intf.stop();
198  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
199  }
200  c = ch[j];
201  if ( c >= s_fixedFont.h.ascii_offset )
202  {
203  c -= s_fixedFont.h.ascii_offset;
204  }
205  ldata = 0;
206  offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.h.width;
207  for( i=s_fixedFont.h.width; i>0; i--)
208  {
209  uint8_t data;
210  if ( style == STYLE_NORMAL )
211  {
212  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
213  }
214  else if ( style == STYLE_BOLD )
215  {
216  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
217  data = temp | ldata;
218  ldata = temp;
219  }
220  else
221  {
222  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
223  data = (temp & 0xF0) | ldata;
224  ldata = (temp & 0x0F);
225  }
226  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
227  offset++;
228  }
229  x += s_fixedFont.h.width;
230  j++;
231  }
232  ssd1306_intf.stop();
233  return j;
234 }
235 
236 uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
237 {
238  uint8_t i, j=0;
239  uint8_t text_index = 0;
240  uint8_t page_offset = 0;
241  uint8_t x = xpos;
242  y >>= 3;
243  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
244  for(;;)
245  {
246  uint8_t c;
247  uint8_t ldata;
248  uint16_t offset;
249  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << 1)) || (ch[j] == '\0') )
250  {
251  x = xpos;
252  y++;
253  if (y >= (ssd1306_lcd.height >> 3))
254  {
255  break;
256  }
257  page_offset++;
258  if (page_offset == (s_fixedFont.pages << 1))
259  {
260  text_index = j;
261  page_offset = 0;
262  if (ch[j] == '\0')
263  {
264  break;
265  }
266  }
267  else
268  {
269  j = text_index;
270  }
271  ssd1306_intf.stop();
272  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
273  }
274  c = ch[j];
275  if ( c >= 32 )
276  {
277  c -= 32;
278  }
279  ldata = 0;
280  offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.h.width;
281  for( i=s_fixedFont.h.width; i>0; i--)
282  {
283  uint8_t data;
284  if ( style == STYLE_NORMAL )
285  {
286  data = pgm_read_byte(&s_fixedFont.primary_table[offset]);
287  }
288  else if ( style == STYLE_BOLD )
289  {
290  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset]);
291  data = temp | ldata;
292  ldata = temp;
293  }
294  else
295  {
296  uint8_t temp = pgm_read_byte(&s_fixedFont.primary_table[offset + 1]);
297  data = (temp & 0xF0) | ldata;
298  ldata = (temp & 0x0F);
299  }
300  if (page_offset & 1) data >>= 4;
301  data = ((data & 0x01) ? 0x03: 0x00) |
302  ((data & 0x02) ? 0x0C: 0x00) |
303  ((data & 0x04) ? 0x30: 0x00) |
304  ((data & 0x08) ? 0xC0: 0x00);
305  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
306  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
307  offset++;
308  }
309  x += (s_fixedFont.h.width << 1);
310  j++;
311  }
312  ssd1306_intf.stop();
313  return j;
314 }
315 
316 
317 uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
318 {
319  uint8_t i, j=0;
320  uint8_t text_index = 0;
321  uint8_t page_offset = 0;
322  uint8_t x = xpos;
323  y >>= 3;
324  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
325  for(;;)
326  {
327  uint8_t ldata;
328  if( (x > ssd1306_lcd.width - (s_fixedFont.h.width << factor)) || (ch[j] == '\0') )
329  {
330  x = xpos;
331  y++;
332  if (y >= (ssd1306_lcd.height >> 3))
333  {
334  break;
335  }
336  page_offset++;
337  if (page_offset == (s_fixedFont.pages << factor))
338  {
339  text_index = j;
340  page_offset = 0;
341  if (ch[j] == '\0')
342  {
343  break;
344  }
345  }
346  else
347  {
348  j = text_index;
349  }
350  ssd1306_intf.stop();
351  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
352  }
353  uint16_t unicode;
354  do
355  {
356  unicode = ssd1306_unicode16FromUtf8(ch[j]);
357  j++;
358  } while ( unicode == SSD1306_MORE_CHARS_REQUIRED );
359  SCharInfo char_info;
360  ssd1306_getCharBitmap(unicode, &char_info);
361  ldata = 0;
362  x += ((char_info.width + char_info.spacing) << factor);
363  if (char_info.height > (page_offset >> factor) * 8)
364  {
365  char_info.glyph += (page_offset >> factor) * char_info.width;
366  for( i=char_info.width; i>0; i--)
367  {
368  uint8_t data;
369  if ( style == STYLE_NORMAL )
370  {
371  data = pgm_read_byte(char_info.glyph);
372  }
373  else if ( style == STYLE_BOLD )
374  {
375  uint8_t temp = pgm_read_byte(char_info.glyph);
376  data = temp | ldata;
377  ldata = temp;
378  }
379  else
380  {
381  uint8_t temp = pgm_read_byte(char_info.glyph+1);
382  data = (temp & 0xF0) | ldata;
383  ldata = (temp & 0x0F);
384  }
385  if ( factor > 0 )
386  {
387  uint8_t accum = 0;
388  uint8_t mask = ~((0xFF) << (1<<factor));
389  // N=0 -> right shift is always 0
390  // N=1 -> right shift goes through 0, 4
391  // N=2 -> right shift goes through 0, 2, 4, 6
392  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
393  data >>= ((page_offset & ((1<<factor) - 1))<<(3-factor));
394  for (uint8_t idx = 0; idx < 1<<(3-factor); idx++)
395  {
396  accum |= (((data>>idx) & 0x01) ? (mask<<(idx<<factor)) : 0);
397  }
398  data = accum;
399  }
400  for (uint8_t z=(1<<factor); z>0; z--)
401  {
402  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
403  }
404  char_info.glyph++;
405  }
406  }
407  else
408  {
409  char_info.spacing += char_info.width;
410  }
411  for (i = 0; i < (char_info.spacing << factor); i++)
412  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
413  }
414  ssd1306_intf.stop();
415  return j;
416 }
417 
418 size_t ssd1306_write(uint8_t ch)
419 {
420  if (ch == '\r')
421  {
422  ssd1306_cursorX = 0;
423  return 0;
424  }
425  SCharInfo char_info = {};
426  uint8_t gotoNewLine = 1;
427  if (ch != '\n')
428  {
429  uint16_t unicode;
430  unicode = ssd1306_unicode16FromUtf8(ch);
431  if (unicode == SSD1306_MORE_CHARS_REQUIRED) return 0;
432  ssd1306_getCharBitmap(unicode, &char_info);
433  gotoNewLine = (ssd1306_cursorX > (ssd1306_lcd.width - char_info.width));
434  }
435  if ( gotoNewLine )
436  {
437  ssd1306_cursorX = 0;
438  ssd1306_cursorY += s_fixedFont.h.height;
439  if ( ssd1306_cursorY > ssd1306_lcd.height - s_fixedFont.h.height )
440  {
441  ssd1306_cursorY = 0;
442  }
443  ssd1306_clearBlock(0, ssd1306_cursorY >> 3, ssd1306_lcd.width, s_fixedFont.h.height);
444  if (ch == '\n')
445  {
446  return 0;
447  }
448  }
449  ssd1306_drawBitmap( ssd1306_cursorX,
450  ssd1306_cursorY >> 3,
451  char_info.width,
452  char_info.height,
453  char_info.glyph );
454  ssd1306_cursorX += char_info.width + char_info.spacing;
455  return 1;
456 }
457 
458 size_t ssd1306_print(const char ch[])
459 {
460  size_t n = 0;
461  while (*ch)
462  {
463  n += ssd1306_write(*ch);
464  ch++;
465  }
466  return n;
467 }
468 
469 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
470 {
471  uint8_t i, j=0;
473  while(ch[j] != '\0')
474  {
475  uint8_t ldata;
476  uint8_t c = ch[j] - 32;
477  if ( c > 224 )
478  {
479  c = 0;
480  }
481  if(x > ssd1306_lcd.width - 6)
482  {
483  x=0;
484  y++;
485  }
486  ldata = 0;
487  for(i=0;i<6;i++)
488  {
489  uint8_t data;
490  if ( style == STYLE_NORMAL )
491  {
492  data = pgm_read_byte(&s_font6x8[c*6+i]);
493  }
494  else if ( style == STYLE_BOLD )
495  {
496  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
497  data = temp | ldata;
498  ldata = temp;
499  }
500  else
501  {
502  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
503  data = (temp & 0xF0) | ldata;
504  ldata = (temp & 0x0F);
505  }
506  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
507  }
508  x += 6;
509  j++;
510  }
511  ssd1306_intf.stop();
512  return j;
513 }
514 
515 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
516 {
517  uint8_t i, j=0;
518  uint8_t text_index = 0;
519  uint8_t odd = 0;
520  uint8_t x = xpos;
521  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
522  for(;;)
523  {
524  uint8_t c;
525  uint8_t ldata;
526  if( (x > ssd1306_lcd.width-12) || (ch[j] == '\0') )
527  {
528  x = xpos;
529  y++;
530  if (y >= (ssd1306_lcd.height >> 3))
531  {
532  break;
533  }
534  if (odd)
535  {
536  text_index = j;
537  if (ch[j] == '\0')
538  {
539  break;
540  }
541  }
542  else
543  {
544  j = text_index;
545  }
546  odd = !odd;
547  ssd1306_intf.stop();
548  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
549  }
550  c = ch[j] - 32;
551  if ( c > 224 )
552  {
553  c = 0;
554  }
555  ldata = 0;
556  for(i=0;i<6;i++)
557  {
558  uint8_t data;
559  if ( style == STYLE_NORMAL )
560  {
561  data = pgm_read_byte(&s_font6x8[c*6+i]);
562  }
563  else if ( style == STYLE_BOLD )
564  {
565  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
566  data = temp | ldata;
567  ldata = temp;
568  }
569  else
570  {
571  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
572  data = (temp & 0xF0) | ldata;
573  ldata = (temp & 0x0F);
574  }
575  if (odd) data >>= 4;
576  data = ((data & 0x01) ? 0x03: 0x00) |
577  ((data & 0x02) ? 0x0C: 0x00) |
578  ((data & 0x04) ? 0x30: 0x00) |
579  ((data & 0x08) ? 0xC0: 0x00);
580  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
581  ssd1306_lcd.send_pixels1(data^s_ssd1306_invertByte);
582  }
583  x += 12;
584  j++;
585  }
586  ssd1306_intf.stop();
587  return j;
588 }
589 
590 uint8_t ssd1306_charF6x8_eol(uint8_t left,
591  uint8_t y,
592  const char ch[],
593  EFontStyle style,
594  uint8_t right)
595 {
596  uint8_t len = ssd1306_printFixed(left, y<<3, ch, style);
597  uint8_t text_end_pos = len * 6 + left;
598  if (text_end_pos <= right)
599  {
600  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
601  }
602  return len;
603 }
604 
605 void ssd1306_putPixel(uint8_t x, uint8_t y)
606 {
607  ssd1306_lcd.set_block(x, y >> 3, 1);
608  ssd1306_lcd.send_pixels1((1 << (y & 0x07))^s_ssd1306_invertByte);
609  ssd1306_intf.stop();
610 }
611 
612 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
613 {
614  ssd1306_lcd.set_block(x, y >> 3, 1);
615  ssd1306_lcd.send_pixels1(pixels^s_ssd1306_invertByte);
616  ssd1306_intf.stop();
617 }
618 
619 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
620 {
621  static uint8_t lx = 0, ly = 0xFF;
622  static uint8_t pixels = 0;
623  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
624  {
625  if (ly != 0xFF)
626  {
627  ssd1306_putPixels( lx, ly, pixels );
628  }
629  pixels = 0;
630  ly = 0xFF;
631  }
632  if ( !complete )
633  {
634  pixels |= (1 << (y & 0x07));
635  lx = x; ly = y;
636  }
637 }
638 
639 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
640 {
641  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
642  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
643  lcduint_t err = 0;
644  if (dy > dx)
645  {
646  if (y1 > y2)
647  {
648  ssd1306_swap_data(x1, x2, uint8_t);
649  ssd1306_swap_data(y1, y2, uint8_t);
650  }
651  for(; y1<=y2; y1++)
652  {
653  err += dx;
654  if (err >= dy)
655  {
656  err -= dy;
657  x1 < x2 ? x1++: x1--;
658  }
659  ssd1306_putPixel_delayed( x1, y1, 0 );
660  }
661  ssd1306_putPixel_delayed( 0, 0, 1 );
662  }
663  else
664  {
665  if (x1 > x2)
666  {
667  ssd1306_swap_data(x1, x2, uint8_t);
668  ssd1306_swap_data(y1, y2, uint8_t);
669  }
670  for(; x1<=x2; x1++)
671  {
672  err += dy;
673  if (err >= dx)
674  {
675  err -= dx;
676  if (y1 < y2) y1++; else y1--;
677  }
678  ssd1306_putPixel( x1, y1 );
679  }
680  }
681 }
682 
683 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
684 {
685  ssd1306_lcd.set_block(x1, y1 >> 3, x2 - x1 + 1);
686  for (uint8_t x = x1; x <= x2; x++)
687  {
688  ssd1306_lcd.send_pixels1((1 << (y1 & 0x07))^s_ssd1306_invertByte);
689  }
690  ssd1306_intf.stop();
691 }
692 
693 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
694 {
695  uint8_t topPage = y1 >> 3;
696  uint8_t bottomPage = y2 >> 3;
697  uint8_t height = y2-y1;
698  uint8_t y;
699  ssd1306_lcd.set_block(x1, topPage, 1);
700  if (topPage == bottomPage)
701  {
702  ssd1306_lcd.send_pixels1( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_ssd1306_invertByte );
703  ssd1306_intf.stop();
704  return;
705  }
706  ssd1306_lcd.send_pixels1( (0xFF << (y1 & 0x07))^s_ssd1306_invertByte );
707  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
708  {
710  ssd1306_lcd.send_pixels1( 0xFF^s_ssd1306_invertByte );
711  }
713  ssd1306_lcd.send_pixels1( (0xFF >> (0x07 - (y2 & 0x07)))^s_ssd1306_invertByte );
714  ssd1306_intf.stop();
715 }
716 
717 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
718 {
719  ssd1306_drawHLine(x1+1, y1, x2-1);
720  ssd1306_drawHLine(x1+1, y2, x2-1);
721  ssd1306_drawVLine(x1, y1, y2);
722  ssd1306_drawVLine(x2, y1, y2);
723 }
724 
725 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
726 {
727  uint8_t j;
728  ssd1306_lcd.set_block(x, y >> 3, w);
729  for(j=(h >> 3); j>0; j--)
730  {
732  buf+=w;
734  }
735  ssd1306_intf.stop();
736 }
737 
738 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
739 {
740  uint8_t i, j;
741  ssd1306_lcd.set_block(x, y, w);
742  for(j=(h >> 3); j>0; j--)
743  {
744  for(i=w;i>0;i--)
745  {
746  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^*buf++);
747  }
749  }
750  ssd1306_intf.stop();
751 }
752 
753 void ssd1306_drawBuffer1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
754 {
755  uint8_t i, j, k;
756  ssd1306_lcd.set_block(x, y>>3, w);
757  uint8_t y_offset = (y & 0x07);
758  uint8_t x_offset = (x & 0x01);
759  for( j = 0; j < ((h + 7 + y_offset) >> 3); j++)
760  {
761  for( i = 0; i < w / 2 + x_offset; i++)
762  {
763  for( k = 0; k < 8; k++)
764  {
765  if ((j*8 + k - y_offset < h) && (k >= y_offset || j != 0))
766  {
767  uint8_t data = (i < w / 2) ? buf[ i + (j * 8 + k - y_offset) * w / 2 ]: 0x00;
768  if ( x_offset )
769  {
770  data <<= 4;
771  if ( i > 0) data |= buf[ i + (j * 8 + k - y_offset) * w / 2 - 1] >> 4;
772  }
773  ssd1306_lcd.send_pixels8( data );
774  }
775  else
776  {
777  ssd1306_lcd.send_pixels8( 0x00 );
778  }
779  }
780  }
782  }
783  ssd1306_intf.stop();
784 }
785 
786 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
787 {
788  uint8_t i, j;
789  uint8_t remainder = (ssd1306_lcd.width - x) < w ? (w + x - ssd1306_lcd.width): 0;
790  w -= remainder;
791  ssd1306_lcd.set_block(x, y, w);
792  for(j=(h >> 3); j>0; j--)
793  {
794  for(i=w;i>0;i--)
795  {
796  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(buf++));
797  }
798  buf += remainder;
800  }
801  ssd1306_intf.stop();
802 }
803 
804 void ssd1306_drawBitmap1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
805 {
806  uint8_t i, j, k;
807  ssd1306_lcd.set_block(x, y>>3, w);
808  uint8_t y_offset = (y & 0x07);
809  uint8_t x_offset = (x & 0x01);
810  for( j = 0; j < ((h + 7 + y_offset) >> 3); j++)
811  {
812  for( i = 0; i < w / 2 + x_offset; i++)
813  {
814  for( k = 0; k < 8; k++)
815  {
816  if ((j*8 + k - y_offset < h) && (k >= y_offset || j != 0))
817  {
818  uint8_t data = (i < w / 2) ? pgm_read_byte( &buf[ i + (j * 8 + k - y_offset) * w / 2 ] ) : 0x00;
819  if ( x_offset )
820  {
821  data <<= 4;
822  if ( i > 0) data |= pgm_read_byte( &buf[ i + (j * 8 + k - y_offset) * w / 2 - 1] ) >> 4;
823  }
824  ssd1306_lcd.send_pixels8( data );
825  }
826  else
827  {
828  ssd1306_lcd.send_pixels8( 0x00 );
829  }
830  }
831  }
833  }
834  ssd1306_intf.stop();
835 }
836 
837 void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
838 {
839  uint8_t i, j;
840  lcduint_t pitch = (w + 7) >> 3;
841  ssd1306_lcd.set_block(x, y, w);
842  for(j=(h >> 3); j>0; j--)
843  {
844  uint8_t bit = 0;
845  for(i=w;i>0;i--)
846  {
847  uint8_t data = 0;
848  for (uint8_t k = 0; k<8; k++)
849  {
850  data |= ( ((pgm_read_byte(&buf[k*pitch]) >> bit) & 0x01) << k );
851  }
852  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
853  bit++;
854  if (bit >= 8)
855  {
856  buf++;
857  bit=0;
858  }
859  }
860  if (bit)
861  {
862  buf++;
863  }
864  buf += pitch * 7;
866  }
867  ssd1306_intf.stop();
868 }
869 
870 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
871 {
872  lcduint_t origin_width = w;
873  uint8_t offset = y & 0x07;
874  uint8_t complexFlag = 0;
875  uint8_t mainFlag = 1;
876  uint8_t max_pages;
877  uint8_t pages;
878  lcduint_t i, j;
879  if (y + (lcdint_t)h <= 0) return;
880  if (y >= ssd1306_lcd.height) return;
881  if (x + (lcdint_t)w <= 0) return;
882  if (x >= ssd1306_lcd.width) return;
883  if (y < 0)
884  {
885  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
886  h += y;
887  y = 0;
888  complexFlag = 1;
889  }
890  if (x < 0)
891  {
892  buf += -x;
893  w += x;
894  x = 0;
895  }
896  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
897  if ((lcduint_t)((lcduint_t)y + h) > (lcduint_t)ssd1306_lcd.height)
898  {
899  h = (lcduint_t)(ssd1306_lcd.height - (lcduint_t)y);
900  }
901  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
902  {
903  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
904  }
905  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
906 
907  ssd1306_lcd.set_block(x, y >> 3, w);
908  for(j=0; j < pages; j++)
909  {
910  if ( j == max_pages - 1 ) mainFlag = !offset;
911  for( i=w; i > 0; i--)
912  {
913  uint8_t data = 0;
914  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
915  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
916  buf++;
917  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^data);
918  }
919  buf += origin_width - w;
920  complexFlag = offset;
922  }
923  ssd1306_intf.stop();
924 }
925 
926 
927 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
928 {
929  uint8_t i, j;
930  ssd1306_lcd.set_block(x, y, w);
931  for(j=(h >> 3); j>0; j--)
932  {
933  for(i=w;i>0;i--)
934  {
935  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte);
936  }
938  }
939  ssd1306_intf.stop();
940 }
941 
942 void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
943 {
944  uint8_t templ = ssd1306_color^s_ssd1306_invertByte;
945  if (x1 > x2) return;
946  if (y1 > y2) return;
947  if ((lcduint_t)x2 >= ssd1306_displayWidth()) x2 = (lcdint_t)ssd1306_displayWidth() - 1;
948  if ((lcduint_t)y2 >= ssd1306_displayHeight()) y2 = (lcdint_t)ssd1306_displayHeight() - 1;
949  uint8_t bank1 = (y1 >> 3);
950  uint8_t bank2 = (y2 >> 3);
951  ssd1306_lcd.set_block(x1, bank1, x2 - x1 + 1);
952  for (uint8_t bank = bank1; bank<=bank2; bank++)
953  {
954  uint8_t mask = 0xFF;
955  if (bank1 == bank2)
956  {
957  mask = (mask >> ((y1 & 7) + 7 - (y2 & 7))) << (y1 & 7);
958  }
959  else if (bank1 == bank)
960  {
961  mask = (mask << (y1 & 7));
962  }
963  else if (bank2 == bank)
964  {
965  mask = (mask >> (7 - (y2 & 7)));
966  }
967  for (uint8_t x=x1; x<=x2; x++)
968  {
969  ssd1306_lcd.send_pixels1(templ & mask);
970  }
972  }
973  ssd1306_intf.stop();
974 }
975 
976 
977 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
978 {
979  uint8_t i;
980  ssd1306_lcd.set_block(x,y,w);
981  for(i=0;i<w;i++)
982  {
983  ssd1306_lcd.send_pixels1(s_ssd1306_invertByte^pgm_read_byte(&sprite[i]));
984  }
985  ssd1306_intf.stop();
986 }
987 
988 
990 {
991  uint8_t offsety = sprite->y & 0x7;
992  if (sprite->y < ssd1306_lcd.height)
993  {
994  ssd1306_lcd.set_block(sprite->x, sprite->y >> 3, sprite->w);
995  for (uint8_t i=0; i < sprite->w; i++)
996  {
997  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
998  }
999  ssd1306_intf.stop();
1000  }
1001  if (offsety && (sprite->y + 8 < ssd1306_lcd.height))
1002  {
1003  ssd1306_lcd.set_block(sprite->x, (sprite->y >> 3) + 1, sprite->w);
1004  for (uint8_t i=0; i < sprite->w; i++)
1005  {
1006  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
1007  }
1008  ssd1306_intf.stop();
1009  }
1010  sprite->lx = sprite->x;
1011  sprite->ly = sprite->y;
1012 }
1013 
1014 
1016 {
1017  uint8_t posy = sprite->y >> 3;
1018  uint8_t offsety = sprite->y & 0x7;
1019  ssd1306_lcd.set_block(sprite->x, posy, sprite->w);
1020  for (uint8_t i=sprite->w; i > 0; i--)
1021  {
1022  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1023  }
1024  ssd1306_intf.stop();
1025  if (offsety)
1026  {
1027  ssd1306_lcd.set_block(sprite->x, posy + 1, sprite->w);
1028  for (uint8_t i=sprite->w; i > 0; i--)
1029  {
1030  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1031  }
1032  }
1033  ssd1306_intf.stop();
1034 }
1035 
1036 
1038 {
1039  uint8_t y1 = sprite->ly >> 3;
1040  uint8_t y2 = (sprite->ly + 7) >> 3;
1041  if (sprite->ly < sprite->y)
1042  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
1043  else if (sprite->y + 8 > sprite->ly)
1044  y1 = max(y1, (sprite->ly + 7) >> 3);
1045  for(uint8_t y = y1; y <= y2; y++)
1046  {
1047  ssd1306_lcd.set_block(sprite->lx, y, sprite->w);
1048  for(uint8_t x = sprite->w; x > 0; x--)
1049  {
1050  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1051  }
1052  ssd1306_intf.stop();
1053  }
1054  if (sprite->lx != sprite->x)
1055  {
1056  uint8_t x1 = sprite->lx;
1057  uint8_t x2 = sprite->lx + sprite->w - 1;
1058  if (sprite->x < sprite->lx)
1059  x1 = max(x1, sprite->x + sprite->w);
1060  else
1061  x2 = min((uint8_t)(sprite->x - 1), x2);
1062  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
1063  {
1064  ssd1306_lcd.set_block(x1, y, x2 - x1 + 1 );
1065  for(uint8_t x = x2 - x1 + 1; x > 0; x--)
1066  {
1067  ssd1306_lcd.send_pixels1( s_ssd1306_invertByte );
1068  }
1069  ssd1306_intf.stop();
1070  }
1071  }
1072 }
1073 
1074 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
1075 {
1076  return (SPRITE){x,y,w,x,y,data,NULL};
1077 }
1078 
1079 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
1080 {
1081  sprite->data = data;
1082 }
1083 
1085 {
1086  s_ssd1306_invertByte = 0xFF;
1087 }
1088 
1090 {
1091  s_ssd1306_invertByte = 0x00;
1092 }
1093 
1094 void ssd1306_setFont6x8(const uint8_t * progmemFont)
1095 {
1096  s_font6x8 = progmemFont + 4;
1097 }
1098 
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:738
void ssd1306_drawBitmap1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:804
lcduint_t ssd1306_displayWidth(void)
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:469
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
Definition: ssd1306_1bit.c:612
uint8_t height
char height in pixels
void ssd1306_positiveMode()
const uint8_t * data
Pointer to PROGMEM data, representing sprite image.
SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
const uint8_t * primary_table
font chars bits
uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:236
void ssd1306_drawXBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:837
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:639
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
Definition: ssd1306_1bit.c:79
void ssd1306_drawSprite(SPRITE *sprite)
Definition: ssd1306_1bit.c:989
uint8_t width
width in pixels
int lcdint_t
Definition: io.h:63
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
Definition: ssd1306_1bit.c:717
void(* set_block)(lcduint_t x, lcduint_t y, lcduint_t w)
Sets block in RAM of lcd display controller to write data to.
Definition: lcd_common.h:114
void ssd1306_fillScreen(uint8_t fill_Data)
Definition: ssd1306_1bit.c:50
unsigned int lcduint_t
Definition: io.h:65
void(* send_pixels8)(uint8_t data)
Sends RGB pixel encoded in 3-3-2 format to OLED driver. Sends RGB pixel encoded in 3-3-2 format to OL...
Definition: lcd_common.h:142
void ssd1306_eraseTrace(SPRITE *sprite)
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:135
void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:786
const PROGMEM uint8_t ssd1306xled_font6x8[]
Definition: ssd1306_fonts.c:42
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
uint8_t height
height in pixels
void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:870
uint8_t ascii_offset
ascii offset
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:33
size_t ssd1306_print(const char ch[])
Prints null-terminated string to display at current cursor position.
Definition: ssd1306_1bit.c:458
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
Definition: ssd1306_1bit.c:515
void ssd1306_setFont6x8(const uint8_t *progmemFont)
void ssd1306_eraseSprite(SPRITE *sprite)
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
Definition: ssd1306_1bit.c:693
void ssd1306_fillRect(lcdint_t x1, lcdint_t y1, lcdint_t x2, lcdint_t y2)
Definition: ssd1306_1bit.c:942
ssd1306_interface_t ssd1306_intf
#define max(a, b)
uint8_t y
draw position Y on the screen
#define min(a, b)
lcduint_t height
Definition: lcd_common.h:97
uint8_t width
char width in pixels
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
Definition: ssd1306_1bit.c:977
SFixedFontInfo s_fixedFont
Definition: tiler.h:44
SFontHeaderRecord h
record, containing information on font
uint8_t x
draw position X on the screen
const uint8_t * glyph
char data, located in progmem.
uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
Definition: ssd1306_1bit.c:317
uint8_t w
sprite width
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
Definition: ssd1306_1bit.c:683
lcduint_t ssd1306_displayHeight(void)
void(* next_page)(void)
Definition: lcd_common.h:122
uint8_t spacing
additional spaces after char in pixels
uint8_t lx
last draw position X on the screen
void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
Definition: ssd1306_1bit.c:927
void ssd1306_getCharBitmap(uint16_t unicode, SCharInfo *info)
returns char data for currently set (active) font.
lcduint_t width
Definition: lcd_common.h:94
uint8_t ssd1306_charF6x8_eol(uint8_t left, uint8_t y, const char ch[], EFontStyle style, uint8_t right)
Definition: ssd1306_1bit.c:590
void ssd1306_clearScreen()
Definition: ssd1306_1bit.c:65
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
#define SSD1306_MORE_CHARS_REQUIRED
EFontStyle
void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:725
uint8_t pages
height in pages (each page height is 8-pixels)
#define ssd1306_swap_data(a, b, type)
Definition: io.h:69
uint8_t ly
last draw position Y on the screen
void ssd1306_negativeMode()
void ssd1306_putPixel(uint8_t x, uint8_t y)
Definition: ssd1306_1bit.c:605
void ssd1306_drawBuffer1_4(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
Definition: ssd1306_1bit.c:753
size_t ssd1306_write(uint8_t ch)
Prints single character to display at current cursor position.
Definition: ssd1306_1bit.c:418