This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

[FATFS] FA_OPEN_APPEND destroy first file content

Hello,

I am trying to run USBD_MSC example using PCA10056 board from SDK15.

It works fine, when creating new file on each button press. 

I modified code to create and append some data to file on button event. When using FAT file system, content of first created file always gets corrupted. When I switched to exFAT file system everything works fine. 

Can you help me point out what I am doing wrong? I share modified main.c file for this example. (in this example F1.txt will be corrupted)

/**
 * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 * 
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 * 
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 * 
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <stdlib.h>

#include "nrf.h"
#include "nrf_block_dev.h"
#include "nrf_block_dev_ram.h"
#include "nrf_block_dev_empty.h"
#include "nrf_block_dev_qspi.h"
#include "nrf_block_dev_sdc.h"
#include "nrf_drv_usbd.h"
#include "nrf_drv_clock.h"
#include "nrf_gpio.h"
#include "nrf_atomic.h"
#include "nrf_drv_power.h"

#include "ff.h"
#include "diskio_blkdev.h"

#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_string_desc.h"
#include "app_usbd_msc.h"
#include "app_error.h"
#include "app_timer.h"

#include "bsp.h"


#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

/**@file
 * @defgroup usbd_msc_example main.c
 * @{
 * @ingroup usbd_msc_example
 * @brief USBD MSC example
 *
 */

#define LED_USB_RESUME   (BSP_BOARD_LED_0)
#define LED_USB_START    (BSP_BOARD_LED_1)

#define BTN_RANDOM_FILE  0
#define BTN_LIST_DIR     1
#define BTN_MKFS         2

#define KEY_EV_RANDOM_FILE_MSK (1U << BTN_RANDOM_FILE)
#define KEY_EV_LIST_DIR_MSK    (1U << BTN_LIST_DIR   )
#define KEY_EV_MKFS_MSK        (1U << BTN_MKFS       )

/**
 * @brief Enable power USB detection
 *
 * Configure if example supports USB port connection
 */
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION true
#endif

/**
 * @brief SD card enable/disable
 */
#define USE_SD_CARD       0

/**
 * @brief FatFS for QPSI enable/disable
 */
#define USE_FATFS_QSPI    1

/**
 * @brief Mass storage class user event handler
 */
static void msc_user_ev_handler(app_usbd_class_inst_t const * p_inst,
                                app_usbd_msc_user_event_t     event);


/**
 * @brief Ram block device size
 *
 * @note Windows fails to format volumes smaller than 190KB
 */
#define RAM_BLOCK_DEVICE_SIZE (380 * 512)

/**
 * @brief  RAM block device work buffer
 */
static uint8_t m_block_dev_ram_buff[RAM_BLOCK_DEVICE_SIZE];

/**
 * @brief  RAM block device definition
 */
NRF_BLOCK_DEV_RAM_DEFINE(
    m_block_dev_ram,
    NRF_BLOCK_DEV_RAM_CONFIG(512, m_block_dev_ram_buff, sizeof(m_block_dev_ram_buff)),
    NFR_BLOCK_DEV_INFO_CONFIG("Nordic", "RAM", "1.00")
);


/**
 * @brief Empty block device definition
 */
NRF_BLOCK_DEV_EMPTY_DEFINE(
    m_block_dev_empty,
    NRF_BLOCK_DEV_EMPTY_CONFIG(512, 1024 * 1024),
    NFR_BLOCK_DEV_INFO_CONFIG("Nordic", "EMPTY", "1.00")
);


/**
 * @brief  QSPI block device definition
 */
NRF_BLOCK_DEV_QSPI_DEFINE(
    m_block_dev_qspi,
    NRF_BLOCK_DEV_QSPI_CONFIG(
        512,
        NRF_BLOCK_DEV_QSPI_FLAG_CACHE_WRITEBACK,
        NRF_DRV_QSPI_DEFAULT_CONFIG
     ),
     NFR_BLOCK_DEV_INFO_CONFIG("Nordic", "QSPI", "1.00")
);

#if USE_SD_CARD

#define SDC_SCK_PIN     (27)        ///< SDC serial clock (SCK) pin.
#define SDC_MOSI_PIN    (26)        ///< SDC serial data in (DI) pin.
#define SDC_MISO_PIN    (2)         ///< SDC serial data out (DO) pin.
#define SDC_CS_PIN      (32 + 15)   ///< SDC chip select (CS) pin.

/**
 * @brief  SDC block device definition
 */
NRF_BLOCK_DEV_SDC_DEFINE(
    m_block_dev_sdc,
    NRF_BLOCK_DEV_SDC_CONFIG(
        SDC_SECTOR_SIZE,
        APP_SDCARD_CONFIG(SDC_MOSI_PIN, SDC_MISO_PIN, SDC_SCK_PIN, SDC_CS_PIN)
     ),
     NFR_BLOCK_DEV_INFO_CONFIG("Nordic", "SDC", "1.00")
);


/**
 * @brief Block devices list passed to @ref APP_USBD_MSC_GLOBAL_DEF
 */
#define BLOCKDEV_LIST() (                                   \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_ram, block_dev),     \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_empty, block_dev),   \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_qspi, block_dev),    \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_sdc, block_dev)      \
)

#else
#define BLOCKDEV_LIST() (                                   \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_ram, block_dev),     \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_empty, block_dev),   \
    NRF_BLOCKDEV_BASE_ADDR(m_block_dev_qspi, block_dev)     \
)
#endif

/**
 * @brief Endpoint list passed to @ref APP_USBD_MSC_GLOBAL_DEF
 */
#define ENDPOINT_LIST() APP_USBD_MSC_ENDPOINT_LIST(1, 1)

/**
 * @brief Mass storage class work buffer size
 */
#define MSC_WORKBUFFER_SIZE (1024)

/*lint -save -e26 -e64 -e123 -e505 -e651*/
/**
 * @brief Mass storage class instance
 */
APP_USBD_MSC_GLOBAL_DEF(m_app_msc,
                        0,
                        msc_user_ev_handler,
                        ENDPOINT_LIST(),
                        BLOCKDEV_LIST(),
                        MSC_WORKBUFFER_SIZE);

/*lint -restore*/

/**
 * @brief Events from keys
 */
static nrf_atomic_u32_t m_key_events;

/**
 * @brief  USB connection status
 */
static bool m_usb_connected = false;


#if USE_FATFS_QSPI

static FATFS m_filesystem;

static bool fatfs_init(void)
{
    FRESULT ff_result;
    DSTATUS disk_state = STA_NOINIT;

    memset(&m_filesystem, 0, sizeof(FATFS));

    // Initialize FATFS disk I/O interface by providing the block device.
    static diskio_blkdev_t drives[] =
    {
        DISKIO_BLOCKDEV_CONFIG(NRF_BLOCKDEV_BASE_ADDR(m_block_dev_qspi, block_dev), NULL)
    };

    diskio_blockdev_register(drives, ARRAY_SIZE(drives));

    NRF_LOG_INFO("Initializing disk 0 (QSPI)...");
    disk_state = disk_initialize(0);
    if (disk_state)
    {
        NRF_LOG_ERROR("Disk initialization failed.");
        return false;
    }

    NRF_LOG_INFO("Mounting volume...");
    ff_result = f_mount(&m_filesystem, "", 1);
    if (ff_result != FR_OK)
    {
        if (ff_result == FR_NO_FILESYSTEM)
        {
            NRF_LOG_ERROR("Mount failed. Filesystem not found. Please format device.");
        }
        else
        {
            NRF_LOG_ERROR("Mount failed: %u", ff_result);
        }
        return false;
    }

    return true;
}

static void fatfs_mkfs(void)
{
    FRESULT ff_result;

    if (m_usb_connected)
    {
        NRF_LOG_ERROR("Unable to operate on filesystem while USB is connected");
        return;
    }

    NRF_LOG_INFO("\r\nCreating filesystem...");
    static uint8_t buf[512];
    ff_result = f_mkfs("", FM_FAT, 1024, buf, sizeof(buf));
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("Mkfs failed.");
        return;
    }

    NRF_LOG_INFO("Mounting volume...");
    ff_result = f_mount(&m_filesystem, "", 1);
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("Mount failed.");
        return;
    }

    NRF_LOG_INFO("Done");
}

static void fatfs_ls(void)
{
    DIR dir;
    FRESULT ff_result;
    FILINFO fno;

    if (m_usb_connected)
    {
        NRF_LOG_ERROR("Unable to operate on filesystem while USB is connected");
        return;
    }

    NRF_LOG_INFO("\r\nListing directory: /");
    ff_result = f_opendir(&dir, "/");
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("Directory listing failed: %u", ff_result);
        return;
    }

    uint32_t entries_count = 0;
    do
    {
        ff_result = f_readdir(&dir, &fno);
        if (ff_result != FR_OK)
        {
            NRF_LOG_ERROR("Directory read failed: %u", ff_result);
            return;
        }

        if (fno.fname[0])
        {
            if (fno.fattrib & AM_DIR)
            {
                NRF_LOG_RAW_INFO("   <DIR>   %s\r\n",(uint32_t)fno.fname);
            }
            else
            {
                NRF_LOG_RAW_INFO("%9lu  %s\r\n", fno.fsize, (uint32_t)fno.fname);
            }
        }

        ++entries_count;
        NRF_LOG_FLUSH();
    } while (fno.fname[0]);


    NRF_LOG_RAW_INFO("Entries count: %u\r\n", entries_count);
}
static void fatfs_file_create(const char *filename, const char *p_data, uint8_t len)
{
    FRESULT ff_result;
    static FIL file;
    if (m_usb_connected)
    {
        NRF_LOG_ERROR("Unable to operate on filesystem while USB is connected");
        return;
    }

    // (void)snprintf(filename, sizeof(filename), "%08x.txt", rand());

    NRF_LOG_RAW_INFO("Creating file: %s ...", (uint32_t)filename);
    NRF_LOG_FLUSH();

    ff_result = f_open(&file, filename, FA_READ | FA_WRITE | FA_OPEN_APPEND);
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("\r\nUnable to open or create file: %u", ff_result);
        NRF_LOG_FLUSH();
        return;
    }

    UINT written_bytes = 0;
    ff_result = f_write(&file, p_data, len, &written_bytes);
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("Unable to write to file: %u", ff_result);
        return;
    }
    else
    {
        NRF_LOG_INFO("%d/%d bytes written to: %s", len, written_bytes, filename);
    }

    ff_result = f_close(&file);
    if (ff_result != FR_OK)
    {
        NRF_LOG_ERROR("\r\nUnable to close file: %u", ff_result);
        NRF_LOG_FLUSH();
        return;
    }
    memset(&file, 0, sizeof(file));
    NRF_LOG_RAW_INFO("done\r\n");
}

static void fatfs_uninit(void)
{
    NRF_LOG_INFO("Un-initializing disk 0 (QSPI)...");
    UNUSED_RETURN_VALUE(disk_uninitialize(0));
}
#else //USE_FATFS_QSPI
#define fatfs_init()        false
#define fatfs_mkfs()        do { } while (0)
#define fatfs_ls()          do { } while (0)
#define fatfs_file_create() do { } while (0)
#define fatfs_uninit()      do { } while (0)
#endif

/**
 * @brief Class specific event handler.
 *
 * @param p_inst    Class instance.
 * @param event     Class specific event.
 */
static void msc_user_ev_handler(app_usbd_class_inst_t const * p_inst,
                                app_usbd_msc_user_event_t     event)
{
    UNUSED_PARAMETER(p_inst);
    UNUSED_PARAMETER(event);
}

/**
 * @brief USBD library specific event handler.
 *
 * @param event     USBD library event.
 */
static void usbd_user_ev_handler(app_usbd_event_type_t event)
{
    switch (event)
    {
        case APP_USBD_EVT_DRV_SUSPEND:
            bsp_board_led_off(LED_USB_RESUME);
            break;
        case APP_USBD_EVT_DRV_RESUME:
            bsp_board_led_on(LED_USB_RESUME);
            break;
        case APP_USBD_EVT_STARTED:
            bsp_board_led_on(LED_USB_START);
            break;
        case APP_USBD_EVT_STOPPED:
            UNUSED_RETURN_VALUE(fatfs_init());
            app_usbd_disable();
            bsp_board_leds_off();
            break;
        case APP_USBD_EVT_POWER_DETECTED:
            NRF_LOG_INFO("USB power detected");

            if (!nrf_drv_usbd_is_enabled())
            {
                fatfs_uninit();
                app_usbd_enable();
            }
            break;
        case APP_USBD_EVT_POWER_REMOVED:
            NRF_LOG_INFO("USB power removed");
            app_usbd_stop();
            m_usb_connected = false;
            break;
        case APP_USBD_EVT_POWER_READY:
            NRF_LOG_INFO("USB ready");
            app_usbd_start();
            m_usb_connected = true;
            break;
        default:
            break;
    }
}

static void bsp_event_callback(bsp_event_t ev)
{
    switch (ev)
    {
        /* Just set a flag to be processed in the main loop */
        case CONCAT_2(BSP_EVENT_KEY_, BTN_RANDOM_FILE):
            UNUSED_RETURN_VALUE(nrf_atomic_u32_or(&m_key_events, KEY_EV_RANDOM_FILE_MSK));
            break;

        case CONCAT_2(BSP_EVENT_KEY_, BTN_LIST_DIR):
            UNUSED_RETURN_VALUE(nrf_atomic_u32_or(&m_key_events, KEY_EV_LIST_DIR_MSK));
            break;

        case CONCAT_2(BSP_EVENT_KEY_, BTN_MKFS):
            UNUSED_RETURN_VALUE(nrf_atomic_u32_or(&m_key_events, KEY_EV_MKFS_MSK));
            break;

        default:
            return; // no implementation needed
    }
}

const char file1[] = "f1.txt";
const char file2[] = "f2.txt";
const char file3[] = "f3.txt";

const char data1[] = "line1\n";
const char data2[] = "line2\n";
const char data3[] = "line3\n";
int main(void)
{
    ret_code_t ret;
    static const app_usbd_config_t usbd_config = {
        .ev_state_proc = usbd_user_ev_handler
    };

    ret = NRF_LOG_INIT(app_usbd_sof_timestamp_get);
    APP_ERROR_CHECK(ret);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);

    /* Fill whole RAM block device buffer */
    for (size_t i = 0; i < sizeof(m_block_dev_ram_buff); ++i)
    {
        m_block_dev_ram_buff[i] = i;
    }

    /* Configure LEDs and buttons */
    nrf_drv_clock_lfclk_request(NULL);
    ret = app_timer_init();
    APP_ERROR_CHECK(ret);
    ret = bsp_init(BSP_INIT_BUTTONS, bsp_event_callback);
    APP_ERROR_CHECK(ret);
    bsp_board_init(BSP_INIT_LEDS);

    if (fatfs_init())
    {
        fatfs_ls();
        // fatfs_file_create();
    }

    ret = app_usbd_init(&usbd_config);
    APP_ERROR_CHECK(ret);

    app_usbd_class_inst_t const * class_inst_msc = app_usbd_msc_class_inst_get(&m_app_msc);
    ret = app_usbd_class_append(class_inst_msc);
    APP_ERROR_CHECK(ret);

    NRF_LOG_INFO("USBD MSC example started.");

    if (USBD_POWER_DETECTION)
    {
        ret = app_usbd_power_events_enable();
        APP_ERROR_CHECK(ret);
    }
    else
    {
        NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");

        app_usbd_enable();
        app_usbd_start();
        m_usb_connected = true;
    }

    while (true)
    {
        while (app_usbd_event_queue_process())
        {
            /* Nothing to do */
        }

        /* Process BSP key events flags.*/
        uint32_t events = nrf_atomic_u32_fetch_store(&m_key_events, 0);
        if (events & KEY_EV_RANDOM_FILE_MSK)
        {
            fatfs_file_create(file1, data1, sizeof(data1)-1); //not save NULL on the end of string
            fatfs_file_create(file1, data2, sizeof(data2)-1); //not save NULL on the end of string
            fatfs_file_create(file1, data3, sizeof(data3)-1); //not save NULL on the end of string

            fatfs_file_create(file2, data1, sizeof(data1)-1); //not save NULL on the end of string
            fatfs_file_create(file2, data2, sizeof(data2)-1); //not save NULL on the end of string
            fatfs_file_create(file2, data3, sizeof(data3)-1); //not save NULL on the end of string

            fatfs_file_create(file3, data1, sizeof(data1)-1); //not save NULL on the end of string
            fatfs_file_create(file3, data2, sizeof(data2)-1); //not save NULL on the end of string
            fatfs_file_create(file3, data3, sizeof(data3)-1); //not save NULL on the end of string
        }

        if (events & KEY_EV_LIST_DIR_MSK)
        {
            fatfs_ls();
        }

        if (events & KEY_EV_MKFS_MSK)
        {
            fatfs_mkfs();
        }

        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        /* Sleep CPU only if there was no interrupt since last loop processing */
        __WFE();
    }
}

/** @} */

  • I am running into a very similar issue. 


    I have implemented the two known issue fixes, but was getting corruption on FATFS in the header of a file just by f_printf's.  

    I have since switched to exFat, the corruption no longer occurs in the top line of the text file, but deletes about 10 lines of log in the middle of the file, inserting many symbols and characters. This is very reproducible in my experimentation.

  • We are facing the same issue. Writing into the SD card is just fine and when we plug the SD card directly in to the PC it is fine. But when we read via the msc it is corrupted there are some lines destroyed.

    Did you had a solution for this problem?

  • This case is almost 2 years old, and is based on an older SDK. Could you create a new thread with your issue? Remember to describe which device you're using (and revision of it), as well as which SDK is in use.

     

    Kind regards,

    Håkon

Related