使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程

本文详细记录了使用STM32 F407ZGT6芯片开发USB读卡器的过程,包括开发环境搭建、配置要点、官方例程应用及代码修改技巧。作者分享了如何解决常见问题,如USB识别、格式化提示等,为初学者提供了一套完整的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚开始学习使用STM32的USB,之前的USB虚拟串口就折腾了半天,在网上找的资料大部分都不知道从哪直接复制过来的,没有多大参考意义,这次的读卡器也是一样,几乎翻遍了能找到的资料,照猫画虎编辑代码却都不成功,后来发现直接找STM32官方的例程看是最靠谱的,重点:一定要看和自己使用的库版本一致的例程,高手除外。
话不多说,进入主题,首先介绍一下开发环境:
1、keil 版本 5.16
2、cube 版本 5.0(第一次使用5.0的,刚装上还以为下错软件了)
3、库函数版本 STM32Cube_FW_F4_V1.23.0 (这个一般不会专门去下,安装完cube新建F4工程时会提示下载库,可以选择版本,我这里使用的当时最新的版本)
4、开发板一块(stm32F407zgt6 芯片),网上买的便宜的,可能有坑,还没遇到,建议初学的还是买大品牌的或者官方的,比较踏实。再就是调试前确认自己使用的板子电路连接、走线没有问题,这很重要。

首先使用cube配置芯片,这里不多做赘述,网上这部分资料还是比较多的,需要注意的点有三个:
1、开启sdio的两个dma通道,配置中断优先级很重要,优先级从高到低依次为sdio、(SDIO对应dma通道)、usb中断;
2、usb端口的配置,这里需要说明的就是usb口的选择,F407有两个usb 一个HS,一个FS,这里选择的是HS;
3、还有一个就是修改堆栈的大小,找到的资料都说因为使用了dma,所以到加大stack的大小,0x1000就可以了,同时我把heap也修改成了0x1000。

其他的就是配置好想用的其他外设资源,以及开启usb对应的msc功能,设置都是默认的,没有做修改,最后就可以生成工程了。

下边就是代码编辑的部分了,强烈建议大家先看看STM官方的例程,基本上认真看完的下边就不用再看了。官方例程的存放路径 C:\Users\raytine\STM32Cube\Repository\STM32Cube_FW_F4_V1.23.0\Projects,前边的C:\Users\raytine\ 是自己电脑里边的个人用户对应的文件夹,我电脑的用户名是:reytine 所以就是C:\Users\raytine\。
文件夹下是各种板的例程,在这里插入图片描述
我参考的是C:\Users\raytine\STM32Cube\Repository\STM32Cube_FW_F4_V1.23.0\Projects\STM324xG_EVAL\Applications\USB_Device\MSC_Standalone在这里插入图片描述
官方例程基本上只看usbd_storage.c文件就可以了,应该是只需要修改这一个文件内容即可,cube生成的工程对应的文件是usbd_storage_if.c
官方例程
在这里插入图片描述

生成的工程
在这里插入图片描述

通过对比代码可以发现,usbd_storage_if.c下对应的几个函数都是空的,需要自己填上代码,对应官方例程的代码

变量声明

__IO uint32_t writestatus, readstatus = 0;

修改的函数,这里的函数我都进行了修改,看得其他资料都是说只需要修改STORAGE_GetCapacity、STORAGE_Read、STORAGE_Write(工程对应的函数名为STORAGE_GetCapacity_HS 、STORAGE_Read_HS 、STORAGE_Write_HS ,可能跟函数版本和使用的USB接口不同有关系)这三个函数即可,我照着做了,但调试的时候电脑只能识别有可移动设备,提示需要格式化,并且看不到SD卡的内容。至于哪个函数不修改也不影响使用这点还没有测试。
另外需要提的一点是,官方例程里边对SD卡的操作都是BSP_开头的函数,我的工程也有,有可能跟我配置CUBE的时候增加了fatfs有关,原来印象里没有bsp_driver_sd.c 文件,对比了一下bsp_driver_sd.c文件里边的函数最终还是使用的hal_库文件,应该也可以直接使用hal_开头的库文件。这里没有验证,有兴趣的可以自己试一下。

int8_t STORAGE_Init(uint8_t lun)
{
  BSP_SD_Init();
  return 0;
}

int8_t STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  HAL_SD_CardInfoTypeDef info;
  int8_t ret = -1;  
  
  if(BSP_SD_IsDetected() != SD_NOT_PRESENT)
  {
    BSP_SD_GetCardInfo(&info);
    
    *block_num =  info.LogBlockNbr  - 1;
    *block_size = info.LogBlockSize;
    ret = 0;
  }
  return ret;
}

int8_t STORAGE_IsReady(uint8_t lun)
{
  static int8_t prev_status = 0;
  int8_t ret = -1;
  
  if(BSP_SD_IsDetected() != SD_NOT_PRESENT)
  {
    if(prev_status < 0)
    {
      BSP_SD_Init();
      prev_status = 0;
      
    }
    if(BSP_SD_GetCardState() == SD_TRANSFER_OK)
    {
      ret = 0;
    }
  }
  else if(prev_status == 0)
  {
    prev_status = -1;
  }
  return ret;
}

int8_t STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  int8_t ret = -1;  
  
  if(BSP_SD_IsDetected() != SD_NOT_PRESENT)
  {  
    BSP_SD_ReadBlocks_DMA((uint32_t *)buf, blk_addr, blk_len);

    /* Wait for Rx Transfer completion */
    while (readstatus == 0){}
    readstatus = 0;

    /* Wait until SD card is ready to use for new operation */
    while (BSP_SD_GetCardState() != SD_TRANSFER_OK){}
    ret = 0;
  }
  return ret;
}

int8_t STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  int8_t ret = -1;  
  
  if(BSP_SD_IsDetected() != SD_NOT_PRESENT)
  { 
    BSP_SD_WriteBlocks_DMA((uint32_t *)buf, blk_addr, blk_len);
    
    /* Wait for Tx Transfer completion */
    while (writestatus == 0){}
    writestatus = 0;
    
    /* Wait until SD card is ready to use for new operation */
    while (BSP_SD_GetCardState() != SD_TRANSFER_OK){}
    ret = 0;
  }
  return ret;
}


另外还有两个回调函数

void BSP_SD_WriteCpltCallback(void)
{
  writestatus = 1;
}

void BSP_SD_ReadCpltCallback(void)
{
  readstatus = 1;
}

至此代码修改完成,就可以进行编译调试了。
运行结果,还是成功的。
在这里插入图片描述

目前剩余的问题就是这样实现的读卡器速度有点慢,只打开SD卡都要读进度条,这个估计有优化的空间。

<think>好的,我现在需要帮助用户了解如何在STM32F407上通过SDIO接口实现TF卡的读写操作。用户提到了参考的引用资料,我需要结合这些信息来构建一个清晰的步骤指南。 首先,我得确定用户的需求。他们可能已经有一定的STM32开发经验,但对SDIO和FATFS的集成不太熟悉。需要从硬件配置开始,确保SDIO接口正确连接TF卡。根据引用[3],用户提到SPI方式的硬件连接,但这里用户问的是SDIO,所以需要转向SDIO的引脚配置。引用[4]中的初始化代码和错误处理可能需要参考。 接下来,软件配置部分。用户可能需要使用CubeMX来配置SDIO外设,设置正确的时钟分频,以确保通信速度。引用[3]提到分频可能过高导致速度慢,所以需要注意时钟配置。此外,引用[4]中的初始化流程和错误提示需要包括进去,比如检查SD卡是否连接正确。 然后是FATFS的移植,引用[5]中的初始化代码示例,需要将SD卡驱动链接到FATFS。用户可能需要添加FATFS中间件,并处理文件系统的挂载。引用[2]建议先测试基础的读写再集成FATFS,这可能是一个好的步骤,确保底层驱动正常后再处理文件系统。 代码实现部分需要包括初始化、读写函数。用户可能需要使用f_open、f_write等函数,但引用[1]提到这些函数偶尔有问题,可能需要硬件流控制或检查底层驱动。此外,引用[3]提到调整分频以提高速度,所以在代码中可能需要优化时钟设置。 测试和调试步骤也很重要。用户需要先验证SD卡的初始化,然后进行简单的读写测试,对比数据是否正确。引用[2]建议写入后读取并比较数据,确保一致性。如果出现问题,可能需要检查硬件连接或驱动配置。 最后,生成相关问题需要考虑用户可能的后续疑问,比如如何优化速度、处理大文件或使用DMA。引用[1]提到的硬件流使能可能是一个优化点,可以作为一个问题。此外,错误处理和应用场景也是常见的疑问点。 整合这些信息时,要确保步骤清晰,代码示例正确,并引用相关的参考资料。同时,语言要简洁,符合中文习惯,避免技术术语过于晦涩。可能还需要提醒用户注意常见的错误,如初始化失败或读写不一致的问题,并参考提供的引用资料中的解决方法。</think>在STM32F407上通过SDIO接口实现TF卡读写操作,需结合硬件配置、驱动移植和FATFS文件系统。以下是分步实现方案: --- ### 1. **硬件配置** - **SDIO引脚连接**:TF卡通过SDIO接口与STM32F407通信,需连接以下引脚: - CLK(PC12)、CMD(PD2)、D0(PC8)、D1(PC9)、D2(PC10)、D3(PC11)[^4] - **电源与上拉电阻**:确保TF卡供电稳定,数据线需加上拉电阻(通常4.7kΩ)。 --- ### 2. **软件配置(CubeMX)** 1. **启用SDIO外设**: - 模式选择:4位总线宽度(SD 4 bits Wide bus) - 时钟分频:初始阶段建议高频率(如24MHz),后续可调整优化[^3] 2. **启用DMA(可选)**:为提升性能,可为SDIO RX/TX通道配置DMA。 3. **生成代码**:生成初始化代码后,检查`HAL_SD_MspInit`函数是否正确配置GPIO和时钟。 --- ### 3. **SD卡驱动移植** ```c // 示例:SD卡初始化与状态检测 SD_HandleTypeDef hsd; if (HAL_SD_Init(&hsd) != HAL_OK) { printf("SD卡初始化失败,检查硬件连接或更换TF卡!\n"); // } else { printf("SD卡初始化成功!\n"); // 获取卡信息 HAL_SD_CardInfoTypeDef CardInfo; HAL_SD_GetCardInfo(&hsd, &CardInfo); } ``` --- ### 4. **FATFS文件系统集成** 1. **添加FATFS中间件**: - 在CubeMX中启用FATFS,选择`SD Card`作为存储设备。 - 实现底层读写接口(`disk_initialize`, `disk_read`, `disk_write`)[^5]。 2. **文件系统挂载**: ```c FATFS fs; FIL file; uint8_t ret = f_mount(&fs, SDPath, 1); // SDPath为驱动路径(如"0:") if (ret != FR_OK) { printf("挂载文件系统失败,错误码:%d\n", ret); } ``` --- ### 5. **读写操作示例** ```c // 写入文件 char data[] = "Hello, TF Card!"; UINT bytes_written; f_open(&file, "test.txt", FA_WRITE | FA_CREATE_ALWAYS); f_write(&file, data, sizeof(data), &bytes_written); f_close(&file); // 读取文件 char buffer[50]; UINT bytes_read; f_open(&file, "test.txt", FA_READ); f_read(&file, buffer, sizeof(buffer), &bytes_read); f_close(&file); printf("读取内容:%s\n", buffer); // 应与写入数据一致[^2] ``` --- ### 6. **调试与优化** - **稳定性检查**:若出现`FS_DISK_ERR`,尝试启用SDIO硬件流控制(STM32CubeMX配置)[^1]。 - **速度优化**:调整SDIO时钟分频(如降至8分频),使用DMA传输[^3]。 - **错误处理**:在读写操作后检查`HAL_SD_GetError(&hsd)`,定位硬件或时序问题。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值