px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_sd.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2013 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: px_sd.h : SD Card Driver
14 Author(s): Pieter Conradie
15 Creation Date: 2013-06-21
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20
21/* _____PROJECT INCLUDES_____________________________________________________ */
22#include "px_sd.h"
23#include "px_spi.h"
24#include "px_board.h"
25#include "px_log.h"
26
27/* _____LOCAL DEFINITIONS____________________________________________________ */
28PX_LOG_NAME("px_sd");
29
30/// SD SPI commands
31#define PX_SD_CMD0_GO_IDLE_STATE 0 ///< Reset all cards to idle state
32#define PX_SD_CMD1_SEND_OP_COND 1 ///< Send host capacitity support info and activate init
33#define PX_SD_CMD6_SWITCH_FUNC 6 ///< Check switchable function and switches card function
34#define PX_SD_CMD8_SEND_IF_COND 8 ///< Send interface condition
35#define PX_SD_CMD9_SEND_CSD 9 ///< Request Card Specific Data
36#define PX_SD_CMD10_SEND_CID 10 ///< Request Card Identification
37#define PX_SD_CMD12_STOP_TRANSMISSION 12 ///< Stop transmission in Multiple Block Read operation
38#define PX_SD_CMD13_SEND_STATUS 13 ///< Request status register
39#define PX_SD_CMD16_SET_BLOCKLEN 16 ///< Set block length for SDSC cards; fixed for SDHC and SDXC cards
40#define PX_SD_CMD17_READ_SINGLE_BLOCK 17 ///< Read a block of size selected with PX_SD_CMD16_SET_BLOCKLEN
41#define PX_SD_CMD18_READ_MULT_BLOCK 18 ///< Continuously transfers data blocks until stopped with PX_SD_CMD12_STOP_TRANSMISSION
42#define PX_SD_CMD24_WRITE_BLOCK 24 ///< Write a block of size selected with PX_SD_CMD16_SET_BLOCKLEN
43#define PX_SD_CMD25_WRITE_MULT_BLOCK 25 ///< Continuously writes data blocks until stopped with 'Stop Tran' token
44#define PX_SD_CMD27_PROGRAM_CSD 27 ///< Program programmable bits of the CSD
45#define PX_SD_CMD28_SET_WRITE_PROT 28 ///< Sets write protection bits if supported by card
46#define PX_SD_CMD29_CLR_WRITE_PROT 29 ///< Clears write protection bits if supported by card
47#define PX_SD_CMD30_SEND_WRITE_PROT 30 ///< Requests status of write protection bits if supported by card
48#define PX_SD_CMD32_ERASE_WR_BLK_START_ADR 32 ///< Sets the address of the first write block to be erased
49#define PX_SD_CMD33_ERASE_WR_BLK_END_ADR 33 ///< Sets the address of the last write block to be erased
50#define PX_SD_CMD38_ERASE 38 ///< Erases all previously selected write blocks
51#define PX_SD_CMD42_LOCK_UNLOCK 42 ///< Used to Set/Reset the password or lock/unlock the card
52#define PX_SD_CMD48_READ_EXTR_SINGLE 48 ///< Used to read xtension register
53#define PX_SD_CMD49_WRITE_EXTR_SINGLE 49 ///< Used to write extension register
54#define PX_SD_CMD55_APP_CMD 55 ///< Next command is an application specific command
55#define PX_SD_CMD56_GEN_CMD 56 ///< Used either to transfer a Data Block to the card or to get a Data Block from the card for general purpose/application specific commands
56#define PX_SD_CMD58_READ_OCR 58 ///< Read the OCR register
57#define PX_SD_CMD59_CRC_ON_OFF 59 ///< Turn the CRC option on or off
58
59
60/// SD SPI application specific command marker bit
61#define PX_SD_ACMD_MARKER_BIT 7
62
63/// SD SPI application specific commands (after PX_SD_CMD55_APP_CMD)
64#define PX_SD_ACMD13_SD_STATUS ((1 << PX_SD_ACMD_MARKER_BIT) + 13) ///< Request the SD Status
65#define PX_SD_ACMD22_SEND_NUM_WR_BLOCKS ((1 << PX_SD_ACMD_MARKER_BIT) + 22) ///< Send the number of the well written (without errors) blocks
66#define PX_SD_ACMD23_SET_WR_BLOCK_COUNT ((1 << PX_SD_ACMD_MARKER_BIT) + 23) ///< Set the number of write blocks to be pre-erased before writing
67#define PX_SD_ACMD41_SD_SEND_OP_COND ((1 << PX_SD_ACMD_MARKER_BIT) + 41) ///< Send host capacity support information and activate init
68#define PX_SD_ACMD42_SET_CLR_CARD_DETECT ((1 << PX_SD_ACMD_MARKER_BIT) + 42) ///< Connect / Disconnect the 50 KOhm pull-up resistor on CS
69#define PX_SD_ACMD51_SEND_SCR ((1 << PX_SD_ACMD_MARKER_BIT) + 51) ///< Read the SD Configuration Register
70
71/// SD R1 response bits
72#define PX_SD_RESP_R1_START_BIT 7 ///< Start bit of response is always '0'
73#define PX_SD_RESP_R1_ERR_PARAM 6 ///< The command's argument (e.g. address, block length) was outside the allowed range for this card
74#define PX_SD_RESP_R1_ERR_ADR 5 ///< A misaligned address that did not match the block length was used in the command
75#define PX_SD_RESP_R1_ERR_ERASE_SEQ 4 ///< An error in the sequence of erase commands occurred
76#define PX_SD_RESP_R1_ERR_COM_CRC 3 ///< The CRC check of the last command failed
77#define PX_SD_RESP_R1_ILLEGAL_CMD 2 ///< An illegal command code was detected
78#define PX_SD_RESP_R1_ERASE_RESET 1 ///< An erase sequence was cleared before executing because an out of erase sequence command was received
79#define PX_SD_RESP_R1_IDLE_STATE 0 ///< The card is in idle state and running the initializing process
80
81/// Data block tokens
82#define PX_SD_TOKEN_DATA_BLOCK_START 0xfe ///< Start block token for Single Block Read (CMD17), Multiple Block Read (CMD18) and Single Block Write (CMD24
83#define PX_SD_TOKEN_DATA_BLOCK_START_MULT_WR 0xfc ///< Start block token for Multiple Block Write (CMD25)
84#define PX_SD_TOKEN_DATA_BLOCK_STOP_MULT_WR 0xfd ///< Stop transaction token for Multiple Block Write (CMD25)
85
86/// Data response token
87#define PX_SD_TOKEN_DATA_RESP_MASK 0x1f
88#define PX_SD_TOKEN_DATA_RESP_DATA_OK 0x05 ///< Data accepted
89#define PX_SD_TOKEN_DATA_RESP_CRC_ERROR 0x0b ///< Data rejected due to a CRC error
90#define PX_SD_TOKEN_DATA_RESP_WRITE_ERROR 0x0d ///< Data Rejected due to a Write Error
91
92/* _____MACROS_______________________________________________________________ */
93
94/* _____GLOBAL VARIABLES_____________________________________________________ */
95
96/* _____LOCAL VARIABLES______________________________________________________ */
97static px_spi_handle_t * px_spi_handle_sd;
98static uint8_t px_sd_rx_data[4];
99static px_sd_card_type_t px_sd_card_type;
100
101/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
102
103/* _____LOCAL FUNCTIONS______________________________________________________ */
104static uint8_t px_sd_spi_xc_u8(uint8_t data)
105{
106 uint8_t data_tx[1];
107 uint8_t data_rx[1];
108
109 data_tx[0] = data;
110 px_spi_xc(px_spi_handle_sd, data_tx, data_rx, 1, 0);
111
112 return data_rx[0];
113}
114
115static uint8_t px_sd_spi_rd_u8(void)
116{
117 return px_sd_spi_xc_u8(0xff);
118}
119
120static void px_sd_spi_rd(void *data, size_t nr_of_bytes)
121{
122 uint8_t * data_u8 = (uint8_t *)data;
123 while(nr_of_bytes != 0)
124 {
125 *data_u8++ = px_sd_spi_rd_u8();
126 nr_of_bytes--;
127 }
128}
129
130static void px_sd_spi_wr_u8(uint8_t data)
131{
132 px_sd_spi_xc_u8(data);
133}
134
135static void px_sd_spi_wr(const void * data, size_t nr_of_bytes)
136{
137 const uint8_t * data_u8 = (uint8_t * )data;
138 while(nr_of_bytes != 0)
139 {
140 px_sd_spi_xc_u8(*data_u8++);
141 nr_of_bytes--;
142 }
143}
144
145static void px_sd_spi_cs_lo(void)
146{
147 px_spi_wr(px_spi_handle_sd, NULL, 0, PX_SPI_FLAG_START);
148}
149
150static void px_sd_spi_cs_end(void)
151{
152 // Deselect SD card to end previous transaction
153 px_spi_wr(px_spi_handle_sd, NULL, 0, PX_SPI_FLAG_STOP);
154 // Provide 8 clocks for SD Card state machine
155 px_sd_spi_rd_u8();
156}
157
158static bool px_sd_wait_ready(void)
159{
160 uint16_t retry;
161
162 // Wait up to 500 ms for SD card to be ready (not busy)
163 for(retry = 5000; retry != 0; retry--)
164 {
165 if(px_sd_spi_rd_u8() == 0xff)
166 {
167 return true;
168 }
169 // Wait 100 us
171 }
172 // Timed-out
173 PX_LOG_E("Timed-out waiting for SD card to be ready");
174 return false;
175}
176
177static uint8_t px_sd_tx_cmd_rx_resp_r1(uint8_t cmd, uint32_t arg)
178{
179 uint8_t r1;
180 uint8_t retry;
181
182 // application specific command?
183 if(PX_BIT_IS_HI(cmd, PX_SD_ACMD_MARKER_BIT))
184 {
185 // Signal to the card that the next command is an application specific
186 // command rather than a standard command.
187 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD55_APP_CMD, 0);
188 // start bit = 1 or any error bit set? (ignore idle state bit)
189 if((r1 & ~(1 << PX_SD_RESP_R1_IDLE_STATE)) != 0)
190 {
191 PX_LOG_E("CMD55 received R1 = 0x%02x", r1);
192 return r1;
193 }
194 // Remove marker
195 PX_BIT_SET_LO(cmd, PX_SD_ACMD_MARKER_BIT);
196 }
197
198 // End previous transaction
199 px_sd_spi_cs_end();
200 PX_LOG_D("CMD%d(%08lX)", cmd, arg);
201
202 // Select SD card to start next transaction
203 px_sd_spi_cs_lo();
204 // Dummy clock until card is ready (not busy).
205 if(!px_sd_wait_ready())
206 {
207 // Card not ready
208 return 0xff;
209 }
210 // Send command index with start bit = 0 (bit 47); transmission bit = 1 (bit 46)
211 px_sd_spi_wr_u8(0x40 | cmd);
212 // Send 32-bit argument
213 px_sd_spi_wr_u8(PX_U32_HI8(arg));
214 px_sd_spi_wr_u8(PX_U32_MH8(arg));
215 px_sd_spi_wr_u8(PX_U32_ML8(arg));
216 px_sd_spi_wr_u8(PX_U32_LO8(arg));
217 // Send CRC and end bit = 1 (bit 0)
218 switch(cmd)
219 {
220 case PX_SD_CMD0_GO_IDLE_STATE:
221 // Valid 7-bit CRC for CMD0 (arg = 0x00000000)
222 px_sd_spi_wr_u8(0x95);
223 break;
224 case PX_SD_CMD8_SEND_IF_COND:
225 // Valid 7-bit CRC for CMD8 (arg = 0x000001aa)
226 px_sd_spi_wr_u8(0x87);
227 break;
228 default:
229 // Invalid 7-bit CRC for other commands
230 px_sd_spi_rd_u8();
231 break;
232 }
233
234 // Try 8 times to receive valid R1 response (start bit = 0)
235 for(retry = 8; retry != 0; retry--)
236 {
237 r1 = px_sd_spi_rd_u8();
238 // Start bit = 0?
239 if(PX_BIT_IS_LO(r1, PX_SD_RESP_R1_START_BIT))
240 {
241 break;
242 }
243 }
244 // Timeout?
245 if(retry == 0)
246 {
247 PX_LOG_E("Timed out waiting for R1 response (received 0x%02x)", r1);
248 }
249 else
250 {
251 PX_LOG_D("R1 = 0x%02X", r1);
252 }
253
254 // Return response
255 return r1;
256}
257
258static uint8_t px_sd_rx_data_block(uint8_t * data, size_t nr_of_bytes)
259{
260 uint16_t retry;
261 uint8_t data_token;
262 uint8_t px_crc_hi, px_crc_lo;
263
264 // Receive data token with 100 ms timeout
265 for(retry = 1000; retry != 0; retry--)
266 {
267 data_token = px_sd_spi_rd_u8();
268 if(data_token != 0xff)
269 {
270 PX_LOG_D("Data token = %02hX", data_token);
271 break;
272 }
273 // Wait 100 us
275 }
276 // Timeout?
277 if(retry == 0)
278 {
279 PX_LOG_E("Timed-out waiting for data token");
280 return 0xff;
281 }
282 // Receive data block
283 px_sd_spi_rd(data, nr_of_bytes);
284 // Receive CRC
285 px_crc_hi = px_sd_spi_rd_u8();
286 px_crc_lo = px_sd_spi_rd_u8();
288 {
289 PX_LOG_D("CRC = %02hX %02hX", px_crc_hi, px_crc_lo);
290 }
291 else
292 {
293 // Stop compiler warning about unused variables
294 (void)px_crc_hi;
295 (void)px_crc_lo;
296 }
297
298 return data_token;
299}
300
301static uint8_t px_sd_tx_data_block(const uint8_t * data, size_t nr_of_bytes, uint8_t data_token_start)
302{
303 uint8_t data_token;
304
305 // Wait for SD card to be ready (not busy)
306 if(!px_sd_wait_ready())
307 {
308 return 0xff;
309 }
310 // Send start data token
311 px_sd_spi_wr_u8(data_token_start);
312 // Send data block
313 px_sd_spi_wr(data, nr_of_bytes);
314 // Send dummy CRC
315 px_sd_spi_rd_u8();
316 px_sd_spi_rd_u8();
317 // Return data response token
318 data_token = px_sd_spi_rd_u8();
319 PX_LOG_D("Data response token = 0x%02X", data_token);
320
321 return data_token;
322}
323
324/* _____GLOBAL FUNCTIONS_____________________________________________________ */
326{
327 // Save SPI slave device handle
328 px_spi_handle_sd = handle;
329}
330
331bool px_sd_reset(void)
332{
333 uint8_t r1, retry;
334 uint16_t wait;
335
336 // Card type not determined yet
337 px_sd_card_type = PX_SD_CARD_TYPE_INVALID;
338 // Change to bit rate equal or below 400 kHz
339 px_spi_change_baud(px_spi_handle_sd, px_spi_util_baud_hz_to_clk_div(400000));
340 // Wait 1 ms
341 px_board_delay_us(1000);
342 // Card requires at least 74 clocks to start up
343 PX_LOG_D("80 Clocks");
344 for(retry = 10; retry != 0 ; retry--)
345 {
346 px_sd_spi_rd_u8();
347 }
348 // Execute CMD0+ (CMD0 with CS asserted) to put SD card into SPI operation mode
349 for(retry = 100; retry != 0; retry--)
350 {
351 // Send CMD0+ (CMD0 with CS asserted)
352 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD0_GO_IDLE_STATE, 0);
353 // SD Card in idle state?
354 if(r1 == (1 << PX_SD_RESP_R1_IDLE_STATE))
355 {
356 break;
357 }
358 }
359 // Timeout?
360 if(retry == 0)
361 {
362 PX_LOG_E("Unable to put SD Card in idle state (R1 = 0x%02X)", r1);
363 px_sd_spi_cs_end();
364 return false;
365 }
366
367 /*
368 * Execute CMD8 to initialise SD cards compliant with Physical Layer
369 * Specification Version 2.00 or later.
370 *
371 * Voltage supplied (VHS) = 0001b (2.7-3.6V)
372 * Check pattern = 0xaa
373 */
374 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD8_SEND_IF_COND, 0x000001aa);
375 // Did card respond correctly?
376 if(r1 == (1 << PX_SD_RESP_R1_IDLE_STATE))
377 {
378 // Ver 2.00 or later SD Card
379 PX_LOG_D("Ver 2.00 or later SD Card");
380 // Receive rest of R7 response
381 px_sd_spi_rd(px_sd_rx_data, 4);
382 if( (px_sd_rx_data[2] != 0x01) // Voltage accepted 2.7-3.6V
383 ||(px_sd_rx_data[3] != 0xaa) ) // Verify check pattern
384 {
385 // Report error
386 if(px_sd_rx_data[2] != 0x01)
387 {
388 PX_LOG_E("Voltage not accepted (received 0x%02X)", px_sd_rx_data[2]);
389 }
390 if(px_sd_rx_data[3] != 0xaa)
391 {
392 PX_LOG_E("Expected 0xaa, but received 0x%02X echo", px_sd_rx_data[3]);
393 }
394 px_sd_spi_cs_end();
395 return false;
396 }
397
398 // Explicitely disable CRC, even though spec says that it is disabled by default
399 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD59_CRC_ON_OFF, 0);
400 if(r1 != (1 << PX_SD_RESP_R1_IDLE_STATE))
401 {
402 PX_LOG_E("Incorrect response to CMD59 (R1 = 0x%02X)", r1);
403 px_sd_spi_cs_end();
404 return false;
405 }
406
407 for(wait = 1000; wait != 0; wait--)
408 {
409 /*
410 * Send host capacity support information and activate the
411 * card's initialization process.
412 *
413 * HCS = 1 (indicate that host supports SDHC or SDXC Card)
414 */
415 if(px_sd_tx_cmd_rx_resp_r1(PX_SD_ACMD41_SD_SEND_OP_COND, (1ul << 30)) == 0)
416 {
417 // Read the Operation Conditions Register (OCR) of the card
418 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD58_READ_OCR, 0);
419 // Init finished (not in idle state)?
420 if(r1 == 0)
421 {
422 // Receive rest of R3 response
423 px_sd_spi_rd(px_sd_rx_data, 4);
424 PX_LOG_D("OCR = 0x%02x%02x%02x%02x",
425 px_sd_rx_data[0], px_sd_rx_data[1],
426 px_sd_rx_data[2], px_sd_rx_data[3]);
427 // Is Card Capacity Status (CCS) bit 30 set?
428 if(px_sd_rx_data[0] & (1 << 6))
429 {
430 PX_LOG_D("Ver 2.00 HCSD or XCSD Card");
431 px_sd_card_type = PX_SD_CARD_TYPE_VER_2_HCSD_XCSD;
432 }
433 else
434 {
435 PX_LOG_D("Ver 2.00 SCSD Card");
436 px_sd_card_type = PX_SD_CARD_TYPE_VER_2_SCSD;
437 }
438 }
439 else
440 {
441 PX_LOG_E("Incorrect response to CMD58 (R1 = 0x%02X)", r1);
442 px_sd_spi_cs_end();
443 return false;
444 }
445 break;
446 }
447 // Wait 1 ms
448 px_board_delay_us(1000);
449 }
450 // Timed-out?
451 if(wait == 0)
452 {
453 PX_LOG_E("Timed out waiting for ACMD41 init to finish");
454 px_sd_spi_cs_end();
455 return false;
456 }
457 }
458 else
459 {
460 // Ver 1.xx SD Card (or not?)
461 PX_LOG_D("Ver 1.xx SD Card (or not?)");
462 // Explicitely disable CRC, even though spec says that it is disabled by default
463 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD59_CRC_ON_OFF, 0);
464 if(r1 != (1 << PX_SD_RESP_R1_IDLE_STATE))
465 {
466 PX_LOG_E("Incorrect response to CMD59 (R1 = 0x%02X)", r1);
467 px_sd_spi_cs_end();
468 return false;
469 }
470
471 for(wait = 1000; wait != 0; wait--)
472 {
473 /*
474 * Send host capacity support information and activate the
475 * card's initialization process.
476 *
477 * HCS = 0
478 */
479 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_ACMD41_SD_SEND_OP_COND, 0);
480 // Init finished?
481 if(r1 == 0)
482 {
483 break;
484 }
485 // Wait 1 ms
486 px_board_delay_us(1000);
487 }
488 // Timed-out?
489 if(wait == 0)
490 {
491 PX_LOG_E("Timed out waiting for ACMD41 init to finish (R1 = 0x%02X)", r1);
492 px_sd_spi_cs_end();
493 return false;
494 }
495 // Set R/W block length to 512 bytes
496 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD16_SET_BLOCKLEN, PX_SD_BLOCK_SIZE);
497 if (r1 != 0)
498 {
499 PX_LOG_E("Incorrect response to CMD16 (R1 = 0x%02X)", r1);
500 px_sd_spi_cs_end();
501 return false;
502 }
503 PX_LOG_D("Ver 1.xx SD Card");
504 px_sd_card_type = PX_SD_CARD_TYPE_VER_1_SD;
505 }
506
507 // Change to maximum bit rate
509
510 px_sd_spi_cs_end();
511 return true;
512}
513
515{
516 uint8_t r1, data_token;
517
518 // Send CMD10 to read CID
519 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD10_SEND_CID, 0);
520 // Any error bit set?
521 if(r1 != 0)
522 {
523 PX_LOG_E("Incorrect response to CMD10 (R1 = 0x%02X)", r1);
524 px_sd_spi_cs_end();
525 return false;
526 }
527 // Receive data block
528 data_token = px_sd_rx_data_block((uint8_t *) cid, sizeof(*cid));
529 if(data_token != PX_SD_TOKEN_DATA_BLOCK_START)
530 {
531 px_sd_spi_cs_end();
532 return false;
533 }
534 px_sd_spi_cs_end();
535
536 return true;
537}
538
540{
541 uint8_t r1, data_token;
542
543 // Send CMD9 to read CSD
544 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD9_SEND_CSD, 0);
545 // Any error bit set?
546 if(r1 != 0)
547 {
548 PX_LOG_E("Incorrect response to CMD9 (R1 = 0x%02X)", r1);
549 px_sd_spi_cs_end();
550 return false;
551 }
552 // Receive data block
553 data_token = px_sd_rx_data_block((uint8_t *) csd, sizeof(*csd));
554 if(data_token != PX_SD_TOKEN_DATA_BLOCK_START)
555 {
556 PX_LOG_E("Incorrect data token (received 0x%02X)", data_token);
557 px_sd_spi_cs_end();
558 return false;
559 }
560 px_sd_spi_cs_end();
561
563 {
564 PX_LOG_D("CSD: \t");
565 PX_LOG_TRACE_DATA(csd, sizeof(px_sd_csd_t));
566 PX_LOG_TRACE("\n");
567 }
568 return true;
569}
570
571bool px_sd_get_status(uint16_t * status)
572{
573 uint8_t r1, r2;
574
575 // Send CMD13 to get status
576 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD13_SEND_STATUS, 0);
577 // Any error bit set?
578 if(PX_BIT_IS_HI(r1, PX_SD_RESP_R1_START_BIT))
579 {
580 PX_LOG_E("Incorrect response to CMD13 (R1 = 0x%02X)", r1);
581 px_sd_spi_cs_end();
582 return false;
583 }
584 // Read second part of response
585 r2 = px_sd_spi_rd_u8();
586 // Combine R1 and R2
587 *status = ((uint16_t)r1<<8) + r2;
588 // End operation
589 px_sd_spi_cs_end();
590 return true;
591}
592
594{
595 uint32_t capacity = 0;
596 uint8_t n;
597
598 PX_LOG_D("csd_structure = %02X", csd->csd_structure);
599 if(csd->csd_structure == 0) // CSD Structure version 1.0?
600 {
601 PX_LOG_D("read_bl_len = %02hX", csd->read_bl_len);
602 PX_LOG_D("c_size_mult_hi = %02hX", csd->ver.csd_1_0.c_size_mult_hi);
603 PX_LOG_D("c_size_mult_lo = %02hX", csd->ver.csd_1_0.c_size_mult_lo);
604
605 // READ_BL_LEN + C_SIZE_MULT + 2
606 n = csd->read_bl_len
607 + (csd->ver.csd_1_0.c_size_mult_hi << 1)
608 + csd->ver.csd_1_0.c_size_mult_lo + 2;
609
610 PX_LOG_D("n = %02hX", n);
611
612 PX_LOG_D("c_size_hi = %02hX", csd->ver.csd_1_0.c_size_hi);
613 PX_LOG_D("c_size_mid = %02hX", csd->ver.csd_1_0.c_size_mid);
614 PX_LOG_D("c_size_lo = %02hX", csd->ver.csd_1_0.c_size_lo);
615
616 // C_SIZE + 1
617 capacity = ( ((uint16_t)csd->ver.csd_1_0.c_size_hi << 10)
618 | ((uint16_t)csd->ver.csd_1_0.c_size_mid << 2)
619 | (csd->ver.csd_1_0.c_size_lo ) )
620 + 1;
621
622 PX_LOG_D("capacity = %08lX", capacity);
623
624 // (C_SIZE + 1) * 2 ^ (READ_BL_LEN + C_SIZE_MULT + 2) / 512
625 capacity = capacity << (n - 9);
626
627 PX_LOG_D("capacity = %08lX", capacity);
628 }
629 else if(csd->csd_structure == 1) // CSD Structure version 2.0?
630 {
631 PX_LOG_D("c_size_hi = %02hX", csd->ver.csd_2_0.c_size_hi);
632 PX_LOG_D("c_size_mid = %02hX", csd->ver.csd_2_0.c_size_mid);
633 PX_LOG_D("c_size_lo = %02hX", csd->ver.csd_2_0.c_size_lo);
634
635 // C_SIZE + 1
636 capacity = ((uint32_t)csd->ver.csd_2_0.c_size_hi << 16)
637 | ((uint16_t)csd->ver.csd_2_0.c_size_mid << 8)
638 | (csd->ver.csd_2_0.c_size_lo + 1);
639
640 PX_LOG_D("capacity = %08lX", capacity);
641
642 // Memory capacity = (C_SIZE + 1) * 512 KByte
643 // Size in blocks = (C_SIZE + 1) * 512 KByte / 0.5 KByte
644 capacity <<= 10;
645
646 PX_LOG_D("capacity = %08lX", capacity);
647 }
648
649 return capacity;
650}
651
652bool px_sd_rd_block(uint8_t * data, uint32_t block_adr)
653{
654 uint8_t r1, data_token;
655
656 PX_LOG_ASSERT(px_sd_card_type != PX_SD_CARD_TYPE_INVALID);
657
658 // Standard Capacity card?
659 if(px_sd_card_type != PX_SD_CARD_TYPE_VER_2_HCSD_XCSD)
660 {
661 // Multiply with block size of 512
662 block_adr *= PX_SD_BLOCK_SIZE;
663 }
664 // Send CMD17 for single block read
665 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD17_READ_SINGLE_BLOCK, block_adr);
666 // Any error bit set?
667 if(r1 != 0)
668 {
669 PX_LOG_E("Incorrect response to CMD17 (R1 = 0x%02X)", r1);
670 px_sd_spi_cs_end();
671 return false;
672 }
673 // Receive data block
674 data_token = px_sd_rx_data_block(data, PX_SD_BLOCK_SIZE);
675 if(data_token != PX_SD_TOKEN_DATA_BLOCK_START)
676 {
677 px_sd_spi_cs_end();
678 return false;
679 }
680 // Success
681 px_sd_spi_cs_end();
682 return true;
683}
684
685uint8_t px_sd_rd_blocks(uint8_t * data, uint32_t block_adr, uint8_t nr_of_blocks)
686{
687 uint8_t r1, data_token, blocks_read;
688
689 PX_LOG_ASSERT(px_sd_card_type != PX_SD_CARD_TYPE_INVALID);
690
691 if(nr_of_blocks == 0)
692 {
693 return 0;
694 }
695 if(nr_of_blocks == 1)
696 {
697 // Read single block
698 if(px_sd_rd_block(data, block_adr))
699 {
700 return 1;
701 }
702 else
703 {
704 return 0;
705 }
706 }
707 // Standard Capacity card?
708 if(px_sd_card_type != PX_SD_CARD_TYPE_VER_2_HCSD_XCSD)
709 {
710 // Multiply with block size of 512
711 block_adr *= PX_SD_BLOCK_SIZE;
712 }
713 // Send CMD18 for multiple block read
714 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD18_READ_MULT_BLOCK, block_adr);
715 // Any error bit set?
716 if(r1 != 0)
717 {
718 PX_LOG_E("Incorrect response to CMD18 (R1 = 0x%02X)", r1);
719 px_sd_spi_cs_end();
720 return 0;
721 }
722
723 for(blocks_read = 0; blocks_read < nr_of_blocks; blocks_read++)
724 {
725 // Receive data block
726 data_token = px_sd_rx_data_block(data, PX_SD_BLOCK_SIZE);
727 if(data_token != PX_SD_TOKEN_DATA_BLOCK_START)
728 {
729 break;
730 }
731 // Next block
732 data += PX_SD_BLOCK_SIZE;
733 }
734
735 // Send CMD12 to stop multiple block read operation
736 px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD12_STOP_TRANSMISSION, 0);
737
738 // Success
739 px_sd_spi_cs_end();
740 return blocks_read;
741}
742
743bool px_sd_wr_block(const uint8_t * data, uint32_t block_adr)
744{
745 uint8_t r1, data_resp_token;
746
747 PX_LOG_ASSERT(px_sd_card_type != PX_SD_CARD_TYPE_INVALID);
748
749 // Standard Capacity card?
750 if(px_sd_card_type != PX_SD_CARD_TYPE_VER_2_HCSD_XCSD)
751 {
752 // Multiply with block size of 512
753 block_adr *= PX_SD_BLOCK_SIZE;
754 }
755 // Send CMD24 for single block write
756 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD24_WRITE_BLOCK, block_adr);
757 // Any error bit set?
758 if(r1 != 0)
759 {
760 PX_LOG_E("Incorrect response to CMD24 (R1 = 0x%02X)", r1);
761 px_sd_spi_cs_end();
762 return false;
763 }
764 // Send data block
765 data_resp_token = px_sd_tx_data_block(data, PX_SD_BLOCK_SIZE, PX_SD_TOKEN_DATA_BLOCK_START);
766 // data token correct?
767 if((data_resp_token & PX_SD_TOKEN_DATA_RESP_MASK) != PX_SD_TOKEN_DATA_RESP_DATA_OK)
768 {
769 PX_LOG_E("Data response token = 0x%02X", data_resp_token);
770 px_sd_spi_cs_end();
771 return false;
772 }
773
774 // Success
775 px_sd_spi_cs_end();
776 return true;
777}
778
779uint8_t px_sd_wr_blocks(const uint8_t * data, uint32_t block_adr, uint8_t nr_of_blocks)
780{
781 uint8_t r1, data_resp_token, blocks_written;
782
783 PX_LOG_D("px_sd_write_blocks(%04X, %08lX, %hd)", data, block_adr, nr_of_blocks);
784 PX_LOG_ASSERT(px_sd_card_type != PX_SD_CARD_TYPE_INVALID);
785
786 if(nr_of_blocks == 0)
787 {
788 return 0;
789 }
790 if(nr_of_blocks == 1)
791 {
792 // Write single block
793 if(px_sd_wr_block(data, block_adr))
794 {
795 return 1;
796 }
797 else
798 {
799 return 0;
800 }
801 }
802 // Standard Capacity card?
803 if(px_sd_card_type != PX_SD_CARD_TYPE_VER_2_HCSD_XCSD)
804 {
805 // Multiply with block size of 512
806 block_adr *= PX_SD_BLOCK_SIZE;
807 }
808 // Send CMD25 for multiple block write
809 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD25_WRITE_MULT_BLOCK, block_adr);
810 // Any error bit set?
811 if(r1 != 0)
812 {
813 PX_LOG_E("Incorrect response to CMD25 (R1 = 0x%02X)", r1);
814 px_sd_spi_cs_end();
815 return 0;
816 }
817 // Send ACMD23 to set block erase count to number of block about to be written
818 r1 = px_sd_tx_cmd_rx_resp_r1(PX_SD_ACMD23_SET_WR_BLOCK_COUNT, nr_of_blocks);
819 // Any error bit set?
820 if(r1 != 0)
821 {
822 PX_LOG_E("Incorrect response to ACMD23 (R1 = 0x%02X)", r1);
823 px_sd_spi_cs_end();
824 return 0;
825 }
826
827 for(blocks_written = 0; blocks_written < nr_of_blocks; blocks_written++)
828 {
829 // Send data block
830 data_resp_token = px_sd_tx_data_block(data, PX_SD_BLOCK_SIZE, PX_SD_TOKEN_DATA_BLOCK_START_MULT_WR);
831
832 // data token correct?
833 if((data_resp_token & PX_SD_TOKEN_DATA_RESP_MASK) != PX_SD_TOKEN_DATA_RESP_DATA_OK)
834 {
835 PX_LOG_E("Data response token = 0x%02X", data_resp_token);
836
837 // Send CMD12 to stop multiple block write operation
838 px_sd_tx_cmd_rx_resp_r1(PX_SD_CMD12_STOP_TRANSMISSION, 0);
839
840 px_sd_spi_cs_end();
841 return blocks_written;
842 }
843
844 // Next block
845 data += PX_SD_BLOCK_SIZE;
846 }
847
848 // Wait for SD card to be ready (not busy)
849 px_sd_wait_ready();
850 // Send stop data token
851 px_sd_spi_xc_u8(PX_SD_TOKEN_DATA_BLOCK_STOP_MULT_WR);
852 px_sd_spi_cs_end();
853
854 PX_LOG_D("%hd block(s) written", blocks_written);
855 return blocks_written;
856}
857
859{
860 bool flag;
861
862 // Select SD card
863 px_spi_wr(px_spi_handle_sd, NULL, 0, PX_SPI_FLAG_START);
864 // Dummy clock until card is ready (not busy).
865 flag = px_sd_wait_ready();
866 px_spi_wr(px_spi_handle_sd, NULL, 0, PX_SPI_FLAG_STOP);
867
868 return flag;
869}
void px_board_delay_us(uint16_t delay_us)
Blocking delay for specified number of microseconds.
Definition: px_board.c:222
#define NULL
NULL pointer.
Definition: px_defs.h:49
#define PX_U32_LO8(data)
Extract the low 8 bits (bits 7..0) of a 32-bit value.
Definition: px_defs.h:240
#define PX_U32_HI8(data)
Extract the high 8 bits (bits 31..24) of a 32-bit value.
Definition: px_defs.h:231
#define PX_BIT_IS_LO(var, bit)
Test if a bit is cleared (0?)
Definition: px_defs.h:190
#define PX_U32_MH8(data)
Extract the middle high 8 bits (bits 23..16) of a 32-bit value.
Definition: px_defs.h:234
#define PX_U32_ML8(data)
Extract the middle low 8 bits (bits 15..8) of a 32-bit value.
Definition: px_defs.h:237
#define PX_BIT_SET_LO(var, bit)
Clear a bit (0)
Definition: px_defs.h:181
#define PX_BIT_IS_HI(var, bit)
Test if a bit is set (1?)
Definition: px_defs.h:187
#define PX_LOG_D(format,...)
Macro to display a formatted DEBUG message.
Definition: px_log.h:410
#define PX_LOG_TRACE(format,...)
Macro to output a user format string if PX_LOG=1.
Definition: px_log.h:458
#define PX_LOG_TRACE_DATA(data, nr_of_bytes)
Macro to output the content of a buffer if PX_LOG=1.
Definition: px_log.h:476
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
Definition: px_log.h:349
#define PX_LOG_LEVEL_IS_D()
Debug level enabled?
Definition: px_log.h:371
#define PX_LOG_E(format,...)
Macro to display a formatted ERROR message.
Definition: px_log.h:377
#define PX_LOG_ASSERT(expression)
Macro that will test an expression, and block indefinitely if false.
Definition: px_log.h:440
uint8_t csd_structure
CSD structure version 1.0 or 2.0.
Definition: px_sd.h:87
uint8_t read_bl_len
max. read data block length
Definition: px_sd.h:97
bool px_sd_reset(void)
Detect and reset SD card.
Definition: px_sd.c:331
#define PX_SD_BLOCK_SIZE
Size of each data block.
Definition: px_sd.h:56
bool px_sd_rd_block(uint8_t *data, uint32_t block_adr)
Read a data block from the SD card.
Definition: px_sd.c:652
uint8_t px_sd_wr_blocks(const uint8_t *data, uint32_t block_adr, uint8_t nr_of_blocks)
Write a number of data blocks to the SD card.
Definition: px_sd.c:779
#define PX_SD_MAX_SPI_CLOCK_HZ
Maximum SPI Clock rate.
Definition: px_sd.h:47
bool px_sd_wait_wr_is_finished(void)
Wait up to 500 ms for write block transaction to finish.
Definition: px_sd.c:858
void px_sd_init(px_spi_handle_t *handle)
Initialise driver.
Definition: px_sd.c:325
bool px_sd_rd_cid(px_sd_cid_t *cid)
Read Card ID Register.
Definition: px_sd.c:514
bool px_sd_wr_block(const uint8_t *data, uint32_t block_adr)
Write a data block to the SD card.
Definition: px_sd.c:743
uint32_t px_sd_get_capacity_in_blocks(const px_sd_csd_t *csd)
Extract and calculate card capacity from Card Specific Data (CSD).
Definition: px_sd.c:593
bool px_sd_get_status(uint16_t *status)
Read Card Status.
Definition: px_sd.c:571
bool px_sd_rd_csd(px_sd_csd_t *csd)
Read Card Specific Data.
Definition: px_sd.c:539
uint8_t px_sd_rd_blocks(uint8_t *data, uint32_t block_adr, uint8_t nr_of_blocks)
Read a number of data blocks from the SD card.
Definition: px_sd.c:685
CID - Card ID register; Ref 1. Paragraph "5.2 CID Register", page 113.
Definition: px_sd.h:69
CSD - Card Specific Data register; Paragraph "5.3 CSD Register", page 114.
Definition: px_sd.h:84
#define PX_SPI_FLAG_START
Begin SPI transaction (take SPI slave's Chip Select line low)
Definition: px_spi.h:117
void px_spi_xc(px_spi_handle_t *handle, const void *data_wr, void *data_rd, size_t nr_of_bytes, uint8_t flags)
Perform an SPI exchange (write and read) transaction with an SPI slave.
Definition: px_spi.c:568
void px_spi_wr(px_spi_handle_t *handle, const void *data, size_t nr_of_bytes, uint8_t flags)
Perform an SPI write transaction with an SPI slave.
Definition: px_spi.c:396
void px_spi_change_baud(px_spi_handle_t *handle, px_spi_baud_t baud)
Change SPI peripheral baud.
Definition: px_spi.c:657
#define PX_SPI_FLAG_STOP
Finish SPI transaction (take SPI slave's Chip Select line high)
Definition: px_spi.h:119
px_spi_baud_t px_spi_util_baud_hz_to_clk_div(uint32_t baud_hz)
Calculate clock divisor that will yield closest frequency equal to or less than specified baud rate (...
Definition: px_spi.c:698
Define SPI handle.
Definition: px_spi.h:126