Fopen not opening/creating files on SD card

22 Mar 2018

Hi,

So I am trying to create an unexisting text file in my SD card and I am unable to fopen my path or file. I am using this SD card breakout from sparkfun: https://www.sparkfun.com/products/12941

My init() function for the Blockdevice is successful.

I've tried to use the SDFileSystem library but apparently it isn't supported anymore: https://os.mbed.com/questions/77743/stm32f769NI-SDFileSystem-Error/

I'm using a microSD card adapter. I don't know if this may be causing the errors and I am using a mDot.

And I am following along this code: https://os.mbed.com/teams/University-of-Plymouth-Stage-2-and-3/code/ELEC350-SD_Card_Demo/file/528e42a15d44/main.cpp/

Thanks.

SDCardTest

#include <mbed.h>
#include "SDBlockDevice.h"
#include "FATFileSystem.h"

SDBlockDevice sd(D11, D12, D13, D10); // mosi, miso, sclk, cs
FATFileSystem fs("sd"); 

static uint8_t network_address[] = { 0x00, 0x11, 0x22, 0x33 };
static uint8_t network_session_key[] = { 0x00, 0x11, 0x22, 0x33, 0x00, 0x11, 0x22, 0x33, 0x00, 0x11, 0x22, 0x33, 0x00, 0x11, 0x22, 0x33 };
static uint8_t data_session_key[] = { 0x33, 0x22, 0x11, 0x00, 0x33, 0x22, 0x11, 0x00, 0x33, 0x22, 0x11, 0x00, 0x33, 0x22, 0x11, 0x00 };

mDot* dot = NULL;
lora::ChannelPlan* plan = NULL;

Serial pc(USBTX, USBRX);

/*
 *  Variables used for mDot
 */


uint32_t tx_frequency;
uint8_t tx_datarate;
uint8_t tx_power;
uint8_t frequency_band;

void return_error(int ret_val){
  if (ret_val)
    printf("Failure. %d\r\n", ret_val);
  else
    printf("done.\r\n");
}

void errno_error(void* ret_val){
  if (ret_val == NULL)
    printf(" Failure. %d \r\n", ret_val);
  else
    printf(" done.\r\n");
}

int main(void)
{
    // Custom event handler for automatically displaying RX data
    //interruptEverything.attach(&interruptReadTemperature, 7.0);
    RadioEvent events;
    // Change baud rate in serial terminal to this value
    pc.baud(115200);

    FILE *fp;
    
    mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
    
    plan = new lora::ChannelPlan_US915();

    logInfo("Now asserting");
    assert(plan);

    dot = mDot::getInstance(plan);
    assert(dot);

    logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);

    // start from a well-known state
    logInfo("defaulting Dot configuration");
    dot->resetConfig();

    // make sure library logging is turned on
    dot->setLogLevel(mts::MTSLog::INFO_LEVEL);

    // attach the custom events handler
    dot->setEvents(&events);

    // update configuration if necessary
    if (dot->getJoinMode() != mDot::PEER_TO_PEER) {
        logInfo("changing network join mode to PEER_TO_PEER");
        if (dot->setJoinMode(mDot::PEER_TO_PEER) != mDot::MDOT_OK) {
            logError("failed to set network join mode to PEER_TO_PEER");
        }
    }
   
    frequency_band = dot->getFrequencyBand();
    switch (frequency_band) {
        case lora::ChannelPlan::EU868_OLD:
        case lora::ChannelPlan::EU868:
            // 250kHz channels achieve higher throughput
            // DR_6 : SF7 @ 250kHz
            // DR_0 - DR_5 (125kHz channels) available but much slower
            tx_frequency = 869850000;
            tx_datarate = lora::DR_6;
            // the 869850000 frequency is 100% duty cycle if the total power is under 7 dBm - tx power 4 + antenna gain 3 = 7
            tx_power = 4;
            break;

        case lora::ChannelPlan::US915_OLD:
        case lora::ChannelPlan::US915:
        case lora::ChannelPlan::AU915_OLD:
        case lora::ChannelPlan::AU915:
            // 500kHz channels achieve highest throughput
            // DR_8 : SF12 @ 500kHz
            // DR_9 : SF11 @ 500kHz
            // DR_10 : SF10 @ 500kHz
            // DR_11 : SF9 @ 500kHz
            // DR_12 : SF8 @ 500kHz
            // DR_13 : SF7 @ 500kHz
            // DR_0 - DR_3 (125kHz channels) available but much slower
            tx_frequency = 915500000;
            tx_datarate = lora::DR_13;
            // 915 bands have no duty cycle restrictions, set tx power to max
            tx_power = 20;
            break;

        case lora::ChannelPlan::AS923:
        case lora::ChannelPlan::AS923_JAPAN:
            // 250kHz channels achieve higher throughput
            // DR_6 : SF7 @ 250kHz
            // DR_0 - DR_5 (125kHz channels) available but much slower
            tx_frequency = 924800000;
            tx_datarate = lora::DR_6;
            tx_power = 16;
            break;

        case lora::ChannelPlan::KR920:
            // DR_5 : SF7 @ 125kHz
            tx_frequency = 922700000;
            tx_datarate = lora::DR_5;
            tx_power = 14;
            break;

        default:
            while (true) {
                logFatal("no known channel plan in use - extra configuration is needed!");
                wait(5);
            }
            break;
    }


    // in PEER_TO_PEER mode there is no join request/response transaction
    // as long as both Dots are configured correctly, they should be able to communicate
    update_peer_to_peer_config(network_address, network_session_key, data_session_key, tx_frequency, tx_datarate, tx_power);
    
    // save changes to configuration
    logInfo("saving configuration");
    if (!dot->saveConfig()) {
        logError("failed to save configuration");
    }
    // Display configuration
    // It's gonna output a lot of information onto the Serial Terminal
    display_config();
    
    //mkdir("/sd/mytest/", 0777);
	
    int error = 0;
	
    if ( 0 == sd.init()) {
        printf("Init success \n\r");
    }

    fs.mount(&sd);
    // Check if file was opened for some reason
    if(fp != NULL)
    {
        pc.printf("File was opened, closing it\n\r");
        fclose(fp);
    }
    
    fp = fopen("/sd/mytest/sdtest.txt", "w");
    if(fp == NULL) {
        pc.printf("Could not open file for write\n\r");
    }
    fprintf(fp, "Hello fun SD Card World!");
    
    for (int i = 0; i < 20; i++){
    printf("Writing decimal numbers to a file (%d/20)\r\n", i);
    fprintf(fp, "%d\r\n", i);
    }
    
    pc.printf("Writing decimal numbers to a file (20/20) done.\r\n");

    pc.printf("Closing file.\n\r");
    fclose(fp); 
    
    
    
    return 0;
}


22 Mar 2018

Hello Denwis,

Try to modify your code as below:

...

//    fs.mount(&sd);
//    // Check if file was opened for some reason
//    if(fp != NULL)
//    {
//        pc.printf("File was opened, closing it\n\r");
//        fclose(fp);
//    }
    
//    fp = fopen("/sd/mytest/sdtest.txt", "w");
//    if(fp == NULL) {
//        pc.printf("Could not open file for write\n\r");
//    }
//    fprintf(fp, "Hello fun SD Card World!");
    
//    for (int i = 0; i < 20; i++){
//    printf("Writing decimal numbers to a file (%d/20)\r\n", i);
//    fprintf(fp, "%d\r\n", i);
//    }
    
//    pc.printf("Writing decimal numbers to a file (20/20) done.\r\n");
    
//    pc.printf("Closing file.\n\r");
//    fclose(fp);

//    return 0;
    
    int err = fs.mount(&sd);
    pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
    if (err)
        return err;

    // Open the file.
    pc.printf("Opening file '/sd/mytest/sdtest.txt'... ");

    fp = fopen("/sd/mytest/sdtest.txt", "w+");
    pc.printf("%s\r\n", (!fp ? "Failed :(\r\n" : "OK\r\n"));

    if (!fp)
    {
        // Check whether directory '/sd/mytest' exists.
        pc.printf("\r\nChecking directory '/sd/mytest'...\r\n");
        struct stat info;
        err = stat("/sd/mytest", &info);
        if (err)
        {
            pc.printf("Directory '/sd/mytest' does not exist.\r\n");
            pc.printf("Trying to create it...");
            err = mkdir("/sd/mytest", 0777);
            pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
            if (err)
              return err;
        }
                
        // Create a new 'sdtest.txt' file.
        pc.printf("File not found, creating a new one...\r\n");
        fp = fopen("/sd/mytest/sdtest.txt", "w+");
        pc.printf("%s\r\n", (!fp ? "Failed :(" : "OK"));
        if (!fp)
        {
            error("error: %s (%d)\r\n", strerror(errno), -errno);
            return errno;
        }
    }
    
    for (int i = 0; i < 10; i++)
    {
        pc.printf("Writing numbers (%d/%d)... ", i, 10);
        err = fprintf(fp, "    %d\r\n", i);
        if (err < 0)
        {
            pc.printf("Fail :(\r\n");
            error("error: %s (%d)\r\n", strerror(errno), -errno);
        }
        else
            pc.printf("OK\r\n");
    }

    pc.printf("Writing numbers (%d/%d)... OK\r\n\r\n", 10, 10);
    
    err = fclose(fp);
    pc.printf("Closing file '/sd/mytest/sdtest.txt'... ");
    pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
    if (err)
      return err;

    return 0;

  • Before using it remember to format your SD card for the FAT file system for example with the SD Formatter utility.
  • To test the code above I have connected an SD card to my mbed board according to this schematic and it worked fine.
24 Mar 2018

Thanks for your input,

I get errors saying " Error: Incomplete type is not allowed "struct stat info;"" " Error: Incomplete type is not allowed "err = stat("/sd/mytest", &info);"" Am I missing a library for stat?

If it helps, I am using mbed os version 5.5.7 for mDot uses.

I double checked my SD card and it is in FAT32 format. I formatted it again just in case.

This is what I'm following for my SD card breakout board

/media/uploads/SDesign2018/full_sd_with_5v_bb.jpg

MOSI - 11 - Green, MISO - 12 - Red, CLK - 13 - Yellow, CS - 8 - Blue

24 Mar 2018

I have tested the code with mbed-os- 5.7.7:

  • The data type struct stat and function int stat(const char *path, struct stat *st) are declared in the platform/mbed-retarget.h file of the mbed-os library.
  • The int stat(const char *path, struct stat *st) function is defined in platform/mbed-retarget.cpp file of the mbed-os library.

Unfortunately it seems that older versions do not include stat support. In such case I would recommend to either create the /sdtest directory in advance on a PC or to simply use the SD card root directory instead of the /sdtest one.

There is mismatch between the code and wiring:

  • The CS signal supposed to be connected to pin D10

SDBlockDevice sd(D11, D12, D13, D10); // mosi, miso, sclk, cs
  • However, on the picture above it is connected to pin D8.
25 Mar 2018

Ok I've created my own struct stat as shown below.

Now the problem is that mount() never exits.

I have my signals at the correct pins. Sorry it wasn't clear that the signals I gave were to show which wires came from which pin on the arduino, which I used as a guide to how I should wire my SD card breakout board.

EDIT: Nevermind, it does exit mount() and outputs "Failed :(" after a very long time but it doesn't go anywhere else after. Added the sd card code you provided.

stat

#include "platform/FilePath.h"

// For struct stat
typedef unsigned int  dev_t;    ///< Device ID type
typedef unsigned long ino_t;    ///< File serial number
typedef unsigned int  nlink_t;  ///< Number of links to a file
typedef unsigned int  uid_t;    ///< User ID
typedef unsigned int  gid_t;    ///< Group ID
typedef signed   long off_t;    ///< Offset in a data stream

struct mbed::stat {
    dev_t     st_dev;     ///< Device ID containing file
    ino_t     st_ino;     ///< File serial number
    mode_t    st_mode;    ///< Mode of file
    nlink_t   st_nlink;   ///< Number of links to file
 
    uid_t     st_uid;     ///< User ID
    gid_t     st_gid;     ///< Group ID
 
    off_t     st_size;    ///< Size of file in bytes
 
    time_t    st_atime;   ///< Time of last access
    time_t    st_mtime;   ///< Time of last data modification
    time_t    st_ctime;   ///< Time of last status change
};

int mystat(const char *path, struct stat *st) {
    FilePath fp(path);
    FileSystemHandle *fs = fp.fileSystem();
    if (fs == NULL) {
        errno = ENODEV;
        return -1;
    }

    int err = fs->stat(fp.fileName(), st);
    if (err < 0) {
        errno = -err;
        return -1;
    } else {
        return 0;
    }
}

sdCardTest

int err = fs.mount(&sd);
    pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
    if (err)
        return err;
    pc.printf("Error for mounting was %d\n\r", err);
    // Open the file.
    pc.printf("Opening file '/sd/mytest/sdtest.txt'... ");
 
    fp = fopen("/sd/mytest/sdtest.txt", "w+");
    pc.printf("%s\r\n", (!fp ? "Failed :(\r\n" : "OK\r\n"));
 
    if (!fp)
    {
        // Check whether directory '/sd/mytest' exists.
        pc.printf("\r\nChecking directory '/sd/mytest'...\r\n");
        struct stat info;
        err = mystat("/sd/mytest", &info);
        if (err)
        {
            pc.printf("Directory '/sd/mytest' does not exist.\r\n");
            pc.printf("Trying to create it...");
            err = mkdir("/sd/mytest", 0777);
            pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
            if (err)
              return err;
        }
                
        // Create a new 'sdtest.txt' file.
        pc.printf("File not found, creating a new one...\r\n");
        fp = fopen("/sd/mytest/sdtest.txt", "w+");
        pc.printf("%s\r\n", (!fp ? "Failed :(" : "OK"));
        if (!fp)
        {
            error("error: %s (%d)\r\n", strerror(errno), -errno);
            return errno;
        }
    }
    
    for (int i = 0; i < 10; i++)
    {
        pc.printf("Writing numbers (%d/%d)... ", i, 10);
        err = fprintf(fp, "    %d\r\n", i);
        if (err < 0)
        {
            pc.printf("Fail :(\r\n");
            error("error: %s (%d)\r\n", strerror(errno), -errno);
        }
        else
            pc.printf("OK\r\n");
    }
 
    pc.printf("Writing numbers (%d/%d)... OK\r\n\r\n", 10, 10);
    
    err = fclose(fp);
    pc.printf("Closing file '/sd/mytest/sdtest.txt'... ");
    pc.printf("%s\r\n", (err ? "Failed :(\r\n" : "OK\r\n"));
    if (err)
      return err;
 
    return 0;

25 Mar 2018

The reason why mount fails could be that the lowest SPI frequency of your mbed board is higher than 100 kHz, so the SD card is not getting initialized properly.
See https://os.mbed.com/forum/bugs-suggestions/topic/27511/

25 Mar 2018

According to the sd-driver library, the most current version, sd-driver-0.1.2, uses mbed-os-5.6.1, and I am now using mbed-os-5.7.4 which the current mdot-3.1.0 uses. This now allows me to use struct stat without problems.

According to that bug topic, I've tried to look for what my board's minimum frequency is and I am having trouble looking for it. I've looked at targets/TARGET_STM/TARGET_STM32F4/spi_api.c and it has a function to get spi frequency, so I think I can pass a SPI object to it to find my minimum frequency. My device is actually 96MHz according to this information: https://os.mbed.com/platforms/MTS-mDot-F411/ but I can't find what the lowesit SPI frequency is.

I also found this topic: https://os.mbed.com/teams/ST/wiki/SPI-output-clock-frequency and I think that it might help me figure out what I should change the default frequency to, but I am confused as to find which SPI_1 or SPI_2.....and from there I am lost.

02 Apr 2018

Everything works now. I think it was the microSD card to SD card adapter that was the problem. I got a new SD card which is a SanDisk 8GB SDHC card, and it worked perfectly once I put it in the breakout board.

No need to change the default spi frequency in the sd-driver library.

Using mbed version 5.7.4.

12 Apr 2018

Hello I'm back.

So sd card is not working again. It is very inconsistent as I've tried 2 different FAT32 formatted sd cards.

This was my process:

I wired the breakout board to an arduino with the same wiring schematics as I've posted before. I tried 6 different sd cards to see which ones were being read correctly. I formatted the cards and 2 were showing files and folders consistently 10/10 tries so I thought they would work when I wire the breakout board to my mDot.

I wire the sd card reader breakout board to my mDot and upload my mbed code to it and it worked initializing, mounting, and creating directory and file. Great. Then I reset my mDot and it initializes and mounts successfully and tries to open the newly created file, but it then just freezes there. I reset again, and it does the same thing.

I then decide to delete the created folder from my PC and put the sd card back to the sd card reader breakout board. This time, it freezes in the initializing stage. I tried again with my other SD card that worked when trying on arduino and it did the same thing, freezes in initializing line.

I wire the breakout board to the arduino again and it reads everything consistently. I don't think it's the breakout board, or the breadbaord, or the wiring. I also tried to use the sd-driver-hs version but that doesn't work either.

I've tried to use SDFileSystem that some people have changed and they don't work. At this point, could it be my mDot? Maybe the high frequency with SPI. Mind you I am using the online compiler. I tried to import ARM's sd-driver 1.2 from github to the online compiler and still same results. I've been using the sd-driver library that is available from the online compiler import function.

13 Apr 2018

I do not use mDot so I'm not able to verify whether it could interfere with the sd-driver. Just a few tips:

  • I was recently struggling with a faulty SD card slot too. So I think it's a good idea to test also the slot with Arduino before using it in mbed application.
  • Make sure that each file in your code was closed before removing the SD card from a slot.
  • Try to simplify your program as much as possible to see which part could cause the problem.