blob: accd5c3a75fe3d3d0ceb54a40bbad41a0ca07210 [file] [log] [blame]
Deokgyu Yang3f787a12020-03-30 15:25:23 +09001/*
2 * lcd128x64.c:
3 * Graphics-based LCD driver.
4 * This is designed to drive the parallel interface LCD drivers
5 * based on the generic 12864H chips
6 *
7 * There are many variations on these chips, however they all mostly
8 * seem to be similar.
9 * This implementation has the Pins from the Pi hard-wired into it,
10 * in particular wiringPi pins 0-7 so that we can use
11 * digitalWriteByete() to speed things up somewhat.
12 *
13 * Copyright (c) 2013 Gordon Henderson.
14 ***********************************************************************
15 * This file is part of wiringPi:
16 * https://projects.drogon.net/raspberry-pi/wiringpi/
17 *
18 * wiringPi is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU Lesser General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
22 *
23 * wiringPi is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU Lesser General Public License for more details.
27 *
28 * You should have received a copy of the GNU Lesser General Public License
29 * along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
30 ***********************************************************************
31 */
32
33#include <stdio.h>
34#include <stdlib.h>
35
36#include <wiringPi.h>
37
38#include "font.h"
39#include "lcd128x64.h"
40
41// Size
42
43#define LCD_WIDTH 128
44#define LCD_HEIGHT 64
45
46// Hardware Pins
47// Note pins 0-7 are the 8-bit data port
48
49#define CS1 10
50#define CS2 11
51#define STROBE 12
52#define RS 13
53
54// Software copy of the framebuffer
55// it's 8-bit deep although the display itself is only 1-bit deep.
56
57static unsigned char frameBuffer [LCD_WIDTH * LCD_HEIGHT] ;
58
59static int maxX, maxY ;
60static int lastX, lastY ;
61static int xOrigin, yOrigin ;
62static int lcdOrientation = 0 ;
63
64/*
65 * strobe:
66 * Toggle the strobe (Really the "E") pin to the device.
67 * According to the docs, data is latched on the falling edge.
68 *********************************************************************************
69 */
70
71static void strobe (void)
72{
73 digitalWrite (STROBE, 1) ; delayMicroseconds (1) ;
74 digitalWrite (STROBE, 0) ; delayMicroseconds (5) ;
75}
76
77
78/*
79 * sentData:
80 * Send an data or command byte to the display.
81 *********************************************************************************
82 */
83
84static void sendData (const int data, const int chip)
85{
86 digitalWrite (chip, 0) ;
87 digitalWriteByte (data) ;
88 strobe () ;
89 digitalWrite (chip, 1) ;
90}
91
92
93/*
94 * sendCommand:
95 * Send a command byte to the display
96 *********************************************************************************
97 */
98
99static void sendCommand (const int command, const int chip)
100{
101 digitalWrite (RS, 0) ;
102 sendData (command, chip) ;
103 digitalWrite (RS, 1) ;
104}
105
106
107/*
108 * setCol: SetLine:
109 * Set the column and line addresses
110 *********************************************************************************
111 */
112
113static void setCol (int col, const int chip)
114 { sendCommand (0x40 | (col & 0x3F), chip) ; }
115
116static void setLine (int line, const int chip)
117 { sendCommand (0xB8 | (line & 0x07), chip) ; }
118
119
120/*
121 * lcd128x64update:
122 * Copy our software version to the real display
123 *********************************************************************************
124 */
125
126void lcd128x64update (void)
127{
128 int line, x, y, fbLoc ;
129 unsigned char byte ;
130
131// Left side
132
133 for (line = 0 ; line < 8 ; ++line)
134 {
135 setCol (0, CS1) ;
136 setLine (line, CS1) ;
137
138 for (x = 63 ; x >= 0 ; --x)
139 {
140 byte = 0 ;
141 for (y = 0 ; y < 8 ; ++y)
142 {
143 fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ;
144 if (frameBuffer [fbLoc] != 0)
145 byte |= (1 << y) ;
146 }
147 sendData (byte, CS1) ;
148 }
149 }
150
151// Right side
152
153 for (line = 0 ; line < 8 ; ++line)
154 {
155 setCol (0, CS2) ;
156 setLine (line, CS2) ;
157
158 for (x = 127 ; x >= 64 ; --x)
159 {
160 byte = 0 ;
161 for (y = 0 ; y < 8 ; ++y)
162 {
163 fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ;
164 if (frameBuffer [fbLoc] != 0)
165 byte |= (1 << y) ;
166 }
167 sendData (byte, CS2) ;
168 }
169 }
170}
171
172
173/*
174 * lcd128x64setOrigin:
175 * Set the display offset origin
176 *********************************************************************************
177 */
178
179void lcd128x64setOrigin (int x, int y)
180{
181 xOrigin = x ;
182 yOrigin = y ;
183}
184
185
186/*
187 * lcd128x64setOrientation:
188 * Set the display orientation:
189 * 0: Normal, the display is portrait mode, 0,0 is top left
190 * 1: Landscape
191 * 2: Portrait, flipped
192 * 3: Landscape, flipped
193 *********************************************************************************
194 */
195
196void lcd128x64setOrientation (int orientation)
197{
198 lcdOrientation = orientation & 3 ;
199
200 lcd128x64setOrigin (0,0) ;
201
202 switch (lcdOrientation)
203 {
204 case 0:
205 maxX = LCD_WIDTH ;
206 maxY = LCD_HEIGHT ;
207 break ;
208
209 case 1:
210 maxX = LCD_HEIGHT ;
211 maxY = LCD_WIDTH ;
212 break ;
213
214 case 2:
215 maxX = LCD_WIDTH ;
216 maxY = LCD_HEIGHT ;
217 break ;
218
219 case 3:
220 maxX = LCD_HEIGHT ;
221 maxY = LCD_WIDTH ;
222 break ;
223 }
224}
225
226
227/*
228 * lcd128x64orientCoordinates:
229 * Adjust the coordinates given to the display orientation
230 *********************************************************************************
231 */
232
233void lcd128x64orientCoordinates (int *x, int *y)
234{
235 register int tmp ;
236
237 *x += xOrigin ;
238 *y += yOrigin ;
239 *y = maxY - *y - 1 ;
240
241 switch (lcdOrientation)
242 {
243 case 0:
244 break;
245
246 case 1:
247 tmp = maxY - *y - 1 ;
248 *y = *x ;
249 *x = tmp ;
250 break;
251
252 case 2:
253 *x = maxX - *x - 1 ;
254 *y = maxY - *y - 1 ;
255 break;
256
257 case 3:
258 *x = maxX - *x - 1 ;
259 tmp = *y ;
260 *y = *x ;
261 *x = tmp ;
262 break ;
263 }
264}
265
266
267/*
268 * lcd128x64getScreenSize:
269 * Return the max X & Y screen sizes. Needs to be called again, if you
270 * change screen orientation.
271 *********************************************************************************
272 */
273
274void lcd128x64getScreenSize (int *x, int *y)
275{
276 *x = maxX ;
277 *y = maxY ;
278}
279
280
281/*
282 *********************************************************************************
283 * Standard Graphical Functions
284 *********************************************************************************
285 */
286
287
288/*
289 * lcd128x64point:
290 * Plot a pixel.
291 *********************************************************************************
292 */
293
294void lcd128x64point (int x, int y, int colour)
295{
296 lastX = x ;
297 lastY = y ;
298
299 lcd128x64orientCoordinates (&x, &y) ;
300
301 if ((x < 0) || (x >= LCD_WIDTH) || (y < 0) || (y >= LCD_HEIGHT))
302 return ;
303
304 frameBuffer [x + y * LCD_WIDTH] = colour ;
305}
306
307
308/*
309 * lcd128x64line: lcd128x64lineTo:
310 * Classic Bressenham Line code
311 *********************************************************************************
312 */
313
314void lcd128x64line (int x0, int y0, int x1, int y1, int colour)
315{
316 int dx, dy ;
317 int sx, sy ;
318 int err, e2 ;
319
320 lastX = x1 ;
321 lastY = y1 ;
322
323 dx = abs (x1 - x0) ;
324 dy = abs (y1 - y0) ;
325
326 sx = (x0 < x1) ? 1 : -1 ;
327 sy = (y0 < y1) ? 1 : -1 ;
328
329 err = dx - dy ;
330
331 for (;;)
332 {
333 lcd128x64point (x0, y0, colour) ;
334
335 if ((x0 == x1) && (y0 == y1))
336 break ;
337
338 e2 = 2 * err ;
339
340 if (e2 > -dy)
341 {
342 err -= dy ;
343 x0 += sx ;
344 }
345
346 if (e2 < dx)
347 {
348 err += dx ;
349 y0 += sy ;
350 }
351 }
352
353}
354
355void lcd128x64lineTo (int x, int y, int colour)
356{
357 lcd128x64line (lastX, lastY, x, y, colour) ;
358}
359
360
361/*
362 * lcd128x64rectangle:
363 * A rectangle is a spoilt days fishing
364 *********************************************************************************
365 */
366
367void lcd128x64rectangle (int x1, int y1, int x2, int y2, int colour, int filled)
368{
369 register int x ;
370
371 if (filled)
372 {
373 /**/ if (x1 == x2)
374 lcd128x64line (x1, y1, x2, y2, colour) ;
375 else if (x1 < x2)
376 for (x = x1 ; x <= x2 ; ++x)
377 lcd128x64line (x, y1, x, y2, colour) ;
378 else
379 for (x = x2 ; x <= x1 ; ++x)
380 lcd128x64line (x, y1, x, y2, colour) ;
381 }
382 else
383 {
384 lcd128x64line (x1, y1, x2, y1, colour) ;
385 lcd128x64lineTo (x2, y2, colour) ;
386 lcd128x64lineTo (x1, y2, colour) ;
387 lcd128x64lineTo (x1, y1, colour) ;
388 }
389}
390
391
392/*
393 * lcd128x64circle:
394 * This is the midpoint circle algorithm.
395 *********************************************************************************
396 */
397
398void lcd128x64circle (int x, int y, int r, int colour, int filled)
399{
400 int ddF_x = 1 ;
401 int ddF_y = -2 * r ;
402
403 int f = 1 - r ;
404 int x1 = 0 ;
405 int y1 = r ;
406
407 if (filled)
408 {
409 lcd128x64line (x, y + r, x, y - r, colour) ;
410 lcd128x64line (x + r, y, x - r, y, colour) ;
411 }
412 else
413 {
414 lcd128x64point (x, y + r, colour) ;
415 lcd128x64point (x, y - r, colour) ;
416 lcd128x64point (x + r, y, colour) ;
417 lcd128x64point (x - r, y, colour) ;
418 }
419
420 while (x1 < y1)
421 {
422 if (f >= 0)
423 {
424 y1-- ;
425 ddF_y += 2 ;
426 f += ddF_y ;
427 }
428 x1++ ;
429 ddF_x += 2 ;
430 f += ddF_x ;
431 if (filled)
432 {
433 lcd128x64line (x + x1, y + y1, x - x1, y + y1, colour) ;
434 lcd128x64line (x + x1, y - y1, x - x1, y - y1, colour) ;
435 lcd128x64line (x + y1, y + x1, x - y1, y + x1, colour) ;
436 lcd128x64line (x + y1, y - x1, x - y1, y - x1, colour) ;
437 }
438 else
439 {
440 lcd128x64point (x + x1, y + y1, colour) ; lcd128x64point (x - x1, y + y1, colour) ;
441 lcd128x64point (x + x1, y - y1, colour) ; lcd128x64point (x - x1, y - y1, colour) ;
442 lcd128x64point (x + y1, y + x1, colour) ; lcd128x64point (x - y1, y + x1, colour) ;
443 lcd128x64point (x + y1, y - x1, colour) ; lcd128x64point (x - y1, y - x1, colour) ;
444 }
445 }
446}
447
448
449/*
450 * lcd128x64ellipse:
451 * Fast ellipse drawing algorithm by
452 * John Kennedy
453 * Mathematics Department
454 * Santa Monica College
455 * 1900 Pico Blvd.
456 * Santa Monica, CA 90405
457 * jrkennedy6@gmail.com
458 * -Confirned in email this algorithm is in the public domain -GH-
459 *********************************************************************************
460 */
461
462static void plot4ellipsePoints (int cx, int cy, int x, int y, int colour, int filled)
463{
464 if (filled)
465 {
466 lcd128x64line (cx + x, cy + y, cx - x, cy + y, colour) ;
467 lcd128x64line (cx - x, cy - y, cx + x, cy - y, colour) ;
468 }
469 else
470 {
471 lcd128x64point (cx + x, cy + y, colour) ;
472 lcd128x64point (cx - x, cy + y, colour) ;
473 lcd128x64point (cx - x, cy - y, colour) ;
474 lcd128x64point (cx + x, cy - y, colour) ;
475 }
476}
477
478void lcd128x64ellipse (int cx, int cy, int xRadius, int yRadius, int colour, int filled)
479{
480 int x, y ;
481 int xChange, yChange, ellipseError ;
482 int twoAsquare, twoBsquare ;
483 int stoppingX, stoppingY ;
484
485 twoAsquare = 2 * xRadius * xRadius ;
486 twoBsquare = 2 * yRadius * yRadius ;
487
488 x = xRadius ;
489 y = 0 ;
490
491 xChange = yRadius * yRadius * (1 - 2 * xRadius) ;
492 yChange = xRadius * xRadius ;
493
494 ellipseError = 0 ;
495 stoppingX = twoBsquare * xRadius ;
496 stoppingY = 0 ;
497
498 while (stoppingX >= stoppingY) // 1st set of points
499 {
500 plot4ellipsePoints (cx, cy, x, y, colour, filled) ;
501 ++y ;
502 stoppingY += twoAsquare ;
503 ellipseError += yChange ;
504 yChange += twoAsquare ;
505
506 if ((2 * ellipseError + xChange) > 0 )
507 {
508 --x ;
509 stoppingX -= twoBsquare ;
510 ellipseError += xChange ;
511 xChange += twoBsquare ;
512 }
513 }
514
515 x = 0 ;
516 y = yRadius ;
517
518 xChange = yRadius * yRadius ;
519 yChange = xRadius * xRadius * (1 - 2 * yRadius) ;
520
521 ellipseError = 0 ;
522 stoppingX = 0 ;
523 stoppingY = twoAsquare * yRadius ;
524
525 while (stoppingX <= stoppingY) //2nd set of points
526 {
527 plot4ellipsePoints (cx, cy, x, y, colour, filled) ;
528 ++x ;
529 stoppingX += twoBsquare ;
530 ellipseError += xChange ;
531 xChange += twoBsquare ;
532
533 if ((2 * ellipseError + yChange) > 0 )
534 {
535 --y ;
536 stoppingY -= twoAsquare ;
537 ellipseError += yChange ;
538 yChange += twoAsquare ;
539 }
540 }
541}
542
543
544/*
545 * lcd128x64putchar:
546 * Print a single character to the screen
547 *********************************************************************************
548 */
549
550void lcd128x64putchar (int x, int y, int c, int bgCol, int fgCol)
551{
552 int y1, y2 ;
553
554 unsigned char line ;
555 unsigned char *fontPtr ;
556
557// Can't print if we're offscreen
558
559//if ((x < 0) || (x >= (maxX - fontWidth)) || (y < 0) || (y >= (maxY - fontHeight)))
560// return ;
561
562 fontPtr = font + c * fontHeight ;
563
564 for (y1 = fontHeight - 1 ; y1 >= 0 ; --y1)
565 {
566 y2 = y + y1 ;
567 line = *fontPtr++ ;
568 lcd128x64point (x + 0, y2, (line & 0x80) == 0 ? bgCol : fgCol) ;
569 lcd128x64point (x + 1, y2, (line & 0x40) == 0 ? bgCol : fgCol) ;
570 lcd128x64point (x + 2, y2, (line & 0x20) == 0 ? bgCol : fgCol) ;
571 lcd128x64point (x + 3, y2, (line & 0x10) == 0 ? bgCol : fgCol) ;
572 lcd128x64point (x + 4, y2, (line & 0x08) == 0 ? bgCol : fgCol) ;
573 lcd128x64point (x + 5, y2, (line & 0x04) == 0 ? bgCol : fgCol) ;
574 lcd128x64point (x + 6, y2, (line & 0x02) == 0 ? bgCol : fgCol) ;
575 lcd128x64point (x + 7, y2, (line & 0x01) == 0 ? bgCol : fgCol) ;
576 }
577}
578
579
580/*
581 * lcd128x64puts:
582 * Send a string to the display. Obeys \n and \r formatting
583 *********************************************************************************
584 */
585
586void lcd128x64puts (int x, int y, const char *str, int bgCol, int fgCol)
587{
588 int c, mx, my ;
589
590 mx = x ; my = y ;
591
592 while (*str)
593 {
594 c = *str++ ;
595
596 if (c == '\r')
597 {
598 mx = x ;
599 continue ;
600 }
601
602 if (c == '\n')
603 {
604 mx = x ;
605 my -= fontHeight ;
606 continue ;
607 }
608
609 lcd128x64putchar (mx, my, c, bgCol, fgCol) ;
610
611 mx += fontWidth ;
612 if (mx >= (maxX - fontWidth))
613 {
614 mx = 0 ;
615 my -= fontHeight ;
616 }
617 }
618}
619
620
621/*
622 * lcd128x64clear:
623 * Clear the display to the given colour.
624 *********************************************************************************
625 */
626
627void lcd128x64clear (int colour)
628{
629 register int i ;
630 register unsigned char *ptr = frameBuffer ;
631
632 for (i = 0 ; i < (maxX * maxY) ; ++i)
633 *ptr++ = colour ;
634}
635
636
637
638
639/*
640 * lcd128x64setup:
641 * Initialise the display and GPIO.
642 *********************************************************************************
643 */
644
645int lcd128x64setup (void)
646{
647 int i ;
648
649 for (i = 0 ; i < 8 ; ++i)
650 pinMode (i, OUTPUT) ;
651
652 digitalWrite (CS1, 1) ;
653 digitalWrite (CS2, 1) ;
654 digitalWrite (STROBE, 0) ;
655 digitalWrite (RS, 1) ;
656
657 pinMode (CS1, OUTPUT) ;
658 pinMode (CS2, OUTPUT) ;
659 pinMode (STROBE, OUTPUT) ;
660 pinMode (RS, OUTPUT) ;
661
662 sendCommand (0x3F, CS1) ; // Display ON
663 sendCommand (0xC0, CS1) ; // Set display start line to 0
664
665 sendCommand (0x3F, CS2) ; // Display ON
666 sendCommand (0xC0, CS2) ; // Set display start line to 0
667
668 lcd128x64clear (0) ;
669 lcd128x64setOrientation (0) ;
670 lcd128x64update () ;
671
672 return 0 ;
673}