GPS Device
Loading...
Searching...
No Matches
sd.c
Go to the documentation of this file.
1
11
12#include <stdbool.h>
13#include <string.h>
14
15#include "sd.h"
16#include "common.h"
17#include "err.h"
18#include "init.h"
19#include "io.h"
20#include "log.h"
21#include "modules.h"
22#include "cmd.h"
23#include "configuration.h"
24#include "stm32f401re.h"
25#include "stm32f401re_gpio.h"
26#include "stm32f401re_rcc.h"
27#include "stm32f401re_spi.h"
29
39typedef struct {
40 uint8_t r1;
41 uint8_t r3[4];
42 uint8_t r7[4];
44
78
104
130
138
146
150typedef enum {
153} SD_TYPE_te;
154
163typedef struct {
164 uint32_t capacity_bytes;
165 uint32_t capacity_mb;
166 uint16_t block_len;
167 uint32_t block_count;
168 uint8_t tran_speed;
169 uint16_t ccc;
171
173 struct {
174 uint16_t c_size;
175 uint8_t c_size_mult;
176 uint8_t read_bl_len;
177 } v1;
178
180 struct {
181 uint32_t c_size;
182 } v2;
183
184 uint8_t taac;
185 uint8_t nsac;
189 uint8_t dsr_imp;
190 uint8_t erase_blk_en;
191 uint8_t sector_size;
192 uint8_t wp_grp_size;
194 uint8_t r2w_factor;
195 uint8_t write_bl_len;
198 uint8_t copy;
201 uint8_t file_format;
202 uint8_t wp_upc;
203 uint8_t crc;
205
237
245struct internal_state_s {
247 SD_HANDLE_ts sds[CONFIG_SD_MAX_OBJECTS];
248
251
254
256 uint32_t sd_num;
257
259 bool initialized;
260
262 bool started;
263};
264
267
268/* ---- Forward declarations for internal helpers ---- */
269static ERR_te sd_go_idle_state(SD_HANDLE_ts *sd_handle);
270static ERR_te sd_send_if_cond(SD_HANDLE_ts *sd_handle, bool *match_o, bool *no_resp_o);
271static ERR_te sd_app_send_op_cond(SD_HANDLE_ts *sd_handle, uint32_t arg);
272static ERR_te sd_read_ocr(SD_HANDLE_ts *sd_handle);
273static ERR_te sd_send_op_cond(SD_HANDLE_ts *sd_handle);
274static ERR_te sd_set_blocklen(SD_HANDLE_ts *sd_handle);
275static ERR_te sd_read_csd(SD_HANDLE_ts *sd_handle);
276static ERR_te decode_csd_v1(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o);
277static ERR_te decode_csd_v2(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o);
278static ERR_te sd_send_cmd(SPI_REGDEF_ts *spi_instance, uint8_t index, uint32_t arg, bool acmd, CMD_RESPONSE_ts *cmd_response_o);
279static ERR_te sd_cease_comms(SD_HANDLE_ts *sd_handle, bool deinit);
280
281/* ---- Forward declarations for command handlers ---- */
282static ERR_te sd_cmd_list_handler(uint32_t argc, char **argv);
283static ERR_te sd_cmd_info_handler(uint32_t argc, char **argv);
284
293 {
294 .name = "list",
295 .help = "Lists active sd objects, usage: sd list",
296 .handler = sd_cmd_list_handler
297 },
298 {
299 .name = "info",
300 .help = "Shows sd object info, usage: sd info <sd object>",
301 .handler = sd_cmd_info_handler
302 }
303};
304
313 .cmds_ptr = sd_cmds,
314 .num_cmds = sizeof(sd_cmds) / sizeof(sd_cmds[0]),
315 .log_level_ptr = &internal_state.log_level,
316 .name = "sd"
317};
318
323
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}
359
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}
384
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}
408
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}
432
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}
725
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}
782
784ERR_te sd_get_handle_init(SD_HANDLE_ts *sd_handle, bool *handle_init_o) {
785 *handle_init_o = sd_handle->initialized;
786
787 return ERR_OK;
788}
789
791ERR_te sd_get_sector_count(SD_HANDLE_ts *sd_handle, uint32_t *sector_count_o) {
792 *sector_count_o = sd_handle->block_count;
793
794 return ERR_OK;
795}
796
798ERR_te sd_get_sector_size(SD_HANDLE_ts *sd_handle, uint32_t *sector_size_o) {
799 *sector_size_o = sd_handle->block_len;
800
801 return ERR_OK;
802}
803
805ERR_te sd_read(SD_HANDLE_ts *sd_handle, uint8_t *read_buf, uint32_t start_sector, uint32_t num_sectors) {
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}
931
933ERR_te sd_write(SD_HANDLE_ts *sd_handle, uint8_t *write_buf, uint32_t start_sector, uint32_t num_sectors) {
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}
1094
1096
1101
1131static ERR_te sd_send_cmd(SPI_REGDEF_ts *spi_instance, uint8_t index, uint32_t arg, bool acmd, CMD_RESPONSE_ts *cmd_response_o) {
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}
1240
1256static ERR_te sd_cease_comms(SD_HANDLE_ts *sd_handle, bool deinit) {
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}
1272
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}
1318
1336static ERR_te sd_send_if_cond(SD_HANDLE_ts *sd_handle, bool *match_o, bool *no_resp_o) {
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}
1364
1383static ERR_te sd_app_send_op_cond(SD_HANDLE_ts *sd_handle, uint32_t arg) {
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}
1424
1440static ERR_te sd_read_ocr(SD_HANDLE_ts *sd_handle) {
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}
1480
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}
1526
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}
1560
1577static ERR_te sd_read_csd(SD_HANDLE_ts *sd_handle) {
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}
1634
1652static ERR_te decode_csd_v1(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o) {
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}
1688
1706static ERR_te decode_csd_v2(const uint8_t *csd_raw, SD_CSD_INFO_ts *csd_info_o) {
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}
1740
1742
1747
1761static ERR_te sd_cmd_list_handler(uint32_t argc, char **argv) {
1762 if(argc != 2) {
1763 LOG_ERROR(
1764 internal_state.subsys,
1765 internal_state.log_level,
1766 "sd_cmd_list_handler: invalid arguments"
1767 );
1768 return ERR_INVALID_ARGUMENT;
1769 }
1770
1771 for(uint32_t i = 0; i < CONFIG_SD_MAX_OBJECTS; i++) {
1772 if(internal_state.sds[i].in_use == true) {
1773 LOG_INFO(
1774 internal_state.subsys,
1775 internal_state.log_level,
1776 "%s",
1777 internal_state.sds[i].name
1778 );
1779 }
1780 }
1781
1782 return ERR_OK;
1783}
1784
1803static ERR_te sd_cmd_info_handler(uint32_t argc, char **argv) {
1804 if(argc != 3) {
1805 LOG_ERROR(
1806 internal_state.subsys,
1807 internal_state.log_level,
1808 "sd_cmd_info_handler: invalid arguments"
1809 );
1810 return ERR_INVALID_ARGUMENT;
1811 }
1812
1813 for(uint32_t i = 0; i < CONFIG_SD_MAX_OBJECTS; i++) {
1814 if(str_cmp(internal_state.sds[i].name, argv[2]) == true) {
1815 char type_str[10];
1816 char addr_mode[10];
1817
1818 switch(internal_state.sds[i].type) {
1819 case SDSC: str_cpy(type_str, "SDSC", get_str_len("SDSC") + 1); break;
1820 case SDHC: str_cpy(type_str, "SDHC", get_str_len("SDHC") + 1); break;
1821 }
1822
1823 switch(internal_state.sds[i].addr_mode) {
1824 case SD_ADDR_MODE_BLOCK: str_cpy(addr_mode, "block", get_str_len("block") + 1); break;
1825 case SD_ADDR_MODE_BYTE: str_cpy(addr_mode, "byte", get_str_len("byte") + 1); break;
1826 }
1827
1828 LOG_INFO(
1829 internal_state.subsys,
1830 internal_state.log_level,
1831 "type: %s, addr mode: %s, capacity: %d mb, block size: %d byte, block count: %d",
1832 type_str,
1833 addr_mode,
1834 internal_state.sds[i].capacity_mb,
1835 internal_state.sds[i].block_len,
1836 internal_state.sds[i].block_count
1837 );
1838
1839 break;
1840 }
1841
1842 if(i == CONFIG_SD_MAX_OBJECTS - 1) {
1843 LOG_ERROR(
1844 internal_state.subsys,
1845 internal_state.log_level,
1846 "sd_cmd_info_handler: no such handle"
1847 );
1848
1849 return ERR_INVALID_ARGUMENT;
1850 }
1851 }
1852
1853 return ERR_OK;
1854}
1855
static struct internal_state_s internal_state
Singleton instance of the SysTick driver internal state.
Arm Cortex-M4 SysTick driver public API.
Command subsystem public API.
Common utility module public API.
System-wide error code definitions.
ERR_te cmd_deregister(CMD_CLIENT_INFO_ts const *cmd_client_info)
Deregisters a client from the command subsystem.
Definition cmd.c:66
ERR_te cmd_register(CMD_CLIENT_INFO_ts *cmd_client_info)
Registers a client with the command subsystem.
Definition cmd.c:51
bool str_cmp(const char *str1, const char *str2)
Compares two null-terminated strings for equality.
Definition common.c:248
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 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
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
@ DISABLE
Definition common.h:97
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_UNINITIALZIED_OBJECT
Definition err.h:42
@ ERR_ILLEGAL_ACTION
Definition err.h:50
@ ERR_DEINITIALIZATION_FAILURE
Definition err.h:44
@ ERR_UNKNOWN
Definition err.h:37
@ ERR_OK
Definition err.h:36
@ ERR_MODULE_ALREADY_INITIALIZED
Definition err.h:54
@ 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 init_log(void)
Initializes the logging subsystem.
Definition init.c:25
ERR_te init_systick(void)
Initializes the SysTick timer.
Definition init.c:40
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
#define LOG_ERROR(subsys, lvl, fmt,...)
Definition log.h:258
#define LOG_INFO(subsys, lvl, fmt,...)
Definition log.h:255
LOG_LEVEL_te
Log severity levels, in ascending order of severity.
Definition log.h:63
@ LOG_LEVEL_ERROR
Definition log.h:67
@ LOG_LEVEL_INFO
Definition log.h:64
MODULES_te
Identifies a subsystem for use in logging and CLI output.
Definition modules.h:42
@ MODULES_SD
Definition modules.h:49
static ERR_te sd_cmd_info_handler(uint32_t argc, char **argv)
CLI handler for the "info" command. Logs detailed information about a named SD card handle.
Definition sd.c:1803
static ERR_te sd_cmd_list_handler(uint32_t argc, char **argv)
CLI handler for the "list" command. Logs the names of all active SD card handles.
Definition sd.c:1761
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_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
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 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 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 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
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
ERR_te sd_start_subsys(void)
Starts the SD card subsystem.
Definition sd.c:386
ERR_te sd_stop_subsys(void)
Stops the SD card subsystem.
Definition sd.c:410
ERR_te sd_deinit_handle(SD_HANDLE_ts *sd_handle)
Deinitializes an SD card handle and resets the SPI peripheral.
Definition sd.c:727
ERR_te sd_init_subsys(void)
Initializes the SD card subsystem.
Definition sd.c:325
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.
Definition sd.c:805
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.
Definition sd.c:933
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.
Definition sd.c:434
ERR_te sd_deinit_subsys(void)
Deinitializes the SD card subsystem.
Definition sd.c:361
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.
Definition sd.c:798
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.
Definition sd.c:791
ERR_te sd_get_handle_init(SD_HANDLE_ts *sd_handle, bool *handle_init_o)
Retrieves the initialization state of an SD card handle.
Definition sd.c:784
struct sd_handle_s SD_HANDLE_ts
Opaque handle representing an SD card instance.
Definition sd.h:109
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_PIN_te
GPIO pin number within a port (0–15).
GPIO_ALTERNATE_FUNCTION_te
GPIO alternate function mapping (AF0–AF15).
@ 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_deinit(SPI_REGDEF_ts const *spi_instance)
Deinitializes the SPI peripheral and disables its clock.
void spi_init(SPI_CFG_ts *spi_cfg)
Initializes the SPI peripheral with the given configuration.
void spi_receive(SPI_REGDEF_ts *spi_instance, uint8_t *rx_buffer, uint32_t len)
Blocking SPI receive. Reads len bytes into rx_buffer.
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
Common initialization public API.
Digital IO module public API.
Log subsystem public API.
System module identifier definitions.
SD_MIN_OPERATING_VOLTAGE_te
Minimum allowed operating voltage of the SD card, decoded from the OCR register.
Definition sd.c:82
@ SD_MIN_OPERATING_VOLTAGE_2_6V
Definition sd.c:92
@ SD_MIN_OPERATING_VOLTAGE_2_2V
Definition sd.c:96
@ SD_MIN_OPERATING_VOLTAGE_1_8V
Definition sd.c:100
@ SD_MIN_OPERATING_VOLTAGE_3_5V
Definition sd.c:83
@ SD_MIN_OPERATING_VOLTAGE_1_7V
Definition sd.c:101
@ SD_MIN_OPERATING_VOLTAGE_3_3V
Definition sd.c:85
@ SD_MIN_OPERATING_VOLTAGE_1_6V
Definition sd.c:102
@ SD_MIN_OPERATING_VOLTAGE_3_2V
Definition sd.c:86
@ SD_MIN_OPERATING_VOLTAGE_2_9V
Definition sd.c:89
@ SD_MIN_OPERATING_VOLTAGE_2_8V
Definition sd.c:90
@ SD_MIN_OPERATING_VOLTAGE_2_3V
Definition sd.c:95
@ SD_MIN_OPERATING_VOLTAGE_2_5V
Definition sd.c:93
@ SD_MIN_OPERATING_VOLTAGE_2_0V
Definition sd.c:98
@ SD_MIN_OPERATING_VOLTAGE_3_1V
Definition sd.c:87
@ SD_MIN_OPERATING_VOLTAGE_3_4V
Definition sd.c:84
@ SD_MIN_OPERATING_VOLTAGE_2_4V
Definition sd.c:94
@ SD_MIN_OPERATING_VOLTAGE_3_0V
Definition sd.c:88
@ SD_MIN_OPERATING_VOLTAGE_2_1V
Definition sd.c:97
@ SD_MIN_OPERATING_VOLTAGE_1_9V
Definition sd.c:99
@ SD_MIN_OPERATING_VOLTAGE_2_7V
Definition sd.c:91
SD_TYPE_te
Card type decoded from the OCR Capacity Status bit.
Definition sd.c:150
@ SDSC
Definition sd.c:151
@ SDHC
Definition sd.c:152
CMD_INFO_ts sd_cmds[]
Table of CLI commands registered by the SD card subsystem.
Definition sd.c:292
SD_MAX_OPERATIING_VOLTAGE_te
Maximum allowed operating voltage of the SD card, decoded from the OCR register.
Definition sd.c:108
@ SD_MAX_OPERATING_VOLTAGE_1_9V
Definition sd.c:126
@ SD_MAX_OPERATING_VOLTAGE_2_2V
Definition sd.c:123
@ SD_MAX_OPERATING_VOLTAGE_2_8V
Definition sd.c:117
@ SD_MAX_OPERATING_VOLTAGE_1_8V
Definition sd.c:127
@ SD_MAX_OPERATING_VOLTAGE_3_2V
Definition sd.c:113
@ SD_MAX_OPERATING_VOLTAGE_2_3V
Definition sd.c:122
@ SD_MAX_OPERATING_VOLTAGE_2_4V
Definition sd.c:121
@ SD_MAX_OPERATING_VOLTAGE_3_3V
Definition sd.c:112
@ SD_MAX_OPERATING_VOLTAGE_1_7V
Definition sd.c:128
@ SD_MAX_OPERATING_VOLTAGE_3_5V
Definition sd.c:110
@ SD_MAX_OPERATING_VOLTAGE_3_4V
Definition sd.c:111
@ SD_MAX_OPERATING_VOLTAGE_2_1V
Definition sd.c:124
@ SD_MAX_OPERATING_VOLTAGE_2_6V
Definition sd.c:119
@ SD_MAX_OPERATING_VOLTAGE_3_6V
Definition sd.c:109
@ SD_MAX_OPERATING_VOLTAGE_2_7V
Definition sd.c:118
@ SD_MAX_OPERATING_VOLTAGE_2_0V
Definition sd.c:125
@ SD_MAX_OPERATING_VOLTAGE_2_9V
Definition sd.c:116
@ SD_MAX_OPERATING_VOLTAGE_2_5V
Definition sd.c:120
@ SD_MAX_OPERATING_VOLTAGE_3_0V
Definition sd.c:115
@ SD_MAX_OPERATING_VOLTAGE_3_1V
Definition sd.c:114
CMD_CLIENT_INFO_ts sd_cmd_client_info
Registration descriptor passed to the command subsystem.
Definition sd.c:312
SD_PWRUP_STATUS_te
Power-up completion status decoded from the OCR register.
Definition sd.c:142
@ SD_PWRUP_STATUS_BUSY
Definition sd.c:143
@ SD_PWRUP_STATUS_READY
Definition sd.c:144
OCR_te
Bit positions within the 32-bit OCR register.
Definition sd.c:54
@ OCR_3_4V_3_3V
Definition sd.c:72
@ OCR_3_0V_2_9V
Definition sd.c:68
@ OCR_2_3V_2_2V
Definition sd.c:61
@ OCR_3_2V_3_1V
Definition sd.c:70
@ OCR_3_1V_3_0V
Definition sd.c:69
@ OCR_1_8V_1_7V
Definition sd.c:56
@ OCR_3_3V_3_2V
Definition sd.c:71
@ OCR_2_0V_1_9V
Definition sd.c:58
@ OCR_2_2V_2_1V
Definition sd.c:60
@ OCR_1_9V_1_8V
Definition sd.c:57
@ OCR_3_6V_3_5V
Definition sd.c:74
@ OCR_PWRUP_STATUS
Definition sd.c:76
@ OCR_2_8V_2_7V
Definition sd.c:66
@ OCR_2_9V_2_8V
Definition sd.c:67
@ OCR_2_1V_2_0V
Definition sd.c:59
@ OCR_2_4V_2_3V
Definition sd.c:62
@ OCR_1_7V_1_6V
Definition sd.c:55
@ OCR_2_5V_2_4V
Definition sd.c:63
@ OCR_CAPACITY_STATUS
Definition sd.c:75
@ OCR_2_6V_2_5V
Definition sd.c:64
@ OCR_3_5V_3_4V
Definition sd.c:73
@ OCR_2_7V_2_6V
Definition sd.c:65
SD_ADDR_MODE_te
Addressing mode used by the SD card for read/write sector addresses.
Definition sd.c:134
@ SD_ADDR_MODE_BYTE
Definition sd.c:135
@ SD_ADDR_MODE_BLOCK
Definition sd.c:136
SD card driver public API.
STM32F401RE MCU-specific peripheral register definitions and bit position enumerations.
STM32F401RE GPIO driver public API.
STM32F401RE RCC driver public API.
STM32F401RE SPI driver public API.
Describes a subsystem client registering with the command module.
Definition cmd.h:92
Describes a single command exposed by a client.
Definition cmd.h:72
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
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
GPIO peripheral register map.
Definition stm32f401re.h:95
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
Configuration structure for initializing an SD card handle.
Definition sd.h:66
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
Decoded contents of the SD card CSD register.
Definition sd.c:163
uint8_t wp_grp_enable
Definition sd.c:193
uint32_t block_count
Definition sd.c:167
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
uint32_t capacity_mb
Definition sd.c:165
uint8_t r2w_factor
Definition sd.c:194
struct SD_CSD_INFO_ts::@123136205353006350230173346147067177263037234074 v2
uint8_t erase_blk_en
Definition sd.c:190
uint8_t tran_speed
Definition sd.c:168
uint16_t block_len
Definition sd.c:166
uint8_t write_blk_misalign
Definition sd.c:187
uint16_t c_size
Definition sd.c:174
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
SPI peripheral register map.
Internal state of the SysTick driver.
MODULES_te subsys
Definition button.c:95
uint32_t sd_num
Definition sd.c:256
LOG_LEVEL_te log_level
Definition button.c:92
SD_HANDLE_ts sds[CONFIG_SD_MAX_OBJECTS]
Definition sd.c:247
Internal structure representing a single SD card handle instance.
Definition sd.c:214
SD_MAX_OPERATIING_VOLTAGE_te max_operating_voltage
Definition sd.c:230
GPIO_REGDEF_ts * mosi_gpio_port
Definition sd.c:220
char name[CONFIG_SD_MAX_NAME_LEN]
Definition sd.c:215
GPIO_REGDEF_ts * sclk_gpio_port
Definition sd.c:217
uint32_t block_count
Definition sd.c:232
SD_TYPE_te type
Definition sd.c:228
bool initialized
Definition sd.c:234
GPIO_PIN_te mosi_gpio_pin
Definition sd.c:224
SD_MIN_OPERATING_VOLTAGE_te min_operating_voltage
Definition sd.c:229
bool in_use
Definition sd.c:235
GPIO_PIN_te miso_gpio_pin
Definition sd.c:223
uint32_t capacity_mb
Definition sd.c:233
GPIO_REGDEF_ts * cs_gpio_port
Definition sd.c:218
SD_ADDR_MODE_te addr_mode
Definition sd.c:227
GPIO_REGDEF_ts * miso_gpio_port
Definition sd.c:219
GPIO_PIN_te sclk_gpio_pin
Definition sd.c:221
GPIO_PIN_te cs_gpio_pin
Definition sd.c:222
SD_PWRUP_STATUS_te pwrup_status
Definition sd.c:226
SPI_REGDEF_ts * spi_instance
Definition sd.c:216
GPIO_ALTERNATE_FUNCTION_te gpio_alternate_function
Definition sd.c:225
uint32_t block_len
Definition sd.c:231