/** * \brief Fill temporary EEPROM page buffer with value. * * This fills the the EEPROM page buffers with a given value. * If memory mapped EEPROM is enabled, this function will not work. * * \note Only the lower part of the address is used to address the buffer. * Therefore, no address parameter is needed. In the end, the data * is written to the EEPROM page given by the address parameter to the * EEPROM write page operation. * * \param value Value to copy to the page buffer. */ void nvm_eeprom_fill_buffer_with_value(uint8_t value) { uint8_t old_cmd; old_cmd = NVM.CMD; nvm_eeprom_flush_buffer(); // Wait until NVM is ready nvm_wait_until_ready(); NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; /* Set address to zero, as only the lower bits matters. ADDR0 is * maintained inside the loop below. */ NVM.ADDR2 = 0x00; NVM.ADDR1 = 0x00; // Load multible bytes into page buffer uint8_t i; for (i = 0; i < EEPROM_PAGE_SIZE; ++i) { NVM.ADDR0 = i; NVM.DATA0 = value; } NVM.CMD = old_cmd; }
/** * \brief Write one byte to EEPROM using IO mapping. * * This function writes one byte to EEPROM using IO-mapped access. * This function will cancel all ongoing EEPROM page buffer loading * operations, if any. * * \param address EEPROM address (max EEPROM_SIZE) * \param value Byte value to write to EEPROM. */ void nvm_eeprom_write_byte(eeprom_addr_t address, uint8_t value) { uint8_t old_cmd; Assert(address <= EEPROM_SIZE); /* Flush buffer to make sure no unintentional data is written and load * the "Page Load" command into the command register. */ old_cmd = NVM.CMD; nvm_eeprom_flush_buffer(); // Wait until NVM is ready nvm_wait_until_ready(); nvm_eeprom_load_byte_to_buffer(address, value); // Set address to write to NVM.ADDR2 = 0x00; NVM.ADDR1 = (address >> 8) & 0xFF; NVM.ADDR0 = address & 0xFF; /* Issue EEPROM Atomic Write (Erase&Write) command. Load command, write * the protection signature and execute command. */ NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; nvm_exec(); NVM.CMD = old_cmd; }
/** * \brief Read buffer within the eeprom * * \param address the address to where to read * \param buf pointer to the data * \param len the number of bytes to read */ void nvm_eeprom_read_buffer(eeprom_addr_t address, void *buf, uint16_t len) { nvm_wait_until_ready(); eeprom_enable_mapping(); memcpy( buf,(void*)(address+MAPPED_EEPROM_START), len ); eeprom_disable_mapping(); }
void debug_string(uint8_t level,const char * const sz,const uint8_t isPGM) { if(level>g_log_verbosity) return; const char * p = sz; if(isPGM) { nvm_wait_until_ready(); while(1) { const uint8_t c = nvm_flash_read_byte( p++ ); if(c==0) break; // while (udi_cdc_is_tx_ready()) {} // udi_cdc_putc(c); while (usart_data_register_is_empty(USART_DEBUG) == false) {} usart_put(USART_DEBUG, c); } } else { while(*p) { while (usart_data_register_is_empty(USART_DEBUG) == false) {} usart_put(USART_DEBUG, *p++); //while (udi_cdc_is_tx_ready()) {} //udi_cdc_putc(*p++); } } }
/** * \brief Erase bytes from all EEPROM pages. * * This function erases bytes from all EEPROM pages, so that every location * written to in the page buffer reads 0xFF. */ void nvm_eeprom_erase_bytes_in_all_pages(void) { // Wait until NVM is ready nvm_wait_until_ready(); // Issue EEPROM Erase All command nvm_issue_command(NVM_CMD_ERASE_EEPROM_gc); }
/** * \brief Load single byte into temporary page buffer. * * This function loads one byte into the temporary EEPROM page buffers. * If memory mapped EEPROM is enabled, this function will not work. * Make sure that the buffer is flushed before starting to load bytes. * Also, if multiple bytes are loaded into the same location, they will * be ANDed together, thus 0x55 and 0xAA will result in 0x00 in the buffer. * * \note Only one page buffer exist, thus only one page can be loaded with * data and programmed into one page. If data needs to be written to * different pages, the loading and writing needs to be repeated. * * \param byte_addr EEPROM Byte address, between 0 and EEPROM_PAGE_SIZE. * \param value Byte value to write to buffer. */ void nvm_eeprom_load_byte_to_buffer(uint8_t byte_addr, uint8_t value) { // Wait until NVM is ready nvm_wait_until_ready(); eeprom_enable_mapping(); *(uint8_t*)(byte_addr + MAPPED_EEPROM_START) = value; eeprom_disable_mapping(); }
/** \brief Read a buffer from non-volatile RAM * * This routine reads \c count Bytes from the NVRAM source pointed * to by \c src to the destination buffer pointed to by \c dst. * * \param src the read source in the NVRAM address space * \param dst the destination buffer in program data memory space * \param count the number of Bytes to read * * \return Nothing. */ void nvram_read(nvram_addr_t src, void *dst, size_t count) { #if XMEGA nvm_wait_until_ready(); nvm_user_sig_read_buffer((flash_addr_t)(src + SENSOR_NVM_OFFSET), dst, count); #elif UC3 memcpy(dst, (void *)(src + SENSOR_NVM_BASE + SENSOR_NVM_OFFSET), count); #endif }
/** * \brief Flush temporary EEPROM page buffer. * * This function flushes the EEPROM page buffers. This function will cancel * any ongoing EEPROM page buffer loading operations, if any. * This function also works for memory mapped EEPROM access. * * \note An EEPROM write operations will automatically flush the buffer for you. * \note The function does not preserve the value of the NVM.CMD register */ void nvm_eeprom_flush_buffer(void) { // Wait until NVM is ready nvm_wait_until_ready(); // Flush EEPROM page buffer if necessary if ((NVM.STATUS & NVM_EELOAD_bm) != 0) { NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc; nvm_exec(); } }
/** * \brief Fill temporary EEPROM page buffer with value. * * This fills the the EEPROM page buffers with a given value. * If memory mapped EEPROM is enabled, this function will not work. * * \note Only the lower part of the address is used to address the buffer. * Therefore, no address parameter is needed. In the end, the data * is written to the EEPROM page given by the address parameter to the * EEPROM write page operation. * * \param value Value to copy to the page buffer. */ void nvm_eeprom_fill_buffer_with_value(uint8_t value) { nvm_eeprom_flush_buffer(); // Wait until NVM is ready nvm_wait_until_ready(); // Load multiple bytes into page buffer uint8_t i; for (i = 0; i < EEPROM_PAGE_SIZE; ++i) { nvm_eeprom_load_byte_to_buffer(i, value); } }
/** * \brief Load entire page into temporary EEPROM page buffer. * * This function loads an entire EEPROM page from an SRAM buffer to * the EEPROM page buffers. If memory mapped EEPROM is enabled, this * function will not work. Make sure that the buffer is flushed before * starting to load bytes. * * \note Only the lower part of the address is used to address the buffer. * Therefore, no address parameter is needed. In the end, the data * is written to the EEPROM page given by the address parameter to the * EEPROM write page operation. * * \param values Pointer to SRAM buffer containing an entire page. */ void nvm_eeprom_load_page_to_buffer(const uint8_t *values) { // Wait until NVM is ready nvm_wait_until_ready(); // Load multiple bytes into page buffer uint8_t i; for (i = 0; i < EEPROM_PAGE_SIZE; ++i) { nvm_eeprom_load_byte_to_buffer(i, *values); ++values; } }
/** * \brief Read one byte from EEPROM using mapped access. * * This function reads one byte from EEPROM using mapped access. * * \param addr EEPROM address, between 0 and EEPROM_SIZE * * \return Byte value read from EEPROM. */ uint8_t nvm_eeprom_read_byte(eeprom_addr_t addr) { uint8_t data; Assert(addr <= EEPROM_SIZE); /* Wait until NVM is ready */ nvm_wait_until_ready(); eeprom_enable_mapping(); data = *(uint8_t*)(addr + MAPPED_EEPROM_START), eeprom_disable_mapping(); return data; }
/** * \brief Read a fuse byte. * * This function reads and returns the value of a given fuse byte. * * \param fuse Fuse byte to read. * * \return Byte value of fuse. */ uint8_t nvm_fuses_read(enum fuse_byte_t fuse) { // Wait until NVM is ready nvm_wait_until_ready(); // Set address NVM.ADDR0 = fuse; // Issue READ_FUSES command nvm_issue_command(NVM_CMD_READ_FUSES_gc); return NVM.DATA0; }
/** * \brief Read buffer within the application section * * \param address the address to where to read * \param buf pointer to the data * \param len the number of bytes to read */ void nvm_flash_read_buffer(flash_addr_t address, void *buf, uint16_t len) { #if (FLASH_SIZE>0x10000) uint32_t opt_address = address; #else uint16_t opt_address = (uint16_t)address; #endif nvm_wait_until_ready(); while ( len ) { *(uint8_t*)buf = nvm_flash_read_byte(opt_address); buf=(uint8_t*)buf+1; opt_address++; len--; } }
/** \brief Write a buffer to non-volatile RAM * * This routine writes \c count Bytes to the NVRAM destination pointed * to by \c dst from the source buffer pointed to by \c src. * * \param dst the write destination in the NVRAM address space * \param src the source buffer in program data memory space * \param count the number of Bytes to write * * \return Nothing. */ void nvram_write(nvram_addr_t dst, const void *src, size_t count) { #if XMEGA nvm_wait_until_ready(); nvm_user_sig_write_buffer((flash_addr_t)(dst + SENSOR_NVM_OFFSET), src, count, true); /* check for blank, erase if needed */ #elif UC3 const bool erase_page = true; volatile void *const flash_addr = (volatile void *)(dst + SENSOR_NVM_BASE + SENSOR_NVM_OFFSET); sysclk_enable_pbb_module(SYSCLK_FLASH_REGS); (void)flash_memcpy(flash_addr, src, count, erase_page); sysclk_disable_pbb_module(SYSCLK_FLASH_REGS); #endif }
/** * \brief Read one byte from EEPROM using IO mapping. * * This function reads one byte from EEPROM using IO-mapped access. * If memory mapped EEPROM is enabled, this function will not work. * * \param addr EEPROM address, between 0 and EEPROM_SIZE * * \return Byte value read from EEPROM. */ uint8_t nvm_eeprom_read_byte(eeprom_addr_t addr) { Assert(addr <= EEPROM_SIZE); /* Wait until NVM is ready */ nvm_wait_until_ready(); /* Set address to read from */ NVM.ADDR2 = 0x00; NVM.ADDR1 = (addr >> 8) & 0xFF; NVM.ADDR0 = addr & 0xFF; /* Issue EEPROM Read command */ nvm_issue_command(NVM_CMD_READ_EEPROM_gc); return NVM.DATA0; }
/** * \brief Erase bytes from EEPROM page. * * This function erases bytes from one EEPROM page, so that every location * written to in the page buffer reads 0xFF. * * \param page_addr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGE_SIZE */ void nvm_eeprom_erase_bytes_in_page(uint8_t page_addr) { // Wait until NVM is ready nvm_wait_until_ready(); // Calculate page address uint16_t address = (uint16_t)(page_addr * EEPROM_PAGE_SIZE); Assert(address <= EEPROM_SIZE); // Set address NVM.ADDR2 = 0x00; NVM.ADDR1 = (address >> 8) & 0xFF; NVM.ADDR0 = address & 0xFF; // Issue EEPROM Erase command nvm_issue_command(NVM_CMD_ERASE_EEPROM_PAGE_gc); }
/** * \brief Load single byte into temporary page buffer. * * This function loads one byte into the temporary EEPROM page buffers. * If memory mapped EEPROM is enabled, this function will not work. * Make sure that the buffer is flushed before starting to load bytes. * Also, if multiple bytes are loaded into the same location, they will * be ANDed together, thus 0x55 and 0xAA will result in 0x00 in the buffer. * * \note Only one page buffer exist, thus only one page can be loaded with * data and programmed into one page. If data needs to be written to * different pages, the loading and writing needs to be repeated. * * \param byte_addr EEPROM Byte address, between 0 and EEPROM_PAGE_SIZE. * \param value Byte value to write to buffer. */ void nvm_eeprom_load_byte_to_buffer(uint8_t byte_addr, uint8_t value) { uint8_t old_cmd; old_cmd = NVM.CMD; // Wait until NVM is ready nvm_wait_until_ready(); NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; // Set address NVM.ADDR2 = 0x00; NVM.ADDR1 = 0x00; NVM.ADDR0 = byte_addr & 0xFF; // Set data, which triggers loading of EEPROM page buffer NVM.DATA0 = value; NVM.CMD = old_cmd; }
int main(void) { ADDR_T address = 0; unsigned int temp_int=0; unsigned char val; /* Initialization */ void (*funcptr)( void ) = 0x0000; // Set up function pointer to RESET vector. PMIC_SetVectorLocationToBoot(); eeprom_disable_mapping(); PROGPORT |= (1<<PROG_NO); // Enable pull-up on PROG_NO line on PROGPORT. /* Branch to bootloader or application code? */ if( /*!(PROGPIN & (1<<PROG_NO))*/1 ) // If PROGPIN is pulled low, enter programmingmode. { initbootuart(); // Initialize UART. /* Main loop */ for(;;) { val = recchar(); // Wait for command character. // Check autoincrement status. if(val=='a') { sendchar('Y'); // Yes, we do autoincrement. } // Set address (2 bytes). else if(val == 'A') { // NOTE: Flash addresses are given in words, not bytes. address = recchar(); address <<= 8; address |= recchar(); // Read address high and low byte. sendchar('\r'); // Send OK back. } // Set extended address (3 bytes). else if(val == 'H') { // NOTE: Flash addresses are given in words, not bytes. address = (uint32_t)recchar() << 16; address |= (uint16_t)recchar() << 8; address |= recchar(); sendchar('\r'); // Send OK back. } // Chip erase. else if(val=='e') { for(address = 0; address < APP_END; address += PAGESIZE) { // NOTE: Here we use address as a byte-address, not word-address, for convenience. nvm_wait_until_ready(); #ifdef __ICCAVR__ #pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr. #endif EraseApplicationPage( address ); #ifdef __ICCAVR__ #pragma diag_default=Pe1053 // Back to default. #endif } nvm_eeprom_erase_all(); sendchar('\r'); // Send OK back. } #ifndef REMOVE_BLOCK_SUPPORT // Check block load support. else if(val=='b') { sendchar('Y'); // Report block load supported. sendchar((BLOCKSIZE>>8) & 0xFF); // MSB first. sendchar(BLOCKSIZE&0xFF); // Report BLOCKSIZE (bytes). } // Start block load. else if(val=='B')
/** * \brief Erase and write specific parts of application flash section * * \param address the address to where to write * \param buf pointer to the data * \param len the number of bytes to write * \param b_blank_check if True then the page flash is checked before write * to run or not the erase page command. * * Set b_blank_check to false if all application flash is erased before. */ void nvm_flash_erase_and_write_buffer(flash_addr_t address, const void *buf, uint16_t len, bool b_blank_check) { uint16_t w_value; uint16_t page_pos; bool b_flag_erase; #if (FLASH_SIZE>0x10000) uint32_t page_address; uint32_t opt_address = address; #else uint16_t page_address; uint16_t opt_address = (uint16_t)address; #endif // Compute the start of the page to be modified page_address = opt_address-(opt_address%FLASH_PAGE_SIZE); // For each page while ( len ) { b_flag_erase = false; nvm_wait_until_ready(); for (page_pos=0; page_pos<FLASH_PAGE_SIZE; page_pos+=2 ) { if (b_blank_check) { // Read flash to know if the erase command is mandatory w_value = nvm_flash_read_word(page_address); if (w_value!=0xFFFF) { b_flag_erase = true; // The page is not empty } }else{ w_value = 0xFFFF; } // Update flash buffer if (len) { if (opt_address == page_address) { // The MSB of flash word must be changed // because the address is even len--; opt_address++; LSB(w_value)=*(uint8_t*)buf; buf=(uint8_t*)buf+1; } } if (len) { if (opt_address == (page_address+1)) { // The LSB of flash word must be changed // because the user buffer is not empty len--; opt_address++; MSB(w_value)=*(uint8_t*)buf; buf=(uint8_t*)buf+1; } } // Load flash buffer nvm_flash_load_word_to_buffer(page_address,w_value); page_address+=2; } // Write flash buffer if (b_flag_erase) { nvm_flash_atomic_write_app_page(page_address-FLASH_PAGE_SIZE); }else{ nvm_flash_split_write_app_page(page_address-FLASH_PAGE_SIZE); } } }