使用STM32 USB设备库将闪存作为大容量存储设备

Ehs*_*uzi 6 usb storage device stm32

板上有此闪存IC,它已连接到STM32F04 ARM处理器。处理器的USB端口可供用户使用。我希望通过USB连接到PC时将我的闪存检测为存储设备。

第一步,我在程序中将USB类定义为MSC,这可以正常工作。因为当我将开发板连接到PC时,它会检测到已连接的大容量存储设备,并出现错误“您应该在使用光盘之前对其进行格式化”。

现在的问题是,如何将闪存定义为处理器的“存储”。以下可能是您答案的一部分:-usbd_msc_storage_template.c -FAT文件系统

我正在使用STM32F446处理器。FREERTOS和FATFS。我的PC上的Windows 10。

提前致谢 :)

Jac*_*mok 9

首先-如果您只需要将闪存作为大容量存储设备在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;
Run Code Online (Sandbox Code Playgroud)

正如您已经提到的,有一个USBD_MSC_Template_fops.c / .h文件为您提供了一个示例空模板供您实施,最重要的功能是完成真正的“工作” ReadWrite在其中完成。要将设备初始化为在连接到PC主机时显示为USB大容量存储设备,剩下的就是:初始化USB本身(USBD_Init),注册MSC设备类(USBD_RegisterClass),在驱动程序中注册所述结构(USBD_MSC_RegisterStorage),然后启动USB USBD_Start检测到与主机的连接时驱动程序()的设备进程。有许多示例可以做到这一点-请参阅Discovery或Eval板的参考实现。您似乎已正确完成了此操作,因为主机正确地将您的设备检测为USB MSC设备,并报告其未格式化。

系统说未格式化驱动器的原因是usbd_msc_storage_template.c文件中的空实现返回功能的成功执行(返回代码0)STORAGE_Read,但实际上并未执行任何读取操作-没有数据回传。尽管不同的主机可能会有所不同,具体取决于操作系统,但最可能的情况是您将看到有关存储未格式化或数据损坏的消息。

将USB Mass Storage设备回调与物理内存连接

如上所述,调用USBD_MSC_RegisterStorage将在USB MSC设备类驱动程序中注册您的结构。这时,驱动程序本身将在适当的时候调用该函数,只要主机请求即可。如果目标内存是SD卡,那么自然的步骤就是首先实现访问SD卡的功能。一旦测试了这些功能并证明它们可以正常工作,剩下的就是将它们放入USB MSC设备ReadWrite功能中,并且-假设正确的中断优先级-通常应该“开箱即用”。系统应该能够格式化卡,并随后通过您的MCU对其进行读写。

对于您选择的任何类型的内存,其工作方式都相同。唯一的要求是实施USBD_StorageTypeDef回调函数完全按原样运行。这意味着主机可以选择在报告的地址空间内的任何地址写入任意数量的随机字节,并且您要么完全服从(按原样写入所有数据),然后返回“成功执行”或返回错误,则很可能会意味着您的驱动器将被卸载,并且将向用户提示错误消息。在读取的情况下,这意味着如果主机从Y地址请求X个字节,则设备需要恰好返回该数据量。这意味着,如果您的内存类型不完全适合此类访问,则在服从USB MSC接口的访问物理内存的层中将需要做更多的工作。所有这些自然地将我们引向下面的最后一点。

闪存作为文件系统存储

对于直接访问原始数据的闪存,存在某些缺点,使其无法完全适合文件系统应用程序。这些来自这些记忆的构建方式。尽管可以实现,但是为了隐藏这些缺陷,还必须执行其他步骤:

  1. 单独写入“ 1”-闪存直接访问时仅允许您在给定地址下写入“ 0”位。一旦将某个位翻转为“ 0”,就不再可以单独将其翻转为“ 1”。为此,需要首先擦除整个数据块。根据闪存部分的不同,这通常是512、4096等字节的区域。这意味着,如果要将给定的字节从1(二进制0000 0001)更改为4(二进制0000 0100),则必须对整个扇区进行读-写操作。对于您来说,这意味着,即使主机请求写入的位之一也需要从“ 0”翻转为“ 1”,您都需要首先擦除该区域。

  2. 随机访问-根据内存类型(NOR / NAND),您可能会或可能不会随机访问数据。特别是,对于NOR闪存,您可以单独读取或写入数据,而对于NAND存储器,由于单元之间的互连方式,仅允许页面访问。这意味着您可能需要读取或写入更多的数据。

  3. 写耐久性-闪存每个单元都有一定数量的写周期。这意味着,如果您不断将数据写入相同的地址,则可能很快超过此限制。这对于像FAT一样会不断写入FAT的文件系统特别重要。这可以通过实施某种形式的损耗均衡来解决,其中物理扇区写入均匀分布。IsWriteProtected如果您的应用程序可能会返回true ,则可以选择将其设为只读。

现在,关于当前的SD卡如何实现所有这些功能-如今我所知道的所有SD卡都包含一个简单的微控制器(某种8081,ARM7或类似产品),该微控制器实现了以上所有功能以及SD协议。与卡通讯时,您实际上并不是在与原始内存通讯,而是与位于您和您的数据之间的MCU通信。它的作用是向您呈现完美连续数据的错觉。