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

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

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

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

重试修改后编译报错,主要因为_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重新生成工程都要删除一次,但至少不用担心自己修改的代码被覆盖

 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
声明:该设计资料来自啊德Blog文章,希望给需要的朋友带来帮助。 一、序言 经常在网上、群里看到很多人问关于STM32FATFS文件系统移植的问题,刚好自己最近也在调试这个程序,为了让大家少走弯路,我把我的调试过程和方法也贡献给大家。 二、FATFS简介 FatFs Module是一种完全免费开源的FAT文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C语言编写,所以具有良好的硬件平台独立性,可以移植到8051、PIC、AVR、SH、Z80、H8、ARM等系列单片机上而只需做简单的修改。它支持FATl2、FATl6和FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对8位单片机和16位单片机做了优化。 三、移植准备 1、FATFS源代码的获取,可以到官网下载:https://elm-chan.org/fsw/ff/00index_e.html最新版本是R0.09版本,我们就移植这个版本的。 2、解压文件会得到两个文件夹,一个是doc文件夹,这里是FATFS的一些使用文档和说明,以后在文件编程的时候可以查看该文档。另一个是src文件夹,里面就是我们所要的源文件。 3、建立一个STM32的工程,为方便调试,我们应重载printf()底层函数实现串口打印输出。可以参考已经建立好的printf()打印输出工程:https://www.viewtool.com/bbs/foru ... d=77&extra=page=1(或者“相关附件”下载) 四、开始移植 在已经建立好的工程目录User文件夹下新建两个文件夹,FATFS_V0.09和SPI_SD_Card,FATFS_V0.09用于存放FATFS文件,SPI_SD_Card用于存放SPI的驱动文件。 将ff.c添加到工程文件夹中,并新建diskio.c文件,在diskio.c文件中实现五个函数: DSTATUS disk_initialize (BYTE);//SD卡的初始化 DSTATUS disk_status (BYTE);//获取SD卡的状态,这里可以不用管 DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//从SD卡读取数据 DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//将数据写入SD卡,若该文件系统为只读文件系统则不用实现该函数 DRESULT disk_ioctl (BYTE, BYTE, void*);//获取SD卡文件系统相关信息 如截图: FATFS初始化函数: FATFS状态获取函数: FATFS底层读数据函数: 注意:更多相关代码下载,见“相关附件”下载

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值