GPS Device
Loading...
Searching...
No Matches
SD Internal Helpers

Functions

static ERR_te sd_send_cmd (SPI_REGDEF_ts *spi_instance, uint8_t index, uint32_t arg, bool acmd, CMD_RESPONSE_ts *cmd_response_o)
 Transmits a single SPI-mode SD command and receives the response.
static ERR_te sd_cease_comms (SD_HANDLE_ts *sd_handle, bool deinit)
 Raises CS, sends two dummy bytes, and disables SPI. Optionally deinitializes the handle.
static ERR_te sd_go_idle_state (SD_HANDLE_ts *sd_handle)
 Issues CMD0 to reset the SD card into idle (SPI) mode.
static ERR_te sd_send_if_cond (SD_HANDLE_ts *sd_handle, bool *match_o, bool *no_resp_o)
 Issues CMD8 to determine whether the card is SD Ver.2 or older.
static ERR_te sd_app_send_op_cond (SD_HANDLE_ts *sd_handle, uint32_t arg)
 Issues ACMD41 to initiate SD card initialization (SD Ver.2 and Ver.1).
static ERR_te sd_read_ocr (SD_HANDLE_ts *sd_handle)
 Reads the OCR register via CMD58 and stores power-up status, addressing mode, and voltage range.
static ERR_te sd_send_op_cond (SD_HANDLE_ts *sd_handle)
 Issues CMD1 to initiate MMC Ver.3 card initialization.
static ERR_te sd_set_blocklen (SD_HANDLE_ts *sd_handle)
 Issues CMD16 to set the block length to 512 bytes for byte-addressed cards.
static ERR_te sd_read_csd (SD_HANDLE_ts *sd_handle)
 Issues CMD9 to read the CSD register and stores capacity information in the handle.
static ERR_te decode_csd_v1 (const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o)
 Decodes a CSD v1.0 register (SDSC cards) into a SD_CSD_INFO_ts structure.
static ERR_te decode_csd_v2 (const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o)
 Decodes a CSD v2.0 register (SDHC/SDXC cards) into a SD_CSD_INFO_ts structure.

Detailed Description

Function Documentation

◆ sd_send_cmd()

ERR_te sd_send_cmd ( SPI_REGDEF_ts * spi_instance,
uint8_t index,
uint32_t arg,
bool acmd,
CMD_RESPONSE_ts * cmd_response_o )
static

Transmits a single SPI-mode SD command and receives the response.

Builds the 6-byte command frame (start bit | index, 4-byte argument, CRC), transmits it over SPI, and receives the R1 response byte. For application- specific commands (ACMD), CMD55 is sent first automatically.

Trailing response bytes are handled per command:

  • R1 only: CMD0, CMD1, CMD9, CMD10, CMD16, CMD17, CMD18, CMD23, CMD24, CMD25, CMD41, CMD55
  • R3 (4 extra bytes, OCR): CMD58
  • R7 (4 extra bytes, interface condition): CMD8
  • R1B (busy polling): CMD12 — discards stuff byte, then polls until card releases MISO

CRC is required for CMD0 (0x95) and CMD8 (0x87); dummy CRC (0x00) is used for all other commands, as CRC checking is disabled after initialization.

Parameters
[in]spi_instancePointer to the SPI peripheral to use.
[in]indexCommand index (0–63, without the 0x40 start bit).
[in]arg32-bit command argument.
[in]acmdIf true, CMD55 is sent before this command to prefix it as an application-specific command.
[out]cmd_response_oPointer to the response structure to populate.
Returns
  • ERR_OK on success
  • ERR_TIMEOUT if R1 or R1B is not received within the configured timeout
  • Propagated error from the CMD55 prefix call if acmd is true

Definition at line 1131 of file sd.c.

1131 {
1132 ERR_te err;
1133 uint32_t start_time;
1134 uint32_t elapsed_time;
1135
1136 uint8_t crc = 0x00;
1137 uint8_t cmd[6];
1138
1139 if(acmd) {
1140 CMD_RESPONSE_ts dummy;
1141 err = sd_send_cmd(spi_instance, 55, 0, false, &dummy);
1142 if(err != ERR_OK) {
1143 LOG_ERROR(
1144 internal_state.subsys,
1146 "sd_send_cmd: unknown error"
1147 );
1148
1149 return err;
1150 }
1151 }
1152
1153 if(index == 0x00) {
1154 crc = 0x95; // CMD0 requires valid CRC
1155 }
1156 else if(index == 0x08) {
1157 crc = 0x87; // CMD8 requires valid CRC
1158 }
1159
1160 cmd[0] = 0x40 | index;
1161 cmd[1] = (arg >> 24) & 0xFF;
1162 cmd[2] = (arg >> 16) & 0xFF;
1163 cmd[3] = (arg >> 8) & 0xFF;
1164 cmd[4] = arg & 0xFF;
1165 cmd[5] = crc;
1166
1167 spi_send(spi_instance, cmd, sizeof(cmd));
1168
1169 // CMD12 requires discarding the first byte (stuff byte) before the R1 response
1170 if(index == 12) {
1171 uint8_t stuff_byte;
1172 spi_receive(spi_instance, &stuff_byte, 1);
1173 }
1174
1175 uint8_t r1 = 0xFF;
1176 start_time = systick_get_ms();
1177
1178 do {
1179 spi_receive(spi_instance, &r1, 1);
1180 elapsed_time = systick_get_ms() - start_time;
1181 } while ((r1 & 0x80) && elapsed_time <= CONFIG_SD_R1_RESP_TIMEOUT);
1182
1183 cmd_response_o->r1 = r1;
1184
1185 if(elapsed_time > CONFIG_SD_R1_RESP_TIMEOUT) {
1186 LOG_ERROR(
1187 internal_state.subsys,
1189 "sd_send_cmd: timed out"
1190 );
1191
1192 return ERR_TIMEOUT;
1193 }
1194
1195 if(
1196 index == 0 || index == 1 || index == 41 || index == 9 ||
1197 index == 10 || index == 16 || index == 17 || index == 18 ||
1198 index == 23 || index == 24 || index == 25 || index == 55
1199 ) {
1200 // R1 only — zero unused fields
1201 memset(cmd_response_o->r3, 0, sizeof(cmd_response_o->r3));
1202 memset(cmd_response_o->r7, 0, sizeof(cmd_response_o->r7));
1203 }
1204 else if(index == 58) {
1205 // R3 (OCR) — receive 4 trailing bytes
1206 memset(cmd_response_o->r7, 0, sizeof(cmd_response_o->r7));
1207 spi_receive(spi_instance, cmd_response_o->r3, 4);
1208 }
1209 else if(index == 8) {
1210 // R7 (interface condition) — receive 4 trailing bytes
1211 memset(cmd_response_o->r3, 0, sizeof(cmd_response_o->r3));
1212 spi_receive(spi_instance, cmd_response_o->r7, 4);
1213 }
1214 else if(index == 12) {
1215 // R1B — poll until card releases MISO (busy signal ends)
1216 memset(cmd_response_o->r3, 0, sizeof(cmd_response_o->r3));
1217 memset(cmd_response_o->r7, 0, sizeof(cmd_response_o->r7));
1218
1219 uint8_t rx = 0x00;
1220 start_time = systick_get_ms();
1221
1222 do {
1223 spi_receive(spi_instance, &rx, 1);
1224 elapsed_time = systick_get_ms() - start_time;
1225 } while(rx == 0x00 && elapsed_time <= CONFIG_SD_R1B_RESP_TIMEOUT);
1226
1227 if(elapsed_time > CONFIG_SD_R1B_RESP_TIMEOUT) {
1228 LOG_ERROR(
1229 internal_state.subsys,
1231 "sd_send_cmd: timed out"
1232 );
1233
1234 return ERR_TIMEOUT;
1235 }
1236 }
1237
1238 return ERR_OK;
1239}
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
uint32_t systick_get_ms(void)
Returns the number of milliseconds elapsed since SysTick was initialized.
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_OK
Definition err.h:36
@ ERR_TIMEOUT
Definition err.h:52
#define LOG_ERROR(subsys, lvl, fmt,...)
Definition log.h:258
@ LOG_LEVEL_ERROR
Definition log.h:67
static ERR_te sd_send_cmd(SPI_REGDEF_ts *spi_instance, uint8_t index, uint32_t arg, bool acmd, CMD_RESPONSE_ts *cmd_response_o)
Transmits a single SPI-mode SD command and receives the response.
Definition sd.c:1131
void spi_send(SPI_REGDEF_ts *spi_instance, uint8_t *tx_buffer, uint32_t len)
Blocking SPI transmit. Sends len bytes from tx_buffer.
void spi_receive(SPI_REGDEF_ts *spi_instance, uint8_t *rx_buffer, uint32_t len)
Blocking SPI receive. Reads len bytes into rx_buffer.
Holds the R1, R3, and R7 response bytes returned by the SD card after a command.
Definition sd.c:39
uint8_t r1
Definition sd.c:40
uint8_t r3[4]
Definition sd.c:41
uint8_t r7[4]
Definition sd.c:42
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_cease_comms()

ERR_te sd_cease_comms ( SD_HANDLE_ts * sd_handle,
bool deinit )
static

Raises CS, sends two dummy bytes, and disables SPI. Optionally deinitializes the handle.

Called after every completed or failed SPI transaction to return the bus to an idle state. When deinit is true, temporarily sets the handle's initialized flag to allow sd_deinit_handle to run, then calls it to release the pool slot.

Parameters
[in]sd_handlePointer to the SD card handle.
[in]deinitIf true, deinitializes the handle after ending communication.
Returns
  • ERR_OK always

Definition at line 1256 of file sd.c.

1256 {
1257 gpio_write(sd_handle->cs_gpio_port, sd_handle->cs_gpio_pin, HIGH);
1258
1259 uint8_t dummy[2] = { 0xFF, 0xFF };
1260 spi_send(sd_handle->spi_instance, dummy, 2);
1261
1262 spi_set_comm(sd_handle->spi_instance, DISABLE);
1263
1264 if(deinit) {
1265 // Bypass init guard to allow sd_deinit_handle to proceed
1266 sd_handle->initialized = true;
1267 sd_deinit_handle(sd_handle);
1268 }
1269
1270 return ERR_OK;
1271}
@ HIGH
Definition common.h:89
@ DISABLE
Definition common.h:97
ERR_te sd_deinit_handle(SD_HANDLE_ts *sd_handle)
Deinitializes an SD card handle and resets the SPI peripheral.
Definition sd.c:727
void gpio_write(GPIO_REGDEF_ts *gpio_port, uint8_t gpio_pin, PIN_STATUS_te pin_status)
Drives a GPIO output pin high or low.
void spi_set_comm(SPI_REGDEF_ts *spi_instance, EN_STATUS_te en_status)
Enables or disables the SPI peripheral (SPE bit).
bool initialized
Definition sd.c:234
GPIO_REGDEF_ts * cs_gpio_port
Definition sd.c:218
GPIO_PIN_te cs_gpio_pin
Definition sd.c:222
SPI_REGDEF_ts * spi_instance
Definition sd.c:216
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_go_idle_state()

ERR_te sd_go_idle_state ( SD_HANDLE_ts * sd_handle)
static

Issues CMD0 to reset the SD card into idle (SPI) mode.

Retries up to CONFIG_SD_CMD_SEND_ERROR_RETRY_NUM times with CONFIG_SD_CMD_SEND_ERROR_RETRY_LATENCY ms between attempts. Succeeds when R1 bit 0 (idle state) is set.

Parameters
[in]sd_handlePointer to the SD card handle.
Returns
  • ERR_OK on success
  • ERR_UNSUCCESFUL_ACTION if the card does not enter idle state within the retry limit

Definition at line 1287 of file sd.c.

1287 {
1288 ERR_te err;
1289 CMD_RESPONSE_ts cmd_response = { 0 };
1290
1291 uint8_t retries = 0;
1292 do {
1293 retries++;
1294 err = sd_send_cmd(sd_handle->spi_instance, 0, 0, false, &cmd_response);
1295 if(err != ERR_OK || !(cmd_response.r1 & 0x01)) {
1296 LOG_ERROR(
1297 internal_state.subsys,
1298 internal_state.log_level,
1299 "sd_go_idle_state: command execution failure, retry %d/%d in %d ms",
1300 retries, CONFIG_SD_CMD_SEND_ERROR_RETRY_NUM, CONFIG_SD_CMD_SEND_ERROR_RETRY_LATENCY
1301 );
1302 DELAY(CONFIG_SD_CMD_SEND_ERROR_RETRY_LATENCY);
1303 }
1304 } while ((err != ERR_OK || !(cmd_response.r1 & 0x01)) && retries < CONFIG_SD_CMD_SEND_ERROR_RETRY_NUM);
1305
1306 if(err != ERR_OK || !(cmd_response.r1 & 0x01)) {
1307 LOG_ERROR(
1308 internal_state.subsys,
1309 internal_state.log_level,
1310 "sd_go_idle_state: command execution failure"
1311 );
1312
1314 }
1315
1316 return ERR_OK;
1317}
#define DELAY(ms)
Blocking delay using the system tick counter.
Definition common.h:65
@ ERR_UNSUCCESFUL_ACTION
Definition err.h:51
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_send_if_cond()

ERR_te sd_send_if_cond ( SD_HANDLE_ts * sd_handle,
bool * match_o,
bool * no_resp_o )
static

Issues CMD8 to determine whether the card is SD Ver.2 or older.

Sends CMD8 with the standard voltage argument 0x000001AA.

  • If the R7 response echoes 0x000001AA, the card is SD Ver.2 and match_o is set.
  • If CMD8 times out, the card is SD Ver.1 or MMC and no_resp_o is set.
  • If the R7 does not match, the card is incompatible and an error is returned.
Parameters
[in]sd_handlePointer to the SD card handle.
[out]match_oSet to true if R7 echoes 0x000001AA (SD Ver.2).
[out]no_resp_oSet to true if CMD8 produces no response (SD Ver.1 / MMC).
Returns
  • ERR_OK on success (either match or no response)
  • ERR_INITIALIZATION_FAILURE if R7 does not match the expected echo

Definition at line 1336 of file sd.c.

1336 {
1337 ERR_te err;
1338 CMD_RESPONSE_ts cmd_response = { 0 };
1339
1340 err = sd_send_cmd(sd_handle->spi_instance, 8, 0x000001AA, false, &cmd_response);
1341 if(err != ERR_OK) {
1342 *no_resp_o = true;
1343
1344 return ERR_OK;
1345 }
1346
1347 uint8_t expected[] = { 0x00, 0x00, 0x01, 0xAA };
1348 for(uint8_t i = 0; i < 4; i++) {
1349 if(cmd_response.r7[i] != expected[i]) {
1350 LOG_ERROR(
1351 internal_state.subsys,
1352 internal_state.log_level,
1353 "sd_send_if_cond: initialization failure"
1354 );
1355
1357 }
1358 }
1359
1360 *match_o = true;
1361
1362 return ERR_OK;
1363}
@ ERR_INITIALIZATION_FAILURE
Definition err.h:43
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_app_send_op_cond()

ERR_te sd_app_send_op_cond ( SD_HANDLE_ts * sd_handle,
uint32_t arg )
static

Issues ACMD41 to initiate SD card initialization (SD Ver.2 and Ver.1).

Retries up to CONFIG_SD_INVALID_RESP_RETRY_NUM times while R1 equals 0x01 (still initializing). Pass arg = 0x40000000 for SD Ver.2 (HCS bit set) or arg = 0 for SD Ver.1.

Parameters
[in]sd_handlePointer to the SD card handle.
[in]argACMD41 argument. Use 0x40000000 for SDHC support, 0x00000000 for SDSC only.
Returns
  • ERR_OK on success
  • ERR_TIMEOUT if the R1 response is not received within timeout
  • ERR_INITIALIZATION_FAILURE if the card does not complete initialization within the retry limit

Definition at line 1383 of file sd.c.

1383 {
1384 ERR_te err;
1385 CMD_RESPONSE_ts cmd_response = { 0 };
1386 uint32_t retries = 0;
1387
1388 do {
1389 retries++;
1390 err = sd_send_cmd(sd_handle->spi_instance, 41, arg, true, &cmd_response);
1391 if(err == ERR_TIMEOUT) {
1392 LOG_ERROR(
1393 internal_state.subsys,
1394 internal_state.log_level,
1395 "sd_app_send_op_cond: R1 response timeout"
1396 );
1397
1398 return ERR_TIMEOUT;
1399 }
1400
1401 if(cmd_response.r1 != 0x00) {
1402 LOG_ERROR(
1403 internal_state.subsys,
1404 internal_state.log_level,
1405 "sd_app_send_op_cond: invalid R1 response, retry %d/%d in %d ms",
1406 retries, CONFIG_SD_INVALID_RESP_RETRY_NUM, CONFIG_SD_INVALID_RESP_RETRY_TIMEOUT
1407 );
1408 DELAY(CONFIG_SD_INVALID_RESP_RETRY_TIMEOUT);
1409 }
1410 } while(cmd_response.r1 == 0x01 && retries < CONFIG_SD_INVALID_RESP_RETRY_NUM);
1411
1412 if(cmd_response.r1 != 0x00) {
1413 LOG_ERROR(
1414 internal_state.subsys,
1415 internal_state.log_level,
1416 "sd_app_send_op_cond: initialization failure"
1417 );
1418
1420 }
1421
1422 return ERR_OK;
1423}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_read_ocr()

ERR_te sd_read_ocr ( SD_HANDLE_ts * sd_handle)
static

Reads the OCR register via CMD58 and stores power-up status, addressing mode, and voltage range.

Reconstructs the 32-bit OCR value from the 4-byte R3 response and extracts: power-up completion flag (SD_PWRUP_STATUS_te), Card Capacity Status (block vs byte addressing), and the supported voltage window (stored but not currently used for filtering).

Parameters
[in]sd_handlePointer to the SD card handle.
Returns
  • ERR_OK on success
  • ERR_UNSUCCESFUL_ACTION if CMD58 fails

Definition at line 1440 of file sd.c.

1440 {
1441 ERR_te err;
1442 CMD_RESPONSE_ts cmd_response = { 0 };
1443
1444 err = sd_send_cmd(sd_handle->spi_instance, 58, 0, false, &cmd_response);
1445 if(err != ERR_OK) {
1446 LOG_ERROR(
1447 internal_state.subsys,
1448 internal_state.log_level,
1449 "sd_read_ocr: failed to read ocr"
1450 );
1451
1453 }
1454
1455 uint32_t ocr =
1456 ((uint32_t)cmd_response.r3[0] << 24) |
1457 ((uint32_t)cmd_response.r3[1] << 16) |
1458 ((uint32_t)cmd_response.r3[2] << 8) |
1459 ((uint32_t)cmd_response.r3[3]);
1460
1461 sd_handle->pwrup_status = ((ocr >> OCR_PWRUP_STATUS) & 0x1) ?
1463
1464 sd_handle->addr_mode = ((ocr >> OCR_CAPACITY_STATUS) & 0x1) ?
1466
1467 bool voltage_low_found = false;
1468 for(uint8_t ocr_counter = 4; ocr_counter < 24; ocr_counter++) {
1469 if((ocr >> ocr_counter) & 0x1 && !voltage_low_found) {
1470 sd_handle->min_operating_voltage = (SD_MIN_OPERATING_VOLTAGE_te)(23 - ocr_counter);
1471 voltage_low_found = true;
1472 }
1473 else if((ocr >> ocr_counter) & 0x1 && voltage_low_found) {
1474 sd_handle->max_operating_voltage = (SD_MAX_OPERATIING_VOLTAGE_te)(23 - ocr_counter);
1475 }
1476 }
1477
1478 return ERR_OK;
1479}
SD_MIN_OPERATING_VOLTAGE_te
Minimum allowed operating voltage of the SD card, decoded from the OCR register.
Definition sd.c:82
SD_MAX_OPERATIING_VOLTAGE_te
Maximum allowed operating voltage of the SD card, decoded from the OCR register.
Definition sd.c:108
@ SD_PWRUP_STATUS_BUSY
Definition sd.c:143
@ SD_PWRUP_STATUS_READY
Definition sd.c:144
@ OCR_PWRUP_STATUS
Definition sd.c:76
@ OCR_CAPACITY_STATUS
Definition sd.c:75
@ SD_ADDR_MODE_BYTE
Definition sd.c:135
@ SD_ADDR_MODE_BLOCK
Definition sd.c:136
SD_MAX_OPERATIING_VOLTAGE_te max_operating_voltage
Definition sd.c:230
SD_MIN_OPERATING_VOLTAGE_te min_operating_voltage
Definition sd.c:229
SD_ADDR_MODE_te addr_mode
Definition sd.c:227
SD_PWRUP_STATUS_te pwrup_status
Definition sd.c:226
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_send_op_cond()

ERR_te sd_send_op_cond ( SD_HANDLE_ts * sd_handle)
static

Issues CMD1 to initiate MMC Ver.3 card initialization.

Used as a fallback when ACMD41 fails (card is MMC, not SD). Retries while R1 equals 0x01 (still initializing).

Parameters
[in]sd_handlePointer to the SD card handle.
Returns
  • ERR_OK on success
  • ERR_TIMEOUT if the R1 response is not received within timeout
  • ERR_INITIALIZATION_FAILURE if the card does not complete initialization

Definition at line 1495 of file sd.c.

1495 {
1496 ERR_te err;
1497 CMD_RESPONSE_ts cmd_response = { 0 };
1498 uint32_t retries = 0;
1499
1500 do {
1501 retries++;
1502 err = sd_send_cmd(sd_handle->spi_instance, 1, 0, false, &cmd_response);
1503 if(err == ERR_TIMEOUT) {
1504 LOG_ERROR(
1505 internal_state.subsys,
1506 internal_state.log_level,
1507 "sd_send_op_cond: R1 response timeout"
1508 );
1509
1510 return ERR_TIMEOUT;
1511 }
1512 } while(cmd_response.r1 == 0x01 && retries < CONFIG_SD_INVALID_RESP_RETRY_NUM);
1513
1514 if(cmd_response.r1 != 0x00) {
1515 LOG_ERROR(
1516 internal_state.subsys,
1517 internal_state.log_level,
1518 "sd_send_op_cond: initialization failure"
1519 );
1520
1522 }
1523
1524 return ERR_OK;
1525}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_set_blocklen()

ERR_te sd_set_blocklen ( SD_HANDLE_ts * sd_handle)
static

Issues CMD16 to set the block length to 512 bytes for byte-addressed cards.

Only called for SDSC (byte-addressed) cards. SDHC cards always use a fixed 512-byte block length and do not require this command.

Parameters
[in]sd_handlePointer to the SD card handle.
Returns
  • ERR_OK on success
  • ERR_UNSUCCESFUL_ACTION if CMD16 fails or the card returns a non-zero R1

Definition at line 1540 of file sd.c.

1540 {
1541 ERR_te err;
1542 CMD_RESPONSE_ts cmd_response = { 0 };
1543
1544 err = sd_send_cmd(sd_handle->spi_instance, 16, 0x00000200, false, &cmd_response);
1545 if(err != ERR_OK) {
1546 LOG_ERROR(
1547 internal_state.subsys,
1548 internal_state.log_level,
1549 "sd_set_blocklen: failed to set block length"
1550 );
1551
1553 }
1554
1555 if(cmd_response.r1 != 0x00)
1557
1558 return ERR_OK;
1559}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_read_csd()

ERR_te sd_read_csd ( SD_HANDLE_ts * sd_handle)
static

Issues CMD9 to read the CSD register and stores capacity information in the handle.

Waits for the data token (0xFE), reads the 16-byte CSD register, and dispatches to decode_csd_v1 or decode_csd_v2 based on the CSD structure version field. CSD version 3 is treated as v2. The resulting sd_handle_s::capacity_mb, sd_handle_s::block_count, and sd_handle_s::block_len fields are populated from the decoded data.

Parameters
[in]sd_handlePointer to the SD card handle.
Returns
  • ERR_OK on success
  • ERR_UNSUCCESFUL_ACTION if CMD9 fails or the data token times out

Definition at line 1577 of file sd.c.

1577 {
1578 ERR_te err;
1579 CMD_RESPONSE_ts cmd_response = { 0 };
1580 uint8_t csd_raw[16];
1581 SD_CSD_INFO_ts csd_info = { 0 };
1582
1583 err = sd_send_cmd(sd_handle->spi_instance, 9, 0, false, &cmd_response);
1584 if (err != ERR_OK || cmd_response.r1 != 0x00) {
1585 LOG_ERROR(internal_state.subsys, internal_state.log_level,
1586 "sd_read_csd: failed to send CMD9");
1588 }
1589
1590 uint8_t token = 0;
1591 uint32_t start_time = systick_get_ms();
1592 uint32_t elapsed_time = 0;
1593
1594 do {
1595 spi_receive(sd_handle->spi_instance, &token, 1);
1596 elapsed_time = systick_get_ms() - start_time;
1597 } while (token != 0xFE && elapsed_time <= CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT);
1598
1599 if (elapsed_time > CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT || token != 0xFE) {
1600 LOG_ERROR(internal_state.subsys, internal_state.log_level,
1601 "sd_read_csd: timeout waiting for data token");
1603 }
1604
1605 memset(csd_raw, 0, sizeof(csd_raw));
1606 spi_receive(sd_handle->spi_instance, csd_raw, 16);
1607
1608 uint8_t crc[2];
1609 spi_receive(sd_handle->spi_instance, crc, 2);
1610
1611 memset(&csd_info, 0, sizeof(SD_CSD_INFO_ts));
1612
1613 uint8_t csd_structure = extract_bits(csd_raw, 126, 2);
1614
1615 switch (csd_structure) {
1616 case 0:
1617 decode_csd_v1(csd_raw, &csd_info);
1618 break;
1619 case 1:
1620 decode_csd_v2(csd_raw, &csd_info);
1621 break;
1622 case 3:
1623 decode_csd_v2(csd_raw, &csd_info);
1624 // SDHC newer version — treated as v2
1625 break;
1626 }
1627
1628 sd_handle->capacity_mb = csd_info.capacity_mb;
1629 sd_handle->block_count = csd_info.block_count;
1630 sd_handle->block_len = csd_info.block_len;
1631
1632 return ERR_OK;
1633}
uint32_t extract_bits(const uint8_t *data, uint16_t start_bit, uint8_t num_bits)
Extracts a range of bits from a big-endian byte array.
Definition common.c:369
static ERR_te decode_csd_v1(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o)
Decodes a CSD v1.0 register (SDSC cards) into a SD_CSD_INFO_ts structure.
Definition sd.c:1652
static ERR_te decode_csd_v2(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o)
Decodes a CSD v2.0 register (SDHC/SDXC cards) into a SD_CSD_INFO_ts structure.
Definition sd.c:1706
Decoded contents of the SD card CSD register.
Definition sd.c:163
uint32_t block_count
Definition sd.c:167
uint32_t capacity_mb
Definition sd.c:165
uint16_t block_len
Definition sd.c:166
uint32_t block_count
Definition sd.c:232
uint32_t capacity_mb
Definition sd.c:233
uint32_t block_len
Definition sd.c:231
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode_csd_v1()

ERR_te decode_csd_v1 ( const uint8_t * csd_raw,
SD_CSD_INFO_ts * csd_info_o )
static

Decodes a CSD v1.0 register (SDSC cards) into a SD_CSD_INFO_ts structure.

Extracts all fields from the 16-byte big-endian CSD register using extract_bits and computes derived values:

  • block_len = 2^READ_BL_LEN
  • block_count = (C_SIZE + 1) × 2^(C_SIZE_MULT + 2)
  • capacity_bytes = block_count × block_len
  • capacity_mb = capacity_bytes / (1024 × 1024)
Parameters
[in]csd_rawPointer to the 16-byte raw CSD register data.
[out]csd_info_oPointer to the structure that will receive the decoded fields.
Returns
  • ERR_OK always

Definition at line 1652 of file sd.c.

1652 {
1653 csd_info_o->csd_structure = extract_bits(csd_raw, 126, 2);
1654 csd_info_o->taac = extract_bits(csd_raw, 112, 8);
1655 csd_info_o->nsac = extract_bits(csd_raw, 104, 8);
1656 csd_info_o->tran_speed = extract_bits(csd_raw, 96, 8);
1657 csd_info_o->ccc = extract_bits(csd_raw, 84, 12);
1658 csd_info_o->v1.read_bl_len = extract_bits(csd_raw, 80, 4);
1659 csd_info_o->read_bl_partial = extract_bits(csd_raw, 79, 1);
1660 csd_info_o->write_blk_misalign = extract_bits(csd_raw, 78, 1);
1661 csd_info_o->read_blk_misalign = extract_bits(csd_raw, 77, 1);
1662 csd_info_o->dsr_imp = extract_bits(csd_raw, 76, 1);
1663 csd_info_o->v1.c_size = extract_bits(csd_raw, 62, 12);
1664 csd_info_o->v1.c_size_mult = extract_bits(csd_raw, 47, 3);
1665 csd_info_o->erase_blk_en = extract_bits(csd_raw, 46, 1);
1666 csd_info_o->sector_size = extract_bits(csd_raw, 39, 7);
1667 csd_info_o->wp_grp_size = extract_bits(csd_raw, 32, 7);
1668 csd_info_o->wp_grp_enable = extract_bits(csd_raw, 31, 1);
1669 csd_info_o->r2w_factor = extract_bits(csd_raw, 26, 3);
1670 csd_info_o->write_bl_len = extract_bits(csd_raw, 22, 4);
1671 csd_info_o->write_bl_partial = extract_bits(csd_raw, 21, 1);
1672 csd_info_o->file_format_grp = extract_bits(csd_raw, 15, 1);
1673 csd_info_o->copy = extract_bits(csd_raw, 14, 1);
1674 csd_info_o->perm_write_protect = extract_bits(csd_raw, 13, 1);
1675 csd_info_o->tmp_write_protect = extract_bits(csd_raw, 12, 1);
1676 csd_info_o->file_format = extract_bits(csd_raw, 10, 2);
1677 csd_info_o->wp_upc = extract_bits(csd_raw, 9, 1);
1678 csd_info_o->crc = extract_bits(csd_raw, 1, 7);
1679
1680 csd_info_o->block_len = 1 << csd_info_o->v1.read_bl_len;
1681 uint32_t mult = 1 << (csd_info_o->v1.c_size_mult + 2);
1682 csd_info_o->block_count = (csd_info_o->v1.c_size + 1) * mult;
1683 csd_info_o->capacity_bytes = csd_info_o->block_count * csd_info_o->block_len;
1684 csd_info_o->capacity_mb = csd_info_o->capacity_bytes / (1024 * 1024);
1685
1686 return ERR_OK;
1687}
uint8_t wp_grp_enable
Definition sd.c:193
uint8_t read_blk_misalign
Definition sd.c:188
struct SD_CSD_INFO_ts::@241120010163000272306350371036221161033372031231 v1
uint8_t copy
Definition sd.c:198
uint8_t wp_grp_size
Definition sd.c:192
uint8_t read_bl_len
Definition sd.c:176
uint8_t perm_write_protect
Definition sd.c:199
uint8_t tmp_write_protect
Definition sd.c:200
uint8_t csd_structure
Definition sd.c:170
uint8_t file_format_grp
Definition sd.c:197
uint8_t taac
Definition sd.c:184
uint8_t write_bl_partial
Definition sd.c:196
uint8_t wp_upc
Definition sd.c:202
uint8_t nsac
Definition sd.c:185
uint16_t ccc
Definition sd.c:169
uint32_t capacity_bytes
Definition sd.c:164
uint8_t crc
Definition sd.c:203
uint8_t read_bl_partial
Definition sd.c:186
uint8_t sector_size
Definition sd.c:191
uint8_t c_size_mult
Definition sd.c:175
uint8_t write_bl_len
Definition sd.c:195
uint8_t dsr_imp
Definition sd.c:189
uint8_t file_format
Definition sd.c:201
uint8_t r2w_factor
Definition sd.c:194
uint8_t erase_blk_en
Definition sd.c:190
uint8_t tran_speed
Definition sd.c:168
uint8_t write_blk_misalign
Definition sd.c:187
uint16_t c_size
Definition sd.c:174
Here is the call graph for this function:
Here is the caller graph for this function:

◆ decode_csd_v2()

ERR_te decode_csd_v2 ( const uint8_t * csd_raw,
SD_CSD_INFO_ts * csd_info_o )
static

Decodes a CSD v2.0 register (SDHC/SDXC cards) into a SD_CSD_INFO_ts structure.

Extracts all fields from the 16-byte big-endian CSD register using extract_bits and computes derived values:

  • block_len = 512 (fixed for SDHC)
  • capacity_bytes = (C_SIZE + 1) × 512 × 1024
  • capacity_mb = capacity_bytes / (1024 × 1024)
  • block_count = capacity_bytes / 512
Parameters
[in]csd_rawPointer to the 16-byte raw CSD register data.
[out]csd_info_oPointer to the structure that will receive the decoded fields.
Returns
  • ERR_OK always

Definition at line 1706 of file sd.c.

1706 {
1707 csd_info_o->csd_structure = extract_bits(csd_raw, 126, 2);
1708 csd_info_o->taac = extract_bits(csd_raw, 112, 8);
1709 csd_info_o->nsac = extract_bits(csd_raw, 104, 8);
1710 csd_info_o->tran_speed = extract_bits(csd_raw, 96, 8);
1711 csd_info_o->ccc = extract_bits(csd_raw, 84, 12);
1712 csd_info_o->v1.read_bl_len = extract_bits(csd_raw, 80, 4);
1713 csd_info_o->read_bl_partial = extract_bits(csd_raw, 79, 1);
1714 csd_info_o->write_blk_misalign = extract_bits(csd_raw, 78, 1);
1715 csd_info_o->read_blk_misalign = extract_bits(csd_raw, 77, 1);
1716 csd_info_o->dsr_imp = extract_bits(csd_raw, 76, 1);
1717 csd_info_o->v2.c_size = extract_bits(csd_raw, 48, 22);
1718 csd_info_o->erase_blk_en = extract_bits(csd_raw, 46, 1);
1719 csd_info_o->sector_size = extract_bits(csd_raw, 39, 7);
1720 csd_info_o->wp_grp_size = extract_bits(csd_raw, 32, 7);
1721 csd_info_o->wp_grp_enable = extract_bits(csd_raw, 31, 1);
1722 csd_info_o->r2w_factor = extract_bits(csd_raw, 26, 3);
1723 csd_info_o->write_bl_len = extract_bits(csd_raw, 22, 4);
1724 csd_info_o->write_bl_partial = extract_bits(csd_raw, 21, 1);
1725 csd_info_o->file_format_grp = extract_bits(csd_raw, 15, 1);
1726 csd_info_o->copy = extract_bits(csd_raw, 14, 1);
1727 csd_info_o->perm_write_protect = extract_bits(csd_raw, 13, 1);
1728 csd_info_o->tmp_write_protect = extract_bits(csd_raw, 12, 1);
1729 csd_info_o->file_format = extract_bits(csd_raw, 10, 2);
1730 csd_info_o->wp_upc = extract_bits(csd_raw, 9, 1);
1731 csd_info_o->crc = extract_bits(csd_raw, 1, 7);
1732
1733 csd_info_o->block_len = 512;
1734 csd_info_o->capacity_bytes = (csd_info_o->v2.c_size + 1) * 512 * 1024;
1735 csd_info_o->capacity_mb = csd_info_o->capacity_bytes / (1024 * 1024);
1736 csd_info_o->block_count = csd_info_o->capacity_bytes / 512;
1737
1738 return ERR_OK;
1739}
struct SD_CSD_INFO_ts::@123136205353006350230173346147067177263037234074 v2
Here is the call graph for this function:
Here is the caller graph for this function: