static void flash_page(uint32_t page, uint8_t *buf) { uint16_t i; uint8_t sreg; #ifdef TFTP_DEBUG_DO_NOT_FLASH return; #endif #if FLASHEND > UINT16_MAX if (memcmp_PF(buf, (uint_farptr_t)page, SPM_PAGESIZE) == 0) #else if (memcmp_P(buf, (PGM_VOID_P)page, SPM_PAGESIZE) == 0) #endif return; /* no changes */ /* Disable interrupts. */ sreg = SREG; cli(); eeprom_busy_wait(); boot_page_erase(page); boot_spm_busy_wait(); 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); boot_spm_busy_wait(); /* Reenable RWW-section again. */ boot_rww_enable (); /* Re-enable interrupts (if they were ever enabled). */ SREG = sreg; }
/* This function stores the CRC value and the length in the last two words of the program flash. It does a read/modify/write type operation on the whole last page. */ void store_crc(uint16_t crc, uint16_t length) { uint16_t n, i=0; /* Run through the page and store the information that is already there in the temporary buffer. */ for(n=PGM_LAST_PAGE_START; n<(PGM_LAST_PAGE_START + PGM_PAGE_SIZE-4); n+=2) { i = pgm_read_word_near(n); boot_page_fill(n, i); } /* Add the length and crc to the buffer and write it out. */ boot_page_fill(PGM_LENGTH, length); boot_page_fill(PGM_CRC, crc); boot_page_erase(PGM_LAST_PAGE_START); boot_spm_busy_wait(); boot_page_write(PGM_LAST_PAGE_START); boot_spm_busy_wait(); }
static void flash_page(uint32_t page, uint8_t *buf) { uint16_t i; uint8_t sreg; #ifdef TFTP_DEBUG_DO_NOT_FLASH return; #endif for(i = 0; i < SPM_PAGESIZE; i ++) if(buf[i] != pgm_read_byte_near(page + i)) goto commit_changes; return; /* no changes */ commit_changes: /* Disable interrupts. */ sreg = SREG; cli(); eeprom_busy_wait(); boot_page_erase(page); boot_spm_busy_wait(); 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); boot_spm_busy_wait(); /* Reenable RWW-section again. */ boot_rww_enable (); /* Re-enable interrupts (if they were ever enabled). */ SREG = sreg; }
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(); }
void write_page(uint16_t address, uint16_t words[SPM_PAGESIZE / 2]) { // fill buffer uint16_t iter = 0; while (iter < SPM_PAGESIZE / 2) { boot_page_fill(address + (iter * 2), words[iter]); iter++; } boot_page_write(address); boot_spm_busy_wait(); // Wait until the memory is written. }
void BootloaderAPI_WritePage(const uint32_t Address) { if (! IsPageAddressValid(Address)) return; ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { boot_page_write_safe(Address); 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(); }
void change_password(const char *password) { uint8_t temp; uint8_t i = 0; temp = SREG; cli(); // Ref: http://www.nongnu.org/avr-libc/user-manual/group__avr__boot.html boot_page_erase(FLASH_MEMORY_PAGE_ADDRESS); boot_spm_busy_wait(); // Wait until the memory is erased. // Add the magic at the beginning boot_page_fill(FLASH_MEMORY_PAGE_ADDRESS + i, PASSWORD_MAGIC); i+=PASSWORD_MAGIC_LENGTH; for(; i<(PASSWORD_MAGIC_LENGTH+MAX_PASSWORD_LENGTH+1); i+=2) { // Set up little-endian word. uint16_t w = *password++; w += (*password++) << 8; boot_page_fill(FLASH_MEMORY_PAGE_ADDRESS + i, w); // Quit if last written word contain the null character if(*(password-1) == '\0' || *(password-2) == '\0') { break; } } boot_page_write(FLASH_MEMORY_PAGE_ADDRESS); // 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 (); // Set back the global interrupt bit to its original state SREG |= temp & (1<<SREG_I); }
int flash_write_block(uint8_t *block_addr, uint8_t *data) { #if (FLASHEND) > 0xFFFF /* we need long addressing */ unsigned long a = (unsigned long)(block_addr); #else unsigned int a = (unsigned int)(block_addr); #endif int i; if ((a & (BLOCK_SIZE - 1)) != 0) /* Not block size aligned */ return -1; if (a >= BL_ADDR) /* Allowing to write only in the application section */ return -1; cli(); // Disable interruptions /* Erase the (flash) block */ boot_page_erase(a); boot_spm_busy_wait(); /* Wait until page is erased */ /* Start filling the block's buffer word-wise */ for (i = 0; i < BLOCK_SIZE; i += 2) { boot_page_fill(a + i, *(uint16_t *)(data + i)); } /* Write the block's buffer into the flash */ boot_page_write(a); boot_spm_busy_wait(); /* Wait until page is written */ boot_rww_enable(); /* Re-enable RWW-section again */ /* The above is needed to access the flash written */ sei(); // Enable interrupts return 0; }
void flash_write(const uint8_t *buf, uint16_t size) { static uint8_t last; const uint8_t *p; for (p = buf; p != buf+size; p++) { if (!(payload & (SPM_PAGESIZE-1))) { boot_page_erase(payload); boot_spm_busy_wait(); } if (payload & 1) boot_page_fill(payload, last | (*p << 8)); else last = *p; payload++; if (!(payload & (SPM_PAGESIZE-1))) { boot_page_write(payload-SPM_PAGESIZE); boot_spm_busy_wait(); } } }
// 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; } }
void boot_program_page (uint32_t page) { 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. uint8_t wbufaddr = 0; for (i=0; i<SPM_PAGESIZE; i+=2) { // Set up little-endian word. uint16_t w = buf[wbufaddr++]; w += buf[wbufaddr++] << 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; }
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(); }
// Zápis po pages do pamìti Flash void WriteFlashPages(uint16_t address, uint8_t *Buffer) { uint16_t i; uint16_t Data=0; for (i = 0; i < SPM_PAGESIZE; i += 2) { Data = *Buffer++; Data |= *Buffer++ << 8; // Plní Page buffer (256 velikost u 644p) boot_page_fill (address + i, Data); } boot_page_write (address); //Naplní buffer boot_spm_busy_wait(); // Èeká dokud se neuvolní }
/* 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")); } }
void ws_flash_read_byte(uint32_t addr, uint8_t *buf) { uint8_t sreg; sreg = SREG; cli(); eeprom_busy_wait(); _WAIT_FOR_SPM(); eeprom_busy_wait(); boot_spm_busy_wait(); _ENABLE_RWW_SECTION(); *buf = pgm_read_byte_far(addr); boot_rww_enable(); SREG = sreg; return; }
// 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 uint16_t writeFlashPage(uint16_t address, pagebuf_t size) { uint16_t pagestart = address; uint16_t data, sreg; uint8_t *tmp = gBuffer; do { // Safeguard if(address >= BOOTLOADER_ADDRESS) return address; data = *tmp++; data |= *tmp++ << 8; if(address == RESET_VECTOR_OFFSET * 2) vectorTemp[0] = (short)data; else if(address == PCINT0_VECTOR_OFFSET * 2) vectorTemp[1] = (short)data; else if(address == TIM0_COMPA_VECTOR_OFFSET * 2) vectorTemp[2] = (short)data; else if(address == TIM0_COMPB_VECTOR_OFFSET * 2) vectorTemp[3] = (short)data; else { sreg = SREG; cli(); boot_page_fill(address, data); SREG = sreg; } address += 2; size -= 2; } while (size); sreg = SREG; cli(); boot_page_write(pagestart); boot_spm_busy_wait(); SREG = sreg; if(pagestart == 0) updateTinyTable(); return address; }
uchar usbFunctionWrite(uchar *data, uchar len) { if (len > bytes_remaining) len = bytes_remaining; bytes_remaining -= len; if (request == USBASP_FUNC_WRITEEEPROM) { for (uint8_t i = 0; i < len; i++) eeprom_write_byte((uint8_t *)flash_address.word++, *data++); } else { /* data is handled wordwise, adjust len */ len /= 2; len -= 1; for (uint8_t i = 0; i <= len; i++) { uint16_t *w = (uint16_t *)data; cli(); boot_page_fill(flash_address.word, *w); sei(); usbWord_t next_address; next_address.word = flash_address.word; next_address.word += 2; data += 2; /* write page if page boundary is crossed or this is the last page */ if ( next_address.bytes[0] % SPM_PAGESIZE == 0 || (bytes_remaining == 0 && i == len) ) { cli(); boot_page_write(flash_address.word); sei(); boot_spm_busy_wait(); cli(); boot_rww_enable(); sei(); } flash_address.word = next_address.word; } } /* flash led on activity */ PORTC ^= _BV(PC4); return (bytes_remaining == 0); }
static inline void eraseApplication() { uint16_t address = BOOTLOADER_ADDRESS; uint8_t sreg; sreg = SREG; cli(); while(address) { address -= SPM_PAGESIZE; boot_page_erase(address); boot_spm_busy_wait(); } fixVectors(); SREG = sreg; }
/** * Flushes a partially written page of data to physical FLASH, if a page * boundary has been crossed. * * \note If a page flush occurs the global HEX parser state is updated. */ static void FlushPageIfRequired(void) { /* Abort if no data has been buffered for writing to the current page */ if (!PageDirty) return; /* Flush the FLASH page to physical memory if we are crossing a page boundary */ uint32_t NewPageStartAddress = (HEXParser.CurrAddress & ~(SPM_PAGESIZE - 1)); if (HEXParser.PageStartAddress != NewPageStartAddress) { boot_page_write(HEXParser.PageStartAddress); boot_spm_busy_wait(); HEXParser.PageStartAddress = NewPageStartAddress; PageDirty = false; } }
void erase_flash_page(uint32_t flashPage) { uint8_t sreg; sreg = SREG; cli(); eeprom_busy_wait (); boot_page_erase (flashPage); boot_spm_busy_wait (); // Wait until the memory is erased. boot_rww_enable (); SREG = sreg; }
static void updateTinyTable() { uint8_t sreg; sreg = SREG; cli(); boot_page_fill(BOOTLOADER_ADDRESS - TINY_RESET_VECTOR_OFFSET, vectorTemp[0] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS) / 2 + 4 + RESET_VECTOR_OFFSET); boot_page_fill(BOOTLOADER_ADDRESS - TINY_PCINT0_VECTOR_OFFSET, vectorTemp[1] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS) / 2 + 3 + PCINT0_VECTOR_OFFSET); boot_page_fill(BOOTLOADER_ADDRESS - TINY_TIM0_COMPA_VECTOR_OFFSET, vectorTemp[2] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS) / 2 + 2 + TIM0_COMPA_VECTOR_OFFSET); boot_page_fill(BOOTLOADER_ADDRESS - TINY_TIM0_COMPB_VECTOR_OFFSET, vectorTemp[3] + ((FLASHEND + 1) - BOOTLOADER_ADDRESS) / 2 + 1 + TIM0_COMPB_VECTOR_OFFSET); boot_page_write(BOOTLOADER_ADDRESS - SPM_PAGESIZE + 1); boot_spm_busy_wait(); SREG = sreg; }
BOOTLOADER_SECTION void flash_write_page(const u16_t page, const u8_t* data) { u16_t i; // Calculate 32-bit address from specified page u32_t adr = ((u32_t)page) * FLASH_PAGE_SIZE; // Save status of global interrupts u8_t sreg = SREG; // Disable interrupts cli(); // Clear the page first flash_clear_page(page); // Fill write data with 16-bit data for(i=0; i<FLASH_PAGE_SIZE; i+=2) { // Fetch little endian word of data u16_t word; word = *data++; word += (*data++) << 8; boot_page_fill(adr+i, word); } // Commit data to flash page boot_page_write(adr); // Wait until SPM command has finished boot_spm_busy_wait(); // Re-enable RWW-section boot_rww_enable(); // Restore status of global interrupts SREG = sreg; }
/* _____GLOBAL FUNCTIONS_____________________________________________________ */ BOOTLOADER_SECTION void flash_clear_page(const u16_t page) { // Calculate 32-bit address from specified page u32_t adr = ((u32_t)page) * SPM_PAGESIZE; // Save status of global interrupts u8_t sreg = SREG; // Disable interrupts cli(); boot_page_erase(adr); // Wait until SPM command has finished boot_spm_busy_wait(); // Re-enable RWW-section boot_rww_enable(); // Restore status of global interrupts SREG = sreg; }
// write a page to flash. This will NOT pre-erase the page! void boot_v_write_page( uint16_t pagenumber, uint8_t *data ){ uint32_t addr = ( uint32_t )pagenumber * ( uint32_t )PAGE_SIZE; // fill page buffer: for(uint32_t i = addr; i < addr + PAGE_SIZE; i += 2){ uint8_t lsb = *data++; uint8_t msb = *data++; uint16_t data = (msb << 8) + lsb; boot_page_fill(i, data); } boot_page_write(addr); boot_spm_busy_wait(); boot_rww_enable(); }
void ws_flash_read_page(uint32_t addr, uint8_t *buf) { uint8_t sreg; uint32_t i; sreg = SREG; cli(); eeprom_busy_wait(); for (i=0;i<PAGESIZE;i++) { _WAIT_FOR_SPM(); eeprom_busy_wait(); boot_spm_busy_wait(); _ENABLE_RWW_SECTION(); buf[i] = pgm_read_byte_far(addr+i); } boot_rww_enable(); SREG = sreg; return; }
static inline uint16_t writeFlashPage(uint16_t waddr, uint8_t size) { uint32_t pagestart = (uint32_t)waddr<<1; uint32_t baddr = pagestart; uint16_t data; uint8_t *tmp = gBuffer; do { data = *tmp++; data |= *tmp++ << 8; boot_page_fill(baddr, data); // call asm routine. baddr += 2; // Select next word in memory size -= 2; // Reduce number of bytes to write by two } while (size); // Loop until all bytes written boot_page_write(pagestart); boot_spm_busy_wait(); boot_rww_enable(); // Re-enable the RWW section return baddr>>1; }
usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *req = (void *)data; uint8_t len = 0; static uint8_t buf[4]; /* set global data pointer to local buffer */ usbMsgPtr = buf; /* on enableprog just return one zero, which means success */ if (req->bRequest == USBASP_FUNC_ENABLEPROG) { buf[0] = 0; len = 1; timeout = 255; } else if (req->bRequest == USBASP_FUNC_CONNECT) { /* turn on led */ PORTD |= _BV(PD5); } else if (req->bRequest == USBASP_FUNC_DISCONNECT) { /* turn off led */ PORTD &= ~_BV(PD6); request_exit = 1; /* catch query for the devicecode, chip erase and eeprom byte requests */ } else if (req->bRequest == USBASP_FUNC_TRANSMIT) { /* reset buffer with zeroes */ memset(buf, '\0', sizeof(buf)); /* read the address for eeprom operations */ usbWord_t address; address.bytes[0] = data[4]; /* low byte is data[4] */ address.bytes[1] = data[3]; /* high byte is data[3] */ /* if this is a request to read the device signature, answer with the * appropiate signature byte */ if (data[2] == ISP_READ_SIGNATURE) { /* the complete isp data is reported back to avrdude, but we just need byte 4 * bits 0 and 1 of byte 3 determine the signature byte address */ buf[3] = signature[data[4] & 0x03]; #ifdef ENABLE_CATCH_EEPROM_ISP /* catch eeprom read */ } else if (data[2] == ISP_READ_EEPROM) { buf[3] = eeprom_read_byte((uint8_t *)address.word); /* catch eeprom write */ } else if (data[2] == ISP_WRITE_EEPROM) { /* address is in data[4], data[3], and databyte is in data[5] */ eeprom_write_byte((uint8_t *)address.word, data[5]); #endif /* catch a chip erase */ } else if (data[2] == ISP_CHIP_ERASE1 && data[3] == ISP_CHIP_ERASE2) { for (flash_address.word = 0; flash_address.word < BOOT_SECTION_START; flash_address.word += SPM_PAGESIZE) { /* wait and erase page */ boot_spm_busy_wait(); cli(); boot_page_erase(flash_address.word); sei(); } } /* in case no data has been filled in by the if's above, just return zeroes */ len = 4; #ifdef ENABLE_ECHO_FUNC /* implement a simple echo function, for testing the usb connectivity */ } else if (req->bRequest == FUNC_ECHO) { buf[0] = req->wValue.bytes[0]; buf[1] = req->wValue.bytes[1]; len = 2; #endif } else if (req->bRequest >= USBASP_FUNC_READFLASH) { /* && req->bRequest <= USBASP_FUNC_SETLONGADDRESS */ putc('R'); putc(req->bRequest); /* extract address and length */ flash_address.word = req->wValue.word; bytes_remaining = req->wLength.bytes[0]; request = req->bRequest; /* hand control over to usbFunctionRead()/usbFunctionWrite() */ len = 0xff; } return len; }
void BootloaderAPI_WritePage(const uint32_t Address) { boot_page_write_safe(Address); boot_spm_busy_wait(); boot_rww_enable(); }