/* main program starts here */ int main(void) { uint8_t ch; /* * Making these local and in registers prevents the need for initializing * them, and also saves space because code no longer stores to memory. * (initializing address keeps the compiler happy, but isn't really * necessary, and uses 4 bytes of flash.) */ register uint16_t address = 0; register pagelen_t length; // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: // cli(); asm volatile ("clr __zero_reg__"); #if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) SP=RAMEND; // This is done by hardware reset #endif /* * modified Adaboot no-wait mod. * Pass the reset reason to app. Also, it appears that an Uno poweron * can leave multiple reset flags set; we only want the bootloader to * run on an 'external reset only' status */ ch = MCUSR; MCUSR = 0; if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF))) appStart(ch); #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 #endif #ifndef SOFT_UART #if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) UCSRA = _BV(U2X); //Double speed mode USART UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #else UART_SRA = _BV(U2X0); //Double speed mode USART0 UART_SRB = _BV(RXEN0) | _BV(TXEN0); UART_SRC = _BV(UCSZ00) | _BV(UCSZ01); UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #endif #endif // Set up watchdog to trigger after 1s watchdogConfig(WATCHDOG_1S); #if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) /* Set LED pin as output */ LED_DDR |= _BV(LED); #endif #ifdef SOFT_UART /* Set TX pin as output */ UART_DDR |= _BV(UART_TX_BIT); #endif #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ flash_led(LED_START_FLASHES * 2); #endif /* Forever loop: exits by causing WDT reset */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { unsigned char which = getch(); verifySpace(); /* * Send optiboot version as "SW version" * Note that the references to memory are optimized away. */ if (which == 0x82) { putch(optiboot_version & 0xFF); } else if (which == 0x81) { putch(optiboot_version >> 8); } else {
void getNch(uint8_t count) { do getch(); while (--count); verifySpace(); }
/* main program starts here */ int main(void) { uint8_t ch; /* * Making these local and in registers prevents the need for initializing * them, and also saves space because code no longer stores to memory. * (initializing address keeps the compiler happy, but isn't really * necessary, and uses 4 bytes of flash.) */ register uint16_t address = 0; register uint8_t length; // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: // cli(); asm volatile ("clr __zero_reg__"); #ifdef __AVR_ATmega8__ SP=RAMEND; // This is done by hardware reset #endif // Adaboot no-wait mod ch = MCUSR; MCUSR = 0; if (!(ch & _BV(EXTRF))) appStart(); #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 #endif #ifndef SOFT_UART #ifdef __AVR_ATmega8__ UCSRA = _BV(U2X); //Double speed mode USART UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #else UCSR0A = _BV(U2X0); //Double speed mode USART0 UCSR0B = _BV(RXEN0) | _BV(TXEN0); UCSR0C = _BV(UCSZ00) | _BV(UCSZ01); UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #endif #endif // Set up watchdog to trigger after 500ms watchdogConfig(WATCHDOG_1S); /* Set LED pin as output */ LED_DDR |= _BV(LED); #ifdef SOFT_UART /* Set TX pin as output */ UART_DDR |= _BV(UART_TX_BIT); #endif #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ flash_led(LED_START_FLASHES * 2); #endif /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { unsigned char which = getch(); verifySpace(); if (which == 0x82) { /* * Send optiboot version as "minor SW version" */ putch(OPTIBOOT_MINVER); } else if (which == 0x81) { putch(OPTIBOOT_MAJVER); } else { /* * GET PARAMETER returns a generic 0x03 reply for * other parameters - enough to keep Avrdude happy */ putch(0x03); } } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(5); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS uint16_t newAddress; newAddress = getch(); newAddress = (newAddress & 0xff) | (getch() << 8); #ifdef RAMPZ // Transfer top bit to RAMPZ RAMPZ = (newAddress & 0x8000) ? 1 : 0; #endif newAddress += newAddress; // Convert from word address to byte address address = newAddress; verifySpace(); } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t *bufPtr; uint16_t addrPtr; getch(); /* getlen() */ length = getch(); getch(); // If we are in RWW section, immediately start page erase if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); // While that is going on, read in page contents bufPtr = buff; do *bufPtr++ = getch(); while (--length); // If we are in NRWW section, page erase has to be delayed until now. // Todo: Take RAMPZ into account if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); // Read command terminator, start reply verifySpace(); // If only a partial page is to be programmed, the erase might not be complete. // So check that here boot_spm_busy_wait(); #ifdef VIRTUAL_BOOT_PARTITION if ((uint16_t)(void*)address == 0) { // This is the reset vector page. We need to live-patch the code so the // bootloader runs. // // Move RESET vector to WDT vector uint16_t vect = buff[0] | (buff[1]<<8); rstVect = vect; wdtVect = buff[8] | (buff[9]<<8); vect -= 4; // Instruction is a relative jump (rjmp), so recalculate. buff[8] = vect & 0xff; buff[9] = vect >> 8; // Add jump to bootloader at RESET vector buff[0] = 0x7f; buff[1] = 0xce; // rjmp 0x1d00 instruction } #endif // Copy buffer into programming buffer bufPtr = buff; addrPtr = (uint16_t)(void*)address; ch = SPM_PAGESIZE / 2; do { uint16_t a; a = *bufPtr++; a |= (*bufPtr++) << 8; __boot_page_fill_short((uint16_t)(void*)addrPtr,a); addrPtr += 2; } while (--ch); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)address); boot_spm_busy_wait(); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif }
/* main program starts here */ int main(void) { // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: cli(); SP=RAMEND; // This is done by hardware reset asm volatile ("clr __zero_reg__"); uint8_t ch; // Adaboot no-wait mod ch = MCUSR; MCUSR = 0; if (!(ch & _BV(EXTRF))) appStart(); // Set up watchdog to trigger after 500ms watchdogConfig(WATCHDOG_OFF); DDRD = 0; PORTD = 0; PORTC = 0; DDRC = C3_WR | C2_RD; /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy getNch(1); putch(0x03); } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(5); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS address = getch(); address = (address & 0xff) | (getch() << 8); address += address; // Convert from word address to byte address verifySpace(); } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t *bufPtr; uint16_t addrPtr; getLen(); // Immediately start page erase - this will 4.5ms boot_page_erase((uint16_t)(void*)address); // While that is going on, read in page contents bufPtr = buff; do *bufPtr++ = getch(); while (--length); // Read command terminator, start reply verifySpace(); // If only a partial page is to be programmed, the erase might not be complete. // So check that here boot_spm_busy_wait(); // Copy buffer into programming buffer bufPtr = buff; addrPtr = (uint16_t)(void*)address; ch = SPM_PAGESIZE / 2; do { uint16_t a; a = *bufPtr++; a |= (*bufPtr++) << 8; boot_page_fill((uint16_t)(void*)addrPtr,a); addrPtr += 2; } while (--ch); // Write from programming buffer boot_page_write((uint16_t)(void*)address); boot_spm_busy_wait(); // Reenable read access to flash boot_rww_enable(); } /* Read memory block mode, length is big endian. */ else if(ch == STK_READ_PAGE) { // READ PAGE - we only read flash getLen(); verifySpace(); do putch(pgm_read_byte_near(address++)); while (--length); } /* Get device signature bytes */ else if(ch == STK_READ_SIGN) { // READ SIGN - return what Avrdude wants to hear verifySpace(); putch(SIGNATURE_0); putch(SIGNATURE_1); putch(SIGNATURE_2); } else if (ch == 'Q') { // Adaboot no-wait mod watchdogConfig(WATCHDOG_16MS); verifySpace(); } else { // This covers the response to commands like STK_ENTER_PROGMODE verifySpace(); } putch(STK_OK); } }
/* main program starts here */ int main(void) { uint8_t ch; uint8_t WaitTime = WATCHDOG_1S; // Set watchdog to trigger after 1 second by default - value set to the watchdog later! /* * Making these local and in registers prevents the need for initializing * them, and also saves space because code no longer stores to memory. * (initializing address keeps the compiler happy, but isn't really * necessary, and uses 4 bytes of flash.) */ register uint16_t address = 0; register pagelen_t length; // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: // Following lines enabled by Mark Griffiths to allow jumping directly to the boot loader from user code. cli(); asm volatile ("clr __zero_reg__"); //#if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) SP=RAMEND; // This is done by hardware reset //#endif /* * modified Adaboot no-wait mod. * Pass the reset reason to app. Also, it appears that an Uno poweron * can leave multiple reset flags set; we only want the bootloader to * run on an 'external reset only' status */ // ch = MCUSR; // MCUSR = 0; // if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF))) // appStart(ch); // Modified no wait mod by Mark Griffiths 8th of April 2015 // This modification allows the majority of the reset flags to be kept // unmodified in the MCUSR register for use by user sketches! // Previous method saved the MCUSR data in r2, but because it cleared // MCUSR before attempting to update the flash memory, there was no way // for user code to distinguish between an external reset and a watchdog // reset. It also required extra code and an extra byte of RAM in the // user sketch. ch = MCUSR; if (ch == 0) { WaitTime = WATCHDOG_8S; // If no Reset Flags are set, it must mean that the user code jumped to the boot loader! Wait 8 seconds for the firmware to be updated! } else { if ((ch & (_BV(WDRF) | _BV(EXTRF))) != _BV(EXTRF)) { // To run the boot loader, External Reset Flag must be set and the Watchdog Flag MUST be cleared! Otherwise jump straight to user code. MCUSR = ~(_BV(WDRF)); appStart(ch); } } #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 #endif #ifndef SOFT_UART #if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) UCSRA = _BV(U2X); //Double speed mode USART UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #else UART_SRA = _BV(U2X0); //Double speed mode USART0 UART_SRB = _BV(RXEN0) | _BV(TXEN0); UART_SRC = _BV(UCSZ00) | _BV(UCSZ01); UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #endif #endif watchdogConfig(WaitTime); #if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) /* Set LED pin as output */ LED_DDR |= _BV(LED); #endif #ifdef SOFT_UART /* Set TX pin as output */ UART_DDR |= _BV(UART_TX_BIT); #endif #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ flash_led(LED_START_FLASHES * 2); #endif /* Forever loop: exits by causing WDT reset */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { unsigned char which = getch(); verifySpace(); /* * Send optiboot version as "SW version" * Note that the references to memory are optimized away. */ if (which == 0x82) { putch(optiboot_version & 0xFF); } else if (which == 0x81) { putch(optiboot_version >> 8); } else {
uint8_t proccessCommand() { uint8_t ch; ch = getch(); if(ch == STK_GET_PARAMETER) { unsigned char which = getch(); verifySpace(); if(which == 0x82) { /* * Send tftpboot version as "minor SW version" */ putch(ARIADNE_MINVER); } else if(which == 0x81) { putch(ARIADNE_MAJVER); } else { /* * GET PARAMETER returns a generic 0x03 reply for * other parameters - enough to keep Avrdude happy */ putch(0x03); } } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(4); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS uint16_t newAddress; newAddress = getch(); newAddress = (newAddress & 0xff) | (getch() << 8); #ifdef RAMPZ // Transfer top bit to RAMPZ RAMPZ = (newAddress & 0x8000) ? 1 : 0; #endif newAddress += newAddress; // Convert from word address to byte address address = newAddress; verifySpace(); } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // This should probably go somewhere but I don't yet know it's place //eeprom_write_byte(EEPROM_IMG_STAT, EEPROM_IMG_BAD_VALUE); // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t buff[256]; uint8_t* bufPtr; uint16_t addrPtr; getch(); /* getlen() */ length = getch(); getch(); // If we are in RWW section, immediately start page erase if(address < NRWWSTART) boot_page_erase((uint16_t)(void*)address); // While that is going on, read in page contents bufPtr = buff; do* bufPtr++ = getch(); while(--length); // If we are in NRWW section, page erase has to be delayed until now. // Todo: Take RAMPZ into account if(address >= NRWWSTART) boot_page_erase((uint16_t)(void*)address); // Read command terminator, start reply verifySpace(); // If only a partial page is to be programmed, the erase might not be complete. // So check that here boot_spm_busy_wait(); // Copy buffer into programming buffer bufPtr = buff; addrPtr = (uint16_t)(void*)address; ch = SPM_PAGESIZE / 2; do { uint16_t a; a = *bufPtr++; a |= (*bufPtr++) << 8; boot_page_fill((uint16_t)(void*)addrPtr, a); addrPtr += 2; } while(--ch); // Write from programming buffer boot_page_write((uint16_t)(void*)address); boot_spm_busy_wait(); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif } /* Read memory block mode, length is big endian. */ else if(ch == STK_READ_PAGE) { // READ PAGE - we only read flash getch(); /* getlen() */ length = getch(); getch(); verifySpace(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560) // do putch(pgm_read_byte_near(address++)); // while (--length); do { uint8_t result; __asm__("elpm %0,Z\n":"=r"(result):"z"(address)); putch(result); address++; } while(--length); #else do putch(pgm_read_byte_near(address++)); while(--length); #endif }
/* main program starts here */ int main(void) { uint8_t ch; uint16_t pmask; /* * Making these local and in registers prevents the need for initializing * them, and also saves space because code no longer stores to memory. * (initializing address keeps the compiler happy, but isn't really * necessary, and uses 4 bytes of flash.) */ register uint16_t address = 0; register uint16_t length; // After the zero init loop, this is the first code to run. // // This code makes the following assumptions: // No interrupts will execute // SP points to RAMEND // r1 contains zero // // If not, uncomment the following instructions: // cli(); asm volatile ("clr __zero_reg__"); SP=RAMEND; // This is done by hardware reset // Adaboot no-wait mod ch = MCUSR; MCUSR = 0; if (ch & (_BV(WDRF) | _BV(BORF) | _BV(PORF))) appStart(ch); // WDT clock by 32KHz IRC PMCR = 0x80; PMCR = 0x93; #if EXT_OSC == 1 #warning Using external crystal now!!! // for case of 16MHz crystall, no clock divider PMCR = 0x80; PMCR = 0x97; for(ch = 0xf; ch > 0; --ch); PMCR = 0x80; PMCR = 0xb7; CLKPR = 0x80; CLKPR = 0x00; // external crsyall flag VDTCR = 0x80; VDTCR = 0x4C; #else // system clock: 16MHz system clock CLKPR = 0x80; CLKPR = 0x01; #endif #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 #endif #ifndef SOFT_UART #if defined(__AVR_ATmega8__) || defined (__AVR_ATmega32__) UCSRA = _BV(U2X); //Double speed mode USART UCSRB = _BV(RXEN) | _BV(TXEN); // enable Rx & Tx UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0); // config USART; 8N1 UBRRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #else //UART_SRA = _BV(U2X0); //Double speed mode USART0 ch = PMXCR | 0x03; PMXCR = 0x80; PMXCR = ch; UART_SRB = _BV(RXEN0) | _BV(TXEN0); UART_SRC = _BV(UCSZ00) | _BV(UCSZ01); UART_SRL = (uint8_t)( F_CPU / (BAUD_RATE * 16L) - 1 ); //UART_SRL = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); #endif #endif // Set up watchdog to trigger after 500ms watchdogConfig(WATCHDOG_16MS); #if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) /* Set LED pin as output */ LED_DDR |= _BV(LED); #endif #ifdef SOFT_UART /* Set TX pin as output */ UART_DDR |= _BV(UART_TX_BIT); #endif #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ flash_led(LED_START_FLASHES * 2); #endif // page erased flag pmask = 0; /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { unsigned char which = getch(); verifySpace(); if (which == 0x82) { /* * Send optiboot version as "minor SW version" */ putch(OPTIBOOT_MINVER); } else if (which == 0x81) { putch(OPTIBOOT_MAJVER); } else { /* * GET PARAMETER returns a generic 0x03 reply for * other parameters - enough to keep Avrdude happy */ putch(0x03); } } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(5); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS uint16_t newAddress; newAddress = getch(); newAddress = (newAddress & 0xff) | (getch() << 8); #ifdef RAMPZ // Transfer top bit to RAMPZ RAMPZ = (newAddress & 0x8000) ? 1 : 0; #endif newAddress += newAddress; // Convert from word address to byte address address = newAddress; verifySpace(); } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t *bufPtr; uint8_t bval; uint16_t len; length = (uint16_t)getch() << 8; /* getlen() */ length += getch(); bval = getch(); // If we are in RWW section, immediately start page erase //if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address); // While that is going on, read in page contents bufPtr = buff; len = length; do *bufPtr++ = getch(); while (--len); EEARL = 0; EEARH = address >> 8; ch = EEARH >> 2; // 1KB page size if((0 == (pmask & (((uint16_t)1 << ch)))) && bval == 'F') { pmask |= ((uint16_t)1 << ch); // do page erase here EECR = 0x94; EECR = 0x92; asm("nop"); asm("nop"); } // Read command terminator, start reply verifySpace(); // If only a partial page is to be programmed, the erase might not be complete. // So check that here //boot_spm_busy_wait(); if (bval == 'E') { for(len = 0; len < length; len++) { if(address >= 512) break; EEARL = address++; EEARH = address >> 8; EEDR = buff[len]; EECR = 0x04; EECR = 0x02; } } else { #ifdef VIRTUAL_BOOT_PARTITION if ((uint16_t)(void*)address == 0) { // This is the reset vector page. We need to live-patch the code so the // bootloader runs. // // Move RESET vector to WDT vector uint16_t vect = buff[0] | (buff[1] << 8); rstVect = vect; wdtVect = buff[8] | (buff[9] << 8); vect -= 4; buff[8] = vect & 0xff; buff[9] = vect >> 8; // Add jump to bootloader at RESET vector buff[0] = 0xff; buff[1] = 0xcd; // jmp } #endif // Write from programming buffer bufPtr = buff; for(length = 0; length < SPM_PAGESIZE; length+=2) { EEARL = 0; EEDR = *bufPtr++; EEARL = 1; EEDR = *bufPtr++; EEARL = (address + length) & 0xff; EECR = 0xA4; EECR = 0xA2; } }
/* main program starts here */ void optiboot(void) { uint8_t ch; /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); uint8_t reply = STK_OK; if(ch == STK_GET_PARAMETER) { // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy getNch(1); putch(0x03); } else if(ch == STK_SET_DEVICE) { // SET DEVICE is ignored getNch(20); } else if(ch == STK_SET_DEVICE_EXT) { // SET DEVICE EXT is ignored getNch(5); } else if(ch == STK_LOAD_ADDRESS) { // LOAD ADDRESS uint16_t address = getch(); address = (address & 0xff) | (getch() << 8); verifySpace(); // address is in words right now if (address % (SPM_PAGESIZE / 2)) { reply = STK_FAILED; } else { // Convert to page address page = address / (SPM_PAGESIZE / 2); } } else if(ch == STK_UNIVERSAL) { // UNIVERSAL command is ignored getNch(4); putch(0x00); } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { // PROGRAM PAGE uint8_t *bufPtr = buff; // we support flash programming only, not EEPROM if ((getLen() == 'E') || (length > SPM_PAGESIZE) || (page >= (CONFIG_BOOTLDR_START_ADDR / SPM_PAGESIZE))) { reply = STK_FAILED; } // Clear the buffer memset(buff, 0xff, sizeof(buff)); // Read in page contents do *bufPtr++ = getch(); while (--length); // Read command terminator, start reply verifySpace(); if (reply == STK_OK) { // Write the page stubboot_write_page(page, buff); } } /* Read memory block mode, length is big endian. */ else if(ch == STK_READ_PAGE) { // READ PAGE - we only read flash if (getLen() == 'E') { reply = STK_FAILED; } verifySpace(); #if (FLASHEND > USHRT_MAX) uint_farptr_t address = (uint_farptr_t)page * SPM_PAGESIZE; #else uint16_t address = page * SPM_PAGESIZE; #endif while (length--) { #if (FLASHEND > USHRT_MAX) putch(pgm_read_byte_far(address++)); #else putch(pgm_read_byte_near(address++)); #endif } } /* Get device signature bytes */ else if(ch == STK_READ_SIGN) { // READ SIGN - return what Avrdude wants to hear verifySpace(); putch(SIGNATURE_0); putch(SIGNATURE_1); putch(SIGNATURE_2); } else { // This covers the response to commands like STK_ENTER_PROGMODE verifySpace(); } putch(reply); } }