This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Probem to Re-mount SD after shutting down its voltage source

On a custom board based on nrf52840.

We want to write data on a SD CARD every XX seconds.

We implement this by changig the state of a state_machine at every wakeup from RTC compare interruption.

To save power, we are shutting the voltage source of the SD Card when it is not writing.

So we are initializing the SD card at begin of every cycle and uninitiliazing at the end.

Here is following code implemented with SDK 17 :

#include <stdio.h>
#include "boards.h"
#include "nrf.h"
#include "bsp.h"
#include "ff.h"
#include "diskio_blkdev.h"
#include "nrf_gpio.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_block_dev_sdc.h"
#include "nrf_delay.h"
#include "nrf_drv_rtc.h"
#include "nrf_drv_clock.h"

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





#define COMPARE_COUNTERTIME (5UL)

#define STATE_INIT 0
#define STATE_MESURE 1
#define STATE_WRITE_SD 2


static bool m_sleep = true;
static int m_state = STATE_INIT;

FATFS m_fs;

FILINFO m_fno;
FIL m_file;
FRESULT m_ff_result;
DSTATUS m_disk_state = STA_NOINIT;


void state_temperature_reading(void);
static void fatfs_example(void);
void init_sd();
void uninit_sd();


#define FILE_NAME   "NORDIC.TXT"
#define TEST_STRING "SD card example. \n"

#define SDC_SCK_PIN     SD_SPI_SCLK  ///< SDC serial clock (SCK) pin.
#define SDC_MOSI_PIN    SD_SPI_MOSI  ///< SDC serial data in (DI) pin.
#define SDC_MISO_PIN    SD_SPI_MISO  ///< SDC serial data out (DO) pin.
#define SDC_CS_PIN      SD_SPI_CS  ///< 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")
);


 void execute_state_machine (int sta)
 {
    if(sta == STATE_INIT) {
            m_sleep = true;
    }
    else if(sta == STATE_MESURE) {
            state_temperature_reading();
            m_sleep = true;
    }
    else if(sta == STATE_WRITE_SD) {
        init_sd();
        fatfs_example();
        uninit_sd();
        m_sleep = true;
    }
    return;
}



/** @brief Function starting the internal LFCLK XTAL oscillator.
 */
static void lfclk_config(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_clock_lfclk_request(NULL);
}

const nrf_drv_rtc_t rtc = NRF_DRV_RTC_INSTANCE(0); /**< Declaring an instance of nrf_drv_rtc for RTC0. */



void rtc_unconfig(void)
{
    nrf_drv_rtc_disable(&rtc);
    nrf_drv_rtc_uninit(&rtc);
}
/** @brief: Function for handling the RTC0 interrupts.
 * Triggered on TICK and COMPARE0 match.
 */
static void rtc_handler(nrf_drv_rtc_int_type_t int_type)
{
    uint32_t err_code;
    if (int_type == NRF_DRV_RTC_INT_COMPARE0)
    {
        nrf_gpio_pin_toggle(COMPARE_EVENT_OUTPUT);
        m_sleep = false;
        m_state = STATE_WRITE_SD;
        err_code = nrf_drv_rtc_cc_set(&rtc, 0, COMPARE_COUNTERTIME * 8, true);
        APP_ERROR_CHECK(err_code);
        nrf_drv_rtc_counter_clear(&rtc);
    }
}


static void rtc_config(void)
{
    uint32_t err_code;

    //Initialize RTC instance
    nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG;
    config.prescaler = 4095;
    err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler);
    APP_ERROR_CHECK(err_code);

    //Enable tick event & interrupt
    nrf_drv_rtc_tick_enable(&rtc, true);

    //Set compare channel to trigger interrupt after COMPARE_COUNTERTIME seconds
    err_code = nrf_drv_rtc_cc_set(&rtc, 0, COMPARE_COUNTERTIME * 8, true);
    APP_ERROR_CHECK(err_code);

    //Power on RTC instance
    nrf_drv_rtc_enable(&rtc);
}


void init_sd(void) {
    m_disk_state = STA_NOINIT;

    nrf_gpio_pin_set(SD_EN_PIN);
    nrf_delay_ms(1000);
    // 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_sdc, block_dev), NULL)
    };

    diskio_blockdev_register(drives, ARRAY_SIZE(drives));

    NRF_LOG_INFO("Initializing disk 0 (SDC)...");
    for (uint32_t retries = 3; retries && m_disk_state; --retries)
    {
        m_disk_state = disk_initialize(0);
    }
    if (m_disk_state)
    {
        NRF_LOG_INFO("Disk initialization failed.");
        return;
    }

    uint32_t blocks_per_mb = (1024uL * 1024uL) / m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_size;
    uint32_t capacity = m_block_dev_sdc.block_dev.p_ops->geometry(&m_block_dev_sdc.block_dev)->blk_count / blocks_per_mb;
    NRF_LOG_INFO("Capacity: %d MB", capacity);

    NRF_LOG_INFO("Mounting volume...");
    m_ff_result = f_mount(&m_fs, "", 1);
    if (m_ff_result)
    {
        NRF_LOG_INFO("Mount failed. %d", m_ff_result);
        return;
    }
}


static void write_on_sd(void)
{
    static DIR m_dir;

    uint32_t bytes_written;

    NRF_LOG_INFO("\r\n Listing directory: /");
    m_ff_result = f_opendir(&m_dir, "/");
    if (m_ff_result)
    {
        NRF_LOG_INFO("Directory listing failed!");
        return;
    }

    do
    {
        m_ff_result = f_readdir(&m_dir, &m_fno);
        if (m_ff_result != FR_OK)
        {
            NRF_LOG_INFO("Directory read failed.");
            return;
        }

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

    NRF_LOG_INFO("Writing to file " FILE_NAME "...");
    m_ff_result = f_open(&m_file, FILE_NAME, FA_READ | FA_WRITE | FA_OPEN_APPEND);
    if (m_ff_result != FR_OK)
    {
        NRF_LOG_INFO("Unable to open or create file: " FILE_NAME ".");
        return;
    }
    NRF_LOG_INFO("File opend");

    m_ff_result = f_write(&m_file, TEST_STRING, sizeof(TEST_STRING) - 1, (UINT *) &bytes_written);
    if (m_ff_result != FR_OK)
    {
        NRF_LOG_INFO("Write failed\r\n.");
    }
    else
    {
        NRF_LOG_INFO("%d bytes written.", bytes_written);
    }

    (void) f_close(&m_file);

     NRF_LOG_INFO("\r\n Closing dir : /");
    m_ff_result = f_closedir(&m_dir);
    if (m_ff_result)
    {
        NRF_LOG_INFO("Closing dir failed!");
        return;
    }

    return;
}

void uninit_sd(void) {
     NRF_LOG_INFO("Unmounting volume...");
    m_ff_result = f_mount(NULL, "", 0);
    if (m_ff_result)
    {
        NRF_LOG_INFO("Unmount failed.");
        return;
    }
 //Uninitialise disc:
    for (uint32_t retries = 3; retries && m_disk_state; --retries)
    {
        m_disk_state = disk_uninitialize(0);
        
    }
    if (m_disk_state)
    {
        NRF_LOG_INFO("Disk uninitialization failed.");
        return;
    }
    NRF_LOG_INFO("disk state : %d", m_disk_state);
    NRF_LOG_INFO("disk unitialized");
    //nrf_gpio_pin_clear(SD_EN_PIN);
}


/**
 * @brief Function for main application entry.
 */
int main(void)
{
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();
    NRF_LOG_INFO("\n\n\n\n\n\n\n\n\n");
    NRF_LOG_INFO("TWI sensor example started. \n");
    nrf_gpio_cfg_output(SD_EN_PIN);
   

    init_sd();
    fatfs_example();
    uninit_sd();
    nrf_delay_ms(3000);
    lfclk_config();
    rtc_config();
   
    NRF_LOG_INFO("end of configs \n");


    while (true)
    {
        if(m_sleep) {
        __WFE();
        __SEV();
        __WFE();
        }

        else {
            execute_state_machine(m_state);
        }
    }
}

When we launch the program the first write (before the main while ) is running correctly.

But after f_mount in init_sd() returns with error code : FR_DISK_ERR

And the data can not be written to SD. 

This problem doesn't occur when we don't shutdown SD voltage source with GPIO : SD_EN_PIN and the program runs without problems.

Thanks for any hint to debug this problem.

Parents Reply Children
Related