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

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.

Detailed Description

Function Documentation

◆ sd_init_subsys()

ERR_te sd_init_subsys ( void )

Initializes the SD card subsystem.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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: