X-Git-Url: http://git.tdb.fi/?p=model-railway-devices.git;a=blobdiff_plain;f=firmware%2Flcd.c;h=6ba00d54a913c01ba6f2aac24a05f708a40c2a7e;hp=8c722d8d29e7e9150d83c76ee9eb63f04e22fb2a;hb=238cd5e5bd9c6fa86ae85f5eb7a8ce00158f2f7c;hpb=d8a31ed675778c08ca781beb62863c62d6f0bd94 diff --git a/firmware/lcd.c b/firmware/lcd.c index 8c722d8..6ba00d5 100644 --- a/firmware/lcd.c +++ b/firmware/lcd.c @@ -1,27 +1,70 @@ +/* $Id$ + +This file is part of the MSP Märklin suite +Copyright © 2010 Mikkosoft Productions, Mikko Rasa +Distributed under the GPL + +ATMega pinout (with LCD_SHIFTREG): +B0 - HD44780 RS +B1 - HD44780 clock +B2 - shift reg data +B3 - shift reg clock + +ATMega pinout (without LCD_SHIFTREG): +D4 - HD44780 RS +D5 - HD44780 clock +D6 - HD44780 data 0 +D7 - HD44780 data 1 +B0 - HD44780 data 2 +B1 - HD44780 data 3 +B2 - HD44780 data 4 +B3 - HD44780 data 5 +B4 - HD44780 data 6 +B5 - HD44780 data 7 + +In both cases, HD44780 R/W needs to be connected to ground. +*/ #include -#include +#include "delay.h" +#include "lcd.h" +#include "timer.h" + +#ifdef LCD_SHIFTREG +#define CLOCK_PORT PORTB +#define CLOCK_BIT 0x02 +#define REGSEL_PORT PORTB +#define REGSEL_BIT 0x01 +#else +#define CLOCK_PORT PORTD +#define CLOCK_BIT 0x20 +#define REGSEL_PORT PORTD +#define REGSEL_BIT 0x10 +#endif -#define USE_SHIFTREG 1 +#ifndef LCD_BUFSIZE +#define LCD_BUFSIZE 32 +#endif #define NOP() __asm__("nop") -void lcd_init(void); -void lcd_on(void); -void lcd_clear(void); -void lcd_goto(uint8_t); -void lcd_write(uint8_t); +#ifdef LCD_ASYNC +static volatile uint8_t lcd_busy = 0; +static uint8_t lcd_buffer[LCD_BUFSIZE]; +static volatile uint8_t lcd_buf_head = 0; +static volatile uint8_t lcd_buf_tail = 0; +#endif -void lcd_clock(void) +static void lcd_clock(void) { - _delay_us(1); - PORTB |= 0x02; - _delay_us(1); - PORTB &= ~0x02; + delay_us(1); + CLOCK_PORT |= CLOCK_BIT; + delay_us(1); + CLOCK_PORT &= ~CLOCK_BIT; } -void lcd_set_data(uint8_t d) +static void lcd_set_data(uint8_t d) { -#ifdef USE_SHIFTREG +#ifdef LCD_SHIFTREG uint8_t i; for(i=0; i<8; ++i) { @@ -37,32 +80,100 @@ void lcd_set_data(uint8_t d) #endif } -void lcd_command(uint8_t c) +static void lcd_command(uint8_t c) { - PORTB &= ~0x01; + REGSEL_PORT &= ~REGSEL_BIT; lcd_set_data(c); lcd_clock(); } +static void lcd_delay(uint16_t us) +{ +#ifdef LCD_ASYNC + lcd_busy = 1; + timer_start_us(0, us); +#else + delay_us(us); +#endif +} + +#ifdef LCD_ASYNC +static void lcd_wait(void) +{ + while(lcd_busy) ; +} + +static void lcd_buffer_push(uint8_t byte) +{ + while((lcd_buf_head+1)%sizeof(lcd_buffer)==lcd_buf_tail) ; + lcd_buffer[lcd_buf_head] = byte; + lcd_buf_head = (lcd_buf_head+1)%sizeof(lcd_buffer); +} + +static uint8_t lcd_buffer_pop(void) +{ + uint8_t byte = lcd_buffer[lcd_buf_tail]; + lcd_buf_tail = (lcd_buf_tail+1)%sizeof(lcd_buffer); + return byte; +} + +static void lcd_timer(void) +{ + if(lcd_busy) + { + if(lcd_buf_head!=lcd_buf_tail) + { + uint8_t byte = lcd_buffer_pop(); + if(byte==0xFF) + { + REGSEL_PORT |= REGSEL_BIT; + byte = lcd_buffer_pop(); + } + else if(byte>=0x80) + REGSEL_PORT &= ~REGSEL_BIT; + else + REGSEL_PORT |= REGSEL_BIT; + lcd_set_data(byte); + lcd_clock(); + lcd_delay(50); + } + else + { + lcd_busy = 0; + timer_stop(0); + } + } +} + +TIMER_SET_CALLBACK(0, lcd_timer) +#endif + void lcd_init(void) { +#ifdef LCD_SHIFTREG DDRB |= 0x0F; PORTB &= ~0x0F; - _delay_ms(20); - lcd_command(0x38); - _delay_us(50); -} +#else + DDRD |= 0xF0; + PORTD &= ~0xF0; + DDRB |= 0x3F; + PORTB &= ~0x3F; +#endif -void lcd_on(void) -{ + delay_ms(20); + lcd_command(0x38); + delay_us(50); lcd_command(0x0C); - _delay_us(50); + delay_us(50); } void lcd_clear(void) { +#ifdef LCD_ASYNC + lcd_wait(); +#endif lcd_command(0x01); - _delay_us(1500); + lcd_delay(1700); } void lcd_gotoxy(uint8_t x, uint8_t y) @@ -70,14 +181,33 @@ void lcd_gotoxy(uint8_t x, uint8_t y) uint8_t a = x+10*y; if(y&1) a += 54; + +#ifdef LCD_ASYNC + if(lcd_busy) + { + lcd_buffer_push(a|0x80); + return; + } +#endif + lcd_command(a|0x80); - _delay_us(50); + lcd_delay(50); } void lcd_write(uint8_t c) { - PORTB |= 0x01; +#ifdef LCD_ASYNC + if(lcd_busy) + { + if(c>=0x80) + lcd_buffer_push(0xFF); + lcd_buffer_push(c); + return; + } +#endif + + REGSEL_PORT |= REGSEL_BIT; lcd_set_data(c); lcd_clock(); - _delay_us(50); + lcd_delay(50); }