diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 801ea6bf7b..ecf77e0ffd 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -159,6 +159,11 @@ ifneq (,$(filter mpu9150,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter mtd_sdcard,$(USEMODULE))) + USEMODULE += mtd + USEMODULE += sdcard_spi +endif + ifneq (,$(filter nrfmin,$(USEMODULE))) FEATURES_REQUIRED += radio_nrfmin FEATURES_REQUIRED += periph_cpuid diff --git a/drivers/include/mtd_sdcard.h b/drivers/include/mtd_sdcard.h new file mode 100644 index 0000000000..6b6388bd0c --- /dev/null +++ b/drivers/include/mtd_sdcard.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 HAW-Hamburg + * + * 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_sdcard mtd wrapper for sdcard_spi + * @ingroup drivers_storage + * @brief Driver for SD-cards using mtd interface + * + * @{ + * + * @file + * @brief Interface definition for mtd_sdcard driver + * + * @author Michel Rottleuthner + */ + +#ifndef MTD_SDCARD_H +#define MTD_SDCARD_H + +#include + +#include "sdcard_spi.h" +#include "mtd.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief Device descriptor for mtd_sdcard device + * + * This is an extension of the @c mtd_dev_t struct + */ +typedef struct { + mtd_dev_t base; /**< inherit from mtd_dev_t object */ + sdcard_spi_t *sd_card; /**< sdcard_spi dev descriptor */ + const sdcard_spi_params_t *params; /**< params for sdcard_spi init */ +} mtd_sdcard_t; + + +/** + * @brief sdcards handle sector erase internally so it's possible to directly + * write to the card without erasing the sector first. + * Attention: an erase call will therefore NOT touch the content, + * so disable this feature to ensure overriding the data. + */ +#ifndef MTD_SDCARD_SKIP_ERASE +#define MTD_SDCARD_SKIP_ERASE (1) +#endif + +/** + * @brief sdcard device operations table for mtd + */ +extern const mtd_desc_t mtd_sdcard_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* MTD_SDCARD_H */ +/** @} */ diff --git a/drivers/include/sdcard_spi.h b/drivers/include/sdcard_spi.h index c2ed3d3dde..bdafa4eeca 100644 --- a/drivers/include/sdcard_spi.h +++ b/drivers/include/sdcard_spi.h @@ -252,7 +252,7 @@ int sdcard_spi_read_blocks(sdcard_spi_t *card, int blockaddr, char *data, int bl * * @return number of sucessfully written blocks (0 if no block was written). */ -int sdcard_spi_write_blocks(sdcard_spi_t *card, int blockaddr, char *data, int blocksize, +int sdcard_spi_write_blocks(sdcard_spi_t *card, int blockaddr, const char *data, int blocksize, int nblocks, sd_rw_response_t *state); /** diff --git a/drivers/mtd_sdcard/Makefile b/drivers/mtd_sdcard/Makefile new file mode 100644 index 0000000000..6b99904df0 --- /dev/null +++ b/drivers/mtd_sdcard/Makefile @@ -0,0 +1,3 @@ +MODULE = mtd_sdcard + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/mtd_sdcard/mtd_sdcard.c b/drivers/mtd_sdcard/mtd_sdcard.c new file mode 100644 index 0000000000..80423e9124 --- /dev/null +++ b/drivers/mtd_sdcard/mtd_sdcard.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2017 HAW-Hamburg + * + * 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_sdcard + * @{ + * + * @file + * @brief Driver for using sdcard_spi via mtd interface + * + * @author Michel Rottleuthner + * + * @} + */ +#define ENABLE_DEBUG (0) +#include "debug.h" +#include "mtd.h" +#include "mtd_sdcard.h" +#include "sdcard_spi.h" +#include "sdcard_spi_internal.h" + +#include +#include + +static int mtd_sdcard_init(mtd_dev_t *mtd); +static int mtd_sdcard_read(mtd_dev_t *mtd, void *dest, uint32_t addr, + uint32_t size); +static int mtd_sdcard_write(mtd_dev_t *mtd, const void *src, uint32_t addr, + uint32_t size); +static int mtd_sdcard_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size); +static int mtd_sdcard_power(mtd_dev_t *mtd, enum mtd_power_state power); + +const mtd_desc_t mtd_sdcard_driver = { + .init = mtd_sdcard_init, + .read = mtd_sdcard_read, + .write = mtd_sdcard_write, + .erase = mtd_sdcard_erase, + .power = mtd_sdcard_power, +}; + +static int mtd_sdcard_init(mtd_dev_t *dev) +{ + DEBUG("mtd_sdcard_init\n"); + mtd_sdcard_t *mtd_sd = (mtd_sdcard_t*)dev; + if ((mtd_sd->sd_card->init_done == true) || + (sdcard_spi_init(mtd_sd->sd_card, mtd_sd->params) == 0)) { + /* erasing whole sectors is handled internally by the card so you can + delete single blocks (i.e. pages) */ + dev->pages_per_sector = 1; + dev->sector_count = sdcard_spi_get_sector_count(mtd_sd->sd_card); + + /* sdcard_spi always uses the fixed block size of SD-HC cards */ + dev->page_size = SD_HC_BLOCK_SIZE; + return 0; + } + return -EIO; +} + +static int mtd_sdcard_read(mtd_dev_t *dev, void *buff, uint32_t addr, + uint32_t size) +{ + DEBUG("mtd_sdcard_read: addr:%lu size:%lu\n", addr, size); + mtd_sdcard_t *mtd_sd = (mtd_sdcard_t*)dev; + sd_rw_response_t err; + int res = sdcard_spi_read_blocks(mtd_sd->sd_card, addr / SD_HC_BLOCK_SIZE, + buff, SD_HC_BLOCK_SIZE, + size / SD_HC_BLOCK_SIZE, &err); + + if (err == SD_RW_OK) { + return res * SD_HC_BLOCK_SIZE; + } + return -EIO; +} + +static int mtd_sdcard_write(mtd_dev_t *dev, const void *buff, uint32_t addr, + uint32_t size) +{ + DEBUG("mtd_sdcard_write: addr:%lu size:%lu\n", addr, size); + mtd_sdcard_t *mtd_sd = (mtd_sdcard_t*)dev; + sd_rw_response_t err; + int res = sdcard_spi_write_blocks(mtd_sd->sd_card, addr / SD_HC_BLOCK_SIZE, + buff, SD_HC_BLOCK_SIZE, + size / SD_HC_BLOCK_SIZE, &err); + + if (err == SD_RW_OK) { + return res * SD_HC_BLOCK_SIZE; + } + return -EIO; +} + +static int mtd_sdcard_erase(mtd_dev_t *dev, + uint32_t addr, + uint32_t size) +{ + DEBUG("mtd_sdcard_erase: addr:%lu size:%lu\n", addr, size); + (void)dev; + (void)addr; + (void)size; + +#if MTD_SDCARD_SKIP_ERASE == 1 + return 0; +#else + return -ENOTSUP; /* explicit erase currently not supported */ +#endif +} + +static int mtd_sdcard_power(mtd_dev_t *dev, enum mtd_power_state power) +{ + (void)dev; + (void)power; + + /* TODO: implement power down of sdcard in sdcard_spi + (make use of sdcard_spi_params_t.power pin) */ + return -ENOTSUP; /* currently not supported */ +} diff --git a/drivers/sdcard_spi/sdcard_spi.c b/drivers/sdcard_spi/sdcard_spi.c index 7eabda4daf..82a6084583 100644 --- a/drivers/sdcard_spi/sdcard_spi.c +++ b/drivers/sdcard_spi/sdcard_spi.c @@ -40,7 +40,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta static sd_rw_response_t _read_cid(sdcard_spi_t *card); static sd_rw_response_t _read_csd(sdcard_spi_t *card); static sd_rw_response_t _read_data_packet(sdcard_spi_t *card, char token, char *data, int size); -static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, char *data, int size); +static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, const char *data, int size); /* CRC-7 (polynomial: x^7 + x^3 + 1) LSB of CRC-7 in a 8-bit variable is always 1*/ static char _crc_7(const char *data, int n); @@ -49,7 +49,7 @@ static char _crc_7(const char *data, int n); static uint16_t _crc_16(const char *data, size_t n); /* use this transfer method instead of _transfer_bytes to force the use of 0xFF as dummy bytes */ -static inline int _transfer_bytes(sdcard_spi_t *card, char *out, char *in, unsigned int length); +static inline int _transfer_bytes(sdcard_spi_t *card, const char *out, char *in, unsigned int length); /* uses bitbanging for spi communication which allows to enable pull-up on the miso pin for greater card compatibility on platforms that don't have a hw pull up installed */ @@ -576,7 +576,7 @@ static inline int _hw_spi_rxtx_byte(sdcard_spi_t *card, char out, char *in){ return 1; } -static inline int _transfer_bytes(sdcard_spi_t *card, char *out, char *in, unsigned int length){ +static inline int _transfer_bytes(sdcard_spi_t *card, const char *out, char *in, unsigned int length){ int trans_ret; unsigned trans_bytes = 0; char in_temp; @@ -703,7 +703,7 @@ int sdcard_spi_read_blocks(sdcard_spi_t *card, int blockaddr, char *data, int bl } } -static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, char *data, int size) +static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, const char *data, int size) { spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, token); @@ -758,7 +758,7 @@ static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, char } } -static inline int _write_blocks(sdcard_spi_t *card, char cmd_idx, int bladdr, char *data, int blsz, +static inline int _write_blocks(sdcard_spi_t *card, char cmd_idx, int bladdr, const char *data, int blsz, int nbl, sd_rw_response_t *state) { _select_card_spi(card); @@ -823,7 +823,7 @@ static inline int _write_blocks(sdcard_spi_t *card, char cmd_idx, int bladdr, ch } } -int sdcard_spi_write_blocks(sdcard_spi_t *card, int blockaddr, char *data, int blocksize, +int sdcard_spi_write_blocks(sdcard_spi_t *card, int blockaddr, const char *data, int blocksize, int nblocks, sd_rw_response_t *state) { if (nblocks > 1) {