lcd128x64.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  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. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <wiringPi.h>
  35. #include "font.h"
  36. #include "lcd128x64.h"
  37. // Size
  38. #define LCD_WIDTH 128
  39. #define LCD_HEIGHT 64
  40. // Hardware Pins
  41. // Note pins 0-7 are the 8-bit data port
  42. #define CS1 10
  43. #define CS2 11
  44. #define STROBE 12
  45. #define RS 13
  46. // Software copy of the framebuffer
  47. // it's 8-bit deep although the display itself is only 1-bit deep.
  48. static unsigned char frameBuffer [LCD_WIDTH * LCD_HEIGHT] ;
  49. static int maxX, maxY ;
  50. static int lastX, lastY ;
  51. static int xOrigin, yOrigin ;
  52. static int lcdOrientation = 0 ;
  53. /*
  54. * strobe:
  55. * Toggle the strobe (Really the "E") pin to the device.
  56. * According to the docs, data is latched on the falling edge.
  57. *********************************************************************************
  58. */
  59. static void strobe (void)
  60. {
  61. digitalWrite (STROBE, 1) ; delayMicroseconds (1) ;
  62. digitalWrite (STROBE, 0) ; delayMicroseconds (5) ;
  63. }
  64. /*
  65. * sentData:
  66. * Send an data or command byte to the display.
  67. *********************************************************************************
  68. */
  69. static void sendData (const int data, const int chip)
  70. {
  71. digitalWrite (chip, 0) ;
  72. digitalWriteByte (data) ;
  73. strobe () ;
  74. digitalWrite (chip, 1) ;
  75. }
  76. /*
  77. * sendCommand:
  78. * Send a command byte to the display
  79. *********************************************************************************
  80. */
  81. static void sendCommand (const int command, const int chip)
  82. {
  83. digitalWrite (RS, 0) ;
  84. sendData (command, chip) ;
  85. digitalWrite (RS, 1) ;
  86. }
  87. /*
  88. * setCol: SetLine:
  89. * Set the column and line addresses
  90. *********************************************************************************
  91. */
  92. static void setCol (int col, const int chip)
  93. { sendCommand (0x40 | (col & 0x3F), chip) ; }
  94. static void setLine (int line, const int chip)
  95. { sendCommand (0xB8 | (line & 0x07), chip) ; }
  96. /*
  97. * lcd128x64update:
  98. * Copy our software version to the real display
  99. *********************************************************************************
  100. */
  101. void lcd128x64update (void)
  102. {
  103. int line, x, y, fbLoc ;
  104. unsigned char byte ;
  105. // Left side
  106. for (line = 0 ; line < 8 ; ++line)
  107. {
  108. setCol (0, CS1) ;
  109. setLine (line, CS1) ;
  110. for (x = 63 ; x >= 0 ; --x)
  111. {
  112. byte = 0 ;
  113. for (y = 0 ; y < 8 ; ++y)
  114. {
  115. fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ;
  116. if (frameBuffer [fbLoc] != 0)
  117. byte |= (1 << y) ;
  118. }
  119. sendData (byte, CS1) ;
  120. }
  121. }
  122. // Right side
  123. for (line = 0 ; line < 8 ; ++line)
  124. {
  125. setCol (0, CS2) ;
  126. setLine (line, CS2) ;
  127. for (x = 127 ; x >= 64 ; --x)
  128. {
  129. byte = 0 ;
  130. for (y = 0 ; y < 8 ; ++y)
  131. {
  132. fbLoc = x + (((7 - line) * 8) + (7 - y)) * LCD_WIDTH ;
  133. if (frameBuffer [fbLoc] != 0)
  134. byte |= (1 << y) ;
  135. }
  136. sendData (byte, CS2) ;
  137. }
  138. }
  139. }
  140. /*
  141. * lcd128x64setOrigin:
  142. * Set the display offset origin
  143. *********************************************************************************
  144. */
  145. void lcd128x64setOrigin (int x, int y)
  146. {
  147. xOrigin = x ;
  148. yOrigin = y ;
  149. }
  150. /*
  151. * lcd128x64setOrientation:
  152. * Set the display orientation:
  153. * 0: Normal, the display is portrait mode, 0,0 is top left
  154. * 1: Landscape
  155. * 2: Portrait, flipped
  156. * 3: Landscape, flipped
  157. *********************************************************************************
  158. */
  159. void lcd128x64setOrientation (int orientation)
  160. {
  161. lcdOrientation = orientation & 3 ;
  162. lcd128x64setOrigin (0,0) ;
  163. switch (lcdOrientation)
  164. {
  165. case 0:
  166. maxX = LCD_WIDTH ;
  167. maxY = LCD_HEIGHT ;
  168. break ;
  169. case 1:
  170. maxX = LCD_HEIGHT ;
  171. maxY = LCD_WIDTH ;
  172. break ;
  173. case 2:
  174. maxX = LCD_WIDTH ;
  175. maxY = LCD_HEIGHT ;
  176. break ;
  177. case 3:
  178. maxX = LCD_HEIGHT ;
  179. maxY = LCD_WIDTH ;
  180. break ;
  181. }
  182. }
  183. /*
  184. * lcd128x64orientCoordinates:
  185. * Adjust the coordinates given to the display orientation
  186. *********************************************************************************
  187. */
  188. void lcd128x64orientCoordinates (int *x, int *y)
  189. {
  190. register int tmp ;
  191. *x += xOrigin ;
  192. *y += yOrigin ;
  193. *y = maxY - *y - 1 ;
  194. switch (lcdOrientation)
  195. {
  196. case 0:
  197. break;
  198. case 1:
  199. tmp = maxY - *y - 1 ;
  200. *y = *x ;
  201. *x = tmp ;
  202. break;
  203. case 2:
  204. *x = maxX - *x - 1 ;
  205. *y = maxY - *y - 1 ;
  206. break;
  207. case 3:
  208. *x = maxX - *x - 1 ;
  209. tmp = *y ;
  210. *y = *x ;
  211. *x = tmp ;
  212. break ;
  213. }
  214. }
  215. /*
  216. * lcd128x64getScreenSize:
  217. * Return the max X & Y screen sizes. Needs to be called again, if you
  218. * change screen orientation.
  219. *********************************************************************************
  220. */
  221. void lcd128x64getScreenSize (int *x, int *y)
  222. {
  223. *x = maxX ;
  224. *y = maxY ;
  225. }
  226. /*
  227. *********************************************************************************
  228. * Standard Graphical Functions
  229. *********************************************************************************
  230. */
  231. /*
  232. * lcd128x64point:
  233. * Plot a pixel.
  234. *********************************************************************************
  235. */
  236. void lcd128x64point (int x, int y, int colour)
  237. {
  238. lastX = x ;
  239. lastY = y ;
  240. lcd128x64orientCoordinates (&x, &y) ;
  241. if ((x < 0) || (x >= LCD_WIDTH) || (y < 0) || (y >= LCD_HEIGHT))
  242. return ;
  243. frameBuffer [x + y * LCD_WIDTH] = colour ;
  244. }
  245. /*
  246. * lcd128x64line: lcd128x64lineTo:
  247. * Classic Bressenham Line code
  248. *********************************************************************************
  249. */
  250. void lcd128x64line (int x0, int y0, int x1, int y1, int colour)
  251. {
  252. int dx, dy ;
  253. int sx, sy ;
  254. int err, e2 ;
  255. lastX = x1 ;
  256. lastY = y1 ;
  257. dx = abs (x1 - x0) ;
  258. dy = abs (y1 - y0) ;
  259. sx = (x0 < x1) ? 1 : -1 ;
  260. sy = (y0 < y1) ? 1 : -1 ;
  261. err = dx - dy ;
  262. for (;;)
  263. {
  264. lcd128x64point (x0, y0, colour) ;
  265. if ((x0 == x1) && (y0 == y1))
  266. break ;
  267. e2 = 2 * err ;
  268. if (e2 > -dy)
  269. {
  270. err -= dy ;
  271. x0 += sx ;
  272. }
  273. if (e2 < dx)
  274. {
  275. err += dx ;
  276. y0 += sy ;
  277. }
  278. }
  279. }
  280. void lcd128x64lineTo (int x, int y, int colour)
  281. {
  282. lcd128x64line (lastX, lastY, x, y, colour) ;
  283. }
  284. /*
  285. * lcd128x64rectangle:
  286. * A rectangle is a spoilt days fishing
  287. *********************************************************************************
  288. */
  289. void lcd128x64rectangle (int x1, int y1, int x2, int y2, int colour, int filled)
  290. {
  291. register int x ;
  292. if (filled)
  293. {
  294. /**/ if (x1 == x2)
  295. lcd128x64line (x1, y1, x2, y2, colour) ;
  296. else if (x1 < x2)
  297. for (x = x1 ; x <= x2 ; ++x)
  298. lcd128x64line (x, y1, x, y2, colour) ;
  299. else
  300. for (x = x2 ; x <= x1 ; ++x)
  301. lcd128x64line (x, y1, x, y2, colour) ;
  302. }
  303. else
  304. {
  305. lcd128x64line (x1, y1, x2, y1, colour) ;
  306. lcd128x64lineTo (x2, y2, colour) ;
  307. lcd128x64lineTo (x1, y2, colour) ;
  308. lcd128x64lineTo (x1, y1, colour) ;
  309. }
  310. }
  311. /*
  312. * lcd128x64circle:
  313. * This is the midpoint circle algorithm.
  314. *********************************************************************************
  315. */
  316. void lcd128x64circle (int x, int y, int r, int colour, int filled)
  317. {
  318. int ddF_x = 1 ;
  319. int ddF_y = -2 * r ;
  320. int f = 1 - r ;
  321. int x1 = 0 ;
  322. int y1 = r ;
  323. if (filled)
  324. {
  325. lcd128x64line (x, y + r, x, y - r, colour) ;
  326. lcd128x64line (x + r, y, x - r, y, colour) ;
  327. }
  328. else
  329. {
  330. lcd128x64point (x, y + r, colour) ;
  331. lcd128x64point (x, y - r, colour) ;
  332. lcd128x64point (x + r, y, colour) ;
  333. lcd128x64point (x - r, y, colour) ;
  334. }
  335. while (x1 < y1)
  336. {
  337. if (f >= 0)
  338. {
  339. y1-- ;
  340. ddF_y += 2 ;
  341. f += ddF_y ;
  342. }
  343. x1++ ;
  344. ddF_x += 2 ;
  345. f += ddF_x ;
  346. if (filled)
  347. {
  348. lcd128x64line (x + x1, y + y1, x - x1, y + y1, colour) ;
  349. lcd128x64line (x + x1, y - y1, x - x1, y - y1, colour) ;
  350. lcd128x64line (x + y1, y + x1, x - y1, y + x1, colour) ;
  351. lcd128x64line (x + y1, y - x1, x - y1, y - x1, colour) ;
  352. }
  353. else
  354. {
  355. lcd128x64point (x + x1, y + y1, colour) ; lcd128x64point (x - x1, y + y1, colour) ;
  356. lcd128x64point (x + x1, y - y1, colour) ; lcd128x64point (x - x1, y - y1, colour) ;
  357. lcd128x64point (x + y1, y + x1, colour) ; lcd128x64point (x - y1, y + x1, colour) ;
  358. lcd128x64point (x + y1, y - x1, colour) ; lcd128x64point (x - y1, y - x1, colour) ;
  359. }
  360. }
  361. }
  362. /*
  363. * lcd128x64ellipse:
  364. * Fast ellipse drawing algorithm by
  365. * John Kennedy
  366. * Mathematics Department
  367. * Santa Monica College
  368. * 1900 Pico Blvd.
  369. * Santa Monica, CA 90405
  370. * jrkennedy6@gmail.com
  371. * -Confirned in email this algorithm is in the public domain -GH-
  372. *********************************************************************************
  373. */
  374. static void plot4ellipsePoints (int cx, int cy, int x, int y, int colour, int filled)
  375. {
  376. if (filled)
  377. {
  378. lcd128x64line (cx + x, cy + y, cx - x, cy + y, colour) ;
  379. lcd128x64line (cx - x, cy - y, cx + x, cy - y, colour) ;
  380. }
  381. else
  382. {
  383. lcd128x64point (cx + x, cy + y, colour) ;
  384. lcd128x64point (cx - x, cy + y, colour) ;
  385. lcd128x64point (cx - x, cy - y, colour) ;
  386. lcd128x64point (cx + x, cy - y, colour) ;
  387. }
  388. }
  389. void lcd128x64ellipse (int cx, int cy, int xRadius, int yRadius, int colour, int filled)
  390. {
  391. int x, y ;
  392. int xChange, yChange, ellipseError ;
  393. int twoAsquare, twoBsquare ;
  394. int stoppingX, stoppingY ;
  395. twoAsquare = 2 * xRadius * xRadius ;
  396. twoBsquare = 2 * yRadius * yRadius ;
  397. x = xRadius ;
  398. y = 0 ;
  399. xChange = yRadius * yRadius * (1 - 2 * xRadius) ;
  400. yChange = xRadius * xRadius ;
  401. ellipseError = 0 ;
  402. stoppingX = twoBsquare * xRadius ;
  403. stoppingY = 0 ;
  404. while (stoppingX >= stoppingY) // 1st set of points
  405. {
  406. plot4ellipsePoints (cx, cy, x, y, colour, filled) ;
  407. ++y ;
  408. stoppingY += twoAsquare ;
  409. ellipseError += yChange ;
  410. yChange += twoAsquare ;
  411. if ((2 * ellipseError + xChange) > 0 )
  412. {
  413. --x ;
  414. stoppingX -= twoBsquare ;
  415. ellipseError += xChange ;
  416. xChange += twoBsquare ;
  417. }
  418. }
  419. x = 0 ;
  420. y = yRadius ;
  421. xChange = yRadius * yRadius ;
  422. yChange = xRadius * xRadius * (1 - 2 * yRadius) ;
  423. ellipseError = 0 ;
  424. stoppingX = 0 ;
  425. stoppingY = twoAsquare * yRadius ;
  426. while (stoppingX <= stoppingY) //2nd set of points
  427. {
  428. plot4ellipsePoints (cx, cy, x, y, colour, filled) ;
  429. ++x ;
  430. stoppingX += twoBsquare ;
  431. ellipseError += xChange ;
  432. xChange += twoBsquare ;
  433. if ((2 * ellipseError + yChange) > 0 )
  434. {
  435. --y ;
  436. stoppingY -= twoAsquare ;
  437. ellipseError += yChange ;
  438. yChange += twoAsquare ;
  439. }
  440. }
  441. }
  442. /*
  443. * lcd128x64putchar:
  444. * Print a single character to the screen
  445. *********************************************************************************
  446. */
  447. void lcd128x64putchar (int x, int y, int c, int bgCol, int fgCol)
  448. {
  449. int y1, y2 ;
  450. unsigned char line ;
  451. unsigned char *fontPtr ;
  452. // Can't print if we're offscreen
  453. //if ((x < 0) || (x >= (maxX - fontWidth)) || (y < 0) || (y >= (maxY - fontHeight)))
  454. // return ;
  455. fontPtr = font + c * fontHeight ;
  456. for (y1 = fontHeight - 1 ; y1 >= 0 ; --y1)
  457. {
  458. y2 = y + y1 ;
  459. line = *fontPtr++ ;
  460. lcd128x64point (x + 0, y2, (line & 0x80) == 0 ? bgCol : fgCol) ;
  461. lcd128x64point (x + 1, y2, (line & 0x40) == 0 ? bgCol : fgCol) ;
  462. lcd128x64point (x + 2, y2, (line & 0x20) == 0 ? bgCol : fgCol) ;
  463. lcd128x64point (x + 3, y2, (line & 0x10) == 0 ? bgCol : fgCol) ;
  464. lcd128x64point (x + 4, y2, (line & 0x08) == 0 ? bgCol : fgCol) ;
  465. lcd128x64point (x + 5, y2, (line & 0x04) == 0 ? bgCol : fgCol) ;
  466. lcd128x64point (x + 6, y2, (line & 0x02) == 0 ? bgCol : fgCol) ;
  467. lcd128x64point (x + 7, y2, (line & 0x01) == 0 ? bgCol : fgCol) ;
  468. }
  469. }
  470. /*
  471. * lcd128x64puts:
  472. * Send a string to the display. Obeys \n and \r formatting
  473. *********************************************************************************
  474. */
  475. void lcd128x64puts (int x, int y, const char *str, int bgCol, int fgCol)
  476. {
  477. int c, mx, my ;
  478. mx = x ; my = y ;
  479. while (*str)
  480. {
  481. c = *str++ ;
  482. if (c == '\r')
  483. {
  484. mx = x ;
  485. continue ;
  486. }
  487. if (c == '\n')
  488. {
  489. mx = x ;
  490. my -= fontHeight ;
  491. continue ;
  492. }
  493. lcd128x64putchar (mx, my, c, bgCol, fgCol) ;
  494. mx += fontWidth ;
  495. if (mx >= (maxX - fontWidth))
  496. {
  497. mx = 0 ;
  498. my -= fontHeight ;
  499. }
  500. }
  501. }
  502. /*
  503. * lcd128x64clear:
  504. * Clear the display to the given colour.
  505. *********************************************************************************
  506. */
  507. void lcd128x64clear (int colour)
  508. {
  509. register int i ;
  510. register unsigned char *ptr = frameBuffer ;
  511. for (i = 0 ; i < (maxX * maxY) ; ++i)
  512. *ptr++ = colour ;
  513. }
  514. /*
  515. * lcd128x64setup:
  516. * Initialise the display and GPIO.
  517. *********************************************************************************
  518. */
  519. int lcd128x64setup (void)
  520. {
  521. int i ;
  522. for (i = 0 ; i < 8 ; ++i)
  523. pinMode (i, OUTPUT) ;
  524. digitalWrite (CS1, 1) ;
  525. digitalWrite (CS2, 1) ;
  526. digitalWrite (STROBE, 0) ;
  527. digitalWrite (RS, 1) ;
  528. pinMode (CS1, OUTPUT) ;
  529. pinMode (CS2, OUTPUT) ;
  530. pinMode (STROBE, OUTPUT) ;
  531. pinMode (RS, OUTPUT) ;
  532. sendCommand (0x3F, CS1) ; // Display ON
  533. sendCommand (0xC0, CS1) ; // Set display start line to 0
  534. sendCommand (0x3F, CS2) ; // Display ON
  535. sendCommand (0xC0, CS2) ; // Set display start line to 0
  536. lcd128x64clear (0) ;
  537. lcd128x64setOrientation (0) ;
  538. lcd128x64update () ;
  539. return 0 ;
  540. }