User Tools

Site Tools


zh:usb_express:usb-cdrom

在STM32F103C8芯片上模拟一个USB CDROM

  • 这个项目已经上传至Github,并且
  • 你也可以从本站的下载页上取得全部源码。

STMicroelectronics公司给他们流行的STM32芯片提供的源代码中包含了一个USB mass storage device class示例. 我对这个示例源码做了一些增强,用以模拟一个微型的USB-CDROM。我只接了一颗512KB spi flash芯片做为光盘盘片并且向其中写入了一个很小的ISO9660映像文件。这就是为什么我称其为微型CDROM。原始的源代码仅支持一小部分SCSI请求,我扩充了源代码来支持一些扩展的指令。由于flash芯片的容易很小,我不得不做了一个工具用于分析ISO9660映像文件并且剪裁文件尺寸。我还做了一个工具,使用自定义的指令把光盘映像文件写入flash芯片中。不过这两个工具都是运行于WINDOWS平台的,我对LINUX下的软件开发不甚了解。

第一步:硬件设计

我选择了Bluepill板做为主控,它有两个SPI接口可用于连接flash芯片和TF卡。我配置了SPI2做为主接口,使用8bit数据位宽。PB12引脚用做CS线,由固件通过GPIO来控制,固件中也配置了SPI1接口但并没有真正使用它。我连接了一个串行flash芯片做为光盘片,不过我手头只有一些已停产的小容量芯片(AT45DB041B),这意味着我必须做一个尺寸很小的ISO9660映像文件才能写入这个芯片中。

第二步:生成固件

我们用STM32CubeMX来生成基本的固件源码:

  • 使用HSE振荡器并且外接8MHz晶体,LSE振荡器不使用。
  • 使用SWD串口调试。
  • 把SPI2配置为全双工主接口,8bit数据位宽。
  • 启用USB Device.
  • 配置USB中间件,选择Mass Storage Class。
  • 选择PLLCLK (72MHz)做为SYSCLK,HCLK设为72MHz并且USB时钟设为48MHz.

第三步:编码及编译

  • 为串行flash芯片做一个驱动程序。(spiflash.c)
    1. 可以获取芯片的ID。(我打算尝试支持一些常见的flash芯片,比如说W25X32等等。)
    2. 对芯片进行初始化。
    3. 计算盘片的最大扇区地址。
    4. 写入/读取芯片的一个存储页。
    5. 写入/读取一个光盘片扇区。
    6. 把flash芯片驱动和USB类进行关联。(usbd_storage_if.c)

驱动中部分代码(SELECT/DESELECT/SPI_Xxx)是从eziya's STM32_SPI_SDCARD project这个项目借鉴来的。

  • 处理一些STM32CubeMX不支持的扩展SCSI请求。
    1. READ TOC/PMA/ATIP (0x43)
    2. GET CONFIGURATION (0x46)
    3. GET EVENT/STATUS NOTIFICATION (0x4A)
    4. READ DISC INFORMATION (0x51)
  • STM32CubeMX生成的源码需要打补订。
    1. INQUIRY (0x12)
      1. 在这个命令的响应数据中声明一个CDROM。
      2. 需要支持PAGE CODE。(我还不大确定这是否必须。)
    2. 在函数“MSC_BOT_CBW_Decode”之中:
      1. 当函数SCSI_ProcessCmd返回-1时它没有向主机发送CSW。
  • 实现一些自定义的SCSI请求。
    1. GET FLASH CHIPID (0xFF)
    2. BURN DISC IMAGE (0xFE)

我使用EmBitz集成开发环境编译这个项目,它带有一个GCC编译器(arm_none_eabi)。我使用我自制的全新的CMSIS-DAP JTAG probe来调试这个项目。 ;-)

第四步:制作并写入ISO9660映像文件

我选择了Folder2Iso这个软件制作ISO9660映像文件。由于AT45DB041B芯片的容量超小,我不得不制作一个工具剪裁映像文件的尺寸。请参考iso9660中的WIN32源码。部分源码来自于gootqt's blog: ISO9660文件系统分析

WINDOWS平台上的盘片烧写工具(MSC_Test)有一点小花活,我使用函数“GetMscDeviceContext”来取得这个小光驱的路径名,如果你有另一个USB光驱插在主机上,你得先把它拔了,要不就得检查INQUIRY指令所取得的manufacturer/product字符串。如果你想尝试使用VID/PID来探测这个小光驱,请参考stackoverflow.com上的这个页面。我在我的项目中留了一些来自这个页面的源码(函数“GetDrivesDevInstByDeviceNumber”和“matchDevInstToUsbDevice”)。

zh/usb_express/usb-cdrom.txt · Last modified: 2020/09/25 22:35 by zach