drivers/at25xxx: add MTD wrapper for AT25XXX EEPROMs

drivers/at25xxx: add mtd_wrapper as submodule

tests: add mtd_at25xxx test module for mtd wrapper

drivers/Makefile.dep: add at25xxx dep for mtd_at25xxx module
This commit is contained in:
Johannes Koster 2020-04-09 13:57:29 +01:00
parent 3e922f878a
commit 177a653bd1
7 changed files with 288 additions and 0 deletions

View File

@ -504,6 +504,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

View File

@ -1 +1,5 @@
ifneq (,$(filter mtd_at25xxx,$(USEMODULE)))
DIRS += mtd
endif
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,10 @@
MODULE := mtd_at25xxx
BASE_MODULE := at25xxx
# at25xxx_mtd files
SRC := mtd.c
# enable submodules
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

83
drivers/at25xxx/mtd/mtd.c Normal file
View File

@ -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 <johannes.koster@ml-pa.com>
*
* @}
*/
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "mtd.h"
#include "at25xxx/mtd.h"
#include "at25xxx.h"
#include "at25xxx_params.h"
#include <inttypes.h>
#include <errno.h>
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,
};

View File

@ -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 <johannes.koster@ml-pa.com>
*/
#ifndef AT25XXX_MTD_H
#define AT25XXX_MTD_H
#include <stdint.h>
#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 */
/** @} */

View File

@ -0,0 +1,6 @@
include ../Makefile.tests_common
USEMODULE += mtd_at25xxx
USEMODULE += embunit
include $(RIOTBASE)/Makefile.include

125
tests/mtd_at25xxx/main.c Normal file
View File

@ -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 <string.h>
#include <errno.h>
#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;
}
/** @} */