lcd_hd44.c

Go to the documentation of this file.
00001 
00040 #include "lcd_hd44.h"
00041 #include "hw_lcd.h"
00042 #include <cfg/arch_config.h>
00043 #include <drv/timer.h>
00044 
00045 #if defined(LCD_READ_H) && defined(LCD_READ_L) && defined(LCD_WRITE_H) && defined(LCD_WRITE_L)
00046     #define CONFIG_LCD_4BIT 1
00047 #elif defined(LCD_READ) && defined(LCD_WRITE)
00048     #define CONFIG_LCD_4BIT 0
00049 #else
00050     #error Incomplete or missing LCD_READ/LCD_WRITE macros
00051 #endif
00052 
00054 #define LCDF_BUSY  BV(7)
00055 
00056 #if CONFIG_LCD_ADDRESS_FAST == 1
00057 #define lcd_address(x) lcd_address[x]
00058 
00062 static const uint8_t lcd_address[] =
00063 {
00064     /* row 0 */
00065     0x80, 0x81, 0x82, 0x83,
00066     0x84, 0x85, 0x86, 0x87,
00067     0x88, 0x89, 0x8A, 0x8B,
00068     0x8C, 0x8D, 0x8E, 0x8F,
00069 #if LCD_COLS > 16
00070     0x90, 0x91, 0x92, 0x93,
00071 #endif
00072 
00073     /* row 1 */
00074     0xC0, 0xC1, 0xC2, 0xC3,
00075     0xC4, 0xC5, 0xC6, 0xC7,
00076     0xC8, 0xC9, 0xCA, 0xCB,
00077     0xCC, 0xCD, 0xCE, 0xCF,
00078 #if LCD_COLS > 16
00079     0xD0, 0xD1, 0xD2, 0xD3,
00080 #endif
00081 
00082 #if LCD_ROWS > 2
00083     /* row 2 */
00084     0x94, 0x95, 0x96, 0x97,
00085     0x98, 0x99, 0x9A, 0x9B,
00086     0x9C, 0x9D, 0x9E, 0x9F,
00087     0xA0, 0xA1, 0xA2, 0xA3,
00088 #if LCD_COLS > 16
00089     0xA4, 0xA5, 0xA6, 0xA7,
00090 #endif
00091 
00092     /* row 3 */
00093     0xD4, 0xD5, 0xD6, 0xD7,
00094     0xD8, 0xD9, 0xDA, 0xDB,
00095     0xDC, 0xDD, 0xDE, 0xDF,
00096     0xE0, 0xE1, 0xE2, 0xE3,
00097 #if LCD_COLS > 16
00098     0xE4, 0xE5, 0xE6, 0xE7,
00099 #endif
00100 
00101 #endif /* LCD_ROWS > 2 */
00102 };
00103 
00104 STATIC_ASSERT(countof(lcd_address) == LCD_ROWS * LCD_COLS);
00105 #else  /* CONFIG_LCD_ADDRESS_FAST == 0 */
00106 
00107 static const uint8_t col_address[] =
00108 {
00109     0x80,
00110     0xC0,
00111 #if LCD_ROWS > 2
00112     0x94,
00113     0xD4
00114 #endif
00115 };
00116 STATIC_ASSERT(countof(col_address) == LCD_ROWS);
00120 static uint8_t lcd_address(uint8_t addr)
00121 {
00122     return col_address[addr / LCD_COLS] + addr % LCD_COLS;
00123 }
00124 #endif /* CONFIG_LCD_ADDRESS_FAST */
00125 
00130 static lcdpos_t lcd_current_addr;
00131 
00132 
00133 #if !defined(ARCH_EMUL) || !(ARCH & ARCH_EMUL)
00134 /*      __________________
00135  * RS
00136  *
00137  * R/W  __________________
00138  *            _______
00139  * ENA  _____/       \____
00140  *
00141  * DATA -<================
00142  */
00143 INLINE void lcd_dataWrite(uint8_t data)
00144 {
00145 #if CONFIG_LCD_4BIT
00146     /* Write high nibble */
00147     LCD_WRITE_H(data);
00148     LCD_SET_E;
00149     LCD_DELAY_WRITE;
00150     LCD_CLR_E;
00151     LCD_DELAY_WRITE;
00152 
00153     /* Write low nibble */
00154     LCD_WRITE_L(data);
00155     LCD_SET_E;
00156     LCD_DELAY_WRITE;
00157     LCD_CLR_E;
00158     LCD_DELAY_WRITE;
00159 
00160 #else /* !CONFIG_LCD_4BIT */
00161 
00162     /* Write data */
00163     LCD_WRITE(data);
00164     LCD_SET_E;
00165     LCD_DELAY_WRITE;
00166     LCD_CLR_E;
00167     LCD_DELAY_WRITE;
00168 
00169 #endif /* !CONFIG_LCD_4BIT */
00170 }
00171 
00172 /*      __________________
00173  * RS
00174  *         ____________
00175  * R/W  __/            \__
00176  *            _______
00177  * ENA  _____/       \____
00178  *        ______      ____
00179  * DATA X/      \====/
00180  */
00181 INLINE uint8_t lcd_dataRead(void)
00182 {
00183     uint8_t data;
00184 
00185     LCD_SET_RD;
00186     LCD_DB_IN;  /* Set bus as input! */
00187     LCD_DELAY_READ;
00188 
00189 #if CONFIG_LCD_4BIT
00190 
00191     /* Read high nibble */
00192     LCD_SET_E;
00193     LCD_DELAY_READ;
00194     data = LCD_READ_H;
00195     LCD_CLR_E;
00196     LCD_DELAY_READ;
00197 
00198     /* Read low nibble */
00199     LCD_SET_E;
00200     LCD_DELAY_READ;
00201     data |= LCD_READ_L;
00202     LCD_CLR_E;
00203     LCD_DELAY_READ;
00204 
00205 #else /* !CONFIG_LCD_4BIT */
00206 
00207     /* Read data */
00208     LCD_SET_E;
00209     LCD_DELAY_READ;
00210     data = LCD_READ;
00211     LCD_CLR_E;
00212     LCD_DELAY_READ;
00213 
00214 #endif /* !CONFIG_LCD_4BIT */
00215 
00216     LCD_CLR_RD;
00217     LCD_DB_OUT; /* Reset bus as output! */
00218 
00219     return data;
00220 }
00221 
00222 /*      ___             __
00223  * RS      \___________/
00224  *
00225  * READ __________________
00226  *            _______
00227  * ENA  _____/       \____
00228  *
00229  * DATA --<===============
00230  */
00231 INLINE void lcd_regWrite(uint8_t data)
00232 {
00233     LCD_CLR_RS;
00234     lcd_dataWrite(data);
00235     LCD_SET_RS;
00236 }
00237 
00238 /*      __               _
00239  * RS     \_____________/
00240  *          ___________
00241  * READ ___/           \__
00242  *            _______
00243  * ENA  _____/       \____
00244  *        ______      ____
00245  * DATA X/      \====/
00246  */
00247 INLINE uint8_t lcd_regRead(void)
00248 {
00249     uint8_t data;
00250 
00251     LCD_CLR_RS;
00252     data = lcd_dataRead();
00253     LCD_SET_RS;
00254     return data;
00255 }
00256 
00257 #if CONFIG_LCD_4BIT
00258 
00259 INLINE void lcd_mode4Bit(void)
00260 {
00261     LCD_CLR_RS;
00262 
00263     LCD_WRITE_H(LCD_CMD_SETFUNC);
00264     LCD_SET_E;
00265     LCD_DELAY_WRITE;
00266     LCD_CLR_E;
00267     LCD_DELAY_WRITE;
00268 
00269     LCD_SET_RS;
00270 }
00271 
00272 #endif /* CONFIG_LCD_4BIT */
00273 
00274 #else /* ARCH_EMUL */
00275 
00276 extern void Emul_LCDWriteReg(uint8_t d);
00277 extern uint8_t Emul_LCDReadReg(void);
00278 extern void Emul_LCDWriteData(uint8_t d);
00279 extern uint8_t Emul_LCDReadData(void);
00280 
00281 #define lcd_regWrite(d)   Emul_LCDWriteReg(d)
00282 #define lcd_regRead(d)    Emul_LCDReadReg()
00283 #define lcd_dataWrite(d)  Emul_LCDWriteData(d)
00284 #define lcd_dataRead(d)   Emul_LCDReadData()
00285 
00286 #endif /* ARCH_EMUL */
00287 
00288 
00292 void lcd_waitBusy(void)
00293 {
00294     for (;;)
00295     {
00296         uint8_t val = lcd_regRead();
00297         if (!(val & LCDF_BUSY))
00298             break;
00299     }
00300 }
00301 
00302 
00306 void lcd_moveTo(uint8_t addr)
00307 {
00308     if (addr != lcd_current_addr)
00309     {
00310         lcd_waitBusy();
00311         lcd_regWrite(lcd_address(addr));
00312         lcd_current_addr = addr;
00313     }
00314 }
00315 
00316 
00320 void lcd_setReg(uint8_t val)
00321 {
00322     lcd_waitBusy();
00323     lcd_regWrite(val);
00324 }
00325 
00326 #include <cfg/debug.h>
00334 void lcd_putc(uint8_t addr, uint8_t c)
00335 {
00336     if (addr != lcd_current_addr)
00337         lcd_setReg(lcd_address(addr));
00338 
00339     lcd_waitBusy();
00340     lcd_dataWrite(c);
00341     lcd_current_addr = addr + 1;
00342 
00343     /* If we are at end of display wrap the address to 0 */
00344     if (lcd_current_addr == LCD_COLS * LCD_ROWS)
00345         lcd_current_addr = 0;
00346 
00347     /* If we are at the end of a row put the cursor at the beginning of the next */
00348     if (!(lcd_current_addr % LCD_COLS))
00349         lcd_setReg(lcd_address(lcd_current_addr));
00350 }
00351 
00352 
00359 void lcd_remapChar(const char *glyph, char code)
00360 {
00361     int i;
00362 
00363     /* Set CG RAM address */
00364     lcd_setReg((uint8_t)((1<<6) | (code << 3)));
00365 
00366     /* Write bitmap data */
00367     for (i = 0; i < 8; i++)
00368     {
00369         lcd_waitBusy();
00370         lcd_dataWrite(glyph[i]);
00371     }
00372 
00373     /* Move back to original address */
00374     lcd_setReg(lcd_address(lcd_current_addr));
00375 }
00376 
00377 
00378 #if 0 /* unused */
00379 void lcd_remapfont(void)
00380 {
00381     static const char lcd_glyphs[8] =
00382     {
00383         0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00 /* up arrow */
00384     };
00385     int i;
00386 
00387     for (i = 0; i < 15; i++)
00388         lcd_remapChar(i, bernie_char);
00389 
00390 
00391     lcd_setAddr(lcd_DefLayer, 0);
00392     for (i = 0; i < 80; i++)
00393         lcd_putCharUnlocked(i);
00394 }
00395 #endif /* unused */
00396 
00397 void lcd_hw_init(void)
00398 {
00399     lcd_bus_init();
00400 
00401     timer_delay(50);
00402 
00403 #if CONFIG_LCD_4BIT
00404     lcd_mode4Bit();
00405     timer_delay(2);
00406 #endif /* CONFIG_LCD_4BIT */
00407 
00408     lcd_regWrite(LCD_CMD_SETFUNC);
00409     timer_delay(2);
00410 
00411     lcd_regWrite(LCD_CMD_DISPLAY_ON);
00412     timer_delay(2);
00413 
00414     lcd_regWrite(LCD_CMD_CLEAR);
00415     timer_delay(2);
00416 
00417 #if !CONFIG_LCD_4BIT
00418     lcd_regWrite(LCD_CMD_RESET_DDRAM); // 4 bit mode doesn't allow char reprogramming
00419 #endif
00420     lcd_regWrite(LCD_CMD_DISPLAYMODE);
00421     timer_delay(2);
00422 }
00423 
00424 #if CONFIG_TEST
00425 
00426 void lcd_hw_test(void)
00427 {
00428     lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 3);
00429     timer_delay(1);
00430     kprintf("3 -> %02X\n", lcd_regRead());
00431     timer_delay(1);
00432 
00433     for (int i = 0; i < 10; i++)
00434     {
00435         lcd_dataWrite('c');
00436         timer_delay(1);
00437         kprintf("addr = %02X\n", lcd_regRead());
00438         timer_delay(1);
00439     }
00440 
00441     lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x4a);
00442     timer_delay(1);
00443     kprintf("4A -> %02X\n", lcd_regRead());
00444     timer_delay(1);
00445 
00446     lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x52);
00447     timer_delay(1);
00448     kprintf("52 -> %02X\n", lcd_regRead());
00449     timer_delay(1);
00450 
00451     lcd_regWrite(LCD_CMD_SET_DDRAMADDR | 0x1F);
00452     timer_delay(1);
00453     kprintf("1F -> %02X\n", lcd_regRead());
00454     timer_delay(1);
00455 }
00456 
00457 #endif /* CONFIG_TEST */