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.8  2007/10/04 19:57:54  olereinhardt
00037  * Support for SAM7S256 added
00038  *
00039  * Revision 1.7  2007/02/15 16:05:29  haraldkipp
00040  * Port usage is now configurable. Data bits no longer need four consecutive
00041  * port bits. Added delays in read for better reliability with some slow
00042  * displays.
00043  *
00044  * Revision 1.6  2006/10/05 17:11:16  haraldkipp
00045  * Fixes bug #1567813. Should now work after power on and after reset without
00046  * power loss. Many thanks to Klaus-Dieter Sohn.
00047  *
00048  * Revision 1.5  2006/08/31 19:02:25  haraldkipp
00049  * Added support for AT91SAM9260.
00050  * Some displays fail after reset. An additional nibble sent
00051  * during 4-bit initialization seems to fix this. However,
00052  * a user reported that his 3.3V driven LCD now fails during
00053  * power on.
00054  *
00055  * Revision 1.4  2006/07/15 11:15:31  haraldkipp
00056  * Initialization flag removed. It is not required because the driver doesn't
00057  * poll the busy flag during initialization.
00058  * Bug fixed, which let the driver fail to properly initialize displays with
00059  * two lines.
00060  *
00061  * Revision 1.3  2006/06/28 17:23:19  haraldkipp
00062  * Significantly extend delay time to allow running slow 3.3V LCDs with fast
00063  * CPUs. Not a nice fix, but it works.
00064  *
00065  * Revision 1.2  2006/05/15 11:44:06  haraldkipp
00066  * Added delays for more reliable initialization.
00067  *
00068  * Revision 1.1  2006/04/07 13:50:15  haraldkipp
00069  * ARM driver for HD44780 LCD controller added.
00070  *
00071  */
00072 
00073 #include <cfg/arch.h>
00074 #include <cfg/arch/gpio.h>
00075 #include <cfg/lcd.h>
00076 
00077 #if 0
00078 /* Configuration items. */
00079 #define LCD_DATA_LSB    0
00080 #define LCD_ENABLE_BIT  4
00081 #define LCD_RW_BIT      5
00082 #define LCD_REGSEL_BIT  7
00083 
00084 #endif
00085 
00086 #include <stdlib.h>
00087 #include <string.h>
00088 
00089 #include <sys/nutconfig.h>
00090 #include <dev/hd44780.h>
00091 #include <dev/term.h>
00092 #include <sys/timer.h>
00093 
00094 #if !defined(LCD_4x20) && !defined(LCD_4x16)
00095 #if !defined(LCD_2x40) && !defined(LCD_2x20) && !defined(LCD_2x16) && !defined(LCD_2x8)
00096 #if !defined(LCD_1x20) && !defined(LCD_1x16) && !defined(LCD_1x8)
00097 #if !defined(KS0073_CONTROLLER)
00098 #define LCD_2x16
00099 #endif                          /* !KS0073_CONTROLLER */
00100 #endif                          /* !1 line */
00101 #endif                          /* !2 lines */
00102 #endif                          /* !4 lines */
00103 
00104 #ifndef LCD_ROWS
00105 #if defined(LCD_4x20) || defined(LCD_4x16) || defined(KS0073_CONTROLLER)
00106 #define LCD_ROWS    4
00107 #elif defined(LCD_1x20) || defined(LCD_1x16) || defined(LCD_1x8)
00108 #define LCD_ROWS    1
00109 #else
00110 #define LCD_ROWS    2
00111 #endif
00112 #endif                          /* LCD_ROWS */
00113 
00114 #ifndef LCD_COLS
00115 #if defined(LCD_2x40)
00116 #define LCD_COLS    40
00117 #elif defined(LCD_4x20) || defined(LCD_2x20) || defined(LCD_1x20) || defined(KS0073_CONTROLLER)
00118 #define LCD_COLS    20
00119 #elif defined(LCD_2x8) || defined(LCD_1x8)
00120 #define LCD_COLS    8
00121 #else
00122 #define LCD_COLS    16
00123 #endif
00124 #endif                          /* LCD_COLS */
00125 
00129 #if !defined(LCD_PIO_ID)
00130 #if defined(MCU_AT91SAM7X256) || defined (MCU_AT91SAM7S256)
00131 #define LCD_PIO_ID  PIOA_ID
00132 #elif defined(MCU_AT91SAM9260)
00133 #define LCD_PIO_ID  PIOB_ID
00134 #else
00135 #define LCD_PIO_ID  PIO_ID
00136 #endif
00137 #endif
00138 
00142 #if !defined(LCD_PIO_PE_REG)
00143 #if LCD_PIO_ID == PIOA_ID
00144 #define LCD_PIO_PE_REG  PIOA_PER
00145 #elif LCD_PIO_ID == PIOB_ID
00146 #define LCD_PIO_PE_REG  PIOB_PER
00147 #elif LCD_PIO_ID == PIOC_ID
00148 #define LCD_PIO_PE_REG  PIOC_PER
00149 #else
00150 #define LCD_PIO_PE_REG  PIO_PER
00151 #endif
00152 #endif
00153 
00157 #if !defined(LCD_PIO_OE_REG)
00158 #if LCD_PIO_ID == PIOA_ID
00159 #define LCD_PIO_OE_REG  PIOA_OER
00160 #elif LCD_PIO_ID == PIOB_ID
00161 #define LCD_PIO_OE_REG  PIOB_OER
00162 #elif LCD_PIO_ID == PIOC_ID
00163 #define LCD_PIO_OE_REG  PIOC_OER
00164 #else
00165 #define LCD_PIO_OE_REG  PIO_OER
00166 #endif
00167 #endif
00168 
00172 #ifdef LCD_RW_BIT
00173 #if !defined(LCD_PIO_OD_REG)
00174 #if LCD_PIO_ID == PIOA_ID
00175 #define LCD_PIO_OD_REG  PIOA_ODR
00176 #elif LCD_PIO_ID == PIOB_ID
00177 #define LCD_PIO_OD_REG  PIOB_ODR
00178 #elif LCD_PIO_ID == PIOC_ID
00179 #define LCD_PIO_OD_REG  PIOC_ODR
00180 #else
00181 #define LCD_PIO_OD_REG  PIO_ODR
00182 #endif
00183 #endif
00184 #endif /* LCD_RW_BIT */
00185 
00189 #if !defined(LCD_PIO_SOD_REG)
00190 #if LCD_PIO_ID == PIOA_ID
00191 #define LCD_PIO_SOD_REG PIOA_SODR
00192 #elif LCD_PIO_ID == PIOB_ID
00193 #define LCD_PIO_SOD_REG PIOB_SODR
00194 #elif LCD_PIO_ID == PIOC_ID
00195 #define LCD_PIO_SOD_REG PIOC_SODR
00196 #else
00197 #define LCD_PIO_SOD_REG PIO_SODR
00198 #endif
00199 #endif
00200 
00204 #if !defined(LCD_PIO_COD_REG)
00205 #if LCD_PIO_ID == PIOA_ID
00206 #define LCD_PIO_COD_REG PIOA_CODR
00207 #elif LCD_PIO_ID == PIOB_ID
00208 #define LCD_PIO_COD_REG PIOB_CODR
00209 #elif LCD_PIO_ID == PIOC_ID
00210 #define LCD_PIO_COD_REG PIOC_CODR
00211 #else
00212 #define LCD_PIO_COD_REG PIO_CODR
00213 #endif
00214 #endif
00215 
00219 #ifdef LCD_RW_BIT
00220 #if !defined(LCD_PIO_PDS_REG)
00221 #if LCD_PIO_ID == PIOA_ID
00222 #define LCD_PIO_PDS_REG PIOA_PDSR
00223 #elif LCD_PIO_ID == PIOB_ID
00224 #define LCD_PIO_PDS_REG PIOB_PDSR
00225 #elif LCD_PIO_ID == PIOC_ID
00226 #define LCD_PIO_PDS_REG PIOC_PDSR
00227 #else
00228 #define LCD_PIO_PDS_REG PIO_PDSR
00229 #endif
00230 #endif
00231 #endif /* LCD_RW_BIT */
00232 
00233 #if !defined(LCD_DATA_LSB) && !defined(LCD_DATA_BIT0)
00234 #define LCD_DATA_LSB    0
00235 #endif
00236 
00237 #ifdef LCD_DATA_LSB
00238 #define LCD_DATA    (0xF << LCD_DATA_LSB)
00239 #else
00240 #define LCD_D0      _BV(LCD_DATA_BIT0)
00241 #define LCD_D1      _BV(LCD_DATA_BIT1)
00242 #define LCD_D2      _BV(LCD_DATA_BIT2)
00243 #define LCD_D3      _BV(LCD_DATA_BIT3)
00244 #define LCD_DATA    (LCD_D0 | LCD_D1 | LCD_D2 | LCD_D3)
00245 #endif
00246 
00247 #ifndef LCD_ENABLE_BIT
00248 #define LCD_ENABLE_BIT  4
00249 #endif
00250 #define LCD_EN      _BV(LCD_ENABLE_BIT)
00251 
00252 #ifndef LCD_REGSEL_BIT
00253 #define LCD_REGSEL_BIT  7
00254 #endif
00255 #define LCD_RS      _BV(LCD_REGSEL_BIT)
00256 
00257 #ifdef LCD_RW_BIT
00258 #define LCD_RW      _BV(LCD_RW_BIT)
00259 #endif
00260 
00261 #ifndef LCD_SHORT_DELAY
00262 #define LCD_SHORT_DELAY 10
00263 #endif
00264 
00265 #ifndef LCD_LONG_DELAY
00266 #define LCD_LONG_DELAY  1000
00267 #endif
00268 
00273 
00284 static void LcdDelay(u_int cycles)
00285 {
00286     while (cycles--) {
00287         _NOP(); _NOP(); _NOP(); _NOP();
00288         _NOP(); _NOP(); _NOP(); _NOP();
00289         _NOP(); _NOP(); _NOP(); _NOP();
00290         _NOP(); _NOP(); _NOP(); _NOP();
00291         _NOP(); _NOP(); _NOP(); _NOP();
00292         _NOP(); _NOP(); _NOP(); _NOP();
00293         _NOP(); _NOP(); _NOP(); _NOP();
00294         _NOP(); _NOP(); _NOP(); _NOP();
00295         _NOP(); _NOP(); _NOP(); _NOP();
00296         _NOP(); _NOP(); _NOP(); _NOP();
00297         _NOP(); _NOP(); _NOP(); _NOP();
00298         _NOP(); _NOP(); _NOP(); _NOP();
00299     }
00300 }
00301 
00302 static void INLINE LcdSetBits(u_int mask)
00303 {
00304     outr(LCD_PIO_SOD_REG, mask);
00305     outr(LCD_PIO_OE_REG, mask);
00306 }
00307 
00308 static void INLINE LcdClrBits(u_int mask)
00309 {
00310     outr(LCD_PIO_COD_REG, mask);
00311     outr(LCD_PIO_OE_REG, mask);
00312 }
00313 
00314 #ifdef LCD_RW_BIT
00315 
00316 static u_int LcdReadNibble(void)
00317 {
00318     u_int rc;
00319 
00320     LcdSetBits(LCD_EN);
00321     LcdDelay(LCD_SHORT_DELAY);
00322     rc = inr(LCD_PIO_PDS_REG) & LCD_DATA;
00323     LcdClrBits(LCD_EN);
00324     LcdDelay(LCD_SHORT_DELAY);
00325 
00326 #ifdef LCD_DATA_LSB
00327     rc >>= LCD_DATA_LSB
00328 #else
00329     {
00330         u_int val = 0;
00331 
00332         if (rc & LCD_D0) {
00333             val |= 0x01;
00334         }
00335         if (rc & LCD_D1) {
00336             val |= 0x02;
00337         }
00338         if (rc & LCD_D2) {
00339             val |= 0x04;
00340         }
00341         if (rc & LCD_D3) {
00342             val |= 0x08;
00343         }
00344         rc = val;
00345     }
00346 #endif
00347     return rc;
00348 }
00349 
00353 static u_int LcdReadByte(void)
00354 {
00355     outr(LCD_PIO_OD_REG, LCD_DATA);
00356     LcdDelay(LCD_SHORT_DELAY);
00357     LcdSetBits(LCD_RW);
00358     LcdDelay(LCD_SHORT_DELAY);
00359     return (LcdReadNibble() << 4) | LcdReadNibble();
00360 }
00361 
00365 static u_int LcdReadStatus(void)
00366 {
00367     /* RS low selects status register. */
00368     LcdClrBits(LCD_RS);
00369     return LcdReadByte();
00370 }
00371 
00372 #endif                          /* LCD_RW_BIT */
00373 
00374 static void LcdWaitReady(u_int delay)
00375 {
00376     while (delay--) {
00377 #if defined(LCD_RW_BIT)
00378         if ((LcdReadStatus() & _BV(LCD_BUSY)) == 0) {
00379             break;
00380         }
00381 #endif
00382         _NOP();
00383     }
00384 }
00385 
00391 static void LcdWriteNibble(u_int nib)
00392 {
00393 #ifdef LCD_DATA_LSB
00394     nib <<= LCD_DATA_LSB;
00395 #else
00396     {
00397         u_int val = 0;
00398         if (nib & 0x01) {
00399             val |= LCD_D0;
00400         }
00401         if (nib & 0x02) {
00402             val |= LCD_D1;
00403         }
00404         if (nib & 0x04) {
00405             val |= LCD_D2;
00406         }
00407         if (nib & 0x08) {
00408             val |= LCD_D3;
00409         }
00410         nib = val;
00411     }
00412 #endif
00413     LcdSetBits(nib & LCD_DATA);
00414     LcdClrBits(~nib & LCD_DATA);
00415 
00416     LcdDelay(LCD_SHORT_DELAY);
00417     LcdSetBits(LCD_EN);
00418     LcdDelay(LCD_SHORT_DELAY);
00419     LcdClrBits(LCD_EN);
00420     LcdDelay(LCD_SHORT_DELAY);
00421 }
00422 
00428 static void LcdWriteByte(u_int data)
00429 {
00430 #ifdef LCD_RW_BIT
00431     LcdClrBits(LCD_RW);
00432 #endif
00433     LcdWriteNibble(data >> 4);
00434     LcdWriteNibble(data);
00435     LcdWaitReady(LCD_LONG_DELAY);
00436 }
00437 
00443 static void LcdWriteCmd(u_char cmd)
00444 {
00445     /* RS low selects instruction register. */
00446     LcdClrBits(LCD_RS);
00447     LcdWriteByte(cmd);
00448 }
00449 
00450 static void LcdWriteInstruction(u_char cmd, u_char xt)
00451 {
00452     LcdWriteCmd(cmd);
00453 }
00454 
00460 static void LcdWriteData(u_char data)
00461 {
00462     /* RS high selects data register. */
00463     LcdSetBits(LCD_RS);
00464     LcdWriteByte(data);
00465 }
00466 
00467 static void LcdSetCursor(u_char pos)
00468 {
00469     u_char offset[] = {
00470 #ifdef KS0073_CONTROLLER
00471         0x00, 0x20, 0x40, 0x60
00472 #elif LCD_COLS == 20
00473         0x00, 0x40, 0x14, 0x54
00474 #else
00475         0x00, 0x40, 0x10, 0x50
00476 #endif
00477     };
00478 
00479     pos = offset[(pos / LCD_COLS) % LCD_ROWS] + pos % LCD_COLS;
00480     LcdWriteCmd(1 << LCD_DDRAM | pos);
00481 }
00482 
00483 static void LcdCursorHome(void)
00484 {
00485     LcdWriteCmd(1 << LCD_HOME);
00486     LcdDelay(10 * LCD_LONG_DELAY);
00487 }
00488 
00489 static void LcdCursorLeft(void)
00490 {
00491     LcdWriteCmd(1 << LCD_MOVE);
00492 }
00493 
00494 static void LcdCursorRight(void)
00495 {
00496     LcdWriteCmd(1 << LCD_MOVE | 1 << LCD_MOVE_RIGHT);
00497 }
00498 
00499 static void LcdClear(void)
00500 {
00501     LcdWriteCmd(_BV(LCD_CLR));
00502     LcdDelay(10 * LCD_LONG_DELAY);
00503 }
00504 
00505 static void LcdCursorMode(u_char on)
00506 {
00507     LcdWriteCmd(1 << LCD_ON_CTRL | on ? 1 << LCD_ON_CURSOR : 0x00);
00508     LcdDelay(10 * LCD_LONG_DELAY);
00509 }
00510 
00511 static void LcdInit(NUTDEVICE * dev)
00512 {
00513 #if defined(PMC_PCER)
00514     outr(PMC_PCER, _BV(LCD_PIO_ID));
00515 #endif
00516 
00517     /* Initialize GPIO lines. */
00518 #ifdef LCD_RW_BIT
00519     outr(LCD_PIO_PE_REG, LCD_RW);
00520     LcdClrBits(LCD_RW);
00521 #endif
00522     outr(LCD_PIO_PE_REG, LCD_EN | LCD_RS | LCD_DATA);
00523     LcdClrBits(LCD_DATA | LCD_RS);
00524     LcdDelay(LCD_LONG_DELAY);
00525     LcdClrBits(LCD_EN);
00526     LcdDelay(LCD_LONG_DELAY);
00527 
00528     /* Initial delay. Actually only required after power on. */
00529     NutSleep(16);
00530 
00531     /* This initialization will make sure, that the LCD is switched
00532        to 4-bit mode, no matter which mode we start from. */
00533     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00534     NutSleep(5);
00535     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00536     NutSleep(2);
00537     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_8BIT)) >> 4);
00538     NutSleep(2);
00539     LcdWriteNibble(_BV(LCD_FUNCTION) >> 4);
00540     NutSleep(2);
00541 
00542     /* Set number of lines and font. Can't be changed later. */
00543     LcdWriteNibble((_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES)) >> 4);
00544     LcdWriteNibble(_BV(LCD_FUNCTION) | _BV(LCD_FUNCTION_2LINES));
00545     NutSleep(2);
00546 
00547     /* Switch display and cursor off. */
00548     LcdWriteNibble(_BV(LCD_ON_CTRL) >> 4);
00549     LcdWriteNibble(_BV(LCD_ON_CTRL));
00550     NutSleep(2);
00551 
00552     /* Clear display. */
00553     LcdClear();
00554 
00555     /* Set entry mode. */
00556     LcdWriteCmd(_BV(LCD_ENTRY_MODE) | _BV(LCD_ENTRY_INC));
00557     /* Switch display on. */
00558     LcdWriteCmd(_BV(LCD_ON_CTRL) | _BV(LCD_ON_DISPLAY));
00559     /* Move cursor home. */
00560     LcdCursorHome();
00561     /* Set data address to zero. */
00562     LcdWriteCmd(_BV(LCD_DDRAM));
00563 }
00564 
00568 TERMDCB dcb_term = {
00569     LcdInit,                    
00570     LcdWriteData,               
00571     LcdWriteInstruction,        
00572     LcdClear,                   
00573     LcdSetCursor,               
00574     LcdCursorHome,              
00575     LcdCursorLeft,              
00576     LcdCursorRight,             
00577     LcdCursorMode,              
00578     0,                          
00579     0,                          
00580     LCD_ROWS,                   
00581     LCD_COLS,                   
00582     LCD_COLS,                   
00583     0,                          
00584     0,                          
00585     0                           
00586 };
00587 
00591 NUTDEVICE devLcd = {
00592     0,                          
00593     {'l', 'c', 'd', 0, 0, 0, 0, 0, 0},  
00594     IFTYP_STREAM,               
00595     0,                          
00596     0,                          
00597     0,                          
00598     &dcb_term,                  
00599     TermInit,                   
00600     TermIOCtl,                  
00601     0,
00602     TermWrite,
00603     TermOpen,
00604     TermClose,
00605     0
00606 };
00607 

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