diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 532ad0fe3f..3903a60d5c 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -509,6 +509,10 @@ endif ifneq (,$(filter mtd_%,$(USEMODULE))) USEMODULE += mtd + ifneq (,$(filter mtd_at25xxx,$(USEMODULE))) + USEMODULE += at25xxx + endif + ifneq (,$(filter mtd_sdcard,$(USEMODULE))) USEMODULE += sdcard_spi endif diff --git a/drivers/at25xxx/Makefile b/drivers/at25xxx/Makefile index 48422e909a..f17127ffd3 100644 --- a/drivers/at25xxx/Makefile +++ b/drivers/at25xxx/Makefile @@ -1 +1,5 @@ +ifneq (,$(filter mtd_at25xxx,$(USEMODULE))) + DIRS += mtd +endif + include $(RIOTBASE)/Makefile.base diff --git a/drivers/at25xxx/mtd/Makefile b/drivers/at25xxx/mtd/Makefile new file mode 100644 index 0000000000..507570df99 --- /dev/null +++ b/drivers/at25xxx/mtd/Makefile @@ -0,0 +1,10 @@ +MODULE := mtd_at25xxx +BASE_MODULE := at25xxx + +# at25xxx_mtd files +SRC := mtd.c + +# enable submodules +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/at25xxx/mtd/mtd.c b/drivers/at25xxx/mtd/mtd.c new file mode 100644 index 0000000000..10b6dc2244 --- /dev/null +++ b/drivers/at25xxx/mtd/mtd.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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_at25xxx + * @{ + * + * @file + * @brief MTD wrapper for AT25XXX based SPI EEPROMs (like AT25xxx, M95xxx, 25AAxxx, 25LCxxx, + * CAT25xxx & BR25Sxxx) + * + * @author Johannes Koster + * + * @} + */ +#define ENABLE_DEBUG (0) +#include "debug.h" +#include "mtd.h" +#include "at25xxx/mtd.h" +#include "at25xxx.h" +#include "at25xxx_params.h" + +#include +#include + +static int mtd_at25xxx_init(mtd_dev_t *dev) +{ + DEBUG("[mtd_at25xxx] initializing\n"); + mtd_at25xxx_t *mtd_at25xxx = (mtd_at25xxx_t*)dev; + if (at25xxx_init(mtd_at25xxx->at25xxx_eeprom, mtd_at25xxx->params) == 0) + { + dev->pages_per_sector = 1; + dev->page_size = mtd_at25xxx->params->page_size; + dev->sector_count = mtd_at25xxx->params->size / mtd_at25xxx->params->page_size; + return 0; + } + return -EIO; +} + +static int mtd_at25xxx_read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) +{ + DEBUG("[mtd_at25xxx] read: addr:%" PRIu32 " size:%" PRIu32 "\n", addr, size); + mtd_at25xxx_t *mtd_at25xxx_ = (mtd_at25xxx_t*)dev; + return at25xxx_read(mtd_at25xxx_->at25xxx_eeprom, addr, buff, size); +} + +static int mtd_at25xxx_write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) +{ + DEBUG("[mtd_at25xxx] write: addr:%" PRIu32 " size:%" PRIu32 "\n", addr, size); + mtd_at25xxx_t *mtd_at25xxx_ = (mtd_at25xxx_t*)dev; + return at25xxx_write(mtd_at25xxx_->at25xxx_eeprom, addr, buff, size); +} + +static int mtd_at25xxx_erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) +{ + DEBUG("[mtd_at25xxx] mtd_at25xxx_erase: addr:%" PRIu32 " size:%" PRIu32 "\n", addr, size); + mtd_at25xxx_t *mtd_at25xxx_ = (mtd_at25xxx_t*)dev; + return at25xxx_clear(mtd_at25xxx_->at25xxx_eeprom, addr, size); +} + +static int mtd_at25xxx_power(mtd_dev_t *dev, enum mtd_power_state power) +{ + (void)dev; + (void)power; + + /* TODO: implement power down/up of EEPROM (at25xxx driver?) + */ + return -ENOTSUP; /* currently not supported */ +} + +const mtd_desc_t mtd_at25xxx_driver = { + .init = mtd_at25xxx_init, + .read = mtd_at25xxx_read, + .write = mtd_at25xxx_write, + .erase = mtd_at25xxx_erase, + .power = mtd_at25xxx_power, +}; diff --git a/drivers/include/at25xxx/mtd.h b/drivers/include/at25xxx/mtd.h new file mode 100644 index 0000000000..870e3a1e95 --- /dev/null +++ b/drivers/include/at25xxx/mtd.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @defgroup drivers_mtd_at25xxx MTD wrapper for AT25xxx family of SPI-EEPROMs + * @ingroup drivers_storage + * @brief MTD wrapper for AT25XXX based SPI EEPROMs + * + * @{ + * + * @file + * @brief Interface definition for at25xxx MTD wrapper + * + * @author Johannes Koster + */ + +#ifndef AT25XXX_MTD_H +#define AT25XXX_MTD_H + +#include + +#include "at25xxx.h" +#include "mtd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Device descriptor for mtd_at25xxx device + * + * This is an extension of the @c mtd_dev_t struct + */ +typedef struct { + mtd_dev_t base; /**< inherit from mtd_dev_t object */ + at25xxx_t *at25xxx_eeprom; /**< at25xxx_eeprom dev descriptor */ + const at25xxx_params_t *params; /**< params for at25xxx_eeprom init */ +} mtd_at25xxx_t; + +/** + * @brief mtd_at25xxx_eeprom device operations table for mtd + */ +extern const mtd_desc_t mtd_at25xxx_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* AT25XXX_MTD_H */ +/** @} */ diff --git a/tests/mtd_at25xxx/Makefile b/tests/mtd_at25xxx/Makefile new file mode 100644 index 0000000000..2f61c782ef --- /dev/null +++ b/tests/mtd_at25xxx/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += mtd_at25xxx +USEMODULE += embunit + +include $(RIOTBASE)/Makefile.include diff --git a/tests/mtd_at25xxx/main.c b/tests/mtd_at25xxx/main.c new file mode 100644 index 0000000000..408697138f --- /dev/null +++ b/tests/mtd_at25xxx/main.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 ML!PA Consulting GmbH + * + * 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. + */ + +/** + * @{ + * + * @file + */ +#include +#include + +#include "embUnit.h" + +#include "mtd.h" +#include "at25xxx.h" +#include "at25xxx/mtd.h" +#include "at25xxx_params.h" + +#define TEST_ADDRESS (uint16_t)((dev->sector_count - 1) * dev->page_size) + +static at25xxx_t at25xxx; + +static mtd_at25xxx_t _dev = { + .base = { + .driver = &mtd_at25xxx_driver + }, + .at25xxx_eeprom = &at25xxx, + .params = &at25xxx_params[0], +}; + +static mtd_dev_t *dev = (mtd_dev_t *)&_dev; + +static void setup(void) +{ + int ret = mtd_init(dev); + TEST_ASSERT_EQUAL_INT(0, ret); + mtd_erase(dev, TEST_ADDRESS, dev->pages_per_sector * dev->page_size); +} + +static void teardown(void) +{ + mtd_erase(dev, TEST_ADDRESS, dev->pages_per_sector * dev->page_size); +} + +static void test_mtd_init(void) +{ + int ret = mtd_init(dev); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +static void test_mtd_erase(void) +{ + int ret = mtd_erase(dev, TEST_ADDRESS, dev->page_size); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +static void test_mtd_write_erase(void) +{ + uint8_t buf_empty[] = {0, 0, 0}; + const char buf[] = "MTD_AT25XXX_TEST_WRITE_ERASE"; + + char buf_read[sizeof(buf) + sizeof(buf_empty)]; + memset(buf_read, 0, sizeof(buf_read)); + + int ret = mtd_write(dev, buf, TEST_ADDRESS, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); + + ret = mtd_erase(dev, TEST_ADDRESS, dev->pages_per_sector * dev->page_size); + TEST_ASSERT_EQUAL_INT(0, ret); + + uint8_t expected[sizeof(buf_read)]; + memset(expected, 0, sizeof(expected)); + ret = mtd_read(dev, buf_read, TEST_ADDRESS, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(sizeof(buf_read), ret); + TEST_ASSERT_EQUAL_INT(0, memcmp(expected, buf_read, sizeof(buf_read))); +} + +static void test_mtd_write_read(void) +{ + uint8_t buf_empty[] = {0, 0, 0}; + const char buf[] = "MTD_AT25XXX_TEST_WRITE_ERASE"; + + char buf_read[sizeof(buf) + sizeof(buf_empty)]; + memset(buf_read, 0, sizeof(buf_read)); + + /* Basic write / read */ + int ret = mtd_write(dev, buf, TEST_ADDRESS, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); + + ret = mtd_read(dev, buf_read, TEST_ADDRESS, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(sizeof(buf_read), ret); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf, buf_read, sizeof(buf))); + TEST_ASSERT_EQUAL_INT(0, memcmp(buf_empty, buf_read + sizeof(buf), sizeof(buf_empty))); + + ret = mtd_erase(dev, TEST_ADDRESS, dev->pages_per_sector * dev->page_size); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +Test *tests_mtd_at25xxx_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_mtd_init), + new_TestFixture(test_mtd_erase), + new_TestFixture(test_mtd_write_erase), + new_TestFixture(test_mtd_write_read), + }; + + EMB_UNIT_TESTCALLER(mtd_at25xxx_tests, setup, teardown, fixtures); + + return (Test *)&mtd_at25xxx_tests; +} + +int main(void) +{ + TESTS_START(); + TESTS_RUN(tests_mtd_at25xxx_tests()); + TESTS_END(); + return 0; +} +/** @} */