Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: flash: Add page_layout test for flash controllers
Add test suite which tests writing to and erasing all pages, of any size defined by the page layout. If the test is built with MCUBOOT, the test will jump into the application, then run write/erase/boundary tests on the bootload partition. If MCUBOOT is not selected, the test will target the slot1 partition instead, performing the same tests. Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
- Loading branch information
1 parent
2d150c5
commit be18b9d
Showing
5 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Copyright (c) 2023 Bjarki Arge Andreasen | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(flash_page_layout) | ||
|
||
target_sources(app PRIVATE src/main.c) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Copyright (c) 2023 Bjarki Arge Andreasen | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
CONFIG_FLASH=y | ||
CONFIG_ZTEST=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
/* | ||
* Copyright (c) 2023 Bjarki Arge Andreasen | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/kernel.h> | ||
#include <string.h> | ||
#include <zephyr/drivers/flash.h> | ||
#include <zephyr/devicetree.h> | ||
#include <zephyr/ztest.h> | ||
#include <zephyr/logging/log.h> | ||
|
||
LOG_MODULE_REGISTER(test_flash); | ||
|
||
#ifdef CONFIG_BOOTLOADER_MCUBOOT | ||
|
||
#define TEST_FLASH_PART_NODE \ | ||
DT_NODELABEL(boot_partition) | ||
|
||
#else | ||
|
||
#define TEST_FLASH_PART_NODE \ | ||
DT_NODELABEL(slot1_partition) | ||
|
||
#endif | ||
|
||
#define TEST_FLASH_PART_OFFSET \ | ||
DT_REG_ADDR(TEST_FLASH_PART_NODE) | ||
|
||
#define TEST_FLASH_PART_SIZE \ | ||
DT_REG_SIZE(TEST_FLASH_PART_NODE) | ||
|
||
#define TEST_FLASH_PART_END_OFFSET \ | ||
(TEST_FLASH_PART_OFFSET + TEST_FLASH_PART_SIZE) | ||
|
||
#define TEST_FLASH_CONTROLLER_NODE \ | ||
DT_MTD_FROM_FIXED_PARTITION(TEST_FLASH_PART_NODE) | ||
|
||
static const struct device *flash_controller = DEVICE_DT_GET(TEST_FLASH_CONTROLLER_NODE); | ||
static uint8_t test_write_block[128]; | ||
static uint8_t test_read_block[128]; | ||
|
||
static void test_flash_fill_test_write_block(void) | ||
{ | ||
for (uint8_t i = 0; i < sizeof(test_write_block); i++) { | ||
test_write_block[i] = i; | ||
} | ||
} | ||
|
||
static void *test_flash_setup(void) | ||
{ | ||
test_flash_fill_test_write_block(); | ||
return NULL; | ||
} | ||
|
||
static bool test_flash_mem_is_set_to(const uint8_t *data, uint8_t to, size_t size) | ||
{ | ||
for (size_t i = 0; i < size; i++) { | ||
if (data[i] != to) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
static bool test_flash_is_erased(off_t offset, size_t size) | ||
{ | ||
static uint8_t test_erase_buffer[99]; | ||
const struct flash_parameters *parameters = flash_get_parameters(flash_controller); | ||
size_t remaining; | ||
size_t readsize; | ||
|
||
while (offset < size) { | ||
remaining = size - (size_t)offset; | ||
readsize = MIN(sizeof(test_erase_buffer), remaining); | ||
|
||
if (flash_read(flash_controller, offset, test_erase_buffer, readsize) < 0) { | ||
return false; | ||
} | ||
|
||
if (!test_flash_mem_is_set_to(test_erase_buffer, parameters->erase_value, | ||
readsize)) { | ||
return false; | ||
} | ||
|
||
offset += (off_t)readsize; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
static bool test_flash_verify_partition_is_erased(void) | ||
{ | ||
return test_flash_is_erased(TEST_FLASH_PART_OFFSET, TEST_FLASH_PART_SIZE); | ||
} | ||
|
||
static int test_flash_erase_partition(void) | ||
{ | ||
LOG_INF("Erasing section of size %zu at offset %zu controlled by %s", | ||
TEST_FLASH_PART_SIZE, | ||
TEST_FLASH_PART_OFFSET, | ||
flash_controller->name); | ||
|
||
return flash_erase(flash_controller, TEST_FLASH_PART_OFFSET, | ||
TEST_FLASH_PART_SIZE); | ||
} | ||
|
||
static void test_flash_before(void *f) | ||
{ | ||
ARG_UNUSED(f); | ||
__ASSERT(test_flash_erase_partition() == 0, | ||
"Failed to erase partition"); | ||
__ASSERT(test_flash_verify_partition_is_erased(), | ||
"Failed to erase partition"); | ||
} | ||
|
||
static void test_flash_write_block_at_offset(off_t offset, size_t size) | ||
{ | ||
zassert_ok(flash_write(flash_controller, offset, test_write_block, size), | ||
"Failed to write block at offset %zu, of size %zu", (size_t)offset, size); | ||
zassert_ok(flash_read(flash_controller, offset, test_read_block, size), | ||
"Failed to read block at offset %zu, of size %zu", (size_t)offset, size); | ||
zassert_ok(memcmp(test_write_block, test_read_block, size), | ||
"Failed to write block at offset %zu, of size %zu to page", (size_t)offset, | ||
size); | ||
} | ||
|
||
static void test_flash_write_across_page_boundary(const struct flash_pages_info *info, | ||
size_t write_block_size) | ||
{ | ||
off_t page_boundary = info->start_offset; | ||
uint32_t page0_index = info->index - 1; | ||
uint32_t page1_index = info->index; | ||
off_t cross_write_start_offset = page_boundary - (off_t)write_block_size; | ||
size_t cross_write_size = write_block_size * 2; | ||
|
||
LOG_INF("Writing across page boundary at %zu, between page index %u and %u", | ||
(size_t)page_boundary, | ||
page0_index, | ||
page1_index); | ||
|
||
test_flash_write_block_at_offset(cross_write_start_offset, cross_write_size); | ||
} | ||
|
||
static bool test_flash_write_across_page_boundaries(const struct flash_pages_info *info, | ||
void *data) | ||
{ | ||
size_t write_block_size = *((size_t *)data); | ||
|
||
if (info->start_offset <= TEST_FLASH_PART_OFFSET) { | ||
/* Not yet reached second page within partition */ | ||
return true; | ||
} | ||
|
||
if (info->start_offset >= TEST_FLASH_PART_END_OFFSET) { | ||
/* Reached first page after partition end */ | ||
return false; | ||
} | ||
|
||
test_flash_write_across_page_boundary(info, write_block_size); | ||
return true; | ||
} | ||
|
||
ZTEST(flash_page_layout, test_write_across_page_boundaries_in_part) | ||
{ | ||
const struct flash_parameters *parameters = flash_get_parameters(flash_controller); | ||
size_t write_block_size = parameters->write_block_size; | ||
|
||
flash_page_foreach(flash_controller, test_flash_write_across_page_boundaries, | ||
&write_block_size); | ||
} | ||
|
||
static void test_flash_erase_page(const struct flash_pages_info *info) | ||
{ | ||
off_t page_offset = info->start_offset; | ||
size_t page_size = info->size; | ||
size_t page_index = info->index; | ||
|
||
LOG_INF("Erasing page at %zu of size %zu with index %zu", | ||
(size_t)page_offset, page_size, page_index); | ||
|
||
zassert_ok(flash_erase(flash_controller, page_offset, page_size), | ||
"Failed to erase page"); | ||
|
||
zassert_true(test_flash_is_erased(page_offset, page_size), | ||
"Failed to erase page"); | ||
} | ||
|
||
static bool test_flash_erase_pages(const struct flash_pages_info *info, void *data) | ||
{ | ||
if (info->start_offset < TEST_FLASH_PART_OFFSET) { | ||
/* Not yet reached first page within partition */ | ||
return true; | ||
} | ||
|
||
if (info->start_offset >= TEST_FLASH_PART_END_OFFSET) { | ||
/* Reached first page after partition end */ | ||
return false; | ||
} | ||
|
||
test_flash_erase_page(info); | ||
return true; | ||
} | ||
|
||
ZTEST(flash_page_layout, test_erase_single_pages_in_part) | ||
{ | ||
const struct flash_parameters *parameters = flash_get_parameters(flash_controller); | ||
size_t write_block_size = parameters->write_block_size; | ||
|
||
flash_page_foreach(flash_controller, test_flash_write_across_page_boundaries, | ||
&write_block_size); | ||
|
||
flash_page_foreach(flash_controller, test_flash_erase_pages, NULL); | ||
} | ||
|
||
ZTEST_SUITE(flash_page_layout, NULL, test_flash_setup, test_flash_before, NULL, NULL); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright (c) 2023 Bjarki Arge Andreasen | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
SB_CONFIG_BOOTLOADER_MCUBOOT=y |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright (c) 2023 Bjarki Arge Andreasen | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
common: | ||
sysbuild: true | ||
tags: | ||
- drivers | ||
- flash | ||
tests: | ||
flash.page_layout.build_only: | ||
harness: ztest | ||
build_only: true | ||
platform_allow: | ||
- sam_v71_xult | ||
- b_u585i_iot02a | ||
- nrf9160dk_nrf9160 | ||
- nrf5340dk_nrf5340_cpuapp |