hd44780.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*
  2. * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*!
  34. * \file arch/avr/dev/hd44780_bus.c
  35. * \brief Terminal device definitions for port mapped LCD.
  36. *
  37. * \verbatim
  38. * $Id: hd44780.c 5472 2013-12-06 00:16:28Z olereinhardt $
  39. * \endverbatim
  40. */
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <cfg/arch/avr.h>
  44. #include <dev/hd44780.h>
  45. #include <dev/term.h>
  46. #include <sys/timer.h>
  47. /* Backward compatibility with old macros */
  48. #ifndef LCD_ROWS
  49. #if defined(LCD_4x20) || defined(LCD_4x16) || defined(KS0073_CONTROLLER)
  50. #define LCD_ROWS 4
  51. #elif defined(LCD_1x20) || defined(LCD_1x16) || defined(LCD_1x8)
  52. #define LCD_ROWS 1
  53. #else
  54. #define LCD_ROWS 2
  55. #endif
  56. #endif /* LCD_ROWS */
  57. /* Backward compatibility with old macros */
  58. #ifndef LCD_COLS
  59. #if defined(LCD_2x40)
  60. #define LCD_COLS 40
  61. #elif defined(LCD_4x20) || defined(LCD_2x20) || defined(LCD_1x20) || defined(KS0073_CONTROLLER)
  62. #define LCD_COLS 20
  63. #elif defined(LCD_2x8) || defined(LCD_1x8)
  64. #define LCD_COLS 8
  65. #else
  66. #define LCD_COLS 16
  67. #endif
  68. #endif /* LCD_COLS */
  69. /*
  70. * Many thanks to Thiago Correa for adding LCD port configuration.
  71. */
  72. /* LCD_DATA_PORT and LCD_DATA_DDR switches */
  73. #if ( LCD_DATA_AVRPORT == AVRPORTA )
  74. #define LCD_DATA_PORT PORTA
  75. #define LCD_DATA_PIN PINA
  76. #define LCD_DATA_DDR DDRA
  77. #elif ( LCD_DATA_AVRPORT == AVRPORTB )
  78. #define LCD_DATA_PORT PORTB
  79. #define LCD_DATA_PIN PINB
  80. #define LCD_DATA_DDR DDRB
  81. #elif ( LCD_DATA_AVRPORT == AVRPORTC )
  82. #define LCD_DATA_PORT PORTC
  83. #define LCD_DATA_PIN PINC
  84. #define LCD_DATA_DDR DDRC
  85. #elif ( LCD_DATA_AVRPORT == AVRPORTE )
  86. #define LCD_DATA_PORT PORTE
  87. #define LCD_DATA_PIN PINE
  88. #define LCD_DATA_DDR DDRE
  89. #elif ( LCD_DATA_AVRPORT == AVRPORTF )
  90. #define LCD_DATA_PORT PORTF
  91. #define LCD_DATA_PIN PINF
  92. #define LCD_DATA_DDR DDRF
  93. #elif ( LCD_DATA_AVRPORT == AVRPORTG )
  94. #define LCD_DATA_PORT PORTG
  95. #define LCD_DATA_PIN PING
  96. #define LCD_DATA_DDR DDRG
  97. #else
  98. #define LCD_DATA_PORT PORTD
  99. #define LCD_DATA_PIN PIND
  100. #define LCD_DATA_DDR DDRD
  101. #endif
  102. #ifndef LCD_DATA_BITS
  103. #define LCD_DATA_BITS 0xF0
  104. #endif
  105. /* LCD_ENABLE_PORT switches */
  106. #if ( LCD_ENABLE_AVRPORT == AVRPORTA )
  107. #define LCD_ENABLE_PORT PORTA
  108. #define LCD_ENABLE_DDR DDRA
  109. #elif ( LCD_ENABLE_AVRPORT == AVRPORTB )
  110. #define LCD_ENABLE_PORT PORTB
  111. #define LCD_ENABLE_DDR DDRB
  112. #elif ( LCD_ENABLE_AVRPORT == AVRPORTC )
  113. #define LCD_ENABLE_PORT PORTC
  114. #define LCD_ENABLE_DDR DDRC
  115. #elif ( LCD_ENABLE_AVRPORT == AVRPORTD )
  116. #define LCD_ENABLE_PORT PORTD
  117. #define LCD_ENABLE_DDR DDRD
  118. #elif ( LCD_ENABLE_AVRPORT == AVRPORTF )
  119. #define LCD_ENABLE_PORT PORTF
  120. #define LCD_ENABLE_DDR DDRF
  121. #elif ( LCD_ENABLE_AVRPORT == AVRPORTG )
  122. #define LCD_ENABLE_PORT PORTG
  123. #define LCD_ENABLE_DDR DDRG
  124. #else
  125. #define LCD_ENABLE_PORT PORTE
  126. #define LCD_ENABLE_DDR DDRE
  127. #endif
  128. #ifndef LCD_ENABLE_BIT
  129. #define LCD_ENABLE_BIT 3 /*!< \brief LCD enable output. */
  130. #endif
  131. /* LCD_REGSEL_PORT switches */
  132. #if ( LCD_REGSEL_AVRPORT == AVRPORTA )
  133. #define LCD_REGSEL_PORT PORTA
  134. #define LCD_REGSEL_DDR DDRA
  135. #elif ( LCD_REGSEL_AVRPORT == AVRPORTB )
  136. #define LCD_REGSEL_PORT PORTB
  137. #define LCD_REGSEL_DDR DDRB
  138. #elif ( LCD_REGSEL_AVRPORT == AVRPORTC )
  139. #define LCD_REGSEL_PORT PORTC
  140. #define LCD_REGSEL_DDR DDRC
  141. #elif ( LCD_REGSEL_AVRPORT == AVRPORTD )
  142. #define LCD_REGSEL_PORT PORTD
  143. #define LCD_REGSEL_DDR DDRD
  144. #elif ( LCD_REGSEL_AVRPORT == AVRPORTF )
  145. #define LCD_REGSEL_PORT PORTF
  146. #define LCD_REGSEL_DDR DDRF
  147. #elif ( LCD_REGSEL_AVRPORT == AVRPORTG )
  148. #define LCD_REGSEL_PORT PORTG
  149. #define LCD_REGSEL_DDR DDRG
  150. #else
  151. #define LCD_REGSEL_PORT PORTE
  152. #define LCD_REGSEL_DDR DDRE
  153. #endif
  154. #ifndef LCD_REGSEL_BIT
  155. #define LCD_REGSEL_BIT 2 /*!< \brief LCD register select output. */
  156. #endif
  157. /* LCD_RW_PORT switches */
  158. #if ( LCD_RW_AVRPORT == AVRPORTA )
  159. #define LCD_RW_PORT PORTA
  160. #define LCD_RW_DDR DDRA
  161. #elif ( LCD_RW_AVRPORT == AVRPORTB )
  162. #define LCD_RW_PORT PORTB
  163. #define LCD_RW_DDR DDRB
  164. #elif ( LCD_RW_AVRPORT == AVRPORTC )
  165. #define LCD_RW_PORT PORTC
  166. #define LCD_RW_DDR DDRC
  167. #elif ( LCD_RW_AVRPORT == AVRPORTD )
  168. #define LCD_RW_PORT PORTD
  169. #define LCD_RW_DDR DDRD
  170. #elif ( LCD_RW_AVRPORT == AVRPORTE )
  171. #define LCD_RW_PORT PORTE
  172. #define LCD_RW_DDR DDRE
  173. #elif ( LCD_RW_AVRPORT == AVRPORTF )
  174. #define LCD_RW_PORT PORTF
  175. #define LCD_RW_DDR DDRF
  176. #elif ( LCD_RW_AVRPORT == AVRPORTG )
  177. #define LCD_RW_PORT PORTG
  178. #define LCD_RW_DDR DDRG
  179. #endif
  180. /*!
  181. * \addtogroup xgDisplay
  182. */
  183. /*@{*/
  184. #ifndef LCD_SHORT_DELAY
  185. #define LCD_SHORT_DELAY 1
  186. #endif
  187. #ifndef LCD_LONG_DELAY
  188. #define LCD_LONG_DELAY 2
  189. #endif
  190. /*!
  191. * \brief Wait until controller will be ready again
  192. *
  193. * If LCD_WR_BIT is defined we will wait until the ready bit is set, otherwise
  194. * We will either busy loop with NutDelay or sleep with NutSleep. The second
  195. * option will be used if we have defined NUT_CPU_FREQ. In this case we have a higher
  196. * timer resolution.
  197. *
  198. * \param xt Delay time in milliseconds
  199. */
  200. static uint8_t during_init = 1;
  201. #define LCD_DELAY _NOP(); _NOP(); _NOP(); _NOP() /*Three Nops would fit too */
  202. #ifdef LCD_RW_BIT
  203. static INLINE uint8_t LcdReadNibble(void)
  204. {
  205. uint8_t ret;
  206. sbi(LCD_RW_PORT, LCD_RW_BIT);
  207. outb(LCD_DATA_DDR, inb(LCD_DATA_DDR) & ~LCD_DATA_BITS); // enable data input
  208. sbi(LCD_ENABLE_PORT, LCD_ENABLE_BIT);
  209. LCD_DELAY;
  210. ret = inb(LCD_DATA_PIN) & LCD_DATA_BITS;
  211. cbi(LCD_ENABLE_PORT, LCD_ENABLE_BIT);
  212. LCD_DELAY;
  213. return ret;
  214. }
  215. static INLINE uint8_t LcdReadByte(void)
  216. {
  217. uint8_t data;
  218. #if LCD_DATA_BITS == 0x0F
  219. data = LcdReadNibble();
  220. data = data | (LcdReadNibble() << 4);
  221. #elif LCD_DATA_BITS == 0xF0
  222. data = LcdReadNibble() >> 4;
  223. data |= LcdReadNibble();
  224. #elif LCD_DATA_BITS == 0xFF
  225. data = LcdReadNibble();
  226. #else
  227. #error "Bad definition of LCD_DATA_BITS"
  228. #endif
  229. return data;
  230. }
  231. /*!
  232. * \brief Read command byte from LCD controller.
  233. */
  234. static uint8_t LcdReadCmd(void)
  235. {
  236. sbi(LCD_REGSEL_DDR, LCD_REGSEL_BIT);
  237. cbi(LCD_REGSEL_PORT, LCD_REGSEL_BIT);
  238. return LcdReadByte();
  239. }
  240. #endif
  241. static void LcdDelay(uint8_t xt)
  242. {
  243. if (during_init) {
  244. NutDelay(xt);
  245. } else {
  246. #if defined(LCD_RW_BIT)
  247. while (LcdReadCmd() & (1 << LCD_BUSY))
  248. LCD_DELAY;
  249. LCD_DELAY;
  250. LCD_DELAY;
  251. LCD_DELAY;
  252. LCD_DELAY;
  253. LCD_DELAY;
  254. LCD_DELAY;
  255. LCD_DELAY;
  256. LCD_DELAY;
  257. LCD_DELAY;
  258. LCD_DELAY;
  259. LCD_DELAY;
  260. #elif defined(NUT_CPU_FREQ)
  261. NutSleep(xt);
  262. #else
  263. NutDelay(xt);
  264. #endif
  265. }
  266. }
  267. static INLINE void LcdSendNibble(uint8_t nib)
  268. {
  269. #ifdef LCD_RW_BIT
  270. cbi(LCD_RW_PORT, LCD_RW_BIT);
  271. #endif
  272. outb(LCD_DATA_DDR, inb(LCD_DATA_DDR) | LCD_DATA_BITS);
  273. outb(LCD_DATA_PORT, (inb(LCD_DATA_PORT) & ~LCD_DATA_BITS) | (nib & LCD_DATA_BITS));
  274. sbi(LCD_ENABLE_PORT, LCD_ENABLE_BIT);
  275. LCD_DELAY;
  276. cbi(LCD_ENABLE_PORT, LCD_ENABLE_BIT);
  277. LCD_DELAY;
  278. }
  279. /*!
  280. * \brief Send byte to LCD controller.
  281. *
  282. * The byte is sent to a 4-bit interface in two nibbles. If one has configured
  283. * LCD_DATA_BITS to 0xFF this will send a whole byte at once
  284. *
  285. * \param ch Byte to send.
  286. * \param xt Delay time in milliseconds.
  287. */
  288. static INLINE void LcdSendByte(uint8_t ch, uint8_t xt)
  289. {
  290. #if LCD_DATA_BITS == 0x0F
  291. LcdSendNibble(ch >> 4);
  292. if(xt)
  293. LcdDelay(xt);
  294. LcdSendNibble(ch);
  295. #elif LCD_DATA_BITS == 0xF0
  296. LcdSendNibble(ch);
  297. if(xt)
  298. LcdDelay(xt);
  299. LcdSendNibble(ch << 4);
  300. #elif LCD_DATA_BITS == 0xFF
  301. LcdSendNibble(ch);
  302. #else
  303. #error "Bad definition of LCD_DATA_BITS"
  304. #endif
  305. if(xt)
  306. LcdDelay(xt);
  307. }
  308. static void LcdWriteData(uint8_t ch)
  309. {
  310. sbi(LCD_REGSEL_DDR, LCD_REGSEL_BIT);
  311. sbi(LCD_REGSEL_PORT, LCD_REGSEL_BIT);
  312. LcdSendByte(ch, LCD_SHORT_DELAY);
  313. }
  314. /*!
  315. * \brief Write command byte to LCD controller.
  316. */
  317. static void LcdWriteCmd(uint8_t cmd, uint8_t xt)
  318. {
  319. sbi(LCD_REGSEL_DDR, LCD_REGSEL_BIT);
  320. cbi(LCD_REGSEL_PORT, LCD_REGSEL_BIT);
  321. LcdSendByte(cmd, xt);
  322. }
  323. static void LcdSetCursor(uint8_t pos)
  324. {
  325. uint8_t offset[] = {
  326. #ifdef KS0073_CONTROLLER
  327. 0x00, 0x20, 0x40, 0x60
  328. #elif LCD_COLS == 20
  329. 0x00, 0x40, 0x14, 0x54
  330. #else
  331. 0x00, 0x40, 0x10, 0x50
  332. #endif
  333. };
  334. pos = offset[(pos / LCD_COLS) % LCD_ROWS] + pos % LCD_COLS;
  335. LcdWriteCmd(1 << LCD_DDRAM | pos, LCD_SHORT_DELAY);
  336. }
  337. static void LcdCursorHome(void)
  338. {
  339. LcdWriteCmd(1 << LCD_HOME, LCD_LONG_DELAY);
  340. }
  341. static void LcdCursorLeft(void)
  342. {
  343. LcdWriteCmd(1 << LCD_MOVE, LCD_SHORT_DELAY);
  344. }
  345. static void LcdCursorRight(void)
  346. {
  347. LcdWriteCmd(1 << LCD_MOVE | 1 << LCD_MOVE_RIGHT, LCD_SHORT_DELAY);
  348. }
  349. static void LcdClear(void)
  350. {
  351. LcdWriteCmd(1 << LCD_CLR, LCD_LONG_DELAY);
  352. }
  353. static void LcdCursorMode(uint8_t on)
  354. {
  355. LcdWriteCmd(1 << LCD_ON_CTRL | on ? 1 << LCD_ON_CURSOR : 0x00, LCD_LONG_DELAY);
  356. }
  357. static int LcdInit(NUTDEVICE *dev)
  358. {
  359. /*
  360. * Set LCD register select and enable outputs.
  361. */
  362. sbi(LCD_REGSEL_DDR, LCD_REGSEL_BIT);
  363. sbi(LCD_ENABLE_DDR, LCD_ENABLE_BIT);
  364. #ifdef LCD_RW_BIT
  365. sbi(LCD_RW_DDR, LCD_RW_BIT);
  366. cbi(LCD_RW_PORT, LCD_RW_BIT);
  367. #endif
  368. /*
  369. * Send a dummy data byte.
  370. */
  371. //LcdWriteData(0);
  372. /*
  373. * Initialize for 4-bit operation.
  374. */
  375. cbi(LCD_REGSEL_PORT, LCD_REGSEL_BIT);
  376. #if (LCD_DATA_BITS == 0xFF) // 8 Bit initialisation
  377. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT), 50);
  378. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT), 50);
  379. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT), 50);
  380. #ifdef KS0073_CONTROLLER
  381. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT) | (1 << LCD_FUNCTION_RE), LCD_SHORT_DELAY);
  382. LcdWriteCmd((1 << LCD_EXT) | ((((TERMDCB *) dev->dev_dcb)->dcb_nrows > 2) ? (1 << LCD_EXT_4LINES) : 0), LCD_SHORT_DELAY);
  383. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT), LCD_SHORT_DELAY);
  384. #endif
  385. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT) | ((((TERMDCB *) dev->dev_dcb)->dcb_nrows > 1) ?(1 << LCD_FUNCTION_2LINES):0), LCD_SHORT_DELAY);
  386. #else // 4 Bit initialisation
  387. LcdSendNibble((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT) | (((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT)) >> 4));
  388. LcdDelay(50);
  389. LcdSendNibble((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT) | (((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT)) >> 4));
  390. LcdDelay(50);
  391. LcdSendNibble((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT) | (((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_8BIT)) >> 4));
  392. LcdDelay(50);
  393. LcdSendNibble((1 << LCD_FUNCTION) | ((1 << LCD_FUNCTION) >> 4)); // Enter 4 Bit mode
  394. LcdDelay(50);
  395. #ifdef KS0073_CONTROLLER
  396. LcdWriteCmd((1 << LCD_FUNCTION) | (1 << LCD_FUNCTION_RE), LCD_SHORT_DELAY);
  397. LcdWriteCmd((1 << LCD_EXT) | ((((TERMDCB *) dev->dev_dcb)->dcb_nrows > 2) ? (1 << LCD_EXT_4LINES) : 0), LCD_LONG_DELAY);
  398. LcdWriteCmd((1 << LCD_FUNCTION), LCD_LONG_DELAY);
  399. #endif
  400. LcdWriteCmd((1 << LCD_FUNCTION) | ((((TERMDCB *) dev->dev_dcb)->dcb_nrows > 1) ? (1 << LCD_FUNCTION_2LINES):0), LCD_SHORT_DELAY);
  401. #endif
  402. // clear LCD
  403. LcdWriteCmd(1 << LCD_CLR, LCD_LONG_DELAY);
  404. // set entry mode
  405. LcdWriteCmd(1 << LCD_ENTRY_MODE | 1 << LCD_ENTRY_INC, LCD_LONG_DELAY);
  406. // set display to on
  407. LcdWriteCmd(1 << LCD_ON_CTRL | 1 << LCD_ON_DISPLAY, LCD_LONG_DELAY);
  408. // move cursor to home
  409. LcdWriteCmd(1 << LCD_HOME, LCD_LONG_DELAY);
  410. // set data address to 0
  411. LcdWriteCmd(1 << LCD_DDRAM | 0x00, LCD_LONG_DELAY);
  412. during_init = 0;
  413. return 0;
  414. }
  415. /*!
  416. * \brief Terminal device control block structure.
  417. */
  418. TERMDCB dcb_term = {
  419. LcdInit, /*!< \brief Initialize display subsystem, dss_init. */
  420. LcdWriteData, /*!< \brief Write display character, dss_write. */
  421. LcdWriteCmd, /*!< \brief Write display command, dss_command. */
  422. LcdClear, /*!< \brief Clear display, dss_clear. */
  423. LcdSetCursor, /*!< \brief Set display cursor, dss_set_cursor. */
  424. LcdCursorHome, /*!< \brief Set display cursor home, dss_cursor_home. */
  425. LcdCursorLeft, /*!< \brief Move display cursor left, dss_cursor_left. */
  426. LcdCursorRight, /*!< \brief Move display cursor right, dss_cursor_right. */
  427. LcdCursorMode, /*!< \brief Switch cursor on/off, dss_cursor_mode. */
  428. 0, /*!< \brief Mode flags. */
  429. 0, /*!< \brief Status flags. */
  430. LCD_ROWS, /*!< \brief Number of rows. */
  431. LCD_COLS, /*!< \brief Number of columns per row. */
  432. LCD_COLS, /*!< \brief Number of visible columns. */
  433. 0, /*!< \brief Cursor row. */
  434. 0, /*!< \brief Cursor column. */
  435. 0 /*!< \brief Display shadow memory. */
  436. };
  437. /*!
  438. * \brief LCD device information structure.
  439. */
  440. NUTDEVICE devLcd = {
  441. 0, /*!< Pointer to next device. */
  442. {'l', 'c', 'd', 0, 0, 0, 0, 0, 0}, /*!< Unique device name. */
  443. IFTYP_STREAM, /*!< Type of device. */
  444. 0, /*!< Base address. */
  445. 0, /*!< First interrupt number. */
  446. 0, /*!< Interface control block. */
  447. &dcb_term, /*!< Driver control block. */
  448. TermInit, /*!< Driver initialization routine. */
  449. TermIOCtl, /*!< Driver specific control function. */
  450. 0,
  451. TermWrite,
  452. TermWrite_P,
  453. TermOpen,
  454. TermClose,
  455. 0,
  456. 0, /*!< Select function, optional, not yet implemented */
  457. };
  458. /*@}*/