0

I'm trying to read a file on an SD card using FATFS in an RTOS. The card successfully mounts in a separate source file in the RTOS, but when I try to use the FatFs operations in my own source file, I get the result FR_NOT_ENABLED.

This is a somewhat strange scenario that requires some context: I am an electronics technician student who has taken on the rather daunting task of re-purposing an MCU and its proprietary RTOS. Within the RTOS, there is already a source file that mounts the SD card (let's call it sd.cpp) and another file (let's call it Sensors.cpp) that writes sensor data files to it. I've made sure to include all relevant header files in my source file (which, for clarity's sake, let's call myfile.cpp).

I've tried a few things: the first was implementing the f_mount operation directly in myfile.cpp. This caused the FR_DISK_ERR result, which I understand is due to the fact that it's already mounted in another file, so that's obviously out of the picture. From there I tried commenting out all instances of the SD card in the Sensors.cpp, but this opens up a real "can of worms" that I'd rather save until other options are exhausted...

I believe what it comes down to is figuring out how to pass the SD workspace from sd.cpp to myfile.cpp. I've tried to study Sensors.cpp to understand how it is done there, but unfortunately its contents is far beyond my comprehension as a mere electronics technician student.

This is an STM32L476RG using the GNU-ARM tool chain and OpenOCD build tools.

Code is all pretty standard FATFS stuff. The SD mount function in the 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;
}

This returns FR_OK and prints "SD Card mounted" to the CLI.

Then there's my own FatFs operations in the myfile.cpp:

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

This works when I run the f_stat operation in the sd.cpp module, confirming that it's an issue of not finding the file system object in the myfile.cpp.

I've also tried utilizing pointers in the sd.cpp mount function:

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

When I tried this I also added the line "extern FATFS* fs;" to the sd.h file. Unfortunately this was also unsuccessful.

Worth adding that I've read over all documentation on the highly informative Fatfs support page.

So in short: I'm hoping to get FR_OK from this f_stat (checking for the file) in myfile.cpp so I can move on. I hope this was detailed enough, as my last attempt at asking this question on here was very quickly (and understandably) down voted!

Zurn
  • 33
  • 5
  • I'd like to add that I've confirmed the f_stat operation works fine when I run it in the same file as the f_mount operation (sd.cpp). I can also create a variable that successfully points to the workspace address in myfile.cpp, it just doesn't know that that address is the workspace. – Zurn Mar 29 '19 at 19:35
  • `FATFS *fs;` is certainly incorrect - `fs` must be an instance, a pointer to it is held internally by the ELM FatFs library - it does not need to be `extern` or even global; it simply needs to be `static` and can be local to `fsMountSd`. If the filesystem is already mounted, you should not mount it again. You should check `isMounted` _before_ calling `f_mount()`, and no other code should mount the file system - and certainly not using a different FATFS object. If you have more that one FATFS object for the same volume, and mount both then that may be your problem - it is not clear. – Clifford Mar 29 '19 at 23:43
  • What RTOS are you using? – Clifford Mar 29 '19 at 23:57
  • Thanks a lot for the response. The RTOS is a specially developed proprietary system made for pipeline analysis that's being repurposed for ocean data acquisition. I can't really give more details than that! – Zurn Mar 30 '19 at 16:08
  • So not really an RTOS question perhaps. The ELM FatFs library has thread-safety stubs that you need to implement using your RTOS's muted functions. Has that been done? – Clifford Mar 30 '19 at 16:55

1 Answers1

0

Your RTOS appears to be using the ELM FatFs fully documented here.

The card successfully mounts in a separate source file in the RTOS, but when I try to use the FatFs operations in my own source file, I get the result FR_NOT_ENABLED. [...] Within the RTOS, there is already a source file that mounts the SD card

If you mean the file system is already mounted, and you are mounting it a second time, that is unnecessary and likely to cause errors if it mounts the same volume. The library holds a single pointer to the provided FATFS instance per volume, you should not pass it a different instance when the first is in use. That said I believe it should be checked, so may not be the issue here.

There is not need to make the FATFS object global, or extern; it simply needs to exist while filesystem operations continue. Better to make it static in fsMountSd(), for example:

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

I've also tried every configuration of the path name: "config.txt", "0:config.txt", "0:\config.txt", "0:/config.txt", etc.

If you only have one volume, then you can use:

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

to mount the default (only) volume.

If you want to explicitly dismount and remount, then that is done by passing NULL to f_mount:

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

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

but that may cause problems with other threads accessing the file system if they have files open at the time.

[...] maybe someone can let me know how to then call that pointer in my own function.

I am not sure what you mean by "call that pointer", the pointer to the FATFS instance is held internally by the library. It does not need to be "passed around" or visible to other modules.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • So, what you're saying is that when you create a file system object with f_mount it should work with other source files by default? This is basically the extent of my issue... that my source file doesn't understand what the file system object is. – Zurn Mar 30 '19 at 16:17
  • @Zurn what I am really saying is that the problem is not what you think it is, and consequently your question does not present the information necessary for a diagnosis. There is little wrong with the code you have posted, but you referred to other code not shown. It is possibly the interaction and/or order of these operations that is causing the problem. In any case, start by not mounting the volume twice. If both parts of the code that mount the volume use the function suggested above, then it will be safe from that. They should not both call f_mount directly.. – Clifford Mar 30 '19 at 17:05
  • Where I have used FatFs, I have a task that polls the card-detect, and mounts and dismounts the volume automatically. Then you need not worry about it elsewhere. Code can either query the mounting task to determine whether the volume is ready, or process the error return of open/read/write operations. – Clifford Mar 30 '19 at 17:12
  • again, thanks for getting back to me. Apologies for the ambiguity... I thought I'd made it clear in my original post that I'd already ruled out the prospect of mounting the card twice. I agree, if there's no need to re-declare the file system object in when its mounted in a different source file, then I think it comes down to an issue of the order of operations. I'll experiment with that when I'm back in the lab on Monday. My question for you is: is your task that polls the card-detect in it's own source file or the one in which you invoke the other FatFs operations? – Zurn Mar 30 '19 at 17:25
  • @Zurn Completely independent. So long as your FATFS object is not in thread-local storage, and/or your RTOS does not use the MMU to hide the data between task contexts, you should be good. Use a debugger, and step into the FatFs calls to see what it is baulking in. And place a break point on f_mount and the failing call to ensure they are called in the right order. – Clifford Mar 30 '19 at 17:31
  • very good to know! I have actually stepped through the code with breakpoints, and have clarified that, for example, that the FATFS variable I created in the myfile.cpp which points to the file system object does have the same address as the file system object in the sd.cpp file (where f_mount occurs). HOWEVER, I realize that doesn't rule out an order of operations issue - so I'll investigate that further on Monday. Thanks again! – Zurn Mar 30 '19 at 17:57
  • @Zurn If the volume is always present, so you need not monitor card-detect, then it is best to mount the volume in system initialisation, before the task scheduler runs. Early in main() for example. It the driver has OS dependencies and cannot work before scheduling starts, then use the zero option flag for f_mount. It will then mount on first use rather than explicitly accessing the device immediately. – Clifford Mar 30 '19 at 18:18