4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
33 * \brief LM044L type LCD hardware module (impl.)
36 * \author Bernardo Innocenti <bernie@develer.com>
37 * \author Stefano Fedrigo <aleph@develer.com>
42 *#* Revision 1.5 2007/10/01 18:59:27 batt
43 *#* Set to const col_address; add static assert check on array dimension.
45 *#* Revision 1.4 2007/10/01 10:46:09 batt
46 *#* Add light LCD position computation.
48 *#* Revision 1.3 2006/09/20 19:55:01 marco
49 *#* Added CONFIG_LCD_4BIT.
51 *#* Revision 1.2 2006/07/19 12:56:25 bernie
52 *#* Convert to new Doxygen style.
54 *#* Revision 1.1 2005/11/04 18:00:42 bernie
55 *#* Import into DevLib.
57 *#* Revision 1.2 2005/06/14 14:43:43 bernie
58 *#* Add DevLib headers.
60 *#* Revision 1.1 2005/05/24 09:17:58 batt
61 *#* Move drivers to top-level.
63 *#* Revision 1.9 2005/05/09 21:58:53 batt
66 *#* Revision 1.8 2005/05/09 12:52:46 batt
67 *#* lcd_dataRead(): Avoid bus collision; Add back *UNTESTED* 8bit bus support.
69 *#* Revision 1.7 2005/05/09 12:24:13 batt
70 *#* lcd_putc(): Fix latent bug; lcd_hw_init(): Extend timings.
75 #include <cfg/arch_config.h>
76 #include <drv/timer.h>
78 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
79 #define CONFIG_LCD_4BIT 1
80 #elif defined(LCD_READ) && defined(LCD_WRITE)
81 #define CONFIG_LCD_4BIT 0
83 #error Incomplete or missing LCD_READ/LCD_WRITE macros
86 /** Flag di stato del display */
87 #define LCDF_BUSY BV(7)
89 #if CONFIG_LCD_ADDRESS_FAST == 1
90 #define lcd_address(x) lcd_address[x]
92 * Addresses of LCD display character positions, expanded
93 * for faster access (DB7 = 1).
95 static const uint8_t lcd_address[] =
98 0x80, 0x81, 0x82, 0x83,
99 0x84, 0x85, 0x86, 0x87,
100 0x88, 0x89, 0x8A, 0x8B,
101 0x8C, 0x8D, 0x8E, 0x8F,
103 0x90, 0x91, 0x92, 0x93,
107 0xC0, 0xC1, 0xC2, 0xC3,
108 0xC4, 0xC5, 0xC6, 0xC7,
109 0xC8, 0xC9, 0xCA, 0xCB,
110 0xCC, 0xCD, 0xCE, 0xCF,
112 0xD0, 0xD1, 0xD2, 0xD3,
117 0x94, 0x95, 0x96, 0x97,
118 0x98, 0x99, 0x9A, 0x9B,
119 0x9C, 0x9D, 0x9E, 0x9F,
120 0xA0, 0xA1, 0xA2, 0xA3,
122 0xA4, 0xA5, 0xA6, 0xA7,
126 0xD4, 0xD5, 0xD6, 0xD7,
127 0xD8, 0xD9, 0xDA, 0xDB,
128 0xDC, 0xDD, 0xDE, 0xDF,
129 0xE0, 0xE1, 0xE2, 0xE3,
131 0xE4, 0xE5, 0xE6, 0xE7,
134 #endif /* LCD_ROWS > 2 */
137 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
138 #else /* CONFIG_LCD_ADDRESS_FAST == 0 */
140 static const uint8_t col_address[] =
149 STATIC_ASSERT(countof(col_address) == LCD_ROWS);
151 * Addresses of LCD display character positions, calculated runtime to save RAM
153 static uint8_t lcd_address(uint8_t addr)
155 return col_address[addr / LCD_COLS] + addr % LCD_COLS;
157 #endif /* CONFIG_LCD_ADDRESS_FAST */
160 * Current display position. We remember this to optimize
161 * LCD output by avoiding to set the address every time.
163 static lcdpos_t lcd_current_addr;
166 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
167 /* __________________
170 * R/W __________________
174 * DATA -<================
176 INLINE void lcd_dataWrite(uint8_t data)
179 /* Write high nibble */
186 /* Write low nibble */
193 #else /* !CONFIG_LCD_4BIT */
202 #endif /* !CONFIG_LCD_4BIT */
205 /* __________________
214 INLINE uint8_t lcd_dataRead(void)
219 LCD_DB_IN; /* Set bus as input! */
224 /* Read high nibble */
231 /* Read low nibble */
238 #else /* !CONFIG_LCD_4BIT */
247 #endif /* !CONFIG_LCD_4BIT */
250 LCD_DB_OUT; /* Reset bus as output! */
258 * READ __________________
262 * DATA --<===============
264 INLINE void lcd_regWrite(uint8_t data)
280 INLINE uint8_t lcd_regRead(void)
285 data = lcd_dataRead();
292 INLINE void lcd_mode4Bit(void)
296 LCD_WRITE_H(LCD_CMD_SETFUNC);
305 #endif /* CONFIG_LCD_4BIT */
307 #else /* ARCH_EMUL */
309 extern void Emul_LCDWriteReg(uint8_t d);
310 extern uint8_t Emul_LCDReadReg(void);
311 extern void Emul_LCDWriteData(uint8_t d);
312 extern uint8_t Emul_LCDReadData(void);
314 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
315 #define lcd_regRead(d) Emul_LCDReadReg()
316 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
317 #define lcd_dataRead(d) Emul_LCDReadData()
319 #endif /* ARCH_EMUL */
323 * Wait until the LCD busy flag clears.
325 void lcd_waitBusy(void)
329 uint8_t val = lcd_regRead();
330 if (!(val & LCDF_BUSY))
337 * Move the cursor to \a addr, only if not already there.
339 void lcd_moveTo(uint8_t addr)
341 if (addr != lcd_current_addr)
344 lcd_regWrite(lcd_address(addr));
345 lcd_current_addr = addr;
351 * Write a value in LCD data register, waiting for the busy flag.
353 void lcd_setReg(uint8_t val)
359 #include <cfg/debug.h>
361 * Write the character \a c on display address \a addr.
363 * NOTE: argh, the HD44 lcd type is a bad beast: our
364 * move/write -> write optimization requires this mess
365 * because display lines are interleaved!
367 void lcd_putc(uint8_t addr, uint8_t c)
369 if (addr != lcd_current_addr)
370 lcd_setReg(lcd_address(addr));
374 lcd_current_addr = addr + 1;
376 /* If we are at end of display wrap the address to 0 */
377 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
378 lcd_current_addr = 0;
380 /* If we are at the end of a row put the cursor at the beginning of the next */
381 if (!(lcd_current_addr % LCD_COLS))
382 lcd_setReg(lcd_address(lcd_current_addr));
387 * Remap the glyph of a character.
389 * glyph - bitmap of 8x8 bits.
390 * code - must be 0-7 for the Hitachi LCD-II controller.
392 void lcd_remapChar(const char *glyph, char code)
396 /* Set CG RAM address */
397 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
399 /* Write bitmap data */
400 for (i = 0; i < 8; i++)
403 lcd_dataWrite(glyph[i]);
406 /* Move back to original address */
407 lcd_setReg(lcd_address(lcd_current_addr));
412 void lcd_remapfont(void)
414 static const char lcd_glyphs[8] =
416 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
420 for (i = 0; i < 15; i++)
421 lcd_remapChar(i, bernie_char);
424 lcd_setAddr(lcd_DefLayer, 0);
425 for (i = 0; i < 80; i++)
426 lcd_putCharUnlocked(i);
430 void lcd_hw_init(void)
439 #endif /* CONFIG_LCD_4BIT */
441 lcd_regWrite(LCD_CMD_SETFUNC);
444 lcd_regWrite(LCD_CMD_DISPLAY_ON);
447 lcd_regWrite(LCD_CMD_CLEAR);
451 lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
453 lcd_regWrite(LCD_CMD_DISPLAYMODE);
459 void lcd_hw_test(void)
461 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
463 kprintf("3 -> %02X\n", lcd_regRead());
466 for (int i = 0; i < 10; i++)
470 kprintf("addr = %02X\n", lcd_regRead());
474 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
476 kprintf("4A -> %02X\n", lcd_regRead());
479 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
481 kprintf("52 -> %02X\n", lcd_regRead());
484 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
486 kprintf("1F -> %02X\n", lcd_regRead());
490 #endif /* CONFIG_TEST */