程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .Net Micro Framework - USB Mass Storage功能實現

.Net Micro Framework - USB Mass Storage功能實現

編輯:關於.NET

1. 說明

由於.Net Micro Framework的USB驅動架構中,沒有為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,這樣有兩個好處,一是讀寫有緩存,操作速度較快,二是程序比較通用,代碼在不用修 改的情況下可以訪問不同的Flash、SD卡等存儲模塊。

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

2. USB Config

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

其二我們USB接口描述類中,接口類必須為0x08(Mass storage class),子類為0x06(SCSI transparent command set)或0x04(UFI),接口協議為0x50(Bulk-only transport)。

表1 子類表

表2 接口協議

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

3. 調用接口

Mass Storage驅動位於"DeviceCode"Drivers目錄下, 屬於通用驅動,其它設備都可以調用。包括如 下三個文件:UsbMassStorage.h、UsbMassStorage.cpp、UsbMassStorage_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();

 }

4.USB枚舉代碼添加

Mass Storage類規范定義了兩個請求:Get_Max_LUN和Mass Storage Reset,所有的Mass Storage類設 備都必須支持這兩個請求。

處理GET MAX LUN命令時,我們返回實際的邏輯單元(LUN:0~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會通過端點2向Mass Storage設備發送各種命令,Mass Storage設備 根據相應的命令,進行不同的應答。

其命令、數據、狀態相關的流程圖如下:

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

5.1.1 CBW命令塊(Command Block Wrapper)

表3 CBW命令塊

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

dCBWTag: 由主機發送的CBW標簽。設備應該在相關的CSW的dCSWTag以相同的值應答主機。

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

bmCBWFlags: 定義如下(Bit7 Direction(dCBWDataTransferLength為0時,該值無意義) :

0= DataOut,數據從主機到設備

1= DataIn, 數據從設備到主機

Bit6 Obsolete 0

Bits 5..0 Reserved 0

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

bCBWCBLength: CBWCB的有效字節長度。有效值是在1到16之間。

CBWCB: 被設備解析執行的命令塊。

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

5.1.2 CSW狀態塊(Command Status Wrapper)

表4 CSW狀態塊

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

dCSWTag: 取相對應的CBW的dCBWTag值。

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的狀態值是否為0(Good Status),如果不為0,則 PC機馬上發送REQUEST_SENSE命令,詢問出錯的進一步信息。

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

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

5.2.7 TEST_UNIT_READY命令

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

由於該命令沒有數據交互,我們直接返回狀態Good Status的CSW狀態塊即可。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved