16FXlib
lcd.c
Go to the documentation of this file.
1 
2 //*****************************************************************************
3 // Author : Christian Illy
4 // Created : 09.04.2009
5 // Revised : 29.06.2009
6 // Version : 0.1
7 // Target MCU : Fujitsu MB96300 series
8 //
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 //
22 //*****************************************************************************
23 
24 #include "mb96348hs.h"
25 #include "lcd.h"
26 #include "lcd.cfg.h"
27 #include "util.h"
28 #include "font.h"
29 
30 #if LCD_FRAMEBUFFER_MODE==1
31 static uint8_t lcd_buffer[128][8];
32 #endif
33 
34 static uint8_t setEnable(void) {
35  uint8_t data;
36  delay_us(1);
38  delay_us(1);
39  data = LCD_DATA_PORT;
41  delay_us(1);
42  return data;
43 }
44 
45 static void selectDisplay(uint8_t disp) {
47  if (disp)
49  else
51 }
52 
53 static void setReadWrite(uint8_t write) {
54  if (write) {
55  LCD_DATA_PORT = 0x00;
56  LCD_DATA_PIER = 0x00;
57  LCD_DATA_DDR = 0xff;
59  } else {
60  LCD_DATA_PORT = 0x00;
61  LCD_DATA_PIER = 0xff;
62  LCD_DATA_DDR = 0x00;
64  }
65 }
66 
67 static void writeCommand(uint8_t cmd, uint8_t disp) {
68  setReadWrite(1);
69  selectDisplay(disp);
71  LCD_DATA_PORT = cmd;
72  setEnable();
73 }
74 
75 static uint8_t readCommand(uint8_t disp) {
76  setReadWrite(0);
77  selectDisplay(disp);
79  return setEnable();
80 }
81 
82 static void writeData(uint8_t data, uint8_t disp) {
83  setReadWrite(1);
84  selectDisplay(disp);
86  LCD_DATA_PORT = data;
87  setEnable();
88 }
89 
90 static uint8_t readData(uint8_t disp) {
91  uint8_t data;
92  setReadWrite(0);
93  selectDisplay(disp);
95  setEnable();
96  data = setEnable();
97  return data;
98 }
99 
100 static uint8_t setXY(uint8_t x, uint8_t y) {
101  uint8_t moduleX = x % 64;
102  uint8_t disp = x / 64;
103  uint8_t page = y / 8;
104  writeCommand(LCD_CMD_SETADDRESS | moduleX, disp);
105  writeCommand(LCD_CMD_SETPAGE | page, disp);
106  return disp;
107 }
108 
109 void lcd_init(void) {
110  LCD_CTRL_PORT = 0x00;
111  LCD_CTRL_DDR = 0xff;
113  writeCommand(LCD_CMD_ON, 0);
114  writeCommand(LCD_CMD_ON, 1);
115  lcd_clear(0);
116  writeCommand(LCD_CMD_STARTLINE | 0, 0);
117  writeCommand(LCD_CMD_STARTLINE | 0, 1);
118 }
119 
120 void lcd_clear(uint8_t color) {
121  uint8_t x;
122  uint8_t y;
123 
124  for (y = 0; y < 8; y++) {
125 #if LCD_FRAMEBUFFER_MODE == 1
126  for (x = 0; x < 128; x++) {
127  lcd_buffer[x][y] = (color ? 0xff : 0x00);
128  }
129 #else
130  setXY(0, y*8);
131  for (x= 0; x < 64; x++)
132  writeData((color ? 0xff : 0x00), 0);
133  setXY(64, y*8);
134  for (x= 0; x < 64; x++)
135  writeData((color ? 0xff : 0x00), 1);
136 #endif
137  }
138 }
139 
140 void lcd_drawPage(uint8_t x, uint8_t page, uint8_t data) {
141 #if LCD_FRAMEBUFFER_MODE==0
142  uint8_t disp;
143 #endif
144  if ((page > 7) || (x > 127))
145  return;
146 #if LCD_FRAMEBUFFER_MODE==1
147  lcd_buffer[x][page] = data;
148 #else
149  disp = setXY(x, page * 8);
150  writeData(data, disp);
151 #endif
152 }
153 
155 #if LCD_FRAMEBUFFER_MODE==1
156  if ((x > 127) || (y > 63) || (x < 0) || (y < 0))
157  return;
158 
159  if (color)
160  lcd_buffer[x][y / 8] |= (1 << (y % 8));
161  else
162  lcd_buffer[x][y / 8] &= ~(1 << (y % 8));
163 #else
164  uint8_t data;
165  uint8_t disp;
166  if ((x > 127) || (y > 63) || (x < 0) || (y < 0))
167  return;
168 
169  disp = setXY(x, y);
170  data = readData(disp);
171  if (color)
172  data |= (1 << (y % 8));
173  else
174  data &= ~(1 << (y % 8));
175 
176  setXY(x, y);
177  writeData(data, disp);
178 #endif
179 }
180 
182 {
183 #if LCD_FRAMEBUFFER_MODE==1
184  if ((x > 127) || (y > 63) || (x < 0) || (y < 0))
185  return -1;
186  return (lcd_buffer[x][y / 8] >> (y % 8)) & 0x01;
187 #else
188  uint8_t disp;
189  if ((x > 127) || (y > 63) || (x < 0) || (y < 0))
190  return -1;
191  disp = setXY(x, y);
192  return (readData(disp) >> (y % 8)) & 0x01;
193 #endif
194 }
195 
196 void lcd_drawCircle(int16_t x, int16_t y, uint8_t r, uint8_t black, uint8_t filled) {
197  /*
198  * Berechnung nach Bresenham
199  * http://de.wikipedia.org/wiki/Bresenham-Algorithmus#Kreisvariante_des_Algorithmus
200  */
201  int16_t f = 1 - r;
202  int16_t ddF_x = 0;
203  int16_t ddF_y = -2 * r;
204  int16_t ix = 0;
205  int16_t iy = r;
206 
207  if (filled) {
208  lcd_drawRect(x, y - r, 1, 2 * r, black, 1);
209  } else {
210  lcd_drawPixel(x, y + r, black);
211  lcd_drawPixel(x, y - r, black);
212  lcd_drawPixel(x + r, y, black);
213  lcd_drawPixel(x - r, y, black);
214  }
215 
216  while (ix < iy) {
217  if (f >= 0) {
218  iy--;
219  ddF_y += 2;
220  f += ddF_y;
221  }
222  ix++;
223  ddF_x += 2;
224  f += ddF_x + 1;
225 
226  if (filled) {
227  lcd_drawRect(x - ix, y - iy, 1, 2 * iy, black, 1);
228  lcd_drawRect(x + ix, y - iy, 1, 2 * iy, black, 1);
229  lcd_drawRect(x - iy, y - ix, 1, 2 * ix, black, 1);
230  lcd_drawRect(x + iy, y - ix, 1, 2 * ix, black, 1);
231  } else {
232  lcd_drawPixel(x + ix, y + iy, black);
233  lcd_drawPixel(x - ix, y + iy, black);
234  lcd_drawPixel(x + ix, y - iy, black);
235  lcd_drawPixel(x - ix, y - iy, black);
236  lcd_drawPixel(x + iy, y + ix, black);
237  lcd_drawPixel(x - iy, y + ix, black);
238  lcd_drawPixel(x + iy, y - ix, black);
239  lcd_drawPixel(x - iy, y - ix, black);
240  }
241  }
242 }
243 
244 void lcd_drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t black, uint8_t filled) {
245  uint8_t startPage, endPage, pages;
246  uint8_t ix, iPage;
247 
248  if (!filled) {
249  lcd_drawLine(x, y, x+w-1, y, black);
250  lcd_drawLine(x+w-1, y, x+w-1, y+h-1, black);
251  lcd_drawLine(x+w-1, y+h-1, x, y+h-1, black);
252  lcd_drawLine(x, y+h-1, x, y, black);
253  return;
254  }
255 
256  if ((x > 127) || (y > 63) || (x+w < 0) || (y+h < 0))
257  return;
258 
259  if (x+w > 128) w = 128-x;
260  if (y+h > 64) h = 64-y;
261  if (x < 0) {w+=x; x=0;}
262  if (y < 0) {h+=y; y=0;}
263 
264  startPage = y / 8;
265  endPage = (y + h - 1) / 8;
266  pages = endPage - startPage + 1;
267 
268  for (iPage = startPage; iPage < endPage + 1; iPage++) {
269  uint8_t data, curData;
270  if (iPage == startPage) {
271  if (pages > 1)
272  data = 0xff << (y - startPage * 8);
273  else
274  data = (0xff >> (8 - h)) << (y - startPage * 8);
275  } else if (iPage == endPage) {
276  data = 0xff >> (7 - (y + h - 1) % 8);
277  } else {
278  data = 0xff;
279  }
280  for (ix = x; ix < (x + w); ix++) {
281 #if LCD_FRAMEBUFFER_MODE == 0
282  uint8_t disp = setXY(ix, iPage * 8);
283 #endif
284  if (data == 0xff) {
285  if (black)
286  curData = data;
287  else
288  curData = ~data;
289  } else {
290 #if LCD_FRAMEBUFFER_MODE == 0
291  curData = readData(disp);
292  setXY(ix, iPage * 8);
293 #else
294  curData = lcd_buffer[ix][iPage];
295 #endif
296  if (black)
297  curData |= data;
298  else
299  curData &= ~data;
300  }
301 #if LCD_FRAMEBUFFER_MODE == 0
302  writeData(curData, disp);
303 #else
304  lcd_buffer[ix][iPage] = curData;
305 #endif
306  }
307  }
308 }
309 
310 void lcd_drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t black) {
311  /*
312  * Berechnung nach Bresenham
313  * http://de.wikipedia.org/wiki/Bresenham-Algorithmus#C-Implementierung
314  */
315  int16_t x, y, t, dx, dy, incx, incy, pdx, pdy, ddx, ddy, es, el, err;
316 
317  /* Entfernung in beiden Dimensionen berechnen */
318  dx = x2 - x1;
319  dy = y2 - y1;
320 
321  /* Vorzeichen des Inkrements bestimmen */
322  incx = sgn(dx);
323  incy = sgn(dy);
324 
325  if (dx < 0)
326  dx = -dx;
327  if (dy < 0)
328  dy = -dy;
329 
330  /* feststellen, welche Entfernung größer ist */
331  if (dx > dy) {
332  /* x ist schnelle Richtung */
333  pdx = incx;
334  pdy = 0; /* pd. ist Parallelschritt */
335 
336  ddx = incx;
337  ddy = incy; /* dd. ist Diagonalschritt */
338 
339  es = dy;
340  el = dx; /* Fehlerschritte schnell, langsam */
341  } else {
342  /* y ist schnelle Richtung */
343  pdx = 0;
344  pdy = incy; /* pd. ist Parallelschritt */
345 
346  ddx = incx;
347  ddy = incy; /* dd. ist Diagonalschritt */
348 
349  es = dx;
350  el = dy; /* Fehlerschritte schnell, langsam */
351  }
352 
353  /* Initialisierungen vor Schleifenbeginn */
354  x = x1;
355  y = y1;
356  err = el / 2;
357 
358  lcd_drawPixel(x, y, black);
359 
360  /* Pixel berechnen */
361  for (t = 0; t < el; t++) { /* t zaehlt die Pixel, el ist auch Anzahl */
362  /* Aktualisierung Fehlerterm */
363  err -= es;
364  if (err < 0) {
365  /* Fehlerterm wieder positiv (>=0) machen */
366  err += el;
367 
368  /* Schritt in langsame Richtung, Diagonalschritt */
369  x += ddx;
370  y += ddy;
371  } else {
372  /* Schritt in schnelle Richtung, Parallelschritt */
373  x += pdx;
374  y += pdy;
375  }
376  lcd_drawPixel(x, y, black);
377  }
378 }
379 
381  uint8_t black, uint8_t overlay) {
382  uint8_t* pages;
383  uint8_t i;
384 
385  if ((x > 127) || (page > 7) || (ascii > 127))
386  return 0;
387 
388  pages = font_getChar(ascii, FONT_REGULAR);
389 
390  if (pages != 0) {
391  for (i = 0; i < 5; i++) {
392 #if LCD_FRAMEBUFFER_MODE == 1
393  uint8_t curData = (black ? 0 : 255);
394  if (overlay)
395  curData = lcd_buffer[x][page];
396 
397  if (black)
398  curData |= *pages++;
399  else
400  curData &= ~(*pages++);
401  lcd_buffer[x][page] = curData;
402 #else
403  uint8_t disp = setXY(x, page * 8);
404  uint8_t curData = (black ? 0 : 255);
405  if (overlay)
406  curData = readData(disp);
407 
408  if (black)
409  curData |= *pages++;
410  else
411  curData &= ~(*pages++);
412  setXY(x, page * 8);
413  writeData(curData, disp);
414 #endif
415  x++;
416  }
417  return ++x;
418  }
419  return x;
420 }
421 
423  uint8_t wrap, uint16_t delay, char* firstChar, uint8_t black,
424  uint8_t overlay) {
425  uint8_t curX = x1;
426  uint8_t curPage = page1;
427  char curChar = 0;
428 
429  if ((x1 > 127) || (page1 > 7) || (x2 > 128) || (page2 > 8))
430  return 0;
431 
432  if (x2)
433  if ((x2 - x1) < 5)
434  return x1;
435 
436  for (curChar = *firstChar++; curChar != 0; curChar = *firstChar++) {
437  if (curChar == '\n') {
438  if (!wrap)
439  return curX;
440  curX = x1;
441  curPage++;
442  if (curPage)
443  if (curPage > page2)
444  return curX;
445  }
446  curX = lcd_drawCharacter(curX, curPage, curChar, black, overlay);
447  if (x2) {
448  if ((curX + 5) > x2) {
449  if (!wrap)
450  return curX;
451  curX = x1;
452  curPage++;
453  if (curPage > page2)
454  return curX;
455  }
456  }
457  delay_ms(delay);
458  }
459  return curX;
460 }
461 
462 int16_t lcd_drawCharacterPrecise(int16_t x, int16_t y, char ascii, uint8_t black, uint8_t orientation, uint8_t font) {
463  uint8_t* pages;
464  uint8_t i, j;
465  uint8_t fontwidth = font_getWidth(font);
466  uint8_t fontheight = font_getHeight(font);
467  uint8_t offset = (8-fontheight);
468 
469  pages = font_getChar(ascii, font);
470 
471  if (pages == 0) {
472  if (orientation & (LCD_ORIENTATION_90 | LCD_ORIENTATION_270)) {
473  return y;
474  } else {
475  return x;
476  }
477  }
478  if (orientation & LCD_ORIENTATION_90) {
479  for (i = 0; i < fontwidth; i++) {
480  for (j = 0; j < fontheight; j++) {
481  if (pages[i] & 1<<(j+offset)) {
482  lcd_drawPixel(x-j, y, black);
483  }
484  }
485  y++;
486  }
487  return ++y;
488  } else if (orientation & LCD_ORIENTATION_180) {
489  for (i = 0; i < fontwidth; i++) {
490  for (j = 0; j < fontheight; j++) {
491  if (pages[i] & 1<<(j+offset)) {
492  lcd_drawPixel(x, y-j, black);
493  }
494  }
495  x--;
496  }
497  return --x;
498  } else if (orientation & LCD_ORIENTATION_270) {
499  for (i = 0; i < fontwidth; i++) {
500  for (j = 0; j < fontheight; j++) {
501  if (pages[i] & 1<<(j+offset)) {
502  lcd_drawPixel(x+j, y, black);
503  }
504  }
505  y--;
506  }
507  return --y;
508  } else { // 0 deg = default
509  for (i = 0; i < fontwidth; i++) {
510  for (j = 0; j < fontheight; j++) {
511  if (pages[i] & 1<<(j+8-fontheight)) {
512  lcd_drawPixel(x, y+j, black);
513  }
514  }
515  x++;
516  }
517  return ++x;
518  }
519 }
520 
521 
522 int16_t lcd_drawStringPrecise(int16_t x, int16_t y, char* firstChar, uint8_t black, uint8_t settings, uint8_t font) {
523  int width;
524  int height;
525  int len = 0;
526  while (firstChar[len++] != 0);
527  len--;
528 
529  width = (len*font_getWidth(font));
530  height = font_getHeight(font);
531 
532  // calculate offset
533  if (settings & LCD_ORIENTATION_90)
534  {
535  if (settings & LCD_ALIGNMENT_CENTER) {
536  y -= width>>1;
537  } else if (settings & LCD_ALIGNMENT_RIGHT) {
538  y -= width;
539  }
540  if (settings & LCD_ALIGNMENT_MIDDLE) {
541  x += height>> 1;
542  } else if (settings & LCD_ALIGNMENT_BOTTOM) {
543  x += height;
544  }
545  }
546  else if (settings & LCD_ORIENTATION_180)
547  {
548  if (settings & LCD_ALIGNMENT_CENTER) {
549  x += width>>1;
550  } else if (settings & LCD_ALIGNMENT_RIGHT) {
551  x += width;
552  }
553  if (settings & LCD_ALIGNMENT_MIDDLE) {
554  y += height>> 1;
555  } else if (settings & LCD_ALIGNMENT_BOTTOM) {
556  y += height;
557  }
558  }
559  else if (settings & LCD_ORIENTATION_270)
560  {
561  if (settings & LCD_ALIGNMENT_CENTER) {
562  y += width>>1;
563  } else if (settings & LCD_ALIGNMENT_RIGHT) {
564  y += width;
565  }
566  if (settings & LCD_ALIGNMENT_MIDDLE) {
567  x -= height>> 1;
568  } else if (settings & LCD_ALIGNMENT_BOTTOM) {
569  x -= height;
570  }
571  }
572  else
573  {
574  if (settings & LCD_ALIGNMENT_CENTER) {
575  x -= width>>1;
576  } else if (settings & LCD_ALIGNMENT_RIGHT) {
577  x -= width;
578  }
579  if (settings & LCD_ALIGNMENT_MIDDLE) {
580  y -= height>> 1;
581  } else if (settings & LCD_ALIGNMENT_BOTTOM) {
582  y -= height;
583  }
584  }
585 
586 
587  // draw characters
588  if (settings & (LCD_ORIENTATION_90 | LCD_ORIENTATION_270)) {
589  while (*firstChar != 0) {
590  y = lcd_drawCharacterPrecise(x, y, *firstChar, black, settings, font);
591  firstChar++;
592  }
593  return y;
594  } else {
595  while (*firstChar != 0) {
596  x = lcd_drawCharacterPrecise(x, y, *firstChar, black, settings, font);
597  firstChar++;
598  }
599  return x;
600  }
601 }
602 
603 void lcd_flush(void) {
604 #if LCD_FRAMEBUFFER_MODE==1
605  uint8_t disp, x, page;
606  for (disp = 0; disp < 2; disp++) {
607  for (page = 0; page < 8; page++) {
608  writeCommand(LCD_CMD_SETPAGE | page, disp);
609  writeCommand(LCD_CMD_SETADDRESS | 0, disp);
610  for (x = 0; x < 64; x++) {
611  writeData(lcd_buffer[x+64*disp][page], disp);
612  }
613  }
614  }
615 #endif
616 }
#define LCD_CTRL_DI
Data/Instruction pin.
Definition: lcd.cfg.h:49
int sgn(int x)
Definition: util.c:51
#define LCD_CTRL_CS1
Chip 1 select pin.
Definition: lcd.cfg.h:55
#define LCD_CTRL_E
Enable pin.
Definition: lcd.cfg.h:53
#define LCD_CTRL_RESET
Reset pint.
Definition: lcd.cfg.h:59
unsigned int uint16_t
Definition: inttypes.h:50
#define _BV(bit)
Definition: util.h:39
void delay_us(uint16_t us)
Definition: util.c:34
void lcd_drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t black)
Definition: lcd.c:310
#define LCD_CTRL_DDR
Direction register of the control pins port.
Definition: lcd.cfg.h:45
unsigned char uint8_t
Definition: inttypes.h:35
#define LCD_DATA_PORT
Port where the data pins of the display are connected.
Definition: lcd.cfg.h:36
char int8_t
Definition: inttypes.h:45
void delay_ms(uint16_t ms)
Definition: util.c:41
int int16_t
Definition: inttypes.h:55
#define LCD_DATA_DDR
Direction register of the data pins port.
Definition: lcd.cfg.h:38
int16_t lcd_drawCharacterPrecise(int16_t x, int16_t y, char ascii, uint8_t black, uint8_t orientation, uint8_t font)
Definition: lcd.c:462
void lcd_init(void)
Definition: lcd.c:109
#define LCD_CTRL_RW
Read/Write pin.
Definition: lcd.cfg.h:51
uint8_t * font_getChar(uint8_t ascii, uint8_t font)
Definition: font.c:345
#define LCD_DATA_PIER
Input enable register of the data pins port.
Definition: lcd.cfg.h:40
#define LCD_CMD_STARTLINE
Set startline.
Definition: lcd.cfg.h:76
#define LCD_CTRL_PORT
Port where the control lines of the display are connected.
Definition: lcd.cfg.h:43
int16_t lcd_drawStringPrecise(int16_t x, int16_t y, char *firstChar, uint8_t black, uint8_t settings, uint8_t font)
Definition: lcd.c:522
uint8_t lcd_drawCharacter(uint8_t x, uint8_t page, char ascii, uint8_t black, uint8_t overlay)
Definition: lcd.c:380
#define LCD_CMD_SETADDRESS
Set address.
Definition: lcd.cfg.h:72
#define LCD_CMD_SETPAGE
Set page.
Definition: lcd.cfg.h:74
#define LCD_CMD_ON
Display on.
Definition: lcd.cfg.h:68
void lcd_flush(void)
Definition: lcd.c:603
void lcd_drawPage(uint8_t x, uint8_t page, uint8_t data)
Definition: lcd.c:140
void lcd_drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t black, uint8_t filled)
Definition: lcd.c:244
int8_t lcd_getPixel(int16_t x, int16_t y)
Definition: lcd.c:181
#define LCD_CTRL_CS2
Chip 2 select pin.
Definition: lcd.cfg.h:57
void delay(uint16_t del)
Definition: util.c:28
void lcd_clear(uint8_t color)
Definition: lcd.c:120
void lcd_drawCircle(int16_t x, int16_t y, uint8_t r, uint8_t black, uint8_t filled)
Definition: lcd.c:196
void lcd_drawPixel(int16_t x, int16_t y, uint8_t color)
Definition: lcd.c:154
uint8_t lcd_drawString(uint8_t x1, uint8_t page1, uint8_t x2, uint8_t page2, uint8_t wrap, uint16_t delay, char *firstChar, uint8_t black, uint8_t overlay)
Definition: lcd.c:422