STM3210B_EVAL U盘功能 USB + SPI +SD 增加对SDHC卡支持
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卡支持相关推荐
- USB硬件 键盘鼠标控制器 V2.0 支持二次开发
USB硬件 控制键盘鼠标 V2.0 支持二次开发提供开发包 usb键盘鼠标控制器由来: 听说过"按键精灵"这个软件,就不难理解了;就是这个思路,做一个真正的硬件键盘鼠标,然后我们控 ...
- ZYNQ裸机实现 USB MASS STORAGE (usb+sd卡 实现U盘功能)
ZYNQ裸机实现 USB MASS STORAGE (usb+sd卡 实现U盘功能) 之所以写裸机,也就是没有操作系统的实现方法是因为linux系统下的实现方法网上已经有很多了,之前使用的STM32实 ...
- usb扩展坞同时接键盘鼠标_这个多功能扩展坞,增加多个接口,笔记本秒变工作站...
原标题:这个多功能扩展坞,增加多个接口,笔记本秒变工作站 为了给笔记本电脑"减负" 越做越薄,接口也是越来越少 很多接口功能都被省去 ... 可是想接入的设备却有很多:鼠标.U盘. ...
- c# 再次尝试 连接失败_[图]连接USB或者SD卡的PC将阻止升级Windows 10 May 2019功能更新...
如果设备在连接外部USB设备或者读卡器的时候,计算机将会阻止升级Windows 10 May 2019(Version 1903)功能更新.在4月24日发布的技术咨询中,微软解释称当连接外部USB设备 ...
- stm32 cubemx usb spi flash w25q128 u盘调试笔记
真的太简单了,十分钟就搞定 参考文章 我卡住了几天,最后发现delay函数的问题,去掉就好了.(评论大佬解释了这一现象) 步骤如下 使用cube mx 生成基本代码 调试spi flash 调试usb ...
- STM32F407 SPI SD卡驱动的验证
试验原因 网上靠谱的STM32F4的SPI方式SD卡驱动不多. 包括ST官方板子,都不用SPI_SD的驱动方式,而是用SDIO. 如果没有官方资料加持,出问题时真头疼, 相当于一个人在玩. 自己板子上 ...
- H7-TOOL发布V2.20带来原创RTOS Trace,截图,Scope功能,脱机烧录增加PSoC6, 中颖, 笙泉, 韦斯佰瑞, nRF9160, 杰发科技新系列等
新功能视频介绍: https://www.bilibili.com/video/BV1ss4y1f7MV H7-TOOL发布原创RTOS Trace,GUI截图,Scope功能,脱机烧录增加PSoC6 ...
- Linux Gadget的一点研究之U盘和USB虚拟串口
origin: https://blog.csdn.net/wuyuwei45/article/details/8926858 Linux kernel2.6以上的版本中,USB设备驱动的接口改为了g ...
- Android4.4KitKat支持u盘功能
Android4.4KitKat支持u盘功能 作者: 发布日期:2014-05-14 23:16:13 我来说两句(0) 0 Tag标签:功能 Android U 盘功能实现和分析 u 盘功能实 ...
- Android 4.4 KitKat 支持 u 盘功能
Android U 盘功能实现和分析 u 盘功能实现结果: u 盘会当成 usb storage 在 Settings Storage 里面显示. 准备工作 内核需支持 usb host,需支持 FU ...
最新文章
- Linux记录-普通用户下执行sudo xxx 找不到命令解决方案
- Redhat EL 5.3上安装Cacti(4)- 编译安装rrdtool及安装配置snmp
- oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
- mysql amoeba 事务_MySQL基于Amoeba实现读写分离
- 高精度计时器 -- C++/Windows版
- php 替换 数组,php如何替换数组的值
- 最新前端中高级面试题
- SpringBoot 2.0 整合Mybatis详细步骤
- dism /online /get-packages与dism /image:e:\ /get-packages
- Oracle 12c新特性--ASMFD(ASM Filter Driver)特性
- 让国外买家秒回复的询盘模板合集
- 数据错误循环冗余检查是什么意思_德尔西曼.交换机是一种什么设备?通过什么方式进行交换?...
- ubuntu双系统时间不一致现象
- 消费复苏中的企业该走向何处?
- EverNote开源协议-Android
- php排行榜系统,cms排行_PHP CMS系统排行榜
- 手把手教-在自己的服务器上运行psychopy线上实验
- 软件著作权 -- 注册+实名认证
- MySQL学习笔记--常用存储引擎InnoDB与MyISAM总结
- python中的 split()函数