使用STM32 USB设备库将闪存作为大容量存储设备 [英] Flash memory as mass storage device using STM32 USB Device Library

查看:184
本文介绍了使用STM32 USB设备库将闪存作为大容量存储设备的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There is this flash memory IC on my board, which is connected to my STM32F04 ARM processor. USB port of the processor is available for the user. I want my flash memory to be detected as storage device when connected to PC via USB.

第一步,我在程序中将USB类定义为MSC,可以正常工作。因为当我将开发板连接到PC时,它会检测到已连接的大容量存储设备,并显示错误消息您应先使用它格式化光盘。

As the first step I defined my USB class as MSC in my program which works fine. Since when I connect my board to PC, it detects a mass storage device connected, giving an error that "You should format the disc before using it".

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

Now the question is that, how I can define my flash as 'the storage' to my processor. The following would probably be a part of your answer: -usbd_msc_storage_template.c -FAT file system

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

I am using STM32F446 processor. FREERTOS and FATFS. Windows 10 on my PC.

预先感谢:)

推荐答案

首先-如果您只需要将闪存作为大容量存储设备在PC上可见,则不需要FatFS,因为它用于从MCU以逐个文件的方式访问存储。当PC访问存储设备时,它将自行管理其上的文件系统,并且您可以选择格式化驱动器时要使用的文件系统类型。与存储本身进行通信时,处于低电平时,它告诉存储从Y地址读取/写入X字节。设备所需要做的就是写入或读取给定的数据并返回操作结果。

First of all - if you only need the flash memory to be visible on your PC as mass storage device then you don't need FatFS, as it is used to access storage in a file-by-file manner from the MCU. When PC accesses the storage devices it manages the filesystem(s) on it by itself and you may choose which kind of filesystem is going to be used when formatting the drive. Down at the low level when communicating with the storage itself all it does is telling the storage to "read/write X bytes from Y address". All the device needs to do is to write or read given data and return the result of the operation.

USB Mass Storage设备类

此USB类将您的设备作为存储设备公开给主机,从而使其可以从/向指定地址读取或写入给定数量的字节。对于您提到的STM32F4,需要实现的功能如下(基于STM32Cube库):

This USB class exposes your device to the host as a storage device, allowing it to read or write given number of bytes from/to specified address. In case of STM32F4 you've mentioned, the functions you need to implement are the following (based on STM32Cube library):

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板的参考实现。您似乎已正确完成了此操作,因为主机正确地将您的设备检测为USB MSC设备并报告其未格式化。

As you've mentioned, there is a USBD_MSC_Template_fops.c / .h files that provide a sample empty template for you to implement, the most important functions being Read and Write where the real "work" is done. To initialize your deivce to be shown as a USB Mass Storage device when connected to a PC host all that's left is: initializing the USB itself (USBD_Init), registering MSC device class (USBD_RegisterClass), registering said structure in the driver (USBD_MSC_RegisterStorage) and starting the USB device process for the driver (USBD_Start) when a connection to the host is detected. There are numerous examples that do just that - see reference implementations for Discovery or Eval boards. You seem to have done that correctly, as the host propery detected your device as USB MSC device and reported it as not formatted.

系统表示驱动器未格式化的原因是因为 usbd_msc_storage_template.c 文件中的空实现返回 STORAGE_Read 函数的成功执行(返回码0),但实际上不执行任何读取操作-没有数据返回。尽管每个主机的具体情况因操作系统而异,但最可能的情况是您会看到一条有关存储未格式化或数据损坏的消息。

The reason your system says that the drive is not formatted is because the empty implementation in the usbd_msc_storage_template.c file returns successful execution (return code 0) for STORAGE_Read function, but does not actually perform any read - no data is sent back. While this may vary from host to host depending on the operating system, the most likely scenarios are that you'll either see a message about storage not being formatted or data being corrupted.

将USB海量存储设备回调与物理内存连接

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

As mentioned above, calling USBD_MSC_RegisterStorage will register your struct in the USB MSC device class driver. At this point the driver itself will call your provided functions at appropriate moments - whenever requested by the host. If the target memory was an SD card the natural step would be to first implement functions accessing your SD card. Once those functions are tested and proven to work all that's left would be to put them inside the USB MSC device Read and Write functions and - assuming correct interrupt priorities - it should generally work "out of the box". The system should be able to format the card and later read and write files to it, all through your MCU.

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

It works the same way for any type of memory you choose. The only requirement is implementing the USBD_StorageTypeDef callback functions exactly as they are. This means that the host may choose to write arbitrary number of random bytes at any address within the reported address space and you either fully obey (write all data as it is) and return "successful execution" or return an error, which most likely will mean that your drive will get unmounted and the user will be prompted with an error message. In case of reads this means that if the host requests X number of bytes from Y address, the device needs to return exactly that amount of data. This means that if your memory type is not perfectly suitable for this kind of access, there will be more work that will have to be done in the layer accessing the physical memory in order to obey the USB MSC interface. All that naturally leads us to the last point below.

闪存作为文件系统存储

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

For the flash memories where you access the raw data directly there are certain drawbacks that make them not perfectly suitable for filesystem applications. Those come from the way these memories are constructed. Although achievable, there will be additional steps that will have to be done in order to hide those imperfections:


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

  1. Writing "1"s individually - Flash memory when accessed directly only allows you to write "0" bits under given address. Once certain bit has been flipped to "0", it can no longer be invidually flipped back to "1". In order to do so, the entire block of data needs to be erased first. Depending on the flash memory part, this will typically be areas of 512, 4096 etc. bytes. This means that if you wanted to change given byte from 1 (binary 0000 0001) to 4 (binary 0000 0100), you'd have to do a read-erase-write of the whole sector. For you this means that if even one of the bits that the hosts requests to write needs to be flipped from "0" to "1", you need to first erase that area.

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

Random access - Depending on the type of memory (NOR/NAND) you may or may not be able to access data randomly. In particular, for NOR flashes you may read or write data individually, while for NAND memories due to how the cells are interconnected only page access is allowed. This means that you may have to read or write more data than necessary.

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

Write endurance - flash memories have a certain number of write cycles for each cell. This means that if you constantly write data to the same address you may very quicky exceed this limit. This is particularily important for filesystems like FAT where the FAT area will be constantly written to. This is solved by implementing some form of wear leveling, where physical sector writes are distributed evenly. You may of course choose to make it read-only by returning true from IsWriteProtected, if that's possible for your applicaiton.

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

Now as for how current SD cards achieve all this - all SD cards nowadays that I'm aware of contain a simple microcontroller (some kind of 8081, ARM7 or similar) that implements everything above plus the SD protocol. When talking to the card, you don't really talk to the raw memory but instead you communicate with the MCU sitting between you and your data. Its role is to present you with an illusion of perfect continuous data.

这篇关于使用STM32 USB设备库将闪存作为大容量存储设备的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆