背景:项目中使用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()是动态增加存储,也就是说不是每次切换读写设备都要链接一次。而是系统增加磁盘时链接,拔出磁盘时断开链接。实现动态磁盘管理的目的。

  • 经过以下修改,完美运行

    1. 系统识别到NOR FLASH和U盘时,FATFS_LinkDriver(),并挂载
    2. 以后每次插入U盘 ,FATFS_LinkDriver(),并挂载。U盘拔出时FATFS_UnLinkDriver(acUSBPath);并且取消挂载

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);
}

Fatfs文件系统二次f_open返回值为FR_DISK_ERR的问题相关推荐

  1. 【软件开发底层知识修炼】二十五 ABI之函数调用约定二之函数返回值为结构体时的约定

    上一篇文章学习了几种函数调用约定的区别,点击链接查看上一篇文章:[软件开发底层知识修炼]二十四 ABI之函数调用约定 本篇文章继续学习函数调用约定中,关于函数返回值的问题.当函数返回值为结构体时,函数 ...

  2. 多维数组之二维数组传参、返回值、申请内存问题

    目录 多维数组 存储顺序 二维数组基础知识 数组名 下标 指向数组的指针 二维数组使用 初始化 作为函数参数的二维数组 二维数组返回值与申请内存问题 多维数组 如果某个数组的维数不止1个,它就被称为多 ...

  3. python怎么调用函数的返回值类型,10、Python基础之函数的调用与返回值

    一.函数参数 1.1 不定长参数 当我们定义函数时,可能需要定义一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数. 我们可以在形参前面加上一个 * ,这样这个形参就可以获取所有的实参,它将 ...

  4. java开启线程的方法_Java有几种方法开启线程?怎么实现带有返回值的线程?

    Java有几种方法开启线程?怎么实现带有返回值的线程? 发布时间:2020-05-22 11:20:08 来源:亿速云 阅读:238 作者:Leah Java有几种方法开启线程?怎么实现带有返回值的线 ...

  5. C++ 函数的引用返回值

    C++ 函数的引用返回值 2009-09-17 09:29 引用是给变量取一个别名,所以引用传递会直接进行变量本身的传递.它的最大好处是可以把别处对变量的改变保留下来,第二好处是它提高了性能:如果函数 ...

  6. java程序调用Oracle 存储过程 获取返回值(无返回,非结果集,结果集)

    oracle中procedure是不能有返回值的,要想返回值,就得有输出参数,同样要想返回记录集,可以把游标类型作为输出参数. 下面是详细情况说明: 一:无返回值的存储过程调用 存储过程: creat ...

  7. oracle java存储过程返回值_java程序调用Oracle 存储过程 获取返回值(无返回,非结果集,结果集)...

    java程序调用Oracle 存储过程 获取返回值(无返回,非结 果集,结果集) oracle中procedure是不能有返回值的,要想返回值,就得有 输出参数,同样要想返回记录集,可以把游标类型作为 ...

  8. html 下拉列表返回值,jquery 根据后台返回值来选中下拉框 option 值

    前景:下拉列表和要选中的下拉项都是通过后台传过来的本人用字符串拼接很low的方法实现: 一  给下拉框加一个默认的option 放在第一个类似于"无"或者"请选择&quo ...

  9. 【淘宝API开发系列】获得商品评论 API 返回值说明

    一.商品评价有什么好处? (1)根据统计,有93%的消费者是会看评价的,并且每一个消费者在阅读评价数量上基本上都是1-3条左右,最重要的是拼多多评价促使转化率提升50%! (2)影响买家购物决策:95 ...

最新文章

  1. 贪心:remove K digits移除K个数字
  2. sql server 2008数据导入Oracle方法
  3. 排序算法总结之堆排序
  4. 干掉 ZooKeeper?阿里为什么不用 ZK 做服务发现?
  5. oracle创建数据库后干什么,手动创建Oracle数据库之前因后果
  6. 【数据结构】队列之链队列
  7. {dede:list}和{dede:arclist}的区别
  8. C++ 学习之函数重载、基于const的重载
  9. 用学生编程记录预测学习成果,第二届计算机教育数据挖掘大赛, 赢取现金奖励+顶刊发表机会!...
  10. 品质创新,江铃控股携手华天软件CAPP系统决战SUV中高端市场
  11. fiddler证书 iphone_【详细】Mac使用Fiddler实现IPhone抓包(支持https)
  12. vs怎么生成html文件,vscode 快速生成html
  13. 用python实现搜索树_二叉搜索树的python实现
  14. Pareidolia — AI的艺术教学
  15. labview卸载重装工具(NI卸载工具)
  16. MATLAB-二次曲面
  17. linux的管理权限命令,Linux权限管理命令
  18. android_文件下载
  19. oracle open_cursors未关闭问题解决
  20. 多线程操作数据库时为了防止数据的增删改的混乱该在数据库层还是程序层面上进行同步?

热门文章

  1. 本地数据库IndexedDB - 学员管理系统之登录(一)
  2. 他是第一个到达学校的人英语_新视野英语unit1-unit6翻译答案(中英对照)
  3. 本科生计算机网络期末复习笔记整理
  4. 那些三十几岁还转行的人,到底是怎么想的?
  5. matlab 绘制椭圆锥波束指向示意图
  6. 计算机为什么无法显示待机,电脑待机久了,屏幕不显示了,怎么重新启动也不管用...
  7. c++ float精度丢失
  8. waitpid最后以一个参数设为0_waitpid
  9. Linux wait()/waitpid()
  10. 网络违法信息巡查上报系统