subsys: storage: Add flash_map abstraction module
Introduce flas_map module is abstraction over flash memory and its driver for using flash memories along with description of available flash areas. Module provides simple API for write/read/erase and so one. Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
parent
4a713aa824
commit
25269fb0ed
13 changed files with 586 additions and 0 deletions
90
include/flash_map.h
Normal file
90
include/flash_map.h
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2015 Runtime Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FLASH_MAP_H__
|
||||||
|
#define __FLASH_MAP_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Provides abstraction of flash regions for type of use.
|
||||||
|
* I.e. dude where's my image?
|
||||||
|
*
|
||||||
|
* System will contain a map which contains flash areas. Every
|
||||||
|
* region will contain flash identifier, offset within flash and length.
|
||||||
|
*
|
||||||
|
* 1. This system map could be in a file within filesystem (Initializer
|
||||||
|
* must know/figure out where the filesystem is at).
|
||||||
|
* 2. Map could be at fixed location for project (compiled to code)
|
||||||
|
* 3. Map could be at specific place in flash (put in place at mfg time).
|
||||||
|
*
|
||||||
|
* Note that the map you use must be valid for BSP it's for,
|
||||||
|
* match the linker scripts when platform executes from flash,
|
||||||
|
* and match the target offset specified in download script.
|
||||||
|
*/
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define SOC_FLASH_0_ID 0 /* device_id for SoC flash memory driver */
|
||||||
|
#define SPI_FLASH_0_ID 1 /* device_id for external SPI flash driver */
|
||||||
|
|
||||||
|
struct flash_area {
|
||||||
|
u8_t fa_id;
|
||||||
|
u8_t fa_device_id;
|
||||||
|
u16_t pad16;
|
||||||
|
off_t fa_off;
|
||||||
|
size_t fa_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct flash_sector {
|
||||||
|
off_t fs_off;
|
||||||
|
size_t fs_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes flash map. Memory will be referenced by flash_map code
|
||||||
|
* from this on.
|
||||||
|
*/
|
||||||
|
void flash_map_init(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start using flash area.
|
||||||
|
*/
|
||||||
|
int flash_area_open(u8_t id, const struct flash_area **fa);
|
||||||
|
|
||||||
|
void flash_area_close(const struct flash_area *fa);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read/write/erase. Offset is relative from beginning of flash area.
|
||||||
|
*/
|
||||||
|
int flash_area_read(const struct flash_area *fa, off_t off, void *dst,
|
||||||
|
size_t len);
|
||||||
|
int flash_area_write(const struct flash_area *fa, off_t off, const void *src,
|
||||||
|
size_t len);
|
||||||
|
int flash_area_erase(const struct flash_area *fa, off_t off, size_t len);
|
||||||
|
/* int flash_area_is_empty(const struct flash_area *, bool *); */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alignment restriction for flash writes.
|
||||||
|
*/
|
||||||
|
u8_t flash_area_align(const struct flash_area *fa);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given flash area ID, return info about sectors within the area.
|
||||||
|
*/
|
||||||
|
int flash_area_get_sectors(int fa_id, uint32_t *count,
|
||||||
|
struct flash_sector *sectors);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __FLASH_MAP_H__ */
|
|
@ -10,3 +10,4 @@ add_subdirectory_ifdef(CONFIG_MCUBOOT_IMG_MANAGER dfu)
|
||||||
add_subdirectory_ifdef(CONFIG_NET_BUF net)
|
add_subdirectory_ifdef(CONFIG_NET_BUF net)
|
||||||
add_subdirectory_ifdef(CONFIG_USB usb)
|
add_subdirectory_ifdef(CONFIG_USB usb)
|
||||||
add_subdirectory(random)
|
add_subdirectory(random)
|
||||||
|
add_subdirectory(storage)
|
||||||
|
|
|
@ -28,3 +28,5 @@ source "subsys/usb/Kconfig"
|
||||||
source "subsys/dfu/Kconfig"
|
source "subsys/dfu/Kconfig"
|
||||||
|
|
||||||
source "subsys/random/Kconfig"
|
source "subsys/random/Kconfig"
|
||||||
|
|
||||||
|
source "subsys/storage/Kconfig"
|
||||||
|
|
1
subsys/storage/CMakeLists.txt
Normal file
1
subsys/storage/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory_ifdef(CONFIG_FLASH_MAP flash_map)
|
13
subsys/storage/Kconfig
Normal file
13
subsys/storage/Kconfig
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Kconfig - Subsystem configuration options
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
menu "Storage"
|
||||||
|
|
||||||
|
source "subsys/storage/flash_map/Kconfig"
|
||||||
|
|
||||||
|
endmenu
|
3
subsys/storage/flash_map/CMakeLists.txt
Normal file
3
subsys/storage/flash_map/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
zephyr_sources(flash_map.c)
|
||||||
|
zephyr_sources_ifndef(CONFIG_FLASH_MAP_CUSTOM flash_map_default.c)
|
||||||
|
|
28
subsys/storage/flash_map/Kconfig
Normal file
28
subsys/storage/flash_map/Kconfig
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Kconfig - Flash map abstraction module
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Flash map
|
||||||
|
#
|
||||||
|
|
||||||
|
menuconfig FLASH_MAP
|
||||||
|
bool
|
||||||
|
prompt "Flash map abstraction module"
|
||||||
|
default n
|
||||||
|
depends on FLASH
|
||||||
|
help
|
||||||
|
Enable support of flash map abstraction.
|
||||||
|
|
||||||
|
config FLASH_MAP_CUSTOM
|
||||||
|
bool
|
||||||
|
prompt "Custom flash map description"
|
||||||
|
default n
|
||||||
|
depends on FLASH_MAP
|
||||||
|
help
|
||||||
|
This option enables custom flash map description.
|
||||||
|
User must provide such a description in place of default on
|
||||||
|
if had enabled this option.
|
270
subsys/storage/flash_map/flash_map.c
Normal file
270
subsys/storage/flash_map/flash_map.c
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2015 Runtime Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <flash_map.h>
|
||||||
|
#include <flash.h>
|
||||||
|
#include <soc.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||||
|
struct layout_data {
|
||||||
|
u32_t area_idx;
|
||||||
|
u32_t area_off;
|
||||||
|
u32_t area_len;
|
||||||
|
void *ret; /* struct flash_area* or struct flash_sector* */
|
||||||
|
u32_t ret_idx;
|
||||||
|
u32_t ret_len;
|
||||||
|
int status;
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
|
||||||
|
|
||||||
|
struct driver_map_entry {
|
||||||
|
u8_t id;
|
||||||
|
const char * const name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct driver_map_entry flash_drivers_map[] = {
|
||||||
|
#ifdef FLASH_DRIVER_NAME /* SoC embedded flash driver */
|
||||||
|
{SOC_FLASH_0_ID, FLASH_DRIVER_NAME},
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_SPI_FLASH_W25QXXDV
|
||||||
|
{SPI_FLASH_0_ID, CONFIG_SPI_FLASH_W25QXXDV_DRV_NAME},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct flash_area *flash_map;
|
||||||
|
extern const int flash_map_entries;
|
||||||
|
|
||||||
|
int flash_area_open(u8_t id, const struct flash_area **fap)
|
||||||
|
{
|
||||||
|
const struct flash_area *area;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (flash_map == NULL) {
|
||||||
|
return -EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < flash_map_entries; i++) {
|
||||||
|
area = flash_map + i;
|
||||||
|
if (area->fa_id == id) {
|
||||||
|
*fap = area;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_area_close(const struct flash_area *fa)
|
||||||
|
{
|
||||||
|
/* nothing to do for now */
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device *get_flah_dev_from_id(u8_t id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(flash_drivers_map); i++) {
|
||||||
|
if (flash_drivers_map[i].id == id) {
|
||||||
|
return device_get_binding(flash_drivers_map[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool is_in_flash_area_bounds(const struct flash_area *fa,
|
||||||
|
off_t off, size_t len)
|
||||||
|
{
|
||||||
|
return (off <= fa->fa_size && off + len <= fa->fa_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct flash_area const *get_flash_area_from_id(int idx)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < flash_map_entries; i++) {
|
||||||
|
if (flash_map[i].fa_id == idx) {
|
||||||
|
return &flash_map[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
|
||||||
|
/*
|
||||||
|
* Check if a flash_page_foreach() callback should exit early, due to
|
||||||
|
* one of the following conditions:
|
||||||
|
*
|
||||||
|
* - The flash page described by "info" is before the area of interest
|
||||||
|
* described in "data"
|
||||||
|
* - The flash page is after the end of the area
|
||||||
|
* - There are too many flash pages on the device to fit in the array
|
||||||
|
* held in data->ret. In this case, data->status is set to -ENOMEM.
|
||||||
|
*
|
||||||
|
* The value to return to flash_page_foreach() is stored in
|
||||||
|
* "bail_value" if the callback should exit early.
|
||||||
|
*/
|
||||||
|
static bool should_bail(const struct flash_pages_info *info,
|
||||||
|
struct layout_data *data,
|
||||||
|
bool *bail_value)
|
||||||
|
{
|
||||||
|
if (info->start_offset < data->area_off) {
|
||||||
|
*bail_value = true;
|
||||||
|
return true;
|
||||||
|
} else if (info->start_offset >= data->area_off + data->area_len) {
|
||||||
|
*bail_value = false;
|
||||||
|
return true;
|
||||||
|
} else if (data->ret_idx >= data->ret_len) {
|
||||||
|
data->status = -ENOMEM;
|
||||||
|
*bail_value = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic page layout discovery routine. This is kept separate to
|
||||||
|
* support both the deprecated flash_area_to_sectors() and the current
|
||||||
|
* flash_area_get_sectors(). A lot of this can be inlined once
|
||||||
|
* flash_area_to_sectors() is removed.
|
||||||
|
*/
|
||||||
|
static int flash_area_layout(int idx, int *cnt, void *ret,
|
||||||
|
flash_page_cb cb, struct layout_data *cb_data)
|
||||||
|
{
|
||||||
|
struct device *flash_dev;
|
||||||
|
|
||||||
|
cb_data->area_idx = idx;
|
||||||
|
|
||||||
|
const struct flash_area *fa;
|
||||||
|
|
||||||
|
fa = get_flash_area_from_id(idx);
|
||||||
|
if (fa == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb_data->area_idx = idx;
|
||||||
|
cb_data->area_off = fa->fa_off;
|
||||||
|
cb_data->area_len = fa->fa_size;
|
||||||
|
|
||||||
|
cb_data->ret = ret;
|
||||||
|
cb_data->ret_idx = 0;
|
||||||
|
cb_data->ret_len = *cnt;
|
||||||
|
cb_data->status = 0;
|
||||||
|
|
||||||
|
flash_dev = get_flah_dev_from_id(fa->fa_device_id);
|
||||||
|
|
||||||
|
flash_page_foreach(flash_dev, cb, cb_data);
|
||||||
|
|
||||||
|
if (cb_data->status == 0) {
|
||||||
|
*cnt = cb_data->ret_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb_data->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_sectors_cb(const struct flash_pages_info *info, void *datav)
|
||||||
|
{
|
||||||
|
struct layout_data *data = datav;
|
||||||
|
struct flash_sector *ret = data->ret;
|
||||||
|
bool bail;
|
||||||
|
|
||||||
|
if (should_bail(info, data, &bail)) {
|
||||||
|
return bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[data->ret_idx].fs_off = info->start_offset - data->area_off;
|
||||||
|
ret[data->ret_idx].fs_size = info->size;
|
||||||
|
data->ret_idx++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flash_area_get_sectors(int idx, uint32_t *cnt, struct flash_sector *ret)
|
||||||
|
{
|
||||||
|
struct layout_data data;
|
||||||
|
|
||||||
|
return flash_area_layout(idx, cnt, ret, get_sectors_cb, &data);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_FLASH_PAGE_LAYOUT */
|
||||||
|
|
||||||
|
int flash_area_read(const struct flash_area *fa, off_t off, void *dst,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
if (!is_in_flash_area_bounds(fa, off, len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = get_flah_dev_from_id(fa->fa_device_id);
|
||||||
|
|
||||||
|
return flash_read(dev, fa->fa_off + off, dst, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flash_area_write(const struct flash_area *fa, off_t off, const void *src,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct device *flash_dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!is_in_flash_area_bounds(fa, off, len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_dev = get_flah_dev_from_id(fa->fa_device_id);
|
||||||
|
|
||||||
|
rc = flash_write_protection_set(flash_dev, false);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_write(flash_dev, fa->fa_off + off, (void *)src, len);
|
||||||
|
|
||||||
|
/* Ignore errors here - this does not affect write operation */
|
||||||
|
(void) flash_write_protection_set(flash_dev, true);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flash_area_erase(const struct flash_area *fa, off_t off, size_t len)
|
||||||
|
{
|
||||||
|
struct device *flash_dev;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!is_in_flash_area_bounds(fa, off, len)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_dev = get_flah_dev_from_id(fa->fa_device_id);
|
||||||
|
|
||||||
|
rc = flash_write_protection_set(flash_dev, false);
|
||||||
|
if (rc) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = flash_erase(flash_dev, fa->fa_off + off, len);
|
||||||
|
|
||||||
|
/* Ignore errors here - this does not affect write operation */
|
||||||
|
(void) flash_write_protection_set(flash_dev, true);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8_t flash_area_align(const struct flash_area *fa)
|
||||||
|
{
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
|
dev = get_flah_dev_from_id(fa->fa_device_id);
|
||||||
|
|
||||||
|
return flash_get_write_block_size(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_map_init(void)
|
||||||
|
{
|
||||||
|
}
|
56
subsys/storage/flash_map/flash_map_default.c
Normal file
56
subsys/storage/flash_map/flash_map_default.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2015 Runtime Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <flash_map.h>
|
||||||
|
|
||||||
|
const struct flash_area default_flash_map[] = {
|
||||||
|
/* FLASH_AREA_BOOTLOADER */
|
||||||
|
{
|
||||||
|
.fa_id = 0,
|
||||||
|
.fa_device_id = SOC_FLASH_0_ID,
|
||||||
|
.fa_off = FLASH_AREA_MCUBOOT_OFFSET,
|
||||||
|
.fa_size = FLASH_AREA_MCUBOOT_SIZE,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* FLASH_AREA_IMAGE_0 */
|
||||||
|
{
|
||||||
|
.fa_id = 1,
|
||||||
|
.fa_device_id = SOC_FLASH_0_ID,
|
||||||
|
.fa_off = FLASH_AREA_IMAGE_0_OFFSET,
|
||||||
|
.fa_size = FLASH_AREA_IMAGE_0_SIZE,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* FLASH_AREA_IMAGE_1 */
|
||||||
|
{
|
||||||
|
.fa_id = 2,
|
||||||
|
.fa_device_id = SOC_FLASH_0_ID,
|
||||||
|
.fa_off = FLASH_AREA_IMAGE_1_OFFSET,
|
||||||
|
.fa_size = FLASH_AREA_IMAGE_1_SIZE,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* FLASH_AREA_IMAGE_SCRATCH */
|
||||||
|
{
|
||||||
|
.fa_id = 3,
|
||||||
|
.fa_device_id = SOC_FLASH_0_ID,
|
||||||
|
.fa_off = FLASH_AREA_IMAGE_SCRATCH_OFFSET,
|
||||||
|
.fa_size = FLASH_AREA_IMAGE_SCRATCH_SIZE,
|
||||||
|
},
|
||||||
|
|
||||||
|
#ifdef CONFIG_FILE_SYSTEM_NFFS
|
||||||
|
/* FLASH_AREA_NFFS_ */
|
||||||
|
{
|
||||||
|
.fa_id = 4,
|
||||||
|
.fa_device_id = SOC_FLASH_0_ID,
|
||||||
|
.fa_off = FLASH_AREA_NFFS_OFFSET,
|
||||||
|
.fa_size = FLASH_AREA_NFFS_SIZE,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const int flash_map_entries = ARRAY_SIZE(default_flash_map);
|
||||||
|
const struct flash_area *flash_map = default_flash_map;
|
5
tests/subsys/storage/flash_mpa/CMakeLists.txt
Normal file
5
tests/subsys/storage/flash_mpa/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
|
||||||
|
project(NONE)
|
||||||
|
|
||||||
|
FILE(GLOB app_sources src/*.c)
|
||||||
|
target_sources(app PRIVATE ${app_sources})
|
9
tests/subsys/storage/flash_mpa/prj.conf
Normal file
9
tests/subsys/storage/flash_mpa/prj.conf
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
CONFIG_ZTEST=y
|
||||||
|
CONFIG_STDOUT_CONSOLE=y
|
||||||
|
CONFIG_FLASH=y
|
||||||
|
CONFIG_SOC_FLASH_NRF5=y
|
||||||
|
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||||
|
CONFIG_FLASH_MAP=y
|
||||||
|
CONFIG_ARM_CORE_MPU=n
|
||||||
|
CONFIG_ARM_MPU=n
|
||||||
|
CONFIG_ARM_MPU_NRF52X=n
|
103
tests/subsys/storage/flash_mpa/src/main.c
Normal file
103
tests/subsys/storage/flash_mpa/src/main.c
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Nordic Semiconductor ASA
|
||||||
|
* Copyright (c) 2015 Runtime Inc
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <flash.h>
|
||||||
|
#include <flash_map.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define FLASH_AREA_BOOTLOADER 0
|
||||||
|
#define FLASH_AREA_IMAGE_0 1
|
||||||
|
#define FLASH_AREA_IMAGE_1 2
|
||||||
|
#define FLASH_AREA_IMAGE_SCRATCH 3
|
||||||
|
|
||||||
|
extern int flash_map_entries;
|
||||||
|
struct flash_sector fs_sectors[256];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test flash_area_to_sectors()
|
||||||
|
*/
|
||||||
|
void flash_map_test_case_2(void)
|
||||||
|
{
|
||||||
|
const struct flash_area *fa;
|
||||||
|
int sec_cnt;
|
||||||
|
int i;
|
||||||
|
int rc;
|
||||||
|
off_t off;
|
||||||
|
u8_t wd[256];
|
||||||
|
u8_t rd[256];
|
||||||
|
struct device *flash_dev;
|
||||||
|
|
||||||
|
rc = flash_area_open(FLASH_AREA_IMAGE_1, &fa);
|
||||||
|
zassert_true(rc == 0, "flash_area_open() fail");
|
||||||
|
|
||||||
|
/* First erase the area so it's ready for use. */
|
||||||
|
flash_dev = device_get_binding(CONFIG_SOC_FLASH_NRF5_DEV_NAME);
|
||||||
|
rc = flash_erase(flash_dev, fa->fa_off, fa->fa_size);
|
||||||
|
zassert_true(rc == 0, "flash area erase fail");
|
||||||
|
|
||||||
|
memset(wd, 0xa5, sizeof(wd));
|
||||||
|
|
||||||
|
rc = flash_area_get_sectors(FLASH_AREA_IMAGE_1, &sec_cnt, fs_sectors);
|
||||||
|
zassert_true(rc == 0, "flash_area_get_sectors failed");
|
||||||
|
|
||||||
|
/* write stuff to beginning of every sector */
|
||||||
|
off = 0;
|
||||||
|
for (i = 0; i < sec_cnt; i++) {
|
||||||
|
rc = flash_area_write(fa, off, wd, sizeof(wd));
|
||||||
|
zassert_true(rc == 0, "flash_area_write() fail");
|
||||||
|
|
||||||
|
/* read it back via hal_flash_Read() */
|
||||||
|
rc = flash_read(flash_dev, fa->fa_off + off, rd, sizeof(rd));
|
||||||
|
zassert_true(rc == 0, "hal_flash_read() fail");
|
||||||
|
|
||||||
|
rc = memcmp(wd, rd, sizeof(wd));
|
||||||
|
zassert_true(rc == 0, "read data != write data");
|
||||||
|
|
||||||
|
(void) flash_write_protection_set(flash_dev, false);
|
||||||
|
/* write stuff to end of area */
|
||||||
|
rc = flash_write(flash_dev, fa->fa_off + off +
|
||||||
|
fs_sectors[i].fs_size - sizeof(wd),
|
||||||
|
wd, sizeof(wd));
|
||||||
|
zassert_true(rc == 0, "hal_flash_write() fail");
|
||||||
|
|
||||||
|
/* and read it back */
|
||||||
|
memset(rd, 0, sizeof(rd));
|
||||||
|
rc = flash_area_read(fa, off + fs_sectors[i].fs_size -
|
||||||
|
sizeof(rd),
|
||||||
|
rd, sizeof(rd));
|
||||||
|
zassert_true(rc == 0, "hal_flash_read() fail");
|
||||||
|
|
||||||
|
rc = memcmp(wd, rd, sizeof(rd));
|
||||||
|
zassert_true(rc == 0, "read data != write data");
|
||||||
|
|
||||||
|
off += fs_sectors[i].fs_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* erase it */
|
||||||
|
rc = flash_area_erase(fa, 0, fa->fa_size);
|
||||||
|
zassert_true(rc == 0, "read data != write data");
|
||||||
|
|
||||||
|
/* should read back ff all throughout*/
|
||||||
|
memset(wd, 0xff, sizeof(wd));
|
||||||
|
for (off = 0; off < fa->fa_size; off += sizeof(rd)) {
|
||||||
|
rc = flash_area_read(fa, off, rd, sizeof(rd));
|
||||||
|
zassert_true(rc == 0, "hal_flash_read() fail");
|
||||||
|
|
||||||
|
rc = memcmp(wd, rd, sizeof(rd));
|
||||||
|
zassert_true(rc == 0, "area not erased");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_main(void *p1, void *p2, void *p3)
|
||||||
|
{
|
||||||
|
ztest_test_suite(test_flash_map,
|
||||||
|
ztest_unit_test(flash_map_test_case_2));
|
||||||
|
ztest_run_test_suite(test_flash_map);
|
||||||
|
}
|
5
tests/subsys/storage/flash_mpa/testcase.yaml
Normal file
5
tests/subsys/storage/flash_mpa/testcase.yaml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
tests:
|
||||||
|
test:
|
||||||
|
build_only: true
|
||||||
|
platform_whitelist: nrf52840_pca10056, nrf52_pca10040, nrf51_pca10028
|
||||||
|
tags: flash_map
|
Loading…
Add table
Add a link
Reference in a new issue