1. 程式人生 > >Net Micro Framework - USB Mass Storage功能實現

Net Micro Framework - USB Mass Storage功能實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

1. 說明

由於.Net Micro FrameworkUSB驅動架構中,沒有為Mass Storage功能提供原生支援,所以除了要編寫Mass Storage主體程式碼外,還需要在原有的USB

驅動中新增部分列舉程式碼。其實從結構上來說,該部分程式碼應該新增在PAL層,不過考慮到這層程式碼為.Net Micro Framework Poring Kit Rtm 3.0標準程式碼,所以把這部分程式碼新增到我們自己編寫的USB驅動之中去了。

此外,由於Mass Storage功能需要不斷地檢測和處理USB埠的資料,需要一個程序(或執行緒)去進行驅動。.Net Micro Framework在應用層僅支援一個程序(單個使用者程式),所以必須在應用程式中專開一個執行緒去進行驅動,考慮到這樣實現需要使用者做額外的工作,最後摒棄了這一實現。最終的做法是,在Mass Storage驅動中添加了時鐘中斷處理函式,

Mass Storage被初始化後,該時鐘中斷被啟用,以一個使用者可設定的間隔去監控和處理USB埠的資料。

在實現Mass Storage功能的程式碼中,並沒有直接去讀寫相關Flash,而是藉助PAL層的SectorCache模組間接訪問Flash,這樣有兩個好處,一是讀寫有快取,操作速度較快,二是程式比較通用,程式碼在不用修改的情況下可以訪問不同的FlashSD卡等儲存模組。

Mass Storage驅動僅實現了一個功能子集,僅支援單個儲存模組,不支援從PC機進行格式化(可通過本地提供的介面進行格式化,檔案系統目前必須是FAT32)。

2. USB Config

Mass Storage

要求的USB Config和我們.Net Micro Framework的標準驅動不同,一是PIDVID不同,由於Mass Storage裝置是免驅動安裝的,這PIDVID應該沒有多大用處,但是由於以前PC上已經安裝了該PIDVID.Net Micro Framework驅動,所以Mass Storage裝置插入時,優先去找匹配PIDVID的裝置驅動(這樣也可以讓一些廠家有機會安裝自己專門的Mass Storage裝置驅動),所以對我們已有該驅動的PC,肯定會有問題,所以我們僅需要調整一下VID的值即可。

其二我們USB介面描述類中,介面類必須為0x08Mass storage class),子類為0x06SCSI transparent command set)或0x04UFI),介面協議為0x50Bulk-only transport)。

 

1 子類表

 

 

2 介面協議

 

其它描述資訊由於非關鍵,所以可修改,也可以不改。

 

3. 呼叫介面

Mass Storage驅動位於/DeviceCode/Drivers目錄下, 屬於通用驅動,其它裝置都可以呼叫。包括如下三個檔案:UsbMassStorage.hUsbMassStorage.cppUsbMassStorage_config.cpp

3.1   PAL層介面

3.1.1 UsbMassStorage_Start

Mass Storage功能初始化和啟動函式。該函式執行時,先關閉原先的USB驅動介面,再用新USB Config初始化USB介面,最後啟動一個定時中斷函式。

函式原型:int UsbMassStorage_Start(UINT32 value)

    數:value為時鐘中斷間隔,單位us

值:0

3.1.2 UsbMassStorage_Stop

Mass Storage功能停止函式。該函式先關閉時鐘中斷函式及自己定義的USB介面,最後恢復預設USB介面(即UsbDefaultConfiguration)。

函式原型:int UsbMassStorage_Stop()

值:0

3.2   P/Invoke介面

考慮到使用者也可以自由開啟和關閉Mass Storage功能,所以為使用者提供了P/Invoke介面。該介面檔案位於:/Solutions/DM335/DeviceCode目錄下,其實該程式通用,可以放在PAL層。包括兩部分程式碼,一是託管程式碼,二是原生代碼。

介面宣告如下,函式功能同PAL層介面。

namespace YFSoft

{

    public static class MassStorage

    {

        [MethodImplAttribute(MethodImplOptions.InternalCall)]

        extern static public int Start(UInt32 value);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]

        extern static public int Stop();

    }

}

注意:使用者在呼叫MassStorage.Start()函式之前,先執行以下程式碼,以使磁碟快取中的內容真實寫入儲存裝置。

    VolumeInfo[] vis = VolumeInfo.GetVolumes();

    foreach (VolumeInfo vi in vis)

    {

        vi.FlushAll();

  }

4USB列舉程式碼新增

Mass Storage類規範定義了兩個請求:Get_Max_LUNMass Storage Reset,所有的Mass Storage類裝置都必須支援這兩個請求。

處理GET MAX LUN命令時,我們返回實際的邏輯單元(LUN0~15)個數即可,由於我們的Mass Storage驅動僅支援一個儲存裝置,所以直接返回0即可。其實該命令也可以不應答,這時PC會重試三次,不過重試過程比較緩慢,使用者體驗體驗很不好。

對於Mass Storage Reset命令,由於我們目前沒有任何工作可做,所以直接返回空資料即可。

相關程式碼如下:

if(len>0)

   {

         USB_SETUP_PACKET* Setup= (USB_SETUP_PACKET*)State->Data;

        //GET MAX LUN  

       if(Setup->bmRequestType == 0xA1 && Setup->bRequest ==  0xFE)

       {

              *(volatile UINT8 *)((UINT32)&usb.FIFO[0]) = 0;

                      usb.Indexed.PERI_CSR0=DM335_USB_Indexed::PERI_CSR0_TXPKTRDY | DM335_USB_Indexed::PERI_CSR0_DATAEND;

           return;

       }

       //Mass Storage Reset

       if(Setup->bmRequestType == 0x21 && Setup->bRequest ==  0xFF)

       {

            usb.Indexed.PERI_CSR0=DM335_USB_Indexed::PERI_CSR0_TXPKTRDY | DM335_USB_Indexed::PERI_CSR0_DATAEND;

         return;

       }

 }

該部分程式碼直接新增在/DeviceCode/Targets/Native/DM335/DeviceCode/DM335_USB.cpp中的DM335_USB_Driver::EP0_ISR()函式即可。

5. Mass Storage功能實現

其實只要實現了標準的USB驅動介面,在此基礎上實現Mass Storage功能應該算不太難,這裡不打算詳細介紹Mass Storage功能的方方面面,這會涉及到太多的相關知識,我這裡只是從我們實際的這部分功能出發,簡明扼要地介紹一下Mass Storage功能實現的原理。

這裡需要特別指出的是,Bulk-only transport協議,僅需要USB驅動提供兩個端點即可,一個是端點1(輸入端點),一個是端點2(輸出端點),兩者的型別都為BULK模式。很幸運的是我們的.Net Micro Framework的標準驅動和這個要求是一致的。

5.1 命令/資料/狀態

Mass Storage裝置列舉成功後,PC會通過端點2Mass Storage裝置傳送各種命令,Mass Storage裝置根據相應的命令,進行不同的應答。

其命令、資料、狀態相關的流程圖如下:

 

 

PC機發送的資料必須符合CBW格式(31byte小端模式),而Mass Storage裝置的應答,其格式必須符合CSW格式(13byte,小端模式)。至於中間過程傳輸的資料,根據不同的命令,格式也有不同地要求。

5.1.1 CBW命令塊(Command Block Wrapper

 

3 CBW命令塊

dCBWSignature:常數0x43425355,標識為CBW命令塊。

dCBWTag: 由主機發送的CBW標籤。裝置應該在相關的CSWdCSWTag以相同的值應答主機。

dCBWDataTransferLength 在本命令執行期間,主機期望通過Bulk-InBulk-Out端點傳輸的資料長度。如果為0,則表示這之間沒有資料傳輸。

bmCBWFlags 定義如下(Bit7 DirectiondCBWDataTransferLength0時,該值無意義)

 0= DataOut,資料從主機到裝置

1= DataIn, 資料從裝置到主機

Bit6 Obsolete  0

Bits 5..0 Reserved  0

bCBWLUN: 表示正在傳送命令字的裝置的邏輯單元號(LUN)。對於支援多個LUN的裝置,主機設定相對應的LUN值。否則,該值為0

bCBWCBLength: CBWCB的有效位元組長度。有效值是在116之間。

CBWCB 被裝置解析執行的命令塊。

注:該部分是重中之重,通過對這部分的命令的解析,實現實際的Mass Storage功能。

5.1.2 CSW狀態塊(Command Status Wrapper

 

4 CSW狀態塊

dCSWSignature: 常數0x53425355,標識為CSW狀態塊

dCSWTag: 取相對應的CBWdCBWTag值。

dCSWDataResidue:實際傳輸的資料個數和期望要傳輸的資料個數之差。

bCSWStatus:命令執行情況,相關值如下:

 

5.2 SCSI 傳輸協議(或UFI傳輸協議)

很多資料上都是把子類協議設定為0x06,也就是SCSI 傳輸協議,實際測試表明設定為0x04(也就是UFI傳輸協議)也是可以的。實際看說明書,發現二者很多命令都是相同的,所以這兩種協議對我們來說都適合,不過我這裡建議最好看UFI傳輸協議手冊,它要比SCSI手冊簡明地多。

無論是SCSI 傳輸協議還是UFI傳輸協議,其命令都是非常多的,不過對於我們的應用,我們僅需實現如下幾條指令即可。

5.2.1 INQUIRY命令

該命令詢問Mass Storage裝置的基本資訊,如生產廠家,產品名稱,產品版本等等。

 

詳細引數說明請參見《UFI Command Specification》,比較有意思的是Peripheral Device Type引數,如果設定為0,則表示這是一個可移動的儲存裝置(類似U盤),而設定為0x1F,則表示是一個非移動裝置(類似硬碟,圖示在硬碟區出現)。

5.2.2 READ_FORMAT_CAPACITIES命令

該命令獲取Mass Storage裝置儲存大小,Block長度(一般為一個扇區大小,預設為512)等資訊。

 

該表僅包括部分反饋資訊,詳細說明請參見《UFI Command Specification》。需要注意的是,無論是塊個數,還是塊長度,其資料格式為大端模式。

5.2.3 READ_CAPACITY命令

該命令返回最後一個塊的索引和塊的長度,其實該命令可以看著是READ_FORMAT_CAPACITIES命令的一個子集。

 

注意資料格式為大端模式。

詳細說明請參見《UFI Command Specification》。

5.2.4 READ_10命令

該命令由PC端發出,請求Mass Storage裝置傳送指定扇區索引、扇區個數的資料。

 

這是PC機請求的命令,Mass Storage裝置直接返回相應的資料即可。

詳細說明請參見《UFI Command Specification》。

5.2.5 WRITE_10命令

該命令由PC端發出,CBW命令塊後面緊跟的就是相應扇區的資料。

 

Mass Storage裝置獲取資料後,寫到相應扇區即可。

這裡需要強調的是,由於要接收的資料量有可能很大,該部分功能又是在時鐘中斷中實現,所以不要試圖一次獲取所有的扇區資料,否則在實際的TinyCLR環境中執行是不正常的。其實在READ_10中也存在類似問題,不過實際測試,直接傳送所有資料,並沒有什麼問題,這從側面反映PC機的接收資料能力,遠遠大於MF裝置。

5.2.6 REQUEST_SENSE命令

PC機每傳送一個命令後,都會檢測裝置返回的CSW的狀態值是否為0Good Status),如果不為0,則PC機馬上傳送REQUEST_SENSE命令,詢問出錯的進一步資訊。

 

我們這裡Sense Key的值直接設為0x05ILLEGAL REQUEST)即可,主要原因是PC端會詢問各種命令,由於我們沒有實現,返回的CSW狀態都非Good Status而已。

詳細說明請參見《UFI Command Specification》。

5.2.7 TEST_UNIT_READY命令

在沒有其它命令進行操作時,PC端會每隔一定時間,就會發送該命令,主要是為了探測Mass Storage裝置是否存在(類似心跳訊號)。

由於該命令沒有資料互動,我們直接返回狀態Good StatusCSW狀態塊即可。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述