/***************************************************************************** * * Atmel Corporation * * File : main.c * Compiler : IAR C 3.10C Kickstart, AVR-GCC/avr-libc(>= 1.2.5) * Revision : $Revision: 1.7 $ * Date : $Date: Tuesday, June 07, 200 $ * Updated by : $Author: raapeland $ * * Support mail : avr@atmel.com * * Target platform : All AVRs with bootloader support * * AppNote : AVR109 - Self-programming * * Description : This Program allows an AVR with bootloader capabilities to * Read/write its own Flash/EEprom. To enter Programming mode * an input pin is checked. If this pin is pulled low, programming mode * is entered. If not, normal execution is done from $0000 * "reset" vector in Application area. * * Preparations : Use the preprocessor.xls file for obtaining a customized * defines.h file and linker-file code-segment definition for * the device you are compiling for. ****************************************************************************/ #include "defines.h" #include "serial.h" #include "flash.h" /* Uncomment the following to save code space */ //#define REMOVE_AVRPROG_SUPPORT //#define REMOVE_FUSE_AND_LOCK_BIT_SUPPORT //#define REMOVE_BLOCK_SUPPORT //#define REMOVE_EEPROM_BYTE_SUPPORT //#define REMOVE_FLASH_BYTE_SUPPORT /* * GCC doesn't optimize long int arithmetics very clever. As the * address only needs to be larger than 16 bits for the ATmega128 and * above (where flash consumptions isn't much of an issue as the * entire boot loader will still fit even into the smallest possible * boot loader section), save space by using a 16-bit variable for the * smaller devices. */ #ifdef LARGE_MEMORY # define ADDR_T unsigned long #else /* !LARGE_MEMORY */ # define ADDR_T unsigned int #endif /* LARGE_MEMORY */ #ifndef REMOVE_BLOCK_SUPPORT unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address); void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address); /* BLOCKSIZE should be chosen so that the following holds: BLOCKSIZE*n = PAGESIZE, where n=1,2,3... */ #define BLOCKSIZE PAGESIZE #endif /* REMOVE_BLOCK_SUPPORT */ #ifdef __ICCAVR__ __C_task void main(void) #else /* ! __ICCAVR__ */ int main(void) #endif /* __ICCAVR__ */ { ADDR_T address; unsigned int temp_int; unsigned char val; /* Initialization */ void (*funcptr)( void ) = 0x0000; // Set up function pointer to RESET vector. PROGPORT |= (1<>8) & 0xFF); // MSB first. sendchar(BLOCKSIZE&0xFF); // Report BLOCKSIZE (bytes). } // Start block load. else if(val=='B') { temp_int = (recchar()<<8) | recchar(); // Get block size. val = recchar(); // Get memtype. sendchar( BlockLoad(temp_int,val,&address) ); // Block load. } // Start block read. else if(val=='g') { temp_int = (recchar()<<8) | recchar(); // Get block size. val = recchar(); // Get memtype BlockRead(temp_int,val,&address); // Block read } #endif /* REMOVE_BLOCK_SUPPORT */ #ifndef REMOVE_FLASH_BYTE_SUPPORT // Read program memory. else if(val=='R') { // Send high byte, then low byte of flash word. _WAIT_FOR_SPM(); _ENABLE_RWW_SECTION(); #ifdef __ICCAVR__ #pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. #endif sendchar( _LOAD_PROGRAM_MEMORY( (address << 1)+1 ) ); sendchar( _LOAD_PROGRAM_MEMORY( (address << 1)+0 ) ); #ifdef __ICCAVR__ #pragma diag_default=Pe1053 // Back to default. #endif address++; // Auto-advance to next Flash word. } // Write program memory, low byte. else if(val=='c') { // NOTE: Always use this command before sending high byte. temp_int=recchar(); // Get low byte for later _FILL_TEMP_WORD. sendchar('\r'); // Send OK back. } // Write program memory, high byte. else if(val=='C') { temp_int |= (recchar()<<8); // Get and insert high byte. _WAIT_FOR_SPM(); #ifdef __ICCAVR__ #pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. #endif _FILL_TEMP_WORD( (address << 1), temp_int ); // Convert word-address to byte-address and fill. #ifdef __ICCAVR__ #pragma diag_default=Pe1053 // Back to default. #endif address++; // Auto-advance to next Flash word. sendchar('\r'); // Send OK back. } // Write page. else if(val== 'm') { if( address >= (APP_END>>1) ) // Protect bootloader area. { sendchar('?'); } else { _WAIT_FOR_SPM(); #ifdef __ICCAVR__ #pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. #endif _PAGE_WRITE( address << 1 ); // Convert word-address to byte-address and write. #ifdef __ICCAVR__ #pragma diag_default=Pe1053 // Back to default. #endif } sendchar('\r'); // Send OK back. } #endif /* REMOVE_FLASH_BYTE_SUPPORT */ #ifndef REMOVE_EEPROM_BYTE_SUPPORT // Write EEPROM memory. else if (val == 'D') { _WAIT_FOR_SPM(); EEARL = address; // Setup EEPROM address. EEARH = (address >> 8); EEDR = recchar(); // Get byte. EECR |= (1<> 8); EECR |= (1< 0 sendchar( PARTCODE ); // Supports only this device, of course. #endif /* PARTCODE */ sendchar( 0 ); // Send list terminator. } // Set LED, clear LED and set device type. else if((val=='x')||(val=='y')||(val=='T')) { recchar(); // Ignore the command and it's parameter. sendchar('\r'); // Send OK back. } #endif /* REMOVE_AVRPROG_SUPPORT */ // Return programmer identifier. else if(val=='S') { sendchar('A'); // Return 'AVRBOOT'. sendchar('V'); // Software identifier (aka programmer signature) is always 7 characters. sendchar('R'); sendchar('B'); sendchar('O'); sendchar('O'); sendchar('T'); } // Return software version. else if(val=='V') { sendchar('1'); sendchar('5'); } // Return signature bytes. else if(val=='s') { sendchar( SIGNATURE_BYTE_3 ); sendchar( SIGNATURE_BYTE_2 ); sendchar( SIGNATURE_BYTE_1 ); } // The last command to accept is ESC (synchronization). else if(val!=0x1b) // If not ESC, then it is unrecognized... { sendchar('?'); } } // end: for(;;) } else { _WAIT_FOR_SPM(); _ENABLE_RWW_SECTION(); funcptr(); // Jump to Reset vector 0x0000 in Application Section. } } // end: main #ifndef REMOVE_BLOCK_SUPPORT unsigned char BlockLoad(unsigned int size, unsigned char mem, ADDR_T *address) { unsigned char buffer[BLOCKSIZE]; unsigned int data; ADDR_T tempaddress; // EEPROM memory type. if(mem=='E') { /* Fill buffer first, as EEPROM is too slow to copy with UART speed */ for(tempaddress=0;tempaddress> 8); EEDR = buffer[tempaddress]; // Get byte. EECR |= (1<>= 1; // Convert address back to Flash words again. return '\r'; // Report programming OK } // Invalid memory type? else { return '?'; } } void BlockRead(unsigned int size, unsigned char mem, ADDR_T *address) { // EEPROM memory type. if (mem=='E') // Read EEPROM { do { EEARL = *address; // Setup EEPROM address EEARH = ((*address) >> 8); (*address)++; // Select next EEPROM byte EECR |= (1<>= 1; // Convert address back to Flash words again. } } #endif /* REMOVE_BLOCK_SUPPORT */ /* end of file */