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 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 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 }
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 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 write_flash_page(uint8_t* buffer, uint32_t address, uint16_t len) { uint16_t size; uint8_t sreg; uint8_t *p; uint16_t data; uint16_t lowByte, highByte; address_t tempAddress; tempAddress = address; p = buffer; size = len; sreg = SREG; cli(); eeprom_busy_wait (); while(size) { lowByte = *p++; highByte = *p++; data = (highByte << 8) | lowByte; boot_page_fill(address, data); address += 2; size-=2; } boot_page_write(tempAddress); boot_spm_busy_wait(); boot_rww_enable(); SREG = sreg; }
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; }
//------------------------------------------------------------------------------ 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; } } }
// simply write currently stored page in to already erased flash memory static void writeFlashPage(void) { didWriteSomething = 1; cli(); boot_page_write(currentAddress - 2); boot_spm_busy_wait(); // Wait until the memory is written. sei(); }
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; } }
// ---------------------------------------------------------------------- // 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(); }
/** 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; } }
/** 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; } }
void flash_end_write(void) { if (payload & (SPM_PAGESIZE-1)) { boot_page_write(payload & ~(SPM_PAGESIZE-1)); boot_spm_busy_wait(); } boot_rww_enable(); }
static void write_flash( void ) { if ( currentAddress - 2 < BOOTLOADER_ADDRESS ) { boot_page_write( currentAddress - 2 ); prevCommand = cmd_written; } }
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. }
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; }
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; }
// 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í }
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"); } }
/** * This function writes a complete page to the flash memory. * * @param[in] page Page which shall be written * @param[in] buffer Pointer to the buffer with the data */ extern void vscp_bl_adapter_programPage(uint16_t page, uint8_t *buffer) { uint32_t addr = page * VSCP_PLATFORM_FLASH_PAGE_SIZE; uint16_t index = 0u; uint8_t sreg = 0; /* Disable interrupts */ sreg = SREG; cli(); /* No EEPROM activity allowed */ eeprom_busy_wait(); /* Erase flash page */ boot_page_erase(addr); /* Wait until the memory is erased. */ boot_spm_busy_wait(); for (index = 0u; index < VSCP_PLATFORM_FLASH_PAGE_SIZE; index += 2u) { /* Set up little-endian word. */ uint16_t leWord = *buffer; ++buffer; leWord += (*buffer) << 8u; ++buffer; boot_page_fill(addr + index, leWord); } /* Store buffer in flash page. */ boot_page_write(addr); /* Wait until the memory is written. */ boot_spm_busy_wait(); /* Re-enable RWW-section again. We need this if we want to jump back * to the application after the boot loader. */ boot_rww_enable(); /* Enable interrupts (if they were ever enabled). */ SREG = sreg; return; }
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); }
/** * 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; } }
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; }