static void programPage(uint16_t page, uint8_t *buf) { // these function calls use "out" commands: save some bytes and cycles :) __boot_page_erase_short(page); boot_spm_busy_wait(); for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) { uint16_t data_word = *buf++; data_word += (*buf++) << 8; __boot_page_fill_short(page + i, data_word); } __boot_page_write_short(page); boot_spm_busy_wait(); __boot_rww_enable_short(); }
/* 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 }
void CheckFlashImage() { #ifdef DEBUG_ON putch('F'); #endif watchdogConfig(WATCHDOG_OFF); #ifdef ANARDUINO #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) DDRB |= _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for SS, MOSI, SCK DDRD |= _BV(FLASHSS); //OUTPUTS for FLASH_SS FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #endif #else //MOTEINO //SPI INIT #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) DDRB |= _BV(FLASHSS) | _BV(SS) | _BV(PINB3) | _BV(PINB5); //OUTPUTS for FLASH_SS and SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #elif defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega644P__) DDRC |= _BV(FLASHSS); //OUTPUT for FLASH_SS DDRB |= _BV(SS) | _BV(PB5) | _BV(PB7); //OUTPUTS for SS, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PORTB |= _BV(SS); //set SS HIGH #endif #endif // MOTEINO*/ //SPCR &= ~(_BV(DORD)); //MSB first //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0 //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2 //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK); // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT. SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value //FLASH_SELECT; FLASH_command(SPIFLASH_JEDECID,1); uint8_t deviceId = SPI_transfer(0); FLASH_UNSELECT; #ifdef DEBUG_ON putch(deviceId); #endif // Disabled check, as it only returns 0xFF or 0x00 for some reasons if (deviceId==0 || deviceId==0xFF) return; //global unprotect FLASH_command(SPIFLASH_STATUSWRITE, 1); SPI_transfer(0); FLASH_UNSELECT; #ifdef DEBUG_ON putch('I'); #endif //check if any flash image exists on external FLASH chip if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':') { #ifdef DEBUG_ON putch('L'); #endif uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8); if (imagesize%2!=0) return; //basic check that we got even # of bytes uint16_t b, i, nextAddress=0; LED_PIN |= _BV(LED); for (i=0; i<imagesize; i+=2) { #ifdef DEBUG_ON putch('*'); #endif //read 2 bytes (16 bits) from flash image, transfer them to page buffer b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes) b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash __boot_page_fill_short((uint16_t)(void*)i,b); //when 1 page is full (or we're on the last page), write it to the internal flash memory if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize)) { __boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); nextAddress += SPM_PAGESIZE; } } LED_PIN &= ~_BV(LED); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif #ifdef DEBUG_ON putch('E'); #endif #ifdef ANARDUINO // Anarduino doesn't support 32K block erase. Do it, with 8 pages of 4k each int page; long address; for (page = 0, address=0; page< 8; page++) { FLASH_command(SPIFLASH_BLOCKERASE_4K, 1); SPI_transfer(address >> 16); SPI_transfer(address >> 8); SPI_transfer(address); FLASH_UNSELECT; while (FLASH_busy()); address += 0x1000; } #else // MOTEINO //erase the first 32/64K block where flash image resided (atmega328 should be less than 31K, and atmega1284 can be up to 64K) if (imagesize+10<=32768) FLASH_command(SPIFLASH_BLOCKERASE_32K, 1); else FLASH_command(SPIFLASH_BLOCKERASE_64K, 1); SPI_transfer(0); SPI_transfer(0); SPI_transfer(0); #endif FLASH_UNSELECT; //now trigger a watchdog reset watchdogConfig(WATCHDOG_16MS); // short WDT timeout while (1); // and busy-loop so that WD causes a reset and app start }
void CheckFlashImage() { #ifdef DEBUG_ON putch('F'); #endif watchdogConfig(WATCHDOG_OFF); //SPI INIT FLASHSS_DDR |= _BV(FLASHSS) | _BV(SS) | _BV(PB3) | _BV(PB5); //OUTPUTS for D8 and D10, MOSI, SCK FLASH_UNSELECT; //unselect FLASH chip PINB |= _BV(SS); //set D10 HIGH //SPCR &= ~(_BV(DORD)); //MSB first //SPCR = (SPCR & ~SPI_MODE_MASK) | SPI_MODE0 ; //SPI MODE 0 //SPCR = (SPCR & ~SPI_CLOCK_MASK) | (SPI_CLOCK_DIV2 & SPI_CLOCK_MASK); //clock divider = 2 //SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((SPI_CLOCK_DIV2 >> 2) & SPI_2XCLOCK_MASK); // Warning: if the SS pin ever becomes a LOW INPUT then SPI automatically switches to Slave, so the data direction of the SS pin MUST be kept as OUTPUT. SPCR |= _BV(MSTR) | _BV(SPE); //enable SPI and set SPI to MASTER mode //read first byte of JEDECID, if chip is present it should return a non-0 and non-FF value FLASH_SELECT; SPI_transfer(SPIFLASH_JEDECID); uint8_t deviceId = SPI_transfer(0); FLASH_UNSELECT; if (deviceId==0 || deviceId==0xFF) return; //global unprotect FLASH_command(SPIFLASH_STATUSWRITE, 1); SPI_transfer(0); FLASH_UNSELECT; //check if any flash image exists on external FLASH chip if (FLASH_readByte(0)=='F' && FLASH_readByte(1)=='L' && FLASH_readByte(2)=='X' && FLASH_readByte(6)==':' && FLASH_readByte(9)==':') { #ifdef DEBUG_ON putch('L'); #endif uint16_t imagesize = (FLASH_readByte(7)<<8) | FLASH_readByte(8); if (imagesize%2!=0) return; //basic check that we got even # of bytes uint16_t b, i, nextAddress=0; LED_PIN |= _BV(LED); for (i=0; i<imagesize; i+=2) { #ifdef DEBUG_ON putch('*'); #endif //read 2 bytes (16 bits) from flash image, transfer them to page buffer b = FLASH_readByte(i+10); // flash image starts at position 10 on the external flash memory: FLX:XX:FLASH_IMAGE_BYTES_HERE...... (XX = two size bytes) b |= FLASH_readByte(i+11) << 8; //bytes are stored big endian on external flash, need to flip the bytes to little endian for transfer to internal flash __boot_page_fill_short((uint16_t)(void*)i,b); //when 1 page is full (or we're on the last page), write it to the internal flash memory if ((i+2)%SPM_PAGESIZE==0 || (i+2==imagesize)) { __boot_page_erase_short((uint16_t)(void*)nextAddress); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); // Write from programming buffer __boot_page_write_short((uint16_t)(void*)nextAddress ); //(i+2-SPM_PAGESIZE) boot_spm_busy_wait(); nextAddress += SPM_PAGESIZE; } } LED_PIN &= ~_BV(LED); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); #endif #ifdef DEBUG_ON putch('E'); #endif //erase the first 32K block where flash image resided FLASH_command(SPIFLASH_BLOCKERASE_32K, 1); SPI_transfer(0); SPI_transfer(0); SPI_transfer(0); FLASH_UNSELECT; //now trigger a watchdog reset watchdogConfig(WATCHDOG_16MS); // short WDT timeout while (1); // and busy-loop so that WD causes a reset and app start } #ifdef DEBUG_ON putch('X'); #endif }