电子技术电子技术
 
 
STM32单片机制作的双盘符U盘 /w\
金坷居士 2015-7-3 00:09:10
近来在鼓捣STM32,玩了两个星期,感觉都玩的差不多了,于是准备做个U盘。

首先晒自制的STM32开发板(其实上面就一个LDO稳压器提供3.3V)
它曾经只素一个LQFP转接板...
245939

掺了USB
245940

背面有点纠结啊,因为素漆包线飞线出来的
245941

整个U盘长这样/w\
245942

属性页(25Q16有2MB,没全用)
245943

整个板子上只集成了STM32 USB接口和稳压器,其他的都需要外接
窝从来不用开发板,因为觉得从硬件开始搭才能真正学习单片机

这次采用的是STM32F103R8T6,软件方面采用ST公司官方的USB例子()打磨而来
首先把修改好的文件给放出来:
usbdisk.rar2.77M65次

在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中添加相关处理过程即可。这个窝还没有实验过,不过理论上应该不难。

参考资料:
http://www.52rd.com/Blog/Detail_RD.Blog_whisperer_26805.html?WebShieldDRSessionVerify=5ZhhM3tT565unfPL0iqJ
http://bh7kqk.blog.163.com/blog/static/127412291201272312850693/
http://blog.sina.com.cn/s/blog_ae3f6c0f01017nyf.html
2015-7-3 07:07:23
1楼
前排支持,数据校验也是操作系统实现的吗?
2楼
很有意思!
3楼
很好玩,等我把51玩通了就上STM32。其实我想问速度,肯定不会快的。
4楼
2MB的新科技,超越3.5寸FDD!
5楼
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前一年国外研究挺热门的,Windows USB HID驱动有一个漏洞,手机版的kail linux就可以伪装一个USB鼠标或键盘,连上别人的电脑USB后就通过溢出偷偷给他添加一个管理员账户,然后就可以利用这个账户不需要密码黑进别人的电脑,当然前提是得有机会接近他的电脑才行
6楼
这个2MB的盘插上去还显示“大容量存储设备”吗[s::lol]
7楼
引用 smith:
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前...
经常移动硬盘插到电脑上显示为硬盘
8楼
厉害!不过卖相需改善。哈哈!
9楼
之前21IC的博主computer00 写了一本书《圈圈教你玩USB》,用8051单片机和飞利浦的一款IC介绍USB协议,书里面还送了一块电路板,我大学的时候买了书
还把这块电路板焊了出来[s::lol],就靠的这个学习了一些USB技术,今天下班回去翻翻破烂箱还能否翻出这块板子出来
10楼
21IC的大牛多啊,,,
2015-7-4 17:30:27
11楼
我记得小黄鸭还有一些令牌都是用这些芯片做的
2015-7-10 12:39:37
12楼
用来做移动硬盘好,多贴几个上去
13楼
大神云集!我要抓紧单片机学习啦
2015-7-20 21:44:31
金坷居士(作者)
14楼
引用 smith:
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前...
USB大容量储存设备的SCSI的inquiry里面的第二个bit的最高位叫RMB还叫啥,其他位是保留的,把最高位改成0就是不可移动设备,就显示为硬盘咯
2015-11-14 12:08:31
15楼
haodongxi a
2015-11-17 12:32:18
16楼
本人只会一点51单片机,做过一些简单的工控项目,想学STM32却始终无法入门,羡慕楼主。
2016-3-24 12:03:54
17楼
大神云集!我要抓紧单片机
2016-4-30 04:47:11
18楼
很有参考的价值。
19楼
突然想到一个问题:DP和DM上不串22欧姆电阻,大部分Host都能正常识别么
2018-7-11 13:10:25
金坷居士(作者)
20楼

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

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

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

https://github.com/rikka0w0/CH55x_USB_CompositeDevice

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

2018-11-12 23:10:36
21楼

解压密码多少


22楼

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

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

万流景仰
专栏收藏夹发私信
学术分 10科创币 3989总主题 169 帖总回复 1699 楼拥有证书:会员 笔友 机友 学者
注册于 2011-09-23 14:21最后登录 2018-09-15 20:47

个人简介

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

nkc production server  https://github.com/kccd/nkc.git

科创研究院 (c)2001-2018

蜀ICP备11004945号-2 川公网安备51010802000058号