2006-05-01 19:19:59 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
*
|
|
|
|
* AVRPROG compatible boot-loader
|
2006-05-22 14:17:47 +02:00
|
|
|
* Version : 0.80beta (May 2006)
|
2006-05-20 00:30:03 +02:00
|
|
|
* Compiler : avr-gcc 3.4.6 / avr-libc 1.4.4
|
2006-05-01 19:19:59 +02:00
|
|
|
* size : depends on features and startup ( minmal features < 512 words)
|
|
|
|
* by : Martin Thomas, Kaiserslautern, Germany
|
|
|
|
* eversmith@heizung-thomas.de
|
2006-05-22 14:17:47 +02:00
|
|
|
* Additional code and improvements contributed by:
|
|
|
|
* - Uwe Bonnes
|
|
|
|
* - Bjoern Riemer
|
|
|
|
* - Olaf Rempel
|
2006-05-01 19:19:59 +02:00
|
|
|
*
|
2006-05-22 14:17:47 +02:00
|
|
|
* License : Copyright (c) 2006 Martin Thomas
|
2006-05-19 21:00:23 +02:00
|
|
|
* Free to use. You have to mention the copyright
|
|
|
|
* owners in source-code and documentation of derived
|
2006-05-22 14:17:47 +02:00
|
|
|
* work. No warranty!
|
2006-05-01 19:20:40 +02:00
|
|
|
*
|
|
|
|
* Tested with ATmega8, ATmega16, ATmega32, ATmega128, AT90CAN128
|
2006-05-01 19:19:59 +02:00
|
|
|
*
|
2006-05-22 14:17:47 +02:00
|
|
|
* - Initial versions have been based on the Butterfly bootloader-code
|
|
|
|
* by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM)
|
2006-05-01 19:19:59 +02:00
|
|
|
*
|
|
|
|
****************************************************************************
|
|
|
|
*
|
2006-05-19 21:00:23 +02:00
|
|
|
* See the makefile for information how to adopt the linker-settings to
|
2006-05-20 00:30:03 +02:00
|
|
|
* the selected Boot Size (BOOTSIZE=xxxx), the AVR clock-frequency and the
|
|
|
|
* MCU-type in
|
2006-05-01 19:19:59 +02:00
|
|
|
*
|
2006-05-20 00:30:03 +02:00
|
|
|
* With BOOT_SIMPLE this bootloader has
|
|
|
|
* 0x2EA - atmega8
|
|
|
|
* 0x368 - atmega16
|
|
|
|
* 0x382 - atmega169
|
|
|
|
* 0x368 - atmega32
|
|
|
|
* 0x360 - atmega128
|
|
|
|
* 0x372 - at90can128
|
|
|
|
* bytes size and should fit into a 512word bootloader-section.
|
2006-05-01 19:19:59 +02:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
/*
|
|
|
|
Does not work reliably so far:
|
|
|
|
- lock bits set
|
|
|
|
*/
|
|
|
|
|
|
|
|
// programmers-notepad tabsize 4
|
|
|
|
#define VERSION_HIGH '0'
|
|
|
|
#define VERSION_LOW '7'
|
|
|
|
|
2006-05-19 22:19:18 +02:00
|
|
|
/* MCU frequency */
|
|
|
|
#define F_CPU 7372800
|
|
|
|
|
|
|
|
/* UART Baudrate */
|
|
|
|
#define BAUDRATE 115200
|
|
|
|
|
|
|
|
/* use "Double Speed Operation" */
|
|
|
|
//#define UART_DOUBLESPEED
|
|
|
|
|
|
|
|
/* use second UART on mega128 / can128 */
|
|
|
|
//#define UART_USE_SECOND
|
|
|
|
|
2006-05-20 00:30:03 +02:00
|
|
|
/*
|
|
|
|
* Pin "STARTPIN" on port "STARTPORT" in this port has to grounded
|
|
|
|
* (active low) to start the bootloader
|
|
|
|
*/
|
|
|
|
#define BLPORT PORTB
|
|
|
|
#define BLDDR DDRB
|
|
|
|
#define BLPIN PINB
|
|
|
|
#define BLPNUM PINB0
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Select startup-mode
|
|
|
|
* SIMPLE-Mode - Jump to bootloader main BL-loop if key is
|
|
|
|
* pressed (Pin grounded) "during" reset or jump to the
|
|
|
|
* application if the pin is not grounded (=pulled up by
|
|
|
|
* internal pull-up-resistor)
|
|
|
|
* POWERSAVE-Mode - Startup is separated in two loops
|
|
|
|
* which makes power-saving a little easier if no firmware
|
|
|
|
* is on the chip. Needs more memory
|
|
|
|
* BOOTICE-Mode - to flash the JTAGICE upgrade.ebn file.
|
|
|
|
* No startup-sequence in this mode. Jump directly to the
|
|
|
|
* parser-loop on reset
|
|
|
|
* F_CPU in BOOTICEMODE must be 7372800 Hz to be compatible
|
|
|
|
* with the org. JTAGICE-Firmware
|
|
|
|
* WAIT-mode waits 1 sec for the S command if nothing is recived
|
|
|
|
* then the user prog is started ..
|
|
|
|
*/
|
|
|
|
#define START_SIMPLE
|
|
|
|
//#define START_WAIT
|
|
|
|
//#define START_POWERSAVE
|
|
|
|
//#define START_BOOTICE
|
|
|
|
|
|
|
|
/*
|
|
|
|
* enable/disable readout of fuse and lock-bits
|
|
|
|
* (will not work for Mega169 since not supported by AVRPROG 1.37
|
|
|
|
*/
|
|
|
|
//#define ENABLEREADFUSELOCK
|
|
|
|
|
|
|
|
/* enable/disable write of lock-bits
|
|
|
|
* WARNING: lock-bits can not be reseted by bootloader (as far as I know)
|
|
|
|
* Only protection no unprotection, "chip erase" from bootloader only
|
|
|
|
* clears the flash but does no real "chip erase" (this is not possible
|
|
|
|
* with a bootloader as far as I know)
|
|
|
|
* Keep this undefined!
|
|
|
|
*/
|
|
|
|
//#define WRITELOCKBITS
|
|
|
|
|
2006-05-20 00:04:32 +02:00
|
|
|
#include <stdint.h>
|
2006-05-01 19:19:59 +02:00
|
|
|
#include <avr/io.h>
|
|
|
|
#include <avr/wdt.h>
|
|
|
|
#include <avr/boot.h>
|
|
|
|
#include <avr/pgmspace.h>
|
|
|
|
|
|
|
|
#include "chipdef.h"
|
|
|
|
|
2006-05-20 00:06:27 +02:00
|
|
|
uint8_t gBuffer[SPM_PAGESIZE];
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-26 19:31:18 +02:00
|
|
|
static void sendchar(uint8_t data)
|
2006-05-19 22:19:18 +02:00
|
|
|
{
|
2006-05-26 19:29:55 +02:00
|
|
|
while (!(UART_STATUS & (1<<UART_TXREADY)));
|
2006-05-19 22:19:18 +02:00
|
|
|
UART_DATA = data;
|
|
|
|
}
|
|
|
|
|
2006-05-26 19:31:18 +02:00
|
|
|
static uint8_t recvchar(void)
|
2006-05-19 22:19:18 +02:00
|
|
|
{
|
2006-05-26 19:29:55 +02:00
|
|
|
while (!(UART_STATUS & (1<<UART_RXREADY)));
|
2006-05-19 22:19:18 +02:00
|
|
|
return UART_DATA;
|
|
|
|
}
|
|
|
|
|
2006-05-20 00:06:27 +02:00
|
|
|
static inline void eraseFlash(void)
|
2006-05-19 21:52:00 +02:00
|
|
|
{
|
2006-05-20 00:06:27 +02:00
|
|
|
// erase only main section (bootloader protection)
|
|
|
|
uint32_t addr = 0;
|
|
|
|
while (APP_END > addr) {
|
|
|
|
boot_page_erase(addr); // Perform page erase
|
|
|
|
boot_spm_busy_wait(); // Wait until the memory is erased.
|
|
|
|
addr += SPM_PAGESIZE;
|
|
|
|
}
|
|
|
|
boot_rww_enable();
|
|
|
|
}
|
2006-05-19 21:52:00 +02:00
|
|
|
|
2006-05-20 00:06:27 +02:00
|
|
|
static inline void recvBuffer(pagebuf_t size)
|
|
|
|
{
|
|
|
|
pagebuf_t cnt;
|
2006-05-26 19:33:50 +02:00
|
|
|
uint8_t *tmp = gBuffer;
|
|
|
|
|
|
|
|
for (cnt = 0; cnt < sizeof(gBuffer); cnt++)
|
|
|
|
*tmp++ = (cnt < size) ? recvchar() : 0xFF;
|
2006-05-19 21:52:00 +02:00
|
|
|
}
|
|
|
|
|
2006-05-20 00:06:27 +02:00
|
|
|
static inline uint16_t writeFlashPage(uint16_t waddr, pagebuf_t size)
|
|
|
|
{
|
2006-05-26 19:26:19 +02:00
|
|
|
uint32_t pagestart = (uint32_t)waddr<<1;
|
2006-05-20 00:06:27 +02:00
|
|
|
uint32_t baddr = pagestart;
|
|
|
|
uint16_t data;
|
2006-05-26 19:33:50 +02:00
|
|
|
uint8_t *tmp = gBuffer;
|
2006-05-20 00:06:27 +02:00
|
|
|
|
|
|
|
do {
|
2006-05-26 19:33:50 +02:00
|
|
|
data = *tmp++;
|
|
|
|
data |= *tmp++ << 8;
|
2006-05-20 00:06:27 +02:00
|
|
|
boot_page_fill(baddr, data); // call asm routine.
|
|
|
|
|
|
|
|
baddr += 2; // Select next word in memory
|
|
|
|
size -= 2; // Reduce number of bytes to write by two
|
|
|
|
} while (size); // Loop until all bytes written
|
|
|
|
|
|
|
|
boot_page_write(pagestart);
|
|
|
|
boot_spm_busy_wait();
|
|
|
|
boot_rww_enable(); // Re-enable the RWW section
|
|
|
|
|
|
|
|
return baddr>>1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t writeEEpromPage(uint16_t address, pagebuf_t size)
|
|
|
|
{
|
2006-05-26 19:33:50 +02:00
|
|
|
uint8_t *tmp = gBuffer;
|
2006-05-20 00:06:27 +02:00
|
|
|
|
|
|
|
do {
|
|
|
|
EEARL = address; // Setup EEPROM address
|
|
|
|
EEARH = (address >> 8);
|
2006-05-26 19:33:50 +02:00
|
|
|
EEDR = *tmp++;
|
2006-05-20 00:06:27 +02:00
|
|
|
address++; // Select next byte
|
|
|
|
|
|
|
|
EECR |= (1<<EEMWE); // Write data into EEPROM
|
|
|
|
EECR |= (1<<EEWE);
|
|
|
|
eeprom_busy_wait();
|
|
|
|
|
|
|
|
size--; // Decreas number of bytes to write
|
|
|
|
} while (size); // Loop until all bytes written
|
|
|
|
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t readFlashPage(uint16_t waddr, pagebuf_t size)
|
2006-05-19 21:52:00 +02:00
|
|
|
{
|
2006-05-26 19:26:19 +02:00
|
|
|
uint32_t baddr = (uint32_t)waddr<<1;
|
2006-05-20 00:04:32 +02:00
|
|
|
uint16_t data;
|
2006-05-19 21:52:00 +02:00
|
|
|
|
2006-05-20 00:06:27 +02:00
|
|
|
do {
|
2006-05-19 21:52:00 +02:00
|
|
|
#if defined(RAMPZ)
|
2006-05-20 00:06:27 +02:00
|
|
|
data = pgm_read_word_far(baddr);
|
2006-05-19 21:52:00 +02:00
|
|
|
#else
|
2006-05-20 00:06:27 +02:00
|
|
|
data = pgm_read_word_near(baddr);
|
2006-05-19 21:52:00 +02:00
|
|
|
#endif
|
2006-05-20 00:06:27 +02:00
|
|
|
sendchar(data); // send LSB
|
|
|
|
sendchar((data >> 8)); // send MSB
|
|
|
|
baddr += 2; // Select next word in memory
|
|
|
|
size -= 2; // Subtract two bytes from number of bytes to read
|
|
|
|
} while (size); // Repeat until all block has been read
|
|
|
|
|
|
|
|
return baddr>>1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t readEEpromPage(uint16_t address, pagebuf_t size)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
EEARL = address; // Setup EEPROM address
|
|
|
|
EEARH = (address >> 8);
|
|
|
|
EECR |= (1<<EERE); // Read EEPROM
|
|
|
|
address++; // Select next EEPROM byte
|
|
|
|
|
|
|
|
sendchar(EEDR); // Transmit EEPROM data to PC
|
|
|
|
|
|
|
|
size--; // Decrease number of bytes to read
|
|
|
|
} while (size); // Repeat until all block has been read
|
|
|
|
|
|
|
|
return address;
|
2006-05-19 21:52:00 +02:00
|
|
|
}
|
|
|
|
|
2006-05-26 19:37:18 +02:00
|
|
|
static uint8_t read_fuse_lock(uint16_t addr)
|
2006-05-19 21:52:00 +02:00
|
|
|
{
|
2006-05-26 19:37:18 +02:00
|
|
|
uint8_t mode = (1<<BLBSET) | (1<<SPMEN);
|
2006-05-20 00:04:32 +02:00
|
|
|
uint8_t retval;
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
asm volatile
|
|
|
|
(
|
2006-05-26 19:37:18 +02:00
|
|
|
"movw r30, %3\n\t" /* Z to addr */ \
|
|
|
|
"sts %0, %2\n\t" /* set mode in SPM_REG */ \
|
|
|
|
"lpm\n\t" /* load fuse/lock value into r0 */ \
|
|
|
|
"mov %1,r0\n\t" /* save return value */ \
|
2006-05-19 21:52:00 +02:00
|
|
|
: "=m" (SPM_REG),
|
|
|
|
"=r" (retval)
|
|
|
|
: "r" (mode),
|
|
|
|
"r" (addr)
|
|
|
|
: "r30", "r31", "r0"
|
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2006-05-26 19:31:18 +02:00
|
|
|
static void send_boot(void)
|
2006-05-01 19:19:59 +02:00
|
|
|
{
|
|
|
|
sendchar('A');
|
|
|
|
sendchar('V');
|
|
|
|
sendchar('R');
|
|
|
|
sendchar('B');
|
|
|
|
sendchar('O');
|
|
|
|
sendchar('O');
|
|
|
|
sendchar('T');
|
|
|
|
}
|
|
|
|
|
2006-05-26 19:31:18 +02:00
|
|
|
static void (*jump_to_app)(void) = 0x0000;
|
2006-05-01 19:19:59 +02:00
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
2006-05-20 00:06:27 +02:00
|
|
|
uint16_t address = 0;
|
|
|
|
uint8_t device = 0, val;
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#ifdef START_POWERSAVE
|
2006-05-20 00:04:32 +02:00
|
|
|
uint8_t OK = 1;
|
2006-05-19 21:52:00 +02:00
|
|
|
#endif
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
BLDDR &= ~(1<<BLPNUM); // set as Input
|
2006-05-01 19:19:59 +02:00
|
|
|
BLPORT |= (1<<BLPNUM); // Enable pullup
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 22:19:18 +02:00
|
|
|
// Set baud rate
|
|
|
|
UART_BAUD_HIGH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
|
|
|
|
UART_BAUD_LOW = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
|
|
|
|
|
|
|
|
#ifdef UART_DOUBLESPEED
|
|
|
|
UART_STATUS = UART_DOUBLE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
UART_CTRL = UART_CTRL_DATA;
|
|
|
|
UART_CTRL2 = UART_CTRL2_DATA;
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#ifdef START_POWERSAVE
|
2006-05-19 21:00:23 +02:00
|
|
|
/*
|
2006-05-01 19:19:59 +02:00
|
|
|
This is an adoption of the Butterfly Bootloader startup-sequence.
|
|
|
|
It may look a little strange but separating the login-loop from
|
|
|
|
the main parser-loop gives a lot a possibilities (timeout, sleep-modes
|
|
|
|
etc.).
|
2006-05-19 21:00:23 +02:00
|
|
|
*/
|
2006-05-19 21:52:00 +02:00
|
|
|
for(;OK;) {
|
|
|
|
if ((BLPIN & (1<<BLPNUM))) {
|
2006-05-01 19:19:59 +02:00
|
|
|
// jump to main app if pin is not grounded
|
2006-05-19 21:52:00 +02:00
|
|
|
BLPORT &= ~(1<<BLPNUM); // set to default
|
|
|
|
jump_to_app(); // Jump to application sector
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
} else {
|
2006-05-26 19:26:19 +02:00
|
|
|
val = recvchar();
|
2006-05-19 21:52:00 +02:00
|
|
|
/* ESC */
|
|
|
|
if (val == 0x1B) {
|
|
|
|
// AVRPROG connection
|
|
|
|
// Wait for signon
|
|
|
|
while (val != 'S')
|
2006-05-26 19:26:19 +02:00
|
|
|
val = recvchar();
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
send_boot(); // Report signon
|
2006-05-01 19:19:59 +02:00
|
|
|
OK = 0;
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
} else {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('?');
|
2006-05-19 21:52:00 +02:00
|
|
|
}
|
2006-05-01 19:19:59 +02:00
|
|
|
}
|
|
|
|
// Power-Save code here
|
|
|
|
}
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#elif defined(START_SIMPLE)
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
if ((BLPIN & (1<<BLPNUM))) {
|
|
|
|
// jump to main app if pin is not grounded
|
|
|
|
BLPORT &= ~(1<<BLPNUM); // set to default
|
|
|
|
jump_to_app(); // Jump to application sector
|
2006-05-01 19:19:59 +02:00
|
|
|
}
|
2006-05-01 19:20:40 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#elif defined(START_WAIT)
|
2006-05-19 21:00:23 +02:00
|
|
|
|
|
|
|
// Timer-Setup for ATmega8
|
2006-05-01 19:20:40 +02:00
|
|
|
// - verify that the configuration is valid for the target AVR
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-01 19:20:40 +02:00
|
|
|
#define MY_WAIT 900
|
|
|
|
// wait ca 1 sec (900ms)
|
|
|
|
TCCR1A = 0; // timer setup
|
|
|
|
// F_OSC / 8 / 1000 -> 1ms
|
2006-05-19 22:19:18 +02:00
|
|
|
#if (((F_CPU / 8 / 1000)*MY_WAIT) < 65535)
|
2006-05-01 19:20:40 +02:00
|
|
|
#warning Information: setting prescaler to 8
|
2006-05-19 22:19:18 +02:00
|
|
|
#define WAIT_VALUE ((F_CPU / 8 / 1000)*MY_WAIT)
|
2006-05-26 19:29:55 +02:00
|
|
|
TCCR1B |= (1<<CS01);
|
2006-05-19 22:19:18 +02:00
|
|
|
#elif ((((F_CPU / 64 / 1000)*MY_WAIT) < 65535))
|
2006-05-01 19:20:40 +02:00
|
|
|
#warning Information: setting prescaler to 64
|
2006-05-19 22:19:18 +02:00
|
|
|
#define WAIT_VALUE ((F_CPU / 64 / 1000)*MY_WAIT)
|
2006-05-26 19:29:55 +02:00
|
|
|
TCCR1B |= (1<<CS01) | (1<<CS00);
|
2006-05-19 22:19:18 +02:00
|
|
|
#elif ((((F_CPU / 256 / 1000)*MY_WAIT) < 65535))
|
2006-05-01 19:20:40 +02:00
|
|
|
#warning Information: setting prescaler to 256
|
2006-05-19 22:19:18 +02:00
|
|
|
#define WAIT_VALUE ((F_CPU / 256 / 1000)*MY_WAIT)
|
2006-05-26 19:29:55 +02:00
|
|
|
TCCR1B |= (1<<CS02);
|
2006-05-19 22:19:18 +02:00
|
|
|
#else //((((F_CPU / 1024 / 1000)*MY_WAIT) < 65535))
|
2006-05-01 19:20:40 +02:00
|
|
|
#warning Information: setting prescaler to 1024
|
2006-05-19 22:19:18 +02:00
|
|
|
#define WAIT_VALUE ((F_CPU / 1024 / 1000)*MY_WAIT)
|
2006-05-26 19:29:55 +02:00
|
|
|
TCCR1B |= (1<<CS00) | (1<<CS02); //1024 prescaler
|
2006-05-01 19:20:40 +02:00
|
|
|
#endif
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
while (1) {
|
2006-05-19 22:19:18 +02:00
|
|
|
if (UART_STATUS & (1<<UART_RXREADY)) {
|
|
|
|
if (UART_DATA == 'S')
|
2006-05-01 19:20:40 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (TCNT1 >= WAIT_VALUE){
|
2006-05-19 21:52:00 +02:00
|
|
|
BLPORT &= ~(1<<BLPNUM); // set to default
|
|
|
|
TCCR1B = 0; // timer off
|
|
|
|
jump_to_app(); // Jump to application sector
|
2006-05-01 19:20:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
TCCR1B = 0; // timer off
|
|
|
|
send_boot();
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#elif defined(START_BOOTICE)
|
|
|
|
#warning "BOOTICE mode - no startup-condition"
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
#else
|
|
|
|
#error "Select START_ condition for bootloader in main.c"
|
|
|
|
#endif
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
for(;;) {
|
2006-05-19 22:19:18 +02:00
|
|
|
val = recvchar();
|
2006-05-19 21:52:00 +02:00
|
|
|
// Autoincrement?
|
|
|
|
if (val == 'a') {
|
|
|
|
sendchar('Y'); // Autoincrement is quicker
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
//write address
|
|
|
|
} else if (val == 'A') {
|
2006-05-19 22:19:18 +02:00
|
|
|
address = recvchar(); //read address 8 MSB
|
|
|
|
address = (address<<8) | recvchar();
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('\r');
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Buffer load support
|
|
|
|
} else if (val == 'b') {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('Y'); // Report buffer load supported
|
2006-05-20 00:06:27 +02:00
|
|
|
sendchar((sizeof(gBuffer) >> 8) & 0xFF); // Report buffer size in bytes
|
|
|
|
sendchar(sizeof(gBuffer) & 0xFF);
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Start buffer load
|
|
|
|
} else if (val == 'B') {
|
2006-05-20 00:06:27 +02:00
|
|
|
pagebuf_t size;
|
2006-05-20 00:04:32 +02:00
|
|
|
size = recvchar() << 8; // Load high byte of buffersize
|
|
|
|
size |= recvchar(); // Load low byte of buffersize
|
2006-05-19 22:19:18 +02:00
|
|
|
val = recvchar(); // Load memory type ('E' or 'F')
|
2006-05-20 00:06:27 +02:00
|
|
|
recvBuffer(size);
|
|
|
|
|
|
|
|
if (device == DEVTYPE) {
|
|
|
|
if (val == 'F') {
|
|
|
|
address = writeFlashPage(address, size);
|
|
|
|
|
|
|
|
} else if (val == 'E') {
|
|
|
|
address = writeEEpromPage(address, size);
|
|
|
|
}
|
|
|
|
sendchar('\r');
|
|
|
|
|
|
|
|
} else {
|
|
|
|
sendchar(0);
|
|
|
|
}
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Block read
|
|
|
|
} else if (val == 'g') {
|
2006-05-20 00:06:27 +02:00
|
|
|
pagebuf_t size;
|
2006-05-20 00:04:32 +02:00
|
|
|
size = recvchar() << 8; // Load high byte of buffersize
|
|
|
|
size |= recvchar(); // Load low byte of buffersize
|
2006-05-19 22:19:18 +02:00
|
|
|
val = recvchar(); // Get memtype
|
2006-05-20 00:06:27 +02:00
|
|
|
|
|
|
|
if (val == 'F') {
|
|
|
|
address = readFlashPage(address, size);
|
|
|
|
|
|
|
|
} else if (val == 'E') {
|
|
|
|
address = readEEpromPage(address, size);
|
|
|
|
}
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Chip erase
|
|
|
|
} else if (val == 'e') {
|
2006-05-20 00:06:27 +02:00
|
|
|
if (device == DEVTYPE)
|
|
|
|
eraseFlash();
|
|
|
|
|
2006-05-19 21:00:23 +02:00
|
|
|
sendchar('\r');
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Exit upgrade
|
|
|
|
} else if (val == 'E') {
|
2006-05-01 19:19:59 +02:00
|
|
|
wdt_enable(WDTO_15MS); // Enable Watchdog Timer to give reset
|
|
|
|
sendchar('\r');
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
#ifdef WRITELOCKBITS
|
|
|
|
#warning "Extension 'WriteLockBits' enabled"
|
|
|
|
// TODO: does not work reliably
|
|
|
|
// write lockbits
|
|
|
|
} else if (val == 'l') {
|
2006-05-19 21:52:42 +02:00
|
|
|
if (device == DEVTYPE) {
|
2006-05-26 19:26:19 +02:00
|
|
|
// write_lock_bits(recvchar());
|
|
|
|
boot_lock_bits_set(recvchar()); // boot.h takes care of mask
|
2006-05-01 19:19:59 +02:00
|
|
|
boot_spm_busy_wait();
|
|
|
|
}
|
|
|
|
sendchar('\r');
|
2006-05-19 21:52:00 +02:00
|
|
|
#endif
|
|
|
|
// Enter programming mode
|
|
|
|
} else if (val == 'P') {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('\r');
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Leave programming mode
|
|
|
|
} else if (val == 'L') {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('\r');
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// return programmer type
|
|
|
|
} else if (val == 'p') {
|
|
|
|
sendchar('S'); // always serial programmer
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-01 19:19:59 +02:00
|
|
|
#ifdef ENABLEREADFUSELOCK
|
|
|
|
#warning "Extension 'ReadFuseLock' enabled"
|
2006-05-19 21:52:00 +02:00
|
|
|
// read "low" fuse bits
|
|
|
|
} else if (val == 'F') {
|
2006-05-26 19:37:18 +02:00
|
|
|
sendchar(read_fuse_lock(GET_LOW_FUSE_BITS));
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
// read lock bits
|
|
|
|
} else if (val == 'r') {
|
2006-05-26 19:37:18 +02:00
|
|
|
sendchar(read_fuse_lock(GET_LOCK_BITS));
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
// read high fuse bits
|
|
|
|
} else if (val == 'N') {
|
2006-05-26 19:37:18 +02:00
|
|
|
sendchar(read_fuse_lock(GET_HIGH_FUSE_BITS));
|
2006-05-19 21:52:00 +02:00
|
|
|
|
|
|
|
// read extended fuse bits
|
|
|
|
} else if (val == 'Q') {
|
2006-05-26 19:37:18 +02:00
|
|
|
sendchar(read_fuse_lock(GET_EXTENDED_FUSE_BITS));
|
2006-05-19 21:00:23 +02:00
|
|
|
#endif
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Return device type
|
|
|
|
} else if (val == 't') {
|
2006-05-19 21:52:42 +02:00
|
|
|
sendchar(DEVTYPE);
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar(0);
|
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// clear and set LED ignored
|
|
|
|
} else if ((val == 'x') || (val == 'y')) {
|
2006-05-19 22:19:18 +02:00
|
|
|
recvchar();
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('\r');
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// set device
|
|
|
|
} else if (val == 'T') {
|
2006-05-19 22:19:18 +02:00
|
|
|
device = recvchar();
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('\r');
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Return software identifier
|
|
|
|
} else if (val == 'S') {
|
2006-05-01 19:19:59 +02:00
|
|
|
send_boot();
|
2006-05-19 21:00:23 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Return Software Version
|
|
|
|
} else if (val == 'V') {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar(VERSION_HIGH);
|
|
|
|
sendchar(VERSION_LOW);
|
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
// Return Signature Byte
|
|
|
|
} else if (val == 's') {
|
2006-05-19 21:52:42 +02:00
|
|
|
sendchar(SIG_BYTE1);
|
|
|
|
sendchar(SIG_BYTE2);
|
|
|
|
sendchar(SIG_BYTE3);
|
2006-05-01 19:19:59 +02:00
|
|
|
|
2006-05-19 21:52:00 +02:00
|
|
|
/* ESC */
|
|
|
|
} else if(val != 0x1b) {
|
2006-05-01 19:19:59 +02:00
|
|
|
sendchar('?');
|
|
|
|
}
|
|
|
|
}
|
2006-05-19 21:52:00 +02:00
|
|
|
return 0;
|
2006-05-01 19:19:59 +02:00
|
|
|
}
|