David Voswinkel aedc6dab5b o add gnususb as reference bootloader
o refactor boot loader  cpde
o
2009-05-06 23:55:56 +02:00

201 lines
6.6 KiB
C

// ==============================================================================
// main.c
// firmware for a device based on the gnusb - OPEN SOURCE USB SENSOR BOX
//
// License:
// The project is built with AVR USB driver by Objective Development, which is
// published under an own licence based on the GNU General Public License (GPL).
// gnusb is also distributed under this enhanced licence. See Documentation.
//
// target-cpu: ATMega16 @ 12MHz
// created 2007-01-28 Michael Egger me@anyma.ch
//
// ==============================================================================
#include "gnusb.h" // the gnusb library: setup and utility functions
// ==============================================================================
// Constants
// ------------------------------------------------------------------------------
#define ADC_PAUSE 10 // number of passes before we sample the next AD channel
#define LED_KEEP_ALIVE 100 // number of passes before usb status led turns off
#define USB_REPLY_PORTB 8 // Values of portb gets stored into 9th byte of usb_reply (counting from 0)
#define USB_REPLY_PORTC 9
// ==============================================================================
// Globals
// ------------------------------------------------------------------------------
static u08 ad_mux; // current ad input channel
static u16 ad_values[8]; // sampled ad input values
static u08 ad_smoothing; // smoothing level of ad samples (0 - 15)
static u08 ad_samplepause; // counts up to ADC_PAUSE between samples
static u08 usb_reply[12]; // 8 bytes AD Values (8 most significant bits)
// 1 byte PORTB
// 1 byte PORTC
// 2 bytes least significant bits of AD values
// ------------------------------------------------------------------------------
// - usbFunctionSetup
// ------------------------------------------------------------------------------
// this function gets called when the usb driver receives a non standard request
// that is: our own requests defined in ../common/gnusb_cmds.h
// here's where the magic happens...
uchar usbFunctionSetup(uchar data[8])
{
switch (data[1]) {
// ---------------------------- get all values
case GNUSB_CMD_POLL:
usbMsgPtr = usb_reply;
return sizeof(usb_reply);
break;
// ---------------------------- set smoothing
case GNUSB_CMD_SET_SMOOTHING:
if (data[2] > 15) ad_smoothing = 15;
else ad_smoothing = data[2];
break;
// ---------------------------- output one byte on PORTB
case GNUSB_CMD_SET_PORTB:
DDRB = 0xff; // set PORTB to output
PORTB = data[2]; // output values
usb_reply[USB_REPLY_PORTB] = data[2]; // mirror data in next poll
break;
// ---------------------------- output one byte on PORTC
case GNUSB_CMD_SET_PORTC:
DDRC = 0xff; // set PORTC to output
PORTC = data[2]; // output values
usb_reply[USB_REPLY_PORTC] = data[2]; // mirror data in next poll
break;
// ---------------------------- set PORTB to input
case GNUSB_CMD_INPUT_PORTB:
DDRB = 0x00;
break;
// ---------------------------- set PORTC to input
case GNUSB_CMD_INPUT_PORTC:
DDRC = 0x00;
break;
// ---------------------------- Start Bootloader for reprogramming the gnusb
case GNUSB_CMD_START_BOOTLOADER:
startBootloader();
break;
default:
break;
}
return 0;
}
// ------------------------------------------------------------------------------
// - Check ADC and update ad_values
// ------------------------------------------------------------------------------
void checkAnlogPorts (void) {
unsigned int temp,replymask,replyshift,replybyte;
if (ad_samplepause != 0xff) {
if (ad_samplepause < ADC_PAUSE) {
ad_samplepause++; // advance pause counter
} else {
ad_StartConversion(); // start a new conversion
ad_samplepause = 0xff; // indicate we're waiting for a result now
}
} else {
if ( ad_ConversionComplete() ) { // see if AD-Conversion is complete
temp = ad_Read10bit(); // read ADC (10 bits);
// basic low pass filter
ad_values[ad_mux] = (ad_values[ad_mux] * ad_smoothing + temp) / (ad_smoothing + 1);
usb_reply[ad_mux] = ad_values[ad_mux] >> 2; // copy 8 most significant bits to usb reply
// if you don't need 10bit precision you can leave out the following stuff
replybyte = 10 + (ad_mux / 4); // are we writing to byte 10 or 11?
replyshift = ((ad_mux % 4) * 2); // how much to shift the bits
replymask = (3 << replyshift); // create bitmask
// write bits to the right place
usb_reply[replybyte] =
(usb_reply[replybyte] & ~replymask) | (replymask & (ad_values[ad_mux] << replyshift));
ad_mux = (ad_mux + 1) % 8; // advance multiplexer index
ad_SetChannel(ad_mux); // set mutliplexer channel
ad_samplepause = 0; // start counting up to ADC_PAUSE in order to let the input settle a bit
}
}
}
// ------------------------------------------------------------------------------
// - Check PORT B and PORT C
// ------------------------------------------------------------------------------
void checkDigitalPorts(void) {
// copy state of pins to usb reply, only if the port is configured as an input
if (DDRB == 0x00) usb_reply[USB_REPLY_PORTB] = PINB;
if (DDRC == 0x00) usb_reply[USB_REPLY_PORTC] = PINC;
}
// ==============================================================================
// - main
// ------------------------------------------------------------------------------
int main(void)
{
// ------------------------- Initialize Hardware
// PORTA: AD Converter
DDRA = 0x00; // set all pins to input
PORTA = 0x00; // make sure pull-up resistors are turned off
// PORTB: Default Input
DDRB = 0x00; // set all pins to input
PORTB = 0xff; // make sure pull-up resistors are turned ON
// PORTC: Default output
DDRC = 0xff; // set all pins to output
PORTC = 0xff; // turn off all leds
// PORTD: gnusbCore stuff: USB, status leds, jumper
initCoreHardware();
ledOn(STATUS_LED_GREEN);
// ------------------------- Main Loop
while(1) {
wdt_reset(); // reset Watchdog timer - otherwise Watchdog will reset gnusb
sleepIfIdle(); // go to low power mode if host computer is sleeping
usbPoll(); // see if there's something going on on the usb bus
checkAnlogPorts(); // see if we've finished an analog-digital conversion
checkDigitalPorts(); // have a look at PORTB and PORTC
}
return 0;
}