STM32单片机制作的双盘符U盘 /w\
金坷居士2015/07/03电子技术 IP:澳大利亚
近来在鼓捣STM32,玩了两个星期,感觉都玩的差不多了,于是准备做个U盘。

首先晒自制的STM32开发板(其实上面就一个LDO稳压器提供3.3V)
它曾经只素一个LQFP转接板...
IMG_6673.jpg
掺了USB
IMG_6678.jpg
背面有点纠结啊,因为素漆包线飞线出来的
IMG_6679.jpg
整个U盘长这样/w\
IMG_6685.jpg
属性页(25Q16有2MB,没全用)
IMG_6688.jpg
整个板子上只集成了STM32 USB接口和稳压器,其他的都需要外接
窝从来不用开发板,因为觉得从硬件开始搭才能真正学习单片机

这次采用的是STM32F103R8T6,软件方面采用ST公司官方的USB例子(
attachment icon STM32_USB-FS-Device_Lib_V3.0.1.zip 822.59KB ZIP 239次下载 )打磨而来
首先把修改好的文件给放出来:
attachment icon usbdisk.rar 2.77MB RAR 303次下载
在Project\Mass_Storage\RVMDK中打开MassStorageSimpleBuffer.uvprojx,然后编译下载到STM32,再把STM32插入USB口,就能看到两个未格式化的分区,格式化之后可以储存数据了

注意:每次下载程序后都会清除内置Flash中的数据!本作品仅供情怀,实际请谨慎使用,不要保存重要数据!

下面简单说一下怎么做到的

1、USB的D-和D+分别接到PA11(USBDM)和PA12(USBDP)上,PA12(USBDP)即D+通过跳线使上拉1.5K电阻到VCC(3.3V),SPI Flash(25Q16)的MISO、MOSI、CLK分别连接到STM32的SPI1,详见STM32 datasheet, 选片CS连接到PC12,25Q16的写保护等引脚接3.3V

一下过程采用原版的USB例子,修改过的可以直接下载

2、在编译那个菜单里面的组合框中选择STM3210E-EVAL
选择菜单 Project->Options for Target 'STM3210E-EVAL'
在Output选项卡里把Create HEX File选上
在C/C++选项卡里的Preprocessor Symbols里的Define: USE_STM3210E_EVAL清除

3、usb_pwr.c
把PowerOn和PowerOff()面里的
USB_Cable_Config(ENABLE);

USB_Cable_Config(DISABLE);
这两句删掉,因为没有准备用这个控制电路(通过跳线把USBDP通过1.5K电阻接通到3.3V)

这时候把程序直接编译然后下载到STM32,然后把它插到电脑的USB上就能识别到两个可移动磁盘了

4、usb_desc.c
修改这两个常数为自己想要的 格式看了就懂了
MASS_StringVendor 公司名
MASS_StringProduct 产品名

usb_desc.h
MASS_SIZ_STRING_VENDOR和MASS_SIZ_STRING_PRODUCT素描述MASS_StringVendor和MASS_StringProduct的长度,包括0和开头两个东西的长度,修改字符串之后不要忘了修改MASS_SIZ_STRING_VENDOR和MASS_SIZ_STRING_PRODUCT

5、scsi_data.c
找到Standard_Inquiry_Data和Standard_Inquiry_Data2,里面有3个字符串可以修改
注意他们的长度不要修改,长度就那么长,多了少了不行

6、memory.c
uint32_t Data_Buffer[BULK_MAX_PACKET_SIZE * 16]; /* 4096 bytes*/
改下这个,因为这个决定了数据缓存有多大的区域,需要大于等于一个扇区的大小
这里内部flash一个扇区1kb,25Q16一个扇区4Kb,所以设定为4kb缓存,就素4096byte = 64byte * 16, 64byte素一个usb包传输的大小,不用管他

7、usb_scsi.c
增加一个函数在最上面:
uint8_t* Get_Custom_Inquiry_Data(uint8_t lun){
    return lun == 0 ? Standard_Inquiry_Data : Standard_Inquiry_Data2;
}

在SCSI_Inquiry_Cmd(uint8_t lun)中把if(lun==0)啥的那段改成
Inquiry_Data = Get_Custom_Inquiry_Data(lun);

在SCSI_Format_Cmd中把NAND_Format();这行注解掉
其实窝还不太明白SCSI_Format_Cmd中到底需不需要对Flash或者NAND进行相关操作,窝认为这个命令只是一个查询功能,真正格式化靠的是上位机系统软件,所以只要SCSI的Write10操作没问题就能格式化成功

8、mass_mal.c
这个才是本作的重点!
里面有4个函数:
MAL_Init,MAL_Write,MAL_Read,MAL_GetStatus
分别负责初始化,写扇区,读扇区和读取状态和扇区信息
每个函数都有个lun参数,用来决定是那个分区要被读取
这里的lun只可能是0和1,因为咱们只有两个分区,一个内部flash一个SPI的flash的

这些函数都有返回值的,操作成功返回MAL_OK,失败返回MAL_FAIL

1、首先在MAL_Init里面修改Flash们的初始化方式,对于SPI Flash是Flash25_Init(位于flash25.h),对于内部Flash则为FLASH_Unlock(位于STM32固件库内)

2、然后系统会调用MAL_GetStatus读取两个分区的信息
Mass_Block_Count 总块数
Mass_Block_Size 一个扇区的大小,对于25Q16是4kb,对于内部Flash来说是1kb
Mass_Memory_Size 整个Flash的大小,不能大于Flash能承受的大小哦

3、MAL_Read和MAL_Write
这两个函数起着核心的作用,负责直接与Flash的驱动接轨。
u32 Memory_Offset 代表内存地址偏移,就是读写开始的位置
u32 *Writebuff 和 u32 *Readbuff 是指向读写缓冲区的指针,指针指向的区域是u32类型的,也就是1个word(4个字节)
u16 Transfer_Length 需要传输数据的字节数,注意不是word的数量哦,是byte的个数!

9、flash25.c(自己加的,原版木有,参考修改过的)
掌管着SPI Flash 25Q16的操作,包括初始化,读写还有擦出功能
一般SPI Flash的驱动读写都是用的1字节为基本单位的缓冲区,而这里用的是word为单位的,所以窝修改之后的程序里面用的25Q16驱动和一般的驱动不太一样,是自己写的捏
重点是批量读取Word函数
void Flash25_Read(u32 address, u32 *Readbuff, u16 length){
    u16 i;
    u8 buffer[4];    
    
    SPI_CS_LOW();
    SPI_WriteByte(FLASH25_READ);
    SPI_WriteByte((address & 0x00FF0000) >> 16);
    SPI_WriteByte((address & 0x0000FF00) >> 8);
    SPI_WriteByte((address & 0x000000FF));

    for(i=0;i<length;i+=4){
        buffer[0] = SPI_ReadByte();
        buffer[1] = SPI_ReadByte();
        buffer[2] = SPI_ReadByte();
        buffer[3] = SPI_ReadByte();
        Readbuff[i>>2] = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
    }
    
    SPI_CS_HIGH();
}
和写入一个Word长度的数据:
void Flash25_WriteWord(u32 address, u32 data){
    FLASH25_WriteEnable();
    
    SPI_CS_LOW();
    SPI_WriteByte(FLASH25_WRITE);
    SPI_WriteByte((address & 0x00FF0000) >> 16);
    SPI_WriteByte((address & 0x0000FF00) >> 8);
    SPI_WriteByte((address & 0x000000FF));
    SPI_WriteByte((data & 0xFF000000) >> 24);
    SPI_WriteByte((data & 0x00FF0000) >> 16);
    SPI_WriteByte((data & 0x0000FF00) >> 8);
    SPI_WriteByte((data & 0x000000FF));    
    SPI_CS_HIGH();

    FLASH25_WaitForWriteEnd();
}
还有用于擦除一个扇区的
void Flash25_SectorErase(u32 address){
    FLASH25_WriteEnable();

    SPI_CS_LOW();
    SPI_WriteByte(FLASH25_SE);
    SPI_WriteByte((address & 0xFF0000) >> 16);
    SPI_WriteByte((address& 0xFF00) >> 8);
    SPI_WriteByte(address & 0xFF);
    SPI_CS_HIGH();

    FLASH25_WaitForWriteEnd();
}
这三个是最重要的函数,其他还有些函数,他们都被调用过的
Flash25_ReadID这个函数用于检验25Q16和STM32的通信,实际没用

常见问题:
1、为什么在代码中找不到任何文件系统相关?
因为文件系统是PC上的操作系统来搞定的,操作系统可能是Windows,Linux,Mac甚至其他奇怪的东西啊示波器都有可能,文件系统可能是FAT32,exFAT,NTFS,EXT4等等,作为USB适配器的STM32不需要知道这些,只需在规定的时候读写扇区即可,实际编程中在MAL_Read和MAL_Write中实现这些功能

2、为什么格式化失败?
一般来说格式化的失败是读取和写入的失败,如果遇到不能格式化的问题先检查相关Flash的初始化以及读取写入擦除是否正常工作,窝在调试好25Q16的读写之后很快就成功了

3、HardFault_Handler是怎么回事
有的时候程序会卡住,然后debug下发现是程序进到HardFault_Handler里了。HardFault_Handler的原因多半是内存溢出,最有可能的就是memory.c里面的uint32_t Data_Buffer这行,可能是某个Flash的扇区大小超过了缓冲区的大小导致的,把这个缓冲的大小改大就解决问题了。

深度打磨:
如何修改有几个盘符呢?在usb_prop.c中有这么一行uint32_t Max_Lun = 1;,Max_Lun的值等于盘符数量-1,然后在usb_scsi.c,mass_mal.c等文件中把Mass_Block_Count[2],Mass_Block_Size[2],Mass_Memory_Size[2]的长度都改成盘符的数量,最后在mass_mal.c中添加相关处理过程即可。这个窝还没有实验过,不过理论上应该不难。

参考资料:
XXXXXXXXXXXXXXXXXXX/Blog/Detail_RD.Blog_whisperer_XXXXXXXXml?WebShieldDRSessionVerify=5ZhhM3tT565unfPL0iqJ
XXXXXXXXXXXXXXXXXXXXXXXXXX/blog/static/127412291201272312850693/
XXXXXXXXXXXXXXXXXXXXXXX/s/blog_XXXXXXXXXXXXXXXXXXXml
来自:电子信息 / 电子技术
26
 
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
张静茹
9年6个月前 IP:山东
776606
前排支持,数据校验也是操作系统实现的吗?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
wenyanwen
9年6个月前 IP:上海
776613
很有意思!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
osfg
9年6个月前 IP:浙江
776639
很好玩,等我把51玩通了就上STM32。其实我想问速度,肯定不会快的。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
celeron533
9年6个月前 IP:上海
776652
2MB的新科技,超越3.5寸FDD!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
smith
9年6个月前 IP:广东
776667
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前一年国外研究挺热门的,Windows USB HID驱动有一个漏洞,手机版的kail linux就可以伪装一个USB鼠标或键盘,连上别人的电脑USB后就通过溢出偷偷给他添加一个管理员账户,然后就可以利用这个账户不需要密码黑进别人的电脑,当然前提是得有机会接近他的电脑才行
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
北落师门
9年6个月前 IP:浙江
776669
这个2MB的盘插上去还显示“大容量存储设备”吗[s::lol]
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
20!Dopaminor
9年6个月前 IP:广东
776677
引用 smith:
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前...
经常移动硬盘插到电脑上显示为硬盘
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
chenhello
9年6个月前 IP:湖南
776678
厉害!不过卖相需改善。哈哈!
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
smith
9年6个月前 IP:广东
776679
之前21IC的博主computer00 写了一本书《圈圈教你玩USB》,用8051单片机和飞利浦的一款IC介绍USB协议,书里面还送了一块电路板,我大学的时候买了书
还把这块电路板焊了出来[s::lol],就靠的这个学习了一些USB技术,今天下班回去翻翻破烂箱还能否翻出这块板子出来
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
fuwen0202
9年6个月前 IP:浙江
776686
21IC的大牛多啊,,,
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
熊猫阿Bo
9年6个月前 IP:德国
776916
我记得小黄鸭还有一些令牌都是用这些芯片做的
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
正丰开来
9年6个月前 IP:广东
778014
用来做移动硬盘好,多贴几个上去
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
那抹余辉
9年6个月前 IP:浙江
778020
大神云集!我要抓紧单片机学习啦
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金坷居士作者
9年5个月前 IP:澳大利亚
780213
引用 smith:
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前...
USB大容量储存设备的SCSI的inquiry里面的第二个bit的最高位叫RMB还叫啥,其他位是保留的,把最高位改成0就是不可移动设备,就显示为硬盘咯
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
yinchengjun
9年1个月前 IP:湖北
796974
haodongxi a
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
cdm701014
9年1个月前 IP:江西
797395
本人只会一点51单片机,做过一些简单的工控项目,想学STM32却始终无法入门,羡慕楼主。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
p1020211369
8年9个月前 IP:湖北
813587
大神云集!我要抓紧单片机
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
hclin
8年8个月前 IP:台湾
817809
很有参考的价值。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
8年8个月前 IP:浙江
817843
突然想到一个问题:DP和DM上不串22欧姆电阻,大部分Host都能正常识别么
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金坷居士作者
6年5个月前 IP:澳大利亚
847962

用stm32做usb有时候有点大材小用,这里安利个国产的51单片机,内置usb1.1低速和全速的硬件,1k xram 256字节的51标配ram(刨除设备保留的内存差不多有1.1kB) 其他外设有2个串口 SPI 简易PWM发生器 一个中规中矩的ADC 和一个没啥卵用不能产生中断的模拟比较器

使用下来感觉32的usb做的低速应用这货都能胜任,而且这货还有10脚封装,TSSOP10的,比NE555贴片还小哦w

窝自己造了个轮子,把这货的usb寄存器尽量包装成像点32的标准库用法,端点操作什么的基本上是一一对应的。

XXXXXXXXXXXXXXXXXX/rikka0w0/CH55x_USB_CompositeDevice

手标 键盘 USB转串口 U盘 这货都能做,而且更逆天的是这货还能做主机!

引用
评论
2
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
mazuhao
6年1个月前 IP:广东
852179

解压密码多少


引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
mazuhao
6年1个月前 IP:广东
852180

楼上发的那个文件解压密码多少

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
tomyluo
5年6个月前 IP:上海
859245

这个U盘的P/E寿命大概有多少次?能保存数据多少年?

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
zjsx8192
5年6个月前 IP:广东
859310

U盘能进行iap操作吗

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
xljxlj
5年6个月前 IP:浙江
859386
引用北落师门发表于6楼的内容
这个2MB的盘插上去还显示“大容量存储设备”吗[s::lol]

我试过普通u盘量产成几百kb,还是大容量存储设备…

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
信仰は儚き人間の為に
5年6个月前 IP:广东
859389
引用xljxlj发表于25楼的内容
我试过普通u盘量产成几百kb,还是大容量存储设备…

USB Mass storage Device是一种协议而不是具体的容量大小

引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
金坷居士
学者 机友 笔友
文章
170
回复
1711
学术分
11
2011/09/23注册,3个月6天前活动

怪哉!灵异的三极管电流流向! 这素一个在仿真的RCC电路,示波器上绿色的是集电极电流红色的是发射极电流。窝萌都知道发射姬电流素集电极电流和基极电流之和,所以讲道理发射极电流一定比集电极略大。可仿真结果刷了三观,Q1集电极电流一部分流经基极,然后流经Q2的C->E。

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}