4 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
8 * \brief LM044L type LCD hardware module (impl.)
11 * \author Bernardo Innocenti <bernie@develer.com>
12 * \author Stefano Fedrigo <aleph@develer.com>
17 *#* Revision 1.2 2006/07/19 12:56:25 bernie
18 *#* Convert to new Doxygen style.
20 *#* Revision 1.1 2005/11/04 18:00:42 bernie
21 *#* Import into DevLib.
23 *#* Revision 1.2 2005/06/14 14:43:43 bernie
24 *#* Add DevLib headers.
26 *#* Revision 1.1 2005/05/24 09:17:58 batt
27 *#* Move drivers to top-level.
29 *#* Revision 1.9 2005/05/09 21:58:53 batt
32 *#* Revision 1.8 2005/05/09 12:52:46 batt
33 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
35 *#* Revision 1.7 2005/05/09 12:24:13 batt
36 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
40 #include "lcd_bus_pz.h"
41 #include <arch_config.h>
42 #include <drv/timer.h>
44 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
45 #define CONFIG_LCD_4BIT 1
46 #elif defined(LCD_READ) && defined(LCD_WRITE)
47 #define CONFIG_LCD_4BIT 0
49 #error Incomplete or missing LCD_READ/LCD_WRITE macros
52 /** Flag di stato del display */
53 #define LCDF_BUSY BV(7)
56 * Addresses of LCD display character positions, expanded
57 * for faster access (DB7 = 1).
59 static const uint8_t lcd_address[] =
62 0x80, 0x81, 0x82, 0x83,
63 0x84, 0x85, 0x86, 0x87,
64 0x88, 0x89, 0x8A, 0x8B,
65 0x8C, 0x8D, 0x8E, 0x8F,
67 0x90, 0x91, 0x92, 0x93,
71 0xC0, 0xC1, 0xC2, 0xC3,
72 0xC4, 0xC5, 0xC6, 0xC7,
73 0xC8, 0xC9, 0xCA, 0xCB,
74 0xCC, 0xCD, 0xCE, 0xCF,
76 0xD0, 0xD1, 0xD2, 0xD3,
81 0x94, 0x95, 0x96, 0x97,
82 0x98, 0x99, 0x9A, 0x9B,
83 0x9C, 0x9D, 0x9E, 0x9F,
84 0xA0, 0xA1, 0xA2, 0xA3,
86 0xA4, 0xA5, 0xA6, 0xA7,
90 0xD4, 0xD5, 0xD6, 0xD7,
91 0xD8, 0xD9, 0xDA, 0xDB,
92 0xDC, 0xDD, 0xDE, 0xDF,
93 0xE0, 0xE1, 0xE2, 0xE3,
95 0xE4, 0xE5, 0xE6, 0xE7,
98 #endif /* LCD_ROWS > 2 */
101 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
104 * Current display position. We remember this to optimize
105 * LCD output by avoiding to set the address every time.
107 static lcdpos_t lcd_current_addr;
110 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
111 /* __________________
114 * R/W __________________
118 * DATA -<================
120 INLINE void lcd_dataWrite(uint8_t data)
123 /* Write high nibble */
130 /* Write low nibble */
137 #else /* !CONFIG_LCD_4BIT */
146 #endif /* !CONFIG_LCD_4BIT */
149 /* __________________
158 INLINE uint8_t lcd_dataRead(void)
163 LCD_DB_IN; /* Set bus as input! */
168 /* Read high nibble */
175 /* Read low nibble */
182 #else /* !CONFIG_LCD_4BIT */
191 #endif /* !CONFIG_LCD_4BIT */
194 LCD_DB_OUT; /* Reset bus as output! */
202 * READ __________________
206 * DATA --<===============
208 INLINE void lcd_regWrite(uint8_t data)
224 INLINE uint8_t lcd_regRead(void)
229 data = lcd_dataRead();
236 INLINE void lcd_mode4Bit(void)
240 LCD_WRITE_H(LCD_CMD_SETFUNC);
249 #endif /* CONFIG_LCD_4BIT */
251 #else /* ARCH_EMUL */
253 extern void Emul_LCDWriteReg(uint8_t d);
254 extern uint8_t Emul_LCDReadReg(void);
255 extern void Emul_LCDWriteData(uint8_t d);
256 extern uint8_t Emul_LCDReadData(void);
258 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
259 #define lcd_regRead(d) Emul_LCDReadReg()
260 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
261 #define lcd_dataRead(d) Emul_LCDReadData()
263 #endif /* ARCH_EMUL */
267 * Wait until the LCD busy flag clears.
269 void lcd_waitBusy(void)
273 uint8_t val = lcd_regRead();
274 if (!(val & LCDF_BUSY))
281 * Move the cursor to \a addr, only if not already there.
283 void lcd_moveTo(uint8_t addr)
285 if (addr != lcd_current_addr)
288 lcd_regWrite(lcd_address[addr]);
289 lcd_current_addr = addr;
295 * Write a value in LCD data register, waiting for the busy flag.
297 void lcd_setReg(uint8_t val)
303 #include <cfg/debug.h>
305 * Write the character \a c on display address \a addr.
307 * NOTE: argh, the HD44 lcd type is a bad beast: our
308 * move/write -> write optimization requires this mess
309 * because display lines are interleaved!
311 void lcd_putc(uint8_t addr, uint8_t c)
313 if (addr != lcd_current_addr)
314 lcd_setReg(lcd_address[addr]);
318 lcd_current_addr = addr + 1;
320 /* If we are at end of display wrap the address to 0 */
321 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
322 lcd_current_addr = 0;
324 /* If we are at the end of a row put the cursor at the beginning of the next */
325 if (!(lcd_current_addr % LCD_COLS))
326 lcd_setReg(lcd_address[lcd_current_addr]);
331 * Remap the glyph of a character.
333 * glyph - bitmap of 8x8 bits.
334 * code - must be 0-7 for the Hitachi LCD-II controller.
336 void lcd_remapChar(const char *glyph, char code)
340 /* Set CG RAM address */
341 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
343 /* Write bitmap data */
344 for (i = 0; i < 8; i++)
347 lcd_dataWrite(glyph[i]);
350 /* Move back to original address */
351 lcd_setReg(lcd_address[lcd_current_addr]);
356 void lcd_remapfont(void)
358 static const char lcd_glyphs[8] =
360 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
364 for (i = 0; i < 15; i++)
365 lcd_remapChar(i, bernie_char);
368 lcd_setAddr(lcd_DefLayer, 0);
369 for (i = 0; i < 80; i++)
370 lcd_putCharUnlocked(i);
374 void lcd_hw_init(void)
383 #endif /* CONFIG_LCD_4BIT */
385 lcd_regWrite(LCD_CMD_SETFUNC);
388 lcd_regWrite(LCD_CMD_DISPLAY_ON);
391 lcd_regWrite(LCD_CMD_CLEAR);
394 //lcd_regWrite(LCD_CMD_RESET_DDRAM); 4 bit mode doesn't allow char reprogramming
396 lcd_regWrite(LCD_CMD_DISPLAYMODE);
402 void lcd_hw_test(void)
404 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
406 kprintf("3 -> %02X\n", lcd_regRead());
409 for (int i = 0; i < 10; i++)
413 kprintf("addr = %02X\n", lcd_regRead());
417 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
419 kprintf("4A -> %02X\n", lcd_regRead());
422 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
424 kprintf("52 -> %02X\n", lcd_regRead());
427 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
429 kprintf("1F -> %02X\n", lcd_regRead());
433 #endif /* CONFIG_TEST */