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

2024-04-08

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

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

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

我使用的是STM32F446处理器。 FREERTOS 和 FATFS。 我的电脑上运行的是 Windows 10。

提前致谢 :)


首先 - 如果您只需要闪存作为大容量存储设备在 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 and Write真正的“工作”完成的地方。要初始化您的设备,使其在连接到 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 大容量存储设备回调与物理内存的接口

如上所述,调用USBD_MSC_RegisterStorage将在 USB MSC 设备类驱动程序中注册您的结构。此时,驱动程序本身将在适当的时候调用您提供的函数 - 无论主机何时请求。如果目标内存是 SD 卡,自然的步骤是首先实现访问 SD 卡的功能。一旦这些功能经过测试并证明可以工作,剩下的就是将它们放入 USB MSC 设备中Read and Write功能并且 - 假设正确的中断优先级 - 它通常应该“开箱即用”。系统应该能够格式化卡,然后通过 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,如果您的应用程序可以的话。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 STM32 USB 设备库将闪存作为大容量存储设备 的相关文章

  • Microsoft SkyDrive 有 API 吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 所以与最近有消息称 Microsoft Skydrive 的存储容量将增至 25GB http lif
  • 无法为 Kindle Fire HD 安装 ADB

    我正在尝试root它 尽管在我安装了正确的ADB驱动程序之后 当我插入我的Kindle fire HD 7 时 点燃火 gt Android 复合 ADB 接口 没有出现在设备管理器中 因此我无法执行root 我已将 0x1949 添加到
  • OSX:如何从 IOUSBDeviceInterface 或位置 id 获取卷名称(或 bsd 名称)

    我正在尝试编写一个应用程序 将特定的 USB 字符串描述符 USB 大容量存储设备 与其卷或 bsd 名称相关联 因此 代码会遍历所有连接的 USB 设备 获取字符串描述符并从其中之一提取信息 我想获取这些 USB 设备的卷名 我找不到合适
  • 如何识别“hw.machine”标识符可靠?

    我正在寻找最官方的来源来完成 维护此方法 NSString platformString NSString platform self platform if platform isEqualToString iPhone1 1 retur
  • 使用 adb 连接到 LG 手机时出现问题 (Mac OS X 10.7.5)

    当我跑步时adb devices没有设备显示为已连接 我的设备是运行 4 4 2 的 LG Optimus Exceed 2 周围有很多这样的帖子 所以这就是我所做的 我正在使用电话附带的数据线 它会充电并尝试同步照片 因此这不是问题 切换
  • Android应用程序数据存储不断增加

    我正在开发一个 Android 应用程序 它基本上加载新闻文章列表 并在用户单击时在网络视图中打开它们 我想知道的是 当我在 设置 gt 应用程序 gt 管理应用程序 中查看应用程序详细信息时 总存储大小不断增加 特别是 数据存储规模不断增
  • Flutter - 每次关闭应用程序时存储对象列表的最佳方式?

    情况 我对 Flutter 和移动开发都很陌生 因此对 Dart 不太了解 我已经从有类似问题的人那里阅读了一些解决方案 但没有设法将这些解决方案应用于我自己的事情 问题 我有一个待办事项应用程序 它有 2 个对象列表 我想在用户重新打开应
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • 在数据库中保存 base64 字符串是一个好习惯吗?

    我正在开发一个 Android 应用程序 用户可以将图像发送到我的网络服务 目前 在我的 WebService 上 我得到一个 Base64 字符串并将其保存在数据库的表中 我的问题 这是一个好的做法吗 因为据我所知 Base64 字符串是
  • USB接口条码扫描器

    不完全是一个编程问题 但很接近 无论如何我都会试试运气 The 键盘楔子 扫码机插入 读者之间的翻译装置 和键盘 数据发送通过 楔形看起来就像是被输入的 电脑 而键盘 本身仍保持完整功能 因为电脑使用键盘 楔子无法区分 在输入的数据之间 扫
  • 我可以从哪里开始使用可编程硬件?

    一段时间以来 我一直渴望至少学习一点有关硬件编程的知识 并想在这里提出要求以获得一些起点 我是一位相当有成就的程序员 具有 Delphi 和 Objective c 经验 但从未听过设备端口 中断 我什至不知道术语 更不用说对硬件进行编程了
  • 在 Linux (libusb-1.0) 上访问 USB 设备?

    我正在编写一个小程序 使用 Linux 上的 libusb 1 0 与特定 USB HID 产品 由供应商和产品 ID 标识 进行通信 现在 我必须以 root 身份运行该程序 因为 libusb 需要对 USB 设备节点的写访问权限 有没
  • Android Studio:“创建新 AVD”窗口中禁用“确定”按钮

    我下载并安装了最新的 Android Studio 版本 0 8 6 测试版 但在尝试创建新的 Android 虚拟设备时遇到了困难 我尝试按照以下步骤操作 https developer android com training wear
  • cordova 使用命令行运行(实际)Android 设备?

    根据文档 http cordova apache org docs en 4 0 0 guide cli index md html 我们可以通过以下方式在模拟器上运行我们的 android 项目 cordova run android o
  • USB 端口速度 Linux [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何以编程方式确定运行 Linux 内核的嵌入式设备中的 USB 端口速度 你可以阅读 sys bus usb devices usb s
  • LibUsb 声明接口访问被拒绝 Java

    我希望能够从 USB 计步器读取数据 我正在 Java 中尝试此操作 并且使用 LibUsb 和 Usb4Java 库 我似乎无法认领 USB 管道或类似的东西 我正在使用的代码 final Context context new Cont
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能
  • 限制特定设备销售应用程序?

    是否可以通过特定设备或设备的功能 屏幕分辨率 处理器 磁盘空间等 来限制 Android Market 上应用程序的销售 我知道我会受到人们的轰炸 他们说如果你的应用程序设计得好 它应该能够在任何尺寸的设备上运行 这一切都很好 但出于某些原
  • 在 Windows 上使用 Python 打开设备句柄

    我正在尝试使用 Giveio sys 驱动程序 该驱动程序需要先打开一个 文件 然后才能访问受保护的内存 我正在查看 WinAVR AVRdude 中的 C 示例 它使用以下语法 define DRIVERNAME giveio HANDL
  • Android - 获取所有可用存储的列表

    我正在从互联网将数据下载到我的应用程序中 如果我指定内部内存 Environment getExternalStorageDirectory 我可能会遇到 空间不足 的问题 SD卡安装地址总是因手机而异 所以我想允许用户选择他喜欢的位置 在

随机推荐

  • 获取Sharepoint 2010中当前登录的用户

    我有一个向我显示调查的 Web 部件 我需要获取当前用户 以便我可以根据当前用户的权限隐藏或显示调查的某些信息 SPContext Current Web CurrentUser应该可以解决问题 它具有类似的功能IsSiteAdmin an
  • Python 请求中的 SSLError(读取操作超时)

    我有一个 python API 脚本 尽管使用了 但我的脚本有时会在这一行终止try except 这是代码 try r requests post URL data params headers headers timeout self
  • 当容器大小调整时如何重绘此处地图?

    今天我遇到了一个以前没有遇到或注意到的特殊问题 在 Here Maps 3 0 中设置地图时 我注意到 如果浏览器窗口 小 小于全屏 则在加载地图期间 即使将浏览器窗口大小调整为全屏的 如何更新此处地图的地图大小以占据分配的空间 我的安排如
  • 如何将存储库注入到工作单元?

    我已经实现了我的 UnitOfWork 以便它保留对所有存储库的引用 public interface IUnitOfWork void Commit void RollBack public interface IMyUnitOfWork
  • 如何停止 GHCi 中的无限评估?

    当我运行类似的东西时 Prelude gt cycle ab I can see an infinite printing of ab To stop it I just use Ctrl c And it works 当我跑步时 Prel
  • AWS:为 Cognito 触发器指定 Lambda 版本

    我有一个 Cognito 用户池和相应的身份池 我想调用 Lambda 函数的特定版本Post authentication或类似的其他触发器 尽管示例都有版本号 但我在控制台中没有看到指定版本代码的选项 http docs aws ama
  • 什么是代数数据类型 (ADT)?

    我听到人们在函数式编程中谈论了很多代数数据类型 不要与 抽象数据类型 混淆 我所知道的是 ADT 指的是某种复合 通常是递归 数据类型 例如树或数学表达式 In 维基百科 https en wikipedia org wiki Algebr
  • 关于外连接的默认/填充值

    以下是我正在使用的更大 复杂数据帧的微小 玩具版本 gt gt gt A key u v w x 0 a 0 757954 0 258917 0 404934 0 303313 1 b 0 583382 0 504687 NaN 0 618
  • 如何将非连续数字添加到范围中?

    我试图迭代范围 750 765 并添加非连续数字 769 770 774 如果我尝试在范围函数之后添加数字 它会返回范围列表 然后是各个数字 gt gt gt for x in range 750 765 769 770 774 print
  • 样式表被汉字接管/替换

    好吧 有些事情变得疯狂了 除非中国从我的 iepage 上的测试 style css 文件开始接管 好吧 我猜他们一开始就讨厌 IE 但无论如何 它加载时没有样式表 悲伤 我进入 Web 检查器 看到所有链接的文件都充满了 可能 中文字符
  • 无法初始化私有常量成员[重复]

    这个问题在这里已经有答案了 我想要一个int与我的类相关联 该类在该类的用户实例化它时设置 class MyClass public MyClass int x private const int x 为了不断初始化它 我尝试使用构造函数
  • 无法运行 XAMPP - MySql

    当我尝试启动 XAMPP MySql 时 它不起作用 我已经尝试修复它 但我找不到任何实际的解决方案 我希望你能找到问题所在 有日志 2019 06 26 9 08 35 0 Note InnoDB Mutexes and rw locks
  • 为了速度/性能什么时候应该、不应该脱离 OOP?

    在 Android 开发者文章中 Google 指出 您通常应该声明公共变量 而不是带有 getter 和 setter 的私有变量 以增强嵌入式设备的性能 我认为函数调用比仅仅写入地址更昂贵 我想知道 应该在多大程度上牺牲性能来坚持 OO
  • 如何在列表框中设置对齐格式

    我将值添加到列表框 for int i 0 i lt 2 i lbBeamValue Items Add Beam i ToString value1 i Angle i ToString value2 i 显示如下 Beam 0 0 12
  • 仅保留 JavaScript 对象中的某些属性

    我有一个对象 我想通过删除除某些特定属性之外的所有属性来修改对象 而不是克隆它 例如 如果我从这个对象开始 var myObj p1 123 p2 321 p3 p3 1 1231 p3 2 342 p4 23423 p99 p99 1 s
  • 截断分页中的页数

    这可能是一个非常愚蠢的问题 但我想不出任何可以帮助我走得更远的东西 我希望缩短页面导航中的数字数量 而不是像 1 2 3 4 5 6 7 8 我希望它像 1 2 7 8 当我去2 数字3现在应该可以在数字组中看到 这是我负责页码的代码 di
  • MySQL 最大用户连接数与最大连接数

    可悲的是 我在任何地方都找不到对此查询的任何直接解释 甚至在 MySQL 文档中也找不到 各个论坛上的一些人说 max user connections 永远不能大于 max connections 例如 如果一个用户有3 max user
  • mutableStateOf 和 mutableStateListOf 有什么区别?

    在与一个ViewModel and a List存储在那里 我通常遵循这种方法 var characteristics by mutableStateOf listOf
  • Emacs、Vim 和 JEdit 中哪些编辑器支持同时多个文本插入点?

    背景 JEdi t 以及其他一些文本编辑器 支持称为多个同时文本插入点 http groups csail mit edu uid projects simuledit usenix01 html 至少我在这里这么称呼它 要了解这意味着什么
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板