1 //*****************************************************************************
\r
3 // File........: LCD_driver.c
\r
5 // Author(s)...: ATMEL Norway
\r
7 // Target(s)...: ATmega169
\r
9 // Compiler....: AVR-GCC 4.1.1; avr-libc 1.4.5
\r
11 // Description.: Functions used to control the AVR Butterfly LCD
\r
13 // Revisions...: 1.0
\r
15 // YYYYMMDD - VER. - COMMENT - SIGN.
\r
17 // 20021015 - 1.0 - Written for STK502 - JLL
\r
18 // 20030116 - 2.0 - Code adapted to AVR Butterfly - KS
\r
19 // 20031009 port to avr-gcc/avr-libc - M.Thomas
\r
20 // 20070122 "updated 2006-10-10" included (from REV07) - from Atmel
\r
21 // 20070129 SIGNAL->ISR, gLCD_Start_Scroll_Timer volatile - mt
\r
23 //*****************************************************************************
\r
28 #include <avr/pgmspace.h>
\r
29 #include <avr/interrupt.h>
\r
31 // mt - only for AUTO:
\r
33 // mt - for gButtonTimeout
\r
35 #include "LCD_Driver.h"
\r
40 #define TRUE (!FALSE)
\r
44 // Used to indicate when the LCD interrupt handler should update the LCD
\r
45 // mt jw char gLCD_Update_Required = FALSE;
\r
46 volatile char gLCD_Update_Required = FALSE;
\r
48 // LCD display buffer (for double buffering).
\r
49 volatile char LCD_Data[LCD_REGISTER_COUNT];
\r
51 // Buffer that contains the text to be displayed
\r
52 // Note: Bit 7 indicates that this character is flashing
\r
53 volatile char gTextBuffer[TEXTBUFFER_SIZE];
\r
55 // Only six letters can be shown on the LCD.
\r
56 // With the gScroll and gScrollMode variables,
\r
57 // one can select which part of the buffer to show
\r
58 volatile signed char gScroll;
\r
59 volatile char gScrollMode;
\r
61 ////Start-up delay before scrolling a string over the LCD
\r
62 volatile char gLCD_Start_Scroll_Timer = 0;
\r
64 // The gFlashTimer is used to determine the on/off
\r
65 // timing of flashing characters
\r
66 volatile char gFlashTimer = 0;
\r
68 // Turns on/off the colons on the LCD
\r
72 // Look-up table used when converting ASCII to
\r
73 // LCD display data (segment control)
\r
74 // mt __flash unsigned int LCD_character_table[] =
\r
75 unsigned int LCD_character_table[] PROGMEM =
\r
79 0x0000, // ',' (Not defined)
\r
81 0xFF00, // '.' Fullstop
\r
82 0x0000, // '/' (Not defined)
\r
93 0x0000, // ':' (Not defined)
\r
94 0x0000, // ';' (Not defined)
\r
95 0x0000, // '<' (Not defined)
\r
96 0x0000, // '=' (Not defined)
\r
97 0x0000, // '>' (Not defined)
\r
98 0x0000, // '?' (Not defined)
\r
99 0x0000, // '@' (Not defined)
\r
100 0x0f51, // 'A' (+ 'a')
\r
101 0x3991, // 'B' (+ 'b')
\r
102 0x1441, // 'C' (+ 'c')
\r
103 0x3191, // 'D' (+ 'd')
\r
104 0x1e41, // 'E' (+ 'e')
\r
105 0x0e41, // 'F' (+ 'f')
\r
106 0x1d41, // 'G' (+ 'g')
\r
107 0x0f50, // 'H' (+ 'h')
\r
108 0x2080, // 'I' (+ 'i')
\r
109 0x1510, // 'J' (+ 'j')
\r
110 0x8648, // 'K' (+ 'k')
\r
111 0x1440, // 'L' (+ 'l')
\r
112 0x0578, // 'M' (+ 'm')
\r
113 0x8570, // 'N' (+ 'n')
\r
114 0x1551, // 'O' (+ 'o')
\r
115 0x0e51, // 'P' (+ 'p')
\r
116 0x9551, // 'Q' (+ 'q')
\r
117 0x8e51, // 'R' (+ 'r')
\r
118 0x9021, // 'S' (+ 's')
\r
119 0x2081, // 'T' (+ 't')
\r
120 0x1550, // 'U' (+ 'u')
\r
121 0x4448, // 'V' (+ 'v')
\r
122 0xc550, // 'W' (+ 'w')
\r
123 0xc028, // 'X' (+ 'x')
\r
124 0x2028, // 'Y' (+ 'y')
\r
125 0x5009, // 'Z' (+ 'z')
\r
126 0x0000, // '[' (Not defined)
\r
127 0x0000, // '\' (Not defined)
\r
128 0x0000, // ']' (Not defined)
\r
129 0x0000, // '^' (Not defined)
\r
134 /*****************************************************************************
\r
136 * Function name : LCD_Init
\r
140 * Parameters : None
\r
142 * Purpose : Initialize LCD_displayData buffer.
\r
143 * Set up the LCD (timing, contrast, etc.)
\r
145 *****************************************************************************/
\r
146 void LCD_Init(void)
\r
148 LCD_AllSegments(FALSE); // Clear segment buffer.
\r
150 LCD_CONTRAST_LEVEL(LCD_INITIAL_CONTRAST); //Set the LCD contrast level
\r
152 // Select asynchronous clock source, enable all COM pins and enable all
\r
154 LCDCRB = (1<<LCDCS) | (3<<LCDMUX0) | (7<<LCDPM0);
\r
156 // Set LCD prescaler to give a framerate of 32,0 Hz
\r
157 LCDFRR = (0<<LCDPS0) | (7<<LCDCD0);
\r
159 LCDCRA = (1<<LCDEN) | (1<<LCDAB); // Enable LCD and set low power waveform
\r
161 //Enable LCD start of frame interrupt
\r
162 LCDCRA |= (1<<LCDIE);
\r
164 //updated 2006-10-10, setting LCD drive time to 1150us in FW rev 07,
\r
165 //instead of previous 300us in FW rev 06. Due to some variations on the LCD
\r
166 //glass provided to the AVR Butterfly production.
\r
167 LCDCCR |= (1<<LCDDC2) | (1<<LCDDC1) | (1<<LCDDC0);
\r
169 gLCD_Update_Required = FALSE;
\r
175 /*****************************************************************************
\r
177 * Function name : LCD_WriteDigit(char c, char digit)
\r
181 * Parameters : Inputs
\r
182 * c: The symbol to be displayed in a LCD digit
\r
183 * digit: In which digit (0-5) the symbol should be displayed
\r
184 * Note: Digit 0 is the first used digit on the LCD,
\r
187 * Purpose : Stores LCD control data in the LCD_displayData buffer.
\r
188 * (The LCD_displayData is latched in the LCD_SOF interrupt.)
\r
190 *****************************************************************************/
\r
191 void LCD_WriteDigit(char c, char digit)
\r
194 unsigned int seg = 0x0000; // Holds the segment pattern
\r
196 volatile char *ptr;
\r
200 if (digit > 5) // Skip if digit is illegal
\r
203 //Lookup character table for segmet data
\r
204 if ((c >= '*') && (c <= 'z'))
\r
207 if (c >= 'a') // Convert to upper case
\r
208 c &= ~0x20; // if necessarry
\r
212 //mt seg = LCD_character_table[c];
\r
213 seg = (unsigned int) pgm_read_word(&LCD_character_table[(uint8_t)c]);
\r
216 // Adjust mask according to LCD segment mapping
\r
218 mask = 0x0F; // Digit 1, 3, 5
\r
220 mask = 0xF0; // Digit 0, 2, 4
\r
222 ptr = LCD_Data + (digit >> 1); // digit = {0,0,1,1,2,2}
\r
224 for (i = 0; i < 4; i++)
\r
226 nibble = seg & 0x000F;
\r
230 *ptr = (*ptr & mask) | nibble;
\r
237 /*****************************************************************************
\r
239 * Function name : LCD_AllSegments(unsigned char input)
\r
243 * Parameters : show - [TRUE;FALSE]
\r
245 * Purpose : shows or hide all all LCD segments on the LCD
\r
247 *****************************************************************************/
\r
248 void LCD_AllSegments(char show)
\r
255 // Set/clear all bits in all LCD registers
\r
256 for (i=0; i < LCD_REGISTER_COUNT; i++)
\r
257 *(LCD_Data + i) = show;
\r
261 /*****************************************************************************
\r
263 * LCD Interrupt Routine
\r
267 * Parameters : None
\r
269 * Purpose: Latch the LCD_displayData and Set LCD_status.updateComplete
\r
271 *****************************************************************************/
\r
275 static char LCD_timer = LCD_TIMER_SEED;
\r
287 LCD_timer--; // Decreased every LCD frame
\r
291 // If we are in scroll mode, and the timer has expired,
\r
292 // we will update the LCD
\r
293 if (LCD_timer == 0)
\r
295 if (gLCD_Start_Scroll_Timer == 0)
\r
297 gLCD_Update_Required = TRUE;
\r
300 gLCD_Start_Scroll_Timer--;
\r
304 { // if not scrolling,
\r
305 // disble LCD start of frame interrupt
\r
306 // cbi(LCDCRA, LCDIE); //DEBUG
\r
312 if (gLCD_Update_Required == TRUE)
\r
314 // Duty cycle of flashing characters
\r
315 if (gFlashTimer < (LCD_FLASH_SEED >> 1))
\r
320 // Repeat for the six LCD characters
\r
321 for (i = 0; i < 6; i++)
\r
323 if ((gScroll+i) >= 0 && (!EOL))
\r
325 // We have some visible characters
\r
326 c = gTextBuffer[i + gScroll];
\r
327 c_flash = c & 0x80 ? 1 : 0;
\r
331 EOL = i+1; // End of character data
\r
336 // Check if this character is flashing
\r
338 if (c_flash && flash)
\r
339 LCD_WriteDigit(' ', i);
\r
341 LCD_WriteDigit(c, i);
\r
344 // Copy the segment buffer to the real segments
\r
345 for (i = 0; i < LCD_REGISTER_COUNT; i++)
\r
346 *(pLCDREG + i) = *(LCD_Data+i);
\r
350 *(pLCDREG + 8) = 0x01;
\r
352 *(pLCDREG + 8) = 0x00;
\r
354 // If the text scrolled off the display,
\r
355 // we have to start over again.
\r
361 // No need to update anymore
\r
362 gLCD_Update_Required = FALSE;
\r
366 // LCD_timer is used when scrolling text
\r
367 if (LCD_timer == 0)
\r
369 /* if ((gScroll <= 0) || EOL)
\r
370 LCD_timer = LCD_TIMER_SEED/2;
\r
372 LCD_timer = LCD_TIMER_SEED;
\r
375 // gFlashTimer is used when flashing characters
\r
376 if (gFlashTimer == LCD_FLASH_SEED)
\r