【STM32】FatFs文件系统多线程支持实现:同时读写多个文件基于FreeRTOS实战指南
问题描述
正常来说,FATFS在读写单个文件是没问题的,但是有时候需要开两个以上线程,同时打开两个以上文件,并同时进行读写操作,实测如果不开启FATFS的多线程支持,直接在每个线程打开文件并写入,会有出错或者出现只有一个线程的文件能写入的问题,这样就需要开启FATFS自带的多线程支持功能了。
解决办法
FATFS的多任务支持其实就是一个互斥锁管理(信号量会有优先级反转)
以freertos,fatfsR0.14b为例
1.
ffconf.h修改以下下配置
/* #include <somertos.h> // O/S definitions */
#include "FreeRTOS.h"
#include "semphr.h"
#define FF_FS_REENTRANT 1
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t SemaphoreHandle_t
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The FF_SYNC_t defines O/S depe
注意#define FF_SYNC_t SemaphoreHandle_t
中的SemaphoreHandle_t
原本是HANDLE
,要把它改成自己所用操作系统对应互斥信号量的同步处理声明。
2.
修改ffsystem.c(注意老版的改syscall.c),添加或者在原程序修改为以下接口函数,把相应用到的操作系统相关的解开注释就行。
#if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
BYTE vol, /* Corresponding volume (logical drive number) */
FF_SYNC_t* sobj /* Pointer to return the created sync object */
)
{
// /* Win32 */
// *sobj = CreateMutex(NULL, FALSE, NULL);
// return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */
// T_CSEM csem = {TA_TPRI,1,1};
// *sobj = acre_sem(&csem);
// return (int)(*sobj > 0);
/* uC/OS-III */
// OS_ERR err;
//
// OSMutexCreate ((OS_MUTEX*) sobj,
// (CPU_CHAR*) "FATFS Mutex",
// (OS_ERR*) &err);
// //return (int)(err == OS_ERR_NONE );
// return 1;
/* FreeRTOS */
*sobj = xSemaphoreCreateMutex();
return (int)(*sobj != NULL);
/* CMSIS-RTOS */
// *sobj = osMutexCreate(Mutex + vol);
// return (int)(*sobj != NULL);
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
// /* Win32 */
// return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-III */
// OS_ERR err;
// OSMutexDel(&sobj, OS_OPT_DEL_ALWAYS, &err);
// return (int)(err == OS_ERR_NONE );
/* FreeRTOS */
vSemaphoreDelete(sobj);
return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
// /* Win32 */
// return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-III */
// OS_ERR err;
// OSMutexPend(&sobj,FF_FS_TIMEOUT, OS_OPT_PEND_BLOCKING,0, &err);
// return (int)(err == OS_ERR_NONE );
/* FreeRTOS */
return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
// /* Win32 */
// ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-III */
// OS_ERR err;
// OSMutexPost ((OS_MUTEX*) &sobj,
// (OS_OPT) OS_OPT_POST_NONE, //2??′DDì?êa2ù×÷£??′2????1μ÷?è
// (OS_ERR*) &err);
/* FreeRTOS */
xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif
结语
现在,就可以快乐地同时打开多个文件读写了。
参考文章
1.FATFS添加多线程支持
作者:ℳ๓. Sweet