lcd.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. #include "all-headers.h"
  2. #include <stddef.h>
  3. #include <stdbool.h>
  4. // http://esd.cs.ucr.edu/labs/interface/interface.html
  5. // PORT CONFIGURATION *
  6. // LCD D4 : Teensy D16
  7. // LCD D5 : Teensy D15
  8. // LCD D6 : Teensy D14
  9. // LCD D7 : Teensy D19
  10. // LCD RS : Teensy D18
  11. // LCD E : Teensy D17
  12. static const DigitalPort LCD_D4 = DigitalPort::D16 ;
  13. static const DigitalPort LCD_D5 = DigitalPort::D15 ;
  14. static const DigitalPort LCD_D6 = DigitalPort::D14 ;
  15. static const DigitalPort LCD_D7 = DigitalPort::D19 ;
  16. static const DigitalPort LCD_RS = DigitalPort::D18 ;
  17. static const DigitalPort LCD_E = DigitalPort::D17 ;
  18. // SEMAPHORE
  19. static Semaphore sem(1);
  20. // UTILITY ROUTINES — ANY MODE
  21. static void driveHighE (void) {
  22. digitalWrite (LCD_E, true) ;
  23. }
  24. static void driveLowE (void) {
  25. digitalWrite (LCD_E, false) ;
  26. }
  27. static void driveHighRS (void) {
  28. digitalWrite (LCD_RS, true) ;
  29. }
  30. static void driveLowRS (void) {
  31. digitalWrite (LCD_RS, false) ;
  32. }
  33. static void setD4 (const bool inValue) {
  34. digitalWrite (LCD_D4, inValue) ;
  35. }
  36. static void setD5 (const bool inValue) {
  37. digitalWrite (LCD_D5, inValue) ;
  38. }
  39. static void setD6 (const bool inValue) {
  40. digitalWrite (LCD_D6, inValue) ;
  41. }
  42. static void setD7 (const bool inValue) {
  43. digitalWrite (LCD_D7, inValue) ;
  44. }
  45. static void programLcd4BitDataBusOutput (const uint8_t inValue) {
  46. setD4 ((inValue & 0x01) != 0) ;
  47. setD5 ((inValue & 0x02) != 0) ;
  48. setD6 ((inValue & 0x04) != 0) ;
  49. setD7 ((inValue & 0x08) != 0) ;
  50. }
  51. // UTILITY ROUTINES — INIT_MODE
  52. static void write4BitCommand_initMode (INIT_MODE_ const uint8_t inCommand) {
  53. busyWaitDuring_initMode (MODE_ 1) ;
  54. driveLowRS () ;
  55. programLcd4BitDataBusOutput (inCommand) ;
  56. driveHighE () ;
  57. busyWaitDuring_initMode (MODE_ 1) ;
  58. driveLowE () ;
  59. }
  60. static void write8bitCommand_initMode (INIT_MODE_ const uint8_t inCommand) {
  61. busyWaitDuring_initMode (MODE_ 1) ;
  62. driveLowRS () ;
  63. programLcd4BitDataBusOutput ((uint8_t) (inCommand >> 4)) ;
  64. driveHighE () ;
  65. busyWaitDuring_initMode (MODE_ 1) ;
  66. driveLowE () ;
  67. busyWaitDuring_initMode (MODE_ 1) ;
  68. programLcd4BitDataBusOutput (inCommand) ;
  69. driveHighE () ;
  70. busyWaitDuring_initMode (MODE_ 1) ;
  71. driveLowE () ;
  72. }
  73. // LCD INIT
  74. static void setupLCD (INIT_MODE) {
  75. // Step 1: Configure ports
  76. pinMode (LCD_D4, DigitalMode::OUTPUT) ;
  77. pinMode (LCD_D5, DigitalMode::OUTPUT) ;
  78. pinMode (LCD_D6, DigitalMode::OUTPUT) ;
  79. pinMode (LCD_D7, DigitalMode::OUTPUT) ;
  80. pinMode (LCD_RS, DigitalMode::OUTPUT) ;
  81. pinMode (LCD_E, DigitalMode::OUTPUT) ;
  82. // Step 2: wait for 15 ms
  83. busyWaitDuring_initMode (MODE_ 15) ;
  84. // Step 3: write command 0x30
  85. write4BitCommand_initMode (MODE_ 0x3) ;
  86. // Step 4: wait for 4,1 ms (actually 5 ms)
  87. busyWaitDuring_initMode (MODE_ 5) ;
  88. // Step 5: write command 0x30 again
  89. write4BitCommand_initMode (MODE_ 0x3) ;
  90. // Step 6: wait for 100 µs (actually 1 ms)
  91. busyWaitDuring_initMode (MODE_ 1) ;
  92. // Step 7: write command 0x30 (third)
  93. write4BitCommand_initMode (MODE_ 0x3) ;
  94. // Step 8: write command 0x20 (4-bit mode)
  95. write4BitCommand_initMode (MODE_ 0x2) ;
  96. // Step 9: write command 'Set Interface Length' : 0 0 1 DL N F * *
  97. // DL : Data interface length : 0 (4 bits)
  98. // N : Number of Display lines : 1 (2 lines)
  99. // F : Character Font : 0 (5x7)
  100. write8bitCommand_initMode (MODE_ 0x28) ;
  101. // Step 10: write command 'Display Off'
  102. write8bitCommand_initMode (MODE_ 0x08) ;
  103. // Step 11: write command 'Clear Display'
  104. write8bitCommand_initMode (MODE_ 0x01) ;
  105. // Step 12: write command 'Set Cursor Move Direction' : 0 0 0 0 0 1 ID S
  106. // ID : Increment Cursor after Each Byte Written to Display : 1 (yes)
  107. // S : Shift Display When Byte Written : 0 (no)
  108. write8bitCommand_initMode (MODE_ 0x06) ;
  109. // Step 13: write command 'Move Cursor / Shift Display' : 0 0 0 1 SC RL * *
  110. // SC : Display Shift On : 1 (oui)
  111. // RL : Direction of Shift : 1 (to right)
  112. write8bitCommand_initMode (MODE_ 0x1C) ;
  113. // Step 14: write command 'Return Cursor and LCD to Home Position'
  114. write8bitCommand_initMode (MODE_ 0x02) ;
  115. // Step 15: write command 'Enable Display / Cursor' : 0 0 0 0 1 D C B
  116. // D : Turn Display On : 1 (yes)
  117. // C : Turn Cursor On : 0 (no)
  118. // B : Cursor Blink On : 0 (no)
  119. write8bitCommand_initMode (MODE_ 0x0C) ;
  120. }
  121. MACRO_INIT_ROUTINE (setupLCD) ;
  122. // UTILITY ROUTINES — USER MODE
  123. static void write8bitCommand (USER_MODE_ const uint8_t inCommand) {
  124. waitDuring (MODE_ 1) ;
  125. driveLowRS () ;
  126. programLcd4BitDataBusOutput ((uint8_t) (inCommand >> 4)) ;
  127. driveHighE () ;
  128. waitDuring (MODE_ 1) ;
  129. driveLowE () ;
  130. waitDuring (MODE_ 1) ;
  131. programLcd4BitDataBusOutput (inCommand) ;
  132. driveHighE () ;
  133. waitDuring (MODE_ 1) ;
  134. driveLowE () ;
  135. }
  136. static void writeData (USER_MODE_ const uint8_t inData) {
  137. sem.P(MODE);
  138. waitDuring (MODE_ 1) ;
  139. driveHighRS () ;
  140. programLcd4BitDataBusOutput (inData >> 4) ;
  141. driveHighE () ;
  142. waitDuring (MODE_ 1) ;
  143. driveLowE () ;
  144. waitDuring (MODE_ 1) ;
  145. programLcd4BitDataBusOutput (inData) ;
  146. driveHighE () ;
  147. waitDuring (MODE_ 1) ;
  148. driveLowE () ;
  149. sem.V(MODE);
  150. }
  151. // PRINT ROUTINES — USER MODE
  152. void clearScreen (USER_MODE) {
  153. write8bitCommand (MODE_ 0x01) ;
  154. }
  155. // Line 0 : 00 -> 19
  156. // Line 1 : 64 -> 83
  157. // Line 2 : 20 -> 39
  158. // Line 3 : 84 -> 103
  159. void gotoLineColumn (USER_MODE_ const uint32_t inLine, const uint32_t inColumn) {
  160. static const uint8_t tab [4] = {0, 64, 20, 84} ;
  161. if ((inLine < 4) && (inColumn < 20)) {
  162. write8bitCommand (MODE_ tab [inLine] + inColumn + 0x80U) ;
  163. }
  164. }
  165. void printString (USER_MODE_ const char * inString) {
  166. if (NULL != inString) {
  167. while ('\0' != *inString) {
  168. writeData (MODE_ *inString) ;
  169. inString ++ ;
  170. }
  171. }
  172. }
  173. void printChar (USER_MODE_ const char inChar) {
  174. writeData (MODE_ inChar) ;
  175. }
  176. void printSpaces (USER_MODE_ const uint32_t inCount) {
  177. uint32_t count = inCount ;
  178. while (count > 0) {
  179. printChar (MODE_ ' ') ;
  180. count -- ;
  181. }
  182. }
  183. void printUnsigned (USER_MODE_ const uint32_t inValue) {
  184. uint32_t divisor = 1000 * 1000 * 1000 ; // 10**9
  185. uint32_t value = inValue ;
  186. bool isPrinting = false ;
  187. while (divisor > 0) {
  188. if (isPrinting || (value >= divisor)) {
  189. printChar (MODE_ '0' + value / divisor) ;
  190. value %= divisor ;
  191. isPrinting = true ;
  192. }
  193. divisor /= 10 ;
  194. }
  195. if (!isPrinting) {
  196. printChar (MODE_ '0') ;
  197. }
  198. }
  199. void printUnsigned64 (USER_MODE_ const uint64_t inValue) {
  200. char buffer [20] ;
  201. buffer [19] = '\0' ;
  202. buffer [18] = (inValue % 10) + '0' ;
  203. uint32_t idx = 18 ;
  204. uint64_t v = inValue / 10 ;
  205. while (v != 0) {
  206. idx -- ;
  207. buffer [idx] = (v % 10) + '0' ;
  208. v /= 10 ;
  209. }
  210. printString (MODE_ & buffer [idx]) ;
  211. }
  212. void printSigned (USER_MODE_ const int32_t inValue) {
  213. if (inValue < 0) {
  214. printChar (MODE_ '-') ;
  215. printUnsigned (MODE_ (uint32_t) -inValue) ;
  216. }else{
  217. printUnsigned (MODE_ (uint32_t) inValue) ;
  218. }
  219. }
  220. void printHex1 (USER_MODE_ const uint32_t inValue) {
  221. const uint32_t v = inValue & 0xF ;
  222. if (v < 10) {
  223. printChar (MODE_ '0' + v) ;
  224. }else{
  225. printChar (MODE_ 'A' + v - 10) ;
  226. }
  227. }
  228. void printHex2 (USER_MODE_ const uint32_t inValue) {
  229. printHex1 (MODE_ inValue >> 4) ;
  230. printHex1 (MODE_ inValue) ;
  231. }
  232. void printHex4 (USER_MODE_ const uint32_t inValue) {
  233. printHex2 (MODE_ inValue >> 8) ;
  234. printHex2 (MODE_ inValue) ;
  235. }
  236. void printHex8 (USER_MODE_ const uint32_t inValue) {
  237. printHex4 (MODE_ inValue >> 16) ;
  238. printHex4 (MODE_ inValue) ;
  239. }
  240. void printHex16 (USER_MODE_ const uint64_t inValue) {
  241. printHex8 (MODE_ (uint32_t) (inValue >> 32)) ;
  242. printHex8 (MODE_ (uint32_t) inValue) ;
  243. }
  244. // FAULT MODE
  245. static void write4BitCommand_faultMode (FAULT_MODE_ const uint8_t inCommand) {
  246. busyWaitDuring_faultMode (MODE_ 1) ;
  247. driveLowRS () ;
  248. programLcd4BitDataBusOutput (inCommand) ;
  249. driveHighE () ;
  250. busyWaitDuring_faultMode (MODE_ 1) ;
  251. driveLowE () ;
  252. }
  253. static void write8bitCommand_faultMode (FAULT_MODE_ const uint8_t inCommand) {
  254. busyWaitDuring_faultMode (MODE_ 1) ;
  255. driveLowRS () ;
  256. programLcd4BitDataBusOutput ((uint8_t) (inCommand >> 4)) ;
  257. driveHighE () ;
  258. busyWaitDuring_faultMode (MODE_ 1) ;
  259. driveLowE () ;
  260. busyWaitDuring_faultMode (MODE_ 1) ;
  261. programLcd4BitDataBusOutput (inCommand) ;
  262. driveHighE () ;
  263. busyWaitDuring_faultMode (MODE_ 1) ;
  264. driveLowE () ;
  265. }
  266. void initScreen_faultMode (FAULT_MODE) {
  267. // Step 1: Configure ports
  268. pinMode (LCD_D4, DigitalMode::OUTPUT) ;
  269. pinMode (LCD_D5, DigitalMode::OUTPUT) ;
  270. pinMode (LCD_D6, DigitalMode::OUTPUT) ;
  271. pinMode (LCD_D7, DigitalMode::OUTPUT) ;
  272. pinMode (LCD_RS, DigitalMode::OUTPUT) ;
  273. pinMode (LCD_E, DigitalMode::OUTPUT) ;
  274. // Step 2: wait for 15 ms
  275. busyWaitDuring_faultMode (MODE_ 15) ;
  276. // Step 3: write command 0x30
  277. write4BitCommand_faultMode (MODE_ 0x3) ;
  278. // Step 4: wait for 4,1 ms (actually 5 ms)
  279. busyWaitDuring_faultMode (MODE_ 5) ;
  280. // Step 5: write command 0x30 again
  281. write4BitCommand_faultMode (MODE_ 0x3) ;
  282. // Step 6: wait for 100 µs (actually 1 ms)
  283. busyWaitDuring_faultMode (MODE_ 1) ;
  284. // Step 7: write command 0x30 (third)
  285. write4BitCommand_faultMode (MODE_ 0x3) ;
  286. // Step 8: write command 0x20 (4-bit mode)
  287. write4BitCommand_faultMode (MODE_ 0x2) ;
  288. // Step 9: write command 'Set Interface Length' : 0 0 1 DL N F * *
  289. // DL : Data interface length : 0 (4 bits)
  290. // N : Number of Display lines : 1 (2 lines)
  291. // F : Character Font : 0 (5x7)
  292. write8bitCommand_faultMode (MODE_ 0x28) ;
  293. // Step 10: write command 'Display Off'
  294. write8bitCommand_faultMode (MODE_ 0x08) ;
  295. // Step 11: write command 'Clear Display'
  296. write8bitCommand_faultMode (MODE_ 0x01) ;
  297. // Step 12: write command 'Set Cursor Move Direction' : 0 0 0 0 0 1 ID S
  298. // ID : Increment Cursor after Each Byte Written to Display : 1 (yes)
  299. // S : Shift Display When Byte Written : 0 (no)
  300. write8bitCommand_faultMode (MODE_ 0x06) ;
  301. // Step 13: write command 'Move Cursor / Shift Display' : 0 0 0 1 SC RL * *
  302. // SC : Display Shift On : 1 (oui)
  303. // RL : Direction of Shift : 1 (to right)
  304. write8bitCommand_faultMode (MODE_ 0x1C) ;
  305. // Step 14: write command 'Return Cursor and LCD to Home Position'
  306. write8bitCommand_faultMode (MODE_ 0x02) ;
  307. // Step 15: write command 'Enable Display / Cursor' : 0 0 0 0 1 D C B
  308. // D : Turn Display On : 1 (yes)
  309. // C : Turn Cursor On : 0 (no)
  310. // B : Cursor Blink On : 0 (no)
  311. write8bitCommand_faultMode (MODE_ 0x0C) ;
  312. }
  313. void gotoLineColumn_faultMode (FAULT_MODE_ const uint32_t inLine, const uint32_t inColumn) {
  314. static const uint8_t tab [4] = {0, 64, 20, 84} ;
  315. if ((inLine < 4) && (inColumn < 20)) {
  316. write8bitCommand_faultMode (MODE_ tab [inLine] + inColumn + 0x80U) ;
  317. }
  318. }
  319. static void writeData_faultMode (FAULT_MODE_ const uint8_t inData) {
  320. busyWaitDuring_faultMode (MODE_ 1) ;
  321. driveHighRS () ;
  322. programLcd4BitDataBusOutput (inData >> 4) ;
  323. driveHighE () ;
  324. busyWaitDuring_faultMode (MODE_ 1) ;
  325. driveLowE () ;
  326. busyWaitDuring_faultMode (MODE_ 1) ;
  327. programLcd4BitDataBusOutput (inData) ;
  328. driveHighE () ;
  329. busyWaitDuring_faultMode (MODE_ 1) ;
  330. driveLowE () ;
  331. }
  332. void printString_faultMode (FAULT_MODE_ const char * inString) {
  333. if (NULL != inString) {
  334. while ('\0' != *inString) {
  335. writeData_faultMode (MODE_ *inString) ;
  336. inString ++ ;
  337. }
  338. }
  339. }
  340. void printChar_faultMode (FAULT_MODE_ const char inChar) {
  341. writeData_faultMode (MODE_ inChar) ;
  342. }
  343. void printUnsigned_faultMode (FAULT_MODE_ const uint32_t inValue) {
  344. uint32_t divisor = 1000 * 1000 * 1000 ; // 10**9
  345. uint32_t value = inValue ;
  346. bool isPrinting = false ;
  347. while (divisor > 0) {
  348. if (isPrinting || (value >= divisor)) {
  349. printChar_faultMode (MODE_ '0' + value / divisor) ;
  350. value %= divisor ;
  351. isPrinting = true ;
  352. }
  353. divisor /= 10 ;
  354. }
  355. if (!isPrinting) {
  356. printChar_faultMode (MODE_ '0') ;
  357. }
  358. }
  359. static void printHex1_faultMode (FAULT_MODE_ const uint32_t inValue) {
  360. const uint32_t v = inValue & 0xF ;
  361. if (v < 10) {
  362. printChar_faultMode (MODE_ '0' + v) ;
  363. }else{
  364. printChar_faultMode (MODE_ 'A' + v - 10) ;
  365. }
  366. }
  367. void printHex2_faultMode (FAULT_MODE_ const uint32_t inValue) {
  368. printHex1_faultMode (MODE_ inValue >> 4) ;
  369. printHex1_faultMode (MODE_ inValue) ;
  370. }
  371. void printHex4_faultMode (FAULT_MODE_ const uint32_t inValue) {
  372. printHex2_faultMode (MODE_ inValue >> 8) ;
  373. printHex2_faultMode (MODE_ inValue) ;
  374. }
  375. void printHex8_faultMode (FAULT_MODE_ const uint32_t inValue) {
  376. printHex4_faultMode (MODE_ inValue >> 16) ;
  377. printHex4_faultMode (MODE_ inValue) ;
  378. }