hd44780_at91.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log: hd44780_at91.c,v $
00036  * Revision 1.11  2008/08/11 06:59:09  haraldkipp
00037  * BSD types replaced by stdint types (feature request #1282721).
00038  *
00039  * Revision 1.10  2008/08/06 12:51:00  haraldkipp
00040  * Added support for Ethernut 5 (AT91SAM9XE reference design).
00041  *
00042  * Revision 1.9  2008/02/15 16:58:41  haraldkipp
00043  * Spport for AT91SAM7SE512 added.
00044  *
00045  * Revision 1.8  2007/10/04 19:57:54  olereinhardt
00046  * Support for SAM7S256 added
00047  *
00048  * Revision 1.7  2007/02/15 16:05:29  haraldkipp
00049  * Port usage is now configurable. Data bits no longer need four consecutive
00050  * port bits. Added delays in read for better reliability with some slow
00051  * displays.
00052  *
00053  * Revision 1.6  2006/10/05 17:11:16  haraldkipp
00054  * Fixes bug #1567813. Should now work after power on and after reset without
00055  * power loss. Many thanks to Klaus-Dieter Sohn.
00056  *
00057  * Revision 1.5  2006/08/31 19:02:25  haraldkipp
00058  * Added support for AT91SAM9260.
00059  * Some displays fail after reset. An additional nibble sent
00060  * during 4-bit initialization seems to fix this. However,
00061  * a user reported that his 3.3V driven LCD now fails during
00062  * power on.
00063  *
00064  * Revision 1.4  2006/07/15 11:15:31  haraldkipp
00065  * Initialization flag removed. It is not required because the driver doesn't
00066  * poll the busy flag during initialization.
00067  * Bug fixed, which let the driver fail to properly initialize displays with
00068  * two lines.
00069  *
00070  * Revision 1.3  2006/06/28 17:23:19  haraldkipp
00071  * Significantly extend delay time to allow running slow 3.3V LCDs with fast
00072  * CPUs. Not a nice fix, but it works.
00073  *
00074  * Revision 1.2  2006/05/15 11:44:06  haraldkipp
00075  * Added delays for more reliable initialization.
00076  *
00077  * Revision 1.1  2006/04/07 13:50:15  haraldkipp
00078  * ARM driver for HD44780 LCD controller added.
00079  *
00080  */
00081 
00082 #include <cfg/arch.h>
00083 #include <cfg/arch/gpio.h>
00084 #include <cfg/lcd.h>
00085 
00086 #if 0
00087 /* Configuration items. */
00088 #define LCD_DATA_LSB    0
00089 #define LCD_ENABLE_BIT  4
00090 #define LCD_RW_BIT      5
00091 #define LCD_REGSEL_BIT  7
00092 
00093 #endif
00094 
00095 #include <stdlib.h>
00096 #include <string.h>
00097 
00098 #include <sys/nutconfig.h>
00099 #include <dev/hd44780.h>
00100 #include <dev/term.h>
00101 #include <sys/timer.h>
00102 
00103 #if !defined(LCD_4x20) && !defined(LCD_4x16)
00104 #if !defined(LCD_2x40) && !defined(LCD_2x20) && !defined(LCD_2x16) && !defined(LCD_2x8)
00105 #if !defined(LCD_1x20) && !defined(LCD_1x16) && !defined(LCD_1x8)
00106 #if !defined(KS0073_CONTROLLER)
00107 #define LCD_2x16
00108 #endif                          /* !KS0073_CONTROLLER */
00109 #endif                          /* !1 line */
00110 #endif                          /* !2 lines */
00111 #endif                          /* !4 lines */
00112 
00113 #ifndef LCD_ROWS
00114 #if defined(LCD_4x20) || defined(LCD_4x16) || defined(KS0073_CONTROLLER)
00115 #define LCD_ROWS    4
00116 #elif defined(LCD_1x20) || defined(LCD_1x16) || defined(LCD_1x8)
00117 #define LCD_ROWS    1
00118 #else
00119 #define LCD_ROWS    2
00120 #endif
00121 #endif                          /* LCD_ROWS */
00122 
00123 #ifndef LCD_COLS
00124 #if defined(LCD_2x40)
00125 #define LCD_COLS    40
00126 #elif defined(LCD_4x20) || defined(LCD_2x20) || defined(LCD_1x20) || defined(KS0073_CONTROLLER)
00127 #define LCD_COLS    20
00128 #elif defined(LCD_2x8) || defined(LCD_1x8)
00129 #define LCD_COLS    8
00130 #else
00131 #define LCD_COLS    16
00132 #endif
00133 #endif                          /* LCD_COLS */
00134 
00138 #if !defined(LCD_PIO_ID)
00139 #if defined(MCU_AT91SAM7X256) || defined (MCU_AT91SAM7S256) || defined (MCU_AT91SAM7SE512)
00140 #define LCD_PIO_ID  PIOA_ID
00141 #elif defined(MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE512)
00142 #define LCD_PIO_ID  PIOB_ID
00143 #else
00144 #define LCD_PIO_ID  PIO_ID
00145 #endif
00146 #endif
00147 
00151 #if !defined(LCD_PIO_PE_REG)
00152 #if LCD_PIO_ID == PIOA_ID
00153 #define LCD_PIO_PE_REG  PIOA_PER
00154 #elif LCD_PIO_ID == PIOB_ID
00155 #define LCD_PIO_PE_REG  PIOB_PER
00156 #elif LCD_PIO_ID == PIOC_ID
00157 #define LCD_PIO_PE_REG  PIOC_PER
00158 #else
00159 #define LCD_PIO_PE_REG  PIO_PER
00160 #endif
00161 #endif
00162 
00166 #if !defined(LCD_PIO_OE_REG)
00167 #if LCD_PIO_ID == PIOA_ID
00168 #define LCD_PIO_OE_REG  PIOA_OER
00169 #elif LCD_PIO_ID == PIOB_ID
00170 #define LCD_PIO_OE_REG  PIOB_OER
00171 #elif LCD_PIO_ID == PIOC_ID
00172 #define LCD_PIO_OE_REG  PIOC_OER
00173 #else
00174 #define LCD_PIO_OE_REG  PIO_OER
00175 #endif
00176 #endif
00177 
00181 #ifdef LCD_RW_BIT
00182 #if !defined(LCD_PIO_OD_REG)
00183 #if LCD_PIO_ID == PIOA_ID
00184 #define LCD_PIO_OD_REG  PIOA_ODR
00185 #elif LCD_PIO_ID == PIOB_ID
00186 #define LCD_PIO_OD_REG  PIOB_ODR
00187 #elif LCD_PIO_ID == PIOC_ID
00188 #define LCD_PIO_OD_REG  PIOC_ODR
00189 #else
00190 #define LCD_PIO_OD_REG  PIO_ODR
00191 #endif
00192 #endif
00193 #endif /* LCD_RW_BIT */
00194 
00198 #if !defined(LCD_PIO_SOD_REG)
00199 #if LCD_PIO_ID == PIOA_ID
00200 #define LCD_PIO_SOD_REG PIOA_SODR
00201 #elif LCD_PIO_ID == PIOB_ID
00202 #define LCD_PIO_SOD_REG PIOB_SODR
00203 #elif LCD_PIO_ID == PIOC_ID
00204 #define LCD_PIO_SOD_REG PIOC_SODR
00205 #else
00206 #define LCD_PIO_SOD_REG PIO_SODR
00207 #endif
00208 #endif
00209 
00213 #if !defined(LCD_PIO_COD_REG)
00214 #if LCD_PIO_ID == PIOA_ID
00215 #define LCD_PIO_COD_REG PIOA_CODR
00216 #elif LCD_PIO_ID == PIOB_ID
00217 #define LCD_PIO_COD_REG PIOB_CODR
00218 #elif LCD_PIO_ID == PIOC_ID
00219 #define LCD_PIO_COD_REG PIOC_CODR
00220 #else
00221 #define LCD_PIO_COD_REG PIO_CODR
00222 #endif
00223 #endif
00224 
00228 #ifdef LCD_RW_BIT
00229 #if !defined(LCD_PIO_PDS_REG)
00230 #if LCD_PIO_ID == PIOA_ID
00231 #define LCD_PIO_PDS_REG PIOA_PDSR
00232 #elif LCD_PIO_ID == PIOB_ID
00233 #define LCD_PIO_PDS_REG PIOB_PDSR
00234 #elif LCD_PIO_ID == PIOC_ID
00235 #define LCD_PIO_PDS_REG PIOC_PDSR
00236 #else
00237 #define LCD_PIO_PDS_REG PIO_PDSR
00238 #endif
00239 #endif
00240 #endif /* LCD_RW_BIT */
00241 
00242 #if !defined(LCD_DATA_LSB) && !defined(LCD_DATA_BIT0)
00243 #define LCD_DATA_LSB    0
00244 #endif
00245 
00246 #ifdef LCD_DATA_LSB
00247 #define LCD_DATA    (0xF << LCD_DATA_LSB)
00248 #else
00249 #define LCD_D0      _BV(LCD_DATA_BIT0)
00250 #define LCD_D1      _BV(LCD_DATA_BIT1)
00251 #define LCD_D2      _BV(LCD_DATA_BIT2)
00252 #define LCD_D3      _BV(LCD_DATA_BIT3)
00253 #define LCD_DATA    (LCD_D0 | LCD_D1 | LCD_D2 | LCD_D3)
00254 #endif
00255 
00256 #ifndef LCD_ENABLE_BIT
00257 #define LCD_ENABLE_BIT  4
00258 #endif
00259 #define LCD_EN      _BV(LCD_ENABLE_BIT)
00260 
00261 #ifndef LCD_REGSEL_BIT
00262 #define LCD_REGSEL_BIT  7
00263 #endif
00264 #define LCD_RS      _BV(LCD_REGSEL_BIT)
00265 
00266 #ifdef LCD_RW_BIT
00267 #define LCD_RW      _BV(LCD_RW_BIT)
00268 #endif
00269 
00270 #ifndef LCD_SHORT_DELAY
00271 #define LCD_SHORT_DELAY 10
00272 #endif
00273 
00274 #ifndef LCD_LONG_DELAY
00275 #define LCD_LONG_DELAY  1000
00276 #endif
00277 
00282 
00293 static void LcdDelay(u_int cycles)
00294 {
00295     while (cycles--) {
00296         _NOP(); _NOP(); _NOP(); _NOP();
00297         _NOP(); _NOP(); _NOP(); _NOP();
00298         _NOP(); _NOP(); _NOP(); _NOP();
00299         _NOP(); _NOP(); _NOP(); _NOP();
00300         _NOP(); _NOP(); _NOP(); _NOP();
00301         _NOP(); _NOP(); _NOP(); _NOP();
00302         _NOP(); _NOP(); _NOP(); _NOP();
00303         _NOP(); _NOP(); _NOP(); _NOP();
00304         _NOP(); _NOP(); _NOP(); _NOP();
00305         _NOP(); _NOP(); _NOP(); _NOP();
00306         _NOP(); _NOP(); _NOP(); _NOP();
00307         _NOP(); _NOP(); _NOP(); _NOP();
00308     }
00309 }
00310 
00311 static void INLINE LcdSetBits(u_int mask)
00312 {
00313     outr(LCD_PIO_SOD_REG, mask);
00314     outr(LCD_PIO_OE_REG, mask);
00315 }
00316 
00317 static void INLINE LcdClrBits(u_int mask)
00318 {
00319     outr(LCD_PIO_COD_REG, mask);
00320     outr(LCD_PIO_OE_REG, mask);
00321 }
00322 
00323 #ifdef LCD_RW_BIT
00324 
00325 static u_int LcdReadNibble(void)
00326 {
00327     u_int rc;
00328 
00329     LcdSetBits(LCD_EN);
00330     LcdDelay(LCD_SHORT_DELAY);
00331     rc = inr(LCD_PIO_PDS_REG) & LCD_DATA;
00332     LcdClrBits(LCD_EN);
00333     LcdDelay(LCD_SHORT_DELAY);
00334 
00335 #ifdef LCD_DATA_LSB
00336     rc >>= LCD_DATA_LSB
00337 #else
00338     {
00339         u_int val = 0;
00340 
00341         if (rc & LCD_D0) {
00342             val |= 0x01;
00343         }
00344         if (rc & LCD_D1) {
00345             val |= 0x02;
00346         }
00347         if (rc & LCD_D2) {
00348             val |= 0x04;
00349         }
00350         if (rc & LCD_D3) {
00351             val |= 0x08;
00352         }
00353         rc = val;
00354     }
00355 #endif
00356     return rc;
00357 }
00358 
00362 static u_int LcdReadByte(void)
00363 {
00364     outr(LCD_PIO_OD_REG, LCD_DATA);
00365     LcdDelay(LCD_SHORT_DELAY);
00366     LcdSetBits(LCD_RW);
00367     LcdDelay(LCD_SHORT_DELAY);
00368     return (LcdReadNibble() << 4) | LcdReadNibble();
00369 }
00370 
00374 static u_int LcdReadStatus(void)
00375 {
00376     /* RS low selects status register. */
00377     LcdClrBits(LCD_RS);
00378     return LcdReadByte();
00379 }
00380 
00381 #endif                          /* LCD_RW_BIT */
00382 
00383 static void LcdWaitReady(u_int delay)
00384 {
00385     while (delay--) {
00386 #if defined(LCD_RW_BIT)
00387         if ((LcdReadStatus() & _BV(LCD_BUSY)) == 0) {
00388             break;
00389         }
00390 #endif
00391         _NOP();
00392     }
00393 }
00394 
00400 static void LcdWriteNibble(u_int nib)
00401 {
00402 #ifdef LCD_DATA_LSB
00403     nib <<= LCD_DATA_LSB;
00404 #else
00405     {
00406         u_int val = 0;
00407         if (nib & 0x01) {
00408             val |= LCD_D0;
00409         }
00410         if (nib & 0x02) {
00411             val |= LCD_D1;
00412         }
00413         if (nib & 0x04) {
00414             val |= LCD_D2;
00415         }
00416         if (nib & 0x08) {
00417             val |= LCD_D3;
00418         }
00419         nib = val;
00420     }
00421 #endif
00422     LcdSetBits(nib & LCD_DATA);
00423     LcdClrBits(~nib & LCD_DATA);
00424 
00425     LcdDelay(LCD_SHORT_DELAY);
00426     LcdSetBits(LCD_EN);
00427     LcdDelay(LCD_SHORT_DELAY);
00428     LcdClrBits(LCD_EN);
00429     LcdDelay(LCD_SHORT_DELAY);
00430 }
00431 
00437 static void LcdWriteByte(u_int data)
00438 {
00439 #ifdef LCD_RW_BIT
00440     LcdClrBits(LCD_RW);
00441 #endif
00442     LcdWriteNibble(data >> 4);
00443     LcdWriteNibble(data);
00444     LcdWaitReady(LCD_LONG_DELAY);
00445 }
00446 
00452 static void LcdWriteCmd(uint8_t cmd)
00453 {
00454     /* RS low selects instruction register. */
00455     LcdClrBits(LCD_RS);
00456     LcdWriteByte(cmd);
00457 }
00458 
00459 static void LcdWriteInstruction(uint8_t cmd, uint8_t xt)
00460 {
00461     LcdWriteCmd(cmd);
00462 }
00463 
00469 static void LcdWriteData(uint8_t data)
00470 {
00471     /* RS high selects data register. */
00472     LcdSetBits(LCD_RS);
00473     LcdWriteByte(data);
00474 }
00475 
00476 static void LcdSetCursor(uint8_t pos)
00477 {
00478     uint8_t offset[] = {
00479 #ifdef KS0073_CONTROLLER
00480         0x00, 0x20, 0x40, 0x60
00481 #elif LCD_COLS == 20
00482         0x00, 0x40, 0x14, 0x54
00483 #else
00484         0x00, 0x40, 0x10, 0x50
00485 #endif
00486     };
00487 
00488     pos = offset[(pos / LCD_COLS) % LCD_ROWS] + pos % LCD_COLS;
00489     LcdWriteCmd(1 << LCD_DDRAM | pos);
00490 }
00491 
00492 static void LcdCursorHome(void)
00493 {
00494     LcdWriteCmd(1 << LCD_HOME);
00495     LcdDelay(10 * LCD_LONG_DELAY);
00496 }
00497 
00498 static void LcdCursorLeft(void)
00499 {
00500     LcdWriteCmd(1 << LCD_MOVE);
00501 }
00502 
00503 static void LcdCursorRight(void)
00504 {
00505     LcdWriteCmd(1 << LCD_MOVE | 1 << LCD_MOVE_RIGHT);
00506 }
00507 
00508 static void LcdClear(void)
00509 {
00510     LcdWriteCmd(_BV(LCD_CLR));
00511     LcdDelay(10 * LCD_LONG_DELAY);
00512 }
00513 
00514 static void LcdCursorMode(uint8_t on)
00515 {
00516     LcdWriteCmd(1 << LCD_ON_CTRL | on ? 1 << LCD_ON_CURSOR : 0x00);
00517     LcdDelay(10 * LCD_LONG_DELAY);
00518 }
00519 
00520 static void LcdInit(NUTDEVICE * dev)
00521 {
00522 #if defined(PMC_PCER)
00523     outr(PMC_PCER, _BV(LCD_PIO_ID));
00524 #endif
00525 
00526     /* Initialize GPIO lines. */
00527 #ifdef LCD_RW_BIT
00528     outr(LCD_PIO_PE_REG, LCD_RW);
00529     LcdClrBits(LCD_RW);
00530 #endif
00531     outr(LCD_PIO_PE_REG, LCD_EN | LCD_RS | LCD_DATA);
00532     LcdClrBits(LCD_DATA | LCD_RS);
00533     LcdDelay(LCD_LONG_DELAY);
00534     LcdClrBits(LCD_EN);
00535     LcdDelay(LCD_LONG_DELAY);
00536 
00537     /* Initial delay. Actually only required after power on. */
00538     NutSleep(16);
00539 
00540     /* This initialization will make sure, that the LCD is switched
00541        to 4-bit mode, no matter which mode we start from. */
00542     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00543     NutSleep(5);
00544     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00545     NutSleep(2);
00546     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00547     NutSleep(2);
00548     LcdWriteNibble(_BV(LCD_FUNCTION) >> 4);
00549     NutSleep(2);
00550 
00551     /* Set number of lines and font. Can't be changed later. */
00552     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES)) >> 4);
00553     LcdWriteNibble(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES));
00554     NutSleep(2);
00555 
00556     /* Switch display and cursor off. */
00557     LcdWriteNibble(_BV(LCD_ON_CTRL) >> 4);
00558     LcdWriteNibble(_BV(LCD_ON_CTRL));
00559     NutSleep(2);
00560 
00561     /* Clear display. */
00562     LcdClear();
00563 
00564     /* Set entry mode. */
00565     LcdWriteCmd(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC));
00566     /* Switch display on. */
00567     LcdWriteCmd(_BV(LCD_ON_CTRL) | _BV(LCD_ON_DISPLAY));
00568     /* Move cursor home. */
00569     LcdCursorHome();
00570     /* Set data address to zero. */
00571     LcdWriteCmd(_BV(LCD_DDRAM));
00572 }
00573 
00577 TERMDCB dcb_term = {
00578     LcdInit,                    
00579     LcdWriteData,               
00580     LcdWriteInstruction,        
00581     LcdClear,                   
00582     LcdSetCursor,               
00583     LcdCursorHome,              
00584     LcdCursorLeft,              
00585     LcdCursorRight,             
00586     LcdCursorMode,              
00587     0,                          
00588     0,                          
00589     LCD_ROWS,                   
00590     LCD_COLS,                   
00591     LCD_COLS,                   
00592     0,                          
00593     0,                          
00594     0                           
00595 };
00596 
00600 NUTDEVICE devLcd = {
00601     0,                          
00602     {'l', 'c', 'd', 0, 0, 0, 0, 0, 0},  
00603     IFTYP_STREAM,               
00604     0,                          
00605     0,                          
00606     0,                          
00607     &dcb_term,                  
00608     TermInit,                   
00609     TermIOCtl,                  
00610     0,
00611     TermWrite,
00612     TermOpen,
00613     TermClose,
00614     0
00615 };
00616 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/