Merge pull request #15843 from benpicco/mtd_write_page_hl
mtd: rename mtd_write_page() -> mtd_write_page_raw(), add high-level mtd_write_page()
This commit is contained in:
commit
1f085cfd03
@ -9,6 +9,7 @@ endif
|
||||
ifneq (,$(filter mtd,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_spi_on_qspi
|
||||
USEMODULE += mtd_spi_nor
|
||||
USEMODULE += mtd_at24cxxx at24mac
|
||||
endif
|
||||
|
||||
# enables sam0_eth as default network device
|
||||
|
||||
@ -49,8 +49,19 @@ static mtd_spi_nor_t same54_nor_dev = {
|
||||
},
|
||||
.params = &_same54_nor_params,
|
||||
};
|
||||
|
||||
mtd_dev_t *mtd0 = (mtd_dev_t *)&same54_nor_dev;
|
||||
|
||||
#include "mtd_at24cxxx.h"
|
||||
#include "at24cxxx_params.h"
|
||||
static at24cxxx_t at24cxxx_dev;
|
||||
static mtd_at24cxxx_t at24mac_dev = {
|
||||
.base = {
|
||||
.driver = &mtd_at24cxxx_driver,
|
||||
},
|
||||
.at24cxxx_eeprom = &at24cxxx_dev,
|
||||
.params = at24cxxx_params,
|
||||
};
|
||||
mtd_dev_t *mtd1 = (mtd_dev_t *)&at24mac_dev;
|
||||
#endif /* MODULE_MTD */
|
||||
|
||||
void board_init(void)
|
||||
|
||||
@ -34,6 +34,7 @@ extern "C" {
|
||||
#define AT24MAC_PARAM_I2C_DEV I2C_DEV(1)
|
||||
#define AT24MAC_PARAM_I2C_ADDR (0x5E)
|
||||
#define AT24MAC_PARAM_TYPE AT24MAC4XX
|
||||
#define AT24CXXX_PARAM_I2C I2C_DEV(1)
|
||||
#define AT24CXXX_PARAM_ADDR (0x56)
|
||||
/** @} */
|
||||
|
||||
@ -71,8 +72,10 @@ extern "C" {
|
||||
* @name MTD configuration
|
||||
* @{
|
||||
*/
|
||||
extern mtd_dev_t *mtd0;
|
||||
#define MTD_0 mtd0
|
||||
extern mtd_dev_t *mtd0, *mtd1;
|
||||
#define MTD_0 mtd0
|
||||
#define MTD_1 mtd1
|
||||
#define MTD_NUMOF 2
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@ -80,5 +80,6 @@ const mtd_desc_t mtd_at24cxxx_driver = {
|
||||
.write = _mtd_at24cxxx_write,
|
||||
.write_page = mtd_at24cxxx_write_page,
|
||||
.erase = _mtd_at24cxxx_erase,
|
||||
.power = _mtd_at24cxxx_power
|
||||
.power = _mtd_at24cxxx_power,
|
||||
.flags = MTD_DRIVER_FLAG_DIRECT_WRITE,
|
||||
};
|
||||
|
||||
@ -90,4 +90,5 @@ const mtd_desc_t mtd_at25xxx_driver = {
|
||||
.write_page = mtd_at25xxx_write_page,
|
||||
.erase = mtd_at25xxx_erase,
|
||||
.power = mtd_at25xxx_power,
|
||||
.flags = MTD_DRIVER_FLAG_DIRECT_WRITE,
|
||||
};
|
||||
|
||||
@ -60,8 +60,16 @@ typedef struct {
|
||||
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 page_size; /**< Size of the pages in the MTD */
|
||||
#if defined(MODULE_MTD_WRITE_PAGE) || DOXYGEN
|
||||
void *work_area; /**< sector-sized buffer */
|
||||
#endif
|
||||
} mtd_dev_t;
|
||||
|
||||
/**
|
||||
* @brief MTD driver can write any data to the storage without erasing it first.
|
||||
*/
|
||||
#define MTD_DRIVER_FLAG_DIRECT_WRITE (1 << 0)
|
||||
|
||||
/**
|
||||
* @brief MTD driver interface
|
||||
*
|
||||
@ -203,6 +211,11 @@ struct mtd_desc {
|
||||
* @return < 0 value on error
|
||||
*/
|
||||
int (*power)(mtd_dev_t *dev, enum mtd_power_state power);
|
||||
|
||||
/**
|
||||
* @brief Properties of the MTD driver
|
||||
*/
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -285,8 +298,9 @@ int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count);
|
||||
* The MTD layer will take care of splitting up the transaction into multiple
|
||||
* writes if it is required by the underlying storage media.
|
||||
*
|
||||
* @p offset must be smaller than the page size
|
||||
* This performs a raw write, no automatic read-modify-write cycle is performed.
|
||||
*
|
||||
* @p offset must be smaller than the page size
|
||||
*
|
||||
* @param mtd the device to write to
|
||||
* @param[in] src the buffer to write
|
||||
@ -302,7 +316,38 @@ int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count);
|
||||
* @return -EIO if I/O error occurred
|
||||
* @return -EINVAL if parameters are invalid
|
||||
*/
|
||||
int mtd_write_page(mtd_dev_t *mtd, const void *src, uint32_t page, uint32_t offset, uint32_t size);
|
||||
int mtd_write_page_raw(mtd_dev_t *mtd, const void *src, uint32_t page,
|
||||
uint32_t offset, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Write data to a MTD device with pagewise addressing
|
||||
*
|
||||
* The MTD layer will take care of splitting up the transaction into multiple
|
||||
* writes if it is required by the underlying storage media.
|
||||
*
|
||||
* If the underlying sector needs to be erased before it can be written, the MTD
|
||||
* layer will take care of the read-modify-write operation.
|
||||
*
|
||||
* @p offset must be smaller than the page size
|
||||
*
|
||||
* @note this requires the `mtd_write_page` module
|
||||
*
|
||||
* @param mtd the device to write to
|
||||
* @param[in] src the buffer to write
|
||||
* @param[in] page Page number to start writing to
|
||||
* @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 -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,
|
||||
* @return -EIO if I/O error occurred
|
||||
* @return -EINVAL if parameters are invalid
|
||||
*/
|
||||
int mtd_write_page(mtd_dev_t *mtd, const void *src, uint32_t page,
|
||||
uint32_t offset, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Erase sectors of a MTD device
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bitarithm.h"
|
||||
#include "mtd.h"
|
||||
@ -32,12 +34,22 @@ int mtd_init(mtd_dev_t *mtd)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int res = -ENOTSUP;
|
||||
|
||||
if (mtd->driver->init) {
|
||||
return mtd->driver->init(mtd);
|
||||
res = mtd->driver->init(mtd);
|
||||
}
|
||||
else {
|
||||
return -ENOTSUP;
|
||||
|
||||
#ifdef MODULE_MTD_WRITE_PAGE
|
||||
if ((mtd->driver->flags & MTD_DRIVER_FLAG_DIRECT_WRITE) == 0) {
|
||||
mtd->work_area = malloc(mtd->pages_per_sector * mtd->page_size);
|
||||
if (mtd->work_area == NULL) {
|
||||
res = -ENOMEM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int mtd_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t count)
|
||||
@ -122,11 +134,49 @@ int mtd_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t count)
|
||||
const uint32_t page_shift = bitarithm_msb(mtd->page_size);
|
||||
const uint32_t page_mask = mtd->page_size - 1;
|
||||
|
||||
return mtd_write_page(mtd, src, addr >> page_shift, addr & page_mask, count);
|
||||
return mtd_write_page_raw(mtd, src, addr >> page_shift, addr & page_mask, count);
|
||||
}
|
||||
|
||||
int mtd_write_page(mtd_dev_t *mtd, const void *src, uint32_t page, uint32_t offset,
|
||||
uint32_t count)
|
||||
#ifdef MODULE_MTD_WRITE_PAGE
|
||||
int mtd_write_page(mtd_dev_t *mtd, const void *data, uint32_t page,
|
||||
uint32_t offset, uint32_t len)
|
||||
{
|
||||
if (!mtd || !mtd->driver) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (mtd->work_area == NULL) {
|
||||
return mtd_write_page_raw(mtd, data, page, offset, len);
|
||||
}
|
||||
|
||||
int res;
|
||||
uint8_t *work = mtd->work_area;
|
||||
const uint32_t sector = page / mtd->pages_per_sector;
|
||||
const uint32_t sector_page = sector * mtd->pages_per_sector;
|
||||
const uint32_t sector_size = mtd->pages_per_sector * mtd->page_size;
|
||||
|
||||
/* copy sector to RAM */
|
||||
res = mtd_read_page(mtd, work, sector_page, 0, sector_size);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* erase sector */
|
||||
res = mtd_erase_sector(mtd, sector, 1);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/* modify sector in RAM */
|
||||
memcpy(work + (page - sector_page) * mtd->page_size + offset, data, len);
|
||||
|
||||
/* write back modified sector copy */
|
||||
return mtd_write_page_raw(mtd, work, sector_page, 0, sector_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
int mtd_write_page_raw(mtd_dev_t *mtd, const void *src, uint32_t page, uint32_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
if (!mtd || !mtd->driver) {
|
||||
return -ENODEV;
|
||||
|
||||
@ -112,9 +112,9 @@ static int _write_page(mtd_dev_t *mtd, const void *src, uint32_t page,
|
||||
mtd_mapper_region_t *region = container_of(mtd, mtd_mapper_region_t, mtd);
|
||||
|
||||
_lock(region);
|
||||
int res = mtd_write_page(region->parent->mtd, src,
|
||||
page + _page_offset(region),
|
||||
offset, count);
|
||||
int res = mtd_write_page_raw(region->parent->mtd, src,
|
||||
page + _page_offset(region),
|
||||
offset, count);
|
||||
_unlock(region);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -143,4 +143,5 @@ const mtd_desc_t mtd_mci_driver = {
|
||||
.write_page = mtd_mci_write_page,
|
||||
.erase_sector = mtd_mci_erase_sector,
|
||||
.power = mtd_mci_power,
|
||||
.flags = MTD_DRIVER_FLAG_DIRECT_WRITE,
|
||||
};
|
||||
|
||||
@ -158,4 +158,5 @@ const mtd_desc_t mtd_sdcard_driver = {
|
||||
.write_page = mtd_sdcard_write_page,
|
||||
.erase = mtd_sdcard_erase,
|
||||
.power = mtd_sdcard_power,
|
||||
.flags = MTD_DRIVER_FLAG_DIRECT_WRITE,
|
||||
};
|
||||
|
||||
@ -81,6 +81,7 @@ PSEUDOMODULES += log_color
|
||||
PSEUDOMODULES += lora
|
||||
PSEUDOMODULES += mpu_stack_guard
|
||||
PSEUDOMODULES += mpu_noexec_ram
|
||||
PSEUDOMODULES += mtd_write_page
|
||||
PSEUDOMODULES += nanocoap_%
|
||||
PSEUDOMODULES += netdev_default
|
||||
PSEUDOMODULES += netdev_ieee802154_%
|
||||
|
||||
@ -135,8 +135,8 @@ DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
|
||||
uint32_t sector_size = fatfs_mtd_devs[pdrv]->page_size
|
||||
* fatfs_mtd_devs[pdrv]->pages_per_sector;
|
||||
|
||||
res = mtd_write_page(fatfs_mtd_devs[pdrv], buff,
|
||||
sector, 0, count * sector_size);
|
||||
res = mtd_write_page_raw(fatfs_mtd_devs[pdrv], buff,
|
||||
sector, 0, count * sector_size);
|
||||
|
||||
if (res != 0) {
|
||||
return RES_ERROR;
|
||||
|
||||
@ -85,8 +85,8 @@ static int _dev_write(const struct lfs_config *c, lfs_block_t block,
|
||||
DEBUG("lfs_write: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n",
|
||||
(void *)c, block, off, buffer, size);
|
||||
|
||||
return mtd_write_page(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector,
|
||||
off, size);
|
||||
return mtd_write_page_raw(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector,
|
||||
off, size);
|
||||
}
|
||||
|
||||
static int _dev_erase(const struct lfs_config *c, lfs_block_t block)
|
||||
|
||||
@ -85,8 +85,8 @@ static int _dev_write(const struct lfs_config *c, lfs_block_t block,
|
||||
DEBUG("lfs_write: c=%p, block=%" PRIu32 ", off=%" PRIu32 ", buf=%p, size=%" PRIu32 "\n",
|
||||
(void *)c, block, off, buffer, size);
|
||||
|
||||
return mtd_write_page(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector,
|
||||
off, size);
|
||||
return mtd_write_page_raw(mtd, buffer, (fs->base_addr + block) * mtd->pages_per_sector,
|
||||
off, size);
|
||||
}
|
||||
|
||||
static int _dev_erase(const struct lfs_config *c, lfs_block_t block)
|
||||
|
||||
@ -5,5 +5,6 @@ USEMODULE += shell_commands
|
||||
|
||||
USEMODULE += od
|
||||
USEMODULE += mtd
|
||||
USEMODULE += mtd_write_page
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
|
||||
@ -173,13 +173,36 @@ static int cmd_write(int argc, char **argv)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cmd_write_page_raw(int argc, char **argv)
|
||||
{
|
||||
mtd_dev_t *dev = _get_dev(argc, argv);
|
||||
uint32_t page, offset, len;
|
||||
|
||||
if (argc < 5 || dev == NULL) {
|
||||
printf("usage: %s <dev> <page> <offset> <data>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
page = atoi(argv[2]);
|
||||
offset = atoi(argv[3]);
|
||||
len = strlen(argv[4]);
|
||||
|
||||
int res = mtd_write_page_raw(dev, argv[4], page, offset, len);
|
||||
|
||||
if (res) {
|
||||
printf("error: %i\n", res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cmd_write_page(int argc, char **argv)
|
||||
{
|
||||
mtd_dev_t *dev = _get_dev(argc, argv);
|
||||
uint32_t page, offset, len;
|
||||
|
||||
if (argc < 5 || dev == NULL) {
|
||||
printf("usage: %s <dev> <page> <offset> <len>\n", argv[0]);
|
||||
printf("usage: %s <dev> <page> <offset> <data>\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -268,7 +291,7 @@ static void _print_size(uint64_t size)
|
||||
unit = "byte";
|
||||
}
|
||||
|
||||
printf("total: %lu %s\n", len, unit);
|
||||
printf("%lu %s", len, unit);
|
||||
}
|
||||
|
||||
static void _print_info(mtd_dev_t *dev)
|
||||
@ -276,7 +299,9 @@ static void _print_info(mtd_dev_t *dev)
|
||||
printf("sectors: %"PRIu32"\n", dev->sector_count);
|
||||
printf("pages per sector: %"PRIu32"\n", dev->pages_per_sector);
|
||||
printf("page size: %"PRIu32"\n", dev->page_size);
|
||||
printf("total: ");
|
||||
_print_size(_get_size(dev));
|
||||
puts("");
|
||||
}
|
||||
|
||||
static int cmd_info(int argc, char **argv)
|
||||
@ -376,36 +401,43 @@ static int cmd_test(int argc, char **argv)
|
||||
|
||||
/* write dummy data to sectors */
|
||||
memset(buffer, 0x23, dev->page_size);
|
||||
assert(mtd_write_page(dev, buffer, page_0, 0, page_size) == 0);
|
||||
assert(mtd_write_page(dev, buffer, page_1, 0, page_size) == 0);
|
||||
assert(mtd_write_page_raw(dev, buffer, page_0, 0, page_size) == 0);
|
||||
assert(mtd_write_page_raw(dev, buffer, page_1, 0, page_size) == 0);
|
||||
|
||||
/* erase two sectors and check if they have been erase */
|
||||
/* erase two sectors and check if they have been erased */
|
||||
assert(mtd_erase_sector(dev, sector, 2) == 0);
|
||||
assert(mtd_read_page(dev, buffer, page_0, 0, page_size) == 0);
|
||||
assert(mem_is_all_set(buffer, 0xFF, page_size));
|
||||
assert(mem_is_all_set(buffer, 0xFF, page_size) || mem_is_all_set(buffer, 0x00, page_size));
|
||||
assert(mtd_read_page(dev, buffer, page_1, 0, page_size) == 0);
|
||||
assert(mem_is_all_set(buffer, 0xFF, page_size));
|
||||
assert(mem_is_all_set(buffer, 0xFF, page_size) || mem_is_all_set(buffer, 0x00, page_size));
|
||||
|
||||
/* write test data & read it back */
|
||||
const char test_str[] = "0123456789";
|
||||
uint32_t offset = 5;
|
||||
assert(mtd_write_page(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_write_page_raw(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_read_page(dev, buffer, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(memcmp(test_str, buffer, sizeof(test_str)) == 0);
|
||||
|
||||
/* write across page boundary */
|
||||
offset = page_size - sizeof(test_str) / 2;
|
||||
assert(mtd_write_page(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_write_page_raw(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_read_page(dev, buffer, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(memcmp(test_str, buffer, sizeof(test_str)) == 0);
|
||||
|
||||
/* write across sector boundary */
|
||||
offset = page_size - sizeof(test_str) / 2
|
||||
+ (dev->pages_per_sector - 1) * page_size;
|
||||
assert(mtd_write_page(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_write_page_raw(dev, test_str, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(mtd_read_page(dev, buffer, page_0, offset, sizeof(test_str)) == 0);
|
||||
assert(memcmp(test_str, buffer, sizeof(test_str)) == 0);
|
||||
|
||||
/* overwrite first test string, rely on MTD for read-modify-write */
|
||||
const char test_str_2[] = "Hello World!";
|
||||
offset = 5;
|
||||
assert(mtd_write_page(dev, test_str_2, page_0, offset, sizeof(test_str_2)) == 0);
|
||||
assert(mtd_read_page(dev, buffer, page_0, offset, sizeof(test_str_2)) == 0);
|
||||
assert(memcmp(test_str_2, buffer, sizeof(test_str_2)) == 0);
|
||||
|
||||
puts("[SUCCESS]");
|
||||
|
||||
free(buffer);
|
||||
@ -419,7 +451,12 @@ static const shell_command_t shell_commands[] = {
|
||||
{ "read", "Read a region of memory on the MTD device", cmd_read },
|
||||
{ "read_page", "Read a region of memory on the MTD device (pagewise addressing)", cmd_read_page },
|
||||
{ "write", "Write a region of memory on the MTD device", cmd_write },
|
||||
{ "write_page", "Write a region of memory on the MTD device (pagewise addressing)", cmd_write_page },
|
||||
{ "write_page_raw",
|
||||
"Write a region of memory on the MTD device (pagewise addressing)",
|
||||
cmd_write_page_raw },
|
||||
{ "write_page",
|
||||
"Write a region of memory on the MTD device (pagewise addressing, read-modify-write)",
|
||||
cmd_write_page },
|
||||
{ "erase", "Erase a region of memory on the MTD device", cmd_erase },
|
||||
{ "erase_sector", "Erase a sector of memory on the MTD device", cmd_erase_sector },
|
||||
{ "test", "Erase & write test data to the last two sectors", cmd_test },
|
||||
@ -444,7 +481,9 @@ int main(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("OK (%lu kiB)\n", (unsigned long)(_get_size(dev) / 1024));
|
||||
printf("OK (");
|
||||
_print_size(_get_size(dev));
|
||||
puts(")");
|
||||
mtd_power(dev, MTD_POWER_UP);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user