lcd.cpp 12 KB

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