背景:项目中使用ST的fatfs驱动,驱动U盘和NOR FLASH
目的:系统往NOR FLASH写日志,插入U盘后导出日志到U盘中
问题现象:每次进去拷贝函数bCopyOneLogFile(),打开pacCurOutFile文件对象时都会报FR_DISK_ERR错误。
分析过程:
经查阅,FR_DISK_ERR是磁盘IO读写错误。故给USBH_read,USBH_write 返回错误处都加断点,进行调试。可是出现FR_DISK_ERR时未进USB读写断点。
很明显不是磁盘IO读写错误,若是磁盘IO读写错误。为什么第一次调用bCopyOneLogFile()时未出现?又为何没进USBH_read,USBH_write 返回错误断点?
遇事不决查手册
dm00105259-developing-applications-on-stm32cube-with-fatfs-stmicroelectronics-zh.pdf
手册中说FATFS_LinkDriver()是动态增加存储,也就是说不是每次切换读写设备都要链接一次。而是系统增加磁盘时链接,拔出磁盘时断开链接。实现动态磁盘管理的目的。
经过以下修改,完美运行
USB磁盘IO读写代码
/**
* @brief Reads Sector(s)
* @param lun : lun id
* @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 USBH_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
BYTE status = USBH_OK;
usb_core_driver *udev = (usb_core_driver *)usb_host_msc.data;
if (!count)
{
return RES_PARERR;
}
if (Stat & STA_NOINIT)
{
return RES_NOTRDY;
}
if (udev->host.connect_status)
{
do
{
status = usbh_msc_read(&usb_host_msc, lun, sector, buff, count);
if (!udev->host.connect_status)
{
return RES_ERROR;
}
} while (status == USBH_BUSY);
}
if (status == USBH_OK)
{
return RES_OK;
}
return RES_ERROR;
}
/**
* @brief Writes Sector(s)
* @param lun : lun id
* @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 USBH_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
BYTE status = USBH_OK;
usb_core_driver *udev = (usb_core_driver *)usb_host_msc.data;
if (!count)
{
return RES_PARERR;
}
if (Stat & STA_NOINIT)
{
return RES_NOTRDY;
}
if (Stat & STA_PROTECT)
{
return RES_WRPRT;
}
if (udev->host.connect_status)
{
do
{
status = usbh_msc_write(&usb_host_msc, lun, sector, (BYTE *)buff, count);
if (!udev->host.connect_status)
{
return RES_ERROR;
}
} while (status == USBH_BUSY);
}
if (status == USBH_OK)
{
return RES_OK;
}
return RES_ERROR;
}
#endif /* _USE_WRITE == 1 */
修改前USB拷贝部分
BOOLEAN LOG_bCopy2USB(void)
{
UNSIGNED32 dwLogSize = 0; /**< 日志大小*/
UINT dwReadedByteNum = 0; /**< 实际读取字节*/
UINT dwWrittenByteNum = 0; /**< 实际写入字节*/
FRESULT eRet = FR_OK;
UNSIGNED8 i = 0;
for (i = 0; i < LOG_FILE_NUM; i++)
{
/**< 打开2个拷贝文件*/
if (FATFS_LinkDriver(&SNORDISK_Driver, acFlashPath) == 0)
{
eRet = f_open(&sLogFile, (TCHAR const *)&acLogFilePath[i][0], FA_READ);
if (FR_OK != eRet)
{
return FALSE;
}
dwLogSize = f_size(&sLogFile);
dwLogSize = dwLogSize;
}
else
{
return FALSE;
}
if (FATFS_LinkDriver(&USBH_Driver, acUSBPath) == 0)
{
eRet = f_open(&sOutFile, (TCHAR const *)&acOutFilePath[i][0], FA_OPEN_ALWAYS | FA_WRITE);
if (FR_OK != eRet)
{
/**< 打开失败取消U盘挂载*/
eRet = f_mount(NULL, acUSBPath, 0);
return FALSE;
}
}
else
{
/**< 链接失败取消U盘挂载*/
eRet = f_mount(NULL, acUSBPath, 0);
return FALSE;
}
/**< 进行拷贝*/
while (FR_OK == eRet)
{
if (FATFS_LinkDriver(&SNORDISK_Driver, acFlashPath) == 0)
{
eRet = f_read(&sLogFile, acCopyBuff, (UINT)sizeof(acCopyBuff), &dwReadedByteNum);
if (FR_OK != eRet || dwReadedByteNum == 0)
{
break;
}
}
else
{
break;
}
if (FATFS_LinkDriver(&USBH_Driver, acUSBPath) == 0)
{
eRet = f_write(&sOutFile, acCopyBuff, dwReadedByteNum, (void *)&dwWrittenByteNum);
if (FR_OK != eRet || dwWrittenByteNum < dwReadedByteNum)
{
break;
}
}
else
{
break;
}
}
/**< 关闭文件*/
eRet = f_close(&sOutFile);
eRet = f_close(&sLogFile);
}
/**< 拷贝完成取消U盘挂载*/
eRet = f_mount(NULL, acUSBPath, 0);
return eRet == FR_OK ? TRUE : FALSE;
}
修改后USB拷贝部分
/**
* @brief 拷贝一个日志文件
*
* @param [in] void
* @return 是否成功
* @retval
* @retval
*
* @see
* @note
* @warning
*/
static BOOLEAN bCopyOneLogFile(void)
{
UINT dwReadedByteNum = 0; /**< 实际读取字节*/
UINT dwWrittenByteNum = 0; /**< 实际写入字节*/
FRESULT eRet = FR_OK; /**< 便于调试,不要优化*/
BOOLEAN bRet = FALSE;
/**< 打开2个拷贝文件*/
eRet = f_open(&sLogFile, (TCHAR const *)pacCurLogFile, FA_OPEN_ALWAYS | FA_READ);
if (FR_OK != eRet)
{
return bRet;
}
eRet = f_open(&sOutFile, (TCHAR const *)pacCurOutFile, FA_OPEN_ALWAYS | FA_WRITE);
if (FR_OK != eRet)
{
eRet = f_close(&sLogFile);
return bRet;
}
/**< 进行拷贝*/
while (FR_OK == eRet)
{
eRet = f_read(&sLogFile, acCopyBuff, (UINT)sizeof(acCopyBuff), &dwReadedByteNum);
if (FR_OK != eRet)
{
break;
}
else if (FR_OK == eRet && dwReadedByteNum == 0)
{
// 说明拷贝完成了
bRet = TRUE;
break;
}
eRet = f_write(&sOutFile, acCopyBuff, dwReadedByteNum, (void *)&dwWrittenByteNum);
eRet = f_sync(&sLogFile);
if (FR_OK != eRet)
{
break;
}
else if (FR_OK == eRet && dwWrittenByteNum < dwReadedByteNum)
{
// 说明文件写不下了
bRet = TRUE;
break;
}
}
/**< 关闭文件*/
eRet = f_close(&sLogFile);
eRet = f_close(&sOutFile);
return bRet;
}
/**
* @brief 导出日志到U盘
*
* @param [in] void
* @return 拷贝日志结果
* @retval TRUE:成功
* @retval FALSE:失败
*
* @see
* @note
* @warning
*/
BOOLEAN LOG_bCopy2USB(void)
{
BOOLEAN bRet = FALSE;
FRESULT eRet = FR_OK; /**< 便于调试,不要优化*/
bRet = bCopyOneLogFile();
if (bRet)
{
vSwitchCurLogFile(); // 切换日志对象
// vTaskDelay(pdMS_TO_TICKS(10));
bRet = bCopyOneLogFile();
vSwitchCurLogFile(); // 还原日志对象
}
/**< 无论拷贝是否完成取消U盘挂载*/
eRet = f_mount(NULL, acUSBPath, 1);
FATFS_UnLinkDriver(acUSBPath);
return bRet && (FR_OK == eRet);
}