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

Issues integrating SD card and FatFS with nRF52833 ble_app_uart example

OS: Windows 10 64bit

SW: Segger Embedded Studio 5.10 nRF SDK 17.0.2 Softdevice S140

HW: nRF52833 2020.6

Hello,

I had found an example integrating the ble_app_uart example and the fatfs library to read data from an SD card and sent it via BLE notification posted by a member here Jørgen Holmefjord

This example is made for the nRF52840 and SDK 16.0. I made the necessary changes to get it working on SDK 17.0.2 which is what I'm currently using. I've been able to successfully flash this example onto the nRF52840 and get data sent over from an SD card to a client. However, when trying to implement this example with an nRF52833, I'm having issues initializing the disk. I made all the necessary changes in my project (FLASH/RAM size,etc), and I'm able to compile and flash to the 52833. However, it seems to get stuck indefinitely when disk_initalization(0) is called in the fatfs_init function on line 23 in the main.c:

static void fatfs_init()
{
    static FATFS fs;
    static DIR dir;
    static FILINFO fno;
    static FIL file;

    uint32_t bytes_read;
    FRESULT ff_result;
    DSTATUS disk_state = STA_NOINIT;

    // 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 && disk_state; --retries)
    {
        disk_state = disk_initialize(0);
    }
    if (disk_state)
    {
        NRF_LOG_INFO("Disk initialization failed.");
        return;
    }

    if(!disk_state)
    {
    NRF_LOG_INFO("Does it even reach here??");
    }

    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...");
    ff_result = f_mount(&fs, "", 1);
    if (ff_result)
    {
        NRF_LOG_INFO("Mount failed.");
        return;
    }

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

    do
    {
        ff_result = f_readdir(&dir, &fno);
        if (ff_result != FR_OK)
        {
            NRF_LOG_INFO("Directory read failed.");
            return;
        }

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

    if(file_found_on_sdcard)
    {
        NRF_LOG_INFO("Reading from file " FILE_NAME "...");
        ff_result = f_open(&file, FILE_NAME, FA_READ);
        if (ff_result != FR_OK)
        {
            NRF_LOG_INFO("Unable to open or create file: " FILE_NAME ".");
            return;
        }

        ff_result = f_read(&file, file_buffer, FILE_SIZE_MAX, (UINT *) &bytes_read);
        if (ff_result != FR_OK)
        {
            NRF_LOG_INFO("Read failed\r\n.");
        }
        else
        {
            NRF_LOG_INFO("%d bytes read.", bytes_read);
            file_actual_read_size = bytes_read;
        }

        (void) f_close(&file);
    }
    else
    {
        NRF_LOG_INFO("No file named" FILE_NAME "found.");
    }
    return;
}
I've tried debugging this, however I'm still new to embedded development(I'm a student), so I'm having trouble understanding where my issue might be. If I simply let it run with no breakpoints and then pause the execution, I end up in the default_wait_func in diskio_blkdev.c. If I set breakpoints at the disk_initalization(0) and step through, I end up in nrfx_spim_init in nrfx_spin.c:

nrfx_err_t nrfx_spim_init(nrfx_spim_t  const * const p_instance,
                          nrfx_spim_config_t const * p_config,
                          nrfx_spim_evt_handler_t    handler,
                          void                     * p_context)
{
    NRFX_ASSERT(p_config);
    spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
    nrfx_err_t err_code;

    if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
    {
        err_code = NRFX_ERROR_INVALID_STATE;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
    // Currently, only SPIM3 in nRF52840 supports the extended features.
    // Other instances must be checked.
    if ((p_instance->drv_inst_idx != NRFX_SPIM3_INST_IDX) &&
        ((p_config->dcx_pin   != NRFX_SPIM_PIN_NOT_USED) ||
         (p_config->frequency == NRF_SPIM_FREQ_16M)      ||
         (p_config->frequency == NRF_SPIM_FREQ_32M)      ||
         (p_config->use_hw_ss)))
    {
        err_code = NRFX_ERROR_NOT_SUPPORTED;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }
#endif

    NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;

#if NRFX_CHECK(NRFX_PRS_ENABLED)
    static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
        #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
        nrfx_spim_0_irq_handler,
        #endif
        #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
        nrfx_spim_1_irq_handler,
        #endif
        #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
        nrfx_spim_2_irq_handler,
        #endif
        #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
        nrfx_spim_3_irq_handler,
        #endif
    };
    if (nrfx_prs_acquire(p_instance->p_reg,
            irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
    {
        err_code = NRFX_ERROR_BUSY;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)

    p_cb->handler = handler;
    p_cb->p_context = p_context;

    uint32_t mosi_pin;
    uint32_t miso_pin;
    // Configure pins used by the peripheral:
    // - SCK - output with initial value corresponding with the SPI mode used:
    //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
    //   according to the reference manual guidelines this pin and its input
    //   buffer must always be connected for the SPI to work.
    if (p_config->mode <= NRF_SPIM_MODE_1)
    {
        nrf_gpio_pin_clear(p_config->sck_pin);
    }
    else
    {
        nrf_gpio_pin_set(p_config->sck_pin);
    }
    nrf_gpio_cfg(p_config->sck_pin,
                 NRF_GPIO_PIN_DIR_OUTPUT,
                 NRF_GPIO_PIN_INPUT_CONNECT,
                 NRF_GPIO_PIN_NOPULL,
                 NRF_GPIO_PIN_S0S1,
                 NRF_GPIO_PIN_NOSENSE);
    // - MOSI (optional) - output with initial value 0,
    if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED)
    {
        mosi_pin = p_config->mosi_pin;
        nrf_gpio_pin_clear(mosi_pin);
        nrf_gpio_cfg_output(mosi_pin);
    }
    else
    {
        mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED;
    }
    // - MISO (optional) - input,
    if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED)
    {
        miso_pin = p_config->miso_pin;
        nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPIM_MISO_PULL_CFG);
    }
    else
    {
        miso_pin = NRF_SPIM_PIN_NOT_CONNECTED;
    }
    p_cb->miso_pin = p_config->miso_pin;
    // - Slave Select (optional) - output with initial value 1 (inactive).

    // 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled,
    // so this field needs to be initialized even if the pin is not used.
    p_cb->ss_pin = p_config->ss_pin;

    if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
    {
        if (p_config->ss_active_high)
        {
            nrf_gpio_pin_clear(p_config->ss_pin);
        }
        else
        {
            nrf_gpio_pin_set(p_config->ss_pin);
        }
        nrf_gpio_cfg_output(p_config->ss_pin);
#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
        if (p_config->use_hw_ss)
        {
            p_cb->use_hw_ss = p_config->use_hw_ss;
            nrf_spim_csn_configure(p_spim,
                                   p_config->ss_pin,
                                   (p_config->ss_active_high == true ?
                                        NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
                                   p_config->ss_duration);
        }
#endif
        p_cb->ss_active_high = p_config->ss_active_high;
    }

#if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
    // - DCX (optional) - output.
    if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED)
    {
        nrf_gpio_pin_set(p_config->dcx_pin);
        nrf_gpio_cfg_output(p_config->dcx_pin);
        nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin);
    }

    // Change rx delay
    nrf_spim_iftiming_set(p_spim, p_config->rx_delay);
#endif


    nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin);
    nrf_spim_frequency_set(p_spim, p_config->frequency);
    nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order);

    nrf_spim_orc_set(p_spim, p_config->orc);

    nrf_spim_enable(p_spim);

    if (p_cb->handler)
    {
        NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
            p_config->irq_priority);
        NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
    }

    p_cb->transfer_in_progress = false;
    p_cb->state = NRFX_DRV_STATE_INITIALIZED;

    err_code = NRFX_SUCCESS;
    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

I'm wondering if it's an issue with my SPI instances in the sdk_config.h, but I'm not sure either way. I understand these are probably things I should be able to figure out on my own, but I've spent a lot of time on this and I'm not getting anywhere so I hope I'm not wasting anyone's time with this. If you can help me then I would really appreciate it, if not I understand and thank you for taking the time to look.

I'll include my current example below if it is of any help. Thank you.ble_app_uart_fatfs_52833.zip

Parents Reply Children
No Data
Related