This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/MSP432P401R: SDFatFS Driver from SimpleLink SDK not working properly

Part Number: MSP432P401R

Tool/software: TI-RTOS

Hello,

I have been using the SDFatFS driver shipped with the last version of SimpleLink SDK for MSP432P401R (simplelink_msp432p4_sdk_2_30_00_14). I have imported the example "fatsd_MSP_EXP432P401R_freertos_ccs" from TI Resource Explorer and modified it to write a large array buffer (16  kbytes), filled with a dummy pattern data (0xAA), to SD Card. I realized that the write speed performance is poor, and then, I have attached a Logic Probe to SPI lines and I discovered even writing a multiple integer of a data block size (512 bytes) the Driver provided by TI is issuing multiples CMD24 (SINGLE DATA BLOCK WRITE) instead of a single CMD25 (MULTIPLE DATA BLOCK WRITE). I looked at the source code provided by TI and I realized that multiple data block (CMD25) is implemented in the TI current driver, but not working for some reason. Is it a possible bug?

The writing of sixteen data blocks is depicted bellow

Zooming around the time that precedes the writing of one of data blocks, the CMD24 can be seen.

I attached the CCS project working out of the box, in order to reproduce the problem, but my code is shown bellow

#include <file.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* POSIX Header files */
#include <pthread.h>

#include <third_party/fatfs/ffcio.h>

#include <ti/display/Display.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/SDFatFS.h>

/* Example/Board Header files */
#include "Board.h"

/* Buffer size used for the file copy process */
#ifndef CPY_BUFF_SIZE
#define BUFF_SIZE       512*16
#endif

/* String conversion macro */
#define STR_(n)             #n
#define STR(n)              STR_(n)

/* Drive number used for FatFs */
#define SD_DRIVE_NUM           0

const char outputfile[] = "fat:"STR(SD_DRIVE_NUM)":data.dat";

static Display_Handle display;

/* Set this to the current UNIX time in seconds */
const struct timespec ts = {
    .tv_sec = 1469647026,
    .tv_nsec = 0
};

/* File name prefix for this filesystem for use with TI C RTS */
char fatfsPrefix[] = "fat";

unsigned char buff[BUFF_SIZE] __attribute__ ((aligned (4)));

/*
 *  ======== mainThread ========
 */
void *mainThread(void *arg0)
{
    SDFatFS_Handle sdfatfsHandle;

    /* Variables for the CIO functions */
    FILE *dst;

    /* Variables to keep track of the file copy progress */
    unsigned int bytesWritten = 0;

    /* Call driver init functions */
    GPIO_init();
    Display_init();
    SDFatFS_init();

    /* Configure the LED pin */
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);

    /* add_device() should be called once and is used for all media types */
    add_device(fatfsPrefix, _MSA, ffcio_open, ffcio_close, ffcio_read,
        ffcio_write, ffcio_lseek, ffcio_unlink, ffcio_rename);

    /* Open the display for output */
    display = Display_open(Display_Type_UART, NULL);
    if (display == NULL) {
        /* Failed to open display driver */
        while (1);
    }

    /* Initialize real-time clock */
    clock_settime(CLOCK_REALTIME, &ts);

    Display_printf(display, 0, 0, "Starting the fats application\n");

    /* Mount and register the SD Card */
    sdfatfsHandle = SDFatFS_open(Board_SDFatFS0, SD_DRIVE_NUM);
    if (sdfatfsHandle == NULL) {
        Display_printf(display, 0, 0, "Error starting the SD card\n");
        while (1);
    }
    else {
        Display_printf(display, 0, 0, "Drive %u is mounted\n", SD_DRIVE_NUM);
    }

    memset((void*) buff, (int) (0xAA), (size_t) BUFF_SIZE);

    /* Create a new file object for the file copy */
    dst = fopen(outputfile, "w");
    if (!dst) {
        Display_printf(display, 0, 0, "Error opening \"%s\"\n", outputfile);
        Display_printf(display, 0, 0, "Aborting...\n");
        while (1);
    }
    else {
        Display_printf(display, 0, 0, "Starting file write\n");
    }

    /*  Write buff to dst file */
    bytesWritten = fwrite(buff, 1, BUFF_SIZE, dst);

    if (bytesWritten < BUFF_SIZE) {
        Display_printf(display, 0, 0, "Disk Full\n");
    }

    /* Close outputfile[] */
    fclose(dst);

    /* Stopping the SDCard */
    SDFatFS_close(sdfatfsHandle);
    Display_printf(display, 0, 0, "Drive %u unmounted\n", SD_DRIVE_NUM);

    return (NULL);
}

fatsd_MSP_EXP432P401R_freertos_ccs.zip

  • Hello Otavio,

    Thanks for the detailed report on this issue!

    Give a couple of day's time to try this issue and get back.

    Regards,
    Sai
  • Hi Sai,

    Is there some update about the reported issue? I have performed some tests and I realized that the problem is not the SDFatFs driver. It seems the problem might be the implementation of "fwrite" funtion from CCS compiler (TI v18.1.4.LTS) that slices the large buffer passed to it in multiples calls to ffcio_write function. I realized It after trying a new project based in fatsdraw (fatsdraw_MSP_EXP432P401R_freertos_ccs) instead of fatfs (fatsd_MSP_EXP432P401R_freertos_ccs). The new project uses the "f_write" function direct from fatfs instead standard "fwrite" function from C compiler, that calls ffcio compatibility layer from TI.

    The new project compiling out of the box (using direct calls from fatfs library): 8625.fatsdraw_MSP_EXP432P401R_freertos_ccs.zip

    The previous project compiling out of the box (using ffcio compatibility layer and calls from standard C library [TI compiler] ): 4532.fatsd_MSP_EXP432P401R_freertos_ccs.zip

    The main code:

    #include <stdbool.h>
    #include <stddef.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    #if defined(__IAR_SYSTEMS_ICC__)
    /*
     *  Prevent time() macro in time.h from being used instead of our
     *  generated time() function.
     */
    #define _NO_DEFINITIONS_IN_HEADER_FILES 1
    #endif
    
    #include <time.h>
    
    #if defined(__IAR_SYSTEMS_ICC__)
    #undef _NO_DEFINITIONS_IN_HEADER_FILES
    #endif
    
    /* POSIX Header files */
    #include <pthread.h>
    
    #include <third_party/fatfs/ff.h>
    
    #include <ti/display/Display.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/SDFatFS.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    /* Buffer size used for the file copy process */
    #ifndef BUFF_SIZE
    #define BUFF_SIZE       512*32
    #endif
    
    /* String conversion macro */
    #define STR_(n)             #n
    #define STR(n)              STR_(n)
    
    /* Drive number used for FatFs */
    #define DRIVE_NUM           0
    
    const char outputfile[] = STR(DRIVE_NUM)":data.dat";
    
    static Display_Handle display;
    
    FIL dst;
    
    /* Set this to the current UNIX time in seconds */
    const struct timespec ts = {
        .tv_sec = 1469647026,
        .tv_nsec = 0
    };
    
    uint8_t buff[BUFF_SIZE] __attribute__ ((aligned (4)));
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        FRESULT fresult;
    
        /* Variables to keep track of the file copy progress */
        unsigned int bytesWritten = 0;
    
        SDFatFS_Handle sdfatfsHandle;
    
        /* Call driver init functions */
        GPIO_init();
        Display_init();
        SDFatFS_init();
    
        /* Configure the LED pin */
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* Open the display for output */
        display = Display_open(Display_Type_UART, NULL);
        if (display == NULL) {
            /* Failed to open display driver */
            while (1);
        }
    
        /* Initialize real-time clock */
        clock_settime(CLOCK_REALTIME, &ts);
    
        /* Turn on user LED */
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    
        Display_printf(display, 0, 0, "Starting the FatSD Raw example\n");
        Display_printf(display, 0, 0,
            "This example requires a FAT filesystem on the SD card.\n");
        Display_printf(display, 0, 0,
            "You will get errors if your SD card is not formatted with a filesystem.\n");
    
        /* Mount and register the SD Card */
        sdfatfsHandle = SDFatFS_open(Board_SDFatFS0, DRIVE_NUM);
        if (sdfatfsHandle == NULL) {
            Display_printf(display, 0, 0, "Error starting the SD card\n");
            while (1);
        }
        else {
            Display_printf(display, 0, 0, "Drive %u is mounted\n", DRIVE_NUM);
        }
    
        /* Open file for writing */
        fresult = f_open(&dst, outputfile, FA_WRITE);
        if (fresult != FR_OK) {
            Display_printf(display, 0, 0,
                "Error: \"%s\" could not be created.\nPlease check the "
                "Board.html if additional jumpers are necessary.\n",
                outputfile);
            Display_printf(display, 0, 0, "Aborting...\n");
            while (1);
        }
    
        memset(buff, 0xAA, BUFF_SIZE);
    
        /*  Write to dst file */
        fresult = f_write(&dst, buff, BUFF_SIZE, &bytesWritten);
        if (fresult || bytesWritten < BUFF_SIZE) {
            Display_printf(display, 0, 0, "Disk Full\n");
        }else{
            Display_printf(display, 0, 0, "File written!\n");
        }
    
        /* Close the file */
        f_close(&dst);
    
        /* Stopping the SDCard */
        SDFatFS_close(sdfatfsHandle);
    
        Display_printf(display, 0, 0, "Drive %u unmounted\n", DRIVE_NUM);
    
        return (NULL);
    }



    Regards,
    Otavio Gomes

  • Hello Otavio,

    I apologize for the delay in getting back on this thread!

    We (I and my colleagues) did debug this example and agree that the "fatsd" example is not using multiple block writes. We were able to confirm that the "fwrite" API from the CCS ARM compiler is restricting the buffer size to 256 Bytes. "ffcio_write" always receives 256 bytes or less data.

    As you have noticed the "fatsdraw" example directly calls the "f_write" and other fatfs APIs instead of the compiler APIs and should be able to do multiple block writes.

    I wanted to once again Thank you for the detailed work! We will work on making the necessary fixes to this example so that it is more useful.

    Regards,
    Sai
  • Hi Otavio,

    In addition we found that the buffering that fwrite does by default can be disabled with a call to setvbuff using flag _IONBF. This allows the driver to use the mutli block write and we've confirmed this using a logic analyzer. Thanks to your help we can improve the example to do this out of the box.

    We appreciate your help!

    Sean

  • Hello Sai and Reddy. Thank you for the efforts to help me solve this. The solution proposed by Reddy has solved my issue. I used the following call

    setvbuf(fp, NULL, _IONBF, 0);
    

    Now, the writting performance was greatly improved. I've used a logic analyzer to confirm which the MULTIPLE BLOCK WRITE feature is working properly now.

    Thanks,

    Otavio Gomes

**Attention** This is a public forum