GPS Device
Loading...
Searching...
No Matches
SD Card Public API

Public functions to interact with the SD card subsystem. More...

Collaboration diagram for SD Card Public API:

Functions

ERR_te sd_init_subsys (void)
 Initializes the SD card subsystem.
ERR_te sd_deinit_subsys (void)
 Deinitializes the SD card subsystem.
ERR_te sd_start_subsys (void)
 Starts the SD card subsystem.
ERR_te sd_stop_subsys (void)
 Stops the SD card subsystem.
ERR_te sd_init_handle (SD_CFG_ts *sd_cfg, SD_HANDLE_ts **sd_handle_o)
 Initializes an SD card handle and performs the full SPI-mode power-up sequence.
ERR_te sd_deinit_handle (SD_HANDLE_ts *sd_handle)
 Deinitializes an SD card handle and resets the SPI peripheral.
ERR_te sd_get_handle_init (SD_HANDLE_ts *sd_handle, bool *handle_init_o)
 Retrieves the initialization state of an SD card handle.
ERR_te sd_get_sector_count (SD_HANDLE_ts *sd_handle, uint32_t *sector_count_o)
 Retrieves the total sector (block) count of the SD card.
ERR_te sd_get_sector_size (SD_HANDLE_ts *sd_handle, uint32_t *sector_size_o)
 Retrieves the sector (block) size of the SD card in bytes.
ERR_te sd_read (SD_HANDLE_ts *sd_handle, uint8_t *read_buf, uint32_t start_sector, uint32_t num_sectors)
 Reads one or more sectors from the SD card.
ERR_te sd_write (SD_HANDLE_ts *sd_handle, uint8_t *write_buf, uint32_t start_sector, uint32_t num_sectors)
 Writes one or more sectors to the SD card.
ERR_te sd_ioctl (SD_HANDLE_ts *sd_handle)
 Executes an IOCTL control command on the SD card handle.

Detailed Description

Public functions to interact with the SD card subsystem.

Function Documentation

◆ sd_init_subsys()

ERR_te sd_init_subsys ( void )

Initializes the SD card subsystem.

Resets the internal state, initializes logging and systick dependencies, and registers the CLI commands.

Must be called before any other SD API function.

Returns
  • ERR_OK on success
  • ERR_MODULE_ALREADY_INITIALIZED if the subsystem is already initialized
  • Propagated error from cmd_register on failure
See also
sd_init_subsys

Definition at line 325 of file sd.c.

325 {
326 ERR_te err;
327
328 if(internal_state.initialized) {
330 }
331
332 internal_state = (struct internal_state_s){ 0 };
333
334 internal_state.log_level = LOG_LEVEL_INFO;
335 internal_state.subsys = MODULES_SD;
336 internal_state.initialized = true;
337 internal_state.started = false;
338
339 init_log();
340 init_systick();
341
343 if(err != ERR_OK) {
344 LOG_ERROR(
345 internal_state.subsys,
346 internal_state.log_level,
347 "sd_init_subsys: cmd_register error"
348 );
349 return err;
350 }
351 LOG_INFO(
352 internal_state.subsys,
353 internal_state.log_level,
354 "sd_init_subsys: subsys initialized"
355 );
356
357 return ERR_OK;
358}
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
ERR_te cmd_register(CMD_CLIENT_INFO_ts *cmd_client_info)
Registers a client with the command subsystem.
Definition cmd.c:51
ERR_te
Standard return type used by all public API functions.
Definition err.h:35
@ ERR_OK
Definition err.h:36
@ ERR_MODULE_ALREADY_INITIALIZED
Definition err.h:54
ERR_te init_log(void)
Initializes the logging subsystem.
Definition init.c:25
ERR_te init_systick(void)
Initializes the SysTick timer.
Definition init.c:40
#define LOG_ERROR(subsys, lvl, fmt,...)
Definition log.h:258
#define LOG_INFO(subsys, lvl, fmt,...)
Definition log.h:255
@ LOG_LEVEL_INFO
Definition log.h:64
@ MODULES_SD
Definition modules.h:49
CMD_CLIENT_INFO_ts sd_cmd_client_info
Registration descriptor passed to the command subsystem.
Definition sd.c:312
Internal state of the SysTick driver.
Here is the call graph for this function:

◆ sd_deinit_subsys()

ERR_te sd_deinit_subsys ( void )

Deinitializes the SD card subsystem.

Resets the internal state to zero and deregisters the CLI commands.

Returns
  • ERR_OK on success
  • ERR_DEINITIALIZATION_FAILURE if the subsystem is not initialized
See also
sd_deinit_subsys

Definition at line 361 of file sd.c.

361 {
362 if(internal_state.initialized) {
363 internal_state = (struct internal_state_s){ 0 };
364
366 }
367 else {
368 LOG_ERROR(
369 internal_state.subsys,
370 internal_state.log_level,
371 "sd_deinit_subsys: subsys is not initialized"
372 );
373
375 }
376 LOG_INFO(
377 internal_state.subsys,
378 internal_state.log_level,
379 "sd_deinit_subsys: subsys deinitialized"
380 );
381
382 return ERR_OK;
383}
ERR_te cmd_deregister(CMD_CLIENT_INFO_ts const *cmd_client_info)
Deregisters a client from the command subsystem.
Definition cmd.c:66
@ ERR_DEINITIALIZATION_FAILURE
Definition err.h:44
Here is the call graph for this function:

◆ sd_start_subsys()

ERR_te sd_start_subsys ( void )

Starts the SD card subsystem.

Enables sd_read and sd_write operations.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already started
See also
sd_start_subsys

Definition at line 386 of file sd.c.

386 {
387 if(internal_state.initialized && !internal_state.started) {
388 internal_state.started = true;
389
390 LOG_INFO(
391 internal_state.subsys,
392 internal_state.log_level,
393 "sd_start_subsys: subsys started"
394 );
395 }
396 else {
397 LOG_ERROR(
398 internal_state.subsys,
399 internal_state.log_level,
400 "sd_start_subsys: subsys not initialized or already started"
401 );
402
403 return ERR_UNKNOWN;
404 }
405
406 return ERR_OK;
407}
@ ERR_UNKNOWN
Definition err.h:37

◆ sd_stop_subsys()

ERR_te sd_stop_subsys ( void )

Stops the SD card subsystem.

Returns
  • ERR_OK on success
  • ERR_UNKNOWN if the subsystem is not initialized or already stopped
See also
sd_stop_subsys

Definition at line 410 of file sd.c.

410 {
411 if(internal_state.initialized && internal_state.started) {
412 internal_state.started = false;
413
414 LOG_INFO(
415 internal_state.subsys,
416 internal_state.log_level,
417 "sd_stop_subsys: subsys stopped"
418 );
419 }
420 else {
421 LOG_ERROR(
422 internal_state.subsys,
423 internal_state.log_level,
424 "sd_stop_subsys: subsys not initialized or already already stopped"
425 );
426
427 return ERR_UNKNOWN;
428 }
429
430 return ERR_OK;
431}

◆ sd_init_handle()

ERR_te sd_init_handle ( SD_CFG_ts * sd_cfg,
SD_HANDLE_ts ** sd_handle_o )

Initializes an SD card handle and performs the full SPI-mode power-up sequence.

Configures all GPIO pins and the SPI peripheral, then executes the SD card initialization sequence (idle state, interface condition check, ACMD41/CMD1, OCR read, CSD read). On success, the SPI clock is ramped to maximum speed.

If any step of the initialization sequence fails, the handle is automatically deinitialized and an error is returned.

Parameters
[in]sd_cfgPointer to the SD card configuration structure.
[out]sd_handle_oPointer to a handle pointer that will be set to the allocated SD card instance.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if the subsystem is not initialized
  • ERR_NOT_ENOUGH_SPACE if the maximum number of handles is reached
  • ERR_INVALID_ARGUMENT if sd_cfg is NULL
  • ERR_UNSUCCESFUL_ACTION if any step of the SD initialization sequence fails
See also
sd_init_handle

Definition at line 434 of file sd.c.

434 {
435 ERR_te err;
436 uint8_t free_index;
437
438 if(!internal_state.initialized) {
439 LOG_ERROR(
440 internal_state.subsys,
441 internal_state.log_level,
442 "sd_init_handle: subsys not initialized"
443 );
444
446 }
447
448 if(internal_state.sd_num == CONFIG_SD_MAX_OBJECTS) {
450 internal_state.subsys,
451 internal_state.log_level,
452 "sd_init_handle: subsystem out of memory space"
453 );
454
456 }
457
458 if(!sd_cfg) {
459 LOG_ERROR(
460 internal_state.subsys,
461 internal_state.log_level,
462 "sd_init_handle: invalid argument"
463 );
465 }
466
467 bool found = false;
468
469 for(uint32_t i = 0; i < CONFIG_SD_MAX_OBJECTS; i++) {
470 if(!internal_state.sds[i].in_use) {
471 free_index = i;
472 found = true;
473 break;
474 }
475 }
476
477 if(!found)
479
480 GPIO_CFG_ts sd_sclk = { 0 };
481 sd_sclk.port = sd_cfg->sclk_gpio_port;
482 sd_sclk.pin = sd_cfg->sclk_gpio_pin;
485 gpio_init(&sd_sclk);
486
487 GPIO_CFG_ts sd_cs = { 0 };
488 sd_cs.port = sd_cfg->cs_gpio_port;
489 sd_cs.pin = sd_cfg->cs_gpio_pin;
490 sd_cs.mode = GPIO_MODE_OUTPUT;
491 gpio_init(&sd_cs);
492
493 GPIO_CFG_ts sd_mosi = { 0 };
494 sd_mosi.port = sd_cfg->mosi_gpio_port;
495 sd_mosi.pin = sd_cfg->mosi_gpio_pin;
498 gpio_init(&sd_mosi);
499
500 GPIO_CFG_ts sd_miso = { 0 };
501 sd_miso.port = sd_cfg->miso_gpio_port;
502 sd_miso.pin = sd_cfg->miso_gpio_pin;
505 gpio_init(&sd_miso);
506
507 // Configure SPI
508 SPI_CFG_ts sd_spi = { 0 };
509 sd_spi.instance = sd_cfg->spi_instance;
515 sd_spi.mode = SPI_MODE_MASTER;
516
517 IO_CFG_ts io_cs_conf = { 0 };
518 IO_HANDLE_ts *io_cs_handle = { 0 };
519 io_cs_conf.gpio_handle = &sd_miso;
520 str_cpy(io_cs_conf.name, "sd_cs", get_str_len("sd_cs") + 1);
522 io_init_handle(&io_cs_conf, &io_cs_handle);
524
525 // Set SPI speed between 100 and 400 KHz for initialization, then initialize
526 uint32_t spi_pclk = 0;
527
528 if(sd_cfg->spi_instance == SPI1 || sd_cfg->spi_instance == SPI4) {
529 spi_pclk = rcc_get_apb2_clk();
530 }
531 else if(sd_cfg->spi_instance == SPI2 || sd_cfg->spi_instance == SPI3) {
532 spi_pclk = rcc_get_apb1_clk();
533 }
534
535 uint32_t spi_pclk_cpy = spi_pclk;
536 uint32_t div_factor = 2;
537 while(div_factor <= 256) {
538 spi_pclk = spi_pclk / div_factor;
539
540 if(spi_pclk >= 100000 && spi_pclk <= 400000) {
541 break;
542 }
543
544 spi_pclk = spi_pclk_cpy;
545 div_factor *= 2;
546 }
547
548 switch (div_factor) {
557 }
558
559 spi_init(&sd_spi);
560
561 str_cpy(
562 internal_state.sds[free_index].name,
563 sd_cfg->name,
564 get_str_len(sd_cfg->name) + 1
565 );
566
567 internal_state.sds[free_index].spi_instance = sd_cfg->spi_instance;
568 internal_state.sds[free_index].sclk_gpio_port = sd_cfg->sclk_gpio_port;
569 internal_state.sds[free_index].cs_gpio_port = sd_cfg->cs_gpio_port;
570 internal_state.sds[free_index].sclk_gpio_pin = sd_cfg->sclk_gpio_pin;
571 internal_state.sds[free_index].miso_gpio_port = sd_cfg->miso_gpio_port;
572 internal_state.sds[free_index].mosi_gpio_port = sd_cfg->mosi_gpio_port;
573 internal_state.sds[free_index].cs_gpio_pin = sd_cfg->cs_gpio_pin;
574 internal_state.sds[free_index].sclk_gpio_pin = sd_cfg->sclk_gpio_pin;
575 internal_state.sds[free_index].miso_gpio_pin = sd_cfg->miso_gpio_pin;
576 internal_state.sds[free_index].mosi_gpio_pin = sd_cfg->mosi_gpio_pin;
577 internal_state.sds[free_index].gpio_alternate_function = sd_cfg->gpio_alternate_function;
578 internal_state.sds[free_index].in_use = true;
579
580 *sd_handle_o = &internal_state.sds[free_index];
581
582 internal_state.sd_num++;
583
584 // Wait for >= 1 ms after supply reached at least 2.2V
585 DELAY(CONFIG_SD_HW_INIT_WAIT_TIME);
586
587 // Enable SPI communication
589
590 // 1. Start initialization — set CS high and send at least 74 dummy clocks
591 gpio_write(sd_cfg->cs_gpio_port, sd_cfg->cs_gpio_pin, HIGH);
592
593 uint8_t dummy_tx = 0xFF;
594 for(uint8_t i = 0; i < 10; i++) {
595 spi_send(sd_cfg->spi_instance, &dummy_tx, 1);
596 }
597
598 gpio_write(sd_cfg->cs_gpio_port, sd_cfg->cs_gpio_pin, LOW);
599
600 // 2. Enter idle state
601 err = sd_go_idle_state(&internal_state.sds[free_index]);
602 if(err != ERR_OK) {
604 internal_state.log_level,
605 "sd_init_handle: failed to enter idle state, deinitializing handle"
606 );
607
608 sd_cease_comms(&internal_state.sds[free_index], true);
609
611 }
612
613 // 3. Detect card type and version
614 bool match = false;
615 bool no_response = false;
616
617 err = sd_send_if_cond(&internal_state.sds[free_index], &match, &no_response);
618 if(err != ERR_OK) {
620 internal_state.log_level,
621 "sd_init_handle: failed to get SD card type, deinitializing handle"
622 );
623
624 sd_cease_comms(&internal_state.sds[free_index], true);
625
627 }
628
629 // 3.1 SD Ver.2 — determine byte or block addressing from OCR
630 if(match) {
631 err = sd_app_send_op_cond(&internal_state.sds[free_index], 0x40000000);
632 if(err != ERR_OK) {
634 internal_state.log_level,
635 "sd_init_handle: failed to initiate initialization of SD Ver.2, deinitializing handle"
636 );
637
638 sd_cease_comms(&internal_state.sds[free_index], true);
639
641 }
642
643 err = sd_read_ocr(&internal_state.sds[free_index]);
644 if(err != ERR_OK) {
646 internal_state.log_level,
647 "sd_init_handle: failed to obtain SD Ver 2. information, deinitializing handle"
648 );
649
651 }
652 }
653 // 3.2 SD Ver.1 or MMC Ver.3
654 else if(no_response) {
655 err = sd_app_send_op_cond(&internal_state.sds[free_index], 0);
656 // SD Ver.1
657 if(err == ERR_OK) {
658 internal_state.sds[free_index].addr_mode = SD_ADDR_MODE_BYTE;
659 }
660 // MMC Ver.3 or unknown
661 else if(err == ERR_TIMEOUT) {
662 err = sd_send_op_cond(&internal_state.sds[free_index]);
663 // Unknown card
664 if(err != ERR_OK) {
666 internal_state.log_level,
667 "sd_init_handle: unknown card, deinitializing handle"
668 );
669
670 sd_cease_comms(&internal_state.sds[free_index], true);
671
673 }
674 // MMC Ver.3
675 else {
676 internal_state.sds[free_index].addr_mode = SD_ADDR_MODE_BYTE;
677 }
678 }
679 // Unknown card
680 else {
682 internal_state.log_level,
683 "sd_init_handle: unknown card, deinitializing handle"
684 );
685
686 sd_cease_comms(&internal_state.sds[free_index], true);
687
689 }
690 }
691
692 if(internal_state.sds[free_index].addr_mode == SD_ADDR_MODE_BYTE) {
693 err = sd_set_blocklen(&internal_state.sds[free_index]);
694 if(err != ERR_OK) {
696 internal_state.log_level,
697 "sd_init_handle: failed to initialize, deinitializing handle"
698 );
699
700 sd_cease_comms(&internal_state.sds[free_index], true);
701
703 }
704 }
705
706 internal_state.sds[free_index].initialized = true;
707
708 LOG_INFO(
709 internal_state.subsys,
710 internal_state.log_level,
711 "sd_init_handle: sd handle %s initialized",
712 internal_state.sds[free_index].name
713 );
714
715 // Read CSD to populate capacity, block size, and block count
716 sd_read_csd(&internal_state.sds[free_index]);
717
718 sd_cease_comms(&internal_state.sds[free_index], false);
719
720 // Ramp SPI to maximum speed after initialization
722
723 return ERR_OK;
724}
int str_cpy(char *str_to, const char *str_from, uint32_t len)
Copies a null-terminated string into a destination buffer.
Definition common.c:333
uint32_t get_str_len(char const *str)
Returns the length of a string, excluding the null terminator.
Definition common.c:22
#define DELAY(ms)
Blocking delay using the system tick counter.
Definition common.h:65
@ HIGH
Definition common.h:89
@ LOW
Definition common.h:86
@ ENABLE
Definition common.h:100
@ ERR_UNSUCCESFUL_ACTION
Definition err.h:51
@ ERR_TIMEOUT
Definition err.h:52
@ ERR_NOT_ENOUGH_SPACE
Definition err.h:49
@ ERR_INITIALIZATION_FAILURE
Definition err.h:43
@ ERR_INVALID_ARGUMENT
Definition err.h:38
ERR_te io_init_handle(IO_CFG_ts *io_cfg, IO_HANDLE_ts **io_handle_o)
Initializes and registers an IO handle.
Definition io.c:229
ERR_te io_start_subsys(void)
Starts the IO subsystem.
Definition io.c:181
ERR_te io_init_subsys(void)
Initializes the IO subsystem.
Definition io.c:120
struct io_handle_s IO_HANDLE_ts
Opaque handle representing an IO instance.
Definition io.h:69
#define LOG_CRITICAL(subsys, lvl, fmt,...)
Definition log.h:259
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.
Definition sd.c:1256
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).
Definition sd.c:1383
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.
Definition sd.c:1440
static ERR_te sd_go_idle_state(SD_HANDLE_ts *sd_handle)
Issues CMD0 to reset the SD card into idle (SPI) mode.
Definition sd.c:1287
static ERR_te sd_send_op_cond(SD_HANDLE_ts *sd_handle)
Issues CMD1 to initiate MMC Ver.3 card initialization.
Definition sd.c:1495
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.
Definition sd.c:1540
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.
Definition sd.c:1577
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.
Definition sd.c:1336
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 gpio_init(GPIO_CFG_ts *gpio_cfg)
Initializes a GPIO pin according to the given configuration.
@ GPIO_MODE_ALTERNATE_FUNCTION
@ GPIO_MODE_OUTPUT
uint32_t rcc_get_apb2_clk(void)
Returns the current APB2 (high-speed) peripheral bus clock frequency in Hz.
uint32_t rcc_get_apb1_clk(void)
Returns the current APB1 (low-speed) peripheral bus clock frequency in Hz.
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_init(SPI_CFG_ts *spi_cfg)
Initializes the SPI peripheral with the given configuration.
void spi_set_comm(SPI_REGDEF_ts *spi_instance, EN_STATUS_te en_status)
Enables or disables the SPI peripheral (SPE bit).
void spi_set_pclk_div(SPI_REGDEF_ts *spi_instance, SPI_MASTER_SCLK_SPEED_te pclk_div)
Changes the SPI master clock speed divisor at runtime.
@ SPI_BIT_FIRST_MSB
@ SPI_CLOCK_PHASE_FIRST_TRANSITION
@ SPI_DATA_FRAME_FORMATE_8_BIT
@ SPI_MODE_MASTER
@ SPI_SLAVE_SELECT_MODE_SW
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_8
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_2
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_16
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_4
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_256
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_32
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_128
@ SPI_MASTER_SCLK_SPEED_PCLK_DIV_64
@ SPI_CLOCK_POLARITY_0_IDLE
#define SPI4
#define SPI3
#define SPI1
#define SPI2
@ SD_ADDR_MODE_BYTE
Definition sd.c:135
Configuration structure for initializing a GPIO pin.
GPIO_REGDEF_ts * port
GPIO_ALTERNATE_FUNCTION_te alternate_function
GPIO_PIN_te pin
GPIO_MODE_te mode
Configuration structure for initializing an IO handle.
Definition io.h:53
char name[CONFIG_IO_MAX_NAME_LEN]
Definition io.h:58
GPIO_CFG_ts * gpio_handle
Definition io.h:55
GPIO_REGDEF_ts * miso_gpio_port
Definition sd.h:80
GPIO_PIN_te sclk_gpio_pin
Definition sd.h:86
GPIO_PIN_te cs_gpio_pin
Definition sd.h:89
GPIO_REGDEF_ts * mosi_gpio_port
Definition sd.h:83
char name[CONFIG_SD_MAX_NAME_LEN]
Definition sd.h:68
GPIO_REGDEF_ts * cs_gpio_port
Definition sd.h:77
SPI_REGDEF_ts * spi_instance
Definition sd.h:71
GPIO_PIN_te mosi_gpio_pin
Definition sd.h:95
GPIO_ALTERNATE_FUNCTION_te gpio_alternate_function
Definition sd.h:98
GPIO_REGDEF_ts * sclk_gpio_port
Definition sd.h:74
GPIO_PIN_te miso_gpio_pin
Definition sd.h:92
Configuration structure for initializing an SPI peripheral.
SPI_CLOCK_POLARITY_te clock_polarity
SPI_SLAVE_SELECT_MODE_te slave_select_mode
SPI_REGDEF_ts * instance
SPI_MASTER_SCLK_SPEED_te master_sclk_speed
SPI_DATA_FRAME_FORMAT_te data_frame_format
SPI_CLOCK_PHASE_te clock_phase
SPI_MODE_te mode
SPI_BIT_FIRST_te bit_first
Here is the call graph for this function:

◆ sd_deinit_handle()

ERR_te sd_deinit_handle ( SD_HANDLE_ts * sd_handle)

Deinitializes an SD card handle and resets the SPI peripheral.

Parameters
[in]sd_handlePointer to the handle to deinitialize.
Returns
  • ERR_OK on success
  • ERR_ILLEGAL_ACTION if the handle is not initialized
  • ERR_UNINITIALZIED_OBJECT if the handle is not found in the pool
See also
sd_deinit_handle

Definition at line 727 of file sd.c.

727 {
728 if(!sd_handle->initialized) {
729 LOG_ERROR(
730 internal_state.subsys,
731 internal_state.log_level,
732 "sd_deinit_handle: handle not initialized"
733 );
734 return ERR_ILLEGAL_ACTION;
735 }
736
737 if(internal_state.sd_num == 0) {
738 LOG_ERROR(
739 internal_state.subsys,
740 internal_state.log_level,
741 "sd_deinit_handle: no such handle to deinitialize"
742 );
743
745 }
746
747 for(uint32_t i = 0; i < CONFIG_SD_MAX_OBJECTS; i++) {
748 if(&internal_state.sds[i] == sd_handle) {
749 uint8_t name_len = get_str_len(internal_state.sds[i].name) + 1;
750 char name[name_len];
751 str_cpy(name, internal_state.sds[i].name, name_len);
752
753 spi_deinit(internal_state.sds[i].spi_instance);
754
755 internal_state.sds[i] = (SD_HANDLE_ts){ 0 };
756
757 internal_state.sd_num--;
758
759 LOG_INFO(
760 internal_state.subsys,
761 internal_state.log_level,
762 "sd_deinit_handle: sd handle %s deinitialized",
763 name
764 );
765
766 break;
767 }
768
769 if(i == CONFIG_SD_MAX_OBJECTS - 1) {
770 LOG_ERROR(
771 internal_state.subsys,
772 internal_state.log_level,
773 "sd_deinit_handle: no such handle to deinitialize"
774 );
775
777 }
778 }
779
780 return ERR_OK;
781}
@ ERR_UNINITIALZIED_OBJECT
Definition err.h:42
@ ERR_ILLEGAL_ACTION
Definition err.h:50
struct sd_handle_s SD_HANDLE_ts
Opaque handle representing an SD card instance.
Definition sd.h:109
void spi_deinit(SPI_REGDEF_ts const *spi_instance)
Deinitializes the SPI peripheral and disables its clock.
bool initialized
Definition sd.c:234
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sd_get_handle_init()

ERR_te sd_get_handle_init ( SD_HANDLE_ts * sd_handle,
bool * handle_init_o )

Retrieves the initialization state of an SD card handle.

Parameters
[in]sd_handlePointer to the SD card handle to query.
[out]handle_init_oPointer to a boolean that will receive the initialization state.
Returns
  • ERR_OK always
See also
sd_get_handle_init

Definition at line 784 of file sd.c.

784 {
785 *handle_init_o = sd_handle->initialized;
786
787 return ERR_OK;
788}

◆ sd_get_sector_count()

ERR_te sd_get_sector_count ( SD_HANDLE_ts * sd_handle,
uint32_t * sector_count_o )

Retrieves the total sector (block) count of the SD card.

The value is determined from the CSD register during sd_init_handle and is used by the FatFs diskio layer.

Parameters
[in]sd_handlePointer to the SD card handle.
[out]sector_count_oPointer to a variable that will receive the sector count.
Returns
  • ERR_OK always
See also
sd_get_sector_count

Definition at line 791 of file sd.c.

791 {
792 *sector_count_o = sd_handle->block_count;
793
794 return ERR_OK;
795}
uint32_t block_count
Definition sd.c:232

◆ sd_get_sector_size()

ERR_te sd_get_sector_size ( SD_HANDLE_ts * sd_handle,
uint32_t * sector_size_o )

Retrieves the sector (block) size of the SD card in bytes.

For SDHC cards this is always 512 bytes. For SDSC cards it is determined from the CSD register. Used by the FatFs diskio layer.

Parameters
[in]sd_handlePointer to the SD card handle.
[out]sector_size_oPointer to a variable that will receive the sector size in bytes.
Returns
  • ERR_OK always
See also
sd_get_sector_size

Definition at line 798 of file sd.c.

798 {
799 *sector_size_o = sd_handle->block_len;
800
801 return ERR_OK;
802}
uint32_t block_len
Definition sd.c:231

◆ sd_read()

ERR_te sd_read ( SD_HANDLE_ts * sd_handle,
uint8_t * read_buf,
uint32_t start_sector,
uint32_t num_sectors )

Reads one or more sectors from the SD card.

Reads num_sectors consecutive sectors starting at start_sector into read_buf. Uses CMD17 for single-sector reads and CMD18 + CMD12 for multi-sector reads. Handles both byte-addressed (SDSC) and block-addressed (SDHC) cards transparently.

Parameters
[in]sd_handlePointer to the SD card handle.
[out]read_bufPointer to the destination buffer. Must be at least num_sectors × sector size bytes.
[in]start_sectorZero-based index of the first sector to read.
[in]num_sectorsNumber of consecutive sectors to read.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if the subsystem or handle is not initialized or started
  • ERR_INVALID_ARGUMENT if sd_handle is NULL or num_sectors is 0
  • ERR_TIMEOUT if the data token is not received within the configured timeout
  • ERR_UNKNOWN if the card returns an error token or an unexpected response
See also
sd_read

Definition at line 805 of file sd.c.

805 {
806 ERR_te err;
807 uint32_t start_time = 0;
808 uint32_t elapsed_time = 0;
809 CMD_RESPONSE_ts cmd_response = { 0 };
810
811 if(!internal_state.initialized || !internal_state.started || !sd_handle->initialized) {
812 LOG_ERROR(
813 internal_state.subsys,
814 internal_state.log_level,
815 "sd_read: subsys or handle not initialized or started"
816 );
817
819 }
820
821 if(sd_handle == NULL || num_sectors == 0) {
823 }
824
825 spi_set_comm(sd_handle->spi_instance, ENABLE);
826 gpio_write(sd_handle->cs_gpio_port, sd_handle->cs_gpio_pin, LOW);
827
828 if(sd_handle->addr_mode == SD_ADDR_MODE_BYTE) {
829 start_sector = start_sector * sd_handle->block_len;
830 }
831
832 if(num_sectors == 1) {
833 err = sd_send_cmd(sd_handle->spi_instance, 17, start_sector, false, &cmd_response);
834 if(err != ERR_OK) {
835 sd_cease_comms(sd_handle, true);
836
837 return err;
838 }
839
840 if(cmd_response.r1 != 0x0) {
841 sd_cease_comms(sd_handle, true);
842
843 return ERR_UNKNOWN;
844 }
845
846 uint8_t token = 0xFF;
847 start_time = systick_get_ms();
848
849 do {
850 elapsed_time = systick_get_ms() - start_time;
851 spi_receive(sd_handle->spi_instance, &token, 1);
852 } while(token == 0xFF && elapsed_time <= CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT);
853
854 if(elapsed_time > CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT) {
855 sd_cease_comms(sd_handle, true);
856
857 return ERR_TIMEOUT;
858 }
859
860 if(token != 0xFE) {
861 sd_cease_comms(sd_handle, true);
862
863 return ERR_UNKNOWN;
864 }
865
866 spi_receive(sd_handle->spi_instance, read_buf, sd_handle->block_len);
867
868 uint8_t crc[2];
869 spi_receive(sd_handle->spi_instance, crc, 2);
870 }
871 else {
872 err = sd_send_cmd(sd_handle->spi_instance, 18, start_sector, false, &cmd_response);
873 if(err != ERR_OK) {
874 sd_cease_comms(sd_handle, true);
875
876 return err;
877 }
878
879 if(cmd_response.r1 != 0x0) {
880 sd_cease_comms(sd_handle, true);
881 return ERR_UNKNOWN;
882 }
883
884 for(uint32_t i = 0; i < num_sectors; i++) {
885 uint8_t token = 0xFF;
886 start_time = systick_get_ms();
887
888 do {
889 elapsed_time = systick_get_ms() - start_time;
890 spi_receive(sd_handle->spi_instance, &token, 1);
891 } while(token == 0xFF && elapsed_time <= CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT);
892
893 if(elapsed_time > CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT) {
894 sd_cease_comms(sd_handle, true);
895
896 return ERR_TIMEOUT;
897 }
898
899 if(token != 0xFE) {
900 sd_cease_comms(sd_handle, true);
901
902 return ERR_UNKNOWN;
903 }
904
905 spi_receive(sd_handle->spi_instance, read_buf + (i * sd_handle->block_len), sd_handle->block_len);
906
907 uint8_t crc[2];
908 spi_receive(sd_handle->spi_instance, crc, 2);
909 }
910 uint8_t retry = 0;
911 do {
912 err = sd_send_cmd(sd_handle->spi_instance, 12, 0, false, &cmd_response);
913 if(err != ERR_OK) {
914 sd_cease_comms(sd_handle, true);
915
916 return err;
917 }
918 } while(cmd_response.r1 != 0x0 && retry++ < CONFIG_SD_INVALID_RESP_RETRY_NUM);
919
920 if(cmd_response.r1 != 0x00) {
921 sd_cease_comms(sd_handle, true);
922
923 return ERR_UNKNOWN;
924 }
925 }
926
927 sd_cease_comms(sd_handle, false);
928
929 return ERR_OK;
930}
uint32_t systick_get_ms(void)
Returns the number of milliseconds elapsed since SysTick was initialized.
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_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
GPIO_REGDEF_ts * cs_gpio_port
Definition sd.c:218
SD_ADDR_MODE_te addr_mode
Definition sd.c:227
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:

◆ sd_write()

ERR_te sd_write ( SD_HANDLE_ts * sd_handle,
uint8_t * write_buf,
uint32_t start_sector,
uint32_t num_sectors )

Writes one or more sectors to the SD card.

Writes num_sectors consecutive sectors from write_buf starting at start_sector. Uses CMD24 for single-sector writes and CMD25 + CMD12 for multi-sector writes. Handles both byte-addressed (SDSC) and block-addressed (SDHC) cards transparently.

Parameters
[in]sd_handlePointer to the SD card handle.
[in]write_bufPointer to the source data buffer. Must contain at least num_sectors × sector size bytes.
[in]start_sectorZero-based index of the first sector to write.
[in]num_sectorsNumber of consecutive sectors to write.
Returns
  • ERR_OK on success
  • ERR_INITIALIZATION_FAILURE if the subsystem is not initialized or started
  • ERR_INVALID_ARGUMENT if sd_handle is NULL or num_sectors is 0
  • ERR_TIMEOUT if the card does not complete the write within the configured timeout
  • ERR_UNKNOWN if the card returns an unexpected response
See also
sd_write

Definition at line 933 of file sd.c.

933 {
934 ERR_te err;
935 uint32_t start_time = 0;
936 uint32_t elapsed_time = 0;
937
938 if(!internal_state.initialized || !internal_state.started) {
939 LOG_ERROR(
940 internal_state.subsys,
941 internal_state.log_level,
942 "sd_write: subsys not initialized or started"
943 );
944
946 }
947
948 if(sd_handle == NULL || num_sectors == 0) {
950 }
951
952 spi_set_comm(sd_handle->spi_instance, ENABLE);
953 gpio_write(sd_handle->cs_gpio_port, sd_handle->cs_gpio_pin, LOW);
954
955 if(sd_handle->addr_mode == SD_ADDR_MODE_BYTE) {
956 start_sector = start_sector * sd_handle->block_len;
957 }
958
959 CMD_RESPONSE_ts cmd_response = { 0 };
960
961 if(num_sectors == 1) {
962 err = sd_send_cmd(sd_handle->spi_instance, 24, start_sector, false, &cmd_response);
963 if(err != ERR_OK) {
964 sd_cease_comms(sd_handle, true);
965
966 return err;
967 }
968
969 if(cmd_response.r1 != 0x0) {
970 sd_cease_comms(sd_handle, true);
971
972 return ERR_UNKNOWN;
973 }
974
975 uint8_t token = 0xFE;
976 spi_send(sd_handle->spi_instance, &token, 1);
977 spi_send(sd_handle->spi_instance, write_buf, sd_handle->block_len);
978
979 uint8_t dummy_crc[2] = { 0xFF, 0xFF };
980 spi_send(sd_handle->spi_instance, dummy_crc, 2);
981
982 uint8_t data_resp = 0xFF;
983 start_time = systick_get_ms();
984
985 do {
986 elapsed_time = systick_get_ms() - start_time;
987 spi_receive(sd_handle->spi_instance, &data_resp, 1);
988 } while(data_resp == 0xFF && elapsed_time <= CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT);
989
990 if(elapsed_time > CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT) {
991 sd_cease_comms(sd_handle, true);
992
993 return ERR_TIMEOUT;
994 }
995
996 if((data_resp & 0b11111) != 0b00101) {
997 sd_cease_comms(sd_handle, true);
998
999 return ERR_UNKNOWN;
1000 }
1001
1002 // Wait until card releases MISO (busy signal)
1003 uint8_t busy = 0x00;
1004 start_time = systick_get_ms();
1005 do {
1006 spi_receive(sd_handle->spi_instance, &busy, 1);
1007 elapsed_time = systick_get_ms() - start_time;
1008 } while(busy == 0x00 && elapsed_time <= CONFIG_SD_BUSY_TIMOUT);
1009
1010 if(elapsed_time > CONFIG_SD_BUSY_TIMOUT) {
1011 sd_cease_comms(sd_handle, true);
1012
1013 return ERR_TIMEOUT;
1014 }
1015 }
1016 else {
1017 err = sd_send_cmd(sd_handle->spi_instance, 25, start_sector, false, &cmd_response);
1018 if(err != ERR_OK) {
1019 sd_cease_comms(sd_handle, true);
1020
1021 return err;
1022 }
1023
1024 if(cmd_response.r1 != 0x0) {
1025 sd_cease_comms(sd_handle, true);
1026
1027 return ERR_UNKNOWN;
1028 }
1029
1030 for(uint32_t i = 0; i < num_sectors; i++) {
1031 uint8_t token = 0xFC;
1032 spi_send(sd_handle->spi_instance, &token, 1);
1033 spi_send(sd_handle->spi_instance, write_buf + (i * sd_handle->block_len), sd_handle->block_len);
1034
1035 uint8_t dummy_crc[2] = { 0xFF, 0xFF };
1036 spi_send(sd_handle->spi_instance, dummy_crc, 2);
1037
1038 uint8_t data_resp = 0xFF;
1039 start_time = systick_get_ms();
1040
1041 do {
1042 elapsed_time = systick_get_ms() - start_time;
1043 spi_receive(sd_handle->spi_instance, &data_resp, 1);
1044 } while(data_resp == 0xFF && elapsed_time <= CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT);
1045
1046 if(elapsed_time > CONFIG_SD_DATA_TOKEN_RECV_TIMEOUT) {
1047 sd_cease_comms(sd_handle, true);
1048
1049 return ERR_TIMEOUT;
1050 }
1051
1052 if((data_resp & 0b11111) != 0b00101) {
1053 sd_cease_comms(sd_handle, true);
1054
1055 return ERR_UNKNOWN;
1056 }
1057
1058 uint8_t busy = 0x00;
1059 start_time = systick_get_ms();
1060 do {
1061 spi_receive(sd_handle->spi_instance, &busy, 1);
1062 elapsed_time = systick_get_ms() - start_time;
1063 } while(busy == 0x00 && elapsed_time <= CONFIG_SD_BUSY_TIMOUT);
1064
1065 if(elapsed_time > CONFIG_SD_BUSY_TIMOUT) {
1066 sd_cease_comms(sd_handle, true);
1067
1068 return ERR_TIMEOUT;
1069 }
1070 }
1071
1072 // Send stop transmission token
1073 uint8_t stop_tran_token = 0xFD;
1074 spi_send(sd_handle->spi_instance, &stop_tran_token, 1);
1075
1076 uint8_t busy = 0x00;
1077 start_time = systick_get_ms();
1078 do {
1079 spi_receive(sd_handle->spi_instance, &busy, 1);
1080 elapsed_time = systick_get_ms() - start_time;
1081 } while(busy == 0x00 && elapsed_time <= CONFIG_SD_BUSY_TIMOUT);
1082
1083 if(elapsed_time > CONFIG_SD_BUSY_TIMOUT) {
1084 sd_cease_comms(sd_handle, true);
1085
1086 return ERR_TIMEOUT;
1087 }
1088 }
1089
1090 sd_cease_comms(sd_handle, false);
1091
1092 return ERR_OK;
1093}
Here is the call graph for this function:

◆ sd_ioctl()

ERR_te sd_ioctl ( SD_HANDLE_ts * sd_handle)

Executes an IOCTL control command on the SD card handle.

Used by the FatFs diskio layer to perform control operations such as flushing write buffers or querying card parameters.

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