Microprocessor and peripheral 2 assignments for AUTH
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

508 lines
13 KiB

  1. /*!
  2. * \file alcd.c
  3. * \brief
  4. * A target independent Alpharithmetic LCD driver
  5. *
  6. * Copyright (C) 2014 Houtouridis Christos (http://www.houtouridis.net)
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as
  10. * published by the Free Software Foundation, either version 3
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "alcd.h"
  23. static int _inc_x (alcd_t *alcd);
  24. static int _dec_x (alcd_t *alcd);
  25. static void _inc_y (alcd_t *alcd);
  26. static void _dec_y (alcd_t *alcd);
  27. static void _set_bus (alcd_t *alcd, int8_t db);
  28. static void _write_data (alcd_t *alcd, int8_t data);
  29. static void _command (alcd_t *alcd, uint8_t c);
  30. static void _character (alcd_t *alcd, uint8_t c);
  31. static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y);
  32. /*!
  33. * \brief
  34. * increase cursor's x position. Positions start from 1.
  35. * If the cursor loops returns 1, else returns 0.
  36. * \param alcd pointer to active alcd.
  37. * \return Change line status
  38. */
  39. static int _inc_x (alcd_t *alcd) {
  40. int ret=0;
  41. if (++alcd->c.x > alcd->columns) {
  42. alcd->c.x = 1;
  43. ret = 1;
  44. }
  45. return ret;
  46. }
  47. /*!
  48. * \brief
  49. * Decrease cursor's x position. Positions start from 1.
  50. * If the cursor loops returns 1, else returns 0.
  51. * \param alcd pointer to active alcd.
  52. * \return none
  53. */
  54. static int _dec_x (alcd_t *alcd) {
  55. int ret = 0;
  56. if (--alcd->c.x < 1) {
  57. alcd->c.x = alcd->columns;
  58. ret = 1;
  59. }
  60. return ret;
  61. }
  62. /*!
  63. * \brief
  64. * increase cursor's y position. Positions start from 1.
  65. * \param alcd pointer to active alcd.
  66. * \return none
  67. */
  68. static void _inc_y (alcd_t *alcd) {
  69. if (++alcd->c.y > alcd->lines) {
  70. alcd->c.y = 1;
  71. }
  72. }
  73. /*!
  74. * \brief
  75. * Decrease cursor's y position. Positions start from 1.
  76. * \param alcd pointer to active alcd.
  77. * \return none
  78. */
  79. static void _dec_y (alcd_t *alcd) {
  80. if (--alcd->c.y < 1) {
  81. alcd->c.y = alcd->lines;
  82. }
  83. }
  84. /*!
  85. * \brief
  86. * Update the bus I/O and send it to the device.
  87. * \param alcd pointer to active alcd.
  88. * \param db the bus data.
  89. * \return none
  90. */
  91. static void _set_bus (alcd_t *alcd, int8_t db)
  92. {
  93. alcd->io.db4 (db & 0x01); //Update port
  94. alcd->io.db5 (db & 0x02);
  95. alcd->io.db6 (db & 0x04);
  96. alcd->io.db7 (db & 0x08);
  97. jf_delay_us (10); // Wait to settle
  98. alcd->io.en (1); // Pulse out the data
  99. jf_delay_us (10);
  100. alcd->io.en (0);
  101. jf_delay_us (10); // Data hold
  102. }
  103. /*!
  104. * \brief
  105. * Write the byte date to the bus using _set_bus ()
  106. * \param alcd pointer to active alcd.
  107. * \param data the data byte.
  108. * \return none
  109. */
  110. static void _write_data (alcd_t *alcd, int8_t data)
  111. {
  112. _set_bus (alcd, data >> 4);
  113. _set_bus (alcd, data & 0x0F);
  114. }
  115. /*!
  116. * \brief
  117. * Send a command to alcd
  118. * \param alcd pointer to active alcd.
  119. * \param c the command byte.
  120. * \return none
  121. */
  122. static void _command (alcd_t *alcd, uint8_t c)
  123. {
  124. alcd->io.rs(0); // Enter command mode
  125. jf_delay_us (100); // Wait
  126. _write_data (alcd, c); // Send
  127. }
  128. /*!
  129. * \brief
  130. * Send a character to alcd
  131. * \param alcd pointer to active alcd.
  132. * \param c the character byte.
  133. * \return none
  134. */
  135. static void _character (alcd_t *alcd, uint8_t c)
  136. {
  137. alcd->io.rs(1); // Enter character mode
  138. jf_delay_us (100); // Wait
  139. _write_data (alcd, c); // Send
  140. }
  141. /*!
  142. * \brief
  143. * Set the Cursor to LCD's position line (y), column (x) starts from 1,2,...n
  144. * \param alcd pointer to active alcd.
  145. * \param x the x position.
  146. * \param y the y position.
  147. * \return none
  148. */
  149. static void _set_cursor (alcd_t *alcd, uint8_t x, uint8_t y)
  150. {
  151. uint8_t cmd;
  152. alcd->c.x = x; // Update alcd data
  153. alcd->c.y = y;
  154. // Calculate address
  155. switch (y) {
  156. default:
  157. case 1: cmd = 0x0; break;
  158. case 2: cmd = 0x40; break;
  159. case 3: cmd = 0x0 + alcd->columns; break;
  160. case 4: cmd = 0x40 + alcd->columns; break;
  161. }
  162. cmd |= (x - 1);
  163. // Calculate command
  164. cmd |= LCD_DDRAMMask;
  165. // Command out the alcd
  166. _command (alcd, cmd);
  167. }
  168. /*
  169. * ============================ Public Functions ============================
  170. */
  171. /*
  172. * Link and Glue functions
  173. */
  174. /*!
  175. * \brief
  176. * Link driver's db4 pin function to io struct.
  177. * \param alcd pointer to active alcd.
  178. * \param pfun driver's DB4 pin function
  179. * \return none
  180. */
  181. inline void alcd_link_db4 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db4 = pfun; }
  182. /*!
  183. * \brief
  184. * Link driver's db4 pin function to io struct.
  185. * \param alcd pointer to active alcd.
  186. * \param pfun driver's DB5 pin function
  187. * \return none
  188. */
  189. inline void alcd_link_db5 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db5 = pfun; }
  190. /*!
  191. * \brief
  192. * Link driver's db4 pin function to io struct.
  193. * \param alcd pointer to active alcd.
  194. * \param pfun driver's DB6 pin function
  195. * \return none
  196. */
  197. inline void alcd_link_db6 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db6 = pfun; }
  198. /*!
  199. * \brief
  200. * Link driver's db4 pin function to io struct.
  201. * \param alcd pointer to active alcd.
  202. * \param pfun driver's DB7 pin function
  203. * \return none
  204. */
  205. inline void alcd_link_db7 (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.db7 = pfun; }
  206. /*!
  207. * \brief
  208. * Link driver's db4 pin function to io struct.
  209. * \param alcd pointer to active alcd.
  210. * \param pfun driver's RS pin function
  211. * \return none
  212. */
  213. inline void alcd_link_rs (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.rs = pfun; }
  214. /*!
  215. * \brief
  216. * Link driver's db4 pin function to io struct.
  217. * \param alcd pointer to active alcd.
  218. * \param pfun driver's EN pin function
  219. * \return none
  220. */
  221. inline void alcd_link_en (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.en = pfun; }
  222. /*!
  223. * \brief
  224. * Link driver's db4 pin function to io struct.
  225. * \param alcd pointer to active alcd.
  226. * \param pfun driver's BL pin function
  227. * \return none
  228. */
  229. inline void alcd_link_bl (alcd_t *alcd, drv_pinout_ft pfun) { alcd->io.bl = pfun; }
  230. /*!
  231. * \brief
  232. * Send an ascii character to alcd.
  233. * \param alcd pointer to active alcd.
  234. * \param ch the character to send
  235. * \return the character send.
  236. *
  237. * \note
  238. * This is the driver's "putchar()" functionality to glue.
  239. * Tailor this function to redirect stdout to alcd.
  240. */
  241. int alcd_putchar (alcd_t *alcd, int ch)
  242. {
  243. alcd->status = DRV_BUSY;
  244. // LCD Character dispatcher
  245. switch (ch) {
  246. case 0:
  247. // don't send null termination to device
  248. break;
  249. case '\n':
  250. _inc_y (alcd);
  251. //break; This "no break" is intentional
  252. case '\r':
  253. _set_cursor (alcd, 1, alcd->c.y);
  254. break;
  255. case '\v':
  256. alcd->c.x = alcd->c.y = 1;
  257. _command (alcd, LCD_RETHOME);
  258. jf_delay_us(2000);
  259. break;
  260. case '\f':
  261. //alcd->c.x = alcd->c.y = 1;
  262. _set_cursor (alcd, 1, 1);
  263. //_command (alcd, LCD_CLRSCR);
  264. //jf_delay_us(5000);
  265. //_command (alcd, LCD_RETHOME);
  266. //_set_cursor (alcd, alcd->c.x, alcd->c.y);
  267. jf_delay_us(2000);
  268. break;
  269. case '\b':
  270. if (_dec_x (alcd)) _dec_y (alcd);
  271. _set_cursor (alcd, alcd->c.x, alcd->c.y);
  272. _character (alcd, ' ');
  273. _set_cursor (alcd, alcd->c.x, alcd->c.y);
  274. break;
  275. default:
  276. _character (alcd, ch);
  277. // Increase cursor and loop inside the same line
  278. if (_inc_x (alcd)) _set_cursor (alcd, alcd->c.x, alcd->c.y);
  279. break;
  280. }
  281. // Restore status
  282. alcd->status = DRV_READY;
  283. //ANSI C (C99) compatible mode
  284. return ch;
  285. }
  286. /*
  287. * Set functions
  288. */
  289. /*!
  290. * \brief
  291. * Set the number of lines for the attached lcd display
  292. * \param alcd pointer to active alcd.
  293. * \param lines The number of lines (usually 2 or 4)
  294. * \return None.
  295. */
  296. void alcd_set_lines (alcd_t *alcd, int lines) {
  297. alcd->lines = lines;
  298. }
  299. /*!
  300. * \brief
  301. * Set the number of columns for the attached lcd display
  302. * \param alcd pointer to active alcd.
  303. * \param lines The number of columns (usually 16 or 20)
  304. * \return None.
  305. */
  306. void alcd_set_columns (alcd_t *alcd, int columns) {
  307. alcd->columns = columns;
  308. }
  309. /*
  310. * User Functions
  311. */
  312. /*!
  313. * \brief
  314. * De-initialize the alcd.
  315. * \param alcd pointer to active alcd.
  316. * \return none
  317. */
  318. void alcd_deinit (alcd_t *alcd)
  319. {
  320. memset ((void*)alcd, 0, sizeof (alcd_t));
  321. /*!<
  322. * This leaves the status DRV_NOINIT
  323. */
  324. }
  325. /*!
  326. * \brief
  327. * Initialize the alcd.
  328. * \param alcd pointer to active alcd.
  329. * \return Zero on success, non zero on error
  330. */
  331. drv_status_en alcd_init (alcd_t *alcd, alcd_funset_en fs)
  332. {
  333. #define _lcd_assert(_x) if (!_x) return alcd->status = DRV_ERROR;
  334. drv_status_en st = jf_probe ();
  335. if (st == DRV_NODEV || st == DRV_BUSY)
  336. return alcd->status = DRV_ERROR;
  337. _lcd_assert (alcd->io.db4);
  338. _lcd_assert (alcd->io.db5);
  339. _lcd_assert (alcd->io.db6);
  340. _lcd_assert (alcd->io.db7);
  341. _lcd_assert (alcd->io.rs);
  342. _lcd_assert (alcd->io.en);
  343. //_lcd_assert (alcd->io.bl);
  344. /*
  345. * We are here, so all its OK. We can (re)initialize alcd.
  346. */
  347. alcd->status = DRV_NOINIT;
  348. alcd->c.x = alcd->c.y = 1;
  349. alcd->io.en (0);
  350. alcd->io.rs (0);
  351. jf_delay_us (100000);
  352. //Pre-Init phase 8bit at this point
  353. _set_bus (alcd, 0x3);
  354. jf_delay_us(50000);
  355. _set_bus (alcd, 0x3);
  356. jf_delay_us(5000);
  357. _set_bus (alcd, 0x3);
  358. jf_delay_us(5000);
  359. _set_bus (alcd, 0x2); //4bit selection
  360. jf_delay_us(10000);
  361. _command (alcd, fs); //4bit selection and Function Set
  362. jf_delay_us(5000);
  363. _command (alcd, LCD_DISP_OFF); //Display Off Control 4bit for now on
  364. jf_delay_us(5000);
  365. _command (alcd, LCD_CLRSCR); //Clear Display
  366. jf_delay_us(5000);
  367. _command (alcd, LCD_ENTRYMODE); //Entry Mode Set
  368. jf_delay_us(5000);
  369. _command (alcd, LCD_RETHOME);
  370. jf_delay_us(10000);
  371. _command (alcd, LCD_DISP_ON);
  372. jf_delay_us(5000);
  373. //alcd_backlight (alcd, 1);
  374. return alcd->status = DRV_READY;
  375. #undef _lcd_assert
  376. }
  377. /*!
  378. * \brief
  379. * Enables and disables the lcd backlight.
  380. * \param alcd pointer to active alcd.
  381. * \param on
  382. * \arg 0 disable the backlight
  383. * \arg 1 enable the backlight
  384. * \return none
  385. */
  386. void alcd_backlight (alcd_t *alcd, uint8_t on) {
  387. if (alcd->io.bl)
  388. alcd->io.bl ((on)?1:0);
  389. }
  390. /*!
  391. * \brief
  392. * Enables and disables the entire lcd (+backlight).
  393. * \param alcd pointer to active alcd.
  394. * \param on
  395. * \arg 0 disable the backlight
  396. * \arg 1 enable the backlight
  397. * \return none
  398. */
  399. void alcd_enable (alcd_t *alcd, uint8_t on)
  400. {
  401. if (on) {
  402. _command (alcd, LCD_DISP_ON);
  403. alcd_backlight (alcd, 1);
  404. } else {
  405. _command (alcd, LCD_DISP_OFF);
  406. alcd_backlight (alcd, 0);
  407. }
  408. }
  409. /*!
  410. * \brief
  411. * Clears screen and returns cursor at home position (1,1).
  412. * \param alcd pointer to active alcd.
  413. * \return none
  414. */
  415. void alcd_cls (alcd_t *alcd)
  416. {
  417. _command(alcd, LCD_CLRSCR);
  418. jf_delay_us(2000);
  419. _command (alcd, LCD_RETHOME);
  420. jf_delay_us(2000);
  421. }
  422. /*!
  423. * \brief
  424. * Shift alcd left or right for a \a pos characters.
  425. * \param alcd pointer to active alcd.
  426. * \param pos The number of position to shift.
  427. * A positive number shifts lcd data to left, so screen shows the data in the right.
  428. * A negative number shifts lcd data to right, so screen shows the data in the left.
  429. * \return none
  430. */
  431. void alcd_shift (alcd_t *alcd, int pos)
  432. {
  433. uint8_t i, cmd = LCD_SHIFT_LEFT;
  434. if (pos<0) {
  435. pos = -pos;
  436. cmd = LCD_SHIFT_RIGHT;
  437. }
  438. for (i=0 ; i<pos ; ++i) {
  439. _command (alcd, cmd);
  440. jf_delay_us(100);
  441. }
  442. }
  443. // Allows us to fill the first 8 CGRAM locations
  444. // with custom characters
  445. void alcd_createChar (alcd_t *alcd, uint8_t location, uint8_t charmap[])
  446. {
  447. location &= 0x7; // we only have 8 locations 0-7
  448. _command (alcd, LCD_SETCGRAMADDR | (location << 3));
  449. for (int i=0; i<8; i++) {
  450. _character (alcd, charmap[i]);
  451. }
  452. }