Merge branch 'mega88'

This commit is contained in:
Olaf Rempel 2010-08-15 16:47:01 +02:00
commit 525c2e3701
2 changed files with 267 additions and 117 deletions

View File

@ -1,14 +1,27 @@
PRG = twiboot PRG = twiboot
OBJ = main.o OBJ = main.o
MCU_TARGET = atmega8 MCU_TARGET = atmega88
OPTIMIZE = -Os OPTIMIZE = -Os
DEFS = ifeq ($(MCU_TARGET), atmega8)
BOOTLOADER_START=0x1C00
AVRDUDE_MCU=m8
endif
ifeq ($(MCU_TARGET), atmega88)
BOOTLOADER_START=0x1C00
AVRDUDE_MCU=m88
endif
ifeq ($(MCU_TARGET), atmega168)
BOOTLOADER_START=0x3C00
AVRDUDE_MCU=m168
endif
DEFS = -DAPP_END=$(BOOTLOADER_START)
LIBS = LIBS =
# Override is only needed by avr-lib build system. # Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS = -Wl,-Map,$(PRG).map,--section-start=.text=0x1C00 override LDFLAGS = -Wl,-Map,$(PRG).map,--section-start=.text=$(BOOTLOADER_START)
CC = avr-gcc CC = avr-gcc
OBJCOPY = avr-objcopy OBJCOPY = avr-objcopy
@ -21,6 +34,9 @@ all: $(PRG).elf lst text
$(PRG).elf: $(OBJ) $(PRG).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
%.o: %.c $(MAKEFILE_LIST)
$(CC) $(CFLAGS) -c $< -o $@
clean: clean:
rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin rm -rf *.o *.lst *.map $(PRG).elf *.hex *.bin
@ -41,4 +57,9 @@ bin: $(PRG).bin
$(OBJCOPY) -j .text -j .data -O binary $< $@ $(OBJCOPY) -j .text -j .data -O binary $< $@
install: text install: text
uisp -dprog=avr910 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=M8 --erase --upload if=$(PRG).hex avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) -U flash:w:$(PRG).hex
fuses:
avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) -U lfuse:w:0xc2:m
avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) -U hfuse:w:0xdd:m
avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) -U efuse:w:0xfa:m

355
main.c
View File

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 09/2007 by Olaf Rempel * * Copyright (C) 08/2010 by Olaf Rempel *
* razzor@kopf-tisch.de * * razzor@kopf-tisch.de *
* * * *
* This program is free software; you can redistribute it and/or modify * * This program is free software; you can redistribute it and/or modify *
@ -24,65 +24,133 @@
#define F_CPU 8000000 #define F_CPU 8000000
#include <util/delay.h> #include <util/delay.h>
/*
* atmega8:
* Fuse E: 0xfa (512 words bootloader)
* Fuse H: 0xdd (2.7V BOD)
* Fuse L: 0xc2 (8Mhz internal RC-Osz.)
*
* atmega88:
* Fuse E: 0xfa (512 words bootloader)
* Fuse H: 0xdd (2.7V BOD)
* Fuse L: 0xc2 (8Mhz internal RC-Osz.)
*
* atmega168:
* Fuse E: 0xfa (512 words bootloader)
* Fuse H: 0xdd (2.7V BOD)
* Fuse L: 0xc2 (8Mhz internal RC-Osz.)
*/
#if defined (__AVR_ATmega8__)
#define VERSION_STRING "TWIBOOT m8v2.0"
#define SIGNATURE_BYTES 0x1E, 0x93, 0x07
#elif defined (__AVR_ATmega88__)
#define VERSION_STRING "TWIBOOT m88v2.0"
#define SIGNATURE_BYTES 0x1E, 0x93, 0x0A
#elif defined (__AVR_ATmega168__)
#define VERSION_STRING "TWIBOOT m168v2.0"
#define SIGNATURE_BYTES 0x1E, 0x94, 0x06
#else
#error MCU not supported
#endif
/* 25ms @8MHz */
#define TIMER_RELOAD (0xFF - 195)
/* 40 * 25ms */
#define TIMEOUT 40
#define LED_RT (1<<PORTB4) #define LED_RT (1<<PORTB4)
#define LED_GN (1<<PORTB5) #define LED_GN (1<<PORTB5)
#define TWI_ADDRESS 0x21 #define TWI_ADDRESS 0x21
#define COOKIE 0x4711 /* SLA+R */
#define APP_END 0x1C00
#define CMD_WAIT 0x00 #define CMD_WAIT 0x00
#define CMD_GET_INFO 0x10 #define CMD_READ_VERSION 0x01
#define CMD_GET_SIGNATURE 0x11 #define CMD_READ_MEMORY 0x02
#define CMD_WRITE_FLASH 0x12 /* internal mappings */
#define CMD_READ_FLASH 0x13 #define CMD_READ_CHIPINFO (0x10 | CMD_READ_MEMORY)
#define CMD_WRITE_EEPROM 0x14 #define CMD_READ_FLASH (0x20 | CMD_READ_MEMORY)
#define CMD_READ_EEPROM 0x15 #define CMD_READ_EEPROM (0x30 | CMD_READ_MEMORY)
#define CMD_BOOT_APPLICATION 0x1F #define CMD_READ_PARAMETERS (0x40 | CMD_READ_MEMORY) /* only in APP */
/* SLA+W */
#define CMD_SWITCH_APPLICATION CMD_READ_VERSION
#define CMD_WRITE_MEMORY CMD_READ_MEMORY
/* internal mappings */
#define CMD_BOOT_BOOTLOADER (0x10 | CMD_SWITCH_APPLICATION) /* only in APP */
#define CMD_BOOT_APPLICATION (0x20 | CMD_SWITCH_APPLICATION)
#define CMD_WRITE_CHIPINFO (0x10 | CMD_WRITE_MEMORY) /* invalid */
#define CMD_WRITE_FLASH (0x20 | CMD_WRITE_MEMORY)
#define CMD_WRITE_EEPROM (0x30 | CMD_WRITE_MEMORY)
#define CMD_WRITE_PARAMETERS (0x40 | CMD_WRITE_MEMORY) /* only in APP */
/* CMD_SWITCH_APPLICATION parameter */
#define BOOTTYPE_BOOTLOADER 0x00 /* only in APP */
#define BOOTTYPE_APPLICATION 0x80
/* CMD_{READ|WRITE}_* parameter */
#define MEMTYPE_CHIPINFO 0x00
#define MEMTYPE_FLASH 0x01
#define MEMTYPE_EEPROM 0x02
#define MEMTYPE_PARAMETERS 0x03 /* only in APP */
/* /*
* LED on PORTB4 blinks with 20Hz (while bootloader is running) * LED_GN blinks with 20Hz (while bootloader is running)
* LED on PORTB5 blinks on TWI activity * LED_RT blinks on TWI activity
*
* Fuse H: 0xda (512 words bootloader)
* Fuse L: 0x84 (8Mhz internal RC-Osz., 2.7V BOD)
* *
* bootloader twi-protocol: * bootloader twi-protocol:
* - get info about bootloader: * - abort boot timeout:
* SLA+W, 0x10, SLA+R, {16 bytes}, STO * SLA+W, 0x00, STO
* *
* - get signature bytes: * - show bootloader version
* SLA+W, 0x11, SLA+R, {4 bytes}, STO * SLA+W, 0x01, SLA+R, {16 bytes}, STO
* *
* - write one flash page (64bytes on mega8) * - start application
* SLA+W, 0x12, addrh, addrl, 0x47, 0x11, {64 bytes}, STO * SLA+W, 0x01, 0x80, STO
*
* - read chip info: 3byte signature, 1byte page size, 2byte flash size, 2byte eeprom size
* SLA+W, 0x02, 0x00, SLA+R, {4 bytes}, STO
* *
* - read one (or more) flash bytes * - read one (or more) flash bytes
* SLA+W, 0x13, addrh, addrl, SLA+R, {* bytes}, STO * SLA+W, 0x02, 0x01, addrh, addrl, SLA+R, {* bytes}, STO
*
* - write one (or more) eeprom bytes
* SLA+W, 0x14, addrh, addrl, 0x47, 0x11, {* bytes}, STO
* *
* - read one (or more) eeprom bytes * - read one (or more) eeprom bytes
* SLA+W, 0x15, addrh, addrl, SLA+R, {* bytes}, STO * SLA+W, 0x02, 0x02, addrh, addrl, SLA+R, {* bytes}, STO
* *
* - boot application * - write one flash page (64bytes on mega8)
* SLA+W, 0x1F, STO * SLA+W, 0x02, 0x01, addrh, addrl, {64 bytes}, STO
*
* - write one (or more) eeprom bytes
* SLA+W, 0x02, 0x02, addrh, addrl, {* bytes}, STO
*/ */
const static uint8_t info[16] = "TWIBOOT m8-v1.2"; const static uint8_t info[16] = VERSION_STRING;
const static uint8_t signature[4] = { 0x1E, 0x93, 0x07, 0x00 }; const static uint8_t chipinfo[8] = {
SIGNATURE_BYTES,
SPM_PAGESIZE,
(APP_END >> 8) & 0xFF,
APP_END & 0xFF,
(E2END >> 8 & 0xFF),
E2END & 0xFF
};
/* wait 40 * 25ms = 1s */ /* wait 40 * 25ms = 1s */
static uint8_t boot_timeout = 40; static uint8_t boot_timeout = TIMEOUT;
volatile static uint8_t cmd = CMD_WAIT; volatile static uint8_t cmd = CMD_WAIT;
/* flash buffer */ /* flash buffer */
static uint8_t buf[SPM_PAGESIZE]; static uint8_t buf[SPM_PAGESIZE];
static uint16_t addr; static uint16_t addr;
void write_flash_page(void) static void write_flash_page(void)
{ {
uint16_t pagestart = addr; uint16_t pagestart = addr;
uint8_t size = SPM_PAGESIZE; uint8_t size = SPM_PAGESIZE;
@ -108,21 +176,36 @@ void write_flash_page(void)
boot_rww_enable(); boot_rww_enable();
} }
void write_eeprom_byte(uint8_t val) static uint8_t read_eeprom_byte(void)
{
EEARL = addr;
EEARH = (addr >> 8);
EECR |= (1<<EERE);
addr++;
return EEDR;
}
static void write_eeprom_byte(uint8_t val)
{ {
EEARL = addr; EEARL = addr;
EEARH = (addr >> 8); EEARH = (addr >> 8);
EEDR = val; EEDR = val;
addr++; addr++;
#if defined (__AVR_ATmega8__)
EECR |= (1<<EEMWE); EECR |= (1<<EEMWE);
EECR |= (1<<EEWE); EECR |= (1<<EEWE);
#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
#endif
eeprom_busy_wait(); eeprom_busy_wait();
} }
ISR(TWI_vect) ISR(TWI_vect)
{ {
static uint8_t bcnt = 0; static uint8_t bcnt;
uint8_t data;
uint8_t ack = (1<<TWEA);
switch (TWSR & 0xF8) { switch (TWSR & 0xF8) {
/* SLA+W received, ACK returned -> receive data and ACK */ /* SLA+W received, ACK returned -> receive data and ACK */
@ -134,64 +217,95 @@ ISR(TWI_vect)
/* prev. SLA+W, data received, ACK returned -> receive data and ACK */ /* prev. SLA+W, data received, ACK returned -> receive data and ACK */
case 0x80: case 0x80:
if (bcnt == 0) { data = TWDR;
cmd = TWDR; switch (bcnt) {
switch (cmd) { case 0:
case CMD_GET_INFO: switch (data) {
case CMD_GET_SIGNATURE: case CMD_SWITCH_APPLICATION:
case CMD_WRITE_FLASH: case CMD_WRITE_MEMORY:
case CMD_READ_FLASH: bcnt++;
case CMD_WRITE_EEPROM: /* no break */
case CMD_READ_EEPROM:
case CMD_WAIT:
/* abort countdown */ /* abort countdown */
boot_timeout = 0; boot_timeout = 0;
break;
case CMD_BOOT_APPLICATION: default:
/* boot app now */
data = CMD_BOOT_APPLICATION;
ack = (0<<TWEA);
break;
}
cmd = data;
break;
case 1:
switch (cmd) {
case CMD_SWITCH_APPLICATION:
if (data == BOOTTYPE_APPLICATION) {
cmd = CMD_BOOT_APPLICATION;
}
ack = (0<<TWEA);
break;
case CMD_WRITE_MEMORY:
bcnt++;
if (data == MEMTYPE_CHIPINFO) {
cmd = CMD_WRITE_CHIPINFO;
} else if (data == MEMTYPE_FLASH) {
cmd = CMD_WRITE_FLASH;
} else if (data == MEMTYPE_EEPROM) {
cmd = CMD_WRITE_EEPROM;
} else {
ack = (0<<TWEA);
}
break;
default:
ack = (0<<TWEA);
break;
}
break;
case 2:
case 3:
addr <<= 8;
addr |= data;
bcnt++;
break;
default:
switch (cmd) {
case CMD_WRITE_FLASH:
buf[bcnt -4] = data;
if (bcnt < sizeof(buf) +3) {
bcnt++;
} else {
write_flash_page();
ack = (0<<TWEA);
}
break;
case CMD_WRITE_EEPROM:
write_eeprom_byte(data);
bcnt++; bcnt++;
break; break;
default: default:
cmd = CMD_WAIT; ack = (0<<TWEA);
bcnt = 0;
break; break;
} }
break;
} else if (bcnt == 1) {
addr = (TWDR << 8);
bcnt++;
} else if (bcnt == 2) {
addr |= TWDR;
bcnt++;
} else if (bcnt == 3) {
if (TWDR == (COOKIE >> 8))
bcnt++;
else
bcnt = 0;
} else if (bcnt == 4) {
if (TWDR == (COOKIE & 0xFF))
bcnt++;
else
bcnt = 0;
} else if (bcnt >= 5 && cmd == CMD_WRITE_FLASH) {
buf[bcnt -5] = TWDR;
if (bcnt < sizeof(buf) +4) {
bcnt++;
} else {
write_flash_page();
bcnt = 0;
}
} else if (bcnt >= 5 && cmd == CMD_WRITE_EEPROM) {
write_eeprom_byte(TWDR);
bcnt++;
} }
TWCR |= (1<<TWINT) | (1<<TWEA); if (ack == 0x00)
bcnt = 0;
TWCR |= (1<<TWINT) | ack;
break; break;
/* SLA+R received, ACK returned -> send data */ /* SLA+R received, ACK returned -> send data */
@ -202,33 +316,30 @@ ISR(TWI_vect)
/* prev. SLA+R, data sent, ACK returned -> send data */ /* prev. SLA+R, data sent, ACK returned -> send data */
case 0xB8: case 0xB8:
switch (cmd) { switch (cmd) {
case CMD_GET_INFO: case CMD_READ_VERSION:
TWDR = info[bcnt++]; data = info[bcnt++];
bcnt %= sizeof(info); bcnt %= sizeof(info);
break; break;
case CMD_GET_SIGNATURE: case CMD_READ_CHIPINFO:
TWDR = signature[bcnt++]; data = chipinfo[bcnt++];
bcnt %= sizeof(signature); bcnt %= sizeof(chipinfo);
break; break;
case CMD_READ_FLASH: case CMD_READ_FLASH:
TWDR = pgm_read_byte_near(addr++); data = pgm_read_byte_near(addr++);
break; break;
case CMD_READ_EEPROM: case CMD_READ_EEPROM:
EEARL = addr; data = read_eeprom_byte();
EEARH = (addr >> 8);
EECR |= (1<<EERE);
addr++;
TWDR = EEDR;
break; break;
default: default:
TWDR = 0xFF; data = 0xFF;
break; break;
} }
TWDR = data;
TWCR |= (1<<TWINT) | (1<<TWEA); TWCR |= (1<<TWINT) | (1<<TWEA);
break; break;
@ -249,8 +360,8 @@ ISR(TWI_vect)
ISR(TIMER0_OVF_vect) ISR(TIMER0_OVF_vect)
{ {
/* come back in 25ms (@8MHz) */ /* restart timer */
TCNT0 = 0xFF - 195; TCNT0 = TIMER_RELOAD;
/* blink LED while running */ /* blink LED while running */
PORTB ^= LED_GN; PORTB ^= LED_GN;
@ -264,22 +375,41 @@ ISR(TIMER0_OVF_vect)
cmd = CMD_BOOT_APPLICATION; cmd = CMD_BOOT_APPLICATION;
} }
static void (*jump_to_app)(void) = 0x0000; static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
/*
* For newer devices (mega88) the watchdog timer remains active even after a
* system reset. So disable it as soon as possible.
* automagically called on startup
*/
#if defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
void disable_wdt_timer(void)
{
MCUSR = 0;
WDTCSR = (1<<WDCE) | (1<<WDE);
WDTCSR = (0<<WDE);
}
#endif
int main(void) __attribute__ ((noreturn));
int main(void) int main(void)
{ {
DDRB = LED_GN | LED_RT; DDRB = LED_GN | LED_RT;
PORTB = LED_GN; PORTB = LED_GN;
/* move interrupt-vectors to bootloader */ /* move interrupt-vectors to bootloader */
GICR = (1<<IVCE); MCUCR = (1<<IVCE);
GICR = (1<<IVSEL); MCUCR = (1<<IVSEL);
/* timer0: running with F_CPU/1024 */ /* timer0: running with F_CPU/1024, OVF interrupt */
#if defined (__AVR_ATmega8__)
TCCR0 = (1<<CS02) | (1<<CS00); TCCR0 = (1<<CS02) | (1<<CS00);
TIMSK = (1<<TOIE0);
/* enable timer0 OVF interrupt */ #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
TIMSK |= (1<<TOIE0); TCCR0B = (1<<CS02) | (1<<CS00);
TIMSK0 = (1<<TOIE0);
#endif
/* TWI init: set address, auto ACKs with interrupts */ /* TWI init: set address, auto ACKs with interrupts */
TWAR = (TWI_ADDRESS<<1); TWAR = (TWI_ADDRESS<<1);
@ -293,20 +423,19 @@ int main(void)
TWCR = 0x00; TWCR = 0x00;
/* disable timer0 */ /* disable timer0 */
TIMSK = 0x00; #if defined (__AVR_ATmega8__)
TCCR0 = 0x00; TCCR0 = 0x00;
TIMSK = 0x00;
#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
TIMSK0 = 0x00;
TCCR0B = 0x00;
#endif
/* move interrupt vectors back to application */ /* move interrupt vectors back to application */
GICR = (1<<IVCE); MCUCR = (1<<IVCE);
GICR = (0<<IVSEL); MCUCR = (0<<IVSEL);
PORTB = 0x00; PORTB = 0x00;
_delay_ms(25);
_delay_ms(25);
_delay_ms(25);
_delay_ms(25);
jump_to_app(); jump_to_app();
return 0;
} }