Browse Source

drivers: added driver for accessing sd_cards over spi

pr/spi.typo
Michel Rottleuthner 6 years ago committed by MichelRottleuthner
parent
commit
ac2ae7cb56
  1. 13
      boards/remote-revb/include/board.h
  2. 6
      drivers/Makefile.dep
  3. 3
      drivers/Makefile.include
  4. 271
      drivers/include/sdcard_spi.h
  5. 3
      drivers/sdcard_spi/Makefile
  6. 243
      drivers/sdcard_spi/include/sdcard_spi_internal.h
  7. 77
      drivers/sdcard_spi/include/sdcard_spi_params.h
  8. 1086
      drivers/sdcard_spi/sdcard_spi.c
  9. 4
      sys/auto_init/Makefile
  10. 11
      sys/auto_init/auto_init.c
  11. 3
      sys/auto_init/storage/Makefile
  12. 55
      sys/auto_init/storage/auto_init_sdcard_spi.c
  13. 9
      tests/driver_sdcard_spi/Makefile
  14. 369
      tests/driver_sdcard_spi/main.c

13
boards/remote-revb/include/board.h

@ -110,6 +110,19 @@
#define CC1200_GPD2_GPIO GPIO_PB0
/** @} */
/**
* @name Onboard micro-sd slot pin definitions
* @{
*/
#define SDCARD_SPI_PARAM_SPI SPI_1
#define SDCARD_SPI_PARAM_CS GPIO_PIN(0,7)
#define SDCARD_SPI_PARAM_CLK GPIO_PIN(2,4)
#define SDCARD_SPI_PARAM_MOSI GPIO_PIN(2,5)
#define SDCARD_SPI_PARAM_MISO GPIO_PIN(2,6)
#define SDCARD_SPI_PARAM_POWER GPIO_PIN(0,6)
#define SDCARD_SPI_PARAM_POWER_AH false
/** @} */
#ifdef __cplusplus
} /* end extern "C" */
#endif

6
drivers/Makefile.dep

@ -137,6 +137,12 @@ ifneq (,$(filter rgbled,$(USEMODULE)))
USEMODULE += color
endif
ifneq (,$(filter sdcard_spi,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_spi
USEMODULE += xtimer
endif
ifneq (,$(filter sht11,$(USEMODULE)))
USEMODULE += xtimer
endif

3
drivers/Makefile.include

@ -88,3 +88,6 @@ endif
ifneq (,$(filter lis3dh,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis3dh/include
endif
ifneq (,$(filter sdcard_spi,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include
endif

271
drivers/include/sdcard_spi.h

@ -0,0 +1,271 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_sdcard_spi SPI SD-Card driver
* @ingroup drivers
* @brief Driver for reading and writing sd-cards via spi interface.
* @{
*
* @file
* @brief Public interface for the sdcard_spi driver.
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef SDCARD_SPI_H
#define SDCARD_SPI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "periph/spi.h"
#include "periph/gpio.h"
#include "stdbool.h"
#define SD_HC_BLOCK_SIZE (512) /**< size of a single block on SDHC cards */
#define SDCARD_SPI_INIT_ERROR (-1) /**< returned on failed init */
#define SDCARD_SPI_OK (0) /**< returned on successful init */
#define SD_SIZE_OF_OID 2 /**< OID (OEM/application ID field in CID reg) */
#define SD_SIZE_OF_PNM 5 /**< PNM (product name field in CID reg) */
/**
* @brief CID register see section 5.2 in SD-Spec v5.00
*/
struct {
uint8_t MID; /**< Manufacturer ID */
char OID[SD_SIZE_OF_OID]; /**< OEM/Application ID*/
char PNM[SD_SIZE_OF_PNM]; /**< Product name */
uint8_t PRV; /**< Product revision */
uint32_t PSN; /**< Product serial number */
uint16_t MDT; /**< Manufacturing date */
uint8_t CID_CRC; /**< CRC7 checksum */
} typedef cid_t;
/**
* @brief CSD register with csd structure version 1.0
* see section 5.3.2 in SD-Spec v5.00
*/
struct {
uint8_t CSD_STRUCTURE : 2; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t TAAC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t NSAC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t TRAN_SPEED : 8; /**< see section 5.3.2 in SD-Spec v5.00 */
uint16_t CCC : 12; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t READ_BL_LEN : 4; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t READ_BL_PARTIAL : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t WRITE_BLK_MISALIGN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t READ_BLK_MISALIGN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t DSR_IMP : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint16_t C_SIZE : 12; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t VDD_R_CURR_MIN : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t VDD_R_CURR_MAX : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t VDD_W_CURR_MIN : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t VDD_W_CURR_MAX : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t C_SIZE_MULT : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t ERASE_BLK_EN : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t SECTOR_SIZE : 7; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t WP_GRP_SIZE : 7; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t WP_GRP_ENABLE : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t R2W_FACTOR : 3; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t WRITE_BL_LEN : 4; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t WRITE_BL_PARTIAL : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t FILE_FORMAT_GRP : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t COPY : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t PERM_WRITE_PROTECT : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t TMP_WRITE_PROTECT : 1; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t FILE_FORMAT : 2; /**< see section 5.3.2 in SD-Spec v5.00 */
uint8_t CSD_CRC : 8; /**< see section 5.3.2 in SD-Spec v5.00 */
} typedef csd_v1_t;
/**
* @brief CSD register with csd structure version 2.0
* see section 5.3.3 in SD-Spec v5.00
*/
struct {
uint8_t CSD_STRUCTURE : 2; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t TAAC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t NSAC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t TRAN_SPEED : 8; /**< see section 5.3.3 in SD-Spec v5.00 */
uint16_t CCC : 12; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t READ_BL_LEN : 4; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t READ_BL_PARTIAL : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t WRITE_BLK_MISALIGN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t READ_BLK_MISALIGN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t DSR_IMP : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint32_t C_SIZE : 22; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t ERASE_BLK_EN : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t SECTOR_SIZE : 7; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t WP_GRP_SIZE : 7; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t WP_GRP_ENABLE : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t R2W_FACTOR : 3; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t WRITE_BL_LEN : 4; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t WRITE_BL_PARTIAL : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t FILE_FORMAT_GRP : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t COPY : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t PERM_WRITE_PROTECT : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t TMP_WRITE_PROTECT : 1; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t FILE_FORMAT : 2; /**< see section 5.3.3 in SD-Spec v5.00 */
uint8_t CSD_CRC : 8; /**< see section 5.3.3 in SD-Spec v5.00 */
} typedef csd_v2_t;
/**
* @brief CSD register (see section 5.3 in SD-Spec v5.00)
*/
union {
csd_v1_t v1; /**< see section 5.3.2 in SD-Spec v5.00 */
csd_v2_t v2; /**< see section 5.3.3 in SD-Spec v5.00 */
} typedef csd_t;
/**
* @brief SD status register (see section 4.10.2 in SD-Spec v5.00)
*/
struct {
uint32_t SIZE_OF_PROTECTED_AREA : 32; /**< see section 4.10.2 in SD-Spec v5.00 */
uint32_t SUS_ADDR : 22; /**< see section 4.10.2.12 in SD-Spec v5.00 */
uint32_t VSC_AU_SIZE : 10; /**< see section 4.10.2.11 in SD-Spec v5.00 */
uint16_t SD_CARD_TYPE : 16; /**< see section 4.10.2 in SD-Spec v5.00 */
uint16_t ERASE_SIZE : 16; /**< see section 4.10.2.5 in SD-Spec v5.00 */
uint8_t SPEED_CLASS : 8; /**< see section 4.10.2.2 in SD-Spec v5.00 */
uint8_t PERFORMANCE_MOVE : 8; /**< see section 4.10.2.3 in SD-Spec v5.00 */
uint8_t VIDEO_SPEED_CLASS : 8; /**< see section 4.10.2.10 in SD-Spec v5.00 */
uint8_t ERASE_TIMEOUT : 6; /**< see section 4.10.2.6 in SD-Spec v5.00 */
uint8_t ERASE_OFFSET : 2; /**< see section 4.10.2.7 in SD-Spec v5.00 */
uint8_t UHS_SPEED_GRADE : 4; /**< see section 4.10.2.8 in SD-Spec v5.00 */
uint8_t UHS_AU_SIZE : 4; /**< see section 4.10.2.9 in SD-Spec v5.00 */
uint8_t AU_SIZE : 4; /**< see section 4.10.2.4 in SD-Spec v5.00 */
uint8_t DAT_BUS_WIDTH : 2; /**< see section 4.10.2 in SD-Spec v5.00 */
uint8_t SECURED_MODE : 1; /**< see section 4.10.2 in SD-Spec v5.00 */
} typedef sd_status_t;
/**
* @brief version type of SD-card
*/
typedef enum {
SD_V2, /**< SD version 2 */
SD_V1, /**< SD version 1 */
MMC_V3, /**< MMC version 3 */
SD_UNKNOWN /**< SD-version unknown */
} sd_version_t;
/**
* @brief sdcard_spi r/w-operation return values
*/
typedef enum {
SD_RW_OK = 0, /**< no error */
SD_RW_NO_TOKEN, /**< no token was received (on block read) */
SD_RW_TIMEOUT, /**< cmd timed out (not-busy-state wasn't entered) */
SD_RW_RX_TX_ERROR, /**< error while performing SPI read/write */
SD_RW_WRITE_ERROR, /**< data-packet response indicates error */
SD_RW_CRC_MISMATCH, /**< CRC-mismatch of received data */
SD_RW_NOT_SUPPORTED /**< operation not supported on used card */
} sd_rw_response_t;
/**
* @brief sdcard_spi device params
*/
typedef struct {
spi_t spi_dev; /**< SPI bus used */
gpio_t cs; /**< pin connected to the DAT3 sd pad */
gpio_t clk; /**< pin connected to the CLK sd pad */
gpio_t mosi; /**< pin connected to the CMD sd pad*/
gpio_t miso; /**< pin connected to the DAT0 sd pad*/
gpio_t power; /**< pin that controls sd power circuit*/
bool power_act_high; /**< true if card power is enabled by 'power'-pin HIGH*/
} sdcard_spi_params_t;
/**
* @brief Device descriptor for sdcard_spi
*/
struct {
sdcard_spi_params_t params; /**< parameters for pin and spi config */
bool use_block_addr; /**< true if block adressing (vs. byte adressing) is used */
bool init_done; /**< set to true once the init procedure completed sucessfully */
sd_version_t card_type; /**< version of SD-card */
int csd_structure; /**< version of the CSD register structure */
cid_t cid; /**< CID register */
csd_t csd; /**< CSD register */
} typedef sdcard_spi_t;
/**
* @brief Initializes the sd-card with the given parameters in sdcard_spi_t structure.
* The init procedure also takes care of initializing the spi peripheral to master
* mode and performing all neccecary steps to set the sd-card to spi-mode. Reading
* the CID and CSD registers is also done within this routine and their
* values are copied to the given sdcard_spi_t struct.
*
* @param[out] card the device descriptor
* @param[in] params parameters for this device (pins and spi device are initialized by this driver)
*
* @return 0 if the card could be initialized successfully
* @return false if an error occured while initializing the card
*/
int sdcard_spi_init(sdcard_spi_t *card, const sdcard_spi_params_t *params);
/**
* @brief Reads data blocks (usually multiples of 512 Bytes) from card to buffer.
*
* @param[in] card Initialized sd-card struct
* @param[in] blockaddr Start adress to read from. Independet of the actual adressing scheme of
* the used card the adress needs to be given as block address
* (e.g. 0, 1, 2... NOT: 0, 512... ). The driver takes care of mapping to
* byte adressing if needed.
* @param[out] data Buffer to store the read data in. The user is responsible for providing a
* suitable buffer size.
* @param[in] blocksize Size of data blocks. For now only 512 byte blocks are supported because
* only older (SDSC) cards support variable blocksizes anyway.
* With SDHC/SDXC-cards this is always fixed to 512 bytes. SDSC cards are
* automatically forced to use 512 byte as blocksize by the init procedure.
* @param[in] nblocks Number of blocks to read
* @param[out] state Contains information about the error state if something went wrong
* (if return value is lower than nblocks).
*
* @return number of sucessfully read blocks (0 if no block was read).
*/
int sdcard_spi_read_blocks(sdcard_spi_t *card, int blockaddr, char *data, int blocksize,
int nblocks, sd_rw_response_t *state);
/**
* @brief Writes data blocks (usually multiples of 512 Bytes) from buffer to card.
*
* @param[in] card Initialized sd-card struct
* @param[in] blockaddr Start adress to read from. Independet of the actual adressing scheme of
* the used card the adress needs to be given as block address
* (e.g. 0, 1, 2... NOT: 0, 512... ). The driver takes care of mapping to
* byte adressing if needed.
* @param[out] data Buffer that contains the data to be sent.
* @param[in] blocksize Size of data blocks. For now only 512 byte blocks are supported because
* only older (SDSC) cards support variable blocksizes anyway.
* With SDHC/SDXC-cards this is always fixed to 512 bytes. SDSC cards are
* automatically forced to use 512 byte as blocksize by the init procedure.
* @param[in] nblocks Number of blocks to write
* @param[out] state Contains information about the error state if something went wrong
* (if return value is lower than nblocks).
*
* @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 nblocks, sd_rw_response_t *state);
/**
* @brief Gets the capacity of the card.
*
* @param[in] card Initialized sd-card struct
*
* @return capacity of the card in bytes
*/
uint64_t sdcard_spi_get_capacity(sdcard_spi_t *card);
#ifdef __cplusplus
}
#endif
#endif /* SDCARD_SPI_H */
/** @} */

3
drivers/sdcard_spi/Makefile

@ -0,0 +1,3 @@
MODULE = sdcard_spi
include $(RIOTBASE)/Makefile.base

243
drivers/sdcard_spi/include/sdcard_spi_internal.h

@ -0,0 +1,243 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_sdcard_spi
* @{
*
* @file
* @brief Interface for issuing commands on sd-cards via SPI.
* @details For details of the sd card standard and the spi mode refer to
* "SD Specifications Part 1 Physical Layer Simplified Specification".
* References to the sd specs in this file apply to Version 5.00
* from August 10, 2016. For further details see
* https://www.sdcard.org/downloads/pls/pdf/part1_500.pdf.
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef SDCARD_SPI_INTERNAL_H
#define SDCARD_SPI_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include "periph/spi.h"
#include "periph/gpio.h"
#include "stdbool.h"
#include "sdcard_spi.h"
/* number of clocks that should be applied to the card on init
before taking furter actions (see sd spec. 6.4.1.1 Power Up Time of Card) */
#define SD_POWERSEQUENCE_CLOCK_COUNT 74
#define SD_CARD_PREINIT_CLOCK_PERIOD_US 10 /* used to generate 100 kHz clock in init phase*/
#define SD_CARD_WAIT_AFTER_POWER_UP_US 1000
/* R1 response bits (see sd spec. 7.3.2.1 Format R1) */
#define SD_R1_RESPONSE_PARAM_ERROR (1<<6)
#define SD_R1_RESPONSE_ADDR_ERROR (1<<5)
#define SD_R1_RESPONSE_ERASE_SEQ_ERROR (1<<4)
#define SD_R1_RESPONSE_CMD_CRC_ERROR (1<<3)
#define SD_R1_RESPONSE_ILLEGAL_CMD_ERROR (1<<2)
#define SD_R1_RESPONSE_ERASE_RESET (1<<1)
#define SD_R1_RESPONSE_IN_IDLE_STATE (0x01)
#define SD_INVALID_R1_RESPONSE (1<<7)
#define R1_VALID(X) (((X) >> 7) == 0)
#define R1_PARAM_ERR(X) ((((X) &SD_R1_RESPONSE_PARAM_ERROR) != 0))
#define R1_ADDR_ERR(X) ((((X) &SD_R1_RESPONSE_ADDR_ERROR) != 0))
#define R1_ERASE_ERR(X) ((((X) &SD_R1_RESPONSE_ERASE_SEQ_ERROR) != 0))
#define R1_CMD_CRC_ERR(X) ((((X) &SD_R1_RESPONSE_CMD_CRC_ERROR) != 0))
#define R1_ILL_CMD_ERR(X) ((((X) &SD_R1_RESPONSE_ILLEGAL_CMD_ERROR) != 0))
#define R1_IDLE_BIT_SET(X) (((X) &SD_R1_RESPONSE_IN_IDLE_STATE) != 0)
#define R1_ERROR(X) (R1_PARAM_ERR(X) || R1_ADDR_ERR(X) || R1_ERASE_ERR(X) || \
R1_CMD_CRC_ERR(X) || R1_ILL_CMD_ERR(X))
/* see sd spec. 7.3.3.1 Data Response Token */
#define DATA_RESPONSE_IS_VALID(X) (((X) & 0x11) == 0x01)
#define DATA_RESPONSE_ACCEPTED(X) (((X) & 0x0E) == (1<<2))
#define DATA_RESPONSE_CRC_ERR(X) (((X) & 0x0E) == 0x0A)
#define DATA_RESPONSE_WRITE_ERR(X) (((X) & 0x0E) == 0x0C)
/* see sd spec. 5.1 OCR register */
#define OCR_VOLTAGE_3_2_TO_3_3 (1L << 20)
#define OCR_VOLTAGE_3_3_TO_3_4 (1L << 21)
/* card capacity status (CCS=0: the card is SDSD; CCS=1: card is SDHC or SDXC) */
#define OCR_CCS (1L << 30)
/* This bit is set to low if the card has not finished power up routine */
#define OCR_POWER_UP_STATUS (1L << 31)
/* to ensure the voltage range check on init is done properly you need to
define this according to your actual interface/wiring with the sd-card */
#define SYSTEM_VOLTAGE (OCR_VOLTAGE_3_2_TO_3_3 | OCR_VOLTAGE_3_2_TO_3_3)
/* see sd spec. 7.3.1.3 Detailed Command Description */
#define SD_CMD_PREFIX_MASK (1<<6)
#define SD_CMD_0 0 /* Resets the SD Memory Card */
#define SD_CMD_1 1 /* Sends host capacity support info and starts the cards init process */
#define SD_CMD_8 8 /* Sends SD Card interface condition incl. host supply voltage info */
#define SD_CMD_9 9 /* Asks the selected card to send its card-specific data (CSD) */
#define SD_CMD_10 10 /* Asks the selected card to send its card identification (CID) */
#define SD_CMD_12 12 /* Forces the card to stop transmission in Multiple Block Read Operation */
#define SD_CMD_13 13 /* Sent as ACMD13 asks the card to send it's SD status */
#define SD_CMD_16 16 /* In case of SDSC Card, block length is set by this command */
#define SD_CMD_17 17 /* Reads a block of the size selected by the SET_BLOCKLEN command */
#define SD_CMD_18 18 /* Continuously transfers data blocks from card to host
until interrupted by a STOP_TRANSMISSION command */
#define SD_CMD_24 24 /* Writes a block of the size selected by the SET_BLOCKLEN command */
#define SD_CMD_25 25 /* Continuously writes blocks of data until 'Stop Tran'token is sent */
#define SD_CMD_41 41 /* Reserved (used for ACMD41) */
#define SD_CMD_55 55 /* Defines to the card that the next commmand is an application specific
command rather than a standard command */
#define SD_CMD_58 58 /* Reads the OCR register of a card */
#define SD_CMD_59 59 /* Turns the CRC option on or off. Argument: 1:on; 0:off */
#define SD_CMD_8_VHS_2_7_V_TO_3_6_V 0x01
#define SD_CMD_8_CHECK_PATTERN 0xB5
#define SD_CMD_NO_ARG 0x00000000
#define SD_ACMD_41_ARG_HC 0x40000000
#define SD_CMD_59_ARG_EN 0x00000001
#define SD_CMD_59_ARG_DIS 0x00000000
/* see sd spec. 7.3.3 Control Tokens */
#define SD_DATA_TOKEN_CMD_17_18_24 0xFE
#define SD_DATA_TOKEN_CMD_25 0xFC
#define SD_DATA_TOKEN_CMD_25_STOP 0xFD
#define SD_SIZE_OF_CID_AND_CSD_REG 16
#define SD_SIZE_OF_SD_STATUS 64
#define SD_BLOCKS_FOR_REG_READ 1
#define SD_GET_CSD_STRUCTURE(CSD_RAW_DATA) ((CSD_RAW_DATA)[0] >> 6)
#define SD_CSD_V1 0
#define SD_CSD_V2 1
#define SD_CSD_VUNSUPPORTED -1
/* the retry counters below are used as timeouts for specific actions.
The values may need some adjustments to either give the card more time to respond
to commands or to achieve a lower delay / avoid infinite blocking. */
#define R1_POLLING_RETRY_CNT 1000000
#define SD_DATA_TOKEN_RETRY_CNT 1000000
#define INIT_CMD_RETRY_CNT 1000000
#define INIT_CMD0_RETRY_CNT 3
#define SD_WAIT_FOR_NOT_BUSY_CNT 1000000 /* use -1 for full blocking till the card isn't busy */
#define SD_BLOCK_READ_CMD_RETRIES 10 /* only affects sending of cmd not whole transaction! */
#define SD_BLOCK_WRITE_CMD_RETRIES 10 /* only affects sending of cmd not whole transaction! */
/* memory capacity in bytes = (C_SIZE+1) * SD_CSD_V2_C_SIZE_BLOCK_MULT * BLOCK_LEN */
#define SD_CSD_V2_C_SIZE_BLOCK_MULT 1024
#define SD_CARD_SPI_MODE SPI_CONF_FIRST_RISING
/* this speed setting is only used while the init procedure is performed */
#define SD_CARD_SPI_SPEED_PREINIT SPI_SPEED_400KHZ
/* after init procedure is finished the driver auto sets the card to this speed */
#define SD_CARD_SPI_SPEED_POSTINIT SPI_SPEED_10MHZ
#define SD_CARD_DUMMY_BYTE 0xFF
#define SDCARD_SPI_IEC_KIBI (1024L)
#define SDCARD_SPI_SI_KILO (1000L)
typedef enum {
SD_INIT_START,
SD_INIT_SPI_POWER_SEQ,
SD_INIT_SEND_CMD0,
SD_INIT_SEND_CMD8,
SD_INIT_CARD_UNKNOWN,
SD_INIT_SEND_ACMD41_HCS,
SD_INIT_SEND_ACMD41,
SD_INIT_SEND_CMD1,
SD_INIT_SEND_CMD58,
SD_INIT_SEND_CMD16,
SD_INIT_ENABLE_CRC,
SD_INIT_READ_CID,
SD_INIT_READ_CSD,
SD_INIT_SET_MAX_SPI_SPEED,
SD_INIT_FINISH
} sd_init_fsm_state_t;
/**
* @brief Sends a cmd to the sd card.
*
* @param[in] card Initialized sd-card struct
* @param[in] sd_cmd_idx A supported sd-card command index for SPI-mode like defined in
* "7.3.1.3 Detailed Command Description" of sd spec.
* (for CMDX this parameter is simply the integer value X).
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
* This argument is transmitted byte wise with most significant byte first.
* @param[in] max_retry Specifies how often the command should be retried if an error occures.
* Use 0 to try only once, -1 to try forever, or n to retry n times.
*
* @return R1 response of the command if no (low-level) communication error occured
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
* not-busy-state timed out or spi communication failed
*/
char sdcard_spi_send_cmd(sdcard_spi_t *card, char sd_cmd_idx, uint32_t argument, int32_t max_retry);
/**
* @brief Sends an acmd to the sd card. ACMD<n> consists of sending CMD55 + CMD<n>
*
* @param[in] card Initialized sd-card struct
* @param[in] sd_cmd_idx A supported sd-card command index for SPI-mode like defined in
* "7.3.1.3 Detailed Command Description" of sd spec.
* (for ACMDX this parameter is simply the integer value X).
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
* This argument is transmitted byte wise with most significant byte first.
* @param[in] max_retry Specifies how often the command should be retried if an error occures.
* Use 0 to try only once, -1 to try forever, or n to retry n times.
*
* @return R1 response of the command if no (low-level) communication error occured
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
* not-busy-state timed out or spi communication failed
*/
char sdcard_spi_send_acmd(sdcard_spi_t *card, char sd_cmd_idx, uint32_t argument, int32_t max_retry);
/**
* @brief Gets the sector count of the card.
*
* @param[in] card Initialized sd-card struct
*
* @return number of available sectors
*/
uint32_t sdcard_spi_get_sector_count(sdcard_spi_t *card);
/**
* @brief Gets the allocation unit size of the card.
*
* @param[in] card Initialized sd-card struct
*
* @return size of AU in bytes
*/
uint32_t sdcard_spi_get_au_size(sdcard_spi_t *card);
/**
* @brief Gets the SD status of the card.
*
* @param[in] card Initialized sd-card struct
* @param[out] sd_status memory location where status struct is stored
*
* @return sd_status_t struct that contains all SD status information
*/
sd_rw_response_t sdcard_spi_read_sds(sdcard_spi_t *card, sd_status_t *sd_status);
#ifdef __cplusplus
}
#endif
#endif /* SDCARD_SPI_INTERNAL_H */
/** @} */

77
drivers/sdcard_spi/include/sdcard_spi_params.h

@ -0,0 +1,77 @@
/*
* Copyright (C) 2017 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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_sdcard_spi
* @{
*
* @file
* @brief Default parameters for sdcard_spi driver
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifndef SDCARD_SPI_PARAMS_H
#define SDCARD_SPI_PARAMS_H
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the sdcard_spi driver
* @{
*/
#ifndef SDCARD_SPI_PARAM_SPI
#define SDCARD_SPI_PARAM_SPI (SPI_0)
#endif
#ifndef SDCARD_SPI_PARAM_CS
#define SDCARD_SPI_PARAM_CS (GPIO_PIN(2,4))
#endif
#ifndef SDCARD_SPI_PARAM_CLK
#define SDCARD_SPI_PARAM_CLK (GPIO_PIN(2,5))
#endif
#ifndef SDCARD_SPI_PARAM_MOSI
#define SDCARD_SPI_PARAM_MOSI (GPIO_PIN(2,6))
#endif
#ifndef SDCARD_SPI_PARAM_MISO
#define SDCARD_SPI_PARAM_MISO (GPIO_PIN(2,7))
#endif
#ifndef SDCARD_SPI_PARAM_POWER
#define SDCARD_SPI_PARAM_POWER (GPIO_UNDEF)
#endif
#ifndef SDCARD_SPI_PARAM_POWER_AH
/** treated as 'don't care' if SDCARD_SPI_PARAM_POWER is GPIO_UNDEF */
#define SDCARD_SPI_PARAM_POWER_AH (true)
#endif
/** @} */
/**
* @brief sdcard_spi configuration
*/
static const sdcard_spi_params_t sdcard_spi_params[] = {
{
.spi_dev = SDCARD_SPI_PARAM_SPI,
.cs = SDCARD_SPI_PARAM_CS,
.clk = SDCARD_SPI_PARAM_CLK,
.mosi = SDCARD_SPI_PARAM_MOSI,
.miso = SDCARD_SPI_PARAM_MISO,
.power = SDCARD_SPI_PARAM_POWER,
.power_act_high = SDCARD_SPI_PARAM_POWER_AH
},
};
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* SDCARD_SPI_PARAMS_H */
/** @} */

1086
drivers/sdcard_spi/sdcard_spi.c

File diff suppressed because it is too large Load Diff

4
sys/auto_init/Makefile

@ -8,4 +8,8 @@ ifneq (,$(filter auto_init_saul,$(USEMODULE)))
DIRS += saul
endif
ifneq (,$(filter auto_init_storage,$(USEMODULE)))
DIRS += storage
endif
include $(RIOTBASE)/Makefile.base

11
sys/auto_init/auto_init.c

@ -313,4 +313,15 @@ void auto_init(void)
#endif
#endif /* MODULE_AUTO_INIT_GNRC_RPL */
/* initialize storage devices */
#ifdef MODULE_AUTO_INIT_STORAGE
DEBUG("auto_init STORAGE\n");
#ifdef MODULE_SDCARD_SPI
extern void auto_init_sdcard_spi(void);
auto_init_sdcard_spi();
#endif
#endif /* MODULE_AUTO_INIT_STORAGE */
}

3
sys/auto_init/storage/Makefile

@ -0,0 +1,3 @@
MODULE = auto_init_storage
include $(RIOTBASE)/Makefile.base

55
sys/auto_init/storage/auto_init_sdcard_spi.c

@ -0,0 +1,55 @@
/*
* Copyright (C) 2017 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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 auto_init_sdcard_spi
* @{
*
* @file
* @brief Auto initialization for sd-cards connected over spi
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*/
#ifdef MODULE_SDCARD_SPI
#include "sdcard_spi.h"
#include "sdcard_spi_params.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief number of used sd cards
* @{
*/
#define SDCARD_SPI_NUM (sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0]))
/** @} */
/**
* @brief Allocate memory for the device descriptors
* @{
*/
sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM];
/** @} */
void auto_init_sdcard_spi(void)
{
for (int i = 0; i < SDCARD_SPI_NUM; i++) {
DEBUG("sdcard_spi_auto_init(): initializing device [%i]...\n", i);
int resu = sdcard_spi_init(&sdcard_spi_devs[i], &sdcard_spi_params[i]);
if(resu != 0){
DEBUG("error initializing device [%i]\n", i);
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SDCARD_SPI */
/** @} */

9
tests/driver_sdcard_spi/Makefile

@ -0,0 +1,9 @@
APPLICATION = driver_sdcard_spi
include ../Makefile.tests_common
USEMODULE += sdcard_spi
USEMODULE += auto_init_storage
USEMODULE += fmt
USEMODULE += shell
include $(RIOTBASE)/Makefile.include

369
tests/driver_sdcard_spi/main.c

@ -0,0 +1,369 @@
/*
* Copyright (C) 2016 Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* 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 tests
* @{
*
* @file
* @brief Test application for the sd-card spi driver
*
* @author Michel Rottleuthner <michel.rottleuthner@haw-hamburg.de>
*
* @}
*/
#include "shell.h"
#include "sdcard_spi.h"
#include "sdcard_spi_internal.h"
#include "sdcard_spi_params.h"
#include "fmt.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* independent of what you specify in a r/w cmd this is the maximum number of blocks read at once.
If you call read with a bigger blockcount the read is performed in chunks*/
#define MAX_BLOCKS_IN_BUFFER 4
#define BLOCK_PRINT_BYTES_PER_LINE 16
#define FIRST_PRINTABLE_ASCII_CHAR 0x20
#define ASCII_UNPRINTABLE_REPLACEMENT "."
/* this is provided by the sdcard_spi driver
* see sys/auto_init/storage/auto_init_sdcard_spi.c */
extern sdcard_spi_t sdcard_spi_devs[sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0])];
sdcard_spi_t *card = &sdcard_spi_devs[0];
char buffer[SD_HC_BLOCK_SIZE * MAX_BLOCKS_IN_BUFFER];
static int _init(int argc, char **argv)
{
printf("Initializing SD-card at SPI_%i...", sdcard_spi_params[0].spi_dev);
if (sdcard_spi_init(card, &sdcard_spi_params[0]) != 0) {
puts("[FAILED]");
#if ENABLE_DEBUG != 1
puts("enable debugging in sdcard_spi.c for further information!");
#endif
return -2;
}
puts("[OK]");
return 0;
}
static int _cid(int argc, char **argv)
{
puts("----------------------------------------");
printf("MID: %d\n", card->cid.MID);
printf("OID: %c%c\n", card->cid.OID[0], card->cid.OID[1]);
printf("PNM: %c%c%c%c%c\n", card->cid.PNM[0], card->cid.PNM[1], card->cid.PNM[2],
card->cid.PNM[3], card->cid.PNM[4]);
printf("PRV: %d\n", card->cid.PRV);
printf("PSN: %lu\n", card->cid.PSN);
printf("MDT: %d\n", card->cid.MDT);
printf("CRC: %d\n", card->cid.CID_CRC);
puts("----------------------------------------");
return 0;
}
static int _csd(int argc, char **argv)
{
if (card->csd_structure == SD_CSD_V1) {
puts("CSD V1\n----------------------------------------");
printf("CSD_STRUCTURE: 0x%0lx\n", (unsigned long)card->csd.v1.CSD_STRUCTURE);
printf("TAAC: 0x%0lx\n", (unsigned long)card->csd.v1.TAAC);
printf("NSAC: 0x%0lx\n", (unsigned long)card->csd.v1.NSAC);
printf("TRAN_SPEED: 0x%0lx\n", (unsigned long)card->csd.v1.TRAN_SPEED);
printf("CCC: 0x%0lx\n", (unsigned long)card->csd.v1.CCC);
printf("READ_BL_LEN: 0x%0lx\n", (unsigned long)card->csd.v1.READ_BL_LEN);
printf("READ_BL_PARTIAL: 0x%0lx\n", (unsigned long)card->csd.v1.READ_BL_PARTIAL);
printf("WRITE_BLK_MISALIGN: 0x%0lx\n", (unsigned long)card->csd.v1.WRITE_BLK_MISALIGN);
printf("READ_BLK_MISALIGN: 0x%0lx\n", (unsigned long)card->csd.v1.READ_BLK_MISALIGN);
printf("DSR_IMP: 0x%0lx\n", (unsigned long)card->csd.v1.DSR_IMP);
printf("C_SIZE: 0x%0lx\n", (unsigned long)card->csd.v1.C_SIZE);
printf("VDD_R_CURR_MIN: 0x%0lx\n", (unsigned long)card->csd.v1.VDD_R_CURR_MIN);
printf("VDD_R_CURR_MAX: 0x%0lx\n", (unsigned long)card->csd.v1.VDD_R_CURR_MAX);
printf("VDD_W_CURR_MIN: 0x%0lx\n", (unsigned long)card->csd.v1.VDD_W_CURR_MIN);
printf("VDD_W_CURR_MAX: 0x%0lx\n", (unsigned long)card->csd.v1.VDD_W_CURR_MAX);
printf("C_SIZE_MULT: 0x%0lx\n", (unsigned long)card->csd.v1.C_SIZE_MULT);
printf("ERASE_BLK_EN: 0x%0lx\n", (unsigned long)card->csd.v1.ERASE_BLK_EN);
printf("SECTOR_SIZE: 0x%0lx\n", (unsigned long)card->csd.v1.SECTOR_SIZE);
printf("WP_GRP_SIZE: 0x%0lx\n", (unsigned long)card->csd.v1.WP_GRP_SIZE);
printf("WP_GRP_ENABLE: 0x%0lx\n", (unsigned long)card->csd.v1.WP_GRP_ENABLE);
printf("R2W_FACTOR: 0x%0lx\n", (unsigned long)card->csd.v1.R2W_FACTOR);
printf("WRITE_BL_LEN: 0x%0lx\n", (unsigned long)card->csd.v1.WRITE_BL_LEN);
printf("WRITE_BL_PARTIAL: 0x%0lx\n", (unsigned long)card->csd.v1.WRITE_BL_PARTIAL);
printf("FILE_FORMAT_GRP: 0x%0lx\n", (unsigned long)card->csd.v1.FILE_FORMAT_GRP);
printf("COPY: 0x%0lx\n", (unsigned long)card->csd.v1.COPY);
printf("PERM_WRITE_PROTECT: 0x%0lx\n", (unsigned long)card->csd.v1.PERM_WRITE_PROTECT);
printf("TMP_WRITE_PROTECT: 0x%0lx\n", (unsigned long)card->csd.v1.TMP_WRITE_PROTECT);
printf("FILE_FORMAT: 0x%0lx\n", (unsigned long)card->csd.v1.FILE_FORMAT);
printf("CRC: 0x%0lx\n", (unsigned long)card->csd.v1.CSD_CRC);
}
else if (card->csd_structure == SD_CSD_V2) {
puts("CSD V2:\n----------------------------------------");
printf("CSD_STRUCTURE: 0x%0lx\n", (unsigned long)card->csd.v2.CSD_STRUCTURE);
printf("TAAC: 0x%0lx\n", (unsigned long)card->csd.v2.TAAC);
printf("NSAC: 0x%0lx\n", (unsigned long)card->csd.v2.NSAC);
printf("TRAN_SPEED: 0x%0lx\n", (unsigned long)card->csd.v2.TRAN_SPEED);
printf("CCC: 0x%0lx\n", (unsigned long)card->csd.v2.CCC);
printf("READ_BL_LEN: 0x%0lx\n", (unsigned long)card->csd.v2.READ_BL_LEN);
printf("READ_BL_PARTIAL: 0x%0lx\n", (unsigned long)card->csd.v2.READ_BL_PARTIAL);
printf("WRITE_BLK_MISALIGN: 0x%0lx\n", (unsigned long)card->csd.v2.WRITE_BLK_MISALIGN);
printf("READ_BLK_MISALIGN: 0x%0lx\n", (unsigned long)card->csd.v2.READ_BLK_MISALIGN);
printf("DSR_IMP: 0x%0lx\n", (unsigned long)card->csd.v2.DSR_IMP);
printf("C_SIZE: 0x%0lx\n", (unsigned long)card->csd.v2.C_SIZE);
printf("ERASE_BLK_EN: 0x%0lx\n", (unsigned long)card->csd.v2.ERASE_BLK_EN);
printf("SECTOR_SIZE: 0x%0lx\n", (unsigned long)card->csd.v2.SECTOR_SIZE);
printf("WP_GRP_SIZE: 0x%0lx\n", (unsigned long)card->csd.v2.WP_GRP_SIZE);
printf("WP_GRP_ENABLE: 0x%0lx\n", (unsigned long)card->csd.v2.WP_GRP_ENABLE);
printf("R2W_FACTOR: 0x%0lx\n", (unsigned long)card->csd.v2.R2W_FACTOR);
printf("WRITE_BL_LEN: 0x%0lx\n", (unsigned long)card->csd.v2.WRITE_BL_LEN);
printf("WRITE_BL_PARTIAL: 0x%0lx\n", (unsigned long)card->csd.v2.WRITE_BL_PARTIAL);
printf("FILE_FORMAT_GRP: 0x%0lx\n", (unsigned long)card->csd.v2.FILE_FORMAT_GRP);
printf("COPY: 0x%0lx\n", (unsigned long)card->csd.v2.COPY);
printf("PERM_WRITE_PROTECT: 0x%0lx\n", (unsigned long)card->csd.v2.PERM_WRITE_PROTECT);
printf("TMP_WRITE_PROTECT: 0x%0lx\n", (unsigned long)card->csd.v2.TMP_WRITE_PROTECT);
printf("FILE_FORMAT: 0x%0lx\n", (unsigned long)card->csd.v2.FILE_FORMAT);
printf("CRC: 0x%0lx\n", (unsigned long)card->csd.v2.CSD_CRC);
}
puts("----------------------------------------");
return 0;
}
static int _sds(int argc, char **argv)
{
sd_status_t sds;
if (sdcard_spi_read_sds(card, &sds) == SD_RW_OK) {
puts("SD status:\n----------------------------------------");
printf("SIZE_OF_PROTECTED_AREA: 0x%0lx\n", (unsigned long)sds.SIZE_OF_PROTECTED_AREA);
printf("SUS_ADDR: 0x%0lx\n", (unsigned long)sds.SUS_ADDR);
printf("VSC_AU_SIZE: 0x%0lx\n", (unsigned long)sds.VSC_AU_SIZE);
printf("SD_CARD_TYPE: 0x%0lx\n", (unsigned long)sds.SD_CARD_TYPE);
printf("ERASE_SIZE: 0x%0lx\n", (unsigned long)sds.ERASE_SIZE);
printf("SPEED_CLASS: 0x%0lx\n", (unsigned long)sds.SPEED_CLASS);
printf("PERFORMANCE_MOVE: 0x%0lx\n", (unsigned long)sds.PERFORMANCE_MOVE);
printf("VIDEO_SPEED_CLASS: 0x%0lx\n", (unsigned long)sds.VIDEO_SPEED_CLASS);
printf("ERASE_TIMEOUT: 0x%0lx\n", (unsigned long)sds.ERASE_TIMEOUT);
printf("ERASE_OFFSET: 0x%0lx\n", (unsigned long)sds.ERASE_OFFSET);
printf("UHS_SPEED_GRADE: 0x%0lx\n", (unsigned long)sds.UHS_SPEED_GRADE);
printf("UHS_AU_SIZE: 0x%0lx\n", (unsigned long)sds.UHS_AU_SIZE);
printf("AU_SIZE: 0x%0lx\n", (unsigned long)sds.AU_SIZE);
printf("DAT_BUS_WIDTH: 0x%0lx\n", (unsigned long)sds.DAT_BUS_WIDTH);
printf("SECURED_MODE: 0x%0lx\n", (unsigned long)sds.SECURED_MODE);
puts("----------------------------------------");
return 0;
}
return -1;
}
static int _size(int argc, char **argv)
{
uint64_t bytes = sdcard_spi_get_capacity(card);
uint32_t gib_int = bytes / (SDCARD_SPI_IEC_KIBI * SDCARD_SPI_IEC_KIBI * SDCARD_SPI_IEC_KIBI);
uint32_t gib_frac = ( (((bytes/(SDCARD_SPI_IEC_KIBI * SDCARD_SPI_IEC_KIBI))
- gib_int * SDCARD_SPI_IEC_KIBI) * SDCARD_SPI_SI_KILO)
/ SDCARD_SPI_IEC_KIBI);
uint32_t gb_int = bytes / (SDCARD_SPI_SI_KILO * SDCARD_SPI_SI_KILO * SDCARD_SPI_SI_KILO);
uint32_t gb_frac = (bytes / (SDCARD_SPI_SI_KILO * SDCARD_SPI_SI_KILO))
- (gb_int * SDCARD_SPI_SI_KILO); //[MB]
puts("\nCard size: ");
//fflush(stdout);
print_u64_dec( bytes );
printf(" bytes (%lu,%03lu GiB | %lu,%03lu GB)\n", gib_int, gib_frac, gb_int, gb_frac);
return 0;
}
static int _read(int argc, char **argv)
{
int blockaddr;
int cnt;
bool print_as_char = false;
if ((argc == 3) || (argc == 4)) {
blockaddr = (uint32_t)atoi(argv[1]);
cnt = (uint32_t)atoi(argv[2]);
if (argc == 4 && (strcmp("-c", argv[3]) == 0)) {
print_as_char = true;
}
}
else {
printf("usage: %s blockaddr cnt [-c]\n", argv[0]);
return -1;
}
int total_read = 0;
while (total_read < cnt) {
int chunk_blocks = cnt - total_read;
if (chunk_blocks > MAX_BLOCKS_IN_BUFFER) {
chunk_blocks = MAX_BLOCKS_IN_BUFFER;
}
sd_rw_response_t state;
int chunks_read = sdcard_spi_read_blocks(card, blockaddr + total_read, buffer,
SD_HC_BLOCK_SIZE, chunk_blocks, &state);
if (state != SD_RW_OK) {
printf("read error %d (block %d/%d)\n", state, total_read + chunks_read, cnt);
return -1;
}
for (int i = 0; i < chunk_blocks * SD_HC_BLOCK_SIZE; i++) {
if ((i % SD_HC_BLOCK_SIZE) == 0) {
printf("BLOCK %d:\n", blockaddr + total_read + i / SD_HC_BLOCK_SIZE);
}
if (print_as_char) {
if (buffer[i] >= FIRST_PRINTABLE_ASCII_CHAR) {
printf("%c", buffer[i]);
}
else {
printf(ASCII_UNPRINTABLE_REPLACEMENT);
}
}
else {
printf("%02x ", buffer[i]);
}
if ((i % BLOCK_PRINT_BYTES_PER_LINE) == (BLOCK_PRINT_BYTES_PER_LINE - 1)) {
puts(""); /* line break after BLOCK_PRINT_BYTES_PER_LINE bytes */
}
if ((i % SD_HC_BLOCK_SIZE) == (SD_HC_BLOCK_SIZE - 1)) {
puts(""); /* empty line after each printed block */
}
}
total_read += chunks_read;
}
return 0;
}
static int _write(int argc, char **argv)
{
int bladdr;
char *data;
int size;
bool repeat_data = false;
if (argc == 3 || argc == 4) {
bladdr = (int)atoi(argv[1]);
data = argv[2];
size = strlen(argv[2]);
printf("will write '%s' (%d chars) at start of block %d\n", data, size, bladdr);
if (argc == 4 && (strcmp("-r", argv[3]) == 0)) {
repeat_data = true;
puts("the rest of the block will be filled with copies of that string");
}
else {
puts("the rest of the block will be filled with zeros");
}
}
else {
printf("usage: %s blockaddr string [-r]\n", argv[0]);
return -1;
}
if (size > SD_HC_BLOCK_SIZE) {
printf("maximum stringsize to write at once is %d ...aborting\n", SD_HC_BLOCK_SIZE);
return -1;
}
/* copy data to a full-block-sized buffer an fill remaining block space according to -r param*/
char buffer[SD_HC_BLOCK_SIZE];
for (int i = 0; i < sizeof(buffer); i++) {
if (repeat_data || i < size) {
buffer[i] = data[i % size];
}
else {
buffer[i] = 0;
}
}
sd_rw_response_t state;
int chunks_written = sdcard_spi_write_blocks(card, bladdr, buffer, SD_HC_BLOCK_SIZE, 1, &state);
if (state != SD_RW_OK) {
printf("write error %d (wrote %d/%d blocks)\n", state, chunks_written, 1);
return -1;
}
printf("write block %d [OK]\n", bladdr);
return 0;
}
static int _copy(int argc, char **argv)
{
int src_block;
int dst_block;
char tmp_copy[SD_HC_BLOCK_SIZE];
if (argc != 3) {
printf("usage: %s src_block dst_block\n", argv[0]);
return -1;
}
src_block = (uint32_t)atoi(argv[1]);
dst_block = (uint32_t)atoi(argv[2]);
sd_rw_response_t rd_state;
sdcard_spi_read_blocks(card, src_block, tmp_copy, SD_HC_BLOCK_SIZE, 1, &rd_state);
if (rd_state != SD_RW_OK) {
printf("read error %d (block %d)\n", rd_state, src_block);
return -1;
}
sd_rw_response_t wr_state;
sdcard_spi_write_blocks(card, dst_block, tmp_copy, SD_HC_BLOCK_SIZE, 1, &wr_state);
if (wr_state != SD_RW_OK) {
printf("write error %d (block %d)\n", wr_state, dst_block);
return -2;
}
printf("copy block %d to %d [OK]\n", src_block, dst_block);
return 0;
}
static int _sector_count(int argc, char **argv)
{
printf("available sectors on card: %li\n", sdcard_spi_get_sector_count(card));
return 0;
}
static const shell_command_t shell_commands[] = {
{ "init", "initializes default card", _init },
{ "cid", "print content of CID (Card IDentification) register", _cid },
{ "csd", "print content of CSD (Card-Specific Data) register", _csd },
{ "sds", "print SD status", _sds },
{ "size", "print card size", _size },
{ "sectors", "print sector count of card", _sector_count },
{ "read", "'read n m' reads m blocks beginning at block address n and prints the result. "
"Append -c option to print data readable chars", _read },
{ "write", "'write n data' writes data to block n. Append -r option to "
"repeatedly write data to coplete block", _write },
{ "copy", "'copy src dst' copies block src to block dst", _copy },
{ NULL, NULL, NULL }
};
int main(void)
{
puts("SD-card spi driver test application");
card->init_done = false;
puts("insert SD-card and use 'init' command to set card to spi mode");
puts("WARNING: using 'write' or 'copy' commands WILL overwrite data on your sd-card and");
puts("almost for sure corrupt existing filesystems, partitions and contained data!");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}
Loading…
Cancel
Save