Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members

lcd.c

Go to the documentation of this file.
00001 /***
00002  * This file is part of OpenHome, an open source home automation system.
00003  * Copyright (C) 2003 Jan Klötzke
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00027 #include <avr/io.h>
00028 #include <avr/interrupt.h>
00029 #include <avr/pgmspace.h>
00030 #include <inttypes.h>
00031 #include "main/lcd.h"
00032 #include "main/rom.h"
00033 #include "delay.h"
00034 #include "utils.h"
00035 
00036 #define WBF_MASTER      0x04    /* write to master                 */
00037 #define WBF_SLAVE       0x02    /* write to slave                  */
00038 #define WBF_MODE_DATA   0x01    /* normal data                     */
00039 #define WBF_MODE_CMD    0x00    /* interpret value as command      */
00040 
00041 #define CMD_DISPLAY_ON  0x3f    /* switch display on               */
00042 #define CMD_DISPLAY_OFF 0x3e    /* switch display off              */
00043 #define CMD_SET_START   0xC0    /* set display start line (0-31)   */
00044 #define CMD_SET_PAGE    0xB8    /* set page address register (0-3) */
00045 #define CMD_SET_COLUMN  0x40    /* set column address (0-79)       */
00046 
00047 #define send_cmd(a, b)  write_byte(a, b | WBF_MODE_CMD)
00048 #define send_all_cmd(a) send_cmd(a, WBF_MASTER | WBF_SLAVE)
00049 
00050 // define layout specific pins
00051 #define RES_PORT        PORTC
00052 #define RES_BIT         PC5
00053 #define RS_PORT         PORTE
00054 #define RS_BIT          PE3
00055 #define RW_PORT         PORTE
00056 #define RW_BIT          PE4
00057 #define E_PORT          PORTE
00058 #define E_BIT           PE5
00059 #define CS1_PORT        PORTC
00060 #define CS1_BIT         PC7
00061 #define CS2_PORT        PORTC
00062 #define CS2_BIT         PC6
00063 #define LED_PORT        PORTD
00064 #define LED_BIT         PD7
00065 
00072 static void write_byte(uint8_t value, uint8_t flags)
00073 {
00074         DDRA  = 0xff;           // port a as output
00075         PORTA = value;
00076         if (flags & WBF_MODE_DATA) sbi(RS_PORT, RS_BIT); else cbi(RS_PORT, RS_BIT);
00077         cbi(RW_PORT, RW_BIT);
00078         nop();
00079         if (flags & WBF_MASTER) sbi(CS1_PORT, CS1_BIT);
00080         if (flags & WBF_SLAVE)  sbi(CS2_PORT, CS2_BIT);
00081         nop(); nop();
00082         sbi(E_PORT, E_BIT);
00083         nop(); nop(); nop();
00084         cbi(E_PORT, E_BIT);
00085         nop(); nop();
00086         cbi(CS1_PORT, CS1_BIT);
00087         cbi(CS2_PORT, CS2_BIT);
00088         PORTA = 0x00;
00089         DDRA  = 0x00;           // port a as input, no pullups
00090         delay(3);
00091 }
00092 
00102 static uint8_t read_byte(uint8_t flags)
00103 {
00104         uint8_t result;
00105         
00106         // read byte from display
00107         if (flags & WBF_MODE_DATA) sbi(RS_PORT, RS_BIT); else cbi(RS_PORT, RS_BIT);
00108         sbi(RW_PORT, RW_BIT);
00109         if (flags & WBF_MASTER) {
00110                 sbi(CS1_PORT, CS1_BIT);
00111         } else {
00112                 if (flags & WBF_SLAVE) sbi(CS2_PORT, CS2_BIT);
00113         }       
00114         
00115         nop(); nop();
00116         sbi(E_PORT, E_BIT);
00117         nop(); nop(); nop();
00118         result = PINA;
00119         cbi(E_PORT, E_BIT);
00120         nop();
00121         cbi(CS1_PORT, CS1_BIT);
00122         cbi(CS2_PORT, CS2_BIT);
00123         delay(3);
00124         
00125         return result;
00126 }
00127 
00131 uint8_t lcd_str_width(uint8_t *text)
00132 {
00133         uint8_t chr, cnt;
00134         uint8_t result = 0;
00135         uint16_t charset;
00136         
00137         while ((chr = *text++) != 0x00) {
00138                 charset = ((uint16_t)(&i_small_charset)) + ((uint16_t)chr * SMALL_CHAR_SIZE) + 2;
00139                 for (cnt=0; cnt<8; cnt++) {
00140                         chr = pgm_read_byte(charset);
00141                         charset++;
00142                         result++;
00143                         if (chr == 0x00) break;
00144                 }
00145         }
00146         return result;
00147 }
00148 
00154 void lcd_print(uint8_t x, uint8_t y, uint8_t inverted, char *text)
00155 {
00156         uint8_t chip, chr, cnt;
00157         uint16_t charset;
00158 
00159         if (x > 127) return;
00160         
00161         // set page and column address
00162         send_all_cmd(CMD_SET_PAGE | (y >> 3));
00163         if (x < 64) {
00164                 chip = WBF_MASTER;
00165                 send_cmd(CMD_SET_COLUMN | x, WBF_MASTER);
00166                 send_cmd(CMD_SET_COLUMN | 0, WBF_SLAVE);
00167         } else {
00168                 chip = WBF_SLAVE;
00169                 send_cmd(CMD_SET_COLUMN | (x-64), WBF_SLAVE);
00170         }
00171         
00172         while ((chr = *text++) != 0x00) {
00173                 // calculate address of char
00174                 charset = ((uint16_t)(&i_small_charset)) + ((uint16_t)chr * SMALL_CHAR_SIZE) + 2;
00175                 
00176                 // print char column by column
00177                 for (cnt=0; cnt<8; cnt++) {
00178                         // change to slave-chip?
00179                         if (x == 64) chip = WBF_SLAVE;
00180                         // print column
00181                         chr = pgm_read_byte(charset);
00182                         charset++;
00183                         write_byte((inverted)?~chr:chr, chip | WBF_MODE_DATA);
00184                         x++;
00185                         // char finished?
00186                         if (chr == 0x00) break;
00187                 }
00188         }
00189 }
00190 
00194 void lcd_v_line(uint8_t x, uint8_t y1, uint8_t y2)
00195 {
00196         uint8_t chip, cnt, chr;
00197         uint8_t buffer[8];
00198         
00199         if (x > 63) {
00200                 x-=64;
00201                 chip = WBF_SLAVE;
00202         } else {
00203                 chip = WBF_MASTER;
00204         }
00205 
00206         // TODO: render directly to vram
00207         
00208         // first render to memory buffer
00209         for (cnt=0; cnt<8; cnt++) buffer[cnt] = 0;
00210         for (cnt=y1; cnt<=y2; cnt++) buffer[cnt >> 3] |= 1 << (cnt & 0x07);
00211         
00212         // transfer buffer to display
00213         for (cnt=0; cnt<8; cnt++) {
00214                 send_cmd(CMD_SET_PAGE | cnt, chip);
00215                 send_cmd(CMD_SET_COLUMN | x, chip);
00216                 read_byte(chip | WBF_MODE_DATA);        // dummy read, absolutely needed
00217                 chr = read_byte(chip | WBF_MODE_DATA);
00218                 send_cmd(CMD_SET_COLUMN | x, chip);
00219                 write_byte(chr | buffer[cnt], chip | WBF_MODE_DATA);
00220         }
00221 }
00222 
00226 void lcd_h_line(uint8_t x1, uint8_t x2, uint8_t y)
00227 {
00228         uint8_t chip, posi, mask, chr;
00229         
00230         mask = 1 << (y & 0x07);
00231         send_all_cmd(CMD_SET_PAGE | (y >> 3));
00232         if (x1 < 64) {
00233                 chip = WBF_MASTER;
00234                 posi = x1;
00235                 send_cmd(CMD_SET_COLUMN | 0, WBF_SLAVE);
00236         } else {
00237                 chip = WBF_SLAVE;
00238                 posi = x1-64;
00239         }
00240         send_cmd(CMD_SET_COLUMN | posi, chip);
00241         
00242         while (x1 <= x2) {
00243                 if (x1 == 64) {
00244                         chip = WBF_SLAVE;
00245                         posi = 0;
00246                 }
00247                 send_cmd(CMD_SET_COLUMN | x1, chip);
00248                 read_byte(chip | WBF_MODE_DATA);        // dummy read
00249                 chr = read_byte(chip | WBF_MODE_DATA);
00250                 send_cmd(CMD_SET_COLUMN | x1, chip);
00251                 write_byte(chr | mask, chip | WBF_MODE_DATA);
00252                 posi++;
00253                 x1++;
00254         }
00255 }
00256 
00262 void lcd_put_image(uint8_t x, uint8_t y, PGM_P image)
00263 {
00264         uint8_t chip, cnt, posi, w;
00265         uint8_t width, height;
00266         
00267         y = y >> 3;
00268         width = PRG_RDB(image++);
00269         height = PRG_RDB(image++);
00270         
00271         for (cnt=0; cnt<height; cnt++) {
00272                 posi = x;
00273                 
00274                 if (posi < 64) {
00275                         chip = WBF_MASTER;
00276                         send_cmd(CMD_SET_COLUMN | posi, WBF_MASTER);
00277                         send_cmd(CMD_SET_COLUMN | 0, WBF_SLAVE);
00278                 } else {
00279                         chip = WBF_SLAVE;
00280                         send_cmd(CMD_SET_COLUMN | (posi-64), WBF_SLAVE);
00281                 }
00282                 send_all_cmd(CMD_SET_PAGE | (y+cnt));
00283         
00284                 w = width;      
00285                 while (w--) {
00286                         if (posi == 64) chip = WBF_SLAVE;
00287                         write_byte(pgm_read_byte(image++), chip | WBF_MODE_DATA);
00288                         posi++;
00289                 }
00290         }
00291 }
00292 
00296 void lcd_clear_line(uint8_t x1, uint8_t x2, uint8_t y)
00297 {
00298         uint8_t chip;
00299         
00300         send_all_cmd(CMD_SET_PAGE | (y >> 3));
00301         if (x1 < 64) {
00302                 chip = WBF_MASTER;
00303                 send_cmd(CMD_SET_COLUMN | x1, WBF_MASTER);
00304                 send_cmd(CMD_SET_COLUMN | 0, WBF_SLAVE);
00305         } else {
00306                 chip = WBF_SLAVE;
00307                 send_cmd(CMD_SET_COLUMN | (x1-64), WBF_SLAVE);
00308         }
00309         
00310         while (x1 <= x2) {
00311                 if (x1 == 64) chip = WBF_SLAVE;
00312                 x1++;
00313                 write_byte(0, chip | WBF_MODE_DATA);
00314         }
00315 }
00316 
00320 void lcd_clear(void)
00321 {
00322         uint8_t page_cnt, col_cnt;
00323         
00324         for (page_cnt = 0; page_cnt < 8; page_cnt++) {
00325                 send_all_cmd(CMD_SET_PAGE | page_cnt);
00326                 send_all_cmd(CMD_SET_COLUMN | 0);
00327                 for (col_cnt = 0; col_cnt < 64; col_cnt++)
00328                         write_byte(0x00, WBF_MASTER | WBF_SLAVE | WBF_MODE_DATA);
00329         }
00330 }
00331 
00335 void lcd_init(void)
00336 {
00337         // hw-reset
00338         sbi(RES_PORT, RES_BIT);
00339         delay(1000);
00340         cbi(RES_PORT, RES_BIT);
00341         delay(1000);
00342         sbi(RES_PORT, RES_BIT);
00343         delay(1000);
00344         
00345         lcd_clear();
00346 }
00347 
00351 void lcd_activate(void)
00352 {
00353         sbi(LED_PORT, LED_BIT);         // backlight on
00354         send_all_cmd(CMD_DISPLAY_ON);   // show all pixels
00355 }
00356 
00360 void lcd_deactivate(void)
00361 {
00362         cbi(LED_PORT, LED_BIT);         // backlight off
00363         send_all_cmd(CMD_DISPLAY_OFF);  // enter power save mode
00364 }
00365 
00369 void lcd_enable_backlight(void)
00370 {
00371         sbi(LED_PORT, LED_BIT);
00372 }
00373 
00377 void lcd_disable_backlight(void)
00378 {
00379         cbi(LED_PORT, LED_BIT);
00380 }

Generated on Thu Oct 16 13:13:41 2003 for OpenHomeMainPanel by doxygen 1.3.3