hd44780.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * Copyright (C) 2001-2007 by egnite Software GmbH.
  3. * Copyright (C) 2013 by Comm5 Tecnologia Ltda.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. *
  34. */
  35. /*
  36. * $Log$
  37. * Port done by Walter Orosco
  38. */
  39. #include <arch/avr32.h>
  40. #include <avr32/io.h>
  41. #include <cfg/arch.h>
  42. #include <cfg/lcd.h>
  43. #include <dev/hd44780.h>
  44. #include <dev/term.h>
  45. #include <dev/gpio.h>
  46. #include <dev/board.h>
  47. #include <dev/watchdog.h>
  48. #include <sys/thread.h>
  49. #include <sys/nutconfig.h>
  50. #include <sys/timer.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #ifndef LCD_ROWS
  55. #define LCD_ROWS 2
  56. #endif
  57. #ifndef LCD_COLS
  58. #define LCD_COLS 16
  59. #endif
  60. #ifndef LCD_E2E_DLY
  61. #define LCD_E2E_DLY 80
  62. #endif
  63. #ifndef LCD_LONG_DELAY
  64. #define LCD_LONG_DELAY 1000
  65. #endif
  66. #ifndef LCD_DATA_BIT0
  67. #define LCD_DATA_BIT0 1
  68. #define LCD_DATA_BIT1 1
  69. #define LCD_DATA_BIT2 1
  70. #define LCD_DATA_BIT3 1
  71. #endif
  72. #ifndef LCD_PW_EH
  73. #define LCD_PW_EH 500
  74. #define LcdNanoDelay(x) NutMicroDelay(x/10);
  75. #else
  76. #define LcdNanoDelay(x)
  77. #endif
  78. #if !defined(LCD_IF_8BIT) && !defined(LCD_IF_4BIT)
  79. #define LCD_IF_4BIT
  80. #endif
  81. #ifdef LCD_IF_4BIT
  82. #ifdef LCD_DATA_LSB
  83. #define LCD_DATA (0xF << LCD_DATA_LSB)
  84. #else /* LCD_DATA_LSB */
  85. #define LCD_D0 _BV(LCD_DATA_BIT0)
  86. #define LCD_D1 _BV(LCD_DATA_BIT1)
  87. #define LCD_D2 _BV(LCD_DATA_BIT2)
  88. #define LCD_D3 _BV(LCD_DATA_BIT3)
  89. #define LCD_DATA (LCD_D0 | LCD_D1 | LCD_D2 | LCD_D3)
  90. #endif /* LCD_DATA_LSB */
  91. #else /* LCD_IF_4BIT */
  92. #define LCD_DATA (0xFF << LCD_DATA_LSB)
  93. #endif /* LCD_IF_4BIT */
  94. #ifndef LCD_SHORT_DELAY
  95. #define LCD_SHORT_DELAY 100
  96. #endif
  97. #ifndef LCD_LONG_DELAY
  98. #define LCD_LONG_DELAY 200
  99. #endif
  100. #define LCD_E2E_DLY 80
  101. #ifdef LCD_EN_BIT
  102. #define LCD_EN _BV(LCD_EN_BIT)
  103. #if LCD_EN_PIO_ID == PIOA_ID
  104. #define LCD_EN_SET() { outr(PIO_PER, LCD_EN ); outr(PIO_SODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  105. #define LCD_EN_CLR() { outr(PIO_PER, LCD_EN ); outr(PIO_CODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  106. #elif LCD_EN_PIO_ID == PIOB_ID
  107. #define LCD_EN_SET() { outr(PIO_PER, LCD_EN ); outr(PIO_SODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  108. #define LCD_EN_CLR() { outr(PIO_PER, LCD_EN ); outr(PIO_CODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  109. #elif LCD_EN_PIO_ID == PIOC_ID
  110. #define LCD_EN_SET() { outr(PIO_PER, LCD_EN ); outr(PIO_SODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  111. #define LCD_EN_CLR() { outr(PIO_PER, LCD_EN ); outr(PIO_CODR, LCD_EN ); outr(PIO_OER, LCD_EN ); }
  112. #else
  113. #define LCD_EN_SET() { outr(PIO_PER, LCD_EN); outr(PIO_SODR, LCD_EN); outr(PIO_OER, LCD_EN); }
  114. #define LCD_EN_CLR() { outr(PIO_PER, LCD_EN); outr(PIO_CODR, LCD_EN); outr(PIO_OER, LCD_EN); }
  115. #endif /* LCD_EN_PIO_ID */
  116. #else /* LCD_EN_BIT */
  117. #define LCD_EN_SET()
  118. #define LCD_EN_CLR()
  119. #endif /* LCD_EN_BIT */
  120. #ifdef LCD_RS_BIT
  121. #define LCD_RS _BV(LCD_RS_BIT)
  122. #if LCD_RS_PIO_ID == PIOA_ID
  123. #define LCD_RS_SET() { outr(PIO_PER, LCD_RS); outr(PIO_SODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  124. #define LCD_RS_CLR() { outr(PIO_PER, LCD_RS); outr(PIO_CODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  125. #elif LCD_RS_PIO_ID == PIOB_ID
  126. #define LCD_RS_SET() { outr(PIO_PER, LCD_RS); outr(PIO_SODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  127. #define LCD_RS_CLR() { outr(PIO_PER, LCD_RS); outr(PIO_CODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  128. #elif LCD_RS_PIO_ID == PIOC_ID
  129. #define LCD_RS_SET() { outr(PIO_PER, LCD_RS); outr(PIO_SODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  130. #define LCD_RS_CLR() { outr(PIO_PER, LCD_RS); outr(PIO_CODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  131. #else
  132. #define LCD_RS_SET() { outr(PIO_PER, LCD_RS); outr(PIO_SODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  133. #define LCD_RS_CLR() { outr(PIO_PER, LCD_RS); outr(PIO_CODR, LCD_RS); outr(PIO_OER, LCD_RS); }
  134. #endif /* LCD_RS_PIO_ID */
  135. #else /* LCD_RS_BIT */
  136. #define LCD_RS_SET()
  137. #define LCD_RS_CLR()
  138. #endif /* LCD_RS_BIT */
  139. #ifdef LCD_RW_BIT
  140. #define LCD_RW _BV(LCD_RW_BIT)
  141. #if LCD_RS_PIO_ID == PIOA_ID
  142. #define LCD_RW_SET() { outr(PIO_PER, LCD_RW); outr(PIO_SODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  143. #define LCD_RW_CLR() { outr(PIO_PER, LCD_RW); outr(PIO_CODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  144. #elif LCD_RS_PIO_ID == PIOB_ID
  145. #define LCD_RW_SET() { outr(PIO_PER, LCD_RW); outr(PIO_SODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  146. #define LCD_RW_CLR() { outr(PIO_PER, LCD_RW); outr(PIO_CODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  147. #elif LCD_RS_PIO_ID == PIOC_ID
  148. #define LCD_RW_SET() { outr(PIO_PER, LCD_RW); outr(PIO_SODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  149. #define LCD_RW_CLR() { outr(PIO_PER, LCD_RW); outr(PIO_CODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  150. #else
  151. #define LCD_RW_SET() { outr(PIO_PER, LCD_RW); outr(PIO_SODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  152. #define LCD_RW_CLR() { outr(PIO_PER, LCD_RW); outr(PIO_CODR, LCD_RW); outr(PIO_OER, LCD_RW); }
  153. #endif /* LCD_RW_PIO_ID */
  154. #else /* LCD_RW_BIT */
  155. #define LCD_RW_SET()
  156. #define LCD_RW_CLR()
  157. #endif /* LCD_RW_BIT */
  158. #if LCD_DATA_PIO_ID == PIOA_ID
  159. #define LCD_DATA_BASE PIOA_BASE
  160. #elif LCD_DATA_PIO_ID == PIOB_ID
  161. #define LCD_DATA_BASE PIOB_BASE
  162. #else /* LCD_DATA_PIO_ID */
  163. #define LCD_DATA_BASE PIO_BASE
  164. #endif
  165. #define PIO_PER (LCD_DATA_BASE + AVR32_GPIO_GPERS) /*!< \brief enable register address. */
  166. #define PIO_PDR (LCD_DATA_BASE + AVR32_GPIO_GPERC) /*!< \brief disable register address. */
  167. #define PIO_PSR (LCD_DATA_BASE + AVR32_GPIO_GPER) /*!< \brief status register address. */
  168. #define PIO_OER (LCD_DATA_BASE + AVR32_GPIO_ODERS) /*!< \brief Output enable register address. */
  169. #define PIO_ODR (LCD_DATA_BASE + AVR32_GPIO_ODERC) /*!< \brief Output disable register address. */
  170. #define PIO_OSR (LCD_DATA_BASE + AVR32_GPIO_ODER) /*!< \brief Output status register address. */
  171. #define PIO_SODR (LCD_DATA_BASE + AVR32_GPIO_OVRS) /*!< \brief Set output data register address. */
  172. #define PIO_CODR (LCD_DATA_BASE + AVR32_GPIO_OVRC) /*!< \brief Clear output data register address. */
  173. #define PIO_ODSR (LCD_DATA_BASE + AVR32_GPIO_OVR) /*!< \brief Output data status register address. */
  174. #define PIO_PDSR (LCD_DATA_BASE + AVR32_GPIO_PVR) /*!< \brief Pin data status register address. */
  175. #define PIO_IFER (LCD_DATA_BASE + AVR32_GPIO_GFERS) /*!< \brief Input filter enable register address. */
  176. #define PIO_IFDR (LCD_DATA_BASE + AVR32_GPIO_GFERC) /*!< \brief Input filter disable register address. */
  177. #define PIO_IFSR (LCD_DATA_BASE + AVR32_GPIO_GFER) /*!< \brief Input filter status register address. */
  178. /*!
  179. * \addtogroup xgDisplay
  180. */
  181. /*@{*/
  182. /*!
  183. * \brief Wait until controller will be ready again
  184. *
  185. * If LCD_WR_BIT is defined we will wait until the ready bit is set, otherwise
  186. * We will either busy loop with NutDelay or sleep with NutSleep. The second
  187. * option will be used if we have defined NUT_CPU_FREQ. In this case we have a higher
  188. * timer resolution.
  189. *
  190. * \param xt Delay time in milliseconds
  191. */
  192. static void INLINE LcdSetBits(unsigned int mask)
  193. {
  194. outr(PIO_PER, mask);
  195. outr(PIO_SODR , mask);
  196. outr(PIO_OER, mask);
  197. }
  198. static void INLINE LcdClrBits(unsigned int mask)
  199. {
  200. outr(PIO_PER, mask);
  201. outr(PIO_CODR, mask);
  202. outr(PIO_OER, mask);
  203. }
  204. /*!
  205. * \brief Send half byte to LCD controller.
  206. *
  207. * \param nib The four least significant bits are sent.
  208. */
  209. static void LcdWriteNibble(unsigned int nib)
  210. {
  211. #ifdef LCD_DATA_LSB
  212. nib <<= LCD_DATA_LSB;
  213. #else
  214. {
  215. unsigned int val = 0;
  216. if (nib & 0x01) {
  217. val |= LCD_D0;
  218. }
  219. if (nib & 0x02) {
  220. val |= LCD_D1;
  221. }
  222. if (nib & 0x04) {
  223. val |= LCD_D2;
  224. }
  225. if (nib & 0x08) {
  226. val |= LCD_D3;
  227. }
  228. nib = val;
  229. }
  230. #endif
  231. LcdSetBits(nib & LCD_DATA);
  232. LcdClrBits(~nib & LCD_DATA);
  233. /* Create Enable Pulse:
  234. * For HD44780 Displays we need:
  235. * Vcc = 5.0V -> PWeh >= 230ns
  236. * Vcc = 3.3V -> PWeh >= 500ns
  237. */
  238. LCD_EN_SET();
  239. NutMicroDelay(LCD_SHORT_DELAY);
  240. LCD_EN_CLR();
  241. }
  242. /*!
  243. * \brief Send byte to LCD controller.
  244. *
  245. * \param data Byte to send.
  246. */
  247. static void LcdWriteByte(unsigned int data)
  248. {
  249. /* If configured set RW low */
  250. #ifdef LCD_RW_BIT
  251. LCD_RW_CLR();
  252. #endif
  253. /* If using 4-bit access, write two nibbles now */
  254. #ifdef LCD_IF_4BIT
  255. LcdWriteNibble(data >> 4);
  256. LcdNanoDelay(LCD_PW_EH);
  257. LcdWriteNibble(data);
  258. #else
  259. /* else write one byte */
  260. LcdWriteNibble(data);
  261. #endif
  262. /* If configured, let the task sleep before next character */
  263. #if defined(LCD_SLEEP_DLY)
  264. NutSleep(1);
  265. #else
  266. /* or add a fixed delay and immediately process next char */
  267. NutMicroDelay(LCD_E2E_DLY);
  268. #endif
  269. }
  270. /*!
  271. * \brief Send command byte to LCD controller.
  272. *
  273. * \param cmd Byte to send.
  274. */
  275. static void LcdWriteCmd(uint8_t cmd)
  276. {
  277. /* RS low selects instruction register. */
  278. LCD_RS_CLR();
  279. LcdWriteByte(cmd);
  280. }
  281. static void LcdWriteInstruction(uint8_t cmd, uint8_t xt)
  282. {
  283. LcdWriteCmd(cmd);
  284. }
  285. /*!
  286. * \brief Send data byte to LCD controller.
  287. *
  288. * \param data Byte to send.
  289. */
  290. static void LcdWriteData(uint8_t data)
  291. {
  292. /* RS high selects data register. */
  293. LCD_RS_SET();
  294. LcdWriteByte(data);
  295. }
  296. static void LcdSetCursor(uint8_t pos)
  297. {
  298. uint8_t offset[] = {
  299. #ifdef LCD_KS0073
  300. 0x00, 0x20, 0x40, 0x60
  301. #elif (LCD_COLS >= 20)
  302. 0x00, 0x40, 0x14, 0x54
  303. #else
  304. 0x00, 0x40, 0x10, 0x50
  305. #endif
  306. };
  307. pos = offset[(pos / LCD_COLS) % LCD_ROWS] + pos % LCD_COLS;
  308. LcdWriteCmd(1 << LCD_DDRAM | pos);
  309. }
  310. static void LcdCursorHome(void)
  311. {
  312. LcdWriteCmd(1 << LCD_HOME);
  313. NutSleep(2);
  314. }
  315. static void LcdCursorLeft(void)
  316. {
  317. LcdWriteCmd(1 << LCD_MOVE);
  318. }
  319. static void LcdCursorRight(void)
  320. {
  321. LcdWriteCmd(1 << LCD_MOVE | 1 << LCD_MOVE_RIGHT);
  322. }
  323. static void LcdClear(void)
  324. {
  325. LcdWriteCmd(_BV(LCD_CLR));
  326. NutSleep(2);
  327. }
  328. static void LcdCursorMode(uint8_t on)
  329. {
  330. LcdWriteCmd(1 << LCD_ON_CTRL | on ? 1 << LCD_ON_CURSOR : 0x00);
  331. }
  332. static int LcdInit(NUTDEVICE * dev)
  333. {
  334. LCD_RS_CLR();
  335. LCD_RW_CLR();
  336. LcdClrBits(LCD_DATA);
  337. NutMicroDelay(30);
  338. LCD_EN_CLR();
  339. NutMicroDelay(30);
  340. NutSleep(18);
  341. /* This initialization will make sure, that the LCD is switched
  342. * to 8-bit mode, no matter which mode we start from or we finally
  343. * need.
  344. */
  345. LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT));
  346. NutSleep(16);
  347. LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT));
  348. NutSleep(4);
  349. LcdWriteCmd(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT));
  350. NutSleep(2);
  351. LcdWriteInstruction((_BV(LCD_FUNCTION)) | (_BV(LCD_FUNCTION_8BIT)) | (_BV(LCD_EXT)) , LCD_SHORT_DELAY);
  352. /* Switch display and cursor off. */
  353. LcdWriteNibble(_BV(LCD_ON_CTRL) >> 4);
  354. LcdWriteNibble(_BV(LCD_ON_CTRL));
  355. NutSleep(2);
  356. /* Clear display. */
  357. LcdClear();
  358. /* Set entry mode. */
  359. LcdWriteCmd(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC));
  360. /* Switch display on. */
  361. LcdWriteCmd(_BV(LCD_ON_CTRL) | _BV(LCD_ON_DISPLAY));
  362. /* Move cursor home. */
  363. LcdCursorHome();
  364. /* Set data address to zero. */
  365. LcdWriteCmd(_BV(LCD_DDRAM));
  366. return 0;
  367. }
  368. /*!
  369. * \brief Terminal device control block structure.
  370. */
  371. TERMDCB dcb_term = {
  372. LcdInit, /*!< \brief Initialize display subsystem, dss_init. */
  373. LcdWriteData, /*!< \brief Write display character, dss_write. */
  374. LcdWriteInstruction, /*!< \brief Write display command, dss_command. */
  375. LcdClear, /*!< \brief Clear display, dss_clear. */
  376. LcdSetCursor, /*!< \brief Set display cursor, dss_set_cursor. */
  377. LcdCursorHome, /*!< \brief Set display cursor home, dss_cursor_home. */
  378. LcdCursorLeft, /*!< \brief Move display cursor left, dss_cursor_left. */
  379. LcdCursorRight, /*!< \brief Move display cursor right, dss_cursor_right. */
  380. LcdCursorMode, /*!< \brief Switch cursor on/off, dss_cursor_mode. */
  381. 0, /*!< \brief Mode flags. */
  382. 0, /*!< \brief Status flags. */
  383. LCD_ROWS, /*!< \brief Number of rows. */
  384. LCD_COLS, /*!< \brief Number of columns per row. */
  385. LCD_COLS, /*!< \brief Number of visible columns. */
  386. 0, /*!< \brief Cursor row. */
  387. 0, /*!< \brief Cursor column. */
  388. 0 /*!< \brief Display shadow memory. */
  389. };
  390. /*!
  391. * \brief LCD device information structure.
  392. */
  393. NUTDEVICE devLcd = {
  394. 0, /*!< Pointer to next device. */
  395. {'l', 'c', 'd', 0, 0, 0, 0, 0, 0}, /*!< Unique device name. */
  396. IFTYP_STREAM, /*!< Type of device. */
  397. 0, /*!< Base address. */
  398. 0, /*!< First interrupt number. */
  399. 0, /*!< Interface control block. */
  400. &dcb_term, /*!< Driver control block. */
  401. TermInit, /*!< Driver initialization routine. */
  402. TermIOCtl, /*!< Driver specific control function. */
  403. 0,
  404. TermWrite,
  405. TermOpen,
  406. TermClose,
  407. 0,
  408. 0, /*!< Select function, dev_select, optional. */
  409. };
  410. /*@}*/