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

252 lines
7.4 KiB
C

// ==============================================================================
// gnusbcore.c
// globals and utilities for gnusbCore - 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).
// usb2dmx is also distributed under this enhanced licence. See Documentation.
//
// target-cpu: ATMega16 @ 12MHz
// created 2007-01-28 Michael Egger me@anyma.ch
//
// ==============================================================================
// includes
// ------------------------------------------------------------------------------
// AVR Libc (see http://www.nongnu.org/avr-libc/)
#include <avr/io.h> // include I/O definitions (port names, pin names, etc)
#include <avr/interrupt.h> // include interrupt support
#include <avr/pgmspace.h>
#include <avr/wdt.h> // include watchdog timer support
#include <avr/sleep.h> // include cpu sleep support
// USB driver by Objective Development (see http://www.obdev.at/products/avrusb/index.html)
#include "usbdrv.h"
// local includes
#include "gnusb.h" // gnusb setup and utility functions
// ==============================================================================
// - sleepIfIdle
// ------------------------------------------------------------------------------
void sleepIfIdle()
{
if(TIFR & BV(TOV1)) {
cli();
if(!(GIFR & BV(INTF1))) {
// no activity on INT1 pin for >3ms => suspend:
// - reconfigure INT1 to level-triggered and enable for wake-up
cbi(MCUCR, ISC10);
sbi(GICR, INT1);
// -------------- go to sleep
//cbi(ADCSRA, ADIE); // disable ADC interrupts
// cbi(ADCSRA, ADEN); // disable ADC (turn off ADC power)
PORTA = 0; // pull all pins low
PORTB = 0;
PORTC = 0;
PORTD = 0x60; // except LEDs - they light if pin is low...
wdt_disable();
sleep_enable();
sei();
sleep_cpu();
// -------------- wake up
sleep_disable();
// - reconfigure INT1 to any edge for SE0-detection
cbi(GICR, INT1);
sbi(MCUCR, ISC10);
// - re-enable watchdog
wdt_reset();
wdt_enable(WDTO_1S);
// sbi(ADCSRA, ADIE); // enable ADC interrupts
// sbi(ADCSRA, ADEN); // enable ADC
PORTD = 0x70; // set Pullup for Bootloader Jumper, no pullups on USB pins -> 0111 0000
ledOn(STATUS_LED_GREEN);
}
sei();
// clear INT1 flag
sbi(GIFR, INTF1);
// reload timer and clear overflow
TCCR1B = 1;
TCNT1 = 25000; // max ca. 3ms between SE0
sbi(TIFR, TOV1);
}
}
// ------------------------------------------------------------------------------
// - INT1_vec (dummy for wake-up)
// ------------------------------------------------------------------------------
ISR(INT1_vect) {}
// ------------------------------------------------------------------------------
// - Write to EEPROM
// ------------------------------------------------------------------------------
// from PowerSwitch by Objective Development
void eepromWrite(unsigned char addr, unsigned char val)
{
while(EECR & (1 << EEWE));
EEARL = addr;
EEDR = val;
cli();
EECR |= 1 << EEMWE;
EECR |= 1 << EEWE; /* must follow within a couple of cycles -- therefore cli() */
sei();
}
// ------------------------------------------------------------------------------
// - Read EEPROM
// ------------------------------------------------------------------------------
// from PowerSwitch by Objective Development
uchar eepromRead(uchar addr)
{
while(EECR & (1 << EEWE));
EEARL = addr;
EECR |= 1 << EERE;
return EEDR;
}
// ------------------------------------------------------------------------------
// - Status Leds
// ------------------------------------------------------------------------------
// (on means set to 0 as we sink the LEDs )
void ledOff(uchar led) {
PORTD |= 1 << led;
}
void ledOn(uchar led){
PORTD &= ~(1 << led);
}
void ledToggle(uchar led){
PORTD ^= 1 << led;
}
// ------------------------------------------------------------------------------
// - ADC Utilities
// ------------------------------------------------------------------------------
int ad_ConversionComplete (void) {
return (!(ADCSRA & (1 << ADSC)));
}
int ad_Read10bit (void) {
return (ADCL | ADCH << 8);
}
int ad_Read8bit (void) {
return ad_Read10bit() >> 2;
}
void ad_SetChannel (uchar mux) {
ADMUX = (ADMUX & ~ADC_MUX_MASK) | (mux & ADC_MUX_MASK); // set channel
}
void ad_StartConversion () {
ADCSRA |= (1 << ADIF); // clear hardware "conversion complete" flag
ADCSRA |= (1 << ADSC); // start conversion
}
// ------------------------------------------------------------------------------
// - USB Reset
// ------------------------------------------------------------------------------
// Set USB- and USB+ Pins to output and pull them low for more than 10ms
void usbReset(void) {
u08 i, j;
USBOUT &= ~USBMASK; // make sure USB pins are pulled low
USBDDR |= USBMASK; // set USB pins to output -> SE0
j = 0;
while(--j) {
i = 0;
while(--i); // delay >10ms for USB reset
}
USBDDR &= ~USBMASK; // set USB pins to input
}
// ==============================================================================
// - Init hardware
// ------------------------------------------------------------------------------
void initCoreHardware(void)
{
// --------------------- Init AD Converter
sbi(ADCSRA, ADEN); // enable ADC (turn on ADC power)
cbi(ADCSRA, ADATE); // default to single sample convert mode
// Set ADC-Prescaler (-> precision vs. speed)
ADCSRA = ((ADCSRA & ~ADC_PRESCALE_MASK) | ADC_PRESCALE_DIV64);
sbi(ADMUX,REFS0);cbi(ADMUX,REFS1); // Set ADC Reference Voltage to AVCC
cbi(ADCSRA, ADLAR); // set to right-adjusted result
// sbi(ADCSRA, ADIE); // enable ADC interrupts
cbi(ADCSRA, ADIE); // disable ADC interrupts
// --------------------- Init USB
// set PORT D Directions -> 1110 0000, output 0 on unconnected PD7
DDRD = 0xe0; // 1110 0000 -> set PD0..PD4 to inputs -> USB pins
PORTD = 0x70; // set Pullup for Bootloader Jumper, no pullups on USB pins -> 0111 0000
usbDeviceConnect();
wdt_enable(WDTO_1S); // enable watchdog timer
usbReset();
usbInit();
// --------------------- Init Sleep
// init Timer 1 and Interrupt 1 for usb activity detection:
// - set INT1 to any edge (polled by sleepIfIdle())
cbi(MCUCR, ISC11);
sbi(MCUCR, ISC10);
// set sleep mode to full power-down for minimal consumption
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// - set Timer 1 prescaler to 64 and restart timer
TCCR1B = 3;
TCNT1 = 0;
sbi(TIFR, TOV1);
sei(); // turn on interrupts
}
// ------------------------------------------------------------------------------
// - Start Bootloader
// ------------------------------------------------------------------------------
// dummy function doing the jump to bootloader section (Adress 1C00 on Atmega16)
void (*jump_to_bootloader)(void) = 0x1C00; __attribute__ ((unused))
void startBootloader(void) {
eepromWrite(UBOOT_SOFTJUMPER_ADDRESS,UBOOT_SOFTJUMPER); // set software jumper
cli(); // turn off interrupts
wdt_disable(); // disable watchdog timer
usbDeviceDisconnect(); // disconnect gnusb from USB bus
cbi(ADCSRA, ADIE); // disable ADC interrupts
cbi(ADCSRA, ADEN); // disable ADC (turn off ADC power)
PORTA = 0; // pull all pins low
PORTB = 0;
PORTC = 0;
jump_to_bootloader();
}