SSD1306 OLED display driver  1.6.1
This library is developed to control SSD1306/SSD1331/SSD1351/IL9163/PCD8554 RGB i2c/spi LED displays
ssd1306_generic.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 
28 
29 #include "font6x8.h"
30 #include "ssd1306.h"
31 #include "lcd/lcd_common.h"
32 #include "i2c/ssd1306_i2c.h"
33 #include "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 #define swap_data(a, b) { uint8_t t = a; a = b; b = t; }
41 
42 uint16_t ssd1306_color = 0xFFFF;
43 static uint8_t s_invertByte = 0x00000000;
44 const uint8_t *s_font6x8 = &ssd1306xled_font6x8[4];
46 
48 {
49  return ssd1306_lcd.height;
50 }
51 
53 {
54  return ssd1306_lcd.width;
55 }
56 
57 void ssd1306_fillScreen(uint8_t fill_Data)
58 {
59  fill_Data ^= s_invertByte;
60  ssd1306_lcd.set_block(0, 0, 0);
61  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
62  {
63  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
64  {
65  ssd1306_lcd.send_pixels1(fill_Data);
66  }
68  }
70 }
71 
73 {
74  ssd1306_lcd.set_block(0, 0, 0);
75  for(uint8_t m=(ssd1306_lcd.height >> 3); m>0; m--)
76  {
77  for(uint8_t n=ssd1306_lcd.width; n>0; n--)
78  {
79  ssd1306_lcd.send_pixels1( s_invertByte );
80  }
82  }
84 }
85 
86 
88 {
89  ssd1306_sendCommand(SSD1306_DISPLAYOFF);
90 }
91 
92 
94 {
95  ssd1306_sendCommand(SSD1306_DISPLAYON);
96 }
97 
98 void ssd1306_setContrast(uint8_t contrast)
99 {
101  ssd1306_intf.send(SSD1306_SETCONTRAST);
102  ssd1306_intf.send(contrast);
103  ssd1306_intf.stop();
104 }
105 
106 uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
107 {
108  uint8_t i, j=0;
109  uint8_t text_index = 0;
110  uint8_t page_offset = 0;
111  uint8_t x = xpos;
112  y >>= 3;
113  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
114  for(;;)
115  {
116  uint8_t c;
117  uint8_t ldata;
118  uint16_t offset;
119  if( (x > ssd1306_lcd.width - s_fixedFont.width) || (ch[j] == '\0') )
120  {
121  x = xpos;
122  y++;
123  if (y >= (ssd1306_lcd.height >> 3))
124  {
125  break;
126  }
127  page_offset++;
128  if (page_offset == s_fixedFont.pages)
129  {
130  text_index = j;
131  page_offset = 0;
132  if (ch[j] == '\0')
133  {
134  break;
135  }
136  }
137  else
138  {
139  j = text_index;
140  }
141  ssd1306_intf.stop();
142  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
143  }
144  c = ch[j];
145  if ( c >= s_fixedFont.ascii_offset )
146  {
147  c -= s_fixedFont.ascii_offset;
148  }
149  ldata = 0;
150  offset = (c * s_fixedFont.pages + page_offset) * s_fixedFont.width;
151  for( i=s_fixedFont.width; i>0; i--)
152  {
153  uint8_t data;
154  if ( style == STYLE_NORMAL )
155  {
156  data = pgm_read_byte(&s_fixedFont.data[offset]);
157  }
158  else if ( style == STYLE_BOLD )
159  {
160  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset]);
161  data = temp | ldata;
162  ldata = temp;
163  }
164  else
165  {
166  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset + 1]);
167  data = (temp & 0xF0) | ldata;
168  ldata = (temp & 0x0F);
169  }
170  ssd1306_lcd.send_pixels1(data^s_invertByte);
171  offset++;
172  }
173  x += s_fixedFont.width;
174  j++;
175  }
176  ssd1306_intf.stop();
177  return j;
178 }
179 
180 uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
181 {
182  uint8_t i, j=0;
183  uint8_t text_index = 0;
184  uint8_t page_offset = 0;
185  uint8_t x = xpos;
186  y >>= 3;
187  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
188  for(;;)
189  {
190  uint8_t c;
191  uint8_t ldata;
192  uint16_t offset;
193  if( (x > ssd1306_lcd.width - (s_fixedFont.width << 1)) || (ch[j] == '\0') )
194  {
195  x = xpos;
196  y++;
197  if (y >= (ssd1306_lcd.height >> 3))
198  {
199  break;
200  }
201  page_offset++;
202  if (page_offset == (s_fixedFont.pages << 1))
203  {
204  text_index = j;
205  page_offset = 0;
206  if (ch[j] == '\0')
207  {
208  break;
209  }
210  }
211  else
212  {
213  j = text_index;
214  }
215  ssd1306_intf.stop();
216  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
217  }
218  c = ch[j];
219  if ( c >= s_fixedFont.ascii_offset )
220  {
221  c -= s_fixedFont.ascii_offset;
222  }
223  ldata = 0;
224  offset = (c * s_fixedFont.pages + (page_offset >> 1)) * s_fixedFont.width;
225  for( i=s_fixedFont.width; i>0; i--)
226  {
227  uint8_t data;
228  if ( style == STYLE_NORMAL )
229  {
230  data = pgm_read_byte(&s_fixedFont.data[offset]);
231  }
232  else if ( style == STYLE_BOLD )
233  {
234  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset]);
235  data = temp | ldata;
236  ldata = temp;
237  }
238  else
239  {
240  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset + 1]);
241  data = (temp & 0xF0) | ldata;
242  ldata = (temp & 0x0F);
243  }
244  if (page_offset & 1) data >>= 4;
245  data = ((data & 0x01) ? 0x03: 0x00) |
246  ((data & 0x02) ? 0x0C: 0x00) |
247  ((data & 0x04) ? 0x30: 0x00) |
248  ((data & 0x08) ? 0xC0: 0x00);
249  ssd1306_lcd.send_pixels1(data^s_invertByte);
250  ssd1306_lcd.send_pixels1(data^s_invertByte);
251  offset++;
252  }
253  x += (s_fixedFont.width << 1);
254  j++;
255  }
256  ssd1306_intf.stop();
257  return j;
258 }
259 
260 
261 uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
262 {
263  uint8_t i, j=0;
264  uint8_t text_index = 0;
265  uint8_t page_offset = 0;
266  uint8_t x = xpos;
267  y >>= 3;
268  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
269  for(;;)
270  {
271  uint8_t c;
272  uint8_t ldata;
273  uint16_t offset;
274  if( (x > ssd1306_lcd.width - (s_fixedFont.width << factor)) || (ch[j] == '\0') )
275  {
276  x = xpos;
277  y++;
278  if (y >= (ssd1306_lcd.height >> 3))
279  {
280  break;
281  }
282  page_offset++;
283  if (page_offset == (s_fixedFont.pages << factor))
284  {
285  text_index = j;
286  page_offset = 0;
287  if (ch[j] == '\0')
288  {
289  break;
290  }
291  }
292  else
293  {
294  j = text_index;
295  }
296  ssd1306_intf.stop();
297  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
298  }
299  c = ch[j];
300  if ( c >= s_fixedFont.ascii_offset )
301  {
302  c -= s_fixedFont.ascii_offset;
303  }
304  ldata = 0;
305  offset = (c * s_fixedFont.pages + (page_offset >> factor)) * s_fixedFont.width;
306  for( i=s_fixedFont.width; i>0; i--)
307  {
308  uint8_t data;
309  if ( style == STYLE_NORMAL )
310  {
311  data = pgm_read_byte(&s_fixedFont.data[offset]);
312  }
313  else if ( style == STYLE_BOLD )
314  {
315  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset]);
316  data = temp | ldata;
317  ldata = temp;
318  }
319  else
320  {
321  uint8_t temp = pgm_read_byte(&s_fixedFont.data[offset + 1]);
322  data = (temp & 0xF0) | ldata;
323  ldata = (temp & 0x0F);
324  }
325  if ( factor > 0 )
326  {
327  uint8_t accum = 0;
328  uint8_t mask = ~((0xFF) << (1<<factor));
329  // N=0 -> right shift is always 0
330  // N=1 -> right shift goes through 0, 4
331  // N=2 -> right shift goes through 0, 2, 4, 6
332  // N=3 -> right shift goes through 0, 1, 2, 3, 4, 5, 6, 7
333  data >>= ((page_offset & ((1<<factor) - 1))<<(3-factor));
334  for (uint8_t idx = 0; idx < 1<<(3-factor); idx++)
335  {
336  accum |= (((data>>idx) & 0x01) ? (mask<<(idx<<factor)) : 0);
337  }
338  data = accum;
339  }
340  for (uint8_t z=(1<<factor); z>0; z--)
341  {
342  ssd1306_lcd.send_pixels1(data^s_invertByte);
343  }
344  offset++;
345  }
346  x += (s_fixedFont.width << factor);
347  j++;
348  }
349  ssd1306_intf.stop();
350  return j;
351 }
352 
353 size_t ssd1306_write(uint8_t ch)
354 {
355  static lcduint_t xpos = 0;
356  static lcduint_t ypos = 0;
357  if (ch == '\r')
358  {
359  xpos = 0;
360  return 0;
361  }
362  else if ( (xpos > ssd1306_lcd.width - s_fixedFont.width) || (ch == '\n') )
363  {
364  xpos = 0;
365  ypos += s_fixedFont.height;
366  if ( ypos > ssd1306_lcd.height - s_fixedFont.height )
367  {
368  ypos = 0;
369  }
370  ssd1306_clearBlock(0, ypos>>3, ssd1306_lcd.width, s_fixedFont.height);
371  if (ch == '\n')
372  {
373  return 0;
374  }
375  }
376  ch -= s_fixedFont.ascii_offset;
377  ssd1306_drawBitmap( xpos,
378  ypos>>3,
379  s_fixedFont.width,
380  s_fixedFont.height,
381  &s_fixedFont.data[ ch * s_fixedFont.pages * s_fixedFont.width ] );
382  xpos += s_fixedFont.width;
383  return 1;
384 }
385 
386 size_t ssd1306_print(const char ch[])
387 {
388  size_t n = 0;
389  while (*ch)
390  {
391  n += ssd1306_write(*ch);
392  ch++;
393  }
394  return n;
395 }
396 
397 uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
398 {
399  uint8_t i, j=0;
401  while(ch[j] != '\0')
402  {
403  uint8_t ldata;
404  uint8_t c = ch[j] - 32;
405  if ( c > 224 )
406  {
407  c = 0;
408  }
409  if(x > ssd1306_lcd.width - 6)
410  {
411  x=0;
412  y++;
413  }
414  ldata = 0;
415  for(i=0;i<6;i++)
416  {
417  uint8_t data;
418  if ( style == STYLE_NORMAL )
419  {
420  data = pgm_read_byte(&s_font6x8[c*6+i]);
421  }
422  else if ( style == STYLE_BOLD )
423  {
424  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
425  data = temp | ldata;
426  ldata = temp;
427  }
428  else
429  {
430  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
431  data = (temp & 0xF0) | ldata;
432  ldata = (temp & 0x0F);
433  }
434  ssd1306_lcd.send_pixels1(data^s_invertByte);
435  }
436  x += 6;
437  j++;
438  }
439  ssd1306_intf.stop();
440  return j;
441 }
442 
443 uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
444 {
445  uint8_t i, j=0;
446  uint8_t text_index = 0;
447  uint8_t odd = 0;
448  uint8_t x = xpos;
449  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
450  for(;;)
451  {
452  uint8_t c;
453  uint8_t ldata;
454  if( (x > ssd1306_lcd.width-12) || (ch[j] == '\0') )
455  {
456  x = xpos;
457  y++;
458  if (y >= (ssd1306_lcd.height >> 3))
459  {
460  break;
461  }
462  if (odd)
463  {
464  text_index = j;
465  if (ch[j] == '\0')
466  {
467  break;
468  }
469  }
470  else
471  {
472  j = text_index;
473  }
474  odd = !odd;
475  ssd1306_intf.stop();
476  ssd1306_lcd.set_block(xpos, y, ssd1306_lcd.width - xpos);
477  }
478  c = ch[j] - 32;
479  if ( c > 224 )
480  {
481  c = 0;
482  }
483  ldata = 0;
484  for(i=0;i<6;i++)
485  {
486  uint8_t data;
487  if ( style == STYLE_NORMAL )
488  {
489  data = pgm_read_byte(&s_font6x8[c*6+i]);
490  }
491  else if ( style == STYLE_BOLD )
492  {
493  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i]);
494  data = temp | ldata;
495  ldata = temp;
496  }
497  else
498  {
499  uint8_t temp = pgm_read_byte(&s_font6x8[c*6+i + 1]);
500  data = (temp & 0xF0) | ldata;
501  ldata = (temp & 0x0F);
502  }
503  if (odd) data >>= 4;
504  data = ((data & 0x01) ? 0x03: 0x00) |
505  ((data & 0x02) ? 0x0C: 0x00) |
506  ((data & 0x04) ? 0x30: 0x00) |
507  ((data & 0x08) ? 0xC0: 0x00);
508  ssd1306_lcd.send_pixels1(data^s_invertByte);
509  ssd1306_lcd.send_pixels1(data^s_invertByte);
510  }
511  x += 12;
512  j++;
513  }
514  ssd1306_intf.stop();
515  return j;
516 }
517 
518 uint8_t ssd1306_charF6x8_eol(uint8_t left,
519  uint8_t y,
520  const char ch[],
521  EFontStyle style,
522  uint8_t right)
523 {
524  uint8_t len = ssd1306_charF6x8(left, y, ch, style);
525  uint8_t text_end_pos = len * 6 + left;
526  if (text_end_pos <= right)
527  {
528  ssd1306_clearBlock(text_end_pos, y, right - text_end_pos + 1, 8);
529  }
530  return len;
531 }
532 
533 void ssd1306_setFixedFont(const uint8_t * progmemFont)
534 {
535  s_fixedFont.width = pgm_read_byte(&progmemFont[1]);
536  s_fixedFont.height = pgm_read_byte(&progmemFont[2]);
537  s_fixedFont.pages = (s_fixedFont.height + 7) >> 3;
538  s_fixedFont.ascii_offset = pgm_read_byte(&progmemFont[3]);
539  s_fixedFont.data = progmemFont + 4;
540 }
541 
542 void ssd1306_setFont6x8(const uint8_t * progmemFont)
543 {
544  s_font6x8 = progmemFont + 4;
545 }
546 
547 void ssd1306_putPixel(uint8_t x, uint8_t y)
548 {
549  ssd1306_lcd.set_block(x, y >> 3, 1);
550  ssd1306_lcd.send_pixels1((1 << (y & 0x07))^s_invertByte);
551  ssd1306_intf.stop();
552 }
553 
554 void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
555 {
556  ssd1306_lcd.set_block(x, y >> 3, 1);
557  ssd1306_lcd.send_pixels1(pixels^s_invertByte);
558  ssd1306_intf.stop();
559 }
560 
561 void ssd1306_putPixel_delayed(uint8_t x, uint8_t y, uint8_t complete)
562 {
563  static uint8_t lx = 0, ly = 0xFF;
564  static uint8_t pixels = 0;
565  if ((lx != x) || ((ly & 0xF8) != (y & 0xF8)) || (complete))
566  {
567  if (ly != 0xFF)
568  {
569  ssd1306_putPixels( lx, ly, pixels );
570  }
571  pixels = 0;
572  ly = 0xFF;
573  }
574  if ( !complete )
575  {
576  pixels |= (1 << (y & 0x07));
577  lx = x; ly = y;
578  }
579 }
580 
581 void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
582 {
583  lcduint_t dx = x1 > x2 ? (x1 - x2): (x2 - x1);
584  lcduint_t dy = y1 > y2 ? (y1 - y2): (y2 - y1);
585  lcduint_t err = 0;
586  if (dy > dx)
587  {
588  if (y1 > y2)
589  {
590  swap_data(x1, x2);
591  swap_data(y1, y2);
592  }
593  for(; y1<=y2; y1++)
594  {
595  err += dx;
596  if (err >= dy)
597  {
598  err -= dy;
599  x1 < x2 ? x1++: x1--;
600  }
601  ssd1306_putPixel_delayed( x1, y1, 0 );
602  }
603  ssd1306_putPixel_delayed( 0, 0, 1 );
604  }
605  else
606  {
607  if (x1 > x2)
608  {
609  swap_data(x1, x2);
610  swap_data(y1, y2);
611  }
612  for(; x1<=x2; x1++)
613  {
614  err += dy;
615  if (err >= dx)
616  {
617  err -= dx;
618  if (y1 < y2) y1++; else y1--;
619  }
620  ssd1306_putPixel( x1, y1 );
621  }
622  }
623 }
624 
625 void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
626 {
627  ssd1306_lcd.set_block(x1, y1 >> 3, x2 - x1 + 1);
628  for (uint8_t x = x1; x <= x2; x++)
629  {
630  ssd1306_lcd.send_pixels1((1 << (y1 & 0x07))^s_invertByte);
631  }
632  ssd1306_intf.stop();
633 }
634 
635 void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
636 {
637  uint8_t topPage = y1 >> 3;
638  uint8_t bottomPage = y2 >> 3;
639  uint8_t height = y2-y1;
640  uint8_t y;
641  ssd1306_lcd.set_block(x1, topPage, 1);
642  if (topPage == bottomPage)
643  {
644  ssd1306_lcd.send_pixels1( ((0xFF >> (0x07 - height)) << (y1 & 0x07))^s_invertByte );
645  ssd1306_intf.stop();
646  return;
647  }
648  ssd1306_lcd.send_pixels1( (0xFF << (y1 & 0x07))^s_invertByte );
649  for ( y = (topPage + 1); y <= (bottomPage - 1); y++)
650  {
652  ssd1306_lcd.send_pixels1( 0xFF^s_invertByte );
653  }
655  ssd1306_lcd.send_pixels1( (0xFF >> (0x07 - (y2 & 0x07)))^s_invertByte );
656  ssd1306_intf.stop();
657 }
658 
659 void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
660 {
661  ssd1306_drawHLine(x1+1, y1, x2-1);
662  ssd1306_drawHLine(x1+1, y2, x2-1);
663  ssd1306_drawVLine(x1, y1, y2);
664  ssd1306_drawVLine(x2, y1, y2);
665 }
666 
667 void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
668 {
669  uint8_t j;
670  ssd1306_lcd.set_block(x, y >> 3, w);
671  for(j=(h >> 3); j>0; j--)
672  {
674  buf+=w;
676  }
677  ssd1306_intf.stop();
678 }
679 
680 void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
681 {
682  uint8_t i, j;
683  ssd1306_lcd.set_block(x, y, w);
684  for(j=(h >> 3); j>0; j--)
685  {
686  for(i=w;i>0;i--)
687  {
688  ssd1306_lcd.send_pixels1(s_invertByte^*buf++);
689  }
691  }
692  ssd1306_intf.stop();
693 }
694 
695 void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
696 {
697  uint8_t i, j;
698  uint8_t remainder = (ssd1306_lcd.width - x) < w ? (w + x - ssd1306_lcd.width): 0;
699  w -= remainder;
700  ssd1306_lcd.set_block(x, y, w);
701  for(j=(h >> 3); j>0; j--)
702  {
703  for(i=w;i>0;i--)
704  {
705  ssd1306_lcd.send_pixels1(s_invertByte^pgm_read_byte(buf++));
706  }
707  buf += remainder;
709  }
710  ssd1306_intf.stop();
711 }
712 
713 void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
714 {
715  lcduint_t origin_width = w;
716  uint8_t offset = y & 0x07;
717  uint8_t complexFlag = 0;
718  uint8_t mainFlag = 1;
719  uint8_t max_pages;
720  uint8_t pages;
721  lcduint_t i, j;
722  if (y + (lcdint_t)h <= 0) return;
723  if (y >= ssd1306_lcd.height) return;
724  if (x + (lcdint_t)w <= 0) return;
725  if (x >= ssd1306_lcd.width) return;
726  if (y < 0)
727  {
728  buf += ((lcduint_t)((-y) + 7) >> 3) * w;
729  h += y;
730  y = 0;
731  complexFlag = 1;
732  }
733  if (x < 0)
734  {
735  buf += -x;
736  w += x;
737  x = 0;
738  }
739  max_pages = (lcduint_t)(h + 15 - offset) >> 3;
741  {
743  }
744  if ((lcduint_t)((lcduint_t)x + w) > (lcduint_t)ssd1306_lcd.width)
745  {
746  w = (lcduint_t)(ssd1306_lcd.width - (lcduint_t)x);
747  }
748  pages = ((y + h - 1) >> 3) - (y >> 3) + 1;
749 
750  ssd1306_lcd.set_block(x, y >> 3, w);
751  for(j=0; j < pages; j++)
752  {
753  if ( j == max_pages - 1 ) mainFlag = !offset;
754  for( i=w; i > 0; i--)
755  {
756  uint8_t data = 0;
757  if ( mainFlag ) data |= (pgm_read_byte(buf) << offset);
758  if ( complexFlag ) data |= (pgm_read_byte(buf - origin_width) >> (8 - offset));
759  buf++;
760  ssd1306_lcd.send_pixels1(s_invertByte^data);
761  }
762  buf += origin_width - w;
763  complexFlag = offset;
765  }
766  ssd1306_intf.stop();
767 }
768 
769 
770 void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)
771 {
772  uint8_t i, j;
773  ssd1306_lcd.set_block(x, y, w);
774  for(j=(h >> 3); j>0; j--)
775  {
776  for(i=w;i>0;i--)
777  {
778  ssd1306_lcd.send_pixels1(s_invertByte);
779  }
781  }
782  ssd1306_intf.stop();
783 }
784 
785 
786 void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
787 {
788  uint8_t i;
789  ssd1306_lcd.set_block(x,y,w);
790  for(i=0;i<w;i++)
791  {
792  ssd1306_lcd.send_pixels1(s_invertByte^pgm_read_byte(&sprite[i]));
793  }
794  ssd1306_intf.stop();
795 }
796 
797 
799 {
800  uint8_t offsety = sprite->y & 0x7;
801  if (sprite->y < ssd1306_lcd.height)
802  {
803  ssd1306_lcd.set_block(sprite->x, sprite->y >> 3, sprite->w);
804  for (uint8_t i=0; i < sprite->w; i++)
805  {
806  ssd1306_lcd.send_pixels1( s_invertByte^(pgm_read_byte( &sprite->data[i] ) << offsety) );
807  }
808  ssd1306_intf.stop();
809  }
810  if (offsety && (sprite->y + 8 < ssd1306_lcd.height))
811  {
812  ssd1306_lcd.set_block(sprite->x, (sprite->y >> 3) + 1, sprite->w);
813  for (uint8_t i=0; i < sprite->w; i++)
814  {
815  ssd1306_lcd.send_pixels1( s_invertByte^(pgm_read_byte( &sprite->data[i] ) >> (8 - offsety)) );
816  }
817  ssd1306_intf.stop();
818  }
819  sprite->lx = sprite->x;
820  sprite->ly = sprite->y;
821 }
822 
823 
825 {
826  uint8_t posy = sprite->y >> 3;
827  uint8_t offsety = sprite->y & 0x7;
828  ssd1306_lcd.set_block(sprite->x, posy, sprite->w);
829  for (uint8_t i=sprite->w; i > 0; i--)
830  {
831  ssd1306_lcd.send_pixels1( s_invertByte );
832  }
833  ssd1306_intf.stop();
834  if (offsety)
835  {
836  ssd1306_lcd.set_block(sprite->x, posy + 1, sprite->w);
837  for (uint8_t i=sprite->w; i > 0; i--)
838  {
839  ssd1306_lcd.send_pixels1( s_invertByte );
840  }
841  }
842  ssd1306_intf.stop();
843 }
844 
845 
847 {
848  uint8_t y1 = sprite->ly >> 3;
849  uint8_t y2 = (sprite->ly + 7) >> 3;
850  if (sprite->ly < sprite->y)
851  y2 = min(y2, (uint8_t)((sprite->y >> 3) - 1));
852  else if (sprite->y + 8 > sprite->ly)
853  y1 = max(y1, (sprite->ly + 7) >> 3);
854  for(uint8_t y = y1; y <= y2; y++)
855  {
856  ssd1306_lcd.set_block(sprite->lx, y, sprite->w);
857  for(uint8_t x = sprite->w; x > 0; x--)
858  {
859  ssd1306_lcd.send_pixels1( s_invertByte );
860  }
861  ssd1306_intf.stop();
862  }
863  if (sprite->lx != sprite->x)
864  {
865  uint8_t x1 = sprite->lx;
866  uint8_t x2 = sprite->lx + sprite->w - 1;
867  if (sprite->x < sprite->lx)
868  x1 = max(x1, sprite->x + sprite->w);
869  else
870  x2 = min((uint8_t)(sprite->x - 1), x2);
871  for(uint8_t y = sprite->ly >> 3; y <= (sprite->ly + 7) >> 3; y++)
872  {
873  ssd1306_lcd.set_block(x1, y, x2 - x1 + 1 );
874  for(uint8_t x = x2 - x1 + 1; x > 0; x--)
875  {
876  ssd1306_lcd.send_pixels1( s_invertByte );
877  }
878  ssd1306_intf.stop();
879  }
880  }
881 }
882 
883 SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
884 {
885  return (SPRITE){x,y,w,x,y,data,NULL};
886 }
887 
888 void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
889 {
890  sprite->data = data;
891 }
892 
894 {
896  {
897  ssd1306_sendCommand(SSD1306_INVERTDISPLAY);
898  }
899 }
900 
902 {
904  {
905  ssd1306_sendCommand(SSD1306_NORMALDISPLAY);
906  }
907 }
908 
909 void ssd1306_flipHorizontal(uint8_t mode)
910 {
912  {
913  ssd1306_sendCommand( SSD1306_SEGREMAP | (mode ? 0x00: 0x01 ) );
914  }
915 }
916 
917 void ssd1306_flipVertical(uint8_t mode)
918 {
920  {
921  ssd1306_sendCommand( mode ? SSD1306_COMSCANINC : SSD1306_COMSCANDEC );
922  }
923 }
924 
926 {
927  s_invertByte = 0xFF;
928 }
929 
931 {
932  s_invertByte = 0x00;
933 }
void ssd1306_drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
void ssd1306_drawSprite(SPRITE *sprite)
void ssd1306_putPixels(uint8_t x, uint8_t y, uint8_t pixels)
unsigned int lcduint_t
Definition: io.h:42
uint8_t ssd1306_charF6x8_eol(uint8_t left, uint8_t y, const char ch[], EFontStyle style, uint8_t right)
const uint8_t * data
Pointer to PROGMEM data, representing sprite image.
void gfx_drawMonoBitmap(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
void ssd1306_eraseSprite(SPRITE *sprite)
void ssd1306_eraseTrace(SPRITE *sprite)
void ssd1306_invertMode()
void(* send)(uint8_t data)
void ssd1306_drawBufferFast(lcdint_t x, lcdint_t y, lcduint_t w, lcduint_t h, const uint8_t *buf)
void ssd1306_flipVertical(uint8_t mode)
performs vertical flip
void ssd1306_drawHLine(uint8_t x1, uint8_t y1, uint8_t x2)
size_t ssd1306_write(uint8_t ch)
Prints single character to display at current cursor position.
void ssd1306_putPixel(uint8_t x, uint8_t y)
void ssd1306_clearScreen()
uint8_t ssd1306_printFixed2x(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
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_negativeMode()
SFixedFontInfo s_fixedFont
Definition: tiler.h:39
void ssd1306_drawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
void ssd1306_drawSpriteEx(uint8_t x, uint8_t y, uint8_t w, const uint8_t *sprite)
uint8_t ssd1306_printFixedN(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style, uint8_t factor)
void ssd1306_displayOn()
void(* send_pixels_buffer1)(const uint8_t *buffer, uint16_t len)
Definition: lcd_common.h:135
const PROGMEM uint8_t ssd1306xled_font6x8[]
Definition: ssd1306_fonts.c:41
void(* send_pixels1)(uint8_t data)
Definition: lcd_common.h:128
void ssd1306_drawBitmap(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
uint8_t ascii_offset
ascii offset
uint8_t ssd1306_displayWidth()
void ssd1306_drawVLine(uint8_t x1, uint8_t y1, uint8_t y2)
void ssd1306_flipHorizontal(uint8_t mode)
performs horizontal flip
ssd1306_lcd_t ssd1306_lcd
Definition: lcd_common.c:32
void ssd1306_positiveMode()
ssd1306_interface_t ssd1306_intf
#define max(a, b)
uint8_t y
draw position Y on the screen
#define min(a, b)
void ssd1306_fillScreen(uint8_t fill_Data)
lcduint_t height
Definition: lcd_common.h:97
void ssd1306_setFixedFont(const uint8_t *progmemFont)
int lcdint_t
Definition: io.h:40
uint8_t width
width in pixels
uint8_t x
draw position X on the screen
void ssd1306_replaceSprite(SPRITE *sprite, const uint8_t *data)
uint8_t ssd1306_charF12x16(uint8_t xpos, uint8_t y, const char ch[], EFontStyle style)
void ssd1306_commandStart(void)
uint8_t w
sprite width
void ssd1306_sendCommand(uint8_t command)
size_t ssd1306_print(const char ch[])
Prints null-terminated string to display at current cursor position.
void(* next_page)(void)
Definition: lcd_common.h:122
uint8_t lx
last draw position X on the screen
uint8_t ssd1306_displayHeight()
lcduint_t width
Definition: lcd_common.h:94
void ssd1306_drawBuffer(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint8_t *buf)
lcd_type_t type
Definition: lcd_common.h:91
SPRITE ssd1306_createSprite(uint8_t x, uint8_t y, uint8_t w, const uint8_t *data)
uint8_t ssd1306_charF6x8(uint8_t x, uint8_t y, const char ch[], EFontStyle style)
const uint8_t * data
font chars bits
EFontStyle
uint8_t pages
height in pages (each page height is 8-pixels)
void ssd1306_setFont6x8(const uint8_t *progmemFont)
void ssd1306_normalMode()
uint8_t ly
last draw position Y on the screen
void ssd1306_displayOff()
void ssd1306_setContrast(uint8_t contrast)
uint8_t height
height in pixels
uint8_t ssd1306_printFixed(uint8_t xpos, uint8_t y, const char *ch, EFontStyle style)
void ssd1306_clearBlock(uint8_t x, uint8_t y, uint8_t w, uint8_t h)