/* * Wi-Fi Detector opensource firmware * LCD support * * Copyright (C) 2007 Michael Buesch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "lcd.h" #include "main.h" #include "util.h" #include "font.h" #include #include #include /* LCD hardware definitions */ #define LCD_PORT PORTC #define LCD_DDR DDRC #define LCD_CLK (1 << 0) /* clock */ #define LCD_DTA (1 << 1) /* data */ #define LCD_RS (1 << 2) /* register select */ #define LCD_CS (1 << 3) /* chip select */ #define LCD_RST (1 << 4) /* reset */ #define LCD_BACKL_PORT PORTD /* Backlight */ #define LCD_BACKL_DDR DDRD #define LCD_BACKLIGHT (1 << 4) /* LCD commands */ #define LCD_CMD_LINE(nr) (0xB0 + (nr)) /* The LCD data buffer */ uint8_t lcd_buffer[LCD_BUFFER_SIZE]; uint16_t lcd_cursor; static void lcd_write(uint8_t data) { uint8_t i = 8; LCD_PORT |= LCD_DTA; LCD_PORT |= LCD_CLK; LCD_PORT &= ~LCD_CS; do { if (data & 0x80) LCD_PORT |= LCD_DTA; else LCD_PORT &= ~LCD_DTA; LCD_PORT &= ~LCD_CLK; LCD_PORT |= LCD_CLK; udelay(1); LCD_PORT &= ~LCD_CLK; data <<= 1; } while (--i); LCD_PORT |= LCD_CS; } static void lcd_command(uint8_t command) { LCD_PORT &= ~LCD_RS; lcd_write(command); } static void lcd_data(uint8_t data) { LCD_PORT |= LCD_RS; lcd_write(data); } void lcd_clear_buffer(void) { memset(lcd_buffer, 0, LCD_BUFFER_SIZE); lcd_cursor = 0; } void lcd_commit(void) { uint8_t i, j; uint8_t *d; for (i = 0; i < 4; i++) { lcd_command(LCD_CMD_LINE(i)); d = &lcd_buffer[i * LCD_NR_COLUMNS]; lcd_command(0x12); lcd_command(0x04); for (j = 0; j < LCD_NR_COLUMNS; j++) lcd_data(d[j]); } } void lcd_char_out(uint8_t c) { uint8_t pixel_col; uint8_t i; uint16_t cursor; for (i = 0; i < LCD_PIXCOLS_PER_CHAR; i++) { pixel_col = pgm_read_byte(&font_table[c][i]); cursor = lcd_cursor; lcd_buffer[cursor] = pixel_col; if (cursor == LCD_BUFFER_SIZE - 1) lcd_cursor = 0; else lcd_cursor++; } } void printmem(const char *string, uint8_t length) { uint8_t c, i; for (i = 0; i < length; i++) { c = string[i]; lcd_char_out(c); } } void printee(const eeprom_char *eeprom_string) { uint8_t c; const eeprom_uint8_t *p = (const eeprom_uint8_t *)eeprom_string; for ( ; ; p++) { c = eeprom_read8(p); if (c == '\0') break; lcd_char_out(c); } } void print(const prog_char *flash_string) { uint8_t c; for ( ; ; flash_string++) { c = pgm_read_byte(flash_string); if (c == '\0') break; lcd_char_out(c); } } void printhex(uint8_t number) { lcd_char_out(hexdigit_to_ascii((number & 0xF0) >> 4)); lcd_char_out(hexdigit_to_ascii(number & 0x0F)); } void printdec(uint16_t number) { uint8_t num[NUM16_NR_DIGITS + 1]; uint8_t i, c; num16_to_ascii(num, number); for (i = 0; i < ARRAY_SIZE(num); i++) { c = num[i]; if (c == '\0') break; lcd_char_out(c); } } void lcd_backlight_on(void) { /* This is called from IRQ and non-IRQ context, * so we must make sure this is atomic. */ LCD_BACKL_PORT |= LCD_BACKLIGHT; } void lcd_backlight_off(void) { /* This is called from IRQ and non-IRQ context, * so we must make sure this is atomic. */ LCD_BACKL_PORT &= ~LCD_BACKLIGHT; } void lcd_init(void) { LCD_BACKL_DDR |= LCD_BACKLIGHT; lcd_backlight_off(); LCD_DDR |= LCD_CLK | LCD_DTA | LCD_RS | LCD_CS | LCD_RST; LCD_PORT |= (LCD_CS | LCD_CLK | LCD_DTA | LCD_RS); /* Reset the LCD module */ LCD_PORT &= ~LCD_RST; mdelay(100); LCD_PORT |= LCD_RST; mdelay(50); /* Initialize it */ lcd_command(0xE2); lcd_command(0xAB); lcd_command(0xC8); lcd_command(0x40); lcd_command(LCD_CMD_LINE(0)); lcd_command(0x10); lcd_command(0x00); lcd_command(0xA1); lcd_command(0xA6); lcd_command(0xA2); lcd_command(0x2F); lcd_command(0x24); lcd_command(0x81); lcd_command(0x00); lcd_clear_buffer(); lcd_commit(); lcd_command(0xAF); }