USB-OTG 研究報告
USB-OTG 研究報告
ISP1362在Blackfin DSP上的應(yīng)用
研究人:宋宇寧 趙煥軍
2005-5-20
USB-OTG 研究報告
2
USB-OTG研究報告
注:本報告重點介紹USB host部分軟件,
Slave報告請參考《USB OTG Software
Development Manual.doc》
一,研究內(nèi)容簡介
本課題基于PHILIPS公司的ISP1362芯片,研制應(yīng)用于ADSP-
BF533 EZ-KIT Lite
的USB-OTG子板,并進(jìn)行相應(yīng)軟件的開發(fā),實現(xiàn)以下幾項功能:
1. 通過ID跳線進(jìn)行的Host和Slave功能角色轉(zhuǎn)換;
2. 工作于Slave狀態(tài)時,可以和PC通信,交換板上SDRAM中的數(shù)
據(jù);
3. 工作于Host狀態(tài)時,可以對接在USB-OTG接口上的USB設(shè)備進(jìn)
行枚舉;
4. 對連接的USB Mass Storage類型設(shè)備,枚舉后進(jìn)行數(shù)據(jù)的讀寫;
在以上的研究目標(biāo)基礎(chǔ)上,主要的研究內(nèi)容如下:
1. 硬件電路的設(shè)計,制板,焊接和調(diào)試;
2. 對PHILIPS提供的參考代碼進(jìn)行學(xué)習(xí)和移植;
3. 編寫Slave狀態(tài)的驅(qū)動程序,實現(xiàn)和PC的數(shù)據(jù)通信;
4. 編寫Host狀態(tài)的驅(qū)動程序,實現(xiàn)設(shè)備枚舉;
5. 添加上層驅(qū)動程序,完成對UMS類型設(shè)備的支持;
PHILPS 提供的參考程序,本項目主要參考PHILIPS提供的2個開發(fā)板使用的軟件系統(tǒng),其中一
個是"Philips ISP1362 USB On-The-Go (OTG) Developer Kit",另一個是"ISP1362PCI Dos X2";
由于PHILIPS提供的程序是基于PC的PCI接口,并使用Turbo C
編譯器進(jìn)行編譯,而Blackfin DSP基于EZ-KIT Lite,使用VDSP++
進(jìn)行開發(fā),移植工作的部分內(nèi)容與硬件平臺有關(guān).此部分程序在此
不做介紹.
3
二,詳細(xì)研究內(nèi)容
研究內(nèi)容中的"硬件電路的設(shè)計,制板,焊接和調(diào)試","對PHILIPS提供的參考
代碼進(jìn)行學(xué)習(xí)和移植","編寫Slave狀態(tài)的驅(qū)動程序,實現(xiàn)和PC的數(shù)據(jù)通信"三
部分參考已有文檔,本報告主要介紹"編寫Host狀態(tài)的驅(qū)動程序,實現(xiàn)設(shè)備枚舉",
"添加上層驅(qū)動程序,完成對UMS類型設(shè)備的支持"部分.
1,Host狀態(tài)的驅(qū)動程序
注:代碼請見ISP1362_OTG的VDSP++源程序.
圖4. USB OTG 驅(qū)動程序棧結(jié)構(gòu)圖
USB Host部分程序在整個USB OTG 驅(qū)動程序棧中的位置見上圖.
1.1 Host部分程序流程圖
設(shè)置ATL/INTL/ISTL
緩存長度
設(shè)置SkipMap
設(shè)置root hub
設(shè)置frame interval
設(shè)置中斷允許
和中斷禁止
初始化端口
初始化RH狀態(tài)
等待按鈕
中斷
傳輸結(jié)束
上電
重置
結(jié)束按鈕
枚舉按鈕
USB端口上電
等待穩(wěn)定
進(jìn)行枚舉
取得設(shè)備數(shù)據(jù)
取得設(shè)備數(shù)據(jù)
是否存儲
設(shè)備
Y
N
USB-OTG 研究報告
4
1.2 USBTxfer函數(shù)注釋,USBTxfer是添加的用于常規(guī)端點數(shù)據(jù)傳輸?shù)腁PI函數(shù),
是各種通過Bulk端點進(jìn)行傳輸?shù)幕A(chǔ).主要功能是:
1. 將傳送緩存內(nèi)容分包,建立相應(yīng)的PTD;
2. 發(fā)送PTD;
3. 查詢方式等待傳輸結(jié)束中斷;
4. 讀取更新后的PTD,并進(jìn)行完成狀態(tài)分析
以下是該函數(shù)的流程圖:
圖6. USBXfer函數(shù)流程圖
以下是改函數(shù)的詳細(xì)注釋:
//***********************************************************************
******************
指定設(shè)備端點,設(shè)置
傳輸類型,長度
設(shè)置SkipMap
在RAM中建立In
傳輸?shù)腜TD映象
傳輸長度<
總長
將PTD映象寫入
ISP1362的ATL
發(fā)送PTD
等待ATL中斷
讀取更新后的
PTD,校驗狀態(tài)
傳輸完
成
傳輸結(jié)束
傳輸
開始
5
// usbXfer:
// successful transfer = return TRUE
// fail transfer = return FALSE
//***********************************************************************
******************
UCHAR USBTxfer(
UCHAR DevAddr, // USB 設(shè)備地址
UCHAR Endp, // 設(shè)備端點地址
UCHAR IsISO, // 是否為同步傳輸
UINT XferLength, // 傳輸長度
UCHAR *pPayload // 數(shù)據(jù)緩沖區(qū)地址
)
{
USHORT DownPort;
DownPort = OTG_PORT; // USB Host 口標(biāo)志,代表使用OTG口
USHORT i;
UINT wCount = 0; // 已經(jīng)完成的長度
USHORT uTxLen; // 每次實際傳輸長度
UCHAR result = TRUE; // 傳輸結(jié)果,成功標(biāo)志
Hal4Hc_RegOutDW(REG_ATL_PTD_SKIP_MAP, 0xfffffffe); // the first PTD is
used.
// 設(shè)置 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設(shè)備的速度:1低速還是0全速
IsISO,
FALSE, // last NOT used when ATL
HcS_UsbDataInStage.PTD.Toggle, // 上次傳輸完更新后的Toggle
0, // Paired 號,0或1
0, // 是否使用Paired PTD
// 端點的大小(64字節(jié))
HcS_CtrlBlock.strucDnPortDev[DownPort].uMaxPacketSize[Endp],
uTxLen // 此次傳輸?shù)拈L度(512)
);
// 進(jìn)行數(shù)據(jù)傳輸(詳細(xì)信息見后)
if(HcS_USBBulkXferDataIn())
{
USB-OTG 研究報告
6
// 讀取傳輸?shù)臄?shù)據(jù)到指定的緩沖區(qū)
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; // 更新已經(jīng)傳輸?shù)拈L度
}
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 函數(shù)注釋,HcS_USBBulkXferDataIn主要功能是將
內(nèi)存中的PTD映象寫入ISP1362的ATL空間,并進(jìn)行傳輸.與之對應(yīng)的Out傳輸
的函數(shù)是HcS_USBBulkXferDataOut.
/********************************************************/
/******** Functions - BulkXfer for ATL/ITL Buffer ****/
/********************************************************/
BOOLEAN HcS_USBBulkXferDataIn(void)
{
UCHAR CompletionCode; // 完成標(biāo)志
UCHAR Active; // 有效標(biāo)記
USHORT RetryCnt = MAX_RETRY-1 ; // 重試次數(shù)
USHORT XferLen; // 傳輸數(shù)據(jù)長度
XferLen = HcS_UsbDataInStage.PTD.TotalBytes; // 獲得傳輸長度
while(TRUE)
{
// 將有效標(biāo)記設(shè)成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) );
// 等待傳輸結(jié)束中斷
HcS_Wait4ATLDone();
// 將傳輸后更新的PTD前兩個字節(jié)(包括CompletionCode)讀到PTD緩沖
區(qū),用于判斷傳輸結(jié)果
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 -- ;
}
}
// 如果需要大約調(diào)試信息
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函數(shù)注釋,HcS_DumpATL主要功能是將指定的緩沖內(nèi)容寫入
ISP1362的內(nèi)部ATL空間,并觸發(fā)開始發(fā)送數(shù)據(jù).與之對應(yīng)讀取數(shù)據(jù)的函數(shù)是
HcS_RetrieveATL.
/***********************************************************/
/******** Functions - Xfer for ATL/ITL Buffer **************/
/***********************************************************/
void HcS_DumpATL(PUSHORT ptr2Structure, // 緩沖區(qū)指針
USHORT XferLengthInByte // 傳輸長度
)
{
USHORT i;
// 設(shè)置傳輸長度
PHC_SetXferCounter(XferLengthInByte);
// Begin of Critical Section,屏蔽中斷
if(bIRQL == 0)
RaiseIRQL();
// 輸出指令:寫ATL數(shù)據(jù)
Hal4Hc_CommandOutW(REG_ATL_BUFF_IO|0x80);
// 等待數(shù)據(jù)傳輸
Hal4Hc_Wait4DataPhase();
// 數(shù)據(jù)傳輸過程
for(i = 0; i < (XferLengthInByte+1)/2; i++)
9
{
Hal4Hc_DataOutW(*ptr2Structure);
ptr2Structure ++ ;
}
//add for 1362, Active the ATL,觸發(fā)ATL
Hal4Hc_RegOutW(REG_BUFF_STS,0x08);
// 開中斷
if(bIRQL == 0)
LowerIRQL();
// End of Critical Section
}
1.5 PHC_Wait4ATLDone函數(shù)注釋,PHC_Wait4ATLDone主要功能是等待傳輸完
成的中斷.
void PHC_Wait4ATLDone(void)
{
USHORT BufferStatus; // ATL空間狀態(tài)
long mloop=0; // 循環(huán)次數(shù)
mloop=0;
do {
Hal4Sys_WaitinUS(10); // 等待10uS
if ((bIsATLDone)!=0) // 等待 bIsATLDone 標(biāo)記(在中斷中置成1)
{
bIsATLDone = 0;
BufferStatus = PHC_GetATLPTDDoneMap();
// 如果是第一個PTD傳輸完成,退出循環(huán)
if ((BufferStatus & 0x001)!=0)
break;
}
else
mloop++;
}while((mloop < 200)); // 超過最大循環(huán)次數(shù),認(rèn)為傳輸已經(jīng)完成(理論上是不會
到達(dá)這步)
}
2,USB Mass Storage類型設(shè)備驅(qū)動程序
USB Mass Storage驅(qū)動程序的初始化流程圖:
USB-OTG 研究報告
10
USB Mass Storage驅(qū)動程序讀寫流程圖:
圖7. U盤讀寫程序流程圖
BulkOnlyReset
RequestSense
TestUnitReady
ClearFeature IN
傳輸成
功
初始化成功
ClearFeature OUT
Inquiry
ReadCapacity
傳輸成
功
RequestSense
Y
Y
N
N
建立CBW
設(shè)置ATAPI命令
USB IN
數(shù)據(jù)傳輸
讀取 寫
入
獲取CSW
發(fā)送CBW
USB OUT
數(shù)據(jù)傳輸
傳輸成
功
傳輸結(jié)束
11
三,速度測試
速度測試是基于Blackfin DSP的CYCLE數(shù)進(jìn)行的,在進(jìn)入指定長度數(shù)據(jù)傳輸之前,
將CYCLE數(shù)置成0,在數(shù)據(jù)傳輸結(jié)束時讀取CYCLE數(shù),并通過此CYCLE數(shù)計算
傳輸時間,并計算傳輸速度.以下是測試結(jié)果:
寫速度:寫12個扇區(qū)
字節(jié)數(shù):12×512B = 6144B
Cycle:16581911
速度:1.76Mbps
讀速度:讀20個扇區(qū)
字節(jié)數(shù):20×512B = 10KB
Cycle:15370176
速度:3.70Mbps
通過Paired PTD 進(jìn)行數(shù)據(jù)傳輸,速度沒有明顯提高.主要原因:
1. 采用PIO方式對ISP1362進(jìn)行控制,大大影響整體傳輸速度;
2. 程序不完善,很不穩(wěn)定.
在網(wǎng)上查到的ISP1362在linux下的驅(qū)動程序,PIO方式,Paired PTD,實際傳輸最
高速度是500KB/s(4Mbps),基本上和本項目相同.
四,感謝
首先感謝Analog Device公司給我這次學(xué)習(xí),鍛煉的機(jī)會,讓我獲益匪淺.
本項目得以順利進(jìn)行,要感謝CAST部門所有朋友對作者的支持,尤其感謝DSP組
的Daniel,Tony,Jenny和Rick!感謝你們對我的大力支持和照顧,謝謝!