// finishes up writing to the flash, including adding the tinyVector tables at the end of memory // TODO: can this be simplified? EG: currentAddress = PROGMEM_SIZE; fillFlashWithVectors(); static inline void tiny85FinishWriting(void) { // make sure remainder of flash is erased and write checksum and application reset vectors if (didWriteSomething) { while (currentAddress < BOOTLOADER_ADDRESS) { fillFlashWithVectors(); } } }
static inline void tiny85FlashWrites(void) { _delay_us(2000); // TODO: why is this here? - it just adds pointless two level deep loops seems like? // write page to flash, interrupts will be disabled for > 4.5ms including erase if (currentAddress % SPM_PAGESIZE) { // when we aren't perfectly aligned to a flash page boundary fillFlashWithVectors(); // fill up the rest of the page with 0xFFFF (unprogrammed) bits } else { writeFlashPage(); // otherwise just write it } }
static inline void tiny85FlashInit(void) { // check for erased first page (no bootloader interrupt vectors), add vectors if missing // this needs to happen for usb communication to work later - essential to first run after bootloader // being installed if(pgm_read_word(RESET_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1 || pgm_read_word(USBPLUS_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1) { fillFlashWithVectors(); } // TODO: necessary to reset currentAddress? currentAddress = 0; }
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(); }
// 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(); }
static inline __attribute__((noreturn)) void leaveBootloader(void) { DBG1(0x01, 0, 0); bootLoaderExit(); cli(); USB_INTR_ENABLE = 0; USB_INTR_CFG = 0; /* also reset config bits */ #ifdef TINY85MODE // make sure remainder of flash is erased and write checksum and application reset vectors if(appWriteComplete) { CURRENT_ADDRESS = writeSize; while(CURRENT_ADDRESS < BOOTLOADER_ADDRESS) { fillFlashWithVectors(); } } #else GICR = (1 << IVCE); /* enable change of interrupt vectors */ GICR = (0 << IVSEL); /* move interrupts to application flash section */ #endif // TODO: watchdog reset instead to reset registers? #ifdef APPCHECKSUM if(!testForValidApplication()) asm volatile ("rjmp __vectors"); #endif #ifdef TINY85MODE // clear magic word from bottom of stack before jumping to the app *(uint8_t*)(RAMEND) = 0x00; *(uint8_t*)(RAMEND-1) = 0x00; // jump to application reset vector at end of flash asm volatile ("rjmp __vectors - 4"); #else /* We must go through a global function pointer variable instead of writing * ((void (*)(void))0)(); * because the compiler optimizes a constant 0 to "rcall 0" which is not * handled correctly by the assembler. */ nullVector(); #endif }
static inline void tiny85FlashInit(void) { // check for erased first page (no bootloader interrupt vectors), add vectors if missing if(pgm_read_word(RESET_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1 || pgm_read_word(USBPLUS_VECTOR_OFFSET * 2) != 0xC000 + (BOOTLOADER_ADDRESS/2) - 1) { // TODO: actually need to erase here? how could we end up with missing vectors but application data higher up? # if HAVE_CHIP_ERASE eraseApplication(); # else fillFlashWithVectors(); # endif } // TODO: necessary to reset CURRENT_ADDRESS? CURRENT_ADDRESS = 0; # ifdef APPCHECKSUM checksum = 0; # endif }
static inline void tiny85FlashWrites(void) { #if HAVE_CHIP_ERASE if(eraseRequested) { _delay_ms(2); cli(); eraseApplication(); sei(); #ifdef APPCHECKSUM checksum = 0; #endif eraseRequested = 0; } #endif if(flashPageLoaded) { _delay_ms(2); // write page to flash, interrupts will be disabled for several milliseconds cli(); if(CURRENT_ADDRESS % SPM_PAGESIZE) fillFlashWithVectors(); else writeFlashPage(); sei(); flashPageLoaded = 0; if(isLastPage) { // store number of bytes written so rest of flash can be filled later writeSize = CURRENT_ADDRESS; appWriteComplete = 1; } } }