STM32 USB 系列之大容量设备MSC
这次的项目使用STM32的大容量设备进行文件传输,通过STM32的USB大容量设备将电脑中的文件放到外部FALSH中,然后在程序运行时通过FATFS文件系统读取数据访问文件。
完整工程在文末提供CSDN下载和Github下载
内容提要:USB大容量设备的移植、FATFS文件系统移植、W25Q64驱动。
建立STM32Cube工程
该工程使用STM32F103ZET6,在cube中选择对应的芯片,创建工程。启用USART1作为调试信息输出。
- 首先配置外部晶振,修改时钟为72MHZ。
- 开启SPI外设
我的FLASH芯片引脚接到SPI2,配置并修改通信波特率。
数据长度,时钟极性,时钟相位全部默认值。
波特率设置分频系数,在72M时钟时选择8分频,波特率为4.5MBit/s
- 使能USB外设,启用USB大容量设备库,注意配置输入输出缓冲大小为4096,对应Flash一个扇区大小
- 启用FATFS,注意修改最大扇区大小,其他参数默认
- 由于USB使用了堆,所以将堆栈设置大一点
FLASH芯片驱动
本次使用FLASH芯片问W25Q16,芯片驱动参考使用微雪电子的相关教程,本次主要使用到这几个函数
void BSP_W25Qx_Read_ID(uint8_t *ID); //读取芯片ID
uint8_t BSP_W25Qx_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size); //读取指定长度数据
uint8_t BSP_W25Qx_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size); //写入指定长度数据
uint8_t BSP_W25Qx_Erase_Block(uint32_t Address); //扇区擦除
FATFS移植
FATFS移植核心在于user_diskio.c文件的几个函数,核心在于读写两个函数,其他部分参考文末附带的工程。
这几个宏定义了FATFS使用的扇区数和扇区大小
#define SPI_FLASH_REBUILD 1 // 1:使能格式化串行Flash,0:禁用格式化串行Flash
#define SPI_FLASH_SECTOR_SIZE 4096 // 串行Flash扇区大小
#define SPI_FLASH_START_SECTOR 256 // 串行Flash文件系统FatFS偏移量
#define SPI_FLASH_SECTOR_COUNT 256 // 串行Flash文件系统FatFS占用扇区个数
FATFS的写函数,向FLASH芯片写入数据
DRESULT USER_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
/* USER CODE BEGIN WRITE */
/* USER CODE HERE */
uint32_t write_addr;
/* 扇区偏移7MB,外部Flash文件系统空间放在SPI Flash后面9MB空间 */
sector+=SPI_FLASH_START_SECTOR;
write_addr = sector*SPI_FLASH_SECTOR_SIZE;
BSP_W25Qx_Erase_Block(write_addr);
BSP_W25Qx_Write((uint8_t *)buff,write_addr,count*SPI_FLASH_SECTOR_SIZE);
return RES_OK;
/* USER CODE END WRITE */
}
FATFS的读函数,向FLASH芯片读取数据
DRESULT USER_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
/* USER CODE BEGIN READ */
/*spi flash 文件系统从第256扇区开始,共使用256个扇区,大小为1MB*/
sector+=SPI_FLASH_START_SECTOR;
BSP_W25Qx_Read(buff, sector*SPI_FLASH_SECTOR_SIZE, count*SPI_FLASH_SECTOR_SIZE);
return RES_OK;
/* USER CODE END READ */
}
对FATFS的驱动层移植完成后,可使用f_open等函数,对文件系统进行操作。
void fatfs_tset(void)
{
uint8_t wtext[] = "This is STM32 working with FatFs"; /* File write buffer */
uint8_t rtext[100]; /* File read buffers */
char filename[] = "STM32cube.txt";
FATFS fs; /*Fs文件系统对象 */
uint8_t res; /* Return value for SD */
FIL fil; // file objects
res = f_mount(&fs, "", 0);
#if 1 //第一次格式化后将该代码段注释
/*格式化文件系统*/
res=f_mkfs("",0,0);
#endif
res = f_open(&fil, filename, FA_CREATE_ALWAYS | FA_WRITE);
res = f_write(&fil, wtext, sizeof(wtext), (void *)&byteswritten);
res = f_close(&fil);
res = f_open(&fil, filename, FA_READ);
res = f_read(&fil, rtext, sizeof(rtext), (UINT*)&bytesread);
printf(" Write Data : %s\r\n",rtext);
res = f_close(&fil);
}
USB大容量设备移植
USB大容量设备移植,主要在usbd_storage_if.c文件中,同样核心部分在于读写函数
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 256 //使用扇区数量
#define STORAGE_BLK_SIZ 4096 //扇区大小
//读取数据
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
blk_addr+=SPI_FLASH_START_SECTOR;
BSP_W25Qx_Read(buf, blk_addr*SPI_FLASH_SECTOR_SIZE, blk_len*SPI_FLASH_SECTOR_SIZE);
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)
{
/* USER CODE BEGIN 7 */
uint32_t write_addr;
blk_addr+=SPI_FLASH_START_SECTOR;
write_addr = blk_addr*SPI_FLASH_SECTOR_SIZE;
BSP_W25Qx_Erase_Block(write_addr);
BSP_W25Qx_Write((uint8_t *)buf,write_addr,blk_len*SPI_FLASH_SECTOR_SIZE);
return (USBD_OK);
/* USER CODE END 7 */
}
完成后将USB接入电脑即可查看U盘。并且放入文件后可使用FATFS进行读写 。