2 * Copyright Droids Corporation, Microb Technology, Eirbot (2005)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Revision : $Id: lcd.c,v 1.5.4.3 2007-08-19 10:39:31 zer0 Exp $
22 /* Droids-corp, Eirbot, Microb Technology 2005 - Zer0
23 * Implementation for LCD
27 * \brief Implementation for the LCD module.
29 * \todo Test the module with other wirings, verify the delay macro, stqtic inlines for the public functions ??
31 * \test works on mega32 with all on the same port and old normal wiring, how about more speific connections ?
33 * This module provides functions for using a lcd device
40 #include <aversive/pgmspace.h>
42 #include <aversive/wait.h>
45 #include <lcd_protocol.h>
48 //#define lcd_e_delay() asm volatile("nop") /* delay 500ns with 4Mhz */
49 #define e_delay() _delay_loop_1(1) // ok ca ?
52 /**********************************************************/
54 ** port level functions
58 static inline void port_set_out(void)
62 IRQ_LOCK(flags); // if there is some other stuff on the same port
63 DDR(LCD_PORT) |= LCD_DATA_MASK;
68 static inline void port_set_in(void)
73 DDR(LCD_PORT) &= ~(LCD_DATA_MASK);
78 /* toggle Enable Pin */
79 static inline void e_toggle(void)
81 sbi(LCD_E_PORT, LCD_E_BIT);
83 cbi(LCD_E_PORT, LCD_E_BIT);
86 /**********************************************************/
88 ** byte level functions
90 static inline void lcd_write(uint8_t data,uint8_t rs)
92 register uint8_t port_save;
99 cbi(LCD_RW_PORT, LCD_RW_BIT);//RW=0
102 sbi(LCD_RS_PORT, LCD_RS_BIT); //RS=1
104 cbi(LCD_RS_PORT, LCD_RS_BIT); //RS=0
110 port_save= LCD_DATA_PORT & ~(LCD_DATA_MASK);
112 /* output high nibble first */
113 LCD_DATA_PORT = ( ( ((data>>4) << LCD_FIRST_DATA_BIT) & LCD_DATA_MASK )
118 /* output low nibble */
119 LCD_DATA_PORT = ( ((data<<LCD_FIRST_DATA_BIT) & LCD_DATA_MASK)
130 static uint8_t lcd_read(uint8_t rs)
132 register uint8_t dataH, dataL;
135 if (rs) sbi(LCD_RS_PORT, LCD_RS_BIT); /* RS=1: read data */
136 else cbi(LCD_RS_PORT, LCD_RS_BIT); /* RS=0: read busy flag */
137 sbi(LCD_RW_PORT, LCD_RW_BIT); /* RW=1 read mode */
139 /* configure data pins as input */
142 sbi(LCD_E_PORT, LCD_E_BIT);
146 dataH = PIN(LCD_PORT) >> LCD_FIRST_DATA_BIT ;/* read high nibble first */
148 cbi(LCD_E_PORT, LCD_E_BIT);
149 e_delay(); /* Enable 500ns low */
152 sbi(LCD_E_PORT, LCD_E_BIT);
155 dataL = PIN(LCD_PORT) >> LCD_FIRST_DATA_BIT ; /* read low nibble */
157 cbi(LCD_E_PORT, LCD_E_BIT);
159 return ( (dataH<<4) | (dataL&0x0F) );
163 // use for init, to set lcd mode to 4 bits
164 void initial_8_bit_write(uint8_t value)
166 register uint8_t port_save;
170 cbi(LCD_RW_PORT, LCD_RW_BIT);
172 cbi(LCD_RS_PORT, LCD_RS_BIT);
178 port_save = LCD_DATA_PORT & ~(LCD_DATA_MASK);
181 LCD_DATA_PORT = ( ((value <<LCD_FIRST_DATA_BIT) & LCD_DATA_MASK)
187 wait_ms(1); // delay, busy flag can't be checked here
190 /**********************************************************/
195 static inline unsigned char lcd_waitbusy(void)
196 /* loops while lcd is busy, reads address counter */
198 register unsigned char c;
200 while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) ;
202 return (c); // return address counter
207 void lcd_command(uint8_t cmd)
208 /* send commando <cmd> to LCD */
216 static inline void lcd_newline(uint8_t pos)
217 /* goto start of next line */
219 register uint8_t addressCounter;
226 if ( pos < (LCD_START_LINE2) )
227 addressCounter = LCD_START_LINE2;
229 addressCounter = LCD_START_LINE1;
232 if ( pos < LCD_START_LINE3 )
233 addressCounter = LCD_START_LINE2;
234 else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) )
235 addressCounter = LCD_START_LINE3;
236 else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) )
237 addressCounter = LCD_START_LINE4;
239 addressCounter = LCD_START_LINE1;
243 lcd_command((1<<LCD_DDRAM)+addressCounter);
252 /**********************************************************/
260 void lcd_gotoxy(uint8_t x, uint8_t y)
261 /* goto position (x,y) */
264 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
268 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
270 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
274 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
276 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
278 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);
280 lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);
288 void lcd_clrscr(void)
289 /* clear lcd and set cursor to home position */
291 lcd_command(1<<LCD_CLR);
297 /* set cursor to home position */
299 lcd_command(1<<LCD_HOME);
304 void lcd_putc(char c)
305 /* print character at current cursor position */
307 register unsigned char pos;
309 pos = lcd_waitbusy(); // read busy-flag and address counter
311 #if LCD_DOUBLE_ADDRESSING == 1
319 if (c=='\n') // new line
321 else if (c== '\f') // form feed = clear screen
327 /* for use with fdevopen */
328 int lcd_dev_putc(char c, FILE* f)
334 void lcd_init(uint8_t dispAttr)
335 /* initialize display and select type of cursor */
336 /* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
343 sbi(DDR(LCD_RW_PORT), LCD_RW_BIT);
344 sbi(DDR(LCD_RS_PORT), LCD_RS_BIT);
345 sbi(DDR(LCD_E_PORT), LCD_E_BIT);
348 wait_ms(16); /* wait 16ms or more after power-on */
350 /*------ Initialize lcd to 4 bit i/o mode -------*/
351 /* initial write to lcd is 8bit */
352 initial_8_bit_write(LCD_FUNCTION_8BIT_1LINE>>4);
353 initial_8_bit_write(LCD_FUNCTION_8BIT_1LINE>>4);
354 initial_8_bit_write(LCD_FUNCTION_8BIT_1LINE>>4);
355 initial_8_bit_write(LCD_FUNCTION_4BIT_1LINE>>4);
359 lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
360 lcd_command(LCD_DISP_OFF); /* display off */
361 lcd_clrscr(); /* display clear */
362 lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
363 lcd_command(dispAttr); /* display/cursor control */