/* This function pulls intel hex formatted code from the serial port and loads it into a temporary location. Once a complete SPM page length is stored, it executes a flash memory write. Return Error * ERR 1 - File upload synchronization is off (i.e. the ':' was not found) * ERR 2 - the checksum failed. */ char ihex_load(void) { uint8_t i,temp_char, byte_count = 0, data_pairs, data_type, temp_byte, temp_store, address_lo, address_hi; unsigned int data; // temporary location to store program words unsigned long temp_address = 0ul; //Tmp page fill address ?? do { // Wait for characters do { temp_char = uart_read(); if ( (temp_char == 13) || (temp_char == 10)) // get and dispose of the CR or LF temp_char = 0; // Wait for first character of line } while (!temp_char); if(temp_char != ':') // check to make sure the first character is ':' { return(1); } /* get the count of data pairs */ data_pairs = get_hex_value(); /* get the address to put the data */ /* although we collect this data, we do not use it. All data programmed through this bootloader starts at application program space location 0x0000. The collection is neccessary only for the checksum calculation. */ address_hi = get_hex_value(); address_lo = get_hex_value(); /* get the data type */ data_type = get_hex_value(); temp_store = data_pairs + address_hi + address_lo + data_type; for( i = 0; i < data_pairs; i++ ) { temp_byte = get_hex_value(); page_data[byte_count] = temp_byte; byte_count++; temp_store += temp_byte; } /* get the checksum */ temp_byte = get_hex_value(); /* check the data and checksum */ if( (char)(temp_store + temp_byte) ) { return(2); } /* fill the rest of the page buffer with 0xFF if the last records are not a full page in length */ if( data_type) // End of File record { for(byte_count; byte_count < SPM_PAGESIZE; byte_count++ ) { page_data[byte_count] = 0xFF; } } /* if the page buffer is full, write the buffer to the temp flash buffer */ if( byte_count >= SPM_PAGESIZE ) { byte_count = 0; /* store data in temp buffer and write to flash */ for( i = 0; i < SPM_PAGESIZE; i += 2 ) { /* swap the bytes for little endian format */ data = page_data[i]; data |= ( page_data[ i + 1 ] << 8 ); boot_page_fill( temp_address, data ); // call asm routine to load temporary flash buffer temp_address += 2; // select next word in temporary buffer } /* write to the flash */ boot_page_write( temp_address - SPM_PAGESIZE ); boot_spm_busy_wait(); boot_rww_enable(); //Re-enable the RWW section uart_write_char('*'); // Display - characters E_OUT_PORTA = 0x73; // Show P while programming E_OUT_PB1(0); E_OUT_PB2(1); } } while( data_type != 1); // Do while not end of File uart_write_char('E'); // End of file return(0); }
//Writes all the chars in buffer to the UART. void uart_write_chars(const unsigned char* buffer, size_t size){ for (size_t i = 0; i < size; i++){ uart_write_char(buffer[i]); } }
/*--- MAIN -------------------------------------------------------------------*/ int main(void) { uint8_t temp_char,tmp; uint8_t bootFlag = TRUE; cli(); /* the following code moves the interrupt vector pointer to the bootloader section. The problem is the compiler doesn't understand where to put the IV table. */ GICR = _BV(IVCE); GICR = _BV(IVSEL); //move interruptvectors to the Boot sector ** WRITE 0 TO IVCE use = not | // Initial 7 Segments on E_io // Set direction of two switch to Input DDRB = 0xFF; // Output DDRC = 0x18; // P3, P4 for Control 7 segments Digits // Enable pull up resistor PORTC |= 0x24; /* The slow baud rate is required because of the intel hex parsing overhead. If I could figure out how to enable interrupts in the BLS (compiler issue) then a higher speed could be used by switching to an interrupt based UART ISR. The code could also be optimized. */ uart_init( UART_INTERRUPT,UART_8_N_1,UART_38400); // poll USART receive complete flag 64k times to catch the 'i' reliably // test if flash is empty (i.e. flash content is 0xff) if(pgm_read_byte_near(0x0000) != 0xFF) { bootFlag = FALSE; } // Enter boot mode by press b // while (!(tmp = uart_read())); // if (tmp == 'b') // bootFlag = TRUE; // Check SW for enter boot mode either press both SW at the same time tmp = PINC & (0x24); // PB0, PB3 port if (!tmp) // Press SW tmp = 0 bootFlag = TRUE; uart_write_str (VERSION); // Display b characters E_OUT_PORTA = 0x7C; // b E_OUT_PB1(0); E_OUT_PB2(1); /* this main loop is the user 'menu'. */ while(bootFlag) { if( (tmp = uart_read()) ) { switch(tmp) { case 'u': // download new program { /* erase the main flash excepting BLS */ buf_address = 0; while ( APP_END > buf_address ) { boot_page_erase(buf_address); // Perform page erase boot_spm_busy_wait(); // Wait until the memory is erased. buf_address += SPM_PAGESIZE; } buf_address = 0; /* load new program */ uart_write_str("READY \n"); if(( temp_char = ihex_load())) { uart_write_str("ERR "); uart_write_char(temp_char + '0' ); uart_write_char('\n'); } else { bootFlag = FALSE ; // Exit to run } } break; case 'x': //Exit upgrade { GICR = _BV(IVCE); GICR &= ~(_BV(IVSEL) | _BV(IVCE)); //move interruptvectors to the Application sector Write 0 to IVCE jump_to_app(); // Jump to application sector // wdt_enable(WDTO_15MS); // Enable Watchdog Timer to give reset } break; default: { uart_write_str(" u - Upload or x - Execute \n"); } } // end switch } } // end while(1) // Start to application GICR = _BV(IVCE); GICR &= ~(_BV(IVSEL) | _BV(IVCE)); //move interruptvectors to the Application sector Write 0 to IVCE jump_to_app(); // Jump to application sector return 0; }