硬件环境
STM32(支持USB)
存储介质(SPI FLASH、E2P、甚至是片内FLASH均可),本实验使用外部SPI flash(W25Q64)。
使用STM32CubeMX进行配置初始化信息
1.配置MCU的时钟,外设等信息,可以使用一路串口进行输出Log信息,串口波特率越高越好
2.MCU管脚配置
4. 时钟配置
我这里的硬件中有8M的HSE,然后需要注意的是,USB时钟需要配置到48M
3.USB配置,记得打开中断
4.串口
5.存储介质的通信接口,如使用内部flash,则不需要配置
W25Q64 是SPI FLASH,配置SPI接口,这个配置可能需要根据芯片手册进行调整
6.中间件 USB_DEVICE
Class for FS IP选择大容量存储,其他可以默认,USB_DEBUG_LEVEL改不改都一样,做USB device时没看到打印出log来。如果配置了非0,那么需要重定向printf,并且勾选USE Micro LIB,否则可能会出现问题。
7.将堆栈空间改大之后就可以生成代码了
修改程序
生成完程序后,直接编译烧录,然后将USB连接到电脑上,就可以看到已经多出来一个盘符,但是看不到容量和大小,也不能成功格式化磁盘,那是因为我们还没有完成数据的读取和写入
修改添加存储介质的驱动代码
这个步骤很关键,如果你的驱动有问题,那么就会导致格式化失败,也就没办法使用。
W25Q64
必要的函数
W25Q64.h
- typedef struct
- {
- void (*init) (void);
- void (*read_sector) (uint32_t addr, uint8_t *pData, uint32_t length);
- void (*write_sector) (uint32_t addr, uint8_t *pData, uint32_t length);
- uint8_t (*get_status) (void);
- }W25Q64_Dev_T;
- extern W25Q64_Dev_T w25q64_drv;
复制代码
W25Q64.c
- static void w25q64_write_enable(void);
- static void w25q64_write_disable(void);
- static void w25q64_chip_init(void);
- static void w25q64_page_write(uint32_t addr, uint8_t *pData, uint32_t length); //256byte max
- static void w25q64_sector_write(uint32_t addr, uint8_t *pData, uint32_t length);//4kbyte max
- static void w25q64_sector_read(uint32_t addr, uint8_t *pData, uint32_t length);
- static void w25q64_erase_sector(uint32_t addr);
- static uint8_t w25q64_read_satatus(void);
- static uint8_t data_padding = 0xff;
- W25Q64_Dev_T w25q64_drv =
- {
- w25q64_chip_init,
- w25q64_sector_read,
- w25q64_sector_write,
- w25q64_read_satatus,
- };
复制代码
数据读写函数添加到USB驱动中
我们要修改的文件是 usbd_storage_if.c
- #define STORAGE_LUN_NBR 1
- #define STORAGE_BLK_NBR W25Q64_SECTOR_NBR//改为flash介质的sector 数量
- #define STORAGE_BLK_SIZ W25Q64_SECTOR_SIZE//改为flash介质的sector 大小
复制代码
int8_t STORAGE_Init_FS(uint8_t lun)
我们可以添加我们刚刚写的存储介质初始化,如果正常,则返回 USBD_OK
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
获取存储介质的大小,函数已经填充好,我们可以不动
int8_t STORAGE_IsReady_FS(uint8_t lun)
获取介质状态,我们要对存储介质的状态进行判断,这里我们要判断两点,一个是是否正在读写状态中,另外一个就是存储介质是否是不可工作状态
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
判断是否是写保护,我们可以直接返回USBD_OK
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
读取一个扇区,我们将准备好的读取一个扇区的代码填充进来就好
例上述W25Q64的驱动代码:
- /**
- * @brief .
- * @param lun: .
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
- int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
- {
- /* USER CODE BEGIN 6 */
- while(STORAGE_IsReady_FS(1) != 0);
- storage_status = 1;
- w25q64_drv.read_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);
- storage_status = 0;
- return (USBD_OK);
- /* USER CODE END 6 */
- }
复制代码
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
写入一个扇区,我们将准备好的读取一个扇区的代码填充进来就好
例上述W25Q64的驱动代码:
- /**
- * @brief .
- * @param lun: .
- * @retval USBD_OK if all operations are OK else USBD_FAIL
- */
- int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
- {
- /* USER CODE BEGIN 7 */
- while(STORAGE_IsReady_FS(1) != 0);
- storage_status = 1;
- w25q64_drv.write_sector(blk_addr*W25Q64_SECTOR_SIZE, buf, blk_len*W25Q64_SECTOR_SIZE);
- storage_status = 0;
- return (USBD_OK);
- /* USER CODE END 7 */
- }
复制代码
int8_t STORAGE_GetMaxLun_FS(void)
读取磁盘介质的个数,一般我们只虚拟出一个来,不用管就行
我们使用的spi flash的sector大小为4k,也就是4096,USB这边是520,所以我们需要将其修改一致
修改usbd_msc.h
- /** @defgroup USBD_BOT_Exported_Defines
- * @{
- */
- /* MSC Class Config */
- #ifndef MSC_MEDIA_PACKET
- #define MSC_MEDIA_PACKET 4096U //512U
- #endif /* MSC_MEDIA_PACKET */
- #define MSC_MAX_FS_PACKET 0x40U //0x40
- #define MSC_MAX_HS_PACKET 0x1000U //0x200
- #define BOT_GET_MAX_LUN 0xFE
- #define BOT_RESET 0xFF
- #define USB_MSC_CONFIG_DESC_SIZ 32
- #define MSC_EPIN_ADDR 0x81U
- #define MSC_EPOUT_ADDR 0x01U
复制代码
修改usbd_conf.h
- /** @defgroup USBD_CONF_Exported_Defines USBD_CONF_Exported_Defines
- * @brief Defines for configuration of the Usb device.
- * @{
- */
- /*---------- -----------*/
- #define USBD_MAX_NUM_INTERFACES 1
- /*---------- -----------*/
- #define USBD_MAX_NUM_CONFIGURATION 1
- /*---------- -----------*/
- #define USBD_MAX_STR_DESC_SIZ 4096 //512
- /*---------- -----------*/
- #define USBD_DEBUG_LEVEL 3
- /*---------- -----------*/
- #define USBD_SELF_POWERED 1
- /*---------- -----------*/
- #define MSC_MEDIA_PACKET 4096 //512
复制代码
至此,我们的U盘就做好了
————————————————
版权声明:Logan Li
|