STM3210B_EVAL 模拟U盘 USB+SPI+SD示例程序 增加对SDHC卡支持

STM3210B_EVAL评估版的 USB Mass Storage 范例中,USB + SPI +SD 很适合硬件资源较少的CPU,笔者尝试用STM32F103RC芯片移植,对原程序GPIO稍作修改即可实现SD V1.1卡的操作,虽速度较慢,但U盘的基本功能还算完整。
美中不足,原程序不能支持SD V2.0/HC协议,市面上流行的8G、16G的HC卡、TF卡,统统用不上,确实比较遗憾。
闲着也是闲着,动手修改了一下程序,顺利调试通过。顺便抓了一把大大小小的卡,V1 2G、V2HC 的 4、8、16SD、TF一一试了一遍,还算满意,遂把这点东西拿出来分享一下。

STM3210B_EVAL套件使用了的CPU是STM32F103VB, PD9作为USB连接控制端(USB_Disconnect_Pin,在platform_config.h中定义),笔者使用的是STM32F103RC,IO口资源不足,就改成了PC 15端口。此时,程序即可正常加载V1.1 的2G SD卡。
需要提醒的是控制端的极性可能各有不同,笔者使用低电平为开启,高电平关闭。如须调整,可以在hw_config.c中修改。

简单点理解,HC卡就是因为容量值太大,超过了普通SD卡协议的扇区寻址范围,所以把HC卡区分出来,读写操作的时候,把地址调整一下即可。卡的识别功能放在stm3210b_eval_spi_sd.c的SD_Init()函数中。识别的流程网上有不少介绍,浓缩如下:
1:上电复位后,CMD0 + CMD8 区分出V1/MMC 或者是V2/HC;
2:MMC 对CMD55 + ACMD41不响应,从而区分出V1和MMC;
3:V2/HC对 CMD55 + ACMD41响应后,取得OCR的值,从而可以区分出HC卡。
代码修改如下:

SD_Error SD_Init(void)
{uint32_t i = 0, retry =0;uint8_t buf[4];/*!< Initialize SD_SPI */SD_LowLevel_Init(); //SPI_SpeedLow();/*!< SD chip select high */SD_CS_HIGH();/*!< Send dummy byte 0xFF, 10 times with CS high *//*!< Rise CS and MOSI for 80 clocks cycles */for (i = 0; i <= 9; i++){/*!< Send dummy byte 0xFF */SD_WriteByte(SD_DUMMY_BYTE);}//indenfy sd card type/*------------Put SD in SPI mode--------------*//*!< SD initialized and set to SPI mode properly */SD_CS_LOW();  /*!< Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode */SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95);/*!< Wait for In Idle State Response (R1 Format) equal to 0x01 */if (SD_GetResponse(0x01) == SD_RESPONSE_NO_ERROR){/*--CMD8 区分V1.1/MMC 或 V2.0/HC --*/SD_SendCmd(SD_CMD_HS_SEND_EXT_CSD,0x1AA,0x87);if(SD_GetResponse(0x01) == SD_RESPONSE_NO_ERROR)    //SD V2.0{for(i = 0;i < 4; i++)buf[i] = SD_ReadByte();       //获取OCRif(buf[2] == 0X01 && buf[3] == 0XAA)     // 2.7~3.6V{retry = 0XFF;do{                   i =0x20;do{SD_SendCmd(SD_CMD_APP_CMD,0,0X01);      //CMD55}while(SD_GetResponse(0x01) && i--);SD_SendCmd(SD_CMD_SD_APP_OP_COND,0x40000000,0X01);       //ACMD41}while(SD_GetResponse(0) && retry--);/*--CMD58--*/SD_SendCmd(CMD58,0,0X01);if(retry && (SD_GetResponse(0) == SD_RESPONSE_NO_ERROR)){for(i = 0; i < 4; i++)buf[i] = SD_ReadByte();              //获取OCRif(buf[0] & 0x40)SD_Type = SDIO_HIGH_CAPACITY_SD_CARD;    //检查CCSelse SD_Type = SDIO_STD_CAPACITY_SD_CARD_V2_0; SD_CS_HIGH();return SD_RESPONSE_NO_ERROR;}}}else//SD V1.x/ MMC V3{retry =0xfff;do{                i =0x20;do{SD_SendCmd(SD_CMD_APP_CMD,0,0X01);      //CMD55}    while(SD_GetResponse(0x01) && i--);SD_SendCmd(SD_CMD_SD_APP_OP_COND,0,0X01);    //CMD41} while(SD_GetResponse(0) && retry--);if(retry)SD_Type = SDIO_STD_CAPACITY_SD_CARD_V1_1;else{retry = 0XFFF;do //MMC 退出IDLE {                                               SD_SendCmd(SD_CMD_SEND_OP_COND ,0,0Xff);    //CMD1}while(!SD_GetResponse(0) && retry--);  if(retry)     //有响应{SD_Type = SDIO_MULTIMEDIA_CARD;//MMC V3SD_SendCmd(SD_CMD_SET_BLOCKLEN,512,0X01);SD_GetResponse(0);}elseSD_Type = SDIO_CARD_ERR  ;   //无响应}}}    return (SD_GoIdleState());
}

后面就对几个读写操作函数稍加修改,以块读取函数为例:

SD_Error SD_ReadBlock(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t BlockSize)
{uint32_t i = 0;SD_Error rvalue = SD_RESPONSE_FAILURE;//添加HC卡地址调整if (SD_Type == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;ReadAddr /= 512;}//OK //以下无变动;/*!< SD chip select low */SD_CS_LOW();    ......

这是涉及到的读写操作函数,同样方法修改一下即可:

SD_Error SD_ReadBlock();
SD_Error SD_ReadMultiBlocks();
SD_Error SD_WriteBlock();
SD_Error SD_WriteMultiBlocks();

不同版本的SD卡,其CSD参数格式略有不同,主要在卡容量描述上。因此,对SD_GetCSDRegister(SD_CSD* SD_csd)函数做适当修改:

 ......//兼容HC卡if (SD_Type == SDIO_HIGH_CAPACITY_SD_CARD){/*!< Byte 7 */i = CSD_Tab[7];SD_csd->DeviceSize  = (i & 0x3F) << 16;/*!< Byte 8 */i = CSD_Tab[8];SD_csd->DeviceSize  |= (i << 8);/*!< Byte 9 */SD_csd->DeviceSize  |= CSD_Tab[9];}else{SD_csd->DeviceSize = (CSD_Tab[6] & 0x03) << 10;/*!< Byte 7 */SD_csd->DeviceSize |= (CSD_Tab[7]) << 2;/*!< Byte 8 */SD_csd->DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;SD_csd->MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;SD_csd->MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);/*!< Byte 9 */SD_csd->MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;SD_csd->MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;SD_csd->DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;/*!< Byte 10 */SD_csd->DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;}//OK......

原程序中,V1.1卡初始化完成后,需执行CMD1 退出Idle模式,而V2.0在识别时已经在Active状态了,所以此步骤可以跳过,可以修改SD_GoIdle()函数。 到此,SD卡识别、读写都已完成。因为USB Mass Storage应用,需要读取SD卡的CSD参数,因此在mass_mal.c的MAL_GetStatus (uint8_t lun)函数中,须修改卡片容量:

 ......DeviceSizeMul = SD_csd.DeviceSizeMul + 2;       Mass_Block_Size[0] = 512;
// SDHC容量       if(SD_Type == SDIO_HIGH_CAPACITY_SD_CARD){Mass_Block_Count[0] = (SD_csd.DeviceSize + 1) * 512 * 1024;}else{temp_block_mul = (1 << SD_csd.RdBlockLen)/ 512;Mass_Block_Count[0] = ((SD_csd.DeviceSize + 1) * (1 << (DeviceSizeMul))) * temp_block_mul;         }
//OK......

其余的一些小改动,如定义卡片类型、CMD指令,都在stm3210b_eval_spi_sd.h中添加。

#define SDIO_STD_CAPACITY_SD_CARD_V1_1             ((uint8_t)0x00)
#define SDIO_STD_CAPACITY_SD_CARD_V2_0             ((uint8_t)0x01)
#define SDIO_HIGH_CAPACITY_SD_CARD                 ((uint8_t)0x02)
#define SDIO_MULTIMEDIA_CARD                       ((uint8_t)0x03)
#define SDIO_SECURE_DIGITAL_IO_CARD                ((uint8_t)0x04)
#define SDIO_HIGH_SPEED_MULTIMEDIA_CARD            ((uint8_t)0x05)
#define SDIO_SECURE_DIGITAL_IO_COMBO_CARD          ((uint8_t)0x06)
#define SDIO_HIGH_CAPACITY_MMC_CARD                ((uint8_t)0x07)
#define SDIO_CARD_ERR                                                            ((uint8_t)0xff)

修改完成后,把它与SDIO接口读写速度进行了对比,无论是DMA模式还是轮询模式,都没多大差别。个人认为还是stm32F103对USB的响应慢,造成瓶颈效应。当然如果排除USB因素,SDIO模式还是快的多。

笔者第一次发帖,能力所限,贴中难免有错误和遗漏,望能获得诸位朋友悉心指正。非常感谢!

STM3210B_EVAL U盘功能 USB + SPI +SD 增加对SDHC卡支持相关推荐

  1. USB硬件 键盘鼠标控制器 V2.0 支持二次开发

    USB硬件 控制键盘鼠标 V2.0 支持二次开发提供开发包 usb键盘鼠标控制器由来: 听说过"按键精灵"这个软件,就不难理解了;就是这个思路,做一个真正的硬件键盘鼠标,然后我们控 ...

  2. ZYNQ裸机实现 USB MASS STORAGE (usb+sd卡 实现U盘功能)

    ZYNQ裸机实现 USB MASS STORAGE (usb+sd卡 实现U盘功能) 之所以写裸机,也就是没有操作系统的实现方法是因为linux系统下的实现方法网上已经有很多了,之前使用的STM32实 ...

  3. usb扩展坞同时接键盘鼠标_这个多功能扩展坞,增加多个接口,笔记本秒变工作站...

    原标题:这个多功能扩展坞,增加多个接口,笔记本秒变工作站 为了给笔记本电脑"减负" 越做越薄,接口也是越来越少 很多接口功能都被省去 ... 可是想接入的设备却有很多:鼠标.U盘. ...

  4. c# 再次尝试 连接失败_[图]连接USB或者SD卡的PC将阻止升级Windows 10 May 2019功能更新...

    如果设备在连接外部USB设备或者读卡器的时候,计算机将会阻止升级Windows 10 May 2019(Version 1903)功能更新.在4月24日发布的技术咨询中,微软解释称当连接外部USB设备 ...

  5. stm32 cubemx usb spi flash w25q128 u盘调试笔记

    真的太简单了,十分钟就搞定 参考文章 我卡住了几天,最后发现delay函数的问题,去掉就好了.(评论大佬解释了这一现象) 步骤如下 使用cube mx 生成基本代码 调试spi flash 调试usb ...

  6. STM32F407 SPI SD卡驱动的验证

    试验原因 网上靠谱的STM32F4的SPI方式SD卡驱动不多. 包括ST官方板子,都不用SPI_SD的驱动方式,而是用SDIO. 如果没有官方资料加持,出问题时真头疼, 相当于一个人在玩. 自己板子上 ...

  7. H7-TOOL发布V2.20带来原创RTOS Trace,截图,Scope功能,脱机烧录增加PSoC6, 中颖, 笙泉, 韦斯佰瑞, nRF9160, 杰发科技新系列等

    新功能视频介绍: https://www.bilibili.com/video/BV1ss4y1f7MV H7-TOOL发布原创RTOS Trace,GUI截图,Scope功能,脱机烧录增加PSoC6 ...

  8. Linux Gadget的一点研究之U盘和USB虚拟串口

    origin: https://blog.csdn.net/wuyuwei45/article/details/8926858 Linux kernel2.6以上的版本中,USB设备驱动的接口改为了g ...

  9. Android4.4KitKat支持u盘功能

    Android4.4KitKat支持u盘功能 作者:  发布日期:2014-05-14 23:16:13 我来说两句(0) 0 Tag标签:功能   Android U 盘功能实现和分析 u 盘功能实 ...

  10. Android 4.4 KitKat 支持 u 盘功能

    Android U 盘功能实现和分析 u 盘功能实现结果: u 盘会当成 usb storage 在 Settings Storage 里面显示. 准备工作 内核需支持 usb host,需支持 FU ...

最新文章

  1. Linux记录-普通用户下执行sudo xxx 找不到命令解决方案
  2. Redhat EL 5.3上安装Cacti(4)- 编译安装rrdtool及安装配置snmp
  3. oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
  4. mysql amoeba 事务_MySQL基于Amoeba实现读写分离
  5. 高精度计时器 -- C++/Windows版
  6. php 替换 数组,php如何替换数组的值
  7. 最新前端中高级面试题
  8. SpringBoot 2.0 整合Mybatis详细步骤
  9. dism /online /get-packages与dism /image:e:\ /get-packages
  10. Oracle 12c新特性--ASMFD(ASM Filter Driver)特性
  11. 让国外买家秒回复的询盘模板合集
  12. 数据错误循环冗余检查是什么意思_德尔西曼.交换机是一种什么设备?通过什么方式进行交换?...
  13. ubuntu双系统时间不一致现象
  14. 消费复苏中的企业该走向何处?
  15. EverNote开源协议-Android
  16. php排行榜系统,cms排行_PHP CMS系统排行榜
  17. 手把手教-在自己的服务器上运行psychopy线上实验
  18. 软件著作权 -- 注册+实名认证
  19. MySQL学习笔记--常用存储引擎InnoDB与MyISAM总结
  20. python中的 split()函数

热门文章

  1. 我的团长我的团分集剧情介绍
  2. C\C++ | FILE文件基本操作函数
  3. 能否在计算机界面保存快捷方式,详细教您清理1kb快捷方式病毒
  4. 聊一聊我常用的6种绘制地图的方法
  5. PHPstorm设置字体大小
  6. BE-Gradient 微流控芯片用于胶质母细胞瘤的研究
  7. 快速解决打印机后台程序服务没有运行的问题
  8. 计算机会说,计算机会有意识吗?你以为就我们才有吗~
  9. php圆形设计图,教程|PHP如何制作圆形用户头像?
  10. 关于QtCreator中三种不同编译版本 debug、release、profile 的区别