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