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.1 2005/11/04 18:00:42 bernie
18 *#* Import into DevLib.
20 *#* Revision 1.2 2005/06/14 14:43:43 bernie
21 *#* Add DevLib headers.
23 *#* Revision 1.1 2005/05/24 09:17:58 batt
24 *#* Move drivers to top-level.
26 *#* Revision 1.9 2005/05/09 21:58:53 batt
29 *#* Revision 1.8 2005/05/09 12:52:46 batt
30 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
32 *#* Revision 1.7 2005/05/09 12:24:13 batt
33 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
37 #include "lcd_bus_pz.h"
38 #include <arch_config.h>
39 #include <drv/timer.h>
41 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
42 #define CONFIG_LCD_4BIT 1
43 #elif defined(LCD_READ) && defined(LCD_WRITE)
44 #define CONFIG_LCD_4BIT 0
46 #error Incomplete or missing LCD_READ/LCD_WRITE macros
49 /*! Flag di stato del display */
50 #define LCDF_BUSY BV(7)
53 * Addresses of LCD display character positions, expanded
54 * for faster access (DB7 = 1).
56 static const uint8_t lcd_address[] =
59 0x80, 0x81, 0x82, 0x83,
60 0x84, 0x85, 0x86, 0x87,
61 0x88, 0x89, 0x8A, 0x8B,
62 0x8C, 0x8D, 0x8E, 0x8F,
64 0x90, 0x91, 0x92, 0x93,
68 0xC0, 0xC1, 0xC2, 0xC3,
69 0xC4, 0xC5, 0xC6, 0xC7,
70 0xC8, 0xC9, 0xCA, 0xCB,
71 0xCC, 0xCD, 0xCE, 0xCF,
73 0xD0, 0xD1, 0xD2, 0xD3,
78 0x94, 0x95, 0x96, 0x97,
79 0x98, 0x99, 0x9A, 0x9B,
80 0x9C, 0x9D, 0x9E, 0x9F,
81 0xA0, 0xA1, 0xA2, 0xA3,
83 0xA4, 0xA5, 0xA6, 0xA7,
87 0xD4, 0xD5, 0xD6, 0xD7,
88 0xD8, 0xD9, 0xDA, 0xDB,
89 0xDC, 0xDD, 0xDE, 0xDF,
90 0xE0, 0xE1, 0xE2, 0xE3,
92 0xE4, 0xE5, 0xE6, 0xE7,
95 #endif /* LCD_ROWS > 2 */
98 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
101 * Current display position. We remember this to optimize
102 * LCD output by avoiding to set the address every time.
104 static lcdpos_t lcd_current_addr;
107 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
108 /* __________________
111 * R/W __________________
115 * DATA -<================
117 INLINE void lcd_dataWrite(uint8_t data)
120 /* Write high nibble */
127 /* Write low nibble */
134 #else /* !CONFIG_LCD_4BIT */
143 #endif /* !CONFIG_LCD_4BIT */
146 /* __________________
155 INLINE uint8_t lcd_dataRead(void)
160 LCD_DB_IN; /* Set bus as input! */
165 /* Read high nibble */
172 /* Read low nibble */
179 #else /* !CONFIG_LCD_4BIT */
188 #endif /* !CONFIG_LCD_4BIT */
191 LCD_DB_OUT; /* Reset bus as output! */
199 * READ __________________
203 * DATA --<===============
205 INLINE void lcd_regWrite(uint8_t data)
221 INLINE uint8_t lcd_regRead(void)
226 data = lcd_dataRead();
233 INLINE void lcd_mode4Bit(void)
237 LCD_WRITE_H(LCD_CMD_SETFUNC);
246 #endif /* CONFIG_LCD_4BIT */
248 #else /* ARCH_EMUL */
250 extern void Emul_LCDWriteReg(uint8_t d);
251 extern uint8_t Emul_LCDReadReg(void);
252 extern void Emul_LCDWriteData(uint8_t d);
253 extern uint8_t Emul_LCDReadData(void);
255 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
256 #define lcd_regRead(d) Emul_LCDReadReg()
257 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
258 #define lcd_dataRead(d) Emul_LCDReadData()
260 #endif /* ARCH_EMUL */
264 * Wait until the LCD busy flag clears.
266 void lcd_waitBusy(void)
270 uint8_t val = lcd_regRead();
271 if (!(val & LCDF_BUSY))
278 * Move the cursor to \a addr, only if not already there.
280 void lcd_moveTo(uint8_t addr)
282 if (addr != lcd_current_addr)
285 lcd_regWrite(lcd_address[addr]);
286 lcd_current_addr = addr;
292 * Write a value in LCD data register, waiting for the busy flag.
294 void lcd_setReg(uint8_t val)
300 #include <cfg/debug.h>
302 * Write the character \a c on display address \a addr.
304 * NOTE: argh, the HD44 lcd type is a bad beast: our
305 * move/write -> write optimization requires this mess
306 * because display lines are interleaved!
308 void lcd_putc(uint8_t addr, uint8_t c)
310 if (addr != lcd_current_addr)
311 lcd_setReg(lcd_address[addr]);
315 lcd_current_addr = addr + 1;
317 /* If we are at end of display wrap the address to 0 */
318 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
319 lcd_current_addr = 0;
321 /* If we are at the end of a row put the cursor at the beginning of the next */
322 if (!(lcd_current_addr % LCD_COLS))
323 lcd_setReg(lcd_address[lcd_current_addr]);
328 * Remap the glyph of a character.
330 * glyph - bitmap of 8x8 bits.
331 * code - must be 0-7 for the Hitachi LCD-II controller.
333 void lcd_remapChar(const char *glyph, char code)
337 /* Set CG RAM address */
338 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
340 /* Write bitmap data */
341 for (i = 0; i < 8; i++)
344 lcd_dataWrite(glyph[i]);
347 /* Move back to original address */
348 lcd_setReg(lcd_address[lcd_current_addr]);
353 void lcd_remapfont(void)
355 static const char lcd_glyphs[8] =
357 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
361 for (i = 0; i < 15; i++)
362 lcd_remapChar(i, bernie_char);
365 lcd_setAddr(lcd_DefLayer, 0);
366 for (i = 0; i < 80; i++)
367 lcd_putCharUnlocked(i);
371 void lcd_hw_init(void)
380 #endif /* CONFIG_LCD_4BIT */
382 lcd_regWrite(LCD_CMD_SETFUNC);
385 lcd_regWrite(LCD_CMD_DISPLAY_ON);
388 lcd_regWrite(LCD_CMD_CLEAR);
391 //lcd_regWrite(LCD_CMD_RESET_DDRAM); 4 bit mode doesn't allow char reprogramming
393 lcd_regWrite(LCD_CMD_DISPLAYMODE);
399 void lcd_hw_test(void)
401 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
403 kprintf("3 -> %02X\n", lcd_regRead());
406 for (int i = 0; i < 10; i++)
410 kprintf("addr = %02X\n", lcd_regRead());
414 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
416 kprintf("4A -> %02X\n", lcd_regRead());
419 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
421 kprintf("52 -> %02X\n", lcd_regRead());
424 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
426 kprintf("1F -> %02X\n", lcd_regRead());
430 #endif /* CONFIG_TEST */