From 3f5a773ac786443d74352d20c5baecb7ecd75173 Mon Sep 17 00:00:00 2001 From: Olaf Rempel Date: Thu, 2 Feb 2012 21:24:02 +0100 Subject: [PATCH] initial version --- .gitignore | 6 + Makefile | 56 ++++++ main.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 563 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d36148 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.o +*.elf +*.bin +*.hex +*.lst +*.map diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e7243f0 --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +PRG = mpmboot +OBJ = main.o +MCU_TARGET = atmega32 +OPTIMIZE = -Os + +ifeq ($(MCU_TARGET), atmega32) +# hfuse = 0x?A (2k bootloader) +BOOTLOADER_START=0x7800 +AVRDUDE_MCU=m32 +endif + +DEFS = -DBOOTLOADER_START=$(BOOTLOADER_START) +LIBS = + +# Override is only needed by avr-lib build system. +override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) +override LDFLAGS = -Wl,-Map,$(PRG).map,--section-start=.text=$(BOOTLOADER_START) + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size + +all: $(PRG).elf lst text + $(SIZE) -x -A $(PRG).elf + +$(PRG).elf: $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + +%.o: %.c $(MAKEFILE_LIST) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -rf *.o $(PRG).lst $(PRG).map $(PRG).elf $(PRG).hex $(PRG).bin + +lst: $(PRG).lst + +%.lst: %.elf + $(OBJDUMP) -h -S $< > $@ + +text: hex bin + +hex: $(PRG).hex +bin: $(PRG).bin + +%.hex: %.elf + $(OBJCOPY) -j .text -j .data -O ihex $< $@ + +%.bin: %.elf + $(OBJCOPY) -j .text -j .data -O binary $< $@ + +install: text + avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) -V -U flash:w:$(PRG).hex + +reset: + avrdude -c dragon_isp -P usb -p $(AVRDUDE_MCU) diff --git a/main.c b/main.c new file mode 100644 index 0000000..6635b2e --- /dev/null +++ b/main.c @@ -0,0 +1,501 @@ +/*************************************************************************** +* Copyright (C) 01/2012 by Olaf Rempel * +* razzor@kopf-tisch.de * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; version 2 of the License, * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +***************************************************************************/ +#include +#include +#include +#include + +/* +* atmega32: +* Fuse H: 0xda (1024 words bootloader) +* Fuse L: 0xd4 (8Mhz internal RC-Osz.) +*/ + +#if defined (__AVR_ATmega32__) +#define F_CPU 8000000 +#define VERSION_STRING "MPMBOOT m32v1.0" +#define SIGNATURE_BYTES 0x1E, 0x95, 0x02 + +#else +#error MCU not supported +#endif + +/* 25ms @8MHz */ +#define TIMER_RELOAD (0xFF - 195) + +/* 40 * 25ms */ +#define TIMEOUT 40 + +#define LED_INIT() DDRD = (1< * + * rsp: * + * + * device is MPM device address and has 9th bit set, all other + * bytes in request & response have 9th bit NOT set + * + * length is 16bit, MSB first + * + * rsp-cause codes: + * 0x00 - ok + * 0xF0 - command not supported (unknown to bootloader) + * 0xF1 - parameter error (invalid memtype/address) + * 0xFF - unspecified error + * + * CMD switch mode: + * ================ + * req: ,, + * rsp: ,, + * + * mode codes: + * 0x00 - bootloader + * 0x80 - application + * + * CMD get bootloader version: + * =========================== + * req: , + * rsp: ,,, + * + * response data is bootloader version string with implementation specific length + * + * CMD get chip info: + * ================== + * req: , + * rsp: ,,, + * + * CMD read memory: + * ================ + * req: ,,,, + * rsp: ,,, + * + * memtype codes: + * 0x01 - flash memory + * 0x02 - eeprom memory + * + * CMD write memory: + * ================= + * req: ,,,,, + * rsp: ,, + * + * memtype codes: + * 0x01 - flash memory + * 0x02 - eeprom memory + * + */ + +const static uint8_t info[16] = VERSION_STRING; +const static uint8_t chipinfo[8] = { + SIGNATURE_BYTES, + + SPM_PAGESIZE, + + ((BOOTLOADER_START) >> 8) & 0xFF, + (BOOTLOADER_START) & 0xFF, + ((E2END +1) >> 8 & 0xFF), + (E2END +1) & 0xFF +}; + +/* wait 40 * 25ms = 1s */ +static uint8_t boot_timeout = TIMEOUT; +volatile static uint8_t boot_wait = BOOTWAIT_RUNNING; + +static uint8_t rx_addressed; + +static uint16_t rx_bcnt; +static uint8_t rx_cmd; +static uint16_t rx_length; + +static uint16_t tx_bcnt; +static uint8_t tx_cmd; +static uint8_t tx_cause; +static uint16_t tx_length; + +static uint8_t para_mode; +static uint8_t para_memtype; +static uint16_t para_address; +static uint16_t para_size; + +/* flash buffer */ +static uint8_t pagebuf[SPM_PAGESIZE]; + +static void write_flash_page(void) +{ + uint16_t pagestart = para_address; + uint8_t size = SPM_PAGESIZE; + uint8_t *p = pagebuf; + + if (pagestart >= BOOTLOADER_START) + return; + + boot_page_erase(pagestart); + boot_spm_busy_wait(); + + do { + uint16_t data = *p++; + data |= *p++ << 8; + boot_page_fill(para_address, data); + + para_address += 2; + size -= 2; + } while (size); + + boot_page_write(pagestart); + boot_spm_busy_wait(); + boot_rww_enable(); +} + +static uint8_t read_eeprom_byte(void) +{ + EEARL = para_address; + EEARH = (para_address >> 8); + EECR |= (1<> 8); + EEDR = *val++; + para_address++; + para_size--; +#if defined (__AVR_ATmega32__) + EECR |= (1<= 3) && (rx_bcnt <= 7)) + ) { + switch (rx_bcnt) { + case 3: + para_memtype = data; + break; + + case 4: + case 5: + para_address = (para_address << 8) | data; + break; + + case 6: + case 7: + para_size = (para_size << 8) | data; + break; + + default: + break; + } + + } else if ((rx_cmd == CMD_WRITE_MEMORY) && (rx_bcnt > 7) && (rx_bcnt <= (rx_length +2))) { + if ((rx_bcnt -8) < sizeof(pagebuf)) { + pagebuf[(rx_bcnt -8)] = data; + } + } + + if (rx_bcnt == (rx_length +2)) { + /* setup response */ + tx_bcnt = 0; + tx_cmd = rx_cmd; + tx_cause = CAUSE_SUCCESS; + tx_length = 0; + + switch (tx_cmd) { + case CMD_SWITCH_MODE: + if ((para_mode != BOOTMODE_APPLICATION) && (para_mode != BOOTMODE_BOOTLOADER)) { + tx_cause = CAUSE_INVALID_PARAMETER; + } + break; + + case CMD_GET_VERSION: + tx_length = sizeof(info); + break; + + case CMD_GET_CHIPINFO: + tx_length = sizeof(chipinfo); + break; + + case CMD_READ_MEMORY: + tx_length = para_size; + /* no break */ + case CMD_WRITE_MEMORY: + if (para_memtype == MEMTYPE_FLASH) { + /* only access application area */ + if (para_address > (BOOTLOADER_START - SPM_PAGESIZE)) { + tx_length = 0; + tx_cause = CAUSE_INVALID_PARAMETER; + + /* writes must use pagesize */ + } else if (tx_cmd == CMD_WRITE_MEMORY) { + if (para_size == SPM_PAGESIZE) { + write_flash_page(); + + } else { + tx_cause = CAUSE_INVALID_PARAMETER; + } + } + + } else if (para_memtype == MEMTYPE_EEPROM) { + if ((para_address > (E2END +1)) || ((para_address + para_size) > (E2END +1))) { + tx_cause = CAUSE_INVALID_PARAMETER; + + } else if (tx_cmd == CMD_WRITE_MEMORY) { + write_eeprom_page(); + } + + } else { + tx_length = 0; + tx_cause = CAUSE_INVALID_PARAMETER; + } + break; + + default: + tx_cause = CAUSE_NOT_SUPPORTED; + break; + } + + /* kickoff transmit */ + UCSRB |= (1<> 8); + + } else if (tx_bcnt == 3) { + UDR = (tx_length & 0xFF); + + } else if (tx_bcnt < (tx_length +4)) { + uint16_t pos = tx_bcnt -4; + uint8_t data = 0xFF; + + if (tx_cmd == CMD_GET_VERSION) { + data = info[pos]; + + } else if (tx_cmd == CMD_GET_CHIPINFO) { + data = chipinfo[pos]; + + } else if (tx_cmd == CMD_READ_MEMORY) { + if (para_memtype == MEMTYPE_FLASH) { + data = pgm_read_byte_near(para_address); + para_address++; + + } else if (para_memtype == MEMTYPE_EEPROM) { + data = read_eeprom_byte(); + para_address++; + } + } + + UDR = data; + + } else { + /* stop transmit */ + UCSRB &= ~(1<>8) & 0xFF; + UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF); + + /* 11.354ms for 109 bits @9600 */ + /* 946.18us for 109 bits @115200 */ +// uart_send("1234567890"); + + sei(); + + while (boot_wait != BOOTWAIT_EXPIRED); + + cli(); + + /* disable timer0 */ + /* move interrupt vectors back to application */ +#if defined (__AVR_ATmega32__) + TCCR0 = 0x00; + TIMSK = 0x00; + + GICR = (1<