/** * \brief Test EEPROM atomic write * * This test erases test page \ref TEST_ATOMIC_WRITE_PAGE, then writes the first * byte in the page buffer before flushing it -- this byte should then not be * written to the EEPROM -- and writing different values to the two successive * bytes. An atomic write is then executed before the write of the latter two * bytes is verified. * * \param test Current test case. */ static void run_eeprom_atomic_write_test(const struct test_case *test) { uint8_t buffer[EEPROM_PAGE_SIZE]; bool success; nvm_eeprom_erase_page(TEST_ATOMIC_WRITE_PAGE); /* Load a dummy byte and then flush the buffer to remove the byte from * the buffer. The byte should not be written to the EEPROM. */ nvm_eeprom_load_byte_to_buffer(0, 55); nvm_eeprom_flush_buffer(); /* Load some additional bytes */ set_buffer(buffer, EEPROM_ERASED); buffer[1] = 0xaa; buffer[2] = 0x19; nvm_eeprom_load_byte_to_buffer(1, buffer[1]); nvm_eeprom_load_byte_to_buffer(2, buffer[2]); /* Erase and then write page */ nvm_eeprom_atomic_write_page(TEST_ATOMIC_WRITE_PAGE); success = is_eeprom_page_equal_to_buffer(TEST_ATOMIC_WRITE_PAGE, buffer); test_assert_true(test, success, "Page buffer flush, byte load or atomic write failed"); }
/** * Test nvm_eeprom_erase_bytes_in_page() and * nvm_eeprom_erase_bytes_in_all_pages() * * Test procedure: * - Write two bytes into page TEST_ERASE_BYTES_PAGE_1 and * TEST_ERASE_BYTES_PAGE_2 * - Load value to page buffer in the address of the first byte * - Erase first byte of TEST_ERASE_BYTES_PAGE_1 * - Verify that first byte is deleted in TEST_ERASE_BYTES_PAGE_1 * - Load value to page buffer in the address of the first byte * - Erase first byte of all pages * - Verify that first byte is deleted in TEST_ERASE_BYTES_PAGE_2 * * \return STATUS_OK if test succeeded, otherwise ERR_BAD_DATA */ static status_code_t test_erase_bytes(void) { set_buffer(buffer, EEPROM_ERASED); buffer[0] = 0xaa; buffer[1] = 0xaf; /* Write two bytes into first page */ nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_1 * EEPROM_PAGE_SIZE + 0, buffer[0]); nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_1 * EEPROM_PAGE_SIZE + 1, buffer[1]); /* Write two bytes into second page */ nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_2 * EEPROM_PAGE_SIZE + 0, buffer[0]); nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_2 * EEPROM_PAGE_SIZE + 1, buffer[1]); /* Erase first byte of the first page */ nvm_eeprom_load_byte_to_buffer(0, 0xff); nvm_eeprom_erase_bytes_in_page(TEST_ERASE_BYTES_PAGE_1); buffer[0] = EEPROM_ERASED; if (is_eeprom_page_equal_to_buffer(TEST_ERASE_BYTES_PAGE_1, buffer)) { /* Erase first byte of all pages */ nvm_eeprom_load_byte_to_buffer(0, 0xff); nvm_eeprom_erase_bytes_in_all_pages(); if (is_eeprom_page_equal_to_buffer(TEST_ERASE_BYTES_PAGE_2, buffer)) { return STATUS_OK; } } return ERR_BAD_DATA; }
/** * Test nvm_eeprom_load_byte_to_buffer(), nvm_eeprom_flush_buffer() and * nvm_eeprom_atomic_write_page() * * Test procedure: * - Erase the TEST_ATOMIC_WRITE_PAGE page. * - Load byte and then flush the buffer at one location. * - Load two more bytes at a different location. * - Write the page. * - Verify that only two bytes are written and the rest of the page is erased. * * \return STATUS_OK if test succeeded, otherwise ERR_BAD_DATA */ static status_code_t test_atomic_write(void) { nvm_eeprom_erase_page(TEST_ATOMIC_WRITE_PAGE); /* Load a dummy byte and then flush the buffer to remove the byte from * the buffer. The byte should not be written to the EEPROM. */ nvm_eeprom_load_byte_to_buffer(0, 55); nvm_eeprom_flush_buffer(); /* Load some additional bytes */ set_buffer(buffer, EEPROM_ERASED); buffer[1] = 0xaa; buffer[2] = 0x19; nvm_eeprom_load_byte_to_buffer(1, buffer[1]); nvm_eeprom_load_byte_to_buffer(2, buffer[2]); /* Erase and then write page */ nvm_eeprom_atomic_write_page(TEST_ATOMIC_WRITE_PAGE); if (is_eeprom_page_equal_to_buffer(TEST_ATOMIC_WRITE_PAGE, buffer)) { return STATUS_OK; } return ERR_BAD_DATA; }
/** * \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 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; } }
/** * Test nvm_eeprom_split_write_page() * * Test procedure: * - Erase TEST_SPLIT_WRITE_PAGE page and then write 2 bytes * to TEST_SPLIT_WRITE_PAGE by using an atomic write * - Write 1 additional byte at another location using a split write * - Verify that all 3 bytes written correctly and that the rest of the page * is erased. * * \return STATUS_OK if test succeeded, otherwise ERR_BAD_DATA */ static status_code_t test_split_write(void) { /* Erase and then program two bytes into the page */ set_buffer(buffer, EEPROM_ERASED); buffer[1] = 0xaa; buffer[2] = 0x19; nvm_eeprom_load_byte_to_buffer(1, buffer[1]); nvm_eeprom_load_byte_to_buffer(2, buffer[2]); nvm_eeprom_atomic_write_page(TEST_SPLIT_WRITE_PAGE); /* * Write another value to the EEPROM and then verify that all three bytes * are present, ie. the split write does not delete the first two bytes. */ buffer[3] = 0xa7; nvm_eeprom_load_byte_to_buffer(3, buffer[3]); nvm_eeprom_split_write_page(TEST_SPLIT_WRITE_PAGE); if (is_eeprom_page_equal_to_buffer(TEST_SPLIT_WRITE_PAGE, buffer)) { return STATUS_OK; } return ERR_BAD_DATA; }
/** * \brief Test EEPROM byte erase * * This test writes two bytes to test pages \ref TEST_ERASE_BYTES_PAGE_1 and * \ref TEST_ERASE_BYTES_PAGE_2, then tries to erase one of them in the first * page before verifying the erase, then in all pages before verifying that the * second page was also erased. * * \param test Current test case. */ static void run_eeprom_erase_byte_test(const struct test_case *test) { uint8_t buffer[EEPROM_PAGE_SIZE]; bool success; set_buffer(buffer, EEPROM_ERASED); buffer[0] = 0xaa; buffer[1] = 0xaf; /* Write two bytes into first page */ nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_1 * EEPROM_PAGE_SIZE + 0, buffer[0]); nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_1 * EEPROM_PAGE_SIZE + 1, buffer[1]); /* Write two bytes into second page */ nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_2 * EEPROM_PAGE_SIZE + 0, buffer[0]); nvm_eeprom_write_byte(TEST_ERASE_BYTES_PAGE_2 * EEPROM_PAGE_SIZE + 1, buffer[1]); /* Erase first byte of the first page */ nvm_eeprom_load_byte_to_buffer(0, 0xff); nvm_eeprom_erase_bytes_in_page(TEST_ERASE_BYTES_PAGE_1); buffer[0] = EEPROM_ERASED; success = is_eeprom_page_equal_to_buffer(TEST_ERASE_BYTES_PAGE_1, buffer); test_assert_true(test, success, "Byte erase in single page failed"); /* Erase first byte of all pages */ nvm_eeprom_load_byte_to_buffer(0, 0xff); nvm_eeprom_erase_bytes_in_all_pages(); success = is_eeprom_page_equal_to_buffer(TEST_ERASE_BYTES_PAGE_2, buffer); test_assert_true(test, success, "Byte erase in all pages failed"); }
/** * \brief Test EEPROM split write * * This test writes two bytes to test page \ref TEST_SPLIT_WRITE_PAGE with an * atomic write operation, then writes a third byte to the same page with a * split write operation before verifying that the page contains all three * bytes. * * \param test Current test case. */ static void run_eeprom_split_write_test(const struct test_case *test) { uint8_t buffer[EEPROM_PAGE_SIZE]; bool success; /* Erase and then program two bytes into the page */ set_buffer(buffer, EEPROM_ERASED); buffer[1] = 0xaa; buffer[2] = 0x19; nvm_eeprom_load_byte_to_buffer(1, buffer[1]); nvm_eeprom_load_byte_to_buffer(2, buffer[2]); nvm_eeprom_atomic_write_page(TEST_SPLIT_WRITE_PAGE); /* * Write another value to the EEPROM and then verify that all three bytes * are present, ie. the split write does not delete the first two bytes. */ buffer[3] = 0xa7; nvm_eeprom_load_byte_to_buffer(3, buffer[3]); nvm_eeprom_split_write_page(TEST_SPLIT_WRITE_PAGE); success = is_eeprom_page_equal_to_buffer(TEST_SPLIT_WRITE_PAGE, buffer); test_assert_true(test, success, "Split write failed"); }