使用STM32CUBEMX6.6.1 KEIL5.27
首先打开CUBEMX新建工程:
确定芯片型号
根据实际外部晶振选择
设置下载调试方法
设置usb 引脚
设置usb主机模式
设置W25QXX的SPI引脚,看资料说W25QXX SPI协议要HIGH+2EDGE,但我尝试通信不正确,改为LOW+1EDGE通信正确,FLASH_CS引脚自己根据引脚连接设置。
设置FATFS,开启U盘和USER(W25QXX)
频率设置输入168按回车即可
工程配置,保存位置不要有中文。
最后生成工程;
由于U盘设置只用了俩个引脚会跳出警告无视点yes即可
生成完成后,点击打开工程。
打开工程进入配置界面
根据自己的下载器选择下载方式
下载完成,自动开始运行。
在工程保存地址内,新建文件夹来保存自己移植的文件。
在KEIL里把创建的文件夹包含进来
添加分组,与自己的文件
查看U盘状态在
把Appli_state加入DEBUG中,开始后,插入U盘和拔出U盘状态改变。
自定义的FATFS中这俩个函数返回一定要像U盘FATFS改成返回OK,不然挂载不成功
内容为:
#define FLASH_SECTOR_SIZE 4096 //W25QXX一块4k,对擦写友好
#define FLASH_SECTOR_COUNT 256*16 //代表总大小=FLASH_SECTOR_SIZE*256*16=16M
#define FLASH_BLOCK_SIZE 65536 //不太懂
/* USER CODE END DECL */
/* Private function prototypes -----------------------------------------------*/
DSTATUS USER_initialize (BYTE pdrv);
DSTATUS USER_status (BYTE pdrv);
DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */
Diskio_drvTypeDef USER_Driver =
{
USER_initialize,
USER_status,
USER_read,
#if _USE_WRITE
USER_write,
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
USER_ioctl,
#endif /* _USE_IOCTL == 1 */
};
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initializes a Drive
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
DSTATUS USER_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
/* USER CODE BEGIN INIT */
return RES_OK;
/* USER CODE END INIT */
}
/**
* @brief Gets Disk Status
* @param pdrv: Physical drive number (0..)
* @retval DSTATUS: Operation status
*/
DSTATUS USER_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
/* USER CODE BEGIN STATUS */
return RES_OK;
/* USER CODE END STATUS */
}
/**
* @brief Reads Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data buffer to store read data
* @param sector: Sector address (LBA)
* @param count: Number of sectors to read (1..128)
* @retval DRESULT: Operation result
*/
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 */
for(;count>0;count--)
{
W25QXX_Read(buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
return RES_OK;
/* USER CODE END READ */
}
/**
* @brief Writes Sector(s)
* @param pdrv: Physical drive number (0..)
* @param *buff: Data to be written
* @param sector: Sector address (LBA)
* @param count: Number of sectors to write (1..128)
* @retval DRESULT: Operation result
*/
#if _USE_WRITE == 1
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 */
if(count<=8)
{
W25QXX_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE*count); //节约时间
}
else
{
for(;count>0;count--)
{
W25QXX_Write((u8*)buff,sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE);
sector++;
buff+=FLASH_SECTOR_SIZE;
}
}
return RES_OK;
/* USER CODE END WRITE */
}
#endif /* _USE_WRITE == 1 */
/**
* @brief I/O control operation
* @param pdrv: Physical drive number (0..)
* @param cmd: Control code
* @param *buff: Buffer to send/receive control data
* @retval DRESULT: Operation result
*/
#if _USE_IOCTL == 1
DRESULT USER_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
/* USER CODE BEGIN IOCTL */
DRESULT res = RES_ERROR;
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = (WORD)FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
/* USER CODE END IOCTL */
}
测试时先测试W25QXX读ID是否正确
W25QXX_Init();
retUSER=f_mount(&USERFatFS,USERPath,1);//挂载w25qxx
if(retUSER == FR_NO_FILESYSTEM)//没有格式化过
{
sprintf(system_state,"w25qxx未格式化");
retUSER = f_mkfs(USERPath, 1, 0, work, sizeof(work));//格式化
if(retUSER == FR_OK)//格式化成功后重新挂载
{
sprintf(system_state,"w25qxx格式化成功");
/* 格式化后,先取消挂载 */
retUSER = f_mount(NULL, USERPath, 1);
/* 重新挂载 */
retUSER = f_mount(&USERFatFS,USERPath, 1);
}
else
{
sprintf(system_state,"w25qxx格式化失败");
while(1);
}
}
else if(retUSER != FR_OK)
{
sprintf(system_state,"w25qxx挂载失败");
while(1);
}
else
{
sprintf(system_state,"w25qxx挂载成功");
}
retUSER = f_open(&USERFile, "1:STM32.TXT", FA_OPEN_ALWAYS | FA_WRITE);
if(retUSER != FR_OK)
{
sprintf(system_state,"打开文件失败");
while(1);
}
else
sprintf(system_state,"打开文件成功");
f_lseek(&USERFile,f_size(&USERFile));//应该是开启后可以连续写
retUSER = f_write(&USERFile, &trigger_time, sizeof(trigger_time), &bw);
if(retUSER)
{
sprintf(system_state,"写时间失败");
while(1);
}
else
sprintf(system_state,"写时间成功");
retUSER = f_close(&USERFile);//关闭文件
retUSER = f_mount(NULL, USERPath, 1);//取消挂载
今日先到此。
希望给自己增加一个好习惯。细节之处以后再慢慢积累补全。