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

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