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 #include <cfg/arch_config.h>
43 #include <drv/timer.h>
45 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
46 #define CONFIG_LCD_4BIT 1
47 #elif defined(LCD_READ) && defined(LCD_WRITE)
48 #define CONFIG_LCD_4BIT 0
50 #error Incomplete or missing LCD_READ/LCD_WRITE macros
53 /** Flag di stato del display */
54 #define LCDF_BUSY BV(7)
56 #if CONFIG_LCD_ADDRESS_FAST == 1
57 #define lcd_address(x) lcd_address[x]
59 * Addresses of LCD display character positions, expanded
60 * for faster access (DB7 = 1).
62 static const uint8_t lcd_address[] =
65 0x80, 0x81, 0x82, 0x83,
66 0x84, 0x85, 0x86, 0x87,
67 0x88, 0x89, 0x8A, 0x8B,
68 0x8C, 0x8D, 0x8E, 0x8F,
70 0x90, 0x91, 0x92, 0x93,
74 0xC0, 0xC1, 0xC2, 0xC3,
75 0xC4, 0xC5, 0xC6, 0xC7,
76 0xC8, 0xC9, 0xCA, 0xCB,
77 0xCC, 0xCD, 0xCE, 0xCF,
79 0xD0, 0xD1, 0xD2, 0xD3,
84 0x94, 0x95, 0x96, 0x97,
85 0x98, 0x99, 0x9A, 0x9B,
86 0x9C, 0x9D, 0x9E, 0x9F,
87 0xA0, 0xA1, 0xA2, 0xA3,
89 0xA4, 0xA5, 0xA6, 0xA7,
93 0xD4, 0xD5, 0xD6, 0xD7,
94 0xD8, 0xD9, 0xDA, 0xDB,
95 0xDC, 0xDD, 0xDE, 0xDF,
96 0xE0, 0xE1, 0xE2, 0xE3,
98 0xE4, 0xE5, 0xE6, 0xE7,
101 #endif /* LCD_ROWS > 2 */
104 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
105 #else /* CONFIG_LCD_ADDRESS_FAST == 0 */
107 static const uint8_t col_address[] =
116 STATIC_ASSERT(countof(col_address) == LCD_ROWS);
118 * Addresses of LCD display character positions, calculated runtime to save RAM
120 static uint8_t lcd_address(uint8_t addr)
122 return col_address[addr / LCD_COLS] + addr % LCD_COLS;
124 #endif /* CONFIG_LCD_ADDRESS_FAST */
127 * Current display position. We remember this to optimize
128 * LCD output by avoiding to set the address every time.
130 static lcdpos_t lcd_current_addr;
133 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
134 /* __________________
137 * R/W __________________
141 * DATA -<================
143 INLINE void lcd_dataWrite(uint8_t data)
146 /* Write high nibble */
153 /* Write low nibble */
160 #else /* !CONFIG_LCD_4BIT */
169 #endif /* !CONFIG_LCD_4BIT */
172 /* __________________
181 INLINE uint8_t lcd_dataRead(void)
186 LCD_DB_IN; /* Set bus as input! */
191 /* Read high nibble */
198 /* Read low nibble */
205 #else /* !CONFIG_LCD_4BIT */
214 #endif /* !CONFIG_LCD_4BIT */
217 LCD_DB_OUT; /* Reset bus as output! */
225 * READ __________________
229 * DATA --<===============
231 INLINE void lcd_regWrite(uint8_t data)
247 INLINE uint8_t lcd_regRead(void)
252 data = lcd_dataRead();
259 INLINE void lcd_mode4Bit(void)
263 LCD_WRITE_H(LCD_CMD_SETFUNC);
272 #endif /* CONFIG_LCD_4BIT */
274 #else /* ARCH_EMUL */
276 extern void Emul_LCDWriteReg(uint8_t d);
277 extern uint8_t Emul_LCDReadReg(void);
278 extern void Emul_LCDWriteData(uint8_t d);
279 extern uint8_t Emul_LCDReadData(void);
281 #define lcd_regWrite(d) Emul_LCDWriteReg(d)
282 #define lcd_regRead(d) Emul_LCDReadReg()
283 #define lcd_dataWrite(d) Emul_LCDWriteData(d)
284 #define lcd_dataRead(d) Emul_LCDReadData()
286 #endif /* ARCH_EMUL */
290 * Wait until the LCD busy flag clears.
292 void lcd_waitBusy(void)
296 uint8_t val = lcd_regRead();
297 if (!(val & LCDF_BUSY))
304 * Move the cursor to \a addr, only if not already there.
306 void lcd_moveTo(uint8_t addr)
308 if (addr != lcd_current_addr)
311 lcd_regWrite(lcd_address(addr));
312 lcd_current_addr = addr;
318 * Write a value in LCD data register, waiting for the busy flag.
320 void lcd_setReg(uint8_t val)
326 #include <cfg/debug.h>
328 * Write the character \a c on display address \a addr.
330 * NOTE: argh, the HD44 lcd type is a bad beast: our
331 * move/write -> write optimization requires this mess
332 * because display lines are interleaved!
334 void lcd_putc(uint8_t addr, uint8_t c)
336 if (addr != lcd_current_addr)
337 lcd_setReg(lcd_address(addr));
341 lcd_current_addr = addr + 1;
343 /* If we are at end of display wrap the address to 0 */
344 if (lcd_current_addr == LCD_COLS * LCD_ROWS)
345 lcd_current_addr = 0;
347 /* If we are at the end of a row put the cursor at the beginning of the next */
348 if (!(lcd_current_addr % LCD_COLS))
349 lcd_setReg(lcd_address(lcd_current_addr));
354 * Remap the glyph of a character.
356 * glyph - bitmap of 8x8 bits.
357 * code - must be 0-7 for the Hitachi LCD-II controller.
359 void lcd_remapChar(const char *glyph, char code)
363 /* Set CG RAM address */
364 lcd_setReg((uint8_t)((1<<6) | (code << 3)));
366 /* Write bitmap data */
367 for (i = 0; i < 8; i++)
370 lcd_dataWrite(glyph[i]);
373 /* Move back to original address */
374 lcd_setReg(lcd_address(lcd_current_addr));
379 void lcd_remapfont(void)
381 static const char lcd_glyphs[8] =
383 0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
387 for (i = 0; i < 15; i++)
388 lcd_remapChar(i, bernie_char);
391 lcd_setAddr(lcd_DefLayer, 0);
392 for (i = 0; i < 80; i++)
393 lcd_putCharUnlocked(i);
397 void lcd_hw_init(void)
406 #endif /* CONFIG_LCD_4BIT */
408 lcd_regWrite(LCD_CMD_SETFUNC);
411 lcd_regWrite(LCD_CMD_DISPLAY_ON);
414 lcd_regWrite(LCD_CMD_CLEAR);
418 lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
420 lcd_regWrite(LCD_CMD_DISPLAYMODE);
426 void lcd_hw_test(void)
428 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
430 kprintf("3 -> %02X\n", lcd_regRead());
433 for (int i = 0; i < 10; i++)
437 kprintf("addr = %02X\n", lcd_regRead());
441 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
443 kprintf("4A -> %02X\n", lcd_regRead());
446 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
448 kprintf("52 -> %02X\n", lcd_regRead());
451 lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
453 kprintf("1F -> %02X\n", lcd_regRead());
457 #endif /* CONFIG_TEST */