STM32移植USB库实现U盘功能

2019年5月28日 0条评论 296次阅读 N/A分 嵌入式

一、研究背景

前回非常轻松的移植了SPI Flash的驱动(大概15分钟吧),那么能否利用STM32来充当类似读卡器的功能来向Flash里读写文件呢?答案必然是肯定的,因为STM32F103内置有USB控制器,虽然只能做从机,但是已然能够满足需求。

二、硬件设计

STM32F103的USB数据接口是固定的:P11对应USB-、P12对应USB+。电路设计比较简单,直接连即可,唯一要注意的是在USB+线上上拉,用于插入检测,否则需要软件自动给USB+拉高,不然电脑检测不到舍必的插入。参考电路如下图所示:

三、软件设计

准备好ST提供的USB库,如果想图省事也可以用原子开发板“模拟U盘”实验的代码来修改,按如下步骤进行:

1.导入官方USB库

从官方USB库中找到“Mass_Storage”的例子,把里面所有和USB相关的文件导入到你的工程。

包含上图红框内的文件。

2.修改mass_mal.c文件

相信英语老师没有早死的朋友都看出来了,这个例程叫“mass_storage”和我们插入U盘后电脑提示的“大容量存储设备”正好对应,因而可以推断出mass_mal.c正是我们要修改的核心。这个文件主要有4个功能,初始化存储、读存储、写存储和获取存储状态,因而移植的重点就是把之前写的flash读写驱动添加到这个文件对应的位置。

这里以读取操作为例讲解,其他函数都是类似的方法:

基本不用多说智商没有欠费的朋友都看懂了,只要对应传入的参数调用下Flash的读取函数即可。由于SPI Flash的起始地址为0所以并不需要做偏移操作,直接传入这个参数。值得一提的是长度参数,单位是字节,而非block或者sector更不是cluster,如果你听不懂这些名词你就必须要补习一下操作系统原理或者这篇文章:《扇区、块和簇有什么区别?

另外,要留意每个这种函数里都有一个叫lun的参数,这是用来代指第几个存储设备的。一个读卡器可以带多张卡,分别在电脑显示。同样,一个STM32也可以带多种存储设备,让电脑显示这多个设备。这里我们只使用了一个,所以就在 case 0: 后面书写代码,其他情况通通返回Fail即可。

3.修改hw_config.c文件

如果说mass_mal.c提供的是面向底层的驱动接口,那么这个文件就是其面向应用层向上的接口。基本上,按照官方提供的所有函数(官方是依照STM32F101写的),你按照其功能重新对应你的单片机型号改写就行,同时里面有许多用于指示状态的有关LED的函数,那些都可以删除。

不过为了节省时间,只需要把原子哥提供的这个文件内容全部复制过去即可(确保你STM32的型号和原子例程对应)。当然里面涉及LED的指示灯函数也可以删除。

4.编译到工程不出错为止

官方库中嵌入着许多和官方卖的demo开发板配套的硬件操作函数,可是我们并没有官方开发板,所以离开了相对应的驱动函数,自然会报错,把他们一个个找出来并删除之。

另一方面,可能会由于头文件引用等问题引发一些错误,尤其是类型诸如“uint8_t”这种不识别的情况,一般引用”stdint.h”文件即可解除。

5.修改usb_desc.c

这个文件头上的描述符非常重要,如果你不懂请不要动,具体可以参考USB相关规范的手册。我们需要修改的最后的几个string数组,它们代表插入USB设备报告给电脑我们的设备叫什么、是谁造的、序列号等信息。

这一步不是必须的,但是为了让设备更像是你造的,留下类似版权一样的证据,我们一般会修改这几个字符串。值得注意的是,这些数组都是2字节长度的Unicode编码,支持全世界所有语言,具体怎么转换请自行搜索。

6.在main函数中初始化

首先贴出代码,然后讲为什么:

首先, Max_Lun 代表你要拖几个设备,我们只有一个设备所以设置为0?!没错,这个变量代表设备数-1,所以1个设备就设为0,2个就设为1以此类推。

之后对应这N个设备初始化它们的容量信息: Mass_Memory_Size 代表总共多大容量,单位是字节; Mass_Block_Size 代表一个扇区的大小,我们用默认的512字节; Mass_Block_Count 为扇区总数,直接用前面两个数据除一除即可。当然,这里我们完全可以随便填写容量,比如我写500GB,这就是扩容U盘欺骗消费者的方法。。。

随后,初始化批量传输所需的缓存指针。这里我们没有使用heap 上的空间,而是在全局区定义了固定长度的数组来充当缓冲,大小分别为 BULK_MAX_PACKET_SIZE*2*4 和 BULK_MAX_PACKET_SIZE 。

之后,调用 MAL_Init(0); 函数初始化存储器,它里面的细节你应该已经实现了。最后,断开并重连USB(实际上就是USB+引脚的电平变化),完成USB三连初始化后,这台设备无论多少次插拔都会被电脑识别了。

四、效果验证

烧录好程序后插入USB连接线到电脑,电脑自动安装驱动后提示需要格式化方可使用,格式化为FAT格式后即可正常访问。之后使用就像U盘一样即可,要注意的是我们在硬件上的读写传输使用的是轮询法,所以传文件是很慢的!至于如何用DMA优化留待读者自己探索。

至于如果插入后显示未能识别的设备,本质原因在于USB描述符请求失败,因此要检查基本的IO通信或是中断初始化等。因为描述符数组是官方的例程,所以一般不会错,你驱动写的不对不影响电脑识别设备,最多识别了后不能访问罢了。实在不行,我的经验是找一份可以让你电脑识别的代码,比如原子的例程,然后反向修改到你要效果,随后找到你和他的不同,进而找到问题的根本所在。

Please wait...
 

发表评论