/* -----NOT----- the Arduino Boot-Cloner * * Thanks for carrying on development anonymous member(s), but please give yourself credit for your work here instead of me ;) * Also, this wasn't copyrighted, ever. Nothing I ever wrote was - I'm sorry! I wrote the original project during * college and bad things like fake copyrights were encouraged. (I thought I took them all out years ago...?) * * - this comment made by amplificar, on dec 2013 * hopefully the most recent authors will create a new comments section, * if not - please announce this in the appropriate forums with the subject 'amplificar was eaten by a grue, oh no!'. * * * ------------------- * * Comments * * The ATmega8 fuse bytes and bootloader are copied * from the chip on the Arduino, to a new blank ATmega8. * * / See app note DOC0943.pdf "AVR910: In-System Programming" * / See app note DOC2486.pdf "ATmega8 Documentation" - The chapter on Memory Programming, p.237/240 * / iHex flash file format information "https://www.scienceprog.com/shelling-the-intel-8-bit-hex-file-format/" * / PROGMEM and pgmspace.h usage information: * "https://www.scienceprog.com/simple-routine-how-to-store-data-in-microcontroller-flash-and-read-from-it-using-winavr/" * * Notes: * Contrary to what I originally thought, the bootloader resides at the end of flash memory. * * The program was too big, so some of the extra functions are commented out to save memory. * * This program hasn't been optimized for speed, but it's still pretty quick. Some of the delays are unnecessary. * * Your bootloader flash probably can't be read; the default lock bits prevent that. (0xCF ~ bit 6) * This boot-cloner writes different lock bits to the new ATmega8; so the boot flash section *could* be read * when run from the new chip. (0xEF) * With a microcontroller's bootloader flash unlocked, you could remove the bootloader[] table and copy directly from the source to destination chip. * */ // need this header for PROGMEM and the command pgm_read_byte() // which reads bytes from flash program memory. // you can view the header's contents, which are in arduino->tools->avr->avr->include->avr->pgmspace.h #include "avr/pgmspace.h" #include "avr/io.h" #include "pins_arduino.h" // include some '*' commands to let people peek at the chips // These won't fit in an atmega8, you nee an atmega168. #define UTILITIES 1 #define LCD 1 #ifdef LCD #include "SoftwareSerial.h" #endif // CONSTANT DECLARATION /* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */ #define HW_VER 0x02 #define SW_MAJOR 0x01 #define SW_MINOR 0x12 // the number of words per page uint16_t flashMax = 8192; uint8_t pageWords = 32; uint8_t signature2 = 0; uint16_t bootSize = 0; enum { atunknown=0, atmega8=0x7, atmega48=0x5, atmega88=0xa, atmega168=0x6 }; // PINS #define SCK 13 // serial clock to target avr #define MISO 12 // input from target avr #define MOSI 11 // output to target avr #define RESET 10 // reset pin of the target avr #define BUTTON1 14 #define BUTTON2 15 #define BUTTON3 16 // tied to our own reset pin, yeah, I'm that lazy. #define FORCE_RESET 17 // Goes to a little serial LCD #define SERIAL_DEBUG 18 // active low - starts burning the bootloader to the new chip #define ON_LED 5 #define RUN1_LED 6 #define RUN2_LED 7 #define GOOD_LED 8 #define ERR_LED 9 // on the target avr, wire these other pins: // GND: pins 22 (GND), 8 (GND) // +VCC: pin 7 (VCC) // XTAL1 & XTAL2 #define CKEDGE LOW // SCK transmits the bit from MOSI on the rising edge of the clock pulse // CKEDGE should be LOW, which means SCK pulses "...LOW->HIGH->LOW..." // ISP Command Words (use the functions defined further below) #define PE 0xAC53 #define ER 0xAC80 #define RD_PL 0x2000 #define RD_PH 0x2800 #define LD_PL 0x4000 #define LD_PH 0x4800 #define WR_P 0x4C00 #define RD_E 0xA000 #define WR_E 0xC000 #define RD_L 0x5800 #define WR_L 0xACE0 #define RD_S 0x3000 #define WR_F 0xACA0 #define WR_FH 0xACA8 #define WR_FE 0xACA4 #define RD_F 0x5000 #define RD_FH 0x5808 #define RD_FE 0x5008 #define RD_C 0x3800 // Arduino lock bits (default 0xCF ~ prevented reading the boot sector with LPM) #define LockBits 0xEF // 11101111 = SPM is not allowed to write to the boot loader section (prevents bootloader corruption) // Your mega8 running this program probably has bit 6 is programmed. That lock bit makes the bootloader unreadable... (doh!) // When you use this program to burn new bootloaders, those chips WILL be able to use LPM in the boot flash section. // You could reduce this program's size by 1K, if LPM can read the boot flash. (there'd be no need for the bootloader table above) // Arduino fuse bits #define FuseLow 0xDF // default 11011111 = 0xDF, bits 1-4 (rightmost) are CKSEL clock select, bits 5-6 are SUT1 & SUT0 start up time delay // bits 7-8 are BOD brown out detect, which is disabled #define FuseHigh 0xCA // default 11001010 = 0xCA, bit 1 select reset vector (on), bits 2-3 boot size (1K), bit 4 EESAVE eeprom preserved through chip erase (off) // bit 5 CKOPT clock options (on), bit 6 SPIEN SPI enabled (on), bit 7 WDT watchdog timer (off), bit 8 RSTDISBL reset disable (off) // MACRO DECLARATION //#define PULSE_SCK(level) { digitalWrite((SCK),(level)); digitalWrite((SCK),!(level)); } // slow pulse, max 60KHz //#define PULSE_SCK(level) { *sckport &= ~sckbit; delayMicroseconds(10); *sckport |= sckbit; delayMicroseconds(10); } #define PULSE_SCK(level) { *sckport |= sckbit; delayMicroseconds(1); *sckport &= ~sckbit; delayMicroseconds(1); } #define GetWordHigh(a) ( ((a) & 0xFF00) >> 8 ) #define GetWordLow(a) ( ((a) & 0x00FF) ) // these macros are used by the function declarations below // FUNCTION DECLARATION // sends 4 bytes out with SCK, MOSI (output) and gets the return value of the last byte from MISO (input) unsigned char Send_ISP(unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3); #if 0 #define CMD_Program_Enable() (Send_ISP(GetWordHigh(PE),GetWordLow(PE),0x22,0x22)) // Programming Enable: enable serial programming after reset goes low #define CMD_Erase_Flash() (Send_ISP(GetWordHigh(ER),GetWordLow(ER),0x22,0x22)) // Chip Erase: chip erase eeprom and flash #else #define CMD_Program_Enable() (Send_ISP(GetWordHigh(PE),GetWordLow(PE),0,0)) // Programming Enable: enable serial programming after reset goes low #define CMD_Erase_Flash() (Send_ISP(GetWordHigh(ER),GetWordLow(ER),0,0)) // Chip Erase: chip erase eeprom and flash #endif #define CMD_Read_Flash_Low(addr) (Send_ISP(GetWordHigh(RD_PL), (GetWordLow(RD_PL) | (((addr) & 0x1F00) >> 8)), ((addr) & 0xFF), 0)) // Read Program Memory - Low Byte: reads and returns low data from 12 bit word address (divide byte address by 2 for word address) #define CMD_Read_Flash_High(addr) (Send_ISP(GetWordHigh(RD_PH), (GetWordLow(RD_PH) | (((addr) & 0x1F00) >> 8)), ((addr) & 0xFF), 0)) // Read Program Memory - High Byte: reads and returns high data from 12 bit word address #define CMD_Load_Page_Low(addr,data) (Send_ISP(GetWordHigh(LD_PL),GetWordLow(LD_PL), (addr), (data))) // Load Program Memory Page - Low Byte: loads a low byte to the selected memory page, at word address "page" (page is 4 bits) // data low byte must be loaded before data high byte; the flash data is entered by pages, then that whole page is written // pages are 32 words (64 bytes) #define CMD_Load_Page_High(addr,data) (Send_ISP(GetWordHigh(LD_PH),GetWordLow(LD_PH), (addr), (data))) // Load Program Memory Page - High Byte: loads a high byte to program memory page at word address "page" (page is 4 bits) // data low byte must be loaded before data high byte; the flash data is entered by pages, then that whole page is written // pages are 32 words (64 bytes) //#define CMD_Write_Page(addr) (Send_ISP(GetWordHigh(WR_P),(GetWordLow(WR_P) | (((addr) & 0xF0) >> 4)), (((addr) & 0x0F) << 4), 0)) // this is how it's supposed to be done, according to the documentation, but it doesn't work as it's supposed to. // the code below works correctly, by multiplying the address by 2?... very weird #define CMD_Write_Page(addr) (Send_ISP(GetWordHigh(WR_P),(((addr)*2) & 0xF0) >> 4, ((addr)*2) << 4, 0)) // Write Program Memory Page: write the current page into flash memory at the 8 bit page address "addr" // your program must wait or poll after performing this command; otherwise the page writing will be halted // each page is 32 words (64 bytes) - 8K bytes flash, or 4096 words, is 128 pages (0 thru 127) // 1K flash (bootloader) is 1024 bytes, 512 words - which is 16 pages // the bootloader begins at 7K (7168 /2=3584) which is page address 112 #define CMD_Write_Page_Unhacked(addr) (Send_ISP(GetWordHigh(WR_P),(((addr)) & 0xF0) >> 4, ((addr)) << 4, 0)) #define CMD_Write_Page_Clean(addr) (Send_ISP(GetWordHigh(WR_P),(addr)>>8, ((addr) & 0xff), 0)) #define CMD_Read_EEPROM(addrH,addrL) (Send_ISP(GetWordHigh(RD_E),(GetWordLow(RD_E) | ((addrH) & 0x01)), (addrL), 0)) // Read EEPROM Memory: reads and returns data from the 9 bit address to the EEPROM (addrH is 1 bit, addrL is 8 bit) #define CMD_Write_EEPROM(addrH,addrL,data) (Send_ISP(GetWordHigh(WR_E),(GetWordLow(WR_E) | ((addrH) & 0x01)), (addrL), (data))) // Write EEPROM Memory: writes data from the 9 bit address to the EEPROM (addrH is 1 bit, addrL is 8 bit) #define CMD_Read_Lock() (Send_ISP(GetWordHigh(RD_L),GetWordLow(RD_L), 0, 0)) // Read Lock Bits: read the 6 lock bits; "0" is programmed, 1 is unprogrammed #define CMD_Write_Lock(data) (Send_ISP(GetWordHigh(WR_L),GetWordLow(WR_L), 0, (0xC0 | ((data) & 0x3F)) )) // Write Lock Bits: write the 6 lock bits; "0" is programmed, 1 is unprogrammed #define CMD_Read_Signature(addr) (Send_ISP(GetWordHigh(RD_S),GetWordLow(RD_S), ((addr) & 0x03) , 0)) // Read Signature Byte: reads and returns the signature byte from the 2 bit address #define CMD_Write_Fuse_Low(data) (Send_ISP(GetWordHigh(WR_F),GetWordLow(WR_F), 0, (data) )) // Write Fuse Bits - Low: writes the low fuse bits (8 bits) #define CMD_Write_Fuse_High(data) (Send_ISP(GetWordHigh(WR_FH),GetWordLow(WR_FH), 0, (data) )) // Write Fuse Bits - High: writes the high fuse bits (8 bits) #define CMD_Write_Fuse_Extended(data) (Send_ISP(GetWordHigh(WR_FE),GetWordLow(WR_FE), 0, (data) )) // Write Fuse Bits - Extended: writes the extended fuse bits (8 bits) #define CMD_Read_Fuse_Low() (Send_ISP(GetWordHigh(RD_F),GetWordLow(RD_F), 0, 0 )) // Read Fuse Bits - Low: reads and returns the low fuse bits (8 bits) #define CMD_Read_Fuse_High() (Send_ISP(GetWordHigh(RD_FH),GetWordLow(RD_FH), 0, 0 )) // Read Fuse Bits - High: reads and returns the high fuse bits (8 bits) #define CMD_Read_Fuse_Extended() (Send_ISP(GetWordHigh(RD_FE),GetWordLow(RD_FE), 0, 0 )) // Read Fuse Bits - Extended: reads and returns the extended fuse bits (8 bits) #define CMD_Read_Calibration() (Send_ISP(GetWordHigh(RD_C),GetWordLow(RD_C), 0, 0 )) // Read Calibration Byte: reads and returns the calibration byte (8 bits) #ifdef UTILITIES void Reset_Target(); // resets the target avr void Read_Signature(); // prints the 16 signature bytes (device codes) void Read_Flash(); // prints the target flash memory void Read_EEPROM(); // prints the target eeprom void Read_Fuse(); // prints the lock and fuse bits (no leading zeros) void Fuse_Arduino_Style(); // write the fuses like an arduino void Write_Bootloader(); // write an Arduino bootloader to the device #endif int Probe_Device(); #ifdef LCD class DebugLCD : public SoftwareSerial { private: uint8_t line; public: DebugLCD(uint8_t); void clear(); void println(); void printflash(const char *f); void printhex( uint8_t v); void printhex( uint16_t v); }; DebugLCD::DebugLCD( uint8_t pin) : SoftwareSerial(pin,pin), line(0) { } void DebugLCD::clear() { this->print(254,BYTE); delay(1); this->print(1,BYTE); delay(1); this->print(254,BYTE); delay(1); this->print(2,BYTE); delay(1); } void DebugLCD::println() { this->print(254,BYTE); this->print(128+64,BYTE); } void DebugLCD::printflash(const char *f) { for(;;) { char c = pgm_read_byte(f++); if ( !c) return; this->print(c); } } void DebugLCD::printhex( uint8_t v) { this->print((uint8_t)pgm_read_byte(PSTR("0123456789abcdef")+(v>>4))); this->print((uint8_t)pgm_read_byte(PSTR("0123456789abcdef")+(v&0xf))); } void DebugLCD::printhex( uint16_t v) { this->printhex((uint8_t)(v>>8)); this->printhex((uint8_t)(v&0xff)); } DebugLCD debug(SERIAL_DEBUG); #endif void serialprintflash(const char *f) { for(;;) { char c = pgm_read_byte(f++); if ( !c) return; Serial.print(c); } } void serialprinthex( uint8_t v) { Serial.print((uint8_t)pgm_read_byte(PSTR("0123456789abcdef")+(v>>4))); Serial.print((uint8_t)pgm_read_byte(PSTR("0123456789abcdef")+(v&0xf))); } void serialprinthex( uint16_t v) { serialprinthex((uint8_t)(v>>8)); serialprinthex((uint8_t)(v&0xff)); } uint8_t targetSeized = 0; uint8_t goodBurn = 1; static void ReleaseTarget() { pinMode(SCK,INPUT); digitalWrite(SCK,0); pinMode(MISO,INPUT); digitalWrite(MISO,0); pinMode(MOSI,INPUT); digitalWrite(MOSI,0); pinMode(RESET,INPUT); digitalWrite(RESET,0); targetSeized = 0; digitalWrite(ERR_LED,1); digitalWrite(GOOD_LED,1); } static void SeizeTarget() { digitalWrite(SCK,0); pinMode(SCK,OUTPUT); pinMode(MISO,INPUT); pinMode(MOSI,OUTPUT); digitalWrite(RESET,0); pinMode(RESET,OUTPUT); delayMicroseconds(4); digitalWrite(RESET,1); delayMicroseconds(4); digitalWrite(RESET,0); delay(21); CMD_Program_Enable(); targetSeized = 1; digitalWrite(ERR_LED,0); digitalWrite(GOOD_LED,0);} void setup(void) { ReleaseTarget(); // user interface pinMode(BUTTON1,INPUT); digitalWrite(BUTTON1,1); // turn on pullup pinMode(BUTTON2,INPUT); digitalWrite(BUTTON2,1); // turn on pullup pinMode(BUTTON3,INPUT); digitalWrite(BUTTON3,1); // turn on pullup digitalWrite(ON_LED,0); pinMode(ON_LED,OUTPUT); digitalWrite(RUN1_LED,1); pinMode(RUN1_LED,OUTPUT); digitalWrite(RUN2_LED,1); pinMode(RUN2_LED,OUTPUT); digitalWrite(GOOD_LED,1); pinMode(GOOD_LED,OUTPUT); digitalWrite(ERR_LED,1); pinMode(ERR_LED,OUTPUT); Serial.begin(19200); #ifdef LCD pinMode(SERIAL_DEBUG,OUTPUT); debug.begin(9600); debug.clear(); debug.printflash(PSTR(" Programmer")); debug.println(); #endif } static void BlinkRun(int8_t force) { static long runToggleTime; static uint8_t runState; if ( force > 0) { runState = 0; runToggleTime = 0; } else if ( force < 0) { digitalWrite(RUN1_LED,HIGH); digitalWrite(RUN2_LED,HIGH); return; } if ( runToggleTime >= millis()) return; runToggleTime = millis() + 200; digitalWrite(RUN1_LED,runState); runState ^= 1; digitalWrite(RUN2_LED,runState); } uint8_t getch() { while( !Serial.available()); return Serial.read(); } void getNch(uint8_t count) { for ( ; count > 0; count--) { getch(); } } void byte_response( uint8_t v) { if ( getch() == ' ') { Serial.print((char)0x14); Serial.print((char)v); Serial.print((char)0x10); } } void nothing_response( ) { if ( getch() == ' ') { Serial.print((char)0x14); Serial.print((char)0x10); } } void DoSTK() { uint8_t ch; static uint8_t previousCommand; uint16_t w; uint8_t eeprom = 0; static uint16_t address; uint16_t length; static uint8_t buff[140]; uint8_t j; uint16_t i; static uint16_t page; goodBurn = 0; ch = getch(); switch(ch) { #ifdef UTILITIES case '*': switch(getch()) { case 'f': Read_Flash(); break; case 'u': Read_Fuse(); break; case 's': Read_Signature(); break; case 'e': Erase_Chip(); break; case 'r': Remove_Bootloader(); break; case 'A': Fuse_Arduino_Style(); break; case 'a': Erase_Chip(); Write_Bootloader(); break; case 'p': SeizeTarget(); if ( Probe_Device()) { serialprintflash(PSTR("Probed: ")); Serial.print(flashMax,DEC); Serial.print('/'); Serial.print(pageWords,DEC); Serial.println(); } else { serialprintflash(PSTR("ProbeFailed\n")); } ReleaseTarget(); break; case 'b': SeizeTarget(); delay(10); Probe_Device(); delay(10); Serial.print(CMD_Program_Enable(),HEX); delay(1000); cli(); for ( int i = 0; i < pageWords; i++) { CMD_Load_Page_Low( i, i*2); CMD_Load_Page_High( i, i*2+1); } CMD_Write_Page( 0); sei(); delay(25); ReleaseTarget(); break; case 'B': SeizeTarget(); delay(10); Probe_Device(); delay(10); Serial.print(CMD_Program_Enable(),HEX); delay(1000); for ( int i = 0; i < 256; i++) { CMD_Write_EEPROM( 0,i,i); delay(25); } ReleaseTarget(); break; case 'E': Read_EEPROM(); break; default: serialprintflash(PSTR("bad * command\n")); break; } goodBurn = 1; break; #endif case '0': nothing_response(); break; case '1': if ( getch() == ' ') { Serial.print((char)0x14); Serial.print("AVR ISP"); Serial.print((char)0x10); } break; case '@': if ( getch() > 0x85) getch(); nothing_response(); break; case 'A': switch(getch()) { case 0x80: byte_response(HW_VER); break; case 0x81: byte_response(SW_MAJOR); break; case 0x82: byte_response(SW_MINOR); break; case 0x98: byte_response(0x03); // unknown but required for avr studio break; default: byte_response(0x00); // cover various responses we don't care about break; } break; case 'B': // device parameters, don't care getNch(20); nothing_response(); break; case 'E': // parallel programming stuff, don't care. getNch(5); nothing_response(); break; case 'P': // enter programming mode SeizeTarget(); if ( !Probe_Device()) digitalWrite(ERR_LED,0); nothing_response(); break; case 'Q': // leave programming mode if ( previousCommand != 'u') { ReleaseTarget(); // Arduino environment has a spurious Q without a P to re-enable digitalWrite(GOOD_LED,0); goodBurn = 1; } nothing_response(); break; case 'R': // erase device nothing_response(); break; case 'U': // set address... little ending, eeprom in bytes, flash in words if ( previousCommand == 'P') { CMD_Erase_Flash(); // Seems odd, but I have to erase first delay(10); } address = getch(); address |= ((uint16_t)getch() << 8); page = address/pageWords; nothing_response(); break; case 'V': // Universal SPI programming command, disabled. Would be used for fuses and lock bits. getNch(4); byte_response(0x00); break; case 'd': // wrtie memory, length is big endian and is in bytes length = ((uint16_t)getch() << 8); length |= getch(); eeprom = (getch() == 'E'); for ( w = 0; w < length; w++) { buff[w] = getch(); } if ( getch() == ' ') { if ( eeprom) { for ( w = 0; w < length; w++) { //eeprom_b(address.word,buff[w]); //address.word++; } } else { // write to flash one page at a time for ( i = 0; i < length; ) { uint16_t pollAddr = 0; uint8_t pollByte = 0; cli(); for ( j = 0; j < pageWords; j++) { if ( !pollAddr && buff[i] != 0xff) { pollAddr = j; pollByte = buff[i]; } CMD_Load_Page_Low( j, buff[i++]); CMD_Load_Page_High( j, buff[i++]); } CMD_Write_Page_Clean( page*pageWords); sei(); page++; // don't put it in that macro, it gets evaluated twice. if ( pollAddr) while( CMD_Read_Flash_Low(pollAddr) == 0xff); else delay(11); } // write page } Serial.print((char)0x14); Serial.print((char)0x10); } break; case 't': // read memory block length = (getch() << 8); length |= getch(); eeprom = (getch() == 'E'); if ( !eeprom) address <<= 1; if ( getch() == ' ') { // command terminator Serial.print((char)0x14); for ( w = 0; w < length; w++) { Serial.print((char)0x01); // faked } Serial.print((char)0x10); } break; case 'u': if ( getch() == ' ') { Serial.print((char)0x14); Serial.print((char)CMD_Read_Signature(0)); Serial.print((char)CMD_Read_Signature(1)); Serial.print((char)CMD_Read_Signature(2)); Serial.print((char)0x10); } break; case 'v': byte_response(0x00); break; default: nothing_response(); break; } previousCommand = ch; } void loop(void) { unsigned int result = 0; // used for debugging & showing errors const unsigned char *bootloader; const char *bootloaderName; BlinkRun(-1); // leave GOOD and ERR until cycle starts do {} while ( !digitalRead(BUTTON1) || !digitalRead(BUTTON2) || !digitalRead(BUTTON3)); // wait for all up // wait for something interesting to be happening do {} while ( digitalRead(BUTTON1) && digitalRead(BUTTON2) && digitalRead(BUTTON3) && !Serial.available()); if ( digitalRead(BUTTON3) == 0) { #ifdef LCD debug.clear(); debug.printflash(PSTR("--- reset ---")); #endif pinMode( FORCE_RESET, OUTPUT); digitalWrite( FORCE_RESET, 0); for (;;); } if ( Serial.available()) { long timeout = millis() + 6000; digitalWrite(ERR_LED,HIGH); digitalWrite(GOOD_LED,HIGH); BlinkRun(1); goodBurn = 0; for ( ;; ) { while ( millis() < timeout && !Serial.available()); if ( !Serial.available()) { digitalWrite(ERR_LED,LOW); ReleaseTarget(); break; } timeout = millis() + 6000; DoSTK(); if ( goodBurn) return; BlinkRun(0); } return; } return; } // send 4 bytes to target microcontroller, returns the fourth MISO byte unsigned char Send_ISP(unsigned char v0, unsigned char v1, unsigned char v2, unsigned char v3) { // MO output // MI input unsigned char result = 0; uint8_t mosibit = digitalPinToBitMask(MOSI); volatile uint8_t *mosiport = portOutputRegister( digitalPinToPort(MOSI)); uint8_t sckbit = digitalPinToBitMask(SCK); volatile uint8_t *sckport = portOutputRegister( digitalPinToPort(SCK)); uint8_t misobit = digitalPinToBitMask(MISO); volatile uint8_t *misopins = portInputRegister( digitalPinToPort(MISO)); // first byte result = 0; for ( int i = 0x80 ; i>0 ; i /= 2 ) { if ( v0 & i) *mosiport |= mosibit; else *mosiport &= ~mosibit; result = ((result << 1) | digitalRead(MISO)); // shift contents of result left one bit, set LSB with MISO value PULSE_SCK(CKEDGE); } result = 0; for ( int i = 0x80 ; i>0 ; i /= 2 ) { // second byte - MISO echos first byte if ( v1 & i) *mosiport |= mosibit; else *mosiport &= ~mosibit; result = ((result << 1) | ( (*misopins & misobit) ? 1 : 0)); PULSE_SCK(CKEDGE); } if (result != v0 ) { // handle error } result = 0; for ( int i = 0x80 ; i>0 ; i /= 2 ) { // third byte - MISO echos second byte if ( v2 & i) *mosiport |= mosibit; else *mosiport &= ~mosibit; result = ((result << 1) | ( (*misopins & misobit) ? 1 : 0)); PULSE_SCK(CKEDGE); } if (result != v1 ) { // handle error #ifdef LCD debug.print('['); debug.print(v1&0xff,HEX); debug.print(result&0xff,HEX); debug.print(']'); #endif } result = 0; for ( int i = 0x80 ; i>0 ; i /= 2 ) { // fourth byte - MISO returns some value (depends on command) if ( v3 & i) *mosiport |= mosibit; else *mosiport &= ~mosibit; result = ((result << 1) | ( (*misopins & misobit) ? 1 : 0)); PULSE_SCK(CKEDGE); } return result; } int Probe_Device() { uint8_t fuse; if ( CMD_Read_Signature(0) != 0x1e) return 0; switch( CMD_Read_Signature(1)) { case 0x93: flashMax = 8192; pageWords = 32; break; case 0x94: flashMax = 16384; pageWords = 64; break; default: return 0; } signature2 = CMD_Read_Signature(2); bootSize = 0; switch( signature2) { case atmega8: switch( (CMD_Read_Fuse_High()>>1) & 3) { case 0: bootSize = 2048; break; case 1: bootSize = 1024; break; case 2: bootSize = 512; break; case 3: bootSize = 256; break; } break; case atmega48: case atmega88: case atmega168: switch( (CMD_Read_Fuse_Extended()>>1) & 3) { case 0: bootSize = 2048; break; case 1: bootSize = 1024; break; case 2: bootSize = 512; break; case 3: bootSize = 256; break; } break; } return 1; } #ifdef UTILITIES // prints the 16 signature bytes (device codes) void Read_Signature() { SeizeTarget(); serialprintflash(PSTR("SIGNATURES")); for ( unsigned char x = 0 ; x<4 ; x++ ) { serialprinthex(CMD_Read_Signature(x)); serialprintflash(PSTR(",")); } Serial.println(); ReleaseTarget(); } // prints the flash memory void Read_Flash() { uint8_t skipped = 0; SeizeTarget(); serialprintflash(PSTR("READING FLASH\n")); for ( unsigned int base = 0 ; base<(flashMax/2) ; base += 16 ) { uint8_t mustPrint = 0; for ( uint8_t i = 0; i < 16; i++) { if ( CMD_Read_Flash_Low(base+i) != 0xff || CMD_Read_Flash_High(base+i) != 0xff) { mustPrint = 1; break; } } if ( mustPrint) { if ( skipped) { Serial.println(); skipped = 0; } serialprinthex(base); serialprintflash(PSTR(" = ")); for ( uint8_t i = 0; i < 16; i++) { serialprinthex(CMD_Read_Flash_Low(base+i)); serialprintflash(PSTR(" ")); serialprinthex(CMD_Read_Flash_High(base+i)); serialprintflash(PSTR(" ")); } Serial.println(); } else { if ( skipped) { Serial.print('#'); skipped++; if ( skipped >= 32) { Serial.println(); skipped = 0; } } else { serialprinthex(base); serialprintflash(PSTR(" = #")); skipped = 1; } } } Serial.println(); ReleaseTarget(); } void Read_EEPROM() { uint8_t skipped = 0; SeizeTarget(); serialprintflash(PSTR("READING EEPROM\n")); for ( unsigned int base = 0 ; base<256 ; base += 16 ) { uint8_t mustPrint = 0; for ( uint8_t i = 0; i < 16; i++) { if ( CMD_Read_EEPROM(0,base+i) != 0xff ) { mustPrint = 1; break; } } if ( mustPrint) { if ( skipped) { Serial.println(); skipped = 0; } serialprinthex(base); serialprintflash(PSTR(" = ")); for ( uint8_t i = 0; i < 16; i++) { serialprinthex(CMD_Read_EEPROM(0,base+i)); serialprintflash(PSTR(" ")); } Serial.println(); } else { if ( skipped) { Serial.print('#'); skipped++; if ( skipped >= 32) { Serial.println(); skipped = 0; } } else { serialprinthex(base); serialprintflash(PSTR(" = #")); skipped = 1; } } } Serial.println(); ReleaseTarget(); } // prints the lock and fuse bits (no leading zeros) void Read_Fuse() { SeizeTarget(); Probe_Device(); serialprintflash(PSTR("Lock Bits: ")); Serial.print(CMD_Read_Lock(),BIN); Serial.println(); serialprintflash(PSTR("Fuse Low: ")); Serial.print(CMD_Read_Fuse_Low(),BIN); Serial.println(); serialprintflash(PSTR("Fuse High: ")); Serial.print(CMD_Read_Fuse_High(),BIN); Serial.println(); if ( signature2 == atmega48 || signature2 == atmega88 || signature2 == atmega168) { serialprintflash(PSTR("Fuse Extn: ")); Serial.print(CMD_Read_Fuse_Extended(),BIN); Serial.println(); } ReleaseTarget(); } void Erase_Chip() { SeizeTarget(); serialprintflash(PSTR("Erase chip... ")); delay(20); Serial.print(CMD_Program_Enable(),HEX); delay(10); Serial.print(CMD_Erase_Flash(),BIN); delay(50); serialprintflash(PSTR("... done.\n")); Serial.println(); ReleaseTarget(); } void Fuse_Arduino_Style() { uint8_t fuse; SeizeTarget(); Probe_Device(); switch( signature2) { case atmega8: serialprintflash(PSTR("Writing mega8 fuses: ")); CMD_Write_Fuse_High( 0xca); delay(10); CMD_Write_Fuse_Low( 0xdf); delay(10); serialprintflash(PSTR("high=")); Serial.print(CMD_Read_Fuse_High(), BIN); serialprintflash(PSTR(", low=")); Serial.print(CMD_Read_Fuse_Low(), BIN); serialprintflash(PSTR("... (1k bootloader at reset, 1xcrystal clock) done.\n")); break; case atmega48: case atmega88: case atmega168: serialprintflash(PSTR("Writing mega48/88/168 fuses: ")); CMD_Write_Fuse_Extended( 0xf8); delay(10); CMD_Write_Fuse_High( 0xdf); delay(10); CMD_Write_Fuse_Low( 0xef); delay(10); serialprintflash(PSTR("extended=")); Serial.print(CMD_Read_Fuse_Extended(), BIN); serialprintflash(PSTR("high=")); Serial.print(CMD_Read_Fuse_High(), BIN); serialprintflash(PSTR(", low=")); Serial.print(CMD_Read_Fuse_Low(), BIN); serialprintflash(PSTR("... (2k bootloader at reset, 1xcrystal clock) done.\n")); break; default: serialprintflash(PSTR("Unknown device type. Failed.")); break; } delay(50); Serial.println(); ReleaseTarget(); } void Remove_Bootloader() { uint8_t fuse; SeizeTarget(); Probe_Device(); switch( signature2) { case atmega8: serialprintflash(PSTR("Remove boot loader, fuse high was ")); fuse = CMD_Read_Fuse_High(); Serial.print(fuse,BIN); CMD_Write_Fuse_High( fuse | 1); delay(50); serialprintflash(PSTR(", now ")); Serial.print(CMD_Read_Fuse_High(), BIN); break; case atmega48: case atmega88: case atmega168: serialprintflash(PSTR("Remove boot loader, fuse extended was ")); fuse = CMD_Read_Fuse_Extended(); Serial.print(fuse,BIN); CMD_Write_Fuse_Extended( fuse | 1); delay(50); serialprintflash(PSTR(", now ")); Serial.print(CMD_Read_Fuse_Extended(), BIN); break; default: serialprintflash(PSTR("Unknown device type. Failed.")); break; } delay(50); serialprintflash(PSTR("... done.\n")); Serial.println(); ReleaseTarget(); } /* ** This is the stock bootloader from the arduino-0008 source tree ** atmega8, 16MHz, led on port b 5 */ unsigned char PROGMEM loader8[] = { 0x12, 0xC0, 0x2B, 0xC0, 0x2A, 0xC0, 0x29, 0xC0, 0x28, 0xC0, 0x27, 0xC0, 0x26, 0xC0, 0x25, 0xC0, 0x24, 0xC0, 0x23, 0xC0, 0x22, 0xC0, 0x21, 0xC0, 0x20, 0xC0, 0x1F, 0xC0, 0x1E, 0xC0, 0x1D, 0xC0, 0x1C, 0xC0, 0x1B, 0xC0, 0x1A, 0xC0, 0x11, 0x24, 0x1F, 0xBE, 0xCF, 0xE5, 0xD4, 0xE0, 0xDE, 0xBF, 0xCD, 0xBF, 0x10, 0xE0, 0xA0, 0xE6, 0xB0, 0xE0, 0xE8, 0xEE, 0xFF, 0xE1, 0x02, 0xC0, 0x05, 0x90, 0x0D, 0x92, 0xA2, 0x36, 0xB1, 0x07, 0xD9, 0xF7, 0x11, 0xE0, 0xA2, 0xE6, 0xB0, 0xE0, 0x01, 0xC0, 0x1D, 0x92, 0xAA, 0x36, 0xB1, 0x07, 0xE1, 0xF7, 0x4F, 0xC0, 0xD2, 0xCF, 0xEF, 0x92, 0xFF, 0x92, 0x0F, 0x93, 0x1F, 0x93, 0xEE, 0x24, 0xFF, 0x24, 0x87, 0x01, 0x13, 0xC0, 0x08, 0x94, 0xE1, 0x1C, 0xF1, 0x1C, 0x01, 0x1D, 0x11, 0x1D, 0x81, 0xE0, 0xE8, 0x16, 0x82, 0xE1, 0xF8, 0x06, 0x8A, 0xE7, 0x08, 0x07, 0x80, 0xE0, 0x18, 0x07, 0x28, 0xF0, 0xE0, 0x91, 0x62, 0x00, 0xF0, 0x91, 0x63, 0x00, 0x09, 0x95, 0x5F, 0x9B, 0xEB, 0xCF, 0x8C, 0xB1, 0x99, 0x27, 0x87, 0xFD, 0x90, 0x95, 0x1F, 0x91, 0x0F, 0x91, 0xFF, 0x90, 0xEF, 0x90, 0x08, 0x95, 0x5D, 0x9B, 0xFE, 0xCF, 0x8C, 0xB9, 0x08, 0x95, 0xD5, 0xDF, 0x80, 0x32, 0x21, 0xF4, 0x84, 0xE1, 0xF7, 0xDF, 0x80, 0xE1, 0xF5, 0xDF, 0x08, 0x95, 0x1F, 0x93, 0x18, 0x2F, 0xCB, 0xDF, 0x80, 0x32, 0x31, 0xF4, 0x84, 0xE1, 0xED, 0xDF, 0x81, 0x2F, 0xEB, 0xDF, 0x80, 0xE1, 0xE9, 0xDF, 0x1F, 0x91, 0x08, 0x95, 0x1F, 0x93, 0xCF, 0x93, 0xDF, 0x93, 0x18, 0x2F, 0xC0, 0xE0, 0xD0, 0xE0, 0x02, 0xC0, 0xB9, 0xDF, 0x21, 0x96, 0xC1, 0x17, 0xE0, 0xF3, 0xDF, 0x91, 0xCF, 0x91, 0x1F, 0x91, 0x08, 0x95, 0xCF, 0xE5, 0xD4, 0xE0, 0xDE, 0xBF, 0xCD, 0xBF, 0x00, 0x00, 0x10, 0xBC, 0x83, 0xE3, 0x89, 0xB9, 0x88, 0xE1, 0x8A, 0xB9, 0x86, 0xE8, 0x80, 0xBD, 0xBD, 0x9A, 0x10, 0x92, 0x68, 0x01, 0x30, 0xE2, 0xE0, 0xE0, 0xF0, 0xE0, 0x2F, 0xE0, 0x88, 0xB3, 0x83, 0x27, 0x88, 0xBB, 0xCF, 0x01, 0x01, 0x97, 0xF1, 0xF7, 0x21, 0x50, 0x27, 0xFF, 0xF7, 0xCF, 0x20, 0xE1, 0x20, 0x93, 0x68, 0x01, 0x92, 0xDF, 0x80, 0x33, 0x81, 0xF1, 0x81, 0x33, 0x99, 0xF4, 0x8D, 0xDF, 0x80, 0x32, 0xC1, 0xF7, 0x84, 0xE1, 0xAF, 0xDF, 0x81, 0xE4, 0xAD, 0xDF, 0x86, 0xE5, 0xAB, 0xDF, 0x82, 0xE5, 0xA9, 0xDF, 0x80, 0xE2, 0xA7, 0xDF, 0x89, 0xE4, 0xA5, 0xDF, 0x83, 0xE5, 0xA3, 0xDF, 0x80, 0xE5, 0xC7, 0xC0, 0x80, 0x34, 0x29, 0xF4, 0x78, 0xDF, 0x86, 0x38, 0xB0, 0xF0, 0x75, 0xDF, 0x14, 0xC0, 0x81, 0x34, 0x71, 0xF4, 0x71, 0xDF, 0x80, 0x38, 0x11, 0xF4, 0x82, 0xE0, 0x1D, 0xC1, 0x81, 0x38, 0x11, 0xF4, 0x81, 0xE0, 0x19, 0xC1, 0x82, 0x38, 0x09, 0xF0, 0x15, 0xC1, 0x82, 0xE1, 0x14, 0xC1, 0x82, 0x34, 0x21, 0xF4, 0x84, 0xE1, 0x9F, 0xDF, 0x89, 0xDF, 0xCB, 0xCF, 0x85, 0x34, 0x11, 0xF4, 0x85, 0xE0, 0xF9, 0xCF, 0x80, 0x35, 0xC1, 0xF3, 0x81, 0x35, 0xB1, 0xF3, 0x82, 0x35, 0xA1, 0xF3, 0x85, 0x35, 0x39, 0xF4, 0x51, 0xDF, 0x80, 0x93, 0x64, 0x00, 0x4E, 0xDF, 0x80, 0x93, 0x65, 0x00, 0xEB, 0xCF, 0x86, 0x35, 0x19, 0xF4, 0x84, 0xE0, 0x86, 0xDF, 0xF5, 0xC0, 0x84, 0x36, 0x09, 0xF0, 0x93, 0xC0, 0x42, 0xDF, 0x80, 0x93, 0x67, 0x01, 0x3F, 0xDF, 0x80, 0x93, 0x66, 0x01, 0x80, 0x91, 0x69, 0x01, 0x8E, 0x7F, 0x80, 0x93, 0x69, 0x01, 0x37, 0xDF, 0x85, 0x34, 0x29, 0xF4, 0x80, 0x91, 0x69, 0x01, 0x81, 0x60, 0x80, 0x93, 0x69, 0x01, 0xC0, 0xE0, 0xD0, 0xE0, 0x06, 0xE6, 0x10, 0xE0, 0x05, 0xC0, 0x2A, 0xDF, 0xF8, 0x01, 0x81, 0x93, 0x8F, 0x01, 0x21, 0x96, 0x80, 0x91, 0x66, 0x01, 0x90, 0x91, 0x67, 0x01, 0xC8, 0x17, 0xD9, 0x07, 0xA0, 0xF3, 0x1E, 0xDF, 0x80, 0x32, 0x09, 0xF0, 0x88, 0xCF, 0x80, 0x91, 0x69, 0x01, 0x80, 0xFF, 0x1F, 0xC0, 0x20, 0xE0, 0x30, 0xE0, 0xE6, 0xE6, 0xF0, 0xE0, 0x12, 0xC0, 0xA0, 0x91, 0x64, 0x00, 0xB0, 0x91, 0x65, 0x00, 0x81, 0x91, 0x08, 0x2E, 0xC5, 0xD0, 0x80, 0x91, 0x64, 0x00, 0x90, 0x91, 0x65, 0x00, 0x01, 0x96, 0x90, 0x93, 0x65, 0x00, 0x80, 0x93, 0x64, 0x00, 0x2F, 0x5F, 0x3F, 0x4F, 0x80, 0x91, 0x66, 0x01, 0x90, 0x91, 0x67, 0x01, 0x28, 0x17, 0x39, 0x07, 0x38, 0xF3, 0x43, 0xC0, 0xF8, 0x94, 0xE1, 0x99, 0xFE, 0xCF, 0x11, 0x27, 0xE0, 0x91, 0x64, 0x00, 0xF0, 0x91, 0x65, 0x00, 0xEE, 0x0F, 0xFF, 0x1F, 0xC6, 0xE6, 0xD0, 0xE0, 0x80, 0x91, 0x66, 0x01, 0x90, 0x91, 0x67, 0x01, 0x80, 0xFF, 0x01, 0xC0, 0x01, 0x96, 0x10, 0x30, 0x51, 0xF4, 0x22, 0xD0, 0x03, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x1D, 0xD0, 0x01, 0xE1, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x09, 0x90, 0x19, 0x90, 0x16, 0xD0, 0x01, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x13, 0x95, 0x10, 0x32, 0x58, 0xF0, 0x11, 0x27, 0x0D, 0xD0, 0x05, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x08, 0xD0, 0x01, 0xE1, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x32, 0x96, 0x02, 0x97, 0x39, 0xF0, 0xDB, 0xCF, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x08, 0x95, 0x10, 0x30, 0x11, 0xF0, 0x02, 0x96, 0xE7, 0xCF, 0x11, 0x24, 0x84, 0xE1, 0xD9, 0xDE, 0x80, 0xE1, 0xD7, 0xDE, 0x1D, 0xCF, 0x84, 0x37, 0x09, 0xF0, 0x4B, 0xC0, 0xAC, 0xDE, 0x80, 0x93, 0x67, 0x01, 0xA9, 0xDE, 0x80, 0x93, 0x66, 0x01, 0xA6, 0xDE, 0x90, 0x91, 0x69, 0x01, 0x85, 0x34, 0x21, 0xF4, 0x91, 0x60, 0x90, 0x93, 0x69, 0x01, 0x0D, 0xC0, 0x9E, 0x7F, 0x90, 0x93, 0x69, 0x01, 0x80, 0x91, 0x64, 0x00, 0x90, 0x91, 0x65, 0x00, 0x88, 0x0F, 0x99, 0x1F, 0x90, 0x93, 0x65, 0x00, 0x80, 0x93, 0x64, 0x00, 0x90, 0xDE, 0x80, 0x32, 0x09, 0xF0, 0xFA, 0xCE, 0x84, 0xE1, 0xB1, 0xDE, 0xC0, 0xE0, 0xD0, 0xE0, 0x1E, 0xC0, 0x80, 0x91, 0x69, 0x01, 0x80, 0xFF, 0x07, 0xC0, 0xA0, 0x91, 0x64, 0x00, 0xB0, 0x91, 0x65, 0x00, 0x31, 0xD0, 0x80, 0x2D, 0x08, 0xC0, 0x81, 0xFD, 0x07, 0xC0, 0xE0, 0x91, 0x64, 0x00, 0xF0, 0x91, 0x65, 0x00, 0xE4, 0x91, 0x8E, 0x2F, 0x9A, 0xDE, 0x80, 0x91, 0x64, 0x00, 0x90, 0x91, 0x65, 0x00, 0x01, 0x96, 0x90, 0x93, 0x65, 0x00, 0x80, 0x93, 0x64, 0x00, 0x21, 0x96, 0x80, 0x91, 0x66, 0x01, 0x90, 0x91, 0x67, 0x01, 0xC8, 0x17, 0xD9, 0x07, 0xD8, 0xF2, 0xAF, 0xCF, 0x85, 0x37, 0x61, 0xF4, 0x5F, 0xDE, 0x80, 0x32, 0x09, 0xF0, 0xC9, 0xCE, 0x84, 0xE1, 0x80, 0xDE, 0x8E, 0xE1, 0x7E, 0xDE, 0x83, 0xE9, 0x7C, 0xDE, 0x87, 0xE0, 0xA0, 0xCF, 0x86, 0x37, 0x09, 0xF0, 0xBE, 0xCE, 0x80, 0xE0, 0x81, 0xDE, 0xBB, 0xCE, 0xE1, 0x99, 0xFE, 0xCF, 0xBF, 0xBB, 0xAE, 0xBB, 0xE0, 0x9A, 0x11, 0x96, 0x0D, 0xB2, 0x08, 0x95, 0xE1, 0x99, 0xFE, 0xCF, 0xBF, 0xBB, 0xAE, 0xBB, 0x0D, 0xBA, 0x11, 0x96, 0x0F, 0xB6, 0xF8, 0x94, 0xE2, 0x9A, 0xE1, 0x9A, 0x0F, 0xBE, 0x08, 0x95, 0x80, 0x00, 0x00, 0x00, 0x1C, 0x00, }; /* ** This is for an Arduino Mini, atmega168, 16MHz, LED on portb pin 5. ** I received this as a binary from Daniel of the Arduino Forum. */ unsigned char PROGMEM loader168[] = { 0x0C, 0x94, 0x34, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x0C, 0x94, 0x4F, 0x1C, 0x11, 0x24, 0x1F, 0xBE, 0xCF, 0xEF, 0xD4, 0xE0, 0xDE, 0xBF, 0xCD, 0xBF, 0x11, 0xE0, 0xA0, 0xE0, 0xB1, 0xE0, 0xEA, 0xE2, 0xFE, 0xE3, 0x02, 0xC0, 0x05, 0x90, 0x0D, 0x92, 0xA2, 0x30, 0xB1, 0x07, 0xD9, 0xF7, 0x12, 0xE0, 0xA2, 0xE0, 0xB1, 0xE0, 0x01, 0xC0, 0x1D, 0x92, 0xAC, 0x30, 0xB1, 0x07, 0xE1, 0xF7, 0x0C, 0x94, 0xD6, 0x1C, 0x0C, 0x94, 0x00, 0x1C, 0x88, 0x23, 0x09, 0xF4, 0x83, 0xE0, 0x10, 0x92, 0x09, 0x02, 0x90, 0xE0, 0x98, 0x17, 0xF0, 0xF4, 0x69, 0x2F, 0x2D, 0x9A, 0x2F, 0xEF, 0x37, 0xE4, 0x48, 0xEE, 0x51, 0xE0, 0x22, 0x53, 0x30, 0x40, 0x40, 0x40, 0x50, 0x40, 0x57, 0xFF, 0xFA, 0xCF, 0x2D, 0x98, 0x2F, 0xEF, 0x33, 0xED, 0x40, 0xE3, 0x50, 0xE0, 0x22, 0x53, 0x30, 0x40, 0x40, 0x40, 0x50, 0x40, 0x57, 0xFF, 0xFA, 0xCF, 0x96, 0x2F, 0x9F, 0x5F, 0x69, 0x2F, 0x98, 0x17, 0x28, 0xF3, 0x90, 0x93, 0x09, 0x02, 0x08, 0x95, 0xEF, 0x92, 0xFF, 0x92, 0x0F, 0x93, 0x1F, 0x93, 0xEE, 0x24, 0xFF, 0x24, 0x87, 0x01, 0x80, 0x91, 0xC0, 0x00, 0x87, 0xFD, 0x17, 0xC0, 0x08, 0x94, 0xE1, 0x1C, 0xF1, 0x1C, 0x01, 0x1D, 0x11, 0x1D, 0x81, 0xE0, 0xE8, 0x16, 0x82, 0xE1, 0xF8, 0x06, 0x8A, 0xE7, 0x08, 0x07, 0x80, 0xE0, 0x18, 0x07, 0x70, 0xF3, 0xE0, 0x91, 0x02, 0x01, 0xF0, 0x91, 0x03, 0x01, 0x09, 0x95, 0x80, 0x91, 0xC0, 0x00, 0x87, 0xFF, 0xE9, 0xCF, 0x80, 0x91, 0xC6, 0x00, 0x99, 0x27, 0x87, 0xFD, 0x90, 0x95, 0x1F, 0x91, 0x0F, 0x91, 0xFF, 0x90, 0xEF, 0x90, 0x08, 0x95, 0x98, 0x2F, 0x80, 0x91, 0xC0, 0x00, 0x85, 0xFF, 0xFC, 0xCF, 0x90, 0x93, 0xC6, 0x00, 0x08, 0x95, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x32, 0x09, 0xF0, 0x08, 0x95, 0x84, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x80, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x08, 0x95, 0xCF, 0x93, 0xC8, 0x2F, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x32, 0x49, 0xF4, 0x84, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x8C, 0x2F, 0x0E, 0x94, 0xA4, 0x1C, 0x80, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0xCF, 0x91, 0x08, 0x95, 0x28, 0x2F, 0x90, 0xE0, 0x07, 0xC0, 0x80, 0x91, 0xC0, 0x00, 0x88, 0x23, 0xE4, 0xF7, 0x80, 0x91, 0xC6, 0x00, 0x9F, 0x5F, 0x92, 0x17, 0xB8, 0xF3, 0x08, 0x95, 0xCF, 0xEF, 0xD4, 0xE0, 0xDE, 0xBF, 0xCD, 0xBF, 0x00, 0x00, 0x56, 0x98, 0x5E, 0x9A, 0x83, 0xE3, 0x80, 0x93, 0xC4, 0x00, 0x10, 0x92, 0xC5, 0x00, 0x88, 0xE1, 0x80, 0x93, 0xC1, 0x00, 0x86, 0xE0, 0x80, 0x93, 0xC2, 0x00, 0x25, 0x9A, 0x83, 0xE0, 0x0E, 0x94, 0x51, 0x1C, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x33, 0x61, 0xF1, 0x81, 0x33, 0x69, 0xF1, 0x80, 0x34, 0x09, 0xF4, 0x4B, 0xC0, 0x81, 0x34, 0x09, 0xF4, 0x51, 0xC0, 0x82, 0x34, 0x09, 0xF4, 0x60, 0xC0, 0x85, 0x34, 0x09, 0xF4, 0x63, 0xC0, 0x80, 0x35, 0xE1, 0xF0, 0x81, 0x35, 0xD1, 0xF0, 0x82, 0x35, 0xC1, 0xF0, 0x85, 0x35, 0x09, 0xF4, 0x5E, 0xC0, 0x86, 0x35, 0x09, 0xF4, 0x66, 0xC0, 0x84, 0x36, 0x09, 0xF4, 0x68, 0xC0, 0x84, 0x37, 0x09, 0xF4, 0xBA, 0xC0, 0x85, 0x37, 0x09, 0xF4, 0x15, 0xC1, 0x86, 0x37, 0xB9, 0xF6, 0x80, 0xE0, 0x0E, 0x94, 0xB8, 0x1C, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x33, 0xA1, 0xF6, 0x0E, 0x94, 0xAC, 0x1C, 0xCD, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0xC8, 0x2F, 0x80, 0x32, 0x41, 0xF6, 0x84, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x81, 0xE4, 0x0E, 0x94, 0xA4, 0x1C, 0x86, 0xE5, 0x0E, 0x94, 0xA4, 0x1C, 0x82, 0xE5, 0x0E, 0x94, 0xA4, 0x1C, 0x8C, 0x2F, 0x0E, 0x94, 0xA4, 0x1C, 0x89, 0xE4, 0x0E, 0x94, 0xA4, 0x1C, 0x83, 0xE5, 0x0E, 0x94, 0xA4, 0x1C, 0x80, 0xE5, 0x0E, 0x94, 0xA4, 0x1C, 0x80, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0xAC, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x86, 0x38, 0xC0, 0xF2, 0x0E, 0x94, 0x78, 0x1C, 0x0E, 0x94, 0xAC, 0x1C, 0xA3, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x38, 0x09, 0xF4, 0x65, 0xC1, 0x81, 0x38, 0x09, 0xF4, 0x66, 0xC1, 0x82, 0x38, 0x09, 0xF4, 0x67, 0xC1, 0x88, 0x39, 0x09, 0xF0, 0xBE, 0xCF, 0x83, 0xE0, 0x0E, 0x94, 0xB8, 0x1C, 0xBD, 0xCF, 0x84, 0xE1, 0x0E, 0x94, 0xC9, 0x1C, 0x0E, 0x94, 0xAC, 0x1C, 0x8B, 0xCF, 0x85, 0xE0, 0x0E, 0x94, 0xC9, 0x1C, 0xF9, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x05, 0x01, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x06, 0x01, 0x0E, 0x94, 0xAC, 0x1C, 0x7C, 0xCF, 0x84, 0xE0, 0x0E, 0x94, 0xC9, 0x1C, 0x80, 0xE0, 0xA1, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x08, 0x02, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x07, 0x02, 0x80, 0x91, 0x0B, 0x02, 0x8E, 0x7F, 0x80, 0x93, 0x0B, 0x02, 0x0E, 0x94, 0x78, 0x1C, 0x85, 0x34, 0x09, 0xF4, 0xB1, 0xC0, 0x00, 0xE0, 0x10, 0xE0, 0x80, 0x91, 0x07, 0x02, 0x90, 0x91, 0x08, 0x02, 0x18, 0x16, 0x19, 0x06, 0x70, 0xF4, 0xC7, 0xE0, 0xD1, 0xE0, 0x0E, 0x94, 0x78, 0x1C, 0x89, 0x93, 0x0F, 0x5F, 0x1F, 0x4F, 0x80, 0x91, 0x07, 0x02, 0x90, 0x91, 0x08, 0x02, 0x08, 0x17, 0x19, 0x07, 0xA0, 0xF3, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x32, 0x09, 0xF0, 0x49, 0xCF, 0x80, 0x91, 0x0B, 0x02, 0x80, 0xFF, 0x9D, 0xC0, 0x00, 0xE0, 0x10, 0xE0, 0x20, 0x91, 0x07, 0x02, 0x30, 0x91, 0x08, 0x02, 0x12, 0x16, 0x13, 0x06, 0xC0, 0xF4, 0xE0, 0x91, 0x05, 0x01, 0xF0, 0x91, 0x06, 0x01, 0xA7, 0xE0, 0xB1, 0xE0, 0xF9, 0x99, 0xFE, 0xCF, 0xF2, 0xBD, 0xE1, 0xBD, 0x8D, 0x91, 0x80, 0xBD, 0xFA, 0x9A, 0xF9, 0x9A, 0x31, 0x96, 0x0F, 0x5F, 0x1F, 0x4F, 0x02, 0x17, 0x13, 0x07, 0x90, 0xF3, 0xF0, 0x93, 0x06, 0x01, 0xE0, 0x93, 0x05, 0x01, 0x84, 0xE1, 0x70, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x08, 0x02, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x93, 0x07, 0x02, 0x0E, 0x94, 0x78, 0x1C, 0x85, 0x34, 0x09, 0xF4, 0x67, 0xC0, 0x80, 0x91, 0x0B, 0x02, 0x8E, 0x7F, 0x80, 0x93, 0x0B, 0x02, 0x80, 0x91, 0x05, 0x01, 0x90, 0x91, 0x06, 0x01, 0x88, 0x0F, 0x99, 0x1F, 0x90, 0x93, 0x06, 0x01, 0x80, 0x93, 0x05, 0x01, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x32, 0x09, 0xF0, 0x01, 0xCF, 0x84, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x00, 0xE0, 0x10, 0xE0, 0x20, 0x91, 0x07, 0x02, 0x30, 0x91, 0x08, 0x02, 0x12, 0x16, 0x13, 0x06, 0x08, 0xF0, 0x44, 0xCF, 0xE0, 0x91, 0x05, 0x01, 0xF0, 0x91, 0x06, 0x01, 0x80, 0x91, 0x0B, 0x02, 0x80, 0xFF, 0x1F, 0xC0, 0xF9, 0x99, 0xFE, 0xCF, 0xF2, 0xBD, 0xE1, 0xBD, 0xF8, 0x9A, 0x80, 0xB5, 0x0E, 0x94, 0xA4, 0x1C, 0xE0, 0x91, 0x05, 0x01, 0xF0, 0x91, 0x06, 0x01, 0x31, 0x96, 0xF0, 0x93, 0x06, 0x01, 0xE0, 0x93, 0x05, 0x01, 0x20, 0x91, 0x07, 0x02, 0x30, 0x91, 0x08, 0x02, 0x0F, 0x5F, 0x1F, 0x4F, 0x02, 0x17, 0x13, 0x07, 0x08, 0xF0, 0x21, 0xCF, 0x80, 0x91, 0x0B, 0x02, 0x80, 0xFD, 0xE1, 0xCF, 0x86, 0x95, 0x80, 0xFF, 0x9D, 0xC0, 0x31, 0x96, 0xF0, 0x93, 0x06, 0x01, 0xE0, 0x93, 0x05, 0x01, 0xED, 0xCF, 0x0E, 0x94, 0x78, 0x1C, 0x80, 0x32, 0x09, 0xF0, 0xBF, 0xCE, 0x84, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x8E, 0xE1, 0x0E, 0x94, 0xA4, 0x1C, 0x84, 0xE9, 0x0E, 0x94, 0xA4, 0x1C, 0x86, 0xE0, 0x02, 0xCF, 0x80, 0x91, 0x0B, 0x02, 0x81, 0x60, 0x80, 0x93, 0x0B, 0x02, 0x49, 0xCF, 0x80, 0x91, 0x0B, 0x02, 0x81, 0x60, 0x80, 0x93, 0x0B, 0x02, 0xA2, 0xCF, 0x80, 0x91, 0x06, 0x01, 0x87, 0xFD, 0x67, 0xC0, 0x10, 0x92, 0x0A, 0x02, 0x80, 0x91, 0x05, 0x01, 0x90, 0x91, 0x06, 0x01, 0x88, 0x0F, 0x99, 0x1F, 0x90, 0x93, 0x06, 0x01, 0x80, 0x93, 0x05, 0x01, 0x80, 0x91, 0x07, 0x02, 0x80, 0xFF, 0x09, 0xC0, 0x80, 0x91, 0x07, 0x02, 0x90, 0x91, 0x08, 0x02, 0x01, 0x96, 0x90, 0x93, 0x08, 0x02, 0x80, 0x93, 0x07, 0x02, 0xF8, 0x94, 0xF9, 0x99, 0xFE, 0xCF, 0x11, 0x27, 0xE0, 0x91, 0x05, 0x01, 0xF0, 0x91, 0x06, 0x01, 0xC7, 0xE0, 0xD1, 0xE0, 0x80, 0x91, 0x07, 0x02, 0x90, 0x91, 0x08, 0x02, 0x10, 0x30, 0x91, 0xF4, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x03, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x01, 0xE1, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x09, 0x90, 0x19, 0x90, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x01, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x13, 0x95, 0x10, 0x34, 0x98, 0xF0, 0x11, 0x27, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x05, 0xE0, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x00, 0x91, 0x57, 0x00, 0x01, 0x70, 0x01, 0x30, 0xD9, 0xF3, 0x01, 0xE1, 0x00, 0x93, 0x57, 0x00, 0xE8, 0x95, 0x32, 0x96, 0x02, 0x97, 0x09, 0xF0, 0xC7, 0xCF, 0x10, 0x30, 0x11, 0xF0, 0x02, 0x96, 0xE5, 0xCF, 0x11, 0x24, 0x84, 0xE1, 0x8B, 0xCE, 0x81, 0xE0, 0x80, 0x93, 0x0A, 0x02, 0x97, 0xCF, 0x82, 0xE0, 0x0E, 0x94, 0xB8, 0x1C, 0x61, 0xCE, 0x81, 0xE0, 0x0E, 0x94, 0xB8, 0x1C, 0x5D, 0xCE, 0x8F, 0xE0, 0x0E, 0x94, 0xB8, 0x1C, 0x59, 0xCE, 0x84, 0x91, 0x0E, 0x94, 0xA4, 0x1C, 0x20, 0x91, 0x07, 0x02, 0x30, 0x91, 0x08, 0x02, 0xE0, 0x91, 0x05, 0x01, 0xF0, 0x91, 0x06, 0x01, 0x57, 0xCF, 0x1F, 0x93, 0xCF, 0x93, 0x0E, 0x94, 0x78, 0x1C, 0xC8, 0x2F, 0x0E, 0x94, 0xA4, 0x1C, 0x0E, 0x94, 0x78, 0x1C, 0x18, 0x2F, 0x0E, 0x94, 0xA4, 0x1C, 0xC1, 0x36, 0x2C, 0xF0, 0xC7, 0x55, 0x11, 0x36, 0x3C, 0xF0, 0x17, 0x55, 0x08, 0xC0, 0xC0, 0x33, 0xD4, 0xF3, 0xC0, 0x53, 0x11, 0x36, 0xCC, 0xF7, 0x10, 0x33, 0x0C, 0xF0, 0x10, 0x53, 0xC2, 0x95, 0xC0, 0x7F, 0xC1, 0x0F, 0x8C, 0x2F, 0x99, 0x27, 0x87, 0xFD, 0x90, 0x95, 0xCF, 0x91, 0x1F, 0x91, 0x08, 0x95, 0xCF, 0x93, 0x28, 0x2F, 0x99, 0x27, 0x87, 0xFD, 0x90, 0x95, 0x80, 0x7F, 0x90, 0x70, 0x95, 0x95, 0x87, 0x95, 0x95, 0x95, 0x87, 0x95, 0x95, 0x95, 0x87, 0x95, 0x95, 0x95, 0x87, 0x95, 0x8A, 0x30, 0x3C, 0xF0, 0x89, 0x5A, 0xC2, 0x2F, 0xCF, 0x70, 0xCA, 0x30, 0x3C, 0xF0, 0xC9, 0x5A, 0x06, 0xC0, 0x80, 0x5D, 0xC2, 0x2F, 0xCF, 0x70, 0xCA, 0x30, 0xCC, 0xF7, 0xC0, 0x5D, 0x0E, 0x94, 0xA4, 0x1C, 0x8C, 0x2F, 0x0E, 0x94, 0xA4, 0x1C, 0xCF, 0x91, 0x08, 0x95, 0x80, 0x00, 0x00, 0x00, 0x38, 0x00, }; void Write_Bootloader() { unsigned int loaderSize = 0; unsigned char *loaderPtr = 0; unsigned int page = 0; SeizeTarget(); Probe_Device(); switch( signature2) { case atmega8: loaderSize = sizeof(loader8); loaderPtr = loader8; serialprintflash(PSTR("Installing atmega8 serial bootloader at ")); page = (flashMax-bootSize)/(pageWords*2); Serial.print(page*pageWords,HEX); serialprintflash(PSTR("... ")); break; case atmega48: case atmega88: case atmega168: loaderSize = sizeof(loader168); loaderPtr = loader168; serialprintflash(PSTR("Installing atmega168 serial bootloader at ")); page = (flashMax-bootSize)/(pageWords*2); Serial.print(page*pageWords,HEX); serialprintflash(PSTR("... ")); break; default: serialprintflash(PSTR("Unknown device type. Failed.\n")); ReleaseTarget(); return; } if ( loaderSize > bootSize) { serialprintflash(PSTR("Loader is too large for fused bootsize.\n")); ReleaseTarget(); return; } for ( int i = 0; i < loaderSize; ) { uint16_t pollAddr = 0; uint8_t pollByte = 0; cli(); for ( int j = 0; j < pageWords; j++) { if ( !pollAddr && pgm_read_byte(loaderPtr) != 0xff) { pollAddr = j; pollByte = pgm_read_byte(loaderPtr); } CMD_Load_Page_Low( j, pgm_read_byte(loaderPtr)); loaderPtr++; i++; CMD_Load_Page_High( j, pgm_read_byte(loaderPtr)); loaderPtr++; i++; } CMD_Write_Page_Clean( page*pageWords); sei(); page++; // don't put it in that macro, it gets evaluated twice. if ( pollAddr) { unsigned long bailOut = millis() + 20; while( CMD_Read_Flash_Low(pollAddr) == 0xff && millis() < bailOut); } else delay(11); BlinkRun(0); } serialprintflash(PSTR("... done.\n")); Serial.println(); ReleaseTarget(); } #endif