void ws_flash_write_page(uint32_t address, uint8_t *buf) { uint32_t i; uint8_t sreg; uint8_t *buffer; buffer = buf; // Disable interrupts sreg = SREG; cli(); // Start by erasing the page at given address boot_page_erase_safe (address); boot_spm_busy_wait (); // Wait until the memory is erased for(i=0; i<PAGESIZE; i+=2){ uint16_t w = *buffer++; w += (*buffer++) << 8; boot_page_fill_safe(address+i, w); } boot_page_write_safe (address); boot_spm_busy_wait (); while(boot_rww_busy()){ boot_rww_enable_safe();} boot_rww_enable(); SREG = sreg; }
//**************************[system_bootloader_error]************************** 26.10.2015 void system_bootloader_error() { // enable read while write section cli(); boot_rww_enable_safe(); sei(); eeprom_busy_wait(); boot_spm_busy_wait(); // send error string bootloader_data_out('e'); bootloader_data_out('r'); bootloader_data_out('r'); bootloader_data_out('o'); bootloader_data_out('r'); bootloader_data_out(13 ); // notify user if (! bootloader_error()) { system_bootloader_reset(); } uint8_t t = 100; // dump every data until there is no more data for 0.1 second while (t--) { if (bootloader_data_stat()) { bootloader_data_in(); t = 100; } delay_ms(1); } }
int main(void) { CLKPR = 0x80; CLKPR = 0x00; MCUCR = (1<<IVCE); MCUCR = (1<<IVSEL); i2c_slave_transmit = transmit; i2c_slave_receive = receive; i2c_slave_init(0x10); addr = 0x0000; read_page(addr); sei(); do { _delay_ms(1000); } while (state != BOOT); cli(); write_page(); MCUCR = (1<<IVCE); MCUCR = (0<<IVSEL); app_main = (void *)addr; boot_rww_enable_safe(); app_main(); }
void read_page(uint16_t address) { boot_rww_enable_safe(); page_address = address; for (i = 0; i < SPM_PAGESIZE; i++) { page_buffer[i] = pgm_read_byte(address + i); } page_dirty = 0; }
unsigned char transmit(volatile unsigned char *buffer, unsigned char size) { if (state != READ) return 0; int i; write_page(); boot_rww_enable_safe(); for (i = 0; i < 16; i++) { buffer[i] = pgm_read_byte(addr); addr++; if (addr > FLASHEND) addr = 0x0000; } return 16; }
void write_page(void) { if (!page_dirty) return; uint8_t sreg; sreg = SREG; cli(); boot_page_erase_safe(page_address); for (int i = 0; i < SPM_PAGESIZE; i += 2) { uint16_t data = (uint16_t)page_buffer[i] + ((uint16_t)page_buffer[i+1] << 8); boot_page_fill_safe(page_address + i, data); } boot_page_write_safe(page_address); boot_rww_enable_safe(); page_dirty = 0; SREG = sreg; }
__attribute__((__noreturn__)) void main(void) { #if (FLASHEND > 0xFFFFUL) unsigned long flash_address = 0; #else unsigned int flash_address = 0; #endif #if SPM_PAGESIZE > 128 unsigned int x=0, y=0; #else unsigned char x=0, y=0; #endif unsigned char high_byte_buffer = 0, low_byte_buffer = 0, packet_resend_required = 0; unsigned char packet_number = 0, error_counter = 0, memory_full = 0; unsigned int received_bytes = 0, address_buffer = 0, eeprom_address = 0, crc16 = 0, crc_buffer = 0; EXTRA_STARTUP_COMMANDS(); ENABLE_LEVEL_PIN(); UART_TIMEOUT_ENABLE(); sget_char(); // Dummy receive used as a 200 ms delay as the UART is not yet enabled. if( ((PIN_REG(CHECK_LEVEL_PORT) & (1 << CHECK_LEVEL_PIN))) ){ EXTRA_EXIT_COMMANDS(); asm("jmp 0x0000"); } /* Initialization commands */ // Setup the UART _UCSRA_ = 0; // Enable the UART to receive/transmit and enable UART pins _UCSRB_ = ( (1 << _RXEN_)|(1 << _TXEN_) ); // Set UART to receive and transmit 8 bits per character, 1 stop bit with no parity. _UCSRC_ = ( USEURSEL | (1 << _UCSZ1_) | (1 << _UCSZ0_) ); // Set baudrate. _UBRRH_ = BAUDREG/256; _UBRRL_ = BAUDREG%256; // Turn on the pull up resistor of the UART rx pin. DDR_REG(UART_PORT) &= (~(1<<UART_RX_PIN)); PORT_REG(UART_PORT) |= (1<<UART_RX_PIN); // Make the UART Txd pin an output. DDR_REG(UART_PORT) |= (1<<UART_TX_PIN); // Enable the LED indication. ENABLE_LED(); #if INTIALIZATION_DELAY > 0 sget_char(); #endif /* MAIN BOOTLOADER LOOP */ while(1) { // START THE STANDARD 128 BYTE PACKET X MODEM CRC FILE DOWNLOAD // I tried to follow the crc X modem protocol as faithfully as i could LED_ON(); flash_address = 0; eeprom_address = 0; packet_number = 0; error_counter = 0; received_bytes = 0; memory_to_write = 0; memory_full = 0; UART_TIMEOUT_DISABLE(); //Disable uart receive timeout. receive_at_command(); sput_str("START THE X MODEM TRANSFER\r\n"); UART_TIMEOUT_ENABLE(); //Enable the UART timeout. do{ sput_char(XMODEM_NCG); }while(sget_char() != XMODEM_SOH); // DOWNLOAD AND VERIFY ONE PACKET AT A TIME UNTILL THE BUFFER IS FULL. The buffer is equal to SPM_PAGESIZE. /*------------------------------------------------------------------------------------------------------*/ do{ crc16 = 0; #if BOOTLOADER_SAVE_CODE_SIZE == 1 sget_char(); sget_char(); #elif BOOTLOADER_SAVE_CODE_SIZE == 0 packet_number++; packet_resend_required = 0; high_byte_buffer = sget_char(); //get X modem packet number low_byte_buffer = sget_char(); // Examine the packet number. if( (high_byte_buffer + low_byte_buffer) != 255 ) { packet_resend_required = (1<<2); } if( high_byte_buffer == (packet_number-1) ) { packet_resend_required |= (1<<1); } if(high_byte_buffer != packet_number) { packet_resend_required |= (1<<0); } #endif // Now receive the packet data and perform the crc16 check. for(x = X_MODEM_PACKET_LENGTH; x > 0; x--) { x_buffer[received_bytes] = sget_char(); crc16 = ( crc16 ^ ((unsigned int)x_buffer[received_bytes] << 8) ); for(y = 8; y > 0; y--) { crc_buffer = crc16 << 1; if(crc16 & 0x8000) { crc_buffer = crc_buffer ^ 0x1021; } crc16 = crc_buffer; } received_bytes++; } high_byte_buffer = sget_char(); //get X modem CRC16 low_byte_buffer = sget_char(); #if BOOTLOADER_SAVE_CODE_SIZE == 0 if( (high_byte_buffer != (crc16 / 256))||(low_byte_buffer != (crc16 % 256)) ){ packet_resend_required |= (1<<3); } // Now we must see if the packet was received ok or if not, what went wrong. if(packet_resend_required > 0) { error_counter++; packet_number--; // Packet number is decremented. received_bytes -= X_MODEM_PACKET_LENGTH; if( packet_resend_required >= (1<<2) ) { sput_char(XMODEM_NAK); }else if(packet_resend_required >= (1<<1) ) { sput_char(XMODEM_ACK); }else{ goto XMODEM_FAILED; } // end of "if( packet_resend_required >= (1<<2) )" statement. #elif BOOTLOADER_SAVE_CODE_SIZE == 1 if( (high_byte_buffer != (crc16 / 256))||(low_byte_buffer != (crc16 % 256)) ) { goto XMODEM_FAILED; #endif }else{ // "if(packet_resend_required > 0)" statement. if(memory_to_write == 1) { x = 0; while( received_bytes >= SPM_PAGESIZE ) { if(flash_address <= (BOOTLOADER_MEM_START-SPM_PAGESIZE) ) { address_buffer = x; // Store the x_buffer position for the verification process. y=0; do{ boot_page_fill_safe( y, x_buffer[x] | (x_buffer[x+1] << 8) ); x+=2; //BYTE COUNTER UP TO "received_bytes" y+=2; //BYTE COUNTER UP TO SPM_PAGESIZE }while(y < SPM_PAGESIZE); boot_page_erase_safe(flash_address); //erase one Flash page boot_page_write_safe(flash_address); //write buffer to one Flash page boot_rww_enable_safe(); y=0; do{ if( pgm_read_byte(flash_address+y) != x_buffer[address_buffer+y] ){ goto XMODEM_FAILED; } y++; }while(y < SPM_PAGESIZE); flash_address += SPM_PAGESIZE; received_bytes -= SPM_PAGESIZE; }else{ memory_full = 1; goto XMODEM_FAILED; } } }else if(memory_to_write == 2) { for(x=0; x < X_MODEM_PACKET_LENGTH; x++) { if(eeprom_address <= E2END) { eeprom_write_byte((unsigned char*)eeprom_address, x_buffer[x]); if(eeprom_read_byte((unsigned char*)eeprom_address) != x_buffer[x]){ goto XMODEM_FAILED; } eeprom_address++; }else{ memory_full = 1; } } received_bytes = 0; } sput_char(XMODEM_ACK); //error_counter =0; }// end of "if(packet_resend_required > 0){...}else{...}" statement if(error_counter >= 10){ goto XMODEM_FAILED; } //Standard X modem max errors is 10, abort update. }while(sget_char() != XMODEM_EOT); // End of do{}while loop /*----------------------------------------------------------------------------------------------------------*/ // The flash or Eeprom is written so it is time to exit. // exit the X modem transfer. sput_char(XMODEM_NAK); if(sget_char() == XMODEM_EOT) { sput_char(XMODEM_ACK); error_counter = 0; } else{ // If the transfer failed send the X modem cancel character 10 times as per X modem specifications. XMODEM_FAILED: y=0; do{ sput_char(XMODEM_CAN); y++; }while( y<10); error_counter = 1; } _UCSRB_ &= (~ (1 << _RXEN_)); UART_TIMEOUT_1S(); sget_char(); //dummy receive. It is used as delay. _UCSRB_ |= (1 << _RXEN_); if(memory_full) { sput_str("Error memory full"); }else if(error_counter) { sput_str(error_message); }else{ sput_str(update_success_message); } //(*((void(*)(void))(BOOTLOADER_MEM_START)))(); } // END of while(1) main loop. }