利用嵌入式USB主控进行设计
USB(通用串行总线)于1995年面世,目前已发展成为一种解决个人计算机与外设连接问题的事实标准。由于USB的应用极为广泛,因此对嵌入式系统的总线外部扩展与连接应用来说,它也有着巨大的吸引力。
如今,集成USB主控后,嵌入式产品(如测试设备等)就可以和各种价格低廉、获取方便的外设实现连接,如键盘、鼠标和打印机。对同时扮演USB主端、外设(从端)双重角色的USB主控装置的需求,在移动装置迅速流行的推动下也在不断增长。具有双重身份的这些装置,可以让PDA、打印机等传统USB外设在无PC的情况下直接实现相互通信。
USB之所以广受欢迎,其原因主要在于使用的方便性。消费者不论何时、把何种USB装置插入PC中,它都可以实现无缝工作。这种即插即用能力的实现,离不开各式各样的USB主端装置以及Microsoft Windows中驱动软件的有力支持,但在嵌入式应用环境中却还找不到这样的支持。
我们从不同层次上对USB通信流进行考察,就会发现完整的USB主控系统要包含如下三种基本要素:
传统的USB主控设计将整个主控系统划分为主端控制器(host controller)和控制器之外的整套USB软件。图1示出了USB主控系统组成单元与传统的主机体系结构间的映射关系。
主端控制器一般制作成单独的一块芯片,其中包括了物理和数据链路层硬件(如USB收发器)、SIE(串行接口引擎)等,以及一个可以附加到系统处理器上的总线接口。USB固件(主控栈和装置驱动)驻留在带有USB主端控制器的系统处理器中。
USB硬件和固件的分离反映了一个现实:USB从根本上来说是一种PC总线的外部扩展机制。从USB固件的角度来看,PC提供了无穷无尽的系统资源。此外,PC行业已经实现标准化,统一于一个OS平台——Microsoft Windows,而这一操作系统天生就具备支持USB主控栈和装置驱动的能力。由于拥有极为丰富的系统资源和软件支持,所以传统的USB主控体系结构是PC应用的一种理想的解决方案。
相形之下,嵌入式系统的设计者们若要把传统的USB主控移植到嵌入式装置中,却需要理清多方面的问题。嵌入式设计的挑战,根源在于把USB固件与嵌入式应用及其基础计算平台集成为一体时所需解决的复杂问题。
首先,嵌入式装置一般带有的系统资源(系统处理器和存储器)容量有限。在系统处理器上运行USB主控固件,不仅会占用目标应用的资源,而且还会造成对应用固件的大量反复写入和优化。
其次,嵌入式应用一般要对实时事件作出明确的响应。把USB固件添加到系统中,就会增加复杂性,导致在实时应用的设计和调试中出现更多中断和实时事件。
最后,嵌入式市场具有种类繁多的处理器和实时操作系统。将USB固件开发和移植到任何特定处理器/实时操作系统平台的努力都将花费大量时间,而且需要工作人员在USB技术上具有很高的专业技能。由于USB规范的内容繁多,因此,对于一个设计周期为6~12个月的典型嵌入式项目来说,学习过程实在过长,也过于艰深。
克服嵌入式装置中USB主控设计的复杂性问题,方法之一就是把与USB即插即用能力相关的智能揉入USB主端控制器本身之中。要做到这一点,所采取的办法是:
该设计方法,可以为我们带来一个无需系统处理器干预就能处理USB主控活动的USB主端控制器。它不仅让系统资源的消耗降至最低,而且也将通过系统总线的USB数据流减至最小。
这种设计方法的另一个好处则是简化了所生成的API。API的设计将简单易行,并且独立于处理器和实时操作系统,从而有效地降低了API集移植和集成的难度。
相应的,任何一种专用USB装置驱动都可以由这一不大的API集开发而成。为了进一步降低USB主控实现的复杂程度,USB装置的驱动也应该以独立于处理器/实时操作系统的API形式建立,并呈现给系统设计者。装置驱动API可让已有的和新出现的嵌入式应用很快集成USB主控功能。
Atmel公司的AT43USB370 USB主控/功能处理器的设计,采用了上文提到的设计方法,其目标就是将复杂的USB问题屏蔽掉。下面的实例将向读者表明,利用AT43USB370 海量存储装置驱动API,开发一个海量存储器应用只需少数几个步骤即可。设计目标是从相连的USB储存装置的根目录下读取一个文件。
file://step1: 等待装置完成盘点
connectStatus = MS_Get_Final_Stat();
DeviceAddr = connectStatus.Dev_Addr; file://装置地址
DriveNum = connectStatus.Part_Num;//分区数
// Step2:获取根目录的内容 (ID 0x00)
cmdResponse = Get_Dir(DeviceAddr,DriveNum,0x00);
CommandId = cmdResponse.CmdId;
getDirStatus = MS_Get_Final_Stat(); file://等待目录信息
if (getDirStatus.Get_Cmd_Id == CommandId)
{
file://目录信息采取getDirStatus.pDir_Buff结构
}
// Step 3:为文件内容安排缓冲
int* pMSC_File =(int*)malloc(0x00008023*(sizeof (unsigned char)));
// Step 4:将文件内容读到缓冲器内
// ID据报为 0x0000F17C,大小= 0x8023
cmdResponse = Read_File(DeviceAddr,DriveNum ,
0x0000F17C,pMSC_File, 0x00008023);
CommandId = sreadIntCmdResponse.CmdId;
readStatus = MS_Get_Final_Stat();
if (readStatus.Get_Cmd_Id == CommandId)
{
file://文件已被拷贝到pMSC_File缓冲中
}
- 磁场检测仪的嵌入式软件和硬件协同开发模式(10-13)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)