/**************************************************************************//** * See mss_nvm.h for details of how to use this function. */ nvm_status_t NVM_write ( uint32_t start_addr, const uint8_t * pidata, uint32_t length, uint32_t lock_page ) { nvm_status_t status; uint32_t nvm_offset; uint32_t device_version; uint32_t initial_nvm_config; /* * SAR 57547: Set the FREQRNG field of the eNVM configuration register * to its maximum value (i.e. 15) to ensure successful writes to eNVM. * Store the value of the eNVM configuration before updating it, so * that the prior configuration can be restored when the eNVM write * operation has completed. */ initial_nvm_config = SYSREG->ENVM_CR; SYSREG->ENVM_CR = (initial_nvm_config & NVM_FREQRNG_MASK) | NVM_FREQRNG_MAX; /* Check input parameters */ if((start_addr >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) || \ ((start_addr >= NVM_RSV_PROTECTION_OFFSET) && \ (start_addr < NVM_BASE_ADDRESS)) || \ (!pidata) || \ (!length) || \ ((start_addr + length) >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET))|| \ (((start_addr + length) >= NVM_RSV_PROTECTION_OFFSET) && \ ((start_addr + length) < NVM_BASE_ADDRESS))|| \ (lock_page > PARAM_LOCK_PAGE_FLAG)) { if(((start_addr >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) && \ (start_addr <= (NVM_BASE_ADDRESS + NVM_TOP_OFFSET))) || \ ((start_addr >= NVM_RSV_PROTECTION_OFFSET) && (start_addr <= NVM_TOP_OFFSET)) || \ (((start_addr + length) >= (NVM_BASE_ADDRESS + NVM_RSV_PROTECTION_OFFSET)) && \ ((start_addr + length) <= (NVM_BASE_ADDRESS + NVM_TOP_OFFSET))) || \ (((start_addr + length) >= NVM_RSV_PROTECTION_OFFSET) && \ ((start_addr + length) <= NVM_TOP_OFFSET))) { status = NVM_PROTECTION_ERROR; } else { status = NVM_INVALID_PARAMETER; } } else { /* * Prevent pages being locked for silicon versions which do not allow * locked pages to be unlocked. */ device_version = SYSREG->DEVICE_VERSION; if((0x0000F802u == device_version) || (0x0001F802u == device_version)) { lock_page = NVM_DO_NOT_LOCK_PAGE; } /* Ignore upper address bits to ignore remapping setting. */ nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS; /* Ignore remapping. */ /* Check against attempt to write data larger than eNVM. */ ASSERT((nvm_offset + length) <= MAX_504K_OFFSET); if((nvm_offset + length) <= MAX_504K_OFFSET) { /* Gain exclusive access to eNVM controller */ status = get_ctrl_access(nvm_offset, length); /* Write eNVM one page at a time. */ if(NVM_SUCCESS == status) { uint32_t remaining_length = length; uint32_t errors_and_warnings; while(remaining_length > 0u) { uint32_t length_written; uint32_t nvm_hw_status = 0u; length_written = write_nvm(start_addr + (length - remaining_length), &pidata[length - remaining_length], remaining_length, lock_page, &nvm_hw_status); /* Check for errors and warnings. */ errors_and_warnings = nvm_hw_status & (WRITE_ERROR_MASK | MSS_NVM_WRCNT_OVER); if(errors_and_warnings) { /* * Ensure that the status returned by the NVM_write() * function is NVM_WRITE_THRESHOLD_WARNING if at least one * of the written eNVM pages indicate a write over * threshold condition. */ status = get_error_code(nvm_hw_status); } if((NVM_SUCCESS == status) || (NVM_WRITE_THRESHOLD_WARNING == status )) { if(remaining_length > length_written) { remaining_length -= length_written; } else { remaining_length = 0u; } } else { remaining_length = 0u; } } /* Release eNVM controllers so that other masters can gain access to it. */ release_ctrl_access(); } } else { status = NVM_INVALID_PARAMETER; } } /* Restore back to original value. */ SYSREG->ENVM_CR = initial_nvm_config; return status; }
/**************************************************************************//** * See mss_nvm.h for details of how to use this function. */ nvm_status_t NVM_write ( uint32_t start_addr, const uint8_t * pidata, uint32_t length, uint32_t lock_page ) { nvm_status_t status; uint32_t nvm_offset; uint32_t device_version; /* * Prevent pages being locked for silicon versions which do not allow * locked pages to be unlocked. */ device_version = SYSREG->DEVICE_VERSION; if((0x0000F802u == device_version) || (0x0001F802u == device_version)) { lock_page = NVM_DO_NOT_LOCK_PAGE; } /* Ignore upper address bits to ignore remapping setting. */ nvm_offset = start_addr & NVM_OFFSET_SIGNIFICANT_BITS; /* Ignore remapping. */ /* Check against attempt to write data larger than eNVM. */ ASSERT((nvm_offset + length) < MAX_512K_OFFSET); if((nvm_offset + length) < MAX_512K_OFFSET) { /* Gain exclusive access to eNVM controller */ status = get_ctrl_access(nvm_offset, length); /* Write eNVM one page at a time. */ if(NVM_SUCCESS == status) { uint32_t remaining_length = length; while((remaining_length > 0u) && (NVM_SUCCESS == status)) { uint32_t length_written; uint32_t nvm_hw_status = 0u; length_written = write_nvm(start_addr + (length - remaining_length), &pidata[length - remaining_length], remaining_length, lock_page, &nvm_hw_status); if(0u == length_written) { status = get_error_code(nvm_hw_status); } else if(remaining_length > length_written) { remaining_length -= length_written; } else { remaining_length = 0u; } } /* Release eNVM controllers so that other masters can gain access to it. */ release_ctrl_access(); } } else { status = NVM_INVALID_PARAMETER; } return status; }