STM32 修改FatFs支持文件同时单写多读

最近使用SD卡,需要上传文件到手机,这个功能需要支持同一个文件同时打开一个写入和一个读取句柄,写入的同时能够读取文件内容上传,写入都是写入文件末尾,文件是一个以小时为单位建的,要想上传当前小时内的文件,就必须支持单写多读功能

STM32芯片使用的是STM32 F412系列,使用STM32CubeMX配置的Keil5工程,找了一下配置发现有个可重入的设置

STM32 修改FatFs支持文件同时单写多读_第1张图片

但是默认为Disabled,且只有Disabled可选,看了一下ffconf.h的代码,想直接在代码里修改为enable

STM32 修改FatFs支持文件同时单写多读_第2张图片

重试修改后编译报错,主要因为_SYNC_t配置为空了

接着配置了FreeRTOS,FS_REENTRANT被自动修改为enable了,一阵小兴奋,立刻创建了一个测试文件,写了测试代码,对test.txt文件同时打开一个写入句柄和一个读取句柄,都是返回一个打开成功,另一个就打开返回失败。

不知道是我理解错了还是需要额外的其他配置


直接配置不行,那就直接修改FatFs的源码

FatFs本身是默认支持同一个文件打开多个读取句柄的,但是打开一个写入后其他都会返回失败,或者打开读取后不关闭再打开写入也会返回失败,错误码为:FR_LOCKED,                /* (16) The operation is rejected according to the file sharing policy */

依照这个错误,查找对应的代码,修改为支持单写入多读取,需要修改两个函数

static
FRESULT chk_lock (	/* Check if the file can be accessed */
    DIR* dp,		/* Directory object pointing the file to be checked */
    int acc			/* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */
)
{
    UINT i, be;

    /* Search file semaphore table */
    for (i = be = 0; i < _FS_LOCK; i++) {
        if (Files[i].fs) {	/* Existing entry */
            if (Files[i].fs == dp->obj.fs &&	 	/* Check if the object matched with an open object */
                    Files[i].clu == dp->obj.sclust &&
                    Files[i].ofs == dp->dptr) break;
        } else {			/* Blank entry */
            be = 1;
        }
    }
    if (i == _FS_LOCK) {	/* The object is not opened */
        return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES;	/* Is there a blank entry for new object? */
    }

    /* The object has been opened. Reject any open against writing file and all write mode open */
    //return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
    // 修改为支持多次打开,只支持一个写入,多个读取
    if(acc == 0 || (Files[i].ctr & 0x100) == 0)
    {   // 不是写入或者不是不存在写入锁,直接返回OK
        return FR_OK;
    }
    if((Files[i].ctr & 0x100) && acc != 0)
    {   // 已经存在写入锁,禁止新写入锁
        return FR_LOCKED;
    }
    return FR_LOCKED;
}
static
UINT inc_lock (	/* Increment object open counter and returns its index (0:Internal error) */
    DIR* dp,	/* Directory object pointing the file to register or increment */
    int acc		/* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
)
{
    UINT i;


    for (i = 0; i < _FS_LOCK; i++) {	/* Find the object */
        if (Files[i].fs == dp->obj.fs &&
                Files[i].clu == dp->obj.sclust &&
                Files[i].ofs == dp->dptr) break;
    }

    if (i == _FS_LOCK) {				/* Not opened. Register it as new. */
        for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ;
        if (i == _FS_LOCK) return 0;	/* No free entry to register (int err) */
        Files[i].fs = dp->obj.fs;
        Files[i].clu = dp->obj.sclust;
        Files[i].ofs = dp->dptr;
        Files[i].ctr = 0;
    }

    //if (acc && Files[i].ctr) return 0;	/* Access violation (int err) */

    //Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1;	/* Set semaphore value */
    Files[i].ctr = acc ? (Files[i].ctr | 0x100) : Files[i].ctr + 1;	/* Set semaphore value *//*标志修改为支持一写多读标志*/

    return i + 1;
}

修改后就可以支持单写多读了

测试一个文件打开一个写入,两个读取的代码如下:

int8_t TestFileWriteRead(void)
{
    char szTestFileName[] = "test.txt";

    FIL fTestR;
    retSD = f_open(&fTestR, szTestFileName, FA_READ);
    if(FR_OK != retSD)
    {
        printf("read test:open file(%s) error : %d\r\n", szTestFileName, retSD);
        return -1;
    }

    FIL fTestW;
    retSD = f_open(&fTestW, szTestFileName, FA_WRITE | FA_OPEN_APPEND);
    if(FR_OK != retSD)
    {
        printf("write test:open file(%s) error : %d\r\n", szTestFileName, retSD);
        return -1;
    }
		
		FIL fTestR2;
    retSD = f_open(&fTestR2, szTestFileName, FA_READ);
    if(FR_OK != retSD)
    {
        printf("read2 test:open file(%s) error : %d\r\n", szTestFileName, retSD);
        return -1;
    }
		
	FIL fTestW2;
    retSD = f_open(&fTestW2, szTestFileName, FA_WRITE | FA_OPEN_APPEND);
    if(FR_OK != retSD)
    {// 这个会返回失败,因为已经打开一个写入
        printf("write2 test:open file(%s) error : %d\r\n", szTestFileName, retSD);
        //return -1;
    }

    {
        char bufRead[512];
        f_lseek(&fTestR, 100);
        UINT br = 0;
        retSD = f_read(&fTestR, bufRead, 500, &br);
        bufRead[br] = 0;
        printf("retSD:%d, read Data:%s\r\n", retSD, bufRead);
    }
    {
        char bufWrite[50] = "abcdefghijklmnopqrstuvwxyz";
        UINT bw = 0;
        retSD = f_write(&fTestW, bufWrite, 26, &bw);
        printf("retSD:%d, write Data(%d):%s\r\n", retSD, bw, bufWrite);
    }
    {
        char bufRead[512];
        f_lseek(&fTestR2, 10002);
        UINT br = 0;
        retSD = f_read(&fTestR2, bufRead, 500, &br);
        bufRead[br] = 0;
        printf("retSD:%d, read Data:%s\r\n", retSD, bufRead);
    }

    retSD = f_close(&fTestR);
	retSD = f_close(&fTestR2);
    retSD = f_close(&fTestW);

    return 0;
}

由于直接修改FatFs源码,会担心使用STM32CubeMX再次生成工程时覆盖了修改的代码,我的做法是直接复制了一个ff.c文件到工程目录中,然后新建一个分组,将ff.c文件加入这个分组,然后将Middlewares/FatFs分组的ff.c文件右键移除就可以了,虽然每次使用STM32CubeMX重新生成工程都要删除一次,但至少不用担心自己修改的代码被覆盖

STM32 修改FatFs支持文件同时单写多读_第3张图片

 

你可能感兴趣的:(Stm32)