Esempio n. 1
0
/**
 * \brief Function for programming data to Flash
 *
 * This function will check whether the data is greater than Flash page size.
 * If it is greater, it splits and writes pagewise.
 *
 * \param address address of the Flash page to be programmed
 * \param buffer  pointer to the buffer containing data to be programmed
 * \param len     length of the data to be programmed to Flash
 */
static void program_memory(uint32_t address, uint8_t *buffer, uint32_t len)
{
	/* Check if length is greater than Flash page size */
	if (len > NVMCTRL_PAGE_SIZE) {
		uint32_t offset = 0;
		while (len > NVMCTRL_PAGE_SIZE) {
			/* Check if it is first page of a row */
			if ((address & 0xFF) == 0) {
				/* Erase row */
				nvm_erase_row(address);
			}
			/* Write one page data to flash */
			nvm_write_buffer(address, buffer + offset, NVMCTRL_PAGE_SIZE);
			/* Increment the address to be programmed */
			address += NVMCTRL_PAGE_SIZE;
			/* Increment the offset of the buffer containing data */
			offset += NVMCTRL_PAGE_SIZE;
			/* Decrement the length */
			len -= NVMCTRL_PAGE_SIZE;
		}
		/* Check if there is data remaining to be programmed*/
		if (len > 0) {
			/* Write the data to flash */
			nvm_write_buffer(address, buffer + offset, len);
		}
	} else {
		/* Check if it is first page of a row) */
		if ((address & 0xFF) == 0) {
			/* Erase row */
			nvm_erase_row(address);
		}
		/* Write the data to flash */
		nvm_write_buffer(address, buffer, len);
	}
}
/* if not, save new thing token to memory and use it */
uint8_t thethingsio_example_write_thing_token_nvm(char * thing_token)
{	
	uint8_t token_saved = true;
	uint8_t writeBuffer_Temp[NVMCTRL_PAGE_SIZE] = {0, };
		
	// erase flash memory area
	enum status_code status = nvm_erase_row(NVM_ADDR_THING_TOKEN_SAVED);
	if(status == STATUS_OK)
		status = nvm_erase_row(NVM_ADDR_THING_TOKEN);

	// rewrite flash memory area
	if(status == STATUS_OK)
		status = nvm_write_buffer(NVM_ADDR_THING_TOKEN_SAVED, &token_saved, 1);
	if(status == STATUS_OK)
		status = nvm_write_buffer(NVM_ADDR_THING_TOKEN, thing_token, THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH);
	
	// check if all the operations went through correctly
	if(status != STATUS_OK)
		printf("set thing token, write thing token error!!\r\n");
	
	// update thingsiO read write URL
	uint8_t thing_token_offset = sizeof(gau8TheThingsiOHttpRWUrl) - THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH - 1;
	memcpy((gau8TheThingsiOHttpRWUrl+thing_token_offset),thing_token, THETHINGSIO_EXAMPLE_THING_TOKEN_LENGTH);
	
	return true;
}
Esempio n. 3
0
/*---------------------------------------------------------------------------*/
static int
write(unsigned long addr, const unsigned char * buffer, unsigned long len)
{
  enum status_code ret;
  unsigned long page_addr;
  int copy_len, i;

  if (!opened) {
    return -1;
  }

  /* Check if the row address is valid */
  if ((addr + len) >
      ((uint32_t)parameters.page_size * parameters.nvm_number_of_pages)) {
    WARN("addr is outside flash region");
    return -1;
  }

  while (len > 0) {
    /* Determine start address of page */
    page_addr = (addr / SECTOR_SIZE) * SECTOR_SIZE;

    /* Copy content of current page to tmp_buffer */
    memcpy(tmp_buffer, (void *)page_addr, SECTOR_SIZE);

    /* Wait until flash is ready */
    while (!nvm_is_ready());

    /* Erase current page */
    nvm_erase_row(page_addr);

    /* Determine number of bytes to copy */
    copy_len = min(len, (page_addr + SECTOR_SIZE) - addr);

    /* Update tmp_buffer with content from buffer */
    memcpy(&tmp_buffer[addr - page_addr], buffer, copy_len);

    /* Update buffer, len and addr */
    len    -= copy_len;
    addr   += copy_len;
    buffer += copy_len;

    /* Wait until flash is ready */
    while (!nvm_is_ready());

    /* Write contents of tmp_buffer to flash in NVMCTRL_ROW_PAGES steps */
    for (i = 0; i < NVMCTRL_ROW_PAGES; i++) {
      if ((ret = nvm_write_buffer(page_addr + i * PAGE_SIZE, &tmp_buffer[i * PAGE_SIZE], PAGE_SIZE)) != STATUS_OK) {
        WARN("nvm_write_buffer error: %d", ret);
        return -1;
      }
    }
  }

  /* Return OK */
  return 1;
}
Esempio n. 4
0
int main(void)
{
	//! [setup_init]
	configure_nvm();
	//! [setup_init]

//! [main]
	//! [main_1]
	uint8_t page_buffer[NVMCTRL_PAGE_SIZE];
	//! [main_1]

	//! [main_2]
	for (uint32_t i = 0; i < NVMCTRL_PAGE_SIZE; i++) {
		page_buffer[i] = i;
	}
	//! [main_2]

	//! [main_3]
	enum status_code error_code;
	//! [main_3]

	//! [main_4]
	do
	{
		error_code = nvm_erase_row(
				100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE);
	} while (error_code == STATUS_BUSY);
	//! [main_4]

	//! [main_5]
	do
	{
		error_code = nvm_write_buffer(
				100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE,
				page_buffer, NVMCTRL_PAGE_SIZE);
	} while (error_code == STATUS_BUSY);
	//! [main_5]

	//! [main_6]
	do
	{
		error_code = nvm_read_buffer(
				100 * NVMCTRL_ROW_PAGES * NVMCTRL_PAGE_SIZE,
				page_buffer, NVMCTRL_PAGE_SIZE);
	} while (error_code == STATUS_BUSY);
	//! [main_6]

//! [main]

	while (true) {
		/* Do nothing */
	}
}
Esempio n. 5
0
static int
samd21_flash_write(uint32_t address, const void *src, uint32_t len)
{
    int base_address;
    int offset;
    struct nvm_parameters params;
    uint8_t page_buffer[64];
    const uint8_t *psrc = src;
    
    /* make sure this fits into our stack buffer  */
    nvm_get_parameters(&params);      
    assert(params.page_size <= sizeof(page_buffer));
    
    /* get the page address (this is not a sector, there are 4 pages per
     * row */
    while(len) {   
        int write_len;
        
        base_address = address & ~(params.page_size - 1);
        
        offset = address - base_address;
        write_len = params.page_size - offset;
        
        if(write_len > len) {
            write_len = len;
        }

        if(nvm_read_buffer(base_address, page_buffer, params.page_size) 
                        != STATUS_OK) {
            return -1;
        }

        /* move the pointers since this is a sure thing */
        len -= write_len;
        address += write_len;
        
        /* copy it into the page buffer */
        while(write_len--) {
            page_buffer[offset++] = *psrc++;
        }
        
        /* 0x000054a4 */
#if 1
        /* write back the page buffer buffer */
        if(nvm_write_buffer(base_address,page_buffer, params.page_size)
                        != STATUS_OK) {
            return -1;
        }                
#endif
    }    
    return 0;
}
Esempio n. 6
0
/**
 * \brief Test NVM writing
 *
 * This test writes erased test page with a pattern, reads it back
 * and checks the integrity
 *
 * \param test Current test case.
 */
static void run_nvm_read_and_write_test(const struct test_case *test)
{
	uint8_t buffer[NVMCTRL_PAGE_SIZE], i;
	enum status_code status;

	/* Skip test if NVM initialization failed */
	test_assert_true(test, nvm_init_success == true,
			"NVM initialization failed, skipping test");

	/* Fill the buffer with Pattern 1 */
	for (i = 0; i < NVMCTRL_PAGE_SIZE; i++) {
		buffer[i] = BYTE_PATTERN1(i);
	}

	/* Write the buffer to Test address in NVM */
	status = nvm_write_buffer(TEST_PAGE_ADDR, buffer, NVMCTRL_PAGE_SIZE);

	/* Validate whether write operation is complete */
	test_assert_true(test, status == STATUS_OK,
			"Write operation error");

	/* Flush the buffer */
	for (i = 0; i < NVMCTRL_PAGE_SIZE; i++) {
		buffer[i] = 0;
	}

	/* Read the NVM contents at test address to buffer */
	status = nvm_read_buffer(TEST_PAGE_ADDR, buffer, NVMCTRL_PAGE_SIZE);

	/* Validate whether read operation is complete */
	test_assert_true(test, status == STATUS_OK,
			"Read operation error");

	/* Check the integrity of data in NVM */
	for (i = 0; i < NVMCTRL_PAGE_SIZE; i++) {
		test_assert_true(test, buffer[i] == BYTE_PATTERN1(i),
			"Value not expected @ byte %d (read: 0x%02x,"
			" expected: 0x%02x)", i, buffer[i], BYTE_PATTERN1(i));
	}
 }
/**
 * \brief Updates an arbitrary section of a page with new data.
 *
 * Writes from a buffer to a given page in the NVM memory, retaining any
 * unmodified data already stored in the page.
 *
 * \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.
 *
 * \warning This routine is unsafe if data integrity is critical; a system reset
 *          during the update process will result in up to one row of data being
 *          lost. If corruption must be avoided in all circumstances (including
 *          power loss or system reset) this function should not be used.
 *
 * \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]  offset               Number of bytes to offset the data write in
 *                                  the page
 * \param[in]  length               Number of bytes in the page to update
 *
 * \return Status of the attempt to update 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
 * \retval STATUS_ERR_INVALID_ARG  The supplied length and offset was invalid
 */
enum status_code nvm_update_buffer(
		const uint32_t destination_address,
		uint8_t *const buffer,
		uint16_t offset,
		uint16_t length)
{
	enum status_code error_code = STATUS_OK;
	uint8_t row_buffer[NVMCTRL_ROW_PAGES][NVMCTRL_PAGE_SIZE];

	/* Ensure the read does not overflow the page size */
	if ((offset + length) > _nvm_dev.page_size) {
		return STATUS_ERR_INVALID_ARG;
	}

	/* Calculate the starting row address of the page to update */
	uint32_t row_start_address =
			destination_address & ~((_nvm_dev.page_size * NVMCTRL_ROW_PAGES) - 1);

	/* Read in the current row contents */
	for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) {
		do
		{
			error_code = nvm_read_buffer(
					row_start_address + (i * _nvm_dev.page_size),
					row_buffer[i], _nvm_dev.page_size);
		} while (error_code == STATUS_BUSY);

		if (error_code != STATUS_OK) {
			return error_code;
		}
	}

	/* Calculate the starting page in the row that is to be updated */
	uint8_t page_in_row =
			(destination_address % (_nvm_dev.page_size * NVMCTRL_ROW_PAGES)) /
			_nvm_dev.page_size;

	/* Update the specified bytes in the page buffer */
	for (uint32_t i = 0; i < length; i++) {
		row_buffer[page_in_row][offset + i] = buffer[i];
	}

	system_interrupt_enter_critical_section();

	/* Erase the row */
	do
	{
		error_code = nvm_erase_row(row_start_address);
	} while (error_code == STATUS_BUSY);

	if (error_code != STATUS_OK) {
		system_interrupt_leave_critical_section();
		return error_code;
	}

	/* Write the updated row contents to the erased row */
	for (uint32_t i = 0; i < NVMCTRL_ROW_PAGES; i++) {
		do
		{
			error_code = nvm_write_buffer(
					row_start_address + (i * _nvm_dev.page_size),
					row_buffer[i], _nvm_dev.page_size);
		} while (error_code == STATUS_BUSY);

		if (error_code != STATUS_OK) {
			system_interrupt_leave_critical_section();
			return error_code;
		}
	}

	system_interrupt_leave_critical_section();

	return error_code;
}