Version 0.2 (20040324)

This commit is contained in:
Olaf Rempel 2006-05-01 19:10:39 +02:00
commit 744684bb88
9 changed files with 1507 additions and 0 deletions

79
bin/m16_uart_boot_3_9.hex Normal file
View File

@ -0,0 +1,79 @@
:103800000C942A1C0C94451C0C94451C0C94451CCF
:103810000C94451C0C94451C0C94451C0C94451CA4
:103820000C94451C0C94451C0C94451C0C94451C94
:103830000C94451C0C94451C0C94451C0C94451C84
:103840000C94451C0C94451C0C94451C0C94451C74
:103850000C94451C11241FBECFE5D4E0DEBFCDBFC4
:1038600010E0A0E6B0E0E4ECFCE302C005900D92AD
:10387000A036B107D9F710E0A0E6B0E001C01D9274
:10388000A336B107E1F70C945D1C0C94001C81E495
:103890000E94391E86E50E94391E82E50E94391E6B
:1038A00082E40E94391E8FE40E94391E8FE40E9438
:1038B000391E84E50E94391E0895CFE5D4E0DEBFAD
:1038C000CDBFC0E0D0E001E08FEF8BBB60E08BE0CC
:1038D00090E00E942F1E05BF82E085BFCF9B06C0EF
:1038E00081E085BF15BEFE0109950FC00E944E1EE6
:1038F0008B3141F40E944E1E8335E1F70E94471C34
:1039000000E003C08FE30E94391E002339F70E94B4
:103910004E1E682F813611F489E5B7C08134A9F4B1
:103920000E944E1E99279093610080936000182F8B
:1039300000270E944E1E9927082B192B000F111FDC
:1039400010936100009360005CC0823641F489E509
:103950000E94391E80E00E94391E80E896C08234A1
:1039600089F40E944E1E9927182F00270E944E1E90
:103970009927082B192B0E944E1E682FC8010E9400
:10398000481D83C0873689F40E944E1E9927182F40
:1039900000270E944E1E9927082B192B0E944E1EAD
:1039A000682FC8010E94C31DB2CF853661F5809192
:1039B00062008537F9F4109261001092600063E0B4
:1039C00080916000909161000E94FE1D61E18091F4
:1039D0006000909161000E94FE1D809160009091B6
:1039E000610080589F4F90936100809360008050E9
:1039F000984328F361E180916000909161000E94FA
:103A0000FE1D8DE042C0853451F488E190E028E04D
:103A10000FB6F894A89581BD0FBE21BDF2CF8035B9
:103A200081F38C3471F3803711F483E52EC0843731
:103A300029F485E70E94391E80E027C0885782302C
:103A400018F40E944E1EDDCF643529F40E944E1EEC
:103A500080936200D6CF633519F40E94471C57CF7C
:103A6000663529F480E30E94391E82E30EC0633775
:103A700041F483E00E94391E84E90E94391E8EE1E0
:103A800004C06B3109F443CF8FE30E94391E3FCF4E
:103A9000DF92EF92FF920F931F93CF93DF937C01FE
:103AA000D62EC0916000D091610080916200853770
:103AB00009F05FC086E46817D1F50E944E1E082FFA
:103AC00011270E944E1E9927982F8827082B192B03
:103AD0006091600070916100C8010E940D1E80918C
:103AE0006000909161000296909361008093600065
:103AF0008EEF9FEFE80EF91EE114F104F1F6C078A5
:103B000065E0CE010E94FE1D61E1CE010E94FE1D16
:103B100080916000909161009C012078821793074A
:103B200031F020583F4F309361002093600095E4BE
:103B3000D916E1F4809160008EBB80916000909175
:103B40006100292F33272FBB01969093610080934A
:103B500060000E944E1E8DBBE29AE19AE199FECF71
:103B60000894E108F108E114F10421F78DE090E0F8
:103B700002C080E090E0DF91CF911F910F91FF9004
:103B8000EF90DF9008950F931F93CF93DF93EC0195
:103B90006534B1F4809160008EBB8091600090919B
:103BA0006100292F33272FBB0196909361008093EA
:103BB0006000E09A8DB30E94391E219759F719C011
:103BC00060E080916000909161000E94201E8C0155
:103BD0000E94391E812F99270E94391E8091600012
:103BE000909161000296909361008093600022970B
:103BF00039F7DF91CF911F910F91089507B600FC1F
:103C0000FDCFE199FECFFC0160935700E895FFFFDF
:103C1000000007B600FCFDCF08959C0107B600FC2C
:103C2000FDCFE199FECF81E00901FB0180935700B0
:103C3000E895FFFF0000112407B600FCFDCF0895B2
:103C400007B600FCFDCFE199FECFFC0160FD60935B
:103C50005700C895802DE395C895902D08959C0137
:103C6000832F992780BD29B988E18AB986E880BD6C
:103C7000089520E030E08CB90FB607FE0BC05E99C6
:103C80000BC02F5F3F4F5E9907C087E22031380796
:103C9000C4F302C05E9BFECF5E9A089580E090E080
:103CA0000FB607FE0AC05F990AC001965F9907C068
:103CB00027E280319207CCF302C05F9BFECF8CB12C
:043CC00099270895A3
:0400000300003800C1
:00000001FF

129
chipdef.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef CHIPDEF_H
#define CHIPDEF_H
#if defined(__AVR_ATmega169__)
#define sig_byte3 0x1E
#define sig_byte2 0x94
#define sig_byte1 0x05
#define devtype 0x79 // Mega 169 device code
#define PAGESIZE 128 // 2*64 Words = Size in Bytes
#ifdef _B128
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*128 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B256
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*256 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B512
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*512 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B1024
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*1024 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B2048
#error "_B2048 not suppoted on this device"
#endif
#elif defined(__AVR_ATmega16__)
#define sig_byte3 0x1E
#define sig_byte2 0x94
#define sig_byte1 0x03
#define devtype 0x75 // Mega16 device code
#define PAGESIZE 128 // Size in Bytes
#ifdef _B128
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*128 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B256
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*256 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B512
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*512 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B1024
#define APP_PAGES ((2*8192 / PAGESIZE)- (2*1024 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B2048
#error "_B2048 not suppoted on this device"
#endif
#elif defined(__AVR_ATmega8__)
#define sig_byte3 0x1E
#define sig_byte2 0x93
#define sig_byte1 0x07
#define devtype 0x77 // Mega8 boot device code
#define PAGESIZE 64 // Size in Bytes
#ifdef _B128
#define APP_PAGES ((2*4096 / PAGESIZE)- (2*128 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B256
#define APP_PAGES ((2*4096 / PAGESIZE)- (2*256 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B512
#define APP_PAGES ((2*4096 / PAGESIZE)- (2*512 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B1024
#define APP_PAGES ((2*4096 / PAGESIZE)- (2*1024 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B2048
#error "_B2048 not suppoted on this device"
#endif
#elif defined(__AVR_ATmega32__)
#define sig_byte3 0x1E
#define sig_byte2 0x95
#define sig_byte1 0x02
#define devtype 0x73 // Mega32 device code
#define PAGESIZE 128 // Size in Bytes
#ifdef _B128
#define APP_PAGES ((2*16384 / PAGESIZE)- (2*128 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B256
#define APP_PAGES ((2*16384 / PAGESIZE)- (2*256 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B512
#define APP_PAGES ((2*16384 / PAGESIZE)- (2*512 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B1024
#define APP_PAGES ((2*16384 / PAGESIZE)- (2*1024 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#ifdef _B2048
#define APP_PAGES ((2*16384 / PAGESIZE)- (2*2048 / PAGESIZE ))
#define APP_END APP_PAGES * PAGESIZE
#endif
#else
#error "no definition for MCU available in chipdef.h"
#endif
#endif

156
lowlevel.c Normal file
View File

@ -0,0 +1,156 @@
//
// Low-level bootloader routines to replace "assembly.s90"
// from the original ATMEL code.
//
// See avr-libc's boot-module for more information
// Thanks to Eric B. Weddington author of boot.h.
//
// 3/2004 Martin Thomas, Kaiserslautern, Germany
//
// todo: extend functions with espm
#include <avr/io.h>
// There are some #ifdefs in avr/boot.h V1.0 that do not "know"
// about the ATmega169. So some functions have been copied here
// and small modifications have been done to avoid problems.
#include "chipdef.h"
/* Check for SPM Control Register in processor. */
#if defined (SPMCSR)
# define SPM_REG SPMCSR
#elif defined (SPMCR)
# define SPM_REG SPMCR
#else
# error AVR processor does not provide bootloader support!
#endif
#define BOOT_PAGE_FILL _BV(SPMEN)
#define BOOT_LOCK_BITS_SET (_BV(SPMEN) | _BV(BLBSET))
#define boot_spm_busy() (SPM_REG & (unsigned char)_BV(SPMEN))
#define boot_spm_busy_wait() do{}while(boot_spm_busy())
#define eeprom_is_ready() bit_is_clear(EECR, EEWE)
#define eeprom_is_ready_wait() do{}while(!eeprom_is_ready())
// from avr/boot.h
// added "func" parameter and spm-busy check at end
#define _boot_page_write_alternate_bf(address,func) \
({ \
boot_spm_busy_wait(); \
eeprom_is_ready_wait(); \
asm volatile \
( \
"movw r30, %2\n\t" \
"sts %0, %1\n\t" \
"spm\n\t" \
".word 0xffff\n\t" \
"nop\n\t" \
: "=m" (SPM_REG) \
: "r" ((unsigned char)func), \
"r" ((unsigned short)address) \
: "r30", "r31", "r0" \
); \
boot_spm_busy_wait(); \
})
// from avr/boot.h
// added spm-busy check at end
#define _boot_page_fill_alternate_bf(address, data)\
({ \
boot_spm_busy_wait(); \
eeprom_is_ready_wait(); \
asm volatile \
( \
"movw r0, %3\n\t" \
"movw r30, %2\n\t" \
"sts %0, %1\n\t" \
"spm\n\t" \
".word 0xffff\n\t" \
"nop\n\t" \
"clr r1\n\t" \
: "=m" (SPM_REG) \
: "r" ((unsigned char)BOOT_PAGE_FILL), \
"r" ((unsigned short)address), \
"r" ((unsigned short)data) \
: "r0", "r30", "r31" \
); \
boot_spm_busy_wait(); \
})
// from avr/boot.h
// added spm-busy check at end, removed lockbit-masking,
// removed r30/r31 init - maybe wrong TODO: test this
#ifdef ENABLEREADFUSELOCK
#define _boot_lock_bits_set_alternate_bf(lock_bits) \
({ \
boot_spm_busy_wait(); \
eeprom_is_ready_wait(); \
asm volatile \
( \
"mov r0, %2\n\t" \
"sts %0, %1\n\t" \
"spm\n\t" \
".word 0xffff\n\t" \
"nop\n\t" \
: "=m" (SPM_REG) \
: "r" ((unsigned char)BOOT_LOCK_BITS_SET), \
"r" ((unsigned char) lock_bits) \
: "r0" \
); \
boot_spm_busy_wait(); \
})
void write_lock_bits (unsigned char val)
{
_boot_lock_bits_set_alternate_bf(val);
}
#endif
void write_page (unsigned int adr, unsigned char function)
{
_boot_page_write_alternate_bf(adr,function);
}
void fill_temp_buffer (unsigned int data,unsigned int adr)
{
_boot_page_fill_alternate_bf(adr, data);
}
unsigned int read_program_memory(unsigned int adr ,unsigned char param)
// to read lockbits give param=0x09, if param!=0 it is written to SPMCSR
// this is a "translation" from the original code to gcc-inline-assembler
{
unsigned int retval;
boot_spm_busy_wait();
eeprom_is_ready_wait();
asm volatile
(
"movw r30, %3\n\t"
"sbrc %2,0x00\n\t"
"sts %0, %2\n\t"
#ifdef LARGE_MEMORY // If large memory (>64K) ELPM is needed to use RAMPZ
"elpm\n\t" // read LSB
#else
"lpm\n\t" // R0 is now the LSB of the return value
#endif
"mov %A1,r0\n\t"
"inc r30\n\t"
#ifdef LARGE_MEMORY // If large memory (>64K) ELPM is needed to use RAMPZ
"elpm\n\t" // read MSB
#else
"lpm\n\t" // R0 is now the MSB of the return value
#endif
"mov %B1,r0\n\t"
: "=m" (SPM_REG),
"=r" (retval)
: "r" ((unsigned char)param),
"r" ((unsigned short)adr)
: "r30", "r31", "r0"
);
return retval;
}

9
lowlevel.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef LOWLEVEL_H
#define LOWLEVEL_H
void write_page (unsigned int adr, unsigned char function);
unsigned int read_program_memory (unsigned int,unsigned char);
void fill_temp_buffer (unsigned int data,unsigned int adr);
#ifdef ENABLEREADFUSELOCK
void write_lock_bits (unsigned char val);
#endif
#endif

446
main.c Normal file
View File

@ -0,0 +1,446 @@
/*****************************************************************************
*
* AVRPROG compatible boot-loader
* Version : 0.2 (24. March 2004)
* Compiler : avr-gcc 3.3.1 / avr-libc 1.0
* size : ca. 610 word ( larger than 512 words :-( )
* by : Martin Thomas, Kaiserslautern, Germany
* eversmith@heizung-thomas.de
*
* based on the Butterfly Bootloader-Code
* Copyright (C) 1996-1998 Atmel Corporation
* Author(s) : BBrandal, PKastnes, ARodland, LHM
*
* The orignal code has been made available by ATMEL together with the
* Butterfly application code. Since ATMEL.NO had no problem with
* the application gcc-port they hopefully will not have any concerns about
* publishing this port. Make sure to keep the copyright notice in derived
* work to avoid trouble.
****************************************************************************
*
* Many functions used by "AVRPROG" (fuses) have been disabled by ATMEL in
* the original source code of the Butterfly Boot-loader not by me.
* Please 'diff' against the original source to see everything that has been
* changed for the gcc port.
*
* The boot interrupt vector is included (this bootloader is completly in
* ".text" section). If you need this space for further functions you have to
* add a separate section for the bootloader-functions and add an attribute
* for this section to _all_ function prototypes of functions in the loader.
* With this the interrupt vector will be placed at .0000 and the bootloader
* code (without interrupt vector) at the adress you define in the linker
* options for the newly created section. See the avr-libc FAQ and the avr-
* libc's avr/boot.h documentation for further details.
*
* For this bootloader a Boot-Size of at least 0x4C4 (1220) bytes =
* 610 words is needed. Sorry, so far efforts to shrink to 512 words failed.
* See the makefile for information how to adopt the linker-settings to
* the selected Boot Size (_Bxxx below)
*
****************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/wdt.h>
/* READFUSELOCK is untested, will not work for Mega169 since not
supported by AVRPROG 1.37 */
// #define ENABLEREADFUSELOCK
#define BAUDRATE 19200
#define XTAL 3686400
/* Select Boot Size (select one, comment out the others)
select at least _B1024 */
// NO! #define _B128
// NO! #define _B256
// NO! #define _B512
#define _B1024
//#define _B2048
#include "chipdef.h"
#define UART_RX_BUFFER_SIZE PAGESIZE
#include "lowlevel.h"
#include "uart.h"
unsigned char BufferLoad(unsigned int , unsigned char ) ;
void BlockRead(unsigned int , unsigned char ) ;
unsigned int address;
unsigned char device;
void send_boot(void)
{
sendchar('A');
sendchar('V');
sendchar('R');
sendchar('B');
sendchar('O');
sendchar('O');
sendchar('T');
}
int main(void)
{
void (*funcptr)( void ) = 0x0000; // Set up function pointer
unsigned int tempi;
char val;
char OK = 1;
PORTA = 0xFF; // Enable pullups on Port A
USART_Init(UART_BAUD_SELECT(BAUDRATE,XTAL),UARTSINGLE);
// USART_Init(UART_BAUD_SELECT(BAUDRATE/2,XTAL),UARTDOUBLE);
MCUCR = (1<<IVCE);
MCUCR = (1<<IVSEL); //move interruptvectors to the Boot sector
/* 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.).
*/
for(;OK;)
{
if((PINA & (1<<PINA7)))
{
// jump to main app if PIN A0 is not grounded
MCUCR = (1<<IVCE);
MCUCR = (0<<IVSEL); //move interruptvectors to the Application sector
funcptr(); // Jump to application sector
}
else
{
val = recchar();
if( val == 0x1B)
{ // AVRPROG connection
while (val != 'S') // Wait for signon
{
val = recchar();
}
send_boot(); // Report signon
OK = 0;
}
else
sendchar('?');
}
}
for(;;)
{
val=recchar();
if(val=='a') //Autoincrement?
{
sendchar('Y'); //Autoincrement is quicker
}
else if(val=='A') //write address
{
address=recchar(); //read address 8 MSB
address=(address<<8)|recchar();
address=address<<1; //convert from word address to byte address
sendchar('\r');
}
else if(val=='b')
{ // Buffer load support
sendchar('Y'); // Report buffer load supported
sendchar((UART_RX_BUFFER_SIZE >> 8) & 0xFF);
// Report buffer size in bytes
sendchar(UART_RX_BUFFER_SIZE & 0xFF);
}
else if(val=='B') // Start buffer load
{
tempi = recchar() << 8; // Load high byte of buffersize
tempi |= recchar(); // Load low byte of buffersize
val = recchar(); // Load memory type ('E' or 'F')
sendchar (BufferLoad(tempi,val));
// Start downloading of buffer
}
else if(val == 'g') // Block read
{
tempi = (recchar() << 8) | recchar();
val = recchar(); // Get memtype
BlockRead(tempi,val); // Perform the block read
}
/*
else if(val=='c') //Write program memory, low byte
{
ldata=recchar();
sendchar('\r');
}
else if(val== 'C') //Write program memory, high byte
{
data=ldata|(recchar()<<8);
if (device == devtype)
{
fill_temp_buffer(data,(address)); //call asm routine.
}
address=address+2;
sendchar('\r');
}
*/
else if(val=='e') //Chip erase
{
if (device == devtype)
{
for(address=0;address < APP_END;address += PAGESIZE) //Application section = 60 pages
{
write_page(address,(1<<PGERS) + (1<<SPMEN)); //Perform page erase
write_page(address,(1<<RWWSRE) + (1<<SPMEN)); //Re-enable the RWW section
}
}
write_page(address,(1<<RWWSRE) + (1<<SPMEN)); //Re-enable the RWW section
sendchar('\r');
}
else if(val=='E') //Exit upgrade
{
// WDTCR = (1<<WDTCE) | (1<<WDE); //Enable Watchdog Timer to give reset
wdt_enable(WDTO_15MS);
sendchar('\r');
}
/*
else if(val=='l') // write lockbits
{
if (device == devtype)
{
write_lock_bits(recchar());
}
sendchar('\r');
}
else if(val== 'm') // write page
{
if (device == devtype)
{
write_page(address,(1<<PGERS) + (1<<SPMEN)); //Perform page erase
write_page((address),0x05);
write_page(address,(1<<RWWSRE) + (1<<SPMEN)); //Re-enable the RWW section
}
sendchar('\r');
}
*/
else if(val=='P') // Enter programming mode
{
sendchar('\r');
}
else if(val=='L') // Leave programming mode
{
sendchar('\r');
}
else if (val=='p') // mt: return programmer type
{
sendchar('S'); // serial programmer
}
/*
else if(val=='R') //Read program memory
{
write_page(0,(1<<RWWSRE) + (1<<SPMEN)); //Re-enable the RWW section
// SPMCSR = (1<<RWWSRE) | (1<<SPMEN);
// __store_program_memory();
// while((SPMCSR & 0x01));
intval=read_program_memory(address,0x00);
sendchar((char)(intval>>8)); //send MSB
sendchar((char)intval); //send LSB
address=address+2;
}
else if (val == 'D') // write EEPROM
{
if (device == devtype)
{
EEARL = address;
EEARH = (address >> 8);
address++;
EEDR = recchar();
EECR |= (1<<EEMWE);
EECR |= (1<<EEWE);
while (EECR & (1<<EEWE))
;
}
sendchar('\r');
}
else if (val == 'd') // read eeprom
{
EEARL = address;
EEARH = (address >> 8);
address++;
EECR |= (1<<EERE);
sendchar(EEDR);
}
*/
#ifdef ENABLEREADFUSELOCK
#warning "Extension 'ReadFuseLock' enabled"
// mt TODO: Read fuse bit seems to work for clock speed, other settings are not
// interpreted correctly. Locks and high fuse do not work at all (in AVRPROG 1.37)
// Reason for this should be the difference between ATmega16 and ATmega169.
// AVRPROG interprets the results as from an ATmega16 while they are from an ATmega169
else if(val=='F') // read fuse bits
{
sendchar(read_program_memory(0x0000,0x09)); // 0x09 for (1<<BLBSET)|(1<<SPMEN)
}
else if(val=='r') // read lock bits
{
sendchar(read_program_memory(0x0001,0x09));
}
else if(val=='N') // read high fuse bits
{
// mt sendchar(read_program_memory(0x0003));
sendchar(read_program_memory(0x0003,0x09));
}
else if(val=='Q') // read extended fuse bits
{
sendchar(read_program_memory(0x0002,0x09));
}
#endif
// end of ENABLEREADFUSELOCK section
else if(val=='t') // Return programmer type
{
sendchar(devtype);
sendchar(0);
}
else if ((val=='x')||(val=='y')) // clear and set LED ignored
{
recchar();
sendchar('\r');
}
else if (val=='T') // set device/programmer type in bootloader (?)
{
device = recchar();
sendchar('\r');
}
else if (val=='S') // Return software identifier
{
send_boot();
}
else if (val=='V') // Return Software Version
{
sendchar('0'); // mt: changed from 2;0 to 0;1
sendchar('2');
}
else if (val=='s') // Return Signature Byte
{
sendchar(sig_byte1);
sendchar(sig_byte2);
sendchar(sig_byte3);
}
else if(val!=0x1b) // if not esc
{
sendchar('?');
}
} // "parser" for-loop
return 0;
}
unsigned char BufferLoad(unsigned int size, unsigned char mem)
{
int data, tempaddress;
tempaddress = address; // Store address in page
if (device == devtype)
{
if (mem == 'F')
{
do {
data = recchar();
data |= (recchar() << 8);
fill_temp_buffer(data,(address));
//call asm routine.
address=address+2; // Select next word in memory
size -= 2; // Reduce number of bytes to write by two
} while(size); // Loop until all bytes written
tempaddress &= 0xFF80; // Ensure the address points to the first byte in the page
write_page((tempaddress),0x05); // Program page contents
write_page(tempaddress,(1<<RWWSRE) + (1<<SPMEN));
//Re-enable the RWW section
if (address != (address & 0xFF80))
{ // Ensure that the address points to the beginning of the next page
address &= 0xFF80;
address += PAGESIZE;
}
} // End FLASH
if (mem == 'E') // Start EEPROM
{
do {
EEARL = address; // Setup EEPROM address
EEARH = (address >> 8);
address++; // Select next byte
EEDR = recchar(); // Load data to write
EECR |= (1<<EEMWE); // Write data into EEPROM
EECR |= (1<<EEWE);
while (EECR & (1<<EEWE)) // Wait for EEPROM write to finish
;
size--; // Decreas number of bytes to write
} while(size); // Loop until all bytes written
}
return '\r'; // Report programming OK
}
return 0; // Report programming failed
}
void BlockRead(unsigned int size, unsigned char mem)
{
unsigned int data;
if (mem == 'E') // Read EEPROM
{
do {
EEARL = address; // Setup EEPROM address
EEARH = (address >> 8);
address++; // Select next EEPROM byte
EECR |= (1<<EERE); // Read EEPROM
sendchar(EEDR); // Transmit EEPROM data to PC
size--; // Decrease number of bytes to read
} while (size); // Repeat until all block has been read
}
else // Read Flash
{
do {
data = read_program_memory(address,0x00);
sendchar((char)data); //send LSB
sendchar((char)(data >> 8)); //send MSB
address += 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
}
}

405
makefile Normal file
View File

@ -0,0 +1,405 @@
# WinAVR makefile written by Eric B. Weddington, Jörg Wunsch, et al.
# Released to the Public Domain
# Please read the make user manual!
#
# Additional material for this makefile was submitted by:
# Tim Henigan
# Peter Fleury
# Reiner Patommel
# Sander Pool
# Frederik Rouleau
# Markus Pfaff
#
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF (for use with AVR Studio 3.x or VMLAB).
#
# make extcoff = Convert ELF to AVR Extended COFF (for use with AVR Studio
# 4.07 or greater).
#
# make program = Download the hex file to the device, using avrdude. Please
# customize the avrdude settings below first!
#
# make filename.s = Just compile filename.c into the assembler code only
#
# To rebuild project do "make clean" then "make all".
#
# MCU name
MCU = atmega16
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Target file name (without extension).
TARGET = main
# Optimization level, can be [0, 1, 2, 3, s]. 0 turns off optimization.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c
# If there is more than one source file, append them above, or modify and
# uncomment the following:
# mt: the file test.c can be omitted (remove #inc test.h and test() in main.c)
SRC += lowlevel.c \
uart.c
# You can also wrap lines by appending a backslash to the end of the line:
#SRC += baz.c \
#xyzzy.c
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
EXTRAINCDIRS =
# Optional compiler flags.
# -g: generate debugging information (for GDB, or for COFF conversion)
# -O*: optimization level
# -f...: tuning, see gcc manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -ahlms: create assembler listing
CFLAGS = -g -O$(OPT) \
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \
-Wall -Wstrict-prototypes \
-Wa,-adhlns=$(<:.c=.lst) \
$(patsubst %,-I%,$(EXTRAINCDIRS))
# Set a "language standard" compiler flag.
# Unremark just one line below to set the language standard to use.
# gnu99 = C99 + GNU extensions. See GCC manual for more information.
#CFLAGS += -std=c89
#CFLAGS += -std=gnu89
#CFLAGS += -std=c99
CFLAGS += -std=gnu99
# Optional assembler flags.
# -Wa,...: tell GCC to pass this to the assembler.
# -ahlms: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
# Optional linker flags.
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
# Additional libraries
# Minimalistic printf version
#LDFLAGS += -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires -lm below)
#LDFLAGS += -Wl,-u,vfprintf -lprintf_flt
# -lm = math library
LDFLAGS += -lm
################## BOOTLOADER ######################
# mt: Boot loader support. So far not done with a separate section
# to get the interrupt vector into the bootloader area.
# bootloader address in datasheet and stk500 is given as
# "word", gcc toolchain needs "byte"-address (here: 0x1C00*2)
MT_BOOTLOADER_ADDRESS = 3800
LDFLAGS += -Wl,--section-start=.text=$(MT_BOOTLOADER_ADDRESS)
# Programming support using avrdude. Settings and variables.
# Programming hardware: alf avr910 avrisp bascom bsd
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500
#
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = stk500
AVRDUDE_PORT = com1 # programmer connected to serial device
#AVRDUDE_PORT = lpt1 # programmer connected to parallel port
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE += -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_FLAGS += -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_FLAGS += -v -v
# ---------------------------------------------------------------------------
# Define directories, if needed.
DIRAVR = c:/winavr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = .
DIRLIB = $(DIRAVR)/avr/lib
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
# Programming support using avrdude.
AVRDUDE = avrdude
REMOVE = rm -f
COPY = cp
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#mt - use hexadezimal output-fromat // org: ELFSIZE = $(SIZE) -A $(TARGET).elf
ELFSIZE = $(SIZE) -x -A $(TARGET).elf
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
# Define all object files.
OBJ = $(SRC:.c=.o) $(ASRC:.S=.o)
# Define all listing files.
LST = $(ASRC:.S=.lst) $(SRC:.c=.lst)
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore $(TARGET).elf $(TARGET).hex $(TARGET).eep \
$(TARGET).lss $(TARGET).sym sizeafter finished end
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
finished:
@echo $(MSG_ERRORS_NONE)
end:
@echo $(MSG_END)
@echo
# Display size of file.
sizebefore:
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); echo; fi
sizeafter:
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
# Display compiler version information.
gccversion :
@$(CC) --version
# Convert ELF to COFF for use in debugging / simulating in
# AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
avr-nm -n $< > $@
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list finished end
clean_list :
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).obj
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).obj
$(REMOVE) $(TARGET).a90
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lnk
$(REMOVE) $(TARGET).lss
$(REMOVE) $(OBJ)
$(REMOVE) $(LST)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
# Automatically generate C source code dependencies.
# (Code originally taken from the GNU make user manual and modified
# (See README.txt Credits).)
#
# Note that this will work with sh (bash) and sed that is shipped with WinAVR
# (see the SHELL variable defined above).
# This may not work with other shells or other seds.
#
%.d: %.c
set -e; $(CC) -MM $(ALL_CFLAGS) $< \
| sed 's,\(.*\)\.o[ :]*,\1.o \1.d : ,g' > $@; \
[ -s $@ ] || rm -f $@
# Remove the '-' if you want to see the dependency files generated.
-include $(SRC:.c=.d)
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion coff extcoff \
clean clean_list program

119
readme.txt Normal file
View File

@ -0,0 +1,119 @@
======================================================
ATMEL AVR UART Bootloader for AVR-GCC/avr-libc
based on the AVR Butterfly bootloader code
by Martin Thomas, Kaiserslautern, Germany
mthomas@rhrk.uni-kl.de
eversmith@heizung-thomas.de
This is an adapted version which has been tested
with the ATmega16 but should work with the ATmega8,
ATmega169 and ATmega32. The bootloader uses block/
page write and is fast.
======================================================
24. Mar 2004 - Version 0.2
During the development of a data-logger application
with the AVR-Butterfly there was a need to make
some changes in the bootloader. The same problem
again: no IAR compiler. The same way to solve the
problem: a port of the code to avr-gcc/avr-libc.
So this code is based on the ATMEL Butterfly
bootloader source code Rev 0.2 for IAR.
The bootloader-port for the Butterfly which mimics
the complete functionality of the original
BF-bootloader is availabe at:
www.siwawi.arubi.uni-kl.de/avr_projects
Atmel used a separate "lib" written in "pure"
assembly to access the low-level functions
for flash and eeprom read/write. Well, so far I
don't know how to use "mixed language sources"
with the avr-gcc toolchain, so the low-level
routines have been implemented as inline assembler.
The avr-libc boot.h module written by Eric
Weddington served as a template Three of the four
low-level routines found in lowlevel.c come from
boot.h with minimal changes. The read routine has
been developed based on the ATMEL assembler code.
Ignore the fuse and lock-bit readout. Read and Set is
not enabled (TODO).
--------------- Installation -----------------
- Change the MCU type in the makefile (so far
ATmega16 has been tested, ATmega169, ATmega8
and ATmega32 should be o.k. too.
- Change the boot(loader)-size in main.c, this
bootloader is larger than 512 words (1024 bytes),
so select at least _B1024!
- Change the XTAL in main.c to the clock-frequency
of your board (keep BAUDRATE at 19200). See
the datasheet for frequencies with minimum
error at 19200bps and select Crystal/Oscillator
to get minimum errors.
- Change the start-condition in main.c. Default
is: enter bootloader if Pin A7 is connected to
GND during reset/startup
- Edit the value MT_BOOTLOADER_ADDRESS in the
makefile according to the selected bootloader
size. Keep in mind that this value has to be
given in bytes (not words) in the linker options.
i.e. ATMega16, boot-size 1024 words, see
datasheet and find "Boot Reset Adress" for
"Boot Size" 1024 words is 1C00. 1C00 is given
in words, so set MT_BOOTLOADER_ADDRESS to
3800 (=2*1C00)
- Please use at least avr-gcc 3.3.1/avr-libc 1.0
or WINAVR Sept. 2003 or later to compile and link
the bootloader.
- upload the hex-File to the AVR (STK500, STK200, SP12
etc.)
- program the "Boot Flash section size" (BOOTSZ fuses)
according to the boot-size selected in main.c
i.e. BOOTSZ=00 for boot-size 1024 words on ATmega16
- enable the BOOT Reset Vector (BOOTTRST=0)
- Set the lock bits to protect the bootloader from
SPM-writes (Boot Loader Protection Mode 2 in STK500-
plugin)
- Connect the AVR UART Pins via level-shifter/inverter
(i.e. MAX232) to you PCs Com-Port.
- Reset the AVR while fullfilling the bootloader start-
condition. Which means connect PA7 to GND in the default
config during reste/power-cycle. Keep the connection
or hold the key down until you see the AVRPROG dialog!
- Start AVRPROG (AVRStuido/Tools or stand-alone) -
keep PA7 grounded!
- AVRPROG will detect the bootloader, you may release
PA7 now
- see AVRStuido online-help for more information how
to use AVRPROG
- make sure to EXIT from AVRPROG (button) to start
your main-application (or toogle power/reset)
good luck, feedback welcome.
Martin

151
uart.c Normal file
View File

@ -0,0 +1,151 @@
#include <avr/io.h>
/* most of the definitions borrowed from Peter Fleury's UART-Library
extende for control-register C and ATmega169 */
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
|| defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \
|| defined(__AVR_ATmega323__)
/* ATMega with one USART */
#define ATMEGA_USART
#define UART0_UBRR_HIGH UBRRH
#define UART0_UBRR_LOW UBRRL
#define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
#define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
#define UART0_STATUS UCSRA
#define UART0_CONTROL UCSRB
#define UART0_DATA UDR
#define UART0_UDRIE UDRIE
#elif defined(__AVR_ATmega162__)
/* ATMega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_UBRR_HIGH UBRR0H
#define UART0_UBRR_LOW UBRR0L
#define UART1_UBRR_HIGH UBRR1H
#define UART1_UBRR_LOW UBRR1L
#define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV
#define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV
#define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA
#define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROL2 UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_CONTROL2 UCSR1C
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
/* ATMega with two USART */
#define ATMEGA_USART0
#define ATMEGA_USART1
#define UART0_UBRR_HIGH UBRR0H
#define UART0_UBRR_LOW UBRR0L
#define UART1_UBRR_HIGH UBRR1H
#define UART1_UBRR_LOW UBRR1L
#define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV
#define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV
#define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA
#define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROL2 UCSR0C
#define UART0_DATA UDR0
#define UART0_UDRIE UDRIE0
#define UART1_STATUS UCSR1A
#define UART1_CONTROL UCSR1B
#define UART1_CONTROL2 UCSR1C
#define UART1_DATA UDR1
#define UART1_UDRIE UDRIE1
#elif defined(__AVR_ATmega169__)
#define ATMEGA_USART
#define UART0_UBRR_HIGH UBRR0H
#define UART0_UBRR_LOW UBRR0L
// TODO #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV
// TODO #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA
#define UART0_STATUS UCSR0A
#define UART0_CONTROL UCSR0B
#define UART0_CONTROL2 UCSR0C
#define UART0_DATA UDR0
#define UART0_DOUBLEAVAIL
// TODO #define UART0_UDRIE UDRIE
#else
#error "Processor type not supported in uart.c !"
#endif
void USART_Init(unsigned int baudrate, unsigned char doublespeed)
{
// Set baud rate
UART0_UBRR_HIGH = (unsigned char)(baudrate>>8);
UART0_UBRR_LOW = (unsigned char)baudrate;
// Enable 2x speed - TODO adopt to all uCs
#ifdef UART0_DOUBLEAVAIL
if (doublespeed) UCSR0A = (1<<U2X0);
#endif
#if defined (ATMEGA_USART)
/* Enable USART receiver and transmitter and disable interrupts */
UART0_CONTROL = (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<UDRIE);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef URSEL
UCSRC = (1<<URSEL)|(3<<UCSZ0);
#else
UCSRC = (3<<UCSZ0);
#endif
#elif defined (ATMEGA_USART0 )
/* Enable USART receiver and transmitter and disable interrupts */
UART0_CONTROL = (1<<RXEN0)|(1<<TXEN0)|(0<<RXCIE0)|(0<<UDRIE0);
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */
#ifdef URSEL0
UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
#else
UCSR0C = (3<<UCSZ00);
#endif
#endif
}
void sendchar(char data)
{
int i = 0;
UART0_DATA = data;
if(SREG & 0x80)
{
while ( !(UART0_STATUS&0x40) && (i<10000) )
{
i++;
}
}
else
while( !(UART0_STATUS&0x40) );
UART0_STATUS=UART0_STATUS|0x40; //delete TXCflag
}
char recchar(void)
{
int i = 0;
if(SREG & 0x80)
{
// while (!(UART0_STATUS & (1<<RXC0)) && (i<10000))
while (!(UART0_STATUS & 0x80) && (i<10000))
{
i++;
}
}
else
// while(!(UART0_STATUS & (1<<RXC0)));
while(!(UART0_STATUS & 0x80));
return UART0_DATA ;
}

13
uart.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef UART_H
#define UART_H
#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16L)-1)
#define UARTDOUBLE 1
#define UARTSINGLE 0
void USART_Init(unsigned int, unsigned char);
void sendchar(char);
char recchar(void);
#endif