コード例 #1
0
ファイル: flash.c プロジェクト: abtink/openthread
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;
}
コード例 #2
0
/**
 * \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;
}