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

刚开始学习使用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\。
文件夹下是各种板的例程,使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程_第1张图片
我参考的是C:\Users\raytine\STM32Cube\Repository\STM32Cube_FW_F4_V1.23.0\Projects\STM324xG_EVAL\Applications\USB_Device\MSC_Standalone使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程_第2张图片
官方例程基本上只看usbd_storage.c文件就可以了,应该是只需要修改这一个文件内容即可,cube生成的工程对应的文件是usbd_storage_if.c
官方例程
使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程_第3张图片

生成的工程
使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程_第4张图片

通过对比代码可以发现,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;
}

至此代码修改完成,就可以进行编译调试了。
运行结果,还是成功的。
使用STM32F407实现USB读卡器功能 SDIO DMA 参考官方例程_第5张图片

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

你可能感兴趣的:(STM32)