Files
LCD2USB/firmware/main.c
T
2016-01-12 20:42:20 +01:00

242 lines
6.1 KiB
C

/* Name: main.c
* Project: LCD2USB; lcd display interface based on AVR USB driver
* Author: Till Harbaum
* Creation Date: 2006-01-20
* Tabsize: 4
* Copyright: (c) 2005 by Till Harbaum <till@harbaum.org>
* License: GPL
* This Revision: $Id: main.c,v 1.2 2007/01/14 12:12:27 harbaum Exp $
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include "lcd.h"
// use avrusb library
#include "usbdrv.h"
#include "oddebug.h"
#define VERSION_MAJOR 1
#define VERSION_MINOR 9
#define VERSION_STR "1.09"
// change USB_CFG_DEVICE_VERSION in usbconfig.h as well
// EEMEM wird bei aktuellen Versionen der avr-lib in eeprom.h definiert
// hier: definiere falls noch nicht bekannt ("alte" avr-libc)
#ifndef EEMEM
// alle Textstellen EEMEM im Quellcode durch __attribute__ ... ersetzen
#define EEMEM __attribute__ ((section (".eeprom")))
#endif
/* bitmask of detected lcd controllers */
uchar controller = 0;
/* ------------------------------------------------------------------------- */
/* PWM units are used for contrast and backlight brightness */
/* contrast and brightness are stored in eeprom */
uchar eeprom_valid EEMEM;
uchar eeprom_contrast EEMEM;
uchar eeprom_brightness EEMEM;
void pwm_init(void) {
/* check if eeprom is valid and set default values if not */
/* initial values: full contrast and full brightness */
if(eeprom_read_byte(&eeprom_valid) != 0x42) {
/* write magic "eeprom is valid" marker 0x42 and default values */
eeprom_write_byte(&eeprom_valid, 0x42);
eeprom_write_byte(&eeprom_contrast, 0xff);
eeprom_write_byte(&eeprom_brightness, 0xff);
}
/* PortB: set DDB1 and DDB2 => PORTB1 and PORTB2 are output */
DDRB |= _BV(1) | _BV(2);
/* Set Timer1:
- Fast PWM,8bit => Mode 5 (WGM13=0,WGM12=1,WGM11=0,WGM10=1)
- Output-Mode: lower voltage is higher contrast
=> Set OC1A on Compare Match, clear OC1A at BOTTOM, (inverting mode)
COM1A1=1,COM1A0=1
higher voltage is higher brightness
=> Clear OC1B on Compare Match, set OC1B at BOTTOM, (non-inverting mode)
COM1B1=1,COM1B0=0
- Timer runs at inernal clock with no prescaling => CS12=0,CS11=0,CS10=1
*/
TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM10);
TCCR1B = _BV(WGM12) | _BV(CS10);
TIMSK &=( (~_BV(2)) & (~_BV(3)) & (~_BV(4)) & (~_BV(5)));
OCR1A = eeprom_read_byte(&eeprom_contrast);
OCR1B = eeprom_read_byte(&eeprom_brightness);
}
void set_contrast(uchar value) {
/* store value in eeprom if it actually changed */
if(value != eeprom_read_byte(&eeprom_contrast))
eeprom_write_byte(&eeprom_contrast, value);
OCR1A = value; // lower voltage is higher contrast
}
void set_brightness(uchar value) {
/* store value in eeprom if it actually changed */
if(value != eeprom_read_byte(&eeprom_brightness))
eeprom_write_byte(&eeprom_brightness, value);
OCR1B = value; // higher voltage is higher brightness
}
/* ------------------------------------------------------------------------- */
uchar usbFunctionSetup(uchar data[8]) {
static uchar replyBuf[4];
usbMsgPtr = replyBuf;
uchar len = (data[1] & 3)+1; // 1 .. 4 bytes
uchar target = (data[1] >> 3) & 3; // target 0 .. 3
uchar i;
// request byte:
// 7 6 5 4 3 2 1 0
// C C C T T R L L
// TT = target bit map
// R = reserved for future use, set to 0
// LL = number of bytes in transfer - 1
switch(data[1] >> 5) {
case 0: // echo (for transfer reliability testing)
replyBuf[0] = data[2];
replyBuf[1] = data[3];
return 2;
break;
case 1: // command
target &= controller; // mask installed controllers
if(target) // at least one controller should be used ...
for(i=0;i<len;i++)
lcd_command(target, data[2+i]);
break;
case 2: // data
target &= controller; // mask installed controllers
if(target) // at least one controller should be used ...
for(i=0;i<len;i++)
lcd_data(target, data[2+i]);
break;
case 3: // set
switch(target) {
case 0: // contrast
set_contrast(data[2]);
break;
case 1: // brightness
set_brightness(data[2]);
break;
default:
// must not happen ...
break;
}
break;
case 4: // get
switch(target) {
case 0: // version
replyBuf[0] = VERSION_MAJOR;
replyBuf[1] = VERSION_MINOR;
return 2;
break;
case 1: // keys
replyBuf[0] = ((PINC & _BV(5))?0:1) |
((PINB & _BV(0))?0:2);
replyBuf[1] = 0;
return 2;
break;
case 2: // controller map
replyBuf[0] = controller;
replyBuf[1] = 0;
return 2;
break;
default:
// must not happen ...
break;
}
break;
default:
// must not happen ...
break;
}
return 0; // reply len
}
/* ------------------------------------------------------------------------- */
int main(void) {
wdt_enable(WDTO_1S);
/* let debug routines init the uart if they want to */
odDebugInit();
/* all outputs except INT0 and RxD/TxD */
DDRD = ~(_BV(2) | _BV(1) | _BV(0));
PORTD = 0;
PORTC = 0; /* no pullups on USB pins */
DDRC = ~0; /* output SE0 for USB reset */
/* USB Reset by device only required on Watchdog Reset */
_delay_loop_2(40000); // 10ms
DDRC = ~USBMASK; /* all outputs except USB data */
usbInit();
pwm_init();
DDRC &= ~_BV(5); /* input S1 */
PORTC |= _BV(5); /* with pullup */
DDRB &= ~_BV(0); /* input S2 */
PORTB |= _BV(0); /* with pullup */
/* try to init two controllers */
if(lcd_init(LCD_CTRL_0)) controller |= LCD_CTRL_0;
if(lcd_init(LCD_CTRL_1)) controller |= LCD_CTRL_1;
/* put string to display (line 1) with linefeed */
if(controller & LCD_CTRL_0)
lcd_puts(LCD_CTRL_0, "LCD2USB V" VERSION_STR);
if(controller & LCD_CTRL_1)
lcd_puts(LCD_CTRL_1, "2nd ctrl");
if((controller & LCD_CTRL_0) && (controller & LCD_CTRL_1))
lcd_puts(LCD_CTRL_0 | LCD_CTRL_1, " both!");
sei();
for(;;) { /* main event loop */
wdt_reset();
usbPoll();
}
return 0;
}
/* ------------------------------------------------------------------------- */