USB-OTG 研究报告
USB-OTG 研究报告
ISP1362在Blackfin DSP上的应用
研究人:宋宇宁 赵焕军
2005-5-20
USB-OTG 研究报告
2
USB-OTG研究报告
注:本报告重点介绍USB host部分软件,
Slave报告请参考《USB OTG Software
Development Manual.doc》
一,研究内容简介
本课题基于PHILIPS公司的ISP1362芯片,研制应用于ADSP-
BF533 EZ-KIT Lite
的USB-OTG子板,并进行相应软件的开发,实现以下几项功能:
1. 通过ID跳线进行的Host和Slave功能角色转换;
2. 工作于Slave状态时,可以和PC通信,交换板上SDRAM中的数
据;
3. 工作于Host状态时,可以对接在USB-OTG接口上的USB设备进
行枚举;
4. 对连接的USB Mass Storage类型设备,枚举后进行数据的读写;
在以上的研究目标基础上,主要的研究内容如下:
1. 硬件电路的设计,制板,焊接和调试;
2. 对PHILIPS提供的参考代码进行学习和移植;
3. 编写Slave状态的驱动程序,实现和PC的数据通信;
4. 编写Host状态的驱动程序,实现设备枚举;
5. 添加上层驱动程序,完成对UMS类型设备的支持;
PHILPS 提供的参考程序,本项目主要参考PHILIPS提供的2个开发板使用的软件系统,其中一
个是"Philips ISP1362 USB On-The-Go (OTG) Developer Kit",另一个是"ISP1362PCI Dos X2";
由于PHILIPS提供的程序是基于PC的PCI接口,并使用Turbo C
编译器进行编译,而Blackfin DSP基于EZ-KIT Lite,使用VDSP++
进行开发,移植工作的部分内容与硬件平台有关.此部分程序在此
不做介绍.
3
二,详细研究内容
研究内容中的"硬件电路的设计,制板,焊接和调试","对PHILIPS提供的参考
代码进行学习和移植","编写Slave状态的驱动程序,实现和PC的数据通信"三
部分参考已有文档,本报告主要介绍"编写Host状态的驱动程序,实现设备枚举",
"添加上层驱动程序,完成对UMS类型设备的支持"部分.
1,Host状态的驱动程序
注:代码请见ISP1362_OTG的VDSP++源程序.
图4. USB OTG 驱动程序栈结构图
USB Host部分程序在整个USB OTG 驱动程序栈中的位置见上图.
1.1 Host部分程序流程图
设置ATL/INTL/ISTL
缓存长度
设置SkipMap
设置root hub
设置frame interval
设置中断允许
和中断禁止
初始化端口
初始化RH状态
等待按钮
中断
传输结束
上电
重置
结束按钮
枚举按钮
USB端口上电
等待稳定
进行枚举
取得设备数据
取得设备数据
是否存储
设备
Y
N
USB-OTG 研究报告
4
1.2 USBTxfer函数注释,USBTxfer是添加的用于常规端点数据传输的API函数,
是各种通过Bulk端点进行传输的基础.主要功能是:
1. 将传送缓存内容分包,建立相应的PTD;
2. 发送PTD;
3. 查询方式等待传输结束中断;
4. 读取更新后的PTD,并进行完成状态分析
以下是该函数的流程图:
图6. USBXfer函数流程图
以下是改函数的详细注释:
//***********************************************************************
******************
指定设备端点,设置
传输类型,长度
设置SkipMap
在RAM中建立In
传输的PTD映象
传输长度<
总长
将PTD映象写入
ISP1362的ATL
发送PTD
等待ATL中断
读取更新后的
PTD,校验状态
传输完
成
传输结束
传输
开始
5
// usbXfer:
// successful transfer = return TRUE
// fail transfer = return FALSE
//***********************************************************************
******************
UCHAR USBTxfer(
UCHAR DevAddr, // USB 设备地址
UCHAR Endp, // 设备端点地址
UCHAR IsISO, // 是否为同步传输
UINT XferLength, // 传输长度
UCHAR *pPayload // 数据缓冲区地址
)
{
USHORT DownPort;
DownPort = OTG_PORT; // USB Host 口标志,代表使用OTG口
USHORT i;
UINT wCount = 0; // 已经完成的长度
USHORT uTxLen; // 每次实际传输长度
UCHAR result = TRUE; // 传输结果,成功标志
Hal4Hc_RegOutDW(REG_ATL_PTD_SKIP_MAP, 0xfffffffe); // the first PTD is
used.
// 设置 SkipMap
// 判断是IN传输还是OUT
if ((HcS_CtrlBlock.strucDnPortDev[DownPort].byEndpAddr[Endp] & 0x80) == 0x80)
{
// IN txfer
wCount = 0;
while(wCount MAX_PAYLOAD)
uTxLen = MAX_PAYLOAD; // 超过MAX_PAYLOAD,就取最大
else
uTxLen = (XferLength - wCount);
// 建立IN PTD
HcS_BuildUSBDataIn(
& HcS_UsbDataInStage, // PTD的缓存
DevAddr,
Endp,
OtgTcb.Speed, // USB设备的速度:1低速还是0全速
IsISO,
FALSE, // last NOT used when ATL
HcS_UsbDataInStage.PTD.Toggle, // 上次传输完更新后的Toggle
0, // Paired 号,0或1
0, // 是否使用Paired PTD
// 端点的大小(64字节)
HcS_CtrlBlock.strucDnPortDev[DownPort].uMaxPacketSize[Endp],
uTxLen // 此次传输的长度(512)
);
// 进行数据传输(详细信息见后)
if(HcS_USBBulkXferDataIn())
{
USB-OTG 研究报告
6
// 读取传输的数据到指定的缓冲区
if(NULL != pPayload)
{
for( i = 0; i < uTxLen; i ++)
{
*pPayload = HcS_UsbDataInStage.Payload[i];
pPayload ++;
}
}
else
{
for( i = 0 ; i < uTxLen; i ++)
{
pPayload[i] = 0xff;
}
}
wCount += uTxLen; // 更新已经传输的长度
}
else
{
printf("USB In xfer Failure !!!\n");
result = FALSE;
return result;
}
} // WHILE
return result;
}
else // OUT传输
{
// out txfer
wCount = 0;
while(wCount MAX_PAYLOAD)
uTxLen = MAX_PAYLOAD;
else
uTxLen = (XferLength - wCount);
// 建立OUT PTD
HcS_BuildUSBDataOut(
& HcS_UsbDataOutStage,
DevAddr,
Endp,
OtgTcb.Speed,
IsISO,
FALSE,// last
HcS_UsbDataOutStage.PTD.Toggle,
HcS_CtrlBlock.strucDnPortDev[DownPort].uMaxPacketSize[Endp],
uTxLen,
pPayload
);
if(HcS_USBBulkXferDataOut())
{
wCount += uTxLen;
pPayload += uTxLen;
}
else
7
{
printf("USB Out xfer Failure !!!\n");
result = FALSE;
return result;
}
} // WHILE
}
return result;
}
1.3 HcS_USBBulkXferDataIn 函数注释,HcS_USBBulkXferDataIn主要功能是将
内存中的PTD映象写入ISP1362的ATL空间,并进行传输.与之对应的Out传输
的函数是HcS_USBBulkXferDataOut.
/********************************************************/
/******** Functions - BulkXfer for ATL/ITL Buffer ****/
/********************************************************/
BOOLEAN HcS_USBBulkXferDataIn(void)
{
UCHAR CompletionCode; // 完成标志
UCHAR Active; // 有效标记
USHORT RetryCnt = MAX_RETRY-1 ; // 重试次数
USHORT XferLen; // 传输数据长度
XferLen = HcS_UsbDataInStage.PTD.TotalBytes; // 获得传输长度
while(TRUE)
{
// 将有效标记设成1,表示PTD为Active
HcS_UsbDataInStage.PTD.Active = 1;
// 初始PTD的CompletionCode为0xFF,等待ATL更新
HcS_UsbDataInStage.PTD.CompletionCode = PTD_RETCODE_NOTOUCH;
// Xfer ATL
HcS_DumpATL((PUSHORT) &HcS_UsbDataInStage,
sizeof(PTD_32bitAlign) );
// 等待传输结束中断
HcS_Wait4ATLDone();
// 将传输后更新的PTD前两个字节(包括CompletionCode)读到PTD缓冲
区,用于判断传输结果
HcS_RetrieveATL((PUSHORT) &HcS_UsbDataInStage, 2);
// Analyze ATL,分析CompletionCode的具体含义
CompletionCode = HcS_UsbDataInStage.PTD.CompletionCode;
Active = HcS_UsbDataInStage.PTD.Active;
if( CompletionCode == PTD_RETCODE_STALL ||
CompletionCode == PTD_RETCODE_DATAUNDERUN ||
RetryCnt == 0 ||
(CompletionCode == PTD_RETCODE_OK && Active == 0)
)
{
HcS_RetrieveATL((PUSHORT) &HcS_UsbDataInStage,
sizeof(PTD_32bitAlign)+XferLen);
break;
}
else if(Active == 1 &&
CompletionCode == PTD_RETCODE_NOTOUCH || // First Xaction is
Naking
CompletionCode == PTD_RETCODE_OK // Rest Xactions are
Naking
)
USB-OTG 研究报告
8
{
// Device Keep NAKing
// Host Retry Forever;
RetryCnt = MAX_RETRY-1 ;
}
else
{
RetryCnt -- ;
}
}
// 如果需要大约调试信息
if(bVerboseHCS)
printf("Bulk In: Face Error %u times\n",MAX_RETRY-1-RetryCnt);
if((CompletionCode == PTD_RETCODE_OK && Active == 0)|| CompletionCode ==
PTD_RETCODE_DATAUNDERUN)
{
// 传输成功,退出
return TRUE;
}
else
{
// 传输失败,大印具体错误信息
HcS_PTD_ErrorHandler(BULKXFER_DATA_IN_STAGE,CompletionCode);
return FALSE;
}
}
1.4 HcS_DumpATL函数注释,HcS_DumpATL主要功能是将指定的缓冲内容写入
ISP1362的内部ATL空间,并触发开始发送数据.与之对应读取数据的函数是
HcS_RetrieveATL.
/***********************************************************/
/******** Functions - Xfer for ATL/ITL Buffer **************/
/***********************************************************/
void HcS_DumpATL(PUSHORT ptr2Structure, // 缓冲区指针
USHORT XferLengthInByte // 传输长度
)
{
USHORT i;
// 设置传输长度
PHC_SetXferCounter(XferLengthInByte);
// Begin of Critical Section,屏蔽中断
if(bIRQL == 0)
RaiseIRQL();
// 输出指令:写ATL数据
Hal4Hc_CommandOutW(REG_ATL_BUFF_IO|0x80);
// 等待数据传输
Hal4Hc_Wait4DataPhase();
// 数据传输过程
for(i = 0; i < (XferLengthInByte+1)/2; i++)
9
{
Hal4Hc_DataOutW(*ptr2Structure);
ptr2Structure ++ ;
}
//add for 1362, Active the ATL,触发ATL
Hal4Hc_RegOutW(REG_BUFF_STS,0x08);
// 开中断
if(bIRQL == 0)
LowerIRQL();
// End of Critical Section
}
1.5 PHC_Wait4ATLDone函数注释,PHC_Wait4ATLDone主要功能是等待传输完
成的中断.
void PHC_Wait4ATLDone(void)
{
USHORT BufferStatus; // ATL空间状态
long mloop=0; // 循环次数
mloop=0;
do {
Hal4Sys_WaitinUS(10); // 等待10uS
if ((bIsATLDone)!=0) // 等待 bIsATLDone 标记(在中断中置成1)
{
bIsATLDone = 0;
BufferStatus = PHC_GetATLPTDDoneMap();
// 如果是第一个PTD传输完成,退出循环
if ((BufferStatus & 0x001)!=0)
break;
}
else
mloop++;
}while((mloop < 200)); // 超过最大循环次数,认为传输已经完成(理论上是不会
到达这步)
}
2,USB Mass Storage类型设备驱动程序
USB Mass Storage驱动程序的初始化流程图:
USB-OTG 研究报告
10
USB Mass Storage驱动程序读写流程图:
图7. U盘读写程序流程图
BulkOnlyReset
RequestSense
TestUnitReady
ClearFeature IN
传输成
功
初始化成功
ClearFeature OUT
Inquiry
ReadCapacity
传输成
功
RequestSense
Y
Y
N
N
建立CBW
设置ATAPI命令
USB IN
数据传输
读取 写
入
获取CSW
发送CBW
USB OUT
数据传输
传输成
功
传输结束
11
三,速度测试
速度测试是基于Blackfin DSP的CYCLE数进行的,在进入指定长度数据传输之前,
将CYCLE数置成0,在数据传输结束时读取CYCLE数,并通过此CYCLE数计算
传输时间,并计算传输速度.以下是测试结果:
写速度:写12个扇区
字节数:12×512B = 6144B
Cycle:16581911
速度:1.76Mbps
读速度:读20个扇区
字节数:20×512B = 10KB
Cycle:15370176
速度:3.70Mbps
通过Paired PTD 进行数据传输,速度没有明显提高.主要原因:
1. 采用PIO方式对ISP1362进行控制,大大影响整体传输速度;
2. 程序不完善,很不稳定.
在网上查到的ISP1362在linux下的驱动程序,PIO方式,Paired PTD,实际传输最
高速度是500KB/s(4Mbps),基本上和本项目相同.
四,感谢
首先感谢Analog Device公司给我这次学习,锻炼的机会,让我获益匪浅.
本项目得以顺利进行,要感谢CAST部门所有朋友对作者的支持,尤其感谢DSP组
的Daniel,Tony,Jenny和Rick!感谢你们对我的大力支持和照顾,谢谢!