st7036_at91.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /*
  2. * Copyright (C) 2007 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. * $Log$
  35. * Revision 1.6 2009/01/17 11:26:37 haraldkipp
  36. * Getting rid of two remaining BSD types in favor of stdint.
  37. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  38. *
  39. * Revision 1.5 2008/08/11 06:59:13 haraldkipp
  40. * BSD types replaced by stdint types (feature request #1282721).
  41. *
  42. * Revision 1.4 2008/06/06 10:28:21 haraldkipp
  43. * ST7036 LCD controller settings moved from source to configuration files.
  44. *
  45. * Revision 1.3 2008/02/15 16:59:02 haraldkipp
  46. * Spport for AT91SAM7SE512 added.
  47. *
  48. * Revision 1.2 2007/10/04 20:01:50 olereinhardt
  49. * Support for SAM7S256 added
  50. *
  51. * Revision 1.1 2007/02/15 16:09:07 haraldkipp
  52. * Tested with EA DOG-M LCDs.
  53. *
  54. */
  55. #include <cfg/arch.h>
  56. #include <cfg/arch/gpio.h>
  57. #include <cfg/lcd.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <sys/nutconfig.h>
  61. #include <dev/st7036.h>
  62. #include <dev/term.h>
  63. #include <sys/timer.h>
  64. #ifdef LCD_CLK_BIT
  65. #define LCD_CLK _BV(LCD_CLK_BIT)
  66. #if LCD_CLK_PIO_ID == PIOA_ID
  67. #define LCD_CLK_SET() { outr(PIOA_PER, LCD_CLK); outr(PIOA_SODR, LCD_CLK); outr(PIOA_OER, LCD_CLK); }
  68. #define LCD_CLK_CLR() { outr(PIOA_PER, LCD_CLK); outr(PIOA_CODR, LCD_CLK); outr(PIOA_OER, LCD_CLK); }
  69. #elif LCD_CLK_PIO_ID == PIOB_ID
  70. #define LCD_CLK_SET() { outr(PIOB_PER, LCD_CLK); outr(PIOB_SODR, LCD_CLK); outr(PIOB_OER, LCD_CLK); }
  71. #define LCD_CLK_CLR() { outr(PIOB_PER, LCD_CLK); outr(PIOB_CODR, LCD_CLK); outr(PIOB_OER, LCD_CLK); }
  72. #elif LCD_CLK_PIO_ID == PIOC_ID
  73. #define LCD_CLK_SET() { outr(PIOC_PER, LCD_CLK); outr(PIOC_SODR, LCD_CLK); outr(PIOC_OER, LCD_CLK); }
  74. #define LCD_CLK_CLR() { outr(PIOC_PER, LCD_CLK); outr(PIOC_CODR, LCD_CLK); outr(PIOC_OER, LCD_CLK); }
  75. #else
  76. #define LCD_CLK_SET() { outr(PIO_PER, LCD_CLK); outr(PIO_SODR, LCD_CLK); outr(PIO_OER, LCD_CLK); }
  77. #define LCD_CLK_CLR() { outr(PIO_PER, LCD_CLK); outr(PIO_CODR, LCD_CLK); outr(PIO_OER, LCD_CLK); }
  78. #endif /* LCD_CLK_PIO_ID */
  79. #else /* LCD_CLK_BIT */
  80. #define LCD_CLK_SET()
  81. #define LCD_CLK_CLR()
  82. #endif /* LCD_CLK_BIT */
  83. #ifdef LCD_MOSI_BIT
  84. #define LCD_MOSI _BV(LCD_MOSI_BIT)
  85. #if LCD_MOSI_PIO_ID == PIOA_ID
  86. #define LCD_MOSI_SET() { outr(PIOA_PER, LCD_MOSI); outr(PIOA_SODR, LCD_MOSI); outr(PIOA_OER, LCD_MOSI); }
  87. #define LCD_MOSI_CLR() { outr(PIOA_PER, LCD_MOSI); outr(PIOA_CODR, LCD_MOSI); outr(PIOA_OER, LCD_MOSI); }
  88. #elif LCD_MOSI_PIO_ID == PIOB_ID
  89. #define LCD_MOSI_SET() { outr(PIOB_PER, LCD_MOSI); outr(PIOB_SODR, LCD_MOSI); outr(PIOB_OER, LCD_MOSI); }
  90. #define LCD_MOSI_CLR() { outr(PIOB_PER, LCD_MOSI); outr(PIOB_CODR, LCD_MOSI); outr(PIOB_OER, LCD_MOSI); }
  91. #elif LCD_MOSI_PIO_ID == PIOC_ID
  92. #define LCD_MOSI_SET() { outr(PIOC_PER, LCD_MOSI); outr(PIOC_SODR, LCD_MOSI); outr(PIOC_OER, LCD_MOSI); }
  93. #define LCD_MOSI_CLR() { outr(PIOC_PER, LCD_MOSI); outr(PIOC_CODR, LCD_MOSI); outr(PIOC_OER, LCD_MOSI); }
  94. #else
  95. #define LCD_MOSI_SET() { outr(PIO_PER, LCD_MOSI); outr(PIO_SODR, LCD_MOSI); outr(PIO_OER, LCD_MOSI); }
  96. #define LCD_MOSI_CLR() { outr(PIO_PER, LCD_MOSI); outr(PIO_CODR, LCD_MOSI); outr(PIO_OER, LCD_MOSI); }
  97. #endif /* LCD_MOSI_PIO_ID */
  98. #else /* LCD_MOSI_BIT */
  99. #define LCD_MOSI_SET()
  100. #define LCD_MOSI_CLR()
  101. #endif /* LCD_MOSI_BIT */
  102. /*!
  103. * \addtogroup xgST7036
  104. */
  105. /*@{*/
  106. #ifndef LCD_SHORT_DELAY
  107. #define LCD_SHORT_DELAY 100
  108. #endif
  109. #ifndef LCD_LONG_DELAY
  110. #define LCD_LONG_DELAY 1000
  111. #endif
  112. /*!
  113. * \brief Wait until controller will be ready again
  114. *
  115. * If LCD_WR_BIT is defined we will wait until the ready bit is set, otherwise
  116. * We will either busy loop with NutDelay or sleep with NutSleep. The second
  117. * option will be used if we have defined NUT_CPU_FREQ. In this case we have a higher
  118. * timer resolution.
  119. *
  120. * \param xt Delay time in milliseconds
  121. */
  122. static void LcdDelay(unsigned int cycles)
  123. {
  124. while (cycles--) {
  125. _NOP(); _NOP(); _NOP(); _NOP();
  126. _NOP(); _NOP(); _NOP(); _NOP();
  127. _NOP(); _NOP(); _NOP(); _NOP();
  128. _NOP(); _NOP(); _NOP(); _NOP();
  129. _NOP(); _NOP(); _NOP(); _NOP();
  130. _NOP(); _NOP(); _NOP(); _NOP();
  131. _NOP(); _NOP(); _NOP(); _NOP();
  132. _NOP(); _NOP(); _NOP(); _NOP();
  133. _NOP(); _NOP(); _NOP(); _NOP();
  134. _NOP(); _NOP(); _NOP(); _NOP();
  135. _NOP(); _NOP(); _NOP(); _NOP();
  136. _NOP(); _NOP(); _NOP(); _NOP();
  137. }
  138. }
  139. #if 0
  140. static void INLINE LcdSetBits(unsigned int mask)
  141. {
  142. outr(LCD_PIO_SOD_REG, mask);
  143. outr(LCD_PIO_OE_REG, mask);
  144. }
  145. static void INLINE LcdClrBits(unsigned int mask)
  146. {
  147. outr(LCD_PIO_COD_REG, mask);
  148. outr(LCD_PIO_OE_REG, mask);
  149. }
  150. #endif
  151. static void LcdWaitReady(unsigned int delay)
  152. {
  153. while (delay--) {
  154. _NOP();
  155. }
  156. }
  157. /*!
  158. * \brief Send byte to LCD controller.
  159. *
  160. * \param data Byte to send.
  161. */
  162. static void LcdWriteByte(unsigned int data)
  163. {
  164. uint8_t msk = 0x80;
  165. while (msk) {
  166. LCD_CLK_CLR();
  167. if (data & msk) {
  168. LCD_MOSI_SET();
  169. } else {
  170. LCD_MOSI_CLR();
  171. }
  172. LCD_CLK_SET();
  173. msk >>= 1;
  174. LcdDelay(1);
  175. }
  176. LcdWaitReady(LCD_LONG_DELAY);
  177. }
  178. /*!
  179. * \brief Send command byte to LCD controller.
  180. *
  181. * \param cmd Byte to send.
  182. */
  183. static void LcdWriteCmd(uint8_t cmd)
  184. {
  185. /* RS low selects instruction register. */
  186. LCD_EN_CLR();
  187. LcdDelay(LCD_SHORT_DELAY);
  188. LCD_RS_CLR();
  189. LcdDelay(LCD_SHORT_DELAY);
  190. LcdWriteByte(cmd);
  191. LcdDelay(LCD_SHORT_DELAY);
  192. LCD_RS_SET();
  193. LcdDelay(LCD_SHORT_DELAY);
  194. LCD_EN_SET();
  195. LcdDelay(LCD_SHORT_DELAY);
  196. }
  197. static void LcdWriteInstruction(uint8_t cmd, uint8_t xt)
  198. {
  199. LcdWriteCmd(cmd);
  200. }
  201. /*!
  202. * \brief Send data byte to LCD controller.
  203. *
  204. * \param data Byte to send.
  205. */
  206. static void LcdWriteData(uint8_t data)
  207. {
  208. /* RS high selects data register. */
  209. LCD_EN_CLR();
  210. LcdDelay(LCD_SHORT_DELAY);
  211. LCD_RS_SET();
  212. LcdDelay(LCD_SHORT_DELAY);
  213. LcdWriteByte(data);
  214. LcdDelay(LCD_SHORT_DELAY);
  215. LCD_EN_SET();
  216. LcdDelay(LCD_SHORT_DELAY);
  217. }
  218. static void LcdSetCursor(uint8_t pos)
  219. {
  220. uint8_t offset[] = {
  221. 0x00, 0x40, 0x10, 0x50
  222. };
  223. pos = offset[(pos / LCD_COLS) % LCD_ROWS] + pos % LCD_COLS;
  224. LcdWriteCmd(0x80 | pos);
  225. }
  226. static void LcdCursorHome(void)
  227. {
  228. LcdWriteCmd(0x02);
  229. LcdDelay(10 * LCD_LONG_DELAY);
  230. }
  231. static void LcdCursorLeft(void)
  232. {
  233. LcdWriteCmd(0x10);
  234. }
  235. static void LcdCursorRight(void)
  236. {
  237. LcdWriteCmd(0x14);
  238. }
  239. static void LcdClear(void)
  240. {
  241. LcdWriteCmd(0x01);
  242. LcdDelay(10 * LCD_LONG_DELAY);
  243. }
  244. static void LcdCursorMode(uint8_t on)
  245. {
  246. if (on) {
  247. LcdWriteCmd(0x0D);
  248. } else {
  249. LcdWriteCmd(0x0C);
  250. }
  251. LcdDelay(10 * LCD_LONG_DELAY);
  252. }
  253. static int LcdInit(NUTDEVICE * dev)
  254. {
  255. #if defined(PMC_PCER)
  256. unsigned int pcer = 0;
  257. #if defined(LCD_EN_PIO_ID)
  258. pcer = _BV(LCD_EN_PIO_ID);
  259. #endif
  260. #if defined(LCD_RS_PIO_ID)
  261. pcer |= _BV(LCD_RS_PIO_ID);
  262. #endif
  263. #if defined(LCD_CLK_PIO_ID)
  264. pcer |= _BV(LCD_CLK_PIO_ID);
  265. #endif
  266. #if defined(LCD_MOSI_PIO_ID)
  267. pcer |= _BV(LCD_MOSI_PIO_ID);
  268. #endif
  269. outr(PMC_PCER, pcer);
  270. #endif
  271. /* Initialize GPIO lines. */
  272. LCD_EN_SET();
  273. LCD_RS_SET();
  274. LCD_CLK_SET();
  275. LCD_MOSI_SET();
  276. /* Initial delay. Actually only required after power on. */
  277. NutSleep(50);
  278. LCD_RS_CLR();
  279. LCD_EN_CLR();
  280. LcdWriteCmd(0x38); /* Function set. */
  281. NutSleep(2);
  282. LcdWriteCmd(0x39); /* Function set. */
  283. NutSleep(2);
  284. LcdWriteCmd(0x14); /* Bias 1/5, 2 lines. */
  285. NutSleep(1);
  286. LcdWriteCmd(0x55); /* Power/ICON/Contrast control. */
  287. NutSleep(1);
  288. LcdWriteCmd(0x6D); /* Follower control. */
  289. NutSleep(1);
  290. LcdWriteCmd(0x78); /* Booster on, Contrast set. */
  291. NutSleep(1);
  292. LcdWriteCmd(0x0F); /* Display on. */
  293. NutSleep(1);
  294. LcdWriteCmd(0x01); /* Clear display. */
  295. NutSleep(1);
  296. LcdWriteCmd(0x06); /* Entry mode set. */
  297. NutSleep(1);
  298. LCD_EN_SET();
  299. LCD_RS_SET();
  300. /* Clear display. */
  301. LcdClear();
  302. /* Move cursor home. */
  303. LcdCursorHome();
  304. return 0;
  305. }
  306. /*!
  307. * \brief Terminal device control block structure.
  308. */
  309. static TERMDCB dcb_term = {
  310. LcdInit, /*!< \brief Initialize display subsystem, dss_init. */
  311. LcdWriteData, /*!< \brief Write display character, dss_write. */
  312. LcdWriteInstruction, /*!< \brief Write display command, dss_command. */
  313. LcdClear, /*!< \brief Clear display, dss_clear. */
  314. LcdSetCursor, /*!< \brief Set display cursor, dss_set_cursor. */
  315. LcdCursorHome, /*!< \brief Set display cursor home, dss_cursor_home. */
  316. LcdCursorLeft, /*!< \brief Move display cursor left, dss_cursor_left. */
  317. LcdCursorRight, /*!< \brief Move display cursor right, dss_cursor_right. */
  318. LcdCursorMode, /*!< \brief Switch cursor on/off, dss_cursor_mode. */
  319. 0, /*!< \brief Mode flags. */
  320. 0, /*!< \brief Status flags. */
  321. LCD_ROWS, /*!< \brief Number of rows. */
  322. LCD_COLS, /*!< \brief Number of columns per row. */
  323. LCD_COLS, /*!< \brief Number of visible columns. */
  324. 0, /*!< \brief Cursor row. */
  325. 0, /*!< \brief Cursor column. */
  326. 0 /*!< \brief Display shadow memory. */
  327. };
  328. /*!
  329. * \brief LCD device information structure.
  330. */
  331. NUTDEVICE devSbiLcd = {
  332. 0, /*!< Pointer to next device. */
  333. {'s', 'b', 'i', 'l', 'c', 'd', 0, 0, 0}, /*!< Unique device name. */
  334. IFTYP_STREAM, /*!< Type of device. */
  335. 0, /*!< Base address. */
  336. 0, /*!< First interrupt number. */
  337. 0, /*!< Interface control block. */
  338. &dcb_term, /*!< Driver control block. */
  339. TermInit, /*!< Driver initialization routine. */
  340. TermIOCtl, /*!< Driver specific control function. */
  341. 0,
  342. TermWrite,
  343. TermOpen,
  344. TermClose,
  345. 0,
  346. 0, /*!< Select function, optional, not yet implemented */
  347. };
  348. /*@}*/