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

Issue reading SD card from within a Gatt connection

Hi,

I am using a NRF58240-dk pca10056 S140. 

I have an external SD card device connected which, I am writing live sensor data to then advertising that data over a ble advertisement packet. I also have the code functionality to have a GATT connection. When I connect to the nordic board the "live data advertisement" stops and the GATT connection is made. I then have a custom service which I can write and receive data from using the NRF connect app. I can see the data received from this connection and handle it via a statemachine within the on_write function within my custom code.

The issue I have is when I try to call the command to read the sd card the code locks up and does not run. It goes to the reading state and starts to read the SD card however, it is unable open to file but, this is due to the fact to code is in the default wait function within diskio_bledev.c. 

static void default_wait_func(void)
{
__WFE();
}//Stops here

How do I stop this? 

Within the fatfs example I have the exact same code to read the data and it works but, the main loop has __WFE(); looped within it. So within my code I added the __WFE(); in the idle state handle routine and tried just running __WFE();. I also tried using sd_app_evt_wait(); Neither of which got out of the default wait function. I tried sd_app_evt_wait due to a forum post about issues with __WFE() and the soft device. My code is based off of the ble_app_template example. I can also read the SD card if I call the function before my main loop then run __WFE(). So I think its something to do with priorities / GATT connection.

Please help.

Also below is my code for reading some data of the CSV file

void SD_CARD_Read_Line()
{
    UINT bytesRead;//From sd card driver library
    static FATFS fs;
    static DIR dir;
    static FILINFO fno;
    static FIL file;

    uint32_t bytes_written;
    FRESULT ff_result;
    DSTATUS disk_state = STA_NOINIT;
    
    NRF_LOG_INFO("Reading SD CARD data");
    char data[100]={0}; /* Line buffer */
    unsigned int ByteRead = 0;

    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 ".\r\n");
        return;
    }

    uint16_t size = f_size(&file) ;
    NRF_LOG_INFO("size of the file in bytes = %d\r\n",size);

    ff_result = f_read(&file,data,100, &ByteRead);

    if (ff_result != FR_OK)
    {
        NRF_LOG_INFO("Unable to read or create file: " FILE_NAME ".\r\n");
        return;
    }
    else if(ff_result == FR_OK)
    {
      NRF_LOG_INFO("%d bytes read\r\n",ByteRead);
      NRF_LOG_INFO("Data is : %s\r\n", (uint32_t) data);
    }
    else
    {
      NRF_LOG_INFO("Error operation\r\n");
    }
    (void) f_close(&file);
}

Parents
  • Hi,

    The block_dev_handler() callback must get invoked to clear the "m_drives[n].busy" flag that keeps the program spinning inside the wait loop. The problem is that the callback won't get invoked if the wait loop is already run in an interrupt context with the same interrupt priority (ie if SPI IRQ pri == Softdevice). At least I think this is the problem. Please increase the interrupt priority for the SPI to SPI_DEFAULT_CONFIG_IRQ_PRIORITY==5 in sdk_config.h and see if you get the same result. Both SPI and Softdevice use priority '6' by default. That said, I think the best solution is to not do these operations from an interrupt context to keep your interrupt service routines short.

    Best regards,

    Vidar

  • Hi Vidar,

    That fix worked thanks very much!

    However, how else would you recommend me handling this?

    Basically I have the need to read a CSV file stored on my SD card and then I need to transfer it over my bluetooth Gatt connection to my phone.

    Thanks,

    Thomas

Reply Children
  • Hi Thomas, glad to hear that it worked. Would it make sense to just perform the read and write from your main loop instead of doing it inside the Softdevice interrupt? I think that's probably the easiest solution to this. Another option is to implement the app scheduler library so Softdevice events are not reported in the interrupt context. There is a tutorial for it here: https://devzone.nordicsemi.com/nordic/short-range-guides/b/software-development-kit/posts/scheduler-tutorial

  • Ok but does the main loop run whilst a connection is made? If so I can just test for a connection(I am using a Boolean at the moment and just running idle state handle in it). If so I could poll a value to see if a command for reading the SD card has been called.

  • Yes, program execution returns to the main loop once event processing is complete. So you could add some global state flags that are updated in your event handlers and polled in your main loop.

    static bool m_rcvd_data_request;

    main()

    {

    ...

    for(;;)

    {

         if (m_rcvd_data_request) // Always checked after application interrupts

         {

                 m_rcvd_data_request = false;

                 //TODO: add calls to load data from SD and send over BLE

          }

          else if( <flag>)

         {}

          idle_state_handle(); // sleep while waiting for new events

    }

  • Thanks for the response. I am now trying to implement your solution but, I am having an issue with passing over the boolean command from the gatt connection. My code looks like below.

    From me passing in a Gatt command from my mobile application I change a boolean main_test to 1. I tried with an int and bool and both failed to print out to the RTT terminal. What could I be doing wrong? I decalre the variable in another file I am using as an extern int main_test; and define it in the c file as int main_test = 0;

    My code is below:

    void Process_data(void)
    {
        if(GATT_CONNECTED == false)
        {
            //Non gatt connected functions here
        }
        else if (GATT_CONNECTED == true)// GATT_CONNECTED = true
        {
            NRF_LOG_INFO("Test1 passed");//Testing variable.
            if(main_test == 1)
            {
                NRF_LOG_INFO("Test2 passed");//Testing variable.
                main_test = 0;//False
            }
            if(main_read_sd_card == true)//Not used at the moment by the idea of how I will read the CSV
            {
                NRF_LOG_INFO("Go to reading CSV file in main code");
                main_read_sd_card = false;
                SEND_CSV();//Run the function to send the CSV file
            }
            sd_app_evt_wait();//Processing for SD CARD
            idle_state_handle();
        }
    }

Related