Blame view

RIOT/drivers/include/sdcard_spi.h 13.7 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  /*
   * 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 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 */
      spi_clk_t spi_clk;              /**< active SPI clock speed */
      bool use_block_addr;            /**< true if block adressing (vs. byte adressing) 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 */
  } 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 successfully 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 successfully written blocks (0 if no block was written).
   */
  int sdcard_spi_write_blocks(sdcard_spi_t *card, int blockaddr, const 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 */
  /** @} */