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年5个月前 IP:澳大利亚
780213
引用 smith:
USB massstorage 枚举的时候 忘了是SCSI协议还是massstorage 类里面有一个值,只要设置了,枚举出来的盘符在window系统下可以变成“硬盘” 而不是“可移动硬盘”。这个也是很有趣的。

另外USB hack也是前...
USB大容量储存设备的SCSI的inquiry里面的第二个bit的最高位叫RMB还叫啥,其他位是保留的,把最高位改成0就是不可移动设备,就显示为硬盘咯
引用
评论
加载评论中,请稍候...
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字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

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

所属专业
所属分类
上级专业
同级专业
金坷居士
学者 机友 笔友
文章
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)}}