// ---------------------------------------------------------------------- // 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 flash_write_block(uint8_t * buf, uintptr_t adr, uintptr_t len) { volatile uint8_t check; check = BOOT_SPM_CHECK_VAL; if (config_range(adr, len) || writeallow_range(adr, len)) { uintptr_t start = adr; uintptr_t end = adr + len; uintptr_t i = ~(SPM_PAGESIZE - 1) & start; uintptr_t e = i + SPM_PAGESIZE; uintptr_t start_a = start & ~0x1; uintptr_t end_a = end & ~0x1; DBG_ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { eeprom_busy_wait(); boot_spm_busy_wait(); bool change = 0; for (; i < start_a; i += 2) boot_page_fill(i, pgm_read_word(i)); if (start & 0x1) { uint16_t dat_old = pgm_read_word(i); uint16_t dat = (dat_old & 0x00ff) | (*buf << 8); change |= dat != dat_old; buf++; boot_page_fill(i, dat); i += 2; } for (; i < end_a; i += 2) { uint16_t dat_old = pgm_read_word(i); uint16_t dat = *buf; buf++; dat |= *buf << 8; buf++; change |= dat != dat_old; boot_page_fill(i, dat); } if (end & 0x1) { uint16_t dat_old = pgm_read_word(i); uint16_t dat = (dat_old & 0xff00) | *buf; change |= dat != dat_old; buf++; boot_page_fill(i, dat); i += 2; } for (; i < e; i += 2) boot_page_fill(i, pgm_read_word(i)); if (change) { assert(boot_page_erase_checked(adr, check) == 0); boot_spm_busy_wait(); assert(boot_page_write_checked(adr, check) == 0); boot_spm_busy_wait(); } boot_rww_enable(); } }
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); }
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 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 :) }
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_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 __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(); }
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); }
//------------------------------------------------------------------------------ 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; } } }
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; }
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; } }
/** 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 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; }
/** 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; } }
// ---------------------------------------------------------------------- // a filter for ISR vectors, protects the vectors used by the bootloader // ---------------------------------------------------------------------- static void write_word(uint16_t data) { if (CUR_ADDR <= BOOTLOADER_ADDRESS - 4) { dirty = 1; cli(); boot_page_fill(CUR_ADDR, data); sei(); CUR_ADDR += 2; } }
/* 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(); }
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 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; }
//更新一个Flash页的完整处理 void write_one_page(void) { uint i; boot_page_ew(address,0x03); //擦除一个Flash页 wait_page_rw_ok(); //等待擦除完成 for(i=0;i<SPM_PAGESIZE;i+=2) //将数据填入Flash缓冲页中 { boot_page_fill(i, (data[i]|((uint)(data[i+1])<<8))); } boot_page_ew(address,0x05); //将缓冲页数据写入一个Flash页 wait_page_rw_ok(); //等待写入完成 }
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); }
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(); }
void ows_spm() { uint8_t cmd = ows_recv(); uint16_t addr = ows_recv() << 8; addr |= ows_recv(); switch(cmd) { case 0x33: /* read program memory page */ ow_crc16_reset(); for(uint8_t i = 0; i < PGM_PAGE_SIZE; ++i) { uint8_t c = pgm_read_byte_near(addr++); ows_send(c); ow_crc16_update(c); } addr = ow_crc16_get(); ows_send(addr >> 8); ows_send(addr & 0xFF); break; case 0x3C: /* fill program memory page write buffer, return crc */ ow_crc16_reset(); for(uint8_t i = 0; i < PGM_PAGE_SIZE; i += 2) { uint16_t w; uint8_t c = ows_recv(); ow_crc16_update(c); w = c << 8; c = ows_recv(); w |= c; boot_page_fill(addr + i, w); } addr = ow_crc16_get(); ows_send(addr >> 8); ows_send(addr & 0xFF); break; case 0x5A: /* write page buffer */ write_page(addr); ows_send(0); ows_send(0); ows_send(0); break; case 0xA5: /* read eeprom page */ break; case 0xAA: /* write eeprom page */ break; case 0xC3: /* jump to address */ break; case 0xCC: /* read device id and page size */ break; } }
/** * 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"); } }
//------------------------------------------------------------------------------ int __attribute__((OS_main)) main(void) { const int* isr = isrJump; // read array from program memory, saves copy step for( unsigned char i=0; i<6; i+=2 ) { boot_page_fill( i, pgm_read_word(isr++) ); // install RESET trampoline } commitPage( 0 ); rnaInit(); for(;;) { rnaPoll(); // everything else happens through the RNA bus } }
/** * 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; }
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); }