发新帖我要提问
123
返回列表
打印

【转】USB Mass Storage学习笔记

[复制链接]
楼主: sunmeat
手机看帖
扫描二维码
随时随地手机跟帖
41
sunmeat|  楼主 | 2015-2-25 16:02 | 只看该作者 回帖奖励 |倒序浏览
  在对FLASH或SD卡的读写操作中,该函数需要三个入口参数,第一个是逻辑单元号,用来告诉CPU主机是对哪个磁盘操作(假设有多个磁盘);第二个是逻辑块地址,这里是指第几个扇区,而存储器的地址为字节地址,所以这个地址需要转换;第三个为数据长度,可以是多少个扇区,也可以是多少个字节,这个可以在CBW包中获得。

当数据发送完后,BOT的状态值置为4,进入到状态阶段。

使用特权

评论回复
42
sunmeat|  楼主 | 2015-2-25 16:02 | 只看该作者
五、            FLASH读写

USB对FLASH的操用是任意的,以扇区为单位,由于不是按连续地址写数据,所以FLASH的写函数中要有擦写管理。这里我是直接移植圈圈的FLASH读写函数,所以这里引用他的说明:

使用特权

评论回复
43
sunmeat|  楼主 | 2015-2-25 16:03 | 只看该作者
由于NAND FLASH擦除时,只能按按块擦除,因此在写扇区时,首先要擦除一个块。在擦除块前,必须将块内其他数据复制出来,由于一个块比较大(128KB),无法在MCU内开辟如此大的缓冲区。只好借助该NAND FLASH内的页复制命令,将原来的块暂时复制到一个交换用的交换块中。但是如果仅用一个块作为交换的话,它就会被频繁擦写,因而寿命会大大降低。所以在该系统中,保留了10个块用来作为交换区,轮流使用。

使用特权

评论回复
44
sunmeat|  楼主 | 2015-2-25 16:03 | 只看该作者
另外对扇区的连续写进行了优化,当连续写扇区时,就不必每次重复上面的操作,只有当地址跨块时,才需要重新擦除。连续写扇区的实现原理如下:当检测到扇区地址跨块时,就把原来的整块数据复制到交换块中,然后将该块内当前所写地址的前面部分页面复制到原来的块中,接着就从交换块中取出当前扇区地址所在页(使用页复制-随机写入命令),再把一个扇区的数据写入,并接着写入其他扇区,当扇区地址跨页时,就把该页写入到原来的块中,直到扇区被写完(当然如果写的过程中跨块了,还需要重复前面的块擦除以及复制过程)。

使用特权

评论回复
45
sunmeat|  楼主 | 2015-2-25 16:03 | 只看该作者
接着把交换块中剩余的页再复制回原来的块中,这样一个连续写过程就完成了。

使用特权

评论回复
46
sunmeat|  楼主 | 2015-2-25 16:04 | 只看该作者
因为NAND FLASH在生产和使用过程中,会产生坏块,所以必须增加坏块管理。在该系统中,保留了50个块用做坏块管理。当上述的擦、写过程中,如果发现坏块,那么就把该块的地址重新影射到一个保留的块中。以后每次对该坏块地址操作时,都被重新定位到新的块地址。

使用特权

评论回复
47
sunmeat|  楼主 | 2015-2-25 16:05 | 只看该作者
使用一个二维数组来保存该影射关系。二维数组的前半部分为坏块地址,后半部分为重新影射过后的块地址。每当发现坏块时,就需要重建这张表(主要是增加新的影射并排序,方便地址重新影射的二分查表法),并将其三份一样的写入到专门为此而保留的三个块中。之所以使用三个备份保存,是考虑到这些数据的重要性,因为一旦这个影射关系被破坏,后果将会是灾难性的。在保存这个表格时,做了特殊处理,首先标志他们准备擦除,然后才依次擦除并写入数据,这样即使在操作过程中突然断电,也至少有两个块的备份数据是可以用的,在系统开机初始化时,可以将这些数据恢复。

使用特权

评论回复
48
sunmeat|  楼主 | 2015-2-25 16:06 | 只看该作者
数据使用了特殊标志(0x0055AAFF)以及累加和校验来判断是否有效。对于新出厂的FALSH,在加载坏块表时,就会校验失败,程序就会假设没有坏块并初始化该数组后保存。每个备用块还由另外一个数组用来标志其状态(未用、已损坏、已用等)。当需要使用新的备用块时,就从该数组中查找未用的,并标志为已用。如果备用块本身是坏的,那么就标志它已损坏。该数组与坏块重影射表一并保存。此外还保存了当前坏块的数量。

使用特权

评论回复
49
sunmeat|  楼主 | 2015-2-25 16:06 | 只看该作者
数据使用了特殊标志(0x0055AAFF)以及累加和校验来判断是否有效。对于新出厂的FALSH,在加载坏块表时,就会校验失败,程序就会假设没有坏块并初始化该数组后保存。每个备用块还由另外一个数组用来标志其状态(未用、已损坏、已用等)。当需要使用新的备用块时,就从该数组中查找未用的,并标志为已用。如果备用块本身是坏的,那么就标志它已损坏。该数组与坏块重影射表一并保存。此外还保存了当前坏块的数量。

使用特权

评论回复
50
sunmeat|  楼主 | 2015-2-25 16:07 | 只看该作者
地址的重新影射过程:当对一个地址进行读写操作时,首先要对其进行重影射。首先判断是否有坏块,当坏块数量为0时,就直接返回原来的地址即可。当坏块数量不为0时,先判断最后一次访问和本次访问的地址是否属于同一页,如果属于,那么就直接影射到上一次影射过的块地址。

使用特权

评论回复
51
sunmeat|  楼主 | 2015-2-25 16:08 | 只看该作者
如果不属于,那么就需要去查坏块影射表了。如果只有一个坏块,只要直接比较即可,不用查表。如果坏块数量大于2,那么就需要查表。由于表中地址是按从小到大的顺序排列的,所以可以先和第一个和最后一个判断,如果不在该范围内,那么也不用重新影射,返回原来的地址即可。如果在该范围内,就使用二分查表法查表,搜索它是否在坏块表中。如果是的话,就重新影射地址,并将这个地址保存,以备下一次重影射时地址未跨块直接使用。最大支持50个坏块,在最坏的情况下,该二分查表法需要判断6次。

使用特权

评论回复
52
sunmeat|  楼主 | 2015-2-25 16:08 | 只看该作者
如果不属于,那么就需要去查坏块影射表了。如果只有一个坏块,只要直接比较即可,不用查表。如果坏块数量大于2,那么就需要查表。由于表中地址是按从小到大的顺序排列的,所以可以先和第一个和最后一个判断,如果不在该范围内,那么也不用重新影射,返回原来的地址即可。如果在该范围内,就使用二分查表法查表,搜索它是否在坏块表中。如果是的话,就重新影射地址,并将这个地址保存,以备下一次重影射时地址未跨块直接使用。最大支持50个坏块,在最坏的情况下,该二分查表法需要判断6次。

使用特权

评论回复
53
sunmeat|  楼主 | 2015-2-25 16:09 | 只看该作者
六、          USB文件说明
    1、USB固件库文件
    usb_conf.h      USB库文件配制;
    usb_type.h      USB库文件类型声明,使USB库文件具有独立性;
    usb_def.h       USB库文件公用的宏定义;
    usb_regs.h      USB控制器寄存器描述;
    usb_regs.c      USB控制器寄存器底层操作函数;
    usb_init.c    USB控制器初始化;
    usb_int.c       USB高优先级中断和低优先级中断处理函数,在本例中没有用到高优先级中级,所以去掉了;
    usb_mem.c       这个函数用于将USB端点的数据传送给主机和主机的数据传送到USB端点;
    usb_croe.c    USB2.0协议处理;

                  以上文件具有很强的独立性,除特殊情况,不需要用户修改,直接调用内部的函数即可.

使用特权

评论回复
54
sunmeat|  楼主 | 2015-2-25 16:09 | 只看该作者
2、USB Mass Storage Bulk Only实现

           以下文件也是出自STM32官方,但要根据实际的应用作修改.

            usb_pwr.c         USB控制器的电源管理函数;
    usb_istr.c        USB低优先级中断入;
    usb_endp.c        非控制端点处理(大容量数据存储输入和输出函数);
    usb_prop.c        Mass Storage相关属性:mass初始化、复位等等;
    usb_bot.c         BOT状态机,CBW解析和调用SCSI处理(批量数据输入输出的状态转换通过BOT状态机实现),
                               这个程序负责接收主机的CBW包,并解析,调用SCSI命令处理函数,返回CSW;
    usb_scsi.c        SCSI命令处理;
    usb_desc.c        USB描述符;

使用特权

评论回复
55
sunmeat|  楼主 | 2015-2-25 16:10 | 只看该作者
七、结语

       第一次用32位的ARM单片机,第一次玩USB,能够花两个多星期的时间实现这个U盘,心情还是蛮激动的,当然我参考了很多网友的和官方的代码;在英蓓特的STM32开发板中就有MASS STORAGE的例程,是对SD进行读写,对NAND不能操作,每次在PC端点NAND磁盘时,都提示要格式化磁盘,但总是格式化不成功。后来发现在写NAND的程序中,没有擦写管理,导致数据每次写入都失败,后来我移植了圈圈的NAND擦写管理函数,换了大页的NAND FLASH,终于调试成功。

使用特权

评论回复
56
sunmeat|  楼主 | 2015-2-25 16:11 | 只看该作者
在调试的过程中,了解了STM32的USB控制器,了解了USB MASS STORAGE 批量传输协议,学会使用NAND FLASH,现将自已两个多星期来的学习成果进行总结,希望能与大家交流。

使用特权

评论回复
57
comeon201208| | 2015-2-25 20:34 | 只看该作者
STM32F103的MCU自带USB从控制器,符合USB规范的通信连接;PC主机和微控制器之间的数据传输是通过共享一专用的数据缓冲区来完成的,该数据缓冲区能被USB外设直接访问。
这个对应的GD32F103的也有的吧。。

使用特权

评论回复
58
firstblood| | 2015-3-9 20:57 | 只看该作者
USB模块同PC主机通信,根据USB规范实现令牌分组的检测,数据发送/接收的处理,和握手分组的处理。

使用特权

评论回复
59
smilingangel| | 2015-3-14 23:49 | 只看该作者
USB模块同PC主机通信,根据USB规范实现令牌分组的检测,数据发送/接收的处理,和握手分组的处理。整个传输的格式由硬件完成,其中包括CRC的生成和校验。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则