利用USB2.0的高性能移动存储设备的设计
1.引言
闪存盘(FLASH MEMORY)是USB接口的一种典型应用,1999年朗科研发出全球第一款USB闪存盘,成功启动了全球闪存盘行业。由于闪存是一种基于半导体的存储器,信息在断电后可以保存,并且还具有低功耗、速度快、可擦写性、高可靠性、低成本等特点,是高数据存储密度的最佳选择,在外部存储领域、嵌入式系统、工控行业和信息家电业得到广泛使用,如手机、数码相机、MP3等。市场上的FLASH有多种技术来实现,其中最常用的有NAND(与非)和NOR(异或)两种。
武汉电离层观象台的高频多普勒与到达角探测分析系统在投入实际观测后,获得了一些很重要的观测数据[1],该系统的数据采集单元采用闪存作为数据移动存储设备,实现与计算机的信息交互,完成数据的分析与处理。本文所讨论的NAND FLASH存储器与USB2.0控制器的硬件连接和软件编程方法,在研究开发USB移动存储器使其更稳定安全地工作,具有重要的价值。本文首先介绍移动存储设备的硬件设计部分,重点讨论了该移动存储设备的硬件接口设计,继而给出固件程序的编程方法。其中设备固件的编写是本设计的重点。
2.硬件实现
本移动存储设备的USB2.0控制器采用ATMEL公司的AT89C5131芯片,数据存储介质采用SAMSUNG公司的NAND FLASH 芯片K9K2G08U0A。
2.1 AT89C5131芯片特点
AT89C5131是ATMEL公司生产的基于80C52内核的高性能内置全速USB控制器的8位单CPU微处理芯片[2],直接与MCS-51系列兼容,其内部集成了32KB的Flash存储器,可用于IN- System Programming;内置4KB EEPROM,其中的1KB用于用户数据的存储,具有1个控制端口和6个普通可编程端口,并且支持控制传送、同步传送、中断传送和批量传送四种传输方式。该芯片的优点是采用开发者熟悉的结构和指令集,处理能力强,构成系统的电路简单,调试方便。
2.2 K9K2G08U0A芯片特点
K9K2G08U0A存储器芯片的总容量为(256M +8192k)bit*8bit,分为2048扇区,每扇区又分为64页,每页除了2k字节的主存储区外,还包括64字节的备用[3]。它以200μs/ 页完成2112个字节的编程操作;还可以在2ms内完成128k字节的擦除操作;同时随机读数时间是25μs;数据线与地址线复用为I/O0-I/O7共 8根线;另外还分别提供了命令控制信号线;数据保存时间超过10年。NAND FLASH存储器不会因为存储容量的增加而增加引脚数目,从而极大方便了系统设计和产品升级,但芯片的连接方法与编程访问同传统存储器相比仍有较大差异。
2.3 硬件原理图
该系统的硬件部分由内置USB控制器的单片机AT89C5131,SAMSUNG公司的NAND FLASH 芯片K9K2G08U0A组成,硬件原理图如图1所示。必须写入相应的命令才能顺利执行闪存的各种操作,由于数据线与地址线复用为8根线,因此地址、命令以及数据的输入/输出需要通过命令锁存信号(CLE)和地址锁存信号(ALE)共同控制从而分时复用。
I/O[7:0]:数据输入/输出端口,该信号与AT89C5131芯片的P0[7:0]连接。
:写使能信号。在其上升沿时,命令、地址和数据锁存到相应的寄存器中。该信号与AT89C5131芯片的P3.6 信号连接。
:读使能信号。在其下降沿时,输出数据到I/O总线,同时,它还可以对内部数据地址进行累加。该信号与AT89C5131芯片的P3.7 信号连接。
CLE:命令锁存使能信号。当CLE为高电平时,命令在 上升沿通过I/O端口送入命令寄存器。该信号与AT89C5131芯片的P1.0引脚连接。
ALE:地址锁存使能信号。当ALE为高电平时,地址在 上升沿送入地址寄存器。该信号与AT89C5131芯片的P1.1引脚连接。
:片选信号。用于控制设备的选择。当设备忙时 为高电平而被忽略,当处于编程和擦除操作时设备不能回到备用状态。该信号与AT89C5131芯片的P1.2引脚连接。
R/ :准备好/忙输出。当它为低电平时,表示编程、擦除和随机读操作正在进行,在操作完成后返回高电平;当芯片没被选中或输出禁止时,其为高电平时。该信号与AT89C5131芯片的P1.3引脚连接。
3.固件设计实现
本文设计的USB移动存储设备采用Bulk-Only传输方式,遵循UFI命令规范。移动存储设备固件的主要功能是响应USB总线的各种标准请求,向主机返回设备的状态信息;同时,解析接收到的SCSI命令,进行相应的命令处理和数据读写操作。固件设计采用中断驱动,当AT89C5131从总线上接收到请求包时,通过调用相应的中断事件处理函数来实现,后台处理USB传输,从而保证了闪存的快速读写速率。主要中断事件有:
(1)主循环等待USB中断,设置相应标志位。移动存储设备插入主机后,主机向移动闪存的控制断点0发出标准请求,固件进入标准请求处理函数,设备回送给主机所要求的相应描述符,调用相关驱动程序。
(2)当USB主机通过Bulk-In端口读取闪存数据后,产生Bulk-In端口中断。
(3)当AT89C5131通过Bulk-Out端口接收到主机发送的命令字CBW后,触发Bulk-Out端口中断。
3.1 响应USB总线标准请求
当USB移动存储设备接入主机后,USB主机控制器对设备进行总线枚举过程,首先向设备发送标准USB请求GET_DESCRIPTOR来获得最大数据包长度;接着发出SET ADDRESS请求,为设备分配地址;使用新分配的地址再次发出GET_DESCRIPTOR请求,读取设备的配置信息[4],如设备描述符、配置描述符、接口描述符、端口描述符和字符串描述符等,并选择合适的驱动程序;最后,发出SET CONFIGURATION请求配置端口属性。
USB设备通过控制端口响应USB标准请求,实现主机和设备间的通信。除控制端口外,Bulk-Only传输方式还需支持Bulk-In和Bulk-Out端口。端口初始化代码如下:
void Usb_Init(void)
{
UEPNUM=0x00; UEPCONX=0x80;
//端口0,控制端口
UEPNUM=0x01; UEPCONX=0x86;
//端口1,Bulk-In端口
UEPNUM=0x02; UEPCONX=0x82;
//端口2,Bulk-Out端口
UEPRST=0x07; UEPRST= 0x00;//端口复位
UEPIEN=0x07; USBIEN|=EEOFINT;
USBADDR=FEN; //功能使能位
}
当控制端口配置成功后,主机会发出Inquiry、Mode_Sense、Read_Capacity等请求,提供闪盘基本信息,如扇区大小、簇大小、闪盘容量等,当请求结果正确后,便会发出Read(10)命令,进入文件系统识别阶段。
3.2 解析SCSI命令并处理
UFI 命令规范基于 SFF-8070i 和 SCSI-2 的规范,总共定义了19个固定12字节长度的操作命令,用于 USB主机和 USB 移动存储设备之间进行命令字CBW (Command Block Wrapper)、普通数据、状态字CSW (Command Status Wrapper)的交换。
USB移动存储设备接收到来自于USB主机Bulk-Out端口发给其的CBW命令字后,按照SCSI的命令格式进行解析,得到其中的命令信息,如:格式化设备、查询设备信息、读写设备等,对移动存储设备执行相应的命令后,向主机Bulk-In端口返回状态字 CSW,报告命令执行情况,主机根据反馈的状态字决定是否继续发送命令字或是数据。
3.3 闪存的操作实现
K9K2G08U0A芯片以页为单位来进行读写,以块为单位进行擦除。K9K2G08U0A支持的操作主要有几种:读操作(Read)、页编程(Page Program)、缓存编程(Cache Program)、块擦除(Block Erase)、块复制(Copy-Back Program)、随机数据输入(Random Data Input)、随机数据输出(Random Data Output)、复位(Reset)、读设备号(ReadID)、读状态(Read Status)等操作。在进行写操作之前,必须对写单元所在块进行擦除,因此事先需要对所擦除块内容进行保存。
如果闪存存在坏块,则在进行读、页编程、块擦除、块复制等操作时会失败,因此对坏块要进行提前检测并进行标注。芯片在出厂时,在每块的第一页和第二页的2048列的首字节做出好坏标记,如果标志位不是FFh则为坏块,基于此建立坏块列表。
基于篇幅的原因,这里以写操作过程为例描述闪存使用方法。一般闪存的使用顺序是:块擦除-编程-多次读取-块擦除…, 对K9K2G08U0A芯片进行数据写的步骤如下:(1)将写入数据扇区地址与坏块列表对照,检查错误扇区。若存在坏区,则继续检查下一扇区;(2)开辟缓冲区域,将写入数据扇区的原始数据利用Copy-Back Program方式保存到缓冲区;(3) 利用Block Erase擦除要写入的数据扇区;(4) 利用 Page Program操作将主机传输的数据写到闪存中;(5)利用Copy-Back Program操作将缓冲区的数据写入指定扇区。
K9K2G08U0A编程器件以页为单位编程,它允许在单页编程周期中对部分页或一个甚至连续的多达2112个连续字节编程。一个页编程周期由2个阶段组成[3]:(1)串行数据加载阶段:数据被加载到数据寄存器中,以输入命令80h为标志,紧接着是5个字节的地址输入和串行数据加载;(2)非易失性的编程阶段:命令10h标志着该编程阶段的开始,将已加载的数据写入实际的存储单元,编程典型时间为200μs。之后R/ 跳低,进入闪存内部编程,最后进入读状态确认操作,命令70h表示读状态命令,I/O0表示读到的状态。页编程实现代码如下:
void PageWrite(void ) //页编程
{
CheckBlock(startpage); //检测坏块列表
if(FirstP)
// FirstP为1,开始对一页进行写操作,否则为0
{//片选信号有效
F_CE=0; F_RE=1; F_ALE=0;F_CLE=1;F_WE=0;
OutputCommand(0x80); //输入命令0x80
F_WE=1;
F_ALE=1;//发送地址开始
AddrOut (addr1); //得到页地址,五个周期
AddrOut (addr2); AddrOut (addr3); AddrOut (addr4); AddrOut (addr5);
F_ALE=0;
FirstP =0; }
WriteData(BuffBlock); //将数据写入缓冲区
FlagWrite =0;
Do{
F_WE=0;
WriteFlash(); //将数据写入flash
FlagWrite++;
F_WE=1;
}while(FlagWrite<64); //写满一页数据
OutputCommand (0x10); //输入命令0x10
while(!F_RB); //等待读信号有效
OutputCommand (0x70); //输入命令0x70
Wait();
F_CE=1; //片选结束
startpage++; //继续写下一页
FirstP =1;
}
4.结束语
本文在充分研究USB2.0协议、Bulk-Only传输协议和SCSI指令规范的基础上,设计出USB2.0高性能移动存储设备。本文作者创新点:将FLASH作为数据采集系统中的存储单元,应用在与计算机交互数据的采集过程之中;并采用中断驱动设计固件程序,提高了读写效率。实验证明,其性能稳定可靠,读写数据速度达到了令人满意的效果。移动数据的交换和存储是目前IT行业的热点,可以在此基础上,不断完善现有设计方案,继续研究开发嵌入式USB主机系统,使得在PC机不参与的情况下同样可以进行数据的存储与交换。
评论
查看更多