void __attribute__ ((section (".bootlup"))) __attribute__((noreturn)) bootlup() { const uint32_t addr_to = (uint32_t)BOOTLOADER_ADDRESS*2; /* byte address of bootloader */ const uint8_t nbpages=3072/SPM_PAGESIZE; /* maximum of 3k bootloader at the moment */ #if SPM_PAGESIZE > 255 uint16_t i; #else uint8_t i; #endif for(uint8_t page=0;page<nbpages;page++) { boot_page_erase(addr_to+page*SPM_PAGESIZE); boot_spm_busy_wait (); // Wait until the memory is erased for (i=0; i<SPM_PAGESIZE; i+=2) { uint16_t w = pgm_read_word(page*SPM_PAGESIZE+i); boot_page_fill (addr_to+page*SPM_PAGESIZE+i, w); } boot_page_write (addr_to+page*SPM_PAGESIZE); // Store buffer in flash page boot_spm_busy_wait ();// Wait until the memory is erased } boot_rww_enable (); jump_to_bootloader(); }
bool BootloaderAPI_EraseFillWritePage(const address_size_t address, const uint16_t* words) { // Do not write out of bounds if ((address & (SPM_PAGESIZE - 1)) || (address > (FLASHEND - SPM_PAGESIZE))) { return true; } // Erase the given FLASH page, ready to be programmed boot_page_erase(address); boot_spm_busy_wait(); // Write each of the FLASH page's bytes in sequence uint8_t PageWord; for (PageWord = 0; PageWord < (SPM_PAGESIZE / 2); PageWord++) { // Write the next data word to the FLASH page boot_page_fill(address + ((uint16_t)PageWord << 1), *words); words++; } // Write the filled FLASH page to memory boot_page_write(address); boot_spm_busy_wait(); // Re-enable RWW section boot_rww_enable(); // No error occured return false; }
void main() { DDRB|=(1<<1); unsigned int k=0; while(k<sizeof(bootloader)) { unsigned t=0; for(t=0;t<SPM_PAGESIZE;t++) tpage[t]=pgm_read_byte(&bootloader[k+t]); //erase eeprom_busy_wait(); boot_page_erase(BOOTLOADER_ADDRESS+k); /* erase page */ boot_spm_busy_wait(); /* wait until page is erased */ //load for(t=0;t<SPM_PAGESIZE;t+=2) boot_page_fill(BOOTLOADER_ADDRESS+k+t,*(unsigned int *)&tpage[t]); //program cli(); //boot_page_write(BOOTLOADER_ADDRESS+k); sei(); boot_spm_busy_wait(); boot_rww_enable(); /* wait until page is erased */ k+=SPM_PAGESIZE; blink(2); } while(1); }
void boot_program_page (uint32_t page, uint8_t *buf) { uint16_t i; uint8_t sreg; // Disable interrupts. sreg = SREG; cli(); eeprom_busy_wait (); boot_page_erase (page); boot_spm_busy_wait (); // Wait until the memory is erased. for (i=0; i<SPM_PAGESIZE; i+=2) { // Set up little-endian word. uint16_t w = *buf++; w += (*buf++) << 8; boot_page_fill (page + i, w); } boot_page_write (page); // Store buffer in flash page. boot_spm_busy_wait(); // Wait until the memory is written. // Reenable RWW-section again. We need this if we want to jump back // to the application after bootloading. boot_rww_enable (); // Re-enable interrupts (if they were ever enabled). SREG = sreg; }
/** Event handler for the USB_ControlRequest event. This is used to catch and process control requests sent to * the device from the USB host before passing along unhandled control requests to the library for processing * internally. */ void EVENT_USB_Device_ControlRequest(void) { /* Ignore any requests that aren't directed to the HID interface */ if ((USB_ControlRequest.bmRequestType & (CONTROL_REQTYPE_TYPE | CONTROL_REQTYPE_RECIPIENT)) != (REQTYPE_CLASS | REQREC_INTERFACE)) { return; } /* Process HID specific control requests */ switch (USB_ControlRequest.bRequest) { case HID_REQ_SetReport: Endpoint_ClearSETUP(); /* Wait until the command has been sent by the host */ while (!(Endpoint_IsOUTReceived())); /* Read in the write destination address */ uint16_t PageAddress = Endpoint_Read_16_LE(); /* Check if the command is a program page command, or a start application command */ if (PageAddress == COMMAND_STARTAPPLICATION) { RunBootloader = false; } else { /* Erase the given FLASH page, ready to be programmed */ boot_page_erase(PageAddress); boot_spm_busy_wait(); /* Write each of the FLASH page's bytes in sequence */ for (uint8_t PageWord = 0; PageWord < (SPM_PAGESIZE / 2); PageWord++) { /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived())); } /* Write the next data word to the FLASH page */ boot_page_fill(PageAddress + ((uint16_t)PageWord << 1), Endpoint_Read_16_LE()); } /* Write the filled FLASH page to memory */ boot_page_write(PageAddress); boot_spm_busy_wait(); /* Re-enable RWW section */ boot_rww_enable(); } Endpoint_ClearOUT(); Endpoint_ClearStatusStage(); break; } }
void program_flash (uint16_t address, uint16_t length) { uint16_t ii, ww; uint8_t temp; // wait until eventually running write cycles of internal eeprom are // finished. eeprom_busy_wait (); do { // erase flash page and wait until the memory is erased. boot_page_erase (address); boot_spm_busy_wait (); // only copy full 16bit words to flash memory if (length % 2) length--; for (ii=0; ii<SPM_PAGESIZE; ii+=2) { // read a word and convert to litte endian eep_read(MOD_eExtEEPAddr_AppStart + address + ii, 1, &temp); ww = temp; eep_read(MOD_eExtEEPAddr_AppStart + address + ii + 1, 1, &temp); ww |= temp << 8; boot_page_fill (address + ii, ww); length -= 2; if (length == 0) break; } // store buffer in flash page and wait until the memory is written. boot_page_write (address); boot_spm_busy_wait(); // one flash page has been written address += SPM_PAGESIZE; } while (length > 0); }
static void boot_program_page(uint16_t page, uint8_t* buf) { uint16_t i, w; // Check we are not overwriting this particular routine if ((page >= (FLASHEND - SPM_PAGESIZE + 1)) || ((page & SPM_PAGE_SIZE_BYTES_BM) != 0)) { return; } ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { // Erase page, wait for memories to be ready boot_page_erase(page); boot_spm_busy_wait(); // Fill the bootloader temporary page buffer for (i = 0; i < SPM_PAGESIZE; i+=2) { // Set up little-endian word. w = (*buf++) & 0x00FF; w |= (((uint16_t)(*buf++)) << 8) & 0xFF00; boot_page_fill(page + i, w); } // Store buffer in flash page, wait until the memory is written, re-enable RWW section boot_page_write(page); boot_spm_busy_wait(); boot_rww_enable(); } }
void flash_flush_buffer() { uint8_t sreg; uint16_t word; uint8_t i; uint16_t* buf = (uint16_t*)flash_pagebuf; // Access buffer on a word basis. if (!flash_buffer_dirty) return; // Nothing to flush. // Copy the sram buffer to the temporary page buffer. for (i = 0; i < SPM_PAGESIZE/2; i++) { word = buf[i]; boot_page_fill(i*2, word); // Absolute addressing is not neccessary. } // Disable interrupts. sreg = SREG; cli(); eeprom_busy_wait(); // Make sure any eeprom access has finished. boot_page_erase(flash_prev_addr); boot_spm_busy_wait(); // Wait until the memory is erased. boot_page_write(flash_prev_addr); // Store buffer in flash page. boot_spm_busy_wait(); // Wait until the memory is written. flash_buffer_dirty = 0; // Reenable RWW-section again so we can return to BIOS after flashing. boot_rww_enable (); // Re-enable interrupts (if they were ever enabled). SREG = sreg; }
void write_flash_page() { uint16_t i = 0; eeprom_busy_wait (); boot_page_erase (address); boot_spm_busy_wait (); // Wait until the memory is erased. for (i=0; i<SPM_PAGESIZE; i+=2) { // Set up little-endian word. uint16_t w = *((uint16_t*)(pagebuffer + i)); boot_page_fill (address + i, w); } boot_page_write(address); // Store buffer in flash page. boot_spm_busy_wait(); // Wait until the memory is written. // Normally, we should re-enable the RWW-section here // in order to call the application at bootloader exit. // //boot_rww_enable (); // // However, as we are going to exit the bootloader via // Watchdog - Reset, we can skip this, saving another // 8 bytes :) }
//------------------------------------------------------------------------------ void rnaInputStream( unsigned char *data, unsigned char dataLen ) { for( unsigned char i=0; i<dataLen; i++ ) { packet[packetPos++] = data[i]; } if ( packetPos >= packetExpectedLength ) { if ( packet[0] == RNATypeCodePage ) { struct PacketCodePage *page = (struct PacketCodePage *)(packet + 1); unsigned char pos = 0; for( unsigned char c=0; c<64; c += 2 ) { boot_page_fill( c, page->code[pos++] ); } boot_page_erase( page->page ); boot_spm_busy_wait(); boot_page_write( page->page ); boot_spm_busy_wait(); } else if ( packet[0] == RNATypeEnterApp ) { jumpToApp = 1; } } }
uchar usbFunctionSetup(uchar data[8]) { uchar len = 0; if (data[1] == USBBOOT_FUNC_LEAVE_BOOT) { leaveBootLoader(); } else if (data[1] == USBBOOT_FUNC_WRITE_PAGE) { state = STATE_WRITE_PAGE; page_address = (data[3] << 8) | data[2]; /* page address */ page_offset = 0; eeprom_busy_wait(); cli(); boot_page_erase(page_address); /* erase page */ sei(); boot_spm_busy_wait(); /* wait until page is erased */ len = 0xff; /* multiple out */ } else if (data[1] == USBBOOT_FUNC_GET_PAGESIZE) { replyBuffer[0] = SPM_PAGESIZE >> 8; replyBuffer[1] = SPM_PAGESIZE & 0xff; len = 2; } else return usbAppFunctionSetup(data,&usbMsgPtr);
static void fixVectors() { uint16_t rjmp; uint8_t i; uint8_t sreg; uint8_t vectors[4] = { RESET_VECTOR_OFFSET*2, PCINT0_VECTOR_OFFSET*2, TIM0_COMPA_VECTOR_OFFSET*2, TIM0_COMPB_VECTOR_OFFSET*2, }; rjmp = pgm_read_word(BOOTLOADER_ADDRESS) + BOOTLOADER_ADDRESS / 2; if(rjmp != pgm_read_word(0)) { sreg = SREG; cli(); for( i = 0; i < 4; i++) { rjmp = pgm_read_word(BOOTLOADER_ADDRESS + vectors[i]) + BOOTLOADER_ADDRESS / 2; boot_page_fill(vectors[i], rjmp); } eeprom_busy_wait(); boot_page_erase(0x00); boot_spm_busy_wait(); boot_page_write(0x00); boot_spm_busy_wait(); SREG = sreg; } }
// ---------------------------------------------------------------------- // Handle an OUT packet. // ---------------------------------------------------------------------- uchar usbFunctionWrite ( uchar* data, uchar len ) { uchar i, isLast; if(len > remaining) { len = remaining; } remaining -= len; isLast = remaining == 0; usb_maybe_finalizing = 0; if (cmd0 == USBTINY_EEPROM_WRITE) { #ifdef ENABLE_EEPROM_WRITING for ( i = 0; i < len; i++ ) { eeprom_write_byte((void *)(cur_addr.u16[0]++), *data++); } #endif } else if (cmd0 == USBTINY_FLASH_WRITE) { #ifdef ENABLE_FLASH_WRITING for ( i = 0; i < len; ) { if (CUR_ADDR < SPM_PAGESIZE) { fake_page_used = 1; fake_page[CUR_ADDR] = *((uint16_t*)data); CUR_ADDR += 2; data += 2; i += 2; } else { #ifndef ENABLE_CHIP_ERASE if ((cur_addr.u16[0] & (SPM_PAGESIZE - 1)) == 0 && CUR_ADDR < BOOTLOADER_ADDRESS) { // page start, erase boot_page_erase(CUR_ADDR); //boot_spm_busy_wait(); // wait not required since CPU is halted } #endif write_word(*((uint16_t*)data)); data += 2; i += 2; #ifndef ENABLE_WRITE_WHEN_TOLD if ((cur_addr.u16[0] & (SPM_PAGESIZE - 1)) == 0) { // end of page finalize_flash_if_dirty(); } #endif } } #endif } return isLast; }
// ---------------------------------------------------------------------- // finishes a write operation if already started // ---------------------------------------------------------------------- static void finalize_flash_if_dirty() { if (dirty != 0 && CUR_ADDR <= BOOTLOADER_ADDRESS) { cli(); #ifdef ENABLE_FLASH_WRITING if (CUR_ADDR >= BOOTLOADER_ADDRESS - SPM_PAGESIZE + 2) { // this is the last page before the bootloader // the very last 4 bytes will contain these 2 RJMP instructions // these two instructions are from the user app, but re-targeted boot_page_fill(BOOTLOADER_ADDRESS - 2, 0xCFFF & (((fake_page[0] & 0x0FFF) - (BOOTLOADER_ADDRESS / 2) + 1) | 0xC000)); // jump to start boot_page_fill(BOOTLOADER_ADDRESS - 4, 0xCFFF & (((fake_page[4] & 0x0FFF) - (BOOTLOADER_ADDRESS / 2) + 4) | 0xC000)); // USB interrupt sei(); last_page_used = 1; } boot_page_write(CUR_ADDR - 2); //boot_spm_busy_wait(); // wait not required since CPU is halted #if !defined(ENABLE_CHIP_ERASE) && defined(ENABLE_WRITE_WHEN_TOLD) if (erase_next != 0 && (cur_addr.u16[0] & (SPM_PAGESIZE - 1)) == 0) { boot_page_erase(CUR_ADDR); //boot_spm_busy_wait(); // wait not required since CPU is halted } #endif #endif sei(); } dirty = 0; }
//------------------------------------------------------------------------------ void commitPage( unsigned int page ) { boot_page_erase( page ); boot_spm_busy_wait(); boot_page_write( page ); boot_spm_busy_wait(); }
void flash_copy_data(uint16_t src, uint16_t dst, uint16_t len) { uint16_t data; cli(); // From this point we're on our own len = (len | (SPM_PAGESIZE - 1)) + 3; // Round len up to a whole page + 2 while (len -= 2) { if (dst >= (uint16_t)&__flash_code_start) break; wdt_reset(); data = pgm_read_word(src); // Read source word boot_page_fill(dst, data); // Write word to destination if ((dst + 2) % SPM_PAGESIZE == 0) { // If we just wrote the last word of a page boot_page_erase(dst); boot_spm_busy_wait(); // Wait until the memory is erased. boot_page_write(dst); // Store buffer in flash page. boot_spm_busy_wait(); // Wait until the memory is written. boot_rww_enable(); } src += 2; dst += 2; } while (1); // Nothing more we can do, hopefully there is a watchdog active }
/** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific * control requests that are not handled internally by the USB library (including the HID commands, which are * all issued via the control endpoint), so that they can be handled appropriately for the application. */ void EVENT_USB_UnhandledControlPacket(void) { /* Handle HID Class specific requests */ switch (USB_ControlRequest.bRequest) { case REQ_SetReport: if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) { Endpoint_ClearSETUP(); /* Wait until the command (report) has been sent by the host */ while (!(Endpoint_IsOUTReceived())); /* Read in the write destination address */ uint16_t PageAddress = Endpoint_Read_Word_LE(); /* Check if the command is a program page command, or a start application command */ if (PageAddress == TEENSY_STARTAPPLICATION) { RunBootloader = false; } else { /* Erase the given FLASH page, ready to be programmed */ boot_page_erase(PageAddress); boot_spm_busy_wait(); /* Write each of the FLASH page's bytes in sequence */ for (uint8_t PageByte = 0; PageByte < 128; PageByte += 2) { /* Check if endpoint is empty - if so clear it and wait until ready for next packet */ if (!(Endpoint_BytesInEndpoint())) { Endpoint_ClearOUT(); while (!(Endpoint_IsOUTReceived())); } /* Write the next data word to the FLASH page */ boot_page_fill(PageAddress + PageByte, Endpoint_Read_Word_LE()); } /* Write the filled FLASH page to memory */ boot_page_write(PageAddress); boot_spm_busy_wait(); /* Re-enable RWW section */ boot_rww_enable(); } Endpoint_ClearOUT(); /* Acknowledge status stage */ while (!(Endpoint_IsINReady())); Endpoint_ClearIN(); } break; } }
// Handle setup request extern byte_t usb_setup ( byte_t data[8] ) { byte_t len = 0; // Load the application if (data[1] == USBTINYBL_FUNC_APP_INIT) { init_application(); } // Write a page else if (data[1] == USBTINYBL_FUNC_WRITE) { status = STATUS_WRITE; page_address = (data[3] << 8) | data[2]; // Set the page address // ignore a page write over the bootloader section if (page_address >= BOOTLOADER_ADDRESS) { status = STATUS_IDLE; return 0xff; } page_counter = 0; eeprom_busy_wait(); cli(); boot_page_erase(page_address); // Erase the page sei(); boot_spm_busy_wait(); // Wait until page is erased len = 0xff; // Request the data though usb_out } // Read a page else if (data[1] == USBTINYBL_FUNC_READ) { status = STATUS_READ; page_address = (data[3] << 8) | data[2]; // Set the page address page_counter = 0; boot_rww_enable(); len = 0xff; // Request the data though usb_out } else if (data[1] == USBTINYBL_FUNC_GET_VER) { data[0] = VERSION_MAJOR; data[1] = VERSION_MINOR; len = 2; } // Load page size else if (data[1] == USBTINYBL_FUNC_GET_PAGE) { data[0] = SPM_PAGESIZE >> 8; data[1] = SPM_PAGESIZE & 0xff; len = 2; }
static void erase_flash( void ) { unsigned addr = BOOTLOADER_ADDRESS; do { addr -= SPM_PAGESIZE; boot_page_erase( addr ); wdt_reset(); } while ( addr ); }
void boot_v_erase_page( uint16_t pagenumber ){ uint32_t addr = ( uint32_t )pagenumber * ( uint32_t )PAGE_SIZE; // erase page: boot_page_erase(addr); boot_spm_busy_wait(); boot_rww_enable(); }
static inline void eraseFlash(void) { // erase only main section (bootloader protection) uint32_t addr = 0; while (APP_END > addr) { boot_page_erase(addr); // Perform page erase boot_spm_busy_wait(); // Wait until the memory is erased. addr += SPM_PAGESIZE; } boot_rww_enable(); }
static void write_page(uint16_t addr) { uint8_t sreg; sreg = SREG; cli(); eeprom_busy_wait(); boot_page_erase(addr); boot_spm_busy_wait(); boot_page_write(addr); boot_spm_busy_wait(); SREG = sreg; }
static void writeFlashPage(void) { if(needToErase) { boot_page_erase(CURRENT_ADDRESS - 2); boot_spm_busy_wait(); } boot_page_write(CURRENT_ADDRESS - 2); boot_spm_busy_wait(); // Wait until the memory is written. needToErase = 0; }
// Vymazání celé aplikaèní pamìti void ChipErase(void) { uint16_t address = 0x0000, konec = 0x0000; konec = END_APP_ADDRESS_BYTES; // Maže od adresy 0x0000 po koneènou adresu Bootloaderu while (address < konec) { // Vymaže pøíslušnou adresu boot_page_erase(address); boot_spm_busy_wait(); address += SPM_PAGESIZE; } }
uchar usbFunctionWrite(uchar *data, uchar len) { if (bytesRemaining == 0) return 1; if (len > bytesRemaining) len = bytesRemaining; if (cmd == WRITE_EEPROM_BLOCK) { /* We write only 2 bytes at a time since eeprom_write_block takes a long time. * If we write more data that it will cause V-USB to timeout */ eeprom_write_block((const void*)data, (void *)address, 2); eeprom_busy_wait(); return 1; /* Done with data */ } else if (cmd == WRITE_FLASH_BLOCK) { do { /* if we're at the start of a page, erase the page */ if (startPage){ pageAddress = address; cli(); boot_page_erase(pageAddress); sei(); boot_spm_busy_wait(); startPage = 0; } /* Fill the page buffer */ cli(); boot_page_fill(address, *(short *)data); sei(); /* We wrote 2 bytes */ address += 2; data += 2; len -= 2; bytesRemaining -= 2; /* 0 bytes remaining, so we must be at the end of a page */ if (bytesRemaining == 0) { cli(); boot_page_write(pageAddress); sei(); boot_spm_busy_wait(); return 1; /* Tell the driver that we're done with the data */ } } while(len); } return 1; }
static void eraseApplication(void) { // erase all pages starting from end of application section down to page 1 (leaving page 0) CURRENT_ADDRESS = BOOTLOADER_ADDRESS - SPM_PAGESIZE; while(CURRENT_ADDRESS != 0x0000) { boot_page_erase(CURRENT_ADDRESS); boot_spm_busy_wait(); CURRENT_ADDRESS -= SPM_PAGESIZE; } // erase and load page 0 with vectors fillFlashWithVectors(); }
static inline void flashPage( u16 p_page ) { u16 i; u16 data; boot_page_erase( p_page ); boot_spm_busy_wait(); for( i = 0; i < SPM_PAGESIZE; i += 2 ) { data = s_flashBuffer[i/2]; boot_page_fill( p_page+i, data ); } boot_page_write( p_page ); boot_spm_busy_wait(); }
/** * Private avr flush funtion. * * Write current buffered page in flash memory (if modified). * This function erase flash memory page before writing. * * This function is only use internally in this module. */ static void flash_avr_flush(Flash *fd) { if (fd->page_dirty) { LOG_INFO("Flushing page %d\n", fd->curr_page); // Wait while the SPM instruction is busy. boot_spm_busy_wait(); LOG_INFO("Filling temparary page buffer..."); // Fill the temporary buffer of the AVR for (page_addr_t page_addr = 0; page_addr < SPM_PAGESIZE; page_addr += 2) { uint16_t word = ((uint16_t)fd->page_buf[page_addr + 1] << 8) | fd->page_buf[page_addr]; ATOMIC(boot_page_fill(page_addr, word)); } LOG_INFO("Done.\n"); wdt_reset(); LOG_INFO("Erasing page, addr %u...", fd->curr_page * SPM_PAGESIZE); /* Page erase */ ATOMIC(boot_page_erase(fd->curr_page * SPM_PAGESIZE)); /* Wait until the memory is erased. */ boot_spm_busy_wait(); LOG_INFO("Done.\n"); LOG_INFO("Writing page, addr %u...", fd->curr_page * SPM_PAGESIZE); /* Store buffer in flash page. */ ATOMIC(boot_page_write(fd->curr_page * SPM_PAGESIZE)); boot_spm_busy_wait(); // Wait while the SPM instruction is busy. /* * Reenable RWW-section again. We need this if we want to jump back * to the application after bootloading. */ ATOMIC(boot_rww_enable()); fd->page_dirty = false; LOG_INFO("Done.\n"); } }
/* Erase the flash page(s) corresponding to the coffee sector. This is done by calling the write routine with a null buffer and any address within each page of the sector (we choose the first byte). */ BOOTLOADER_SECTION void avr_flash_erase(coffee_page_t sector) { coffee_page_t i; #if FLASH_COMPLEMENT_DATA uint32_t addr32; volatile uint8_t sreg; // Disable interrupts. sreg = SREG; cli(); for (i = 0; i < COFFEE_SECTOR_SIZE / COFFEE_PAGE_SIZE; i++) { for (addr32 = COFFEE_START + (((sector + i) * COFFEE_PAGE_SIZE) & ~(COFFEE_PAGE_SIZE - 1)); addr32 < (COFFEE_START + (((sector + i + 1) * COFFEE_PAGE_SIZE) & ~(COFFEE_PAGE_SIZE - 1))); addr32 += SPM_PAGESIZE) { boot_page_erase(addr32); boot_spm_busy_wait(); } } //RE-enable interrupts boot_rww_enable(); SREG = sreg; #else for (i=0;i<COFFEE_SECTOR_SIZE/COFFEE_PAGE_SIZE;i++) { avr_flash_write((sector+i)*COFFEE_PAGE_SIZE,0,0); } #endif #if 0 #if TESTCOFFEE /* Defining TESTCOFFEE is a convenient way of testing a new configuration. * It is triggered by an erase of the last sector. * Note this routine will be reentered during the test! */ if ((sector+i)==COFFEE_PAGES-1) { int j=(int)(COFFEE_START>>1),k=(int)((COFFEE_START>>1)+(COFFEE_SIZE>>1)),l=(int)(COFFEE_SIZE/1024UL); printf_P(PSTR("\nTesting coffee filesystem [0x%08x -> 0x%08x (%uKb)] ..."),j,k,l); int r= coffee_file_test(); if (r<0) { printf_P(PSTR("\nFailed with return %d! :-(\n"),r); } else { printf_P(PSTR("Passed! :-)\n")); } }
// erase any existing application and write in jumps for usb interrupt and reset to bootloader // - Because flash can be erased once and programmed several times, we can write the bootloader // - vectors in now, and write in the application stuff around them later. // - if vectors weren't written back in immidately, usb would fail. static inline void eraseApplication(void) { // erase all pages until bootloader, in reverse order (so our vectors stay in place for as long as possible) // while the vectors don't matter for usb comms as interrupts are disabled during erase, it's important // to minimise the chance of leaving the device in a state where the bootloader wont run, if there's power failure // during upload currentAddress = BOOTLOADER_ADDRESS; cli(); while (currentAddress) { currentAddress -= SPM_PAGESIZE; boot_page_erase(currentAddress); boot_spm_busy_wait(); } fillFlashWithVectors(); sei(); }