当前位置:   article > 正文

ESP32驱动SD卡实战_esp32 sd卡

esp32 sd卡

1、SD卡介绍

 SD卡有SD、MiniSD和microSD三种类型。可以访问如下链接查看更多规定。https://www.sdcard.org icon-default.png?t=N7T8https://www.sdcard.org

 最新SD卡规格的参数如下图所示:

其中脚位数对应实卡上的"金手指"数,不同的类型的卡的触点数量不同,访问的速度也不同。

SD卡常见的两种访问接口模式是SDIO模式和SPI模式。

如下图SD卡对于两种模式的引脚功能定义:

microSD卡引脚功能如下图:

 注: S: 电源    I: 输入     O: 推挽输出     PP: 推挽

SD卡内部物理结构如下图所示:

SD卡的寄存器信息如下:

SD卡的OCR、CID、CSD、和SCR寄存器保存卡的配置信息。RCA寄存器保存着通信过程中

卡当前暂时分配的地址(只适合SDIO模式,SPI模式下没有)。CSR寄存器表示卡状态(Card Status)

和SSR寄存器SD状态(SD Status)寄存器保存着卡的状态(例如:是否写成功,通信的CRC校验是否

正确等),这两个寄存器的内容与通信模式(SD模式或SPI模式)相关。MMC卡没有SRC和SSR寄存

器。

2、SD卡命令

SD卡所有的命令都是固定长度48bit,6个Byte。格式如下图:

起始位:固定为0。

传输位:表示传输方向(主机 =1,从机=0)

命令号:占6个bit。

参数:占32个bit,4字节。

CRC7:7位CRC校验位。

结束位:占1bit。

SD卡的命令一共被分为了12类,分为Class0~Class11。比较重要的命令如下图:

3、卡模式

1.卡识别模式

SD卡系统定义了如下图几个工作模式。

对于开发来说只有卡识别和数据传输两种有效操作模式。

主机在系统复位后,处于卡识别模式。寻找总线上可用的SD卡。同时SD卡也处于卡识别模式,

直到被主机识别到,即SD卡在卡识别状态下收到CDM3(SEND_RCA)命令后,SD卡进入数据

传输模式,主机需在总线上所有卡被识别后进入数据传输模式。

SD卡识别模式状态转换如下图所示:

2、数据模式

SD卡有两种数据模式,一种是常规8位宽度,即一次按一字节传输。另一种是512字节传输。本次只使用

第一种单字节传输模式。每次传输从最低字节开始,每字节从最高位(MSB开始发送。数据传输模式下

SD卡状态转换过程如下图所示:

4、SPI模式下SD卡初始化流程

SPI下SD卡的初始化时序如下图所示:

根据初始化时序图,SPI模式下SD卡的初始化主要有以下几个步骤

1、初始化主机与SD卡连接的硬件条件(MCU的SPI配置,IO配置)

2、主机拉低片选(CS)信号,SD卡上电延时(74个CLK)。

3、复位卡(CMD0),进入IDLE状态。

4、发送CMD8命令,检查是否支持2.0协议。

5、根据不同协议检查SD卡(命令包括:CMD55、ACMD41、CMD58和CMD1等)。

6、取消片选,发多8个CLK信号,结束初始化。

以上步骤就可以完成对SD卡的初始化。接下来就可以对SD卡进行读写数据。

SD卡扇区读取数据,具体过程如下:

1、发送CMD17。

2、接收卡响应R1。

3、接收数据起始令牌0xFE。

4、接收数据。

5、接收2个字节的CRC,如果不使用CRC,这两个字节在读取后可以丢掉。

6、禁止片选之后,发多8个CLK。

SD卡写数据的过程如下所示:

1、发送CMD24。

2、接收卡响应R1。

3、发送写数据起始令牌0xFE。

4、发送数据。

5、发送2字节的伪CRC。

6、禁止片选之后,发多8个CLK。

更多资料请查看官方资料  https://www.sdcard.org/

5、ESP32-S3模组的 SD/MMC概述

ESP32-S3模组支持两个外部卡,但不支持同时工作。其内部连接结构如下图所示:

6、ESP32代码编写

1、SPI外设初始化

  1. void spi2_init(void)
  2. {
  3. esp_err_t ret = 0;
  4. spi_bus_config_t spi_bus_conf = {0};
  5. /* SPI总线配置 */
  6. spi_bus_conf.miso_io_num = SPI_MISO_GPIO_PIN; /* SPI_MISO引脚 */
  7. spi_bus_conf.mosi_io_num = SPI_MOSI_GPIO_PIN; /* SPI_MOSI引脚 */
  8. spi_bus_conf.sclk_io_num = SPI_CLK_GPIO_PIN; /* SPI_SCLK引脚 */
  9. spi_bus_conf.quadwp_io_num = -1; /* SPI写保护信号引脚,该引脚未使能 */
  10. spi_bus_conf.quadhd_io_num = -1; /* SPI保持信号引脚,该引脚未使能 */
  11. spi_bus_conf.max_transfer_sz = 320 * 240 * 2; /* 配置最大传输大小,以字节为单位 */
  12. /* 初始化SPI总线 */
  13. ret = spi_bus_initialize(SPI2_HOST, &spi_bus_conf, SPI_DMA_CH_AUTO); /* SPI总线初始化 */
  14. ESP_ERROR_CHECK(ret); /* 校验参数值 */
  15. // /* 添加SPI总线设备 */
  16. }

2、SD卡初始化函数

  1. /*
  2. *@brief SD卡初始化
  3. *@param 无
  4. *retval esp_err_t
  5. */
  6. esp_err_t sd_spi_init(void)
  7. {
  8. esp_err_t ret = ESP_OK;
  9. if(Sky_SD_Handle != NULL)
  10. {
  11. spi_bus_remove_device(Sky_SD_Handle); /*移除SPI上的SD卡设备*/
  12. if(mount_ret == ESP_OK)
  13. {
  14. esp_vfs_fat_sdcard_unmount(mount_point, card); //取消挂载
  15. }
  16. }
  17. /*SPI驱动接口配置,SPISD卡时钟是20-25MHZ*/
  18. spi_device_interface_config_t devcfg = {
  19. .clock_speed_hz = 20 * 1000 * 1000, //SPI时钟
  20. .mode = 0, //SPI模式0
  21. .spics_io_num = SD_NUM_CS, //片选引脚
  22. .queue_size = 7, //事务队列尺寸7
  23. };
  24. ret = spi_bus_add_device(SPI2_HOST, &devcfg, &Sky_SD_Handle); //添加SPI总线设备
  25. esp_vfs_fat_sdmmc_mount_config_t mount_config = {
  26. .format_if_mount_failed = false, //若挂载失败:true会重新分区和格式化/false不会重新分区和格式化
  27. .max_files = 5, //打开文件最大数量
  28. .allocation_unit_size = 4 * 1024 * sizeof(uint8_t) //硬盘分区的大小
  29. };
  30. /*SD 卡参数配置*/
  31. sdmmc_host_t host = {0};
  32. host.flags = SDMMC_HOST_FLAG_SPI | SDMMC_HOST_FLAG_DEINIT_ARG; //定义主机属性的标志:SPI协议且可调用deinit函数
  33. host.slot = SPI2_HOST; //使用SPI2端口
  34. host.max_freq_khz = SDMMC_FREQ_DEFAULT; //主机支持的最大频率: 20000
  35. host.io_voltage = 3.3f; //控制器使用的I/O电压
  36. host.init = &sdspi_host_init; //用于初始化驱动程序的主机函数
  37. host.set_bus_width = NULL; //设置总线宽度的主机功能
  38. host.get_bus_width = NULL; //取总线宽度的主机函数
  39. host.set_bus_ddr_mode = NULL; //设置DDR模式的主机功能
  40. host.set_card_clk = &sdspi_host_set_card_clk; //设置板卡时钟频率的主机函数
  41. host.do_transaction = &sdspi_host_do_transaction; //执行事务的主机函数
  42. host.deinit_p = &sdspi_host_remove_device; //用于取消初始化驱动程序的主机函数
  43. host.io_int_enable = &sdspi_host_io_int_enable; //启用SDIO中断线的主机功能
  44. host.io_int_wait = &sdspi_host_io_int_wait; //等待SDIO中断线路激活的主机功能
  45. host.command_timeout_ms = 0; //超时,默认为0
  46. host.get_real_freq = &sdspi_host_get_real_freq;
  47. host.set_cclk_always_on = NULL;
  48. sdspi_device_config_t slot_config ={0};
  49. slot_config.host_id = host.slot;
  50. slot_config.gpio_cs = SD_NUM_CS;
  51. slot_config.gpio_cd = GPIO_NUM_NC;
  52. slot_config.gpio_wp = GPIO_NUM_NC;
  53. slot_config.gpio_int = GPIO_NUM_NC;
  54. mount_ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); //挂载文件系统
  55. ret |= mount_ret;
  56. return ret;
  57. }

3、获取SD卡内存大小测试函数

  1. /*
  2. *@brief 获取SD卡相关信息
  3. *@param out_total_bytes:总大小
  4. *@param out_free_bytes: 剩余带下
  5. *@retval 无
  6. */
  7. void sd_get_fatfs_usage(size_t *total_bytes, size_t *free_bytes)
  8. {
  9. FATFS *fs;
  10. size_t free_clusters;
  11. int res = f_getfree("0:", (size_t *)&free_clusters, &fs);
  12. assert(res == FR_OK);
  13. size_t total_sectors = (fs->n_fatent - 2) * fs->csize;
  14. size_t free_sectors = free_clusters * fs->csize;
  15. size_t sd_total = total_sectors / 1024;
  16. size_t sd_total_KB = sd_total * fs->ssize;
  17. size_t sd_free = free_sectors / 1024;
  18. size_t sd_free_KB = sd_free * fs->ssize;
  19. //假设总大小小于4GiB,对于SPI Flash 因该为true
  20. if(total_bytes != NULL)
  21. {
  22. *total_bytes = sd_total_KB;
  23. }
  24. if(free_bytes != NULL)
  25. {
  26. *free_bytes = sd_free_KB;
  27. }
  28. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/977117
推荐阅读
相关标签
  

闽ICP备14008679号