1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/include/sdcard_spi.h

285 lines
14 KiB
C

/*
* 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_storage
* @brief Driver for reading and writing SD Cards using the SPI.
* @anchor drivers_sdcard_spi
* @{
*
* @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
*/
typedef 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 */
} cid_t;
/**
* @brief CSD register with csd structure version 1.0
* see section 5.3.2 in SD-Spec v5.00
*/
typedef 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 */
} csd_v1_t;
/**
* @brief CSD register with csd structure version 2.0
* see section 5.3.3 in SD-Spec v5.00
*/
typedef 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 */
} csd_v2_t;
/**
* @brief CSD register (see section 5.3 in SD-Spec v5.00)
*/
typedef 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 */
} csd_t;
/**
* @brief SD status register (see section 4.10.2 in SD-Spec v5.00)
*/
typedef 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 */
} 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
*/
typedef struct {
const sdcard_spi_params_t *params; /**< parameters for pin and spi config */
spi_clk_t spi_clk; /**< active SPI clock speed */
bool use_block_addr; /**< true if block addressing (vs. byte addressing) is used */
bool init_done; /**< set to true once the init procedure completed successfully */
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 */
} 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 necessary 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 occurred 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 address to read from. Independent of the actual
* addressing scheme of the used card the address needs
* to be given as block address (e.g. 0, 1, 2...
* NOT: 0, 512... ). The driver takes care of mapping
* to byte addressing 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 successfully read blocks (0 if no block was read).
*/
int sdcard_spi_read_blocks(sdcard_spi_t *card, uint32_t blockaddr,
void *data, uint16_t blocksize,
uint16_t 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 address to read from. Independent of the actual
* addressing scheme of the used card the address needs
* to be given as block address (e.g. 0, 1, 2...
* NOT: 0, 512... ). The driver takes care of mapping to
* byte addressing 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 successfully written blocks (0 if no block was written).
*/
int sdcard_spi_write_blocks(sdcard_spi_t *card, uint32_t blockaddr,
const void *data, uint16_t blocksize,
uint16_t 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 */
/** @} */