首先 - 如果你只需要閃存是你的PC機作爲大容量存儲設備上可見,那麼你就不需要FATFS,因爲它是用來訪問存儲在從MCU接收文件的方式。當PC訪問存儲設備時,它自己管理其上的文件系統,您可以選擇在格式化驅動器時使用哪種類型的文件系統。在與存儲器本身通信時處於低電平狀態時,它只是告訴存儲器「從Y地址讀取/寫入X字節」。所有設備需要做的是寫入或讀取給定的數據並返回操作結果。
USB大容量存儲設備
這個USB類暴露你的設備到主機的存儲設備,允許其讀取或從/到指定的地址寫入的字節給定數。在STM32F4的情況下,你所提到的,你需要的是以下(基於STM32Cube庫)的實現功能:
typedef struct _USBD_STORAGE
{
int8_t (* Init) (uint8_t lun);
int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint16_t *block_size);
int8_t (* IsReady) (uint8_t lun);
int8_t (* IsWriteProtected) (uint8_t lun);
int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* GetMaxLun)(void);
int8_t *pInquiry;
}USBD_StorageTypeDef;
正如你所提到的,有一個USBD_MSC_Template_fops.c/.h
文件提供了一個樣本空模板你要實現,最重要的功能是Read
和Write
真正的「工作」完成。要將您的設備初始化爲連接到PC主機時顯示爲USB大容量存儲設備,請執行以下操作:初始化USB本身(USBD_Init
),註冊MSC設備類(USBD_RegisterClass
),將所述結構註冊到驅動程序中(USBD_MSC_RegisterStorage
)和當檢測到與主機的連接時,啓動驅動程序的USB設備進程(USBD_Start
)。有很多例子可以做到這一點 - 請參閱Discovery或Eval主板的參考實現。您似乎已經正確地完成了這項工作,因爲主機Propery將您的設備檢測爲USB MSC設備並將其報告爲未格式化。
系統說,未格式化的驅動器是因爲在usbd_msc_storage_template.c
文件中的空實現返回STORAGE_Read
函數執行成功(返回碼爲0),但實際上並不執行任何讀的原因 - 沒有數據發送回。雖然這可能因主機而異,具體取決於操作系統,但最可能的情況是,您將看到有關存儲未格式化或數據被損壞的消息。
接口USB大容量存儲設備與回調的物理內存
如上所述,稱USBD_MSC_RegisterStorage
將註冊在USB MSC設備類驅動程序的結構。此時,驅動程序本身會在適當的時候調用您提供的功能 - 只要主機提出要求。如果目標存儲器是SD卡,則自然會首先實現訪問SD卡的功能。一旦這些功能經過測試並證明可以正常工作,剩下的就是將它們放入USB MSC設備Read
和Write
的功能中,並且 - 假設正確的中斷優先級 - 它通常應該「開箱即用」。系統應該能夠對卡進行格式化,然後通過MCU讀取和寫入文件。
對於您選擇的任何內存類型,它的工作方式都是相同的。唯一的要求是完全按照原樣執行USBD_StorageTypeDef
回調函數。這意味着主機可以選擇在報告的地址空間內的任意地址寫入任意數量的隨機字節,並且您完全遵守(按原樣寫入所有數據)並返回「成功執行」或返回錯誤,這很可能會意味着您的驅動器將被卸載,用戶將收到錯誤消息提示。在讀取的情況下,這意味着如果主機請求來自Y地址的X個字節,則設備需要準確返回該數量的數據。這意味着,如果你的存儲器類型不適合這種訪問,那麼在訪問物理存儲器的層中必須做更多的工作才能遵守USB MSC接口。所有這些自然導致我們下面的最後一點。
閃存文件系統作爲存儲
對於您訪問原始數據直接存在一定的缺陷,使其不能完全適用於文件系統應用的閃存。那些來自這些記憶構建的方式。雖然實現的,將有將有爲了隱藏這些缺陷做額外的步驟:
寫「1」分別 - 當直接訪問閃存只允許你寫在「0」位給定的地址。一旦某位被翻轉爲「0」,就不能再單獨翻轉回「1」。爲了這樣做,首先需要擦除整個數據塊。取決於閃存部分,這通常是512,4096等字節的區域。這意味着如果您想將給定字節從1(二進制0000 0001)更改爲4(二進制0000 0100),則必須對整個扇區執行讀寫擦除。對你而言,這意味着如果主機請求寫入的位中的一位需要從「0」翻轉到「1」,則需要先擦除該區域。
隨機存取 - 根據存儲器類型(NOR/NAND),您可能或不可能隨機存取數據。特別是,對於NOR閃存,您可以單獨讀取或寫入數據,而對於NAND存儲器,由於單元之間的互連方式,只允許頁面訪問。這意味着您可能需要讀取或寫入更多的數據。
寫耐久性 - 閃存對每個單元都有一定的寫週期數。這意味着如果你不斷地寫數據到同一個地址,你可能會很快超過這個限制。這對FAT等文件系統非常重要,FAT區將不斷寫入。這通過實施某種形式的損耗均衡來解決,其中物理扇區寫入均勻分佈。您當然可以選擇通過從IsWriteProtected
返回true來使其成爲只讀,如果這可能適用於您的應用程序。
現在爲如何目前SD卡實現這一切 - 所有的SD卡現在,我所知道的包含一個簡單的微控制器(某種8081,ARM7或類似)實現上面加SD協議的一切。在與卡交談時,您並不真正與原始記憶交談,而是與坐在您和您的數據之間的MCU通信。它的作用是向您呈現完美連續數據的錯覺。
非常感謝您的快速回答Jacek。我會嘗試在usbd_msc_storage_template.c中實現這些API函數,看看會發生什麼。 –