侃侃USB Vendor Command ,灵活性最大的一组usb class

我們來談一下關於在一般USB I/O 常用的 Vendor command 觀念。上回有很簡單的提到關於USB I/O 簡單一個執行範例:

http://chamberplus.myweb.hinet.net/usb_diy5.htm

但是還是有許多讀者朋友還是不是很清楚關於這一部份的觀念,就打電話過來提問題。

雖然版主目前的工作目標是在全球各地大力推行關於FPPA單晶片多核心微控器。

但基於提攜後生晚輩的功德完滿的慈悲心,還是都很樂意的一一回答。

—-

為什麼這一部份會是很重要的觀念呢?!因為您只要弄清楚這一部份,您大概就不會想用一般所謂HID 的USB  Device 來開發一個簡單的純USB I/O  COntroller 的東西,而且這一部份就是USB 很基礎的東西,只要您搞懂之後,您大概USB的基本精髓就搞懂了,至少,我個人是這樣認為的。(但是,有時候,說起來很容易,但是要說到每位入門者都懂的話,真的要大家實際去演練一下!所謂:師傅引進門,修行在個人啊!)

好,我們就開始簡單的說明一下:

一般我們都希望透過USB介面來下命令來執行一些簡單的I/O 控制,譬如:點個LED燈啊 ;或是去控制一個步進馬達… 等等。其實,這一部份的答案就在版主的另一篇文章中:

http://chamberplus.myweb.hinet.net/usb_diy2.htm

但是可能許多人還是一時沒有悟到箇中的精髓,那版主就在此簡單的整理一下以上這兩篇文章的意義。

首先我們來看以下這兩張圖,並結合USB Controller 韌體來說明:

一般在控制系統中,往往我們下完命令後,就想知道我們的控制系統有沒有收到我們的命令就是一個簡單的命令的通訊協定。只要控制系統可以準確的接到我們的命令,他當然就可以準確的執行我們要求的指令了!但是,在USB 中我們該如何完成這個動作呢?!

以USB 的Control pipe 來說:是不能只用一組 Setup- token 來完成的。這是您所必須首先瞭解的。

我們PC端(主控機)該如何下命令呢?因為這一部份是屬於我們自製命令範圍,所以在USB 的規格中就幫我們預留了一個所謂Vendor Command 介面:在Chapter 9 中的那個 Table 9-2 Format of Setup Data (記住:當初版主學USB時,也是一手規格書,一手寫程式的!) — Offset 0 他定義了什麼?就是 bmRequestType !!

Bit7  : 是定義一般命令的方向:是由PC 下給USB Device 的呢?還是USB Device 要回給 PC 的!?

Bit6..5 :就是說明上述所謂:是一般標準Command (一般來說就比較屬於Emuneration 用的)!或是Class Command 用的?(就是我們所謂 MSDC 或HID 的特殊命令,這一部份,您就要另外看相關Class 規格書!),剩下的就是我們所謂的Vendor Command    !! 所以,由此我們就知道:一般來說:Setup token 的第一個Byte 中我們的命令是不是Vendor Command 了:

若是 0x40 的話:就是PC要下給 USB Device 的 Vendor  Command ; 0xc0 就是PC要求 USB Device 要回給 PC 的命令!(注意喔:還是PC 要求USB Device 的喔~因為USB的觀念還是主從觀念,PC 沒有要求USB Device 回命令,USB Device 還是不能主動回的喔!!)

所以一個簡單的程式流程:

PC 端的程式:

int i;
for(i=0;i<8;i++) STICommandString[i]=0x00;
STICommandString[0]=0x82; // SET USB Controller P1
STICommandString[1]=(UCHAR)(USB_P1&0x00FF); // SET USB Controller P1
USB_DEVICE_SEND_STI_COMMAND(STICommandString);

就是要下一個Vendor Command !


我們在 USB 的分析儀上就可以清楚的可以看到我們所下的命令:注意喔:我們在Setup Token 看到的是: 0x40 0x01 0x12 0x20 0x40 0x3F 0x40 0x00 !! 第一個所謂的 0x40 就是要告訴USB 驅動程式,我們這一個USB Command 是Vendor Command !

所以,在相對的韌體中就可以找到所謂:

SetupToken:
REG_RD  bmRequestType ;;讀取bmRequestType Register
mov     B, A ;;避免破壞原有的值,先存放在 B Register中
anl     A, #00011111b ;;為了以後要用,先把Bit0~4存到bmReqTypeCopy中
mov     bmReqTypeRec, A
mov     A, B
anl     A, #01100000b   ;;因為只先判斷Bit5和6,所以把其它的Bit清掉

DoRequestStandar:
cjne    A, #00h, DoRequestClass;;比較是不是Standard Command
ljmp    RequestStandard                 ;; 00 01 02 80 81 82

DoRequestClass:

cjne    A, #20h, DoRequestVendor        ;;比較是不是Vendor Command
ljmp    RequestClass

DoRequestVendor:
cjne    A, #40h, DoRequestReserved ;;如果不是上述兩種就表是有錯誤!!!

ljmp    RequestVendor
DoRequestReserved:
ljmp    RequestReserved                 ;; Other
—–

對不起,我們是老人家,還會用所謂組合語言,我們是比較落伍了。(但是我們學 C 語言    會很快呢!也會C 語言! 所以,我們活得比您快樂,還有競爭優勢:

void CTLSETUP_Packet(void) USING_1
/*++

Routine Description:

process setup packet of control pipe

Arguments:

none

Return Value:

none

–*/
{
UCHAR type;

if (G_ucCtrlPhase != K_CommandPhase)
{
//phase transition error – setup packet should not appear
//                         at current phase
//Since hardware will reset the control pipe whenever
//setup packet arrives, we just force the phase to command phase.
G_ucCtrlPhase = K_CommandPhase;
}

CTLSETUP_GetSetupPacket();      //read setup packet

G_usCtrlDataLength = G_pCtrlCommand->wLength;
G_usCtrlDataIndex = 0x0000;

//check Type of bmRequestType
type = G_pCtrlCommand->bmRequestType & 0x60;
if (type == 0x00)
{
CTLSETUP_StandardRequest();     //Standard Request
}
else if (type == 0x20)
{
CTLSETUP_ClassRequest();        //Class Request
}

else if (type == 0x40)
{
CTLSETUP_VendorRequest();       //Vendor Request
}
else //if (type == 0x60)
{
CTLSETUP_ReservedRequest();     //Reserved Request
}

}

怎樣?!版主不唬您吧!版主也寫過的哩~但在這一次用C 語言作USB 的東西,沒有第一次用組合語言寫 USB 程式快樂!

————————————————————————————————-

然後我們的韌體就可以解 PC 端下給我們的命令內容了~就是上圖中那一大串的 64 Bytes 的內容,夠長了吧!看來還不只可以傳命令,還可以傳資料呢!!您覺得光是Setup Token  就可以讓我們用 USB 作多少DIY 的東西啊?!

;;—————————————————————————–
ScanSTIOutData:
REG_RD  USBDsrr0
mov     Command, A
mov R0, A
lcall   STITxDataClear
        lcall   USBSTIAPI

                call    SetUSBSTITxData    ;;; Assign Status(Zero or Non-Zero) to Echo Cmd
call    SetUSBSTITxData2

ret

;;==============================================================================

….

我們就可以解PC端的命令的!

USBSTIAPI:
MessageCmdInAPI:
mov A, Command
;——————————————————————————
USB3Cmd41:    ;;Cancel_cmd
cjne    A,#41h,USB3Cmd25
ret
;——————————————————————————
USB3Cmd25:    ;; Test Command
cjne    A,#25h,USB3Cmd35
….

簡單吧!

—–

不過,這裡還有一個很重要的學問:您看到我上述解USB Vendor Command 時,還Call 其他副程式:

                call    SetUSBSTITxData    ;;; Assign Status(Zero or Non-Zero) to Echo Cmd
call    SetUSBSTITxData2

就是還要負責 回 USB Protocol 的東西,就是我在USB 簡介中所提到的 USB House-keeping 的管理程式。往往一般人會被兩者給搞亂的。其實,這些USB House-Keeping 成是就是拿來管USB 什麼時候開關USB Setup – Out- In 的那個 通訊協定。記住:USB的Protocol 都是很快的~我們是透韌體還控管的。其實,在一般USB Controller 中(像 Cypress這一種),就是去填一大堆的 USB Registers的!

———————————————————————————————–

所以,當我們收完PC 端的命令後,往往PC還會下個確認命令,要我們USB Device Echo 我們所收到的命令,所以就會有另一組Setup Token : 0xc0 0x01 0x13 0x20 0x00 0x3F 0x40 0x00 !

這個0xc0 就是PC 端要跟USB Device 要一組 命令資料。(不過,這裡版主比較偷懶,所以用  8 bytes 回的 圖中為0x02 0x80 0x00 0x00 0x00 0x00 0x00 0x00 ~照一般的習慣是:64 Bytes 下,就用 64 Bytes 收會比較習慣一點!)

————————

所以,這個一來依往的命令就可讓我們的韌體聽從PC 下過來的命令,來執行PC 端所要求的指令了!

夠簡單吧 !

——–

其實,這其中還要交代一個很重要的觀念:您可別以為這樣子,您PC 端就可以拼命的下命令,或是傳資料喔!因為在USB 的命令傳輸是很快的,而往往我們韌體在執行一些命令時(如:控制步進馬達等這種快不得的指令時!)是需要一點時間的,您如果拼命下命令,您的USB Controller 就必須常常被叫去解USB Command ,結果,哈~哈~ 不是馬達轉起來怪怪的,就是USB 介面不小心就給當掉了!…您的PC端 應用程式還死的不明不白呢!!….您總覺得為何USB 怎麼這麼奇怪?!那這一部份,說真的,版主因為不知道您真正的應用為何?所以,我也沒辦法幫上您什麼忙呢!!這不是版主不負責,真的,我也不知道!  就像版主現在在推多核心的微控器時,我也不知道客戶拿這麼一顆微控器要作什麼啊?!或許,您可以告訴我,我們可以研究研究一下。—-所以您會有一種感覺說:怎麼版主您怎會懂這麼多東西?!因為我們不會藏私什麼?我們是以更寬廣的心,去迎接更寬廣的視野。我們所得到的資訊就越廣!您一直抓著您手上的東西,您怎麼可以還可以抓別的東西呢?!您不幫助別人解決問題,人家怎麼會跟您說他的想法呢?!為什麼我們會相信神明呢?!因為祂們一直在聆聽大家的說法,也看多人們的作法,所以,祂們是用更寬厚的慈悲心來看待我們!而我們自私的人們呢?!由衷的期望我們會有一個處處無私的社會自然就會有競爭力的國家!共勉之!

 


分享:
usb Asked on 2017年3月21日 in 机械.
Add Comment
0 Answer(s)

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.