diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index e313b9d206..f394d34509 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -528,6 +528,10 @@ endif ifneq (,$(filter mtd_%,$(USEMODULE))) USEMODULE += mtd + ifneq (,$(filter mtd_at24cxxx,$(USEMODULE))) + USEMODULE += at24cxxx + endif + ifneq (,$(filter mtd_at25xxx,$(USEMODULE))) USEMODULE += at25xxx endif diff --git a/drivers/at24cxxx/Makefile b/drivers/at24cxxx/Makefile index 48422e909a..4c328975d2 100644 --- a/drivers/at24cxxx/Makefile +++ b/drivers/at24cxxx/Makefile @@ -1 +1,5 @@ +ifneq (,$(filter mtd_at24cxxx,$(USEMODULE))) + DIRS += mtd +endif + include $(RIOTBASE)/Makefile.base diff --git a/drivers/at24cxxx/mtd/Makefile b/drivers/at24cxxx/mtd/Makefile new file mode 100644 index 0000000000..b2910d5125 --- /dev/null +++ b/drivers/at24cxxx/mtd/Makefile @@ -0,0 +1,10 @@ +MODULE := mtd_at24cxxx +BASE_MODULE := at24cxxx + +# at24cxxx_mtd files +SRC := mtd.c + +# enable submodules +SUBMODULES := 1 + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/at24cxxx/mtd/mtd.c b/drivers/at24cxxx/mtd/mtd.c new file mode 100644 index 0000000000..dd36e54a26 --- /dev/null +++ b/drivers/at24cxxx/mtd/mtd.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * 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_at24cxxx + * @{ + * + * @file + * @brief MTD EEPROM driver implementation for at24cxxx EEPROM + * + * @author Fabian Hüßler + * + * @} + */ + +#include +#include + +#include "mtd_at24cxxx.h" + +#define DEV(mtd_ptr) (((mtd_at24cxxx_t *)(mtd_ptr))->at24cxxx_eeprom) +#define PARAMS(mtd_ptr) (((mtd_at24cxxx_t *)(mtd_ptr))->params) + +static int _mtd_at24cxxx_init(mtd_dev_t *mtd) +{ + assert(mtd); + assert(mtd->driver == &mtd_at24cxxx_driver); + assert(DEV(mtd)); + assert(PARAMS(mtd)); + int init = at24cxxx_init(DEV(mtd), PARAMS(mtd)); + if (init != AT24CXXX_OK) { + return init; + } + mtd->page_size = DEV(mtd)->params.page_size; + mtd->pages_per_sector = 1; + mtd->sector_count = DEV(mtd)->params.eeprom_size / + DEV(mtd)->params.page_size; + return 0; +} + +static int _mtd_at24cxxx_read(mtd_dev_t *mtd, void *dest, uint32_t addr, + uint32_t size) +{ + return at24cxxx_read(DEV(mtd), addr, dest, size) == AT24CXXX_OK ? 0 : -EIO; +} + +static int _mtd_at24cxxx_write(mtd_dev_t *mtd, const void *src, uint32_t addr, + uint32_t size) +{ + return at24cxxx_write(DEV(mtd), addr, src, size) == AT24CXXX_OK ? 0 : -EIO; +} + +static int _mtd_at24cxxx_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) +{ + return at24cxxx_clear(DEV(mtd), addr, size) == AT24CXXX_OK ? 0 : -EIO; +} + +static int _mtd_at24cxxx_power(mtd_dev_t *mtd, enum mtd_power_state power) +{ + (void)mtd; + (void)power; + return -ENOTSUP; +} + +const mtd_desc_t mtd_at24cxxx_driver = { + .init = _mtd_at24cxxx_init, + .read = _mtd_at24cxxx_read, + .write = _mtd_at24cxxx_write, + .erase = _mtd_at24cxxx_erase, + .power = _mtd_at24cxxx_power +}; diff --git a/drivers/include/mtd_at24cxxx.h b/drivers/include/mtd_at24cxxx.h new file mode 100644 index 0000000000..ba81401ac3 --- /dev/null +++ b/drivers/include/mtd_at24cxxx.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke Universität + * + * 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_at24cxxx MTD wrapper for AT24cxxx family of I2C-EEPROMs + * @ingroup drivers_storage + * @brief MTD wrapper for AT24XXX I2C based EEPROMs + * + * @{ + * + * @file + * @brief Interface definition for at24cxxx MTD wrapper + * + * + * @author Fabian Hüßler + */ + +#ifndef MTD_AT24CXXX_H +#define MTD_AT24CXXX_H + +#include "at24cxxx.h" +#include "mtd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Device descriptor for mtd at24cxxx device + * + * This is an extension of the @c mtd_dev_t struct + */ +typedef struct { + mtd_dev_t base; /**< inherit from mtd_dev_t object */ + at24cxxx_t *at24cxxx_eeprom; /**< at24cxxx device descriptor */ + const at24cxxx_params_t* params; /**< at24cxxx parameters */ +} mtd_at24cxxx_t; + +/** + * @brief Shortcut initializer for @ref mtd_at24cxxx_t + */ +#define MTD_AT24CXXX_INIT(dev_p, params_p) \ +(mtd_at24cxxx_t) { \ + .base = { \ + .driver = &mtd_at24cxxx_driver \ + }, \ + .at24cxxx_eeprom = (dev_p), \ + .params = (params_p) \ +} + +/** + * @brief MTD EEPROM driver for at24cxxx EEPROM + */ +extern const mtd_desc_t mtd_at24cxxx_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* MTD_AT24CXXX_H */ +/** @} */ diff --git a/tests/mtd_at24cxxx/Makefile b/tests/mtd_at24cxxx/Makefile new file mode 100644 index 0000000000..2d077fa044 --- /dev/null +++ b/tests/mtd_at24cxxx/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.tests_common + +USEMODULE += mtd_at24cxxx +USEMODULE += embunit + +include $(RIOTBASE)/Makefile.include diff --git a/tests/mtd_at24cxxx/main.c b/tests/mtd_at24cxxx/main.c new file mode 100644 index 0000000000..ba5d98ad9c --- /dev/null +++ b/tests/mtd_at24cxxx/main.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * 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_at24cxxx.h" +#include "at24cxxx_params.h" + +#define MTD_DEV (&(_mtd.base)) +#define TEST_ADDRESS (uint16_t)((MTD_DEV->sector_count - 1) * \ + MTD_DEV->page_size) + +static at24cxxx_t _at24cxxx; +static mtd_at24cxxx_t _mtd = MTD_AT24CXXX_INIT(&_at24cxxx, + &at24cxxx_params[0]); + +static void setup(void) +{ + int ret = mtd_init(MTD_DEV); + TEST_ASSERT_EQUAL_INT(0, ret); + mtd_erase(MTD_DEV, TEST_ADDRESS, + MTD_DEV->pages_per_sector * MTD_DEV->page_size); +} + +static void teardown(void) +{ + mtd_erase(MTD_DEV, TEST_ADDRESS, + MTD_DEV->pages_per_sector * MTD_DEV->page_size); +} + +static void test_mtd_init(void) +{ + int ret = mtd_init(MTD_DEV); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +static void test_mtd_erase(void) +{ + int ret = mtd_erase(MTD_DEV, TEST_ADDRESS, MTD_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_AT24CXXX_TEST_WRITE_ERASE"; + + char buf_read[sizeof(buf) + sizeof(buf_empty)]; + memset(buf_read, 0, sizeof(buf_read)); + + int ret = mtd_write(MTD_DEV, buf, TEST_ADDRESS, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(0, ret); + + ret = mtd_erase(MTD_DEV, TEST_ADDRESS, + MTD_DEV->pages_per_sector * MTD_DEV->page_size); + TEST_ASSERT_EQUAL_INT(0, ret); + + uint8_t expected[sizeof(buf_read)]; + memset(expected, 0, sizeof(expected)); + ret = mtd_read(MTD_DEV, buf_read, TEST_ADDRESS, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(0, 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_AT24CXXX_TEST_WRITE_READ"; + + char buf_read[sizeof(buf) + sizeof(buf_empty)]; + memset(buf_read, 0, sizeof(buf_read)); + + /* Basic write / read */ + int ret = mtd_write(MTD_DEV, buf, TEST_ADDRESS, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(0, ret); + + ret = mtd_read(MTD_DEV, buf_read, TEST_ADDRESS, sizeof(buf_read)); + TEST_ASSERT_EQUAL_INT(0, 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(MTD_DEV, TEST_ADDRESS, + MTD_DEV->pages_per_sector * MTD_DEV->page_size); + TEST_ASSERT_EQUAL_INT(0, ret); +} + +Test *tests_mtd_at24cxxx_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_at24cxxx_tests, setup, teardown, fixtures); + + return (Test *)&mtd_at24cxxx_tests; +} + +int main(void) +{ + TESTS_START(); + TESTS_RUN(tests_mtd_at24cxxx_tests()); + TESTS_END(); + return 0; +} +/** @} */