uint32_t utilsFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize) { uint32_t rval = aSize; otEXPECT_ACTION(aData, rval = 0); otEXPECT_ACTION(aAddress >= SETTINGS_CONFIG_BASE_ADDRESS, rval = 0); otEXPECT_ACTION((aAddress - SETTINGS_CONFIG_BASE_ADDRESS + aSize) <= utilsFlashGetSize(), rval = 0); otEXPECT_ACTION(((aAddress & 3) == 0) && ((aSize & 3) == 0), rval = 0); for (uint32_t i = 0; i < (aSize / sizeof(uint32_t)); i++) { *((volatile uint32_t *)aAddress) = *((uint32_t *)aData); aData += sizeof(uint32_t); aAddress += sizeof(uint32_t); } // check if write page command is required if ((aAddress) & (NVMCTRL_PAGE_SIZE - 1)) { enum status_code status; status = nvm_execute_command(NVM_COMMAND_WRITE_PAGE, aAddress & (~(NVMCTRL_PAGE_SIZE - 1)), 0); otEXPECT_ACTION(status == STATUS_OK, rval = 0); } exit: return rval; }
/** * \brief Writes a number of bytes to a page in the NVM memory region. * * Writes from a buffer to a given page address in the NVM memory. * * \param[in] destination_address Destination page address to write to * \param[in] buffer Pointer to buffer where the data to write is * stored * \param[in] length Number of bytes in the page to write * * \note If writing to a page that has previously been written to, the page's * row should be erased (via \ref nvm_erase_row()) before attempting to * write new data to the page. * * \note For SAMD21 RWW devices, see \c SAMD21_64K, command \c NVM_COMMAND_RWWEE_WRITE_PAGE * must be executed before any other commands after writing a page, * refer to errata 13588. * * \note If manual write mode is enable, write command must be executed after * this function, otherwise the data will not write to NVM from page buffer. * * \return Status of the attempt to write a page. * * \retval STATUS_OK Requested NVM memory page was successfully * read * \retval STATUS_BUSY NVM controller was busy when the operation * was attempted * \retval STATUS_ERR_BAD_ADDRESS The requested address was outside the * acceptable range of the NVM memory region or * not aligned to the start of a page * \retval STATUS_ERR_INVALID_ARG The supplied write length was invalid */ enum status_code nvm_write_buffer( const uint32_t destination_address, const uint8_t *buffer, uint16_t length) { #ifdef FEATURE_NVM_RWWEE bool is_rww_eeprom = false; #endif /* Check if the destination address is valid */ if (destination_address > ((uint32_t)_nvm_dev.page_size * _nvm_dev.number_of_pages)) { #ifdef FEATURE_NVM_RWWEE if (destination_address >= ((uint32_t)NVMCTRL_RWW_EEPROM_SIZE + NVMCTRL_RWW_EEPROM_ADDR) || destination_address < NVMCTRL_RWW_EEPROM_ADDR){ return STATUS_ERR_BAD_ADDRESS; } is_rww_eeprom = true; #else return STATUS_ERR_BAD_ADDRESS; #endif } /* Check if the write address not aligned to the start of a page */ if (destination_address & (_nvm_dev.page_size - 1)) { return STATUS_ERR_BAD_ADDRESS; } /* Check if the write length is longer than a NVM page */ if (length > _nvm_dev.page_size) { return STATUS_ERR_INVALID_ARG; } /* Get a pointer to the module hardware instance */ Nvmctrl *const nvm_module = NVMCTRL; /* Check if the module is busy */ if (!nvm_is_ready()) { return STATUS_BUSY; } /* Erase the page buffer before buffering new data */ nvm_module->CTRLA.reg = NVM_COMMAND_PAGE_BUFFER_CLEAR | NVMCTRL_CTRLA_CMDEX_KEY; /* Check if the module is busy */ while (!nvm_is_ready()) { /* Force-wait for the buffer clear to complete */ } /* Clear error flags */ nvm_module->STATUS.reg |= NVMCTRL_STATUS_MASK; uint32_t nvm_address = destination_address / 2; /* NVM _must_ be accessed as a series of 16-bit words, perform manual copy * to ensure alignment */ for (uint16_t i = 0; i < length; i += 2) { uint16_t data; /* Copy first byte of the 16-bit chunk to the temporary buffer */ data = buffer[i]; /* If we are not at the end of a write request with an odd byte count, * store the next byte of data as well */ if (i < (length - 1)) { data |= (buffer[i + 1] << 8); } /* Store next 16-bit chunk to the NVM memory space */ NVM_MEMORY[nvm_address++] = data; } /* If automatic page write mode is enable, then perform a manual NVM * write when the length of data to be programmed is less than page size */ if ((_nvm_dev.manual_page_write == false) && (length < NVMCTRL_PAGE_SIZE)) { #ifdef FEATURE_NVM_RWWEE return ((is_rww_eeprom) ? (nvm_execute_command(NVM_COMMAND_RWWEE_WRITE_PAGE,destination_address, 0)): (nvm_execute_command(NVM_COMMAND_WRITE_PAGE,destination_address, 0))); #else return nvm_execute_command(NVM_COMMAND_WRITE_PAGE, destination_address, 0); #endif } return STATUS_OK; }