1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
19443: drivers: add support for MTDs emulated in RAM r=dylad a=gschorcht

### Contribution description

This PR adds a driver to provide MTDs that are emulated in RAM. It allows to test MTD-based applications on boards that do not provide MTDs by hardware.

It includes also some small documentation fixes for `mtd.h` that were found while writing the driver.

### Testing procedure

The following tests should work on any board:

`tests/pkg_littlefs`
`tests/pkg_littlefs2`
`tests/pkg_spiffs`

### Issues/PRs references


Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
bors[bot] 2023-04-12 09:57:18 +00:00 committed by GitHub
commit b342cdc4d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 397 additions and 354 deletions

View File

@ -33,7 +33,7 @@
* * A **sector** is the device's erase unit. Calls to @ref mtd_erase need to
* work in alignment with this number (commonly somewhere around 1kiB).
*
* (Note that this corresponse to the term "page" as used in the flashpage
* (Note that this corresponds to the term "page" as used in the flashpage
* API, and the term "eraseblock" in Linux's MTD).
*
* * A **page** is the largest a device can write in one transfer.
@ -108,7 +108,7 @@ typedef struct mtd_desc mtd_desc_t;
typedef struct {
const mtd_desc_t *driver; /**< MTD driver */
uint32_t sector_count; /**< Number of sector in the MTD */
uint32_t pages_per_sector; /**< Number of pages by sector in the MTD */
uint32_t pages_per_sector; /**< Number of pages per sector in the MTD */
uint32_t page_size; /**< Size of the pages in the MTD */
uint32_t write_size; /**< Minimum size and alignment of writes to the device */
#if defined(MODULE_MTD_WRITE_PAGE) || DOXYGEN
@ -324,8 +324,8 @@ int mtd_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count);
* @param[in] offset offset from the start of the page (in bytes)
* @param[in] size the number of bytes to read
*
* @return 0 on success
* @return < 0 if an error occurred
* @return number of bytes read on success
* @return < 0 value on error
* @return -ENODEV if @p mtd is not a valid device
* @return -ENOTSUP if operation is not supported on @p mtd
* @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory
@ -373,8 +373,8 @@ int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count);
* @param[in] offset byte offset from the start of the page
* @param[in] size the number of bytes to write
*
* @return 0 on success
* @return < 0 if an error occurred
* @return number of bytes written on success
* @return < 0 value on error
* @return -ENODEV if @p mtd is not a valid device
* @return -ENOTSUP if operation is not supported on @p mtd
* @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory,
@ -403,8 +403,8 @@ int mtd_write_page_raw(mtd_dev_t *mtd, const void *src, uint32_t page,
* @param[in] offset byte offset from the start of the page
* @param[in] size the number of bytes to write
*
* @return 0 on success
* @return < 0 if an error occurred
* @return number of bytes written on success
* @return < 0 value on error
* @return -ENODEV if @p mtd is not a valid device
* @return -ENOTSUP if operation is not supported on @p mtd
* @return -EOVERFLOW if @p addr or @p count are not valid, i.e. outside memory,

View File

@ -18,27 +18,51 @@
#define MTD_DEFAULT_H
#include "board.h"
#include "modules.h"
#include "mtd.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MODULE_MTD_SDCARD_DEFAULT)
#include "mtd_sdcard.h"
#endif
#if defined(MODULE_MTD_EMULATED)
#include "mtd_emulated.h"
#endif
#if !defined(MTD_NUMOF) && !DOXYGEN
#if defined(MTD_3)
#define MTD_BOARD_NUMOF 4
#elif defined(MTD_2)
#define MTD_BOARD_NUMOF 3
#elif defined(MTD_1)
#define MTD_BOARD_NUMOF 2
#elif defined(MTD_0)
#define MTD_BOARD_NUMOF 1
#else
#define MTD_BOARD_NUMOF 0
#endif
#define MTD_SDCARD_NUMOF IS_USED(MODULE_MTD_SDCARD_DEFAULT)
#define MTD_EMULATED_NUMOF IS_USED(MODULE_MTD_EMULATED)
/**
* @brief Number of MTD devices
*/
#ifndef MTD_NUMOF
#if defined(MTD_3)
#define MTD_NUMOF 4
#elif defined(MTD_2)
#define MTD_NUMOF 3
#elif defined(MTD_1)
#define MTD_NUMOF 2
#elif defined(MTD_0)
#define MTD_NUMOF 1
#else
#define MTD_NUMOF 0
#define MTD_NUMOF (MTD_BOARD_NUMOF + MTD_SDCARD_NUMOF + MTD_EMULATED_NUMOF)
#endif /* !defined(MTD_NUMOF) && !DOXYGEN */
#if defined(MODULE_MTD_SDCARD_DEFAULT)
extern mtd_sdcard_t mtd_sdcard_dev0;
#endif
#if defined(MODULE_MTD_EMULATED)
extern mtd_emulated_t mtd_emulated_dev0;
#endif
/**
@ -52,20 +76,25 @@ extern "C" {
static inline mtd_dev_t *mtd_default_get_dev(unsigned idx)
{
switch (idx) {
#ifdef MTD_0
#if MTD_BOARD_NUMOF > 0
case 0: return MTD_0;
#endif
#ifdef MTD_1
#if MTD_BOARD_NUMOF > 1
case 1: return MTD_1;
#endif
#ifdef MTD_2
#if MTD_BOARD_NUMOF > 2
case 2: return MTD_2;
#endif
#ifdef MTD_3
#if MTD_BOARD_NUMOF > 3
case 3: return MTD_3;
#endif
#if MTD_SDCARD_NUMOF > 0
case MTD_BOARD_NUMOF: return (mtd_dev_t *)&mtd_sdcard_dev0;
#endif
#if MTD_EMULATED_NUMOF > 0
case MTD_BOARD_NUMOF + MTD_SDCARD_NUMOF: return (mtd_dev_t *)&mtd_emulated_dev0;
#endif
}
return NULL;
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_mtd
* @{
* @brief MTD device that is emulated in RAM for test purposes
*
* Helpers for using emulated MTDs.
*
* @author Gunar Schorcht <gunar@schorcht.net>
*/
#ifndef MTD_EMULATED_H
#define MTD_EMULATED_H
#include <stdbool.h>
#include "board.h"
#include "macros/utils.h"
#include "mtd.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Macro to define an emulated MTD
*
* This macro creates a MTD device that is emulated in RAM. For example, using
* ```
* MTD_EMULATED_DEV(0, 16, 4, 64)
* ```
* creates the emulated MTD device `mtd_emulated_dev0` with 16 sectors, 4 pages
* per sector and a page size of 64 bytes. The write size is always 1 byte.
*
* @param n index of the emulated MTD (results into symbol `mtd_emulated_devn`)
* @param sc sectors of the emulated MTD
* @param pps pages per sector of the emulated MTD
* @param ps page size in bytes
*/
#define MTD_EMULATED_DEV(n, sc, pps, ps) \
uint8_t _mtd_emulated_memory ## n[sc * pps * ps]; \
\
mtd_emulated_t mtd_emulated_dev ## n = { \
.base = { \
.driver = &_mtd_emulated_driver, \
.sector_count = sc, \
.pages_per_sector = pps, \
.page_size = ps, \
.write_size = 1, \
}, \
.size = sc * pps * ps, \
.memory = _mtd_emulated_memory ## n, \
.init_done = false, \
} \
#if MODULE_VFS_AUTO_MOUNT || DOXYGEN
/**
* @brief Macro to define an automatic VFS mount point for an emulated MTD.
*
* For example, using
* ```
* MTD_EMULATED_DEV_FS(0, 2, fatfs);
* ```
* automatically mounts the emulated MTD `mtd_emulated_dev0` with FAT file
* system under mount point `/mtde0` with unique index 2.
*
* @param n index of the emulated MTD (symbol `mtd_emulated_devn`, mount point `/mtde0`)
* @param m unique overall index of VFS mount point
* @param fs filesystem type used
*/
#define MTD_EMULATED_DEV_FS(n, m, fs) \
VFS_AUTO_MOUNT(fs, VFS_MTD(mtd_emulated_dev ## n), "/mtde" # n, m)
#endif /* MODULE_VFS || DOXYGEN */
/**
* @brief Device descriptor for a MTD device that is emulated in RAM
*/
typedef struct {
mtd_dev_t base; /**< inherit from mtd_dev_t object */
size_t size; /**< total size of the MTD device in bytes */
uint8_t *memory; /**< RAM that is used for the emulated MTD device */
bool init_done; /**< indicates whether initialization is already done */
} mtd_emulated_t;
/**
* @brief Emulated MTD device operations table for mtd
*/
extern const mtd_desc_t _mtd_emulated_driver;
#ifdef __cplusplus
}
#endif
#endif /* MTD_EMULATED_H */
/** @} */

View File

@ -105,6 +105,9 @@ config MODULE_MTD_SDCARD
bool "MTD interface for SPI SD-Card"
depends on MODULE_SDCARD_SPI
config MODULE_MTD_EMULATED
bool "MTD interface for MTD emulated in RAM"
config MODULE_SAM0_SDHC
bool "MTD interface for SAM0 SD Host Controller"
depends on CPU_COMMON_SAM0

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <errno.h>
#include <string.h>
#include "assert.h"
#include "macros/utils.h"
#include "mtd_emulated.h"
static int _init(mtd_dev_t *dev)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
assert(mtd);
if (!mtd->init_done) {
memset(mtd->memory, 0xff, mtd->size);
mtd->init_done = true;
}
return 0;
}
static int _read(mtd_dev_t *dev, void *dest, uint32_t addr, uint32_t count)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
assert(mtd);
assert(dest);
if ((addr + count) > mtd->size) {
/* addr + count must not exceed the size of memory */
return -EOVERFLOW;
}
memcpy(dest, mtd->memory + addr, count);
return 0;
}
static int _read_page(mtd_dev_t *dev, void *dest,
uint32_t page, uint32_t offset, uint32_t size)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
(void)mtd;
assert(mtd);
assert(dest);
if (((page * mtd->base.page_size) + offset + size) > mtd->size) {
/* page addr + offset + size must not exceed the size of memory */
return -EOVERFLOW;
}
memcpy(dest, mtd->memory + (page * mtd->base.page_size) + offset, size);
return size;
}
static int _write(mtd_dev_t *dev, const void *src, uint32_t addr, uint32_t count)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
(void)mtd;
assert(mtd);
assert(src);
if (/* addr + count must be inside a page boundary. */
(((addr % mtd->base.page_size) + count) > mtd->base.page_size) ||
/* addr + count must not exceed the size of memory */
((addr + count) > mtd->size)) {
return -EOVERFLOW;
}
memcpy(mtd->memory + addr, src, count);
return 0;
}
int _write_page(mtd_dev_t *dev, const void *src,
uint32_t page, uint32_t offset, uint32_t size)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
(void)mtd;
assert(mtd);
assert(src);
if (/* offset must be smaller than the page size */
(offset >= mtd->base.page_size) ||
/* page addr + offset + size must not exceed the size of memory */
((page * mtd->base.page_size) + offset + size) > mtd->size) {
return -EOVERFLOW;
}
memcpy(mtd->memory + (page * mtd->base.page_size) + offset, src, size);
return size;
}
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t count)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
(void)mtd;
assert(mtd);
if (/* addr must be aligned on a sector boundary */
(addr % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) ||
/* count must be a multiple of a sector size. */
(count % (mtd->base.pages_per_sector * mtd->base.page_size) != 0) ||
/* addr + count must not exceed the size of memory */
((addr + count) > mtd->size)) {
return -EOVERFLOW;
}
memset(mtd->memory + addr, 0xff, count);
return 0;
}
static int _erase_sector(mtd_dev_t *dev, uint32_t sector, uint32_t num)
{
mtd_emulated_t *mtd = (mtd_emulated_t *)dev;
(void)mtd;
assert(mtd);
if (/* sector must not exceed the number of sectors */
(sector >= mtd->base.sector_count) ||
/* sector + num must not exceed the number of sectors */
((sector + num) > mtd->base.sector_count)) {
return -EOVERFLOW;
}
memset(mtd->memory + (sector * (mtd->base.pages_per_sector * mtd->base.page_size)),
0xff, num * (mtd->base.pages_per_sector * mtd->base.page_size));
return 0;
}
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
{
(void)dev;
(void)power;
return 0;
}
const mtd_desc_t _mtd_emulated_driver = {
.init = _init,
.read = _read,
.read_page = _read_page,
.write = _write,
.write_page = _write_page,
.erase = _erase,
.erase_sector = _erase_sector,
.power = _power,
};

View File

@ -2,5 +2,6 @@ include ../Makefile.tests_common
USEMODULE += littlefs
USEMODULE += embunit
USEMODULE += mtd_emulated
include $(RIOTBASE)/Makefile.include

View File

@ -5,18 +5,12 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-uno \
atmega328p \
atmega328p-xplained-mini \
i-nucleo-lrwan1 \
msb-430 \
msb-430h \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32l0538-disco \
#

View File

@ -27,12 +27,16 @@
* CONFIG_USE_HARDWARE_MTD is defined (add CFLAGS=-DCONFIG_USE_HARDWARE_MTD to
* the command line to enable it */
#if defined(MTD_0) && IS_ACTIVE(CONFIG_USE_HARDWARE_MTD)
#define USE_MTD_0
#define _dev (MTD_0)
#else
#include "mtd_emulated.h"
/* Test mock object implementing a simple RAM-based mtd */
#ifndef SECTOR_COUNT
#define SECTOR_COUNT 16
#define SECTOR_COUNT 12
#endif
#ifndef PAGE_PER_SECTOR
#define PAGE_PER_SECTOR 4
@ -41,84 +45,10 @@
#define PAGE_SIZE 64
#endif
static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT];
MTD_EMULATED_DEV(0, SECTOR_COUNT, PAGE_PER_SECTOR, PAGE_SIZE);
static int _init(mtd_dev_t *dev)
{
(void)dev;
#define _dev (&mtd_emulated_dev0.base)
return 0;
}
static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memcpy(buff, dummy_memory + addr, size);
return 0;
}
static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
if (size > PAGE_SIZE) {
return -EOVERFLOW;
}
memcpy(dummy_memory + addr, buff, size);
return 0;
}
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
{
(void)dev;
if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memset(dummy_memory + addr, 0xff, size);
return 0;
}
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
{
(void)dev;
(void)power;
return 0;
}
static const mtd_desc_t driver = {
.init = _init,
.read = _read,
.write = _write,
.erase = _erase,
.power = _power,
};
static mtd_dev_t dev = {
.driver = &driver,
.sector_count = SECTOR_COUNT,
.pages_per_sector = PAGE_PER_SECTOR,
.page_size = PAGE_SIZE,
.write_size = 1,
};
static mtd_dev_t *_dev = (mtd_dev_t*) &dev;
#endif /* MTD_0 */
static littlefs_desc_t littlefs_desc;
@ -414,10 +344,6 @@ static void tests_littlefs_statvfs(void)
Test *tests_littlefs(void)
{
#ifndef USE_MTD_0
memset(dummy_memory, 0xff, sizeof(dummy_memory));
#endif
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(tests_littlefs_format),
new_TestFixture(tests_littlefs_mount_umount),

View File

@ -2,5 +2,6 @@ include ../Makefile.tests_common
USEPKG += littlefs2
USEMODULE += embunit
USEMODULE += mtd_emulated
include $(RIOTBASE)/Makefile.include

View File

@ -1,2 +1,3 @@
CONFIG_MODULE_EMBUNIT=y
CONFIG_MODULE_MTD_EMULATED=y
CONFIG_PACKAGE_LITTLEFS2=y

View File

@ -27,9 +27,13 @@
* CONFIG_USE_HARDWARE_MTD is defined (add CFLAGS=-DCONFIG_USE_HARDWARE_MTD to
* the command line to enable it */
#if defined(MTD_0) && IS_ACTIVE(CONFIG_USE_HARDWARE_MTD)
#define USE_MTD_0
#define _dev (MTD_0)
#else
#include "mtd_emulated.h"
/* Test mock object implementing a simple RAM-based mtd */
#ifndef SECTOR_COUNT
#define SECTOR_COUNT 16
@ -41,84 +45,10 @@
#define PAGE_SIZE 64
#endif
static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT];
MTD_EMULATED_DEV(0, SECTOR_COUNT, PAGE_PER_SECTOR, PAGE_SIZE);
static int _init(mtd_dev_t *dev)
{
(void)dev;
#define _dev (&mtd_emulated_dev0.base)
return 0;
}
static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memcpy(buff, dummy_memory + addr, size);
return 0;
}
static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
if (size > PAGE_SIZE) {
return -EOVERFLOW;
}
memcpy(dummy_memory + addr, buff, size);
return 0;
}
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
{
(void)dev;
if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memset(dummy_memory + addr, 0xff, size);
return 0;
}
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
{
(void)dev;
(void)power;
return 0;
}
static const mtd_desc_t driver = {
.init = _init,
.read = _read,
.write = _write,
.erase = _erase,
.power = _power,
};
static mtd_dev_t dev = {
.driver = &driver,
.sector_count = SECTOR_COUNT,
.pages_per_sector = PAGE_PER_SECTOR,
.page_size = PAGE_SIZE,
.write_size = 1,
};
static mtd_dev_t *_dev = (mtd_dev_t*) &dev;
#endif /* MTD_0 */
static littlefs2_desc_t littlefs_desc;
@ -416,10 +346,6 @@ static void tests_littlefs_statvfs(void)
Test *tests_littlefs(void)
{
#ifndef USE_MTD_0
memset(dummy_memory, 0xff, sizeof(dummy_memory));
#endif
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(tests_littlefs_format),
new_TestFixture(tests_littlefs_mount_umount),

View File

@ -2,5 +2,6 @@ include ../Makefile.tests_common
USEMODULE += spiffs
USEMODULE += embunit
USEMODULE += mtd_emulated
include $(RIOTBASE)/Makefile.include

View File

@ -25,9 +25,13 @@
* CONFIG_USE_HARDWARE_MTD is defined (add CFLAGS=-DCONFIG_USE_HARDWARE_MTD to
* the command line to enable it */
#if defined(MTD_0) && IS_ACTIVE(CONFIG_USE_HARDWARE_MTD)
#define USE_MTD_0
#define _dev (MTD_0)
#else
#include "mtd_emulated.h"
/* Test mock object implementing a simple RAM-based mtd */
#ifndef SECTOR_COUNT
#define SECTOR_COUNT 4
@ -39,83 +43,10 @@
#define PAGE_SIZE 128
#endif
static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT];
MTD_EMULATED_DEV(0, SECTOR_COUNT, PAGE_PER_SECTOR, PAGE_SIZE);
static int _init(mtd_dev_t *dev)
{
(void)dev;
return 0;
}
#define _dev (&mtd_emulated_dev0.base)
static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memcpy(buff, dummy_memory + addr, size);
return 0;
}
static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
if (size > PAGE_SIZE) {
return -EOVERFLOW;
}
memcpy(dummy_memory + addr, buff, size);
return 0;
}
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
{
(void)dev;
if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memset(dummy_memory + addr, 0xff, size);
return 0;
}
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
{
(void)dev;
(void)power;
return 0;
}
static const mtd_desc_t driver = {
.init = _init,
.read = _read,
.write = _write,
.erase = _erase,
.power = _power,
};
static mtd_dev_t dev = {
.driver = &driver,
.sector_count = SECTOR_COUNT,
.pages_per_sector = PAGE_PER_SECTOR,
.page_size = PAGE_SIZE,
.write_size = 1,
};
static mtd_dev_t *_dev = (mtd_dev_t*) &dev;
#endif /* MTD_0 */
static struct spiffs_desc spiffs_desc = {
@ -439,9 +370,6 @@ static void tests_spiffs_partition(void)
Test *tests_spiffs(void)
{
#ifndef USE_MTD_0
memset(dummy_memory, 0xff, sizeof(dummy_memory));
#endif
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(tests_spiffs_format),
new_TestFixture(tests_spiffs_mount_umount),

View File

@ -1,2 +1,3 @@
USEMODULE += mtd
USEMODULE += mtd_emulated
USEMODULE += vfs

View File

@ -29,6 +29,9 @@
#ifdef MTD_0
#define dev (MTD_0)
#else
#include "mtd_emulated.h"
/* Test mock object implementing a simple RAM-based mtd */
#ifndef SECTOR_COUNT
#define SECTOR_COUNT 4
@ -39,89 +42,10 @@
#ifndef PAGE_SIZE
#define PAGE_SIZE 128
#endif
#ifndef WRITE_SIZE
#define WRITE_SIZE 1
#endif
static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT];
MTD_EMULATED_DEV(0, SECTOR_COUNT, PAGE_PER_SECTOR, PAGE_SIZE);
static int _init(mtd_dev_t *dev)
{
(void)dev;
memset(dummy_memory, 0xff, sizeof(dummy_memory));
return 0;
}
static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memcpy(buff, dummy_memory + addr, size);
return 0;
}
static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size)
{
(void)dev;
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
if (((addr % PAGE_SIZE) + size) > PAGE_SIZE) {
return -EOVERFLOW;
}
memcpy(dummy_memory + addr, buff, size);
return 0;
}
static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size)
{
(void)dev;
if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) {
return -EOVERFLOW;
}
if (addr + size > sizeof(dummy_memory)) {
return -EOVERFLOW;
}
memset(dummy_memory + addr, 0xff, size);
return 0;
}
static int _power(mtd_dev_t *dev, enum mtd_power_state power)
{
(void)dev;
(void)power;
return 0;
}
static const mtd_desc_t driver = {
.init = _init,
.read = _read,
.write = _write,
.erase = _erase,
.power = _power,
};
static mtd_dev_t _dev = {
.driver = &driver,
.sector_count = SECTOR_COUNT,
.pages_per_sector = PAGE_PER_SECTOR,
.page_size = PAGE_SIZE,
.write_size = WRITE_SIZE,
};
static mtd_dev_t *dev = (mtd_dev_t*) &_dev;
#define dev (&mtd_emulated_dev0.base)
#endif /* MTD_0 */

View File

@ -5,7 +5,7 @@ include ../Makefile.tests_common
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
# Comment this out to disable code in RIOT that does safety checking
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
@ -19,6 +19,11 @@ USEMODULE += shell
USEMODULE += usbus_msc
USEMODULE += ztimer_msec
# If your board does not provide a MTD for testing, use the following line
# to emulate an MTD with 64 sectors with 4 pages of 128 bytes each in RAM. You
# can override these parameters by SECTOR_COUNT, PAGES_PER_SECTOR and PAGE_SIZE.
# USEMODULE += mtd_emulated
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1

View File

@ -39,6 +39,19 @@ by attaching it to the host with the command:
At this point, the USBUS stack will export the selected MTD devices.
Devices should appears under /dev/sdX entries.
If the board does not provide a MTD device, a MTD device can be emulated in RAM
for testing using module `mtd_emulated`:
```
USEMODULE=mtd_emulated BOARD=... make ...
```
The emulated MTD device has by default 64 sectors with 4 pages of 128 bytes
each, the minimum size to be able to create a partition with FAT file system.
These default parameters can be overridden e.g. by `SECTOR_COUNT`,
`PAGES_PER_SECTOR` and `PAGE_SIZE`:
```
CFLAGS='-DSECTOR_COUNT=128' USEMODULE=mtd_emulated BOARD=... make ...
```
**Notes:** Depending on the MTD device and the USB speed, this operation can take some times.
USB operation can be stopped at any time using:

View File

@ -22,6 +22,32 @@
#include <stdio.h>
#include <string.h>
#include "board.h"
#if defined(MODULE_MTD_EMULATED)
#include "mtd_emulated.h"
/* The following parameters are only suitable for testing the basic functions
* of USB MSC. To create a partition with a FAT file system, at least 64 sectors
* have to be used. */
#ifndef SECTOR_COUNT
#define SECTOR_COUNT 64
#endif
#ifndef PAGES_PER_SECTOR
#define PAGES_PER_SECTOR 4
#endif
#ifndef PAGE_SIZE
#define PAGE_SIZE 128
#endif
MTD_EMULATED_DEV(0, SECTOR_COUNT, PAGES_PER_SECTOR, PAGE_SIZE);
#endif /* MODULE_MTD_EMULATED */
#include "mtd_default.h"
#include "shell.h"
#include "usb/usbus.h"