2017-06-12 99 views
2

我的主板上有这种闪存IC,它连接到我的STM32F04 ARM处理器。处理器的USB端口可供用户使用。当通过USB连接到PC时,我希望将我的闪存检测为存储设备。闪存作为使用STM32的大容量存储设备USB设备库

作为第一步,我在我的程序中将我的USB类定义为MSC,可以正常工作。由于当我将电路板连接到PC时,它会检测到连接的大容量存储设备,并提供错误信息“您应该在使用前格式化光盘”。

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

我正在使用STM32F446处理器。 FREERTOS和FATFS。 我的电脑上安装了Windows 10。

感谢提前:)

回答

2

首先 - 如果你只需要闪存是你的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文件提供了一个样本空模板你要实现,最重要的功能是ReadWrite真正的“工作”完成。要将您的设备初始化为连接到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设备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通信。它的作用是向您呈现完美连续数据的错觉。

+0

非常感谢您的快速回答Jacek。我会尝试在usbd_msc_storage_template.c中实现这些API函数,看看会发生什么。 –