将使用 f_mount 创建的工作空间传递给另一个源文件

Posted

技术标签:

【中文标题】将使用 f_mount 创建的工作空间传递给另一个源文件【英文标题】:Passing the workspace created with f_mount to another source file 【发布时间】:2019-08-19 20:26:57 【问题描述】:

我正在尝试在 RTOS 中使用 FATFS 读取 SD 卡上的文件。该卡成功安装在 RTOS 中的单独源文件中,但是当我尝试在自己的源文件中使用 FatFs 操作时,我得到结果 FR_NOT_ENABLED。

这是一个有点奇怪的场景,需要一些背景知识:我是一名电子技术学生,承担了重新利用 MCU 及其专有 RTOS 的艰巨任务。在 RTOS 中,已经有一个安装 SD 卡的源文件(我们称之为 sd.cpp)和另一个将传感器数据文件写入其中的文件(我们称之为 Sensors.cpp)。我确保在我的源文件中包含所有相关的头文件(为了清楚起见,我们称之为 myfile.cpp)。

我尝试了一些方法:第一个是直接在 myfile.cpp 中实现 f_mount 操作。这导致了 FR_DISK_ERR 结果,我理解这是因为它已经安装在另一个文件中,所以这显然是不可行的。从那里我尝试在 Sensors.cpp 中注释掉 SD 卡的所有实例,但这会打开一个真正的“蠕虫罐”,我宁愿保存它,直到用尽其他选项...

我相信归根结底是弄清楚如何将 SD 工作区从 sd.cpp 传递到 myfile.cpp。我试图研究 Sensors.cpp 以了解它是如何在那里完成的,但不幸的是,它的内容远远超出了我作为电子技术学生的理解范围。

这是一个使用 GNU-ARM 工具链和 OpenOCD 构建工具的 STM32L476RG。

代码都是非常标准的 FATFS 东西。 SD.cpp中的SD挂载函数:

FATFS fs;
bool isMounted = false;

FRESULT fsMountSd()
    FRESULT res = f_mount(&fs, "0:", 1);
    if( res == FR_OK) isMounted = true;
    if (isMounted = true)
    CLI_printMessage("SD Card mounted");
    
    return res;

这将返回 FR_OK 并在 CLI 中打印“SD Card Mounted”。

然后在myfile.cpp中有我自己的FatFs操作:

FIL config; //file object of  from the SD card


FRESULT fr;
FILINFO fno;

//check for config.txt file
fr = f_stat("0:config.txt", &fno);    //check for config.txt file

if (fr == FR_OK)
      CLI_printMessage("File found!");

这在我在 sd.cpp 模块中运行 f_stat 操作时有效,确认这是在 myfile.cpp 中找不到文件系统对象的问题。

我也尝试过在 sd.cpp 挂载函数中使用指针:

FATFS *fs;

bool isMounted = false;

FRESULT fsMountSd()
    FRESULT res = f_mount(fs, "0:", 1);
    if( res == FR_OK) isMounted = true;
    if (isMounted = true)
    CLI_printMessage("SD Card mounted");
    
    return res;

当我尝试这样做时,我还添加了“extern FATFS* fs;”行到 sd.h 文件。不幸的是,这也没有成功。

值得补充的是,我已经阅读了有关信息丰富的 Fatfs support page 的所有文档。

简而言之:我希望从 myfile.cpp 中的 f_stat(检查文件)中获得 FR_OK,以便继续前进。我希望这足够详细,因为我最后一次在这里提出这个问题的尝试很快(并且可以理解)被否决了!

【问题讨论】:

我想补充一点,当我在与 f_mount 操作 (sd.cpp) 相同的文件中运行 f_stat 操作时,我已经确认它可以正常工作。我还可以在 myfile.cpp 中创建一个成功指向工作区地址的变量,它只是不知道该地址是工作区。 FATFS *fs; 肯定是不正确的 - fs 必须是一个实例,指向它的指针由 ELM FatFs 库内部保存 - 它不需要是 extern 甚至是全局的;它只需要是static 并且可以是fsMountSd 的本地地址。如果文件系统已经挂载,则不应再次挂载它。您应该检查isMounted 在调用f_mount() 之前,并且没有其他代码应该挂载文件系统——当然也不能使用不同的FATFS 对象。如果您有多个 FATFS 对象用于同一个卷,并同时挂载这两个对象,那么这可能是您的问题 - 目前尚不清楚。 你使用的是什么实时操作系统? 非常感谢您的回复。 RTOS 是专为管道分析而开发的专有系统,可用于海洋数据采集。我真的不能提供更多的细节! 所以也许不是真正的 RTOS 问题。 ELM FatFs 库具有线程安全存根,您需要使用 RTOS 的静音函数来实现这些存根。已经完成了吗? 【参考方案1】:

您的 RTOS 似乎正在使用完整记录的 ELM FatFs here。

卡成功挂载在 RTOS 中的单独源文件中, 但是当我尝试在自己的源文件中使用 FatFs 操作时,我 得到结果 FR_NOT_ENABLED。 [...] 在 RTOS 中,已经有一个挂载 SD 卡的源文件

如果您的意思是文件系统已经挂载,并且您正在第二次挂载它,那么这是不必要的,并且如果它挂载相同的卷可能会导致错误。该库为每个卷保存一个指向提供的 FATFS 实例的指针,当第一个正在使用时,您不应将其传递给不同的实例。也就是说,我认为应该对其进行检查,所以可能不是这里的问题。

不需要将 FATFS 对象设为全局或外部;它只需要在文件系统操作继续时存在。最好在fsMountSd() 中设置为static,例如:

FRESULT fsMountSd()

    static FATFS fs;
    static bool isMounted = false;
    FRESULT res = FR_OK ;

    if( !isMounted )
    
        res = f_mount(&fs, "0:", 1);
        isMounted = (res == FR_OK) ;
    

    if( isMounted )
    
        CLI_printMessage("SD Card mounted");
    

    return res;

我也尝试了路径名的每个配置:“config.txt”, “0:config.txt”、“0:\config.txt”、“0:/config.txt”等

如果你只有一卷,那么你可以使用:

    res = f_mount(&fs, "", 1);

挂载默认(仅)卷。

如果您想显式卸载并重新安装,则可以通过将 NULL 传递给 f_mount

    if( isMounted )
    
        f_mount( NULL, "", 1);
    

    res = f_mount(&fs, "", 1);
    isMounted = (res == FR_OK) ;

但这可能会导致其他线程在访问文件系统时出现问题,如果它们当时打开了文件。

[...] 也许有人可以让我知道如何在我自己的函数中调用该指针。

我不确定您所说的“调用该指针”是什么意思,指向 FATFS 实例的指针由库内部保存。它不需要“传递”或对其他模块可见。

【讨论】:

那么,您的意思是,当您使用 f_mount 创建文件系统对象时,它应该默认与其他源文件一起使用?这基本上是我的问题的范围......我的源文件不理解文件系统对象是什么。 @Zurn 我真正想说的是问题不是您认为的那样,因此您的问题没有提供诊断所需的信息。您发布的代码没有什么问题,但您引用了其他未显示的代码。导致问题的可能是这些操作的交互和/或顺序。在任何情况下,首先不要安装卷两次。如果挂载卷的代码的两个部分都使用上面建议的函数,那么它将是安全的。他们不应该都直接调用 f_mount.. 在我使用 FatFs 的地方,我有一个轮询卡检测的任务,并自动安装和卸载卷。那么你就不必在其他地方担心了。代码既可以查询挂载任务判断卷是否就绪,也可以处理打开/读/写操作的错误返回。 再次感谢您回复我。为模棱两可道歉......我想我已经在我的原始帖子中明确表示我已经排除了安装卡两次的可能性。我同意,如果在将文件系统对象安装在不同的源文件中时不需要重新声明文件系统对象,那么我认为这归结为操作顺序的问题。周一我回到实验室时,我将对此进行试验。我的问题是:您的任务是在它自己的源文件中轮询卡片检测还是在其中调用其他 FatFs 操作? @Zurn 完全独立。只要您的 FATFS 对象不在线程本地存储中,和/或您的 RTOS 不使用 MMU 来隐藏任务上下文之间的数据,那么您应该很好。使用调试器,进入 FatFs 调用,看看它在阻止什么。并在 f_mount 和失败的调用上放置一个断点,以确保它们以正确的顺序调用。

以上是关于将使用 f_mount 创建的工作空间传递给另一个源文件的主要内容,如果未能解决你的问题,请参考以下文章

fatfs源码阅读

将 MODEL_id 传递给另一个模型参数

Swift UI 将绑定传递给另一个视图以通过 init 发出警报

将列表视图选定的文本传递给另一个活动

将变量传递给另一个 JAVA 类中的主函数

API 密钥和秘密密钥如何工作?如果我必须将我的 API 和密钥传递给另一个应用程序,它会安全吗?