void leaveBootloader() { cli(); boot_rww_enable(); GICR = (1 << IVCE); /* enable change of interrupt vectors */ GICR = (0 << IVSEL); /* move interrupts to application flash section */ jump_to_app(); }
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(); } }
/** 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 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 ws_flash_write_page(uint32_t address, uint8_t *buf) { uint32_t i; uint8_t sreg; uint8_t *buffer; buffer = buf; // Disable interrupts sreg = SREG; cli(); // Start by erasing the page at given address boot_page_erase_safe (address); boot_spm_busy_wait (); // Wait until the memory is erased for(i=0; i<PAGESIZE; i+=2){ uint16_t w = *buffer++; w += (*buffer++) << 8; boot_page_fill_safe(address+i, w); } boot_page_write_safe (address); boot_spm_busy_wait (); while(boot_rww_busy()){ boot_rww_enable_safe();} boot_rww_enable(); SREG = sreg; }
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 leaveBootLoader() { /* boot_rww_enable_safe(); */ boot_spm_busy_wait(); eeprom_busy_wait(); boot_rww_enable(); state=STATE_IDLE; }
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 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 __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 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; }
/** 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; } }
// Start the application in firmware void init_application() { cli(); boot_rww_enable(); // Enable access to the flash memory GICR = (1 << IVCE); // enable change of interrupt vectors GICR = (0 << IVSEL); // move interrupts to application flash section init_app(); }
void flash_end_write(void) { if (payload & (SPM_PAGESIZE-1)) { boot_page_write(payload & ~(SPM_PAGESIZE-1)); boot_spm_busy_wait(); } boot_rww_enable(); }
/** Reads or writes a block of EEPROM or FLASH memory to or from the appropriate CDC data endpoint, depending * on the AVR910 protocol command issued. * * \param[in] Command Single character AVR910 protocol command indicating what memory operation to perform */ static void ReadWriteMemoryBlock(const uint8_t Command) { uint16_t BlockSize; char MemoryType; bool HighByte = false; uint8_t LowByte = 0; BlockSize = (FetchNextCommandByte() << 8); BlockSize |= FetchNextCommandByte(); MemoryType = FetchNextCommandByte(); if ((MemoryType != 'E') && (MemoryType != 'F')) { /* Send error byte back to the host */ WriteNextResponseByte('?'); return; } /* Disable timer 1 interrupt - can't afford to process nonessential interrupts * while doing SPM tasks */ TIMSK1 = 0; /* Check if command is to read memory */ if (Command == 'g') { /* Re-enable RWW section */ boot_rww_enable(); while (BlockSize--) { if (MemoryType == 'F') { /* Read the next FLASH byte from the current FLASH page */ #if (FLASHEND > 0xFFFF) WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte)); #else WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte)); #endif /* If both bytes in current word have been read, increment the address counter */ if (HighByte) CurrAddress += 2; HighByte = !HighByte; } else { /* Read the next EEPROM byte into the endpoint */ WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1))); /* Increment the address counter after use */ CurrAddress += 2; } } }
// 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; }
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(); } }
/** Reads or writes a block of EEPROM or FLASH memory to or from the appropriate CDC data endpoint, depending * on the AVR109 protocol command issued. * * \param[in] Command Single character AVR109 protocol command indicating what memory operation to perform */ static void ReadWriteMemoryBlock(const uint8_t Command) { uint16_t BlockSize; char MemoryType; uint8_t HighByte = 0; uint8_t LowByte = 0; BlockSize = (FetchNextCommandByte() << 8); BlockSize |= FetchNextCommandByte(); MemoryType = FetchNextCommandByte(); if ((MemoryType != MEMORY_TYPE_FLASH) && (MemoryType != MEMORY_TYPE_EEPROM)) { /* Send error byte back to the host */ WriteNextResponseByte('?'); return; } /* Check if command is to read a memory block */ if (Command == AVR109_COMMAND_BlockRead) { /* Re-enable RWW section */ boot_rww_enable(); while (BlockSize--) { if (MemoryType == MEMORY_TYPE_FLASH) { /* Read the next FLASH byte from the current FLASH page */ #if (FLASHEND > 0xFFFF) WriteNextResponseByte(pgm_read_byte_far(CurrAddress | HighByte)); #else WriteNextResponseByte(pgm_read_byte(CurrAddress | HighByte)); #endif /* If both bytes in current word have been read, increment the address counter */ if (HighByte) CurrAddress += 2; HighByte = !HighByte; } else { /* Read the next EEPROM byte into the endpoint */ WriteNextResponseByte(eeprom_read_byte((uint8_t*)(intptr_t)(CurrAddress >> 1))); /* Increment the address counter after use */ CurrAddress += 2; } } }
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(); }
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(); } }
/** Resets all configured hardware required for the bootloader back to their original states. */ void ResetHardware(void) { /* Shut down the USB subsystem */ USB_ShutDown(); /* Relocate the interrupt vector table back to the application section */ MCUCR = (1 << IVCE); MCUCR = 0; /* Re-enable RWW section */ boot_rww_enable(); }
void BOOTLOADER_SECTION bootloader(void) { unsigned long address; unsigned short boot_word; // unsigned char buffer[8]; cli(); // Erase page. boot_page_erase((unsigned long)ADDRESS); while(boot_rww_busy()) { boot_rww_enable(); } // Write data to buffer a word at a time. Note incrementing address by 2. // SPM_PAGESIZE is defined in the microprocessor IO header file. for(address = ADDRESS; address < ADDRESS + SPM_PAGESIZE; address += 2) { boot_word=boot_word_read(); boot_page_fill(address, boot_word); } // Write page. boot_page_write((unsigned long)ADDRESS); while(boot_rww_busy()) { boot_rww_enable(); } sei(); // Read back the values and display. // (The show() function is undefined and is used here as an example only.) // for(unsigned long i = ADDRESS; i < ADDRESS + 256; i++) // { // show(utoa(pgm_read_byte(i), buffer, 16)); // } }
static inline void uploadPage() { u16 ourCRC = 0xffff; u16 page = getWordWithCRC( &ourCRC ); u16 realCRC = getWord(); char *response = RESPONSE_ERROR; fillBuffer( page ); if ( realCRC == ourCRC ) { flashPage( page * SPM_PAGESIZE ); boot_rww_enable(); //Re-enable the RWW section response = RESPONSE_OK; } respond( UPLOAD_PAGE_COMMAND, page, response ); }
/** * 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")); } }
/** * 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; }
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; }
static void leaveBootloader() { statusLedOff(); cli(); boot_rww_enable(); USB_INTR_ENABLE = 0; USB_INTR_CFG = 0; /* also reset config bits */ GICR = (1 << IVCE); /* enable change of interrupt vectors */ GICR = (0 << IVSEL); /* move interrupts to application flash section */ /* 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(); }