mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers: added driver for accessing sd_cards over spi
This commit is contained in:
parent
9a38c1085c
commit
ac2ae7cb56
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Normal file
271
drivers/include/sdcard_spi.h
Normal file
@ -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
Normal file
3
drivers/sdcard_spi/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = sdcard_spi
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
243
drivers/sdcard_spi/include/sdcard_spi_internal.h
Normal file
243
drivers/sdcard_spi/include/sdcard_spi_internal.h
Normal file
@ -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
Normal file
77
drivers/sdcard_spi/include/sdcard_spi_params.h
Normal file
@ -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
Normal file
1086
drivers/sdcard_spi/sdcard_spi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
Normal file
3
sys/auto_init/storage/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = auto_init_storage
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
55
sys/auto_init/storage/auto_init_sdcard_spi.c
Normal file
55
sys/auto_init/storage/auto_init_sdcard_spi.c
Normal file
@ -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
Normal file
9
tests/driver_sdcard_spi/Makefile
Normal file
@ -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
Normal file
369
tests/driver_sdcard_spi/main.c
Normal file
@ -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…
Reference in New Issue
Block a user