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