Use of SD Card with SPI+EasyDMA and BLE

Hi there,

My nRF5340 application requires the use of SD card with DMA and BLE transmission. Howerver, as soon as I turn on the device, I get the following errors:

[00:00:00.452,667] <27>[1;31m<err> spi_nrfx_spim: Timeout waiting for transfer complete<27>[0m<\r><\n>
[00:00:00.453,125] <27>[1;31m<err> sdhc_spi: Card SCLK init sequence failed<27>[0m<\r><\n>
[00:00:00.453,155] <27>[1;31m<err> sd: Could not disable card power via SDHC<27>[0m<\r><\n>
disk_access_init failed. Error code: -5 ()<\r><\n>
[00:00:00.453,186] <27>[1;31m<err> SDCard: Failed to initialize SD card

A few internet searches and ChatGPT conversations have revealed that the clocking sequence is tied with the BLE operations and cant be used for initializing the SD card operations. A summary here:

Both BLE and SPIM require the 64 MHz HFCLK.

The Zephyr Bluetooth Controller enables the HFCLK through the MPSL (Multiprotocol Service Layer).

If BLE claims the HFCLK first, it may block or delay other peripherals (like SPIM) from accessing it when needed.

As a result, the spi_nrfx_spim driver fails to receive the clock enablement, and SCLK doesn’t toggle, leading to:

Please guide how to best use the SPIM on SD card while using BLE operations.

Best,

Umer

Parents
  • ChatGPT is bullshitting you as usual.

    Check your DTS and your pin config. Logic analyser might also be a good idea.

  • Thanks for your reply. 

    But there has to be a link between the two as I have confirmed this point by repeatedly compiling an SD card application. It only does not compile as soon as I enable BLE in the prj.conf file:

    CONFIG_BT=y

    in the prj.conf file, the application throws the run time error I provided earlier:

    [00:00:00.594,146] <27>[1;31m<err> spi_nrfx_spim: Timeout waiting for transfer complete<27>[0m<\r><\n>
    [00:00:00.594,604] <27>[1;31m<err> sdhc_spi: Card SCLK init sequence failed<27>[0m<\r><\n>
    [00:00:00.594,635] <27>[1;31m<err> sd: Could not disable card power via SDHC<27>[0m<\r><\n>
    disk_access_init failed. Error code: -5 ()<\r><\n>

Reply
  • Thanks for your reply. 

    But there has to be a link between the two as I have confirmed this point by repeatedly compiling an SD card application. It only does not compile as soon as I enable BLE in the prj.conf file:

    CONFIG_BT=y

    in the prj.conf file, the application throws the run time error I provided earlier:

    [00:00:00.594,146] <27>[1;31m<err> spi_nrfx_spim: Timeout waiting for transfer complete<27>[0m<\r><\n>
    [00:00:00.594,604] <27>[1;31m<err> sdhc_spi: Card SCLK init sequence failed<27>[0m<\r><\n>
    [00:00:00.594,635] <27>[1;31m<err> sd: Could not disable card power via SDHC<27>[0m<\r><\n>
    disk_access_init failed. Error code: -5 ()<\r><\n>

Children
  • The example code assigned a few pins to the network core for UART debug output. That might get only pulled in when network core is in use (i.e. CONFIG_BT=yes).

    Pins assigned to the other core cannot be used by the application core at all.

    You can fix this in the dts overlay - just don't assign pins to the network core.

  • Thanks again for the reply.

    I am not really assigning any pins to the network core--not deliberately anyways. Here is my overlay file:

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
     &clock {
    	
    	status = "okay";
    };
    
    
    &pinctrl {
    	
    
    	i2s0_default_alt: i2s0_default_alt {
    		group1 {
    			psels = <NRF_PSEL(I2S_SCK_M, 0, 26)>,
    				<NRF_PSEL(I2S_LRCK_M, 0, 6)>,  // MODIFIED from 0.07 since that is taken by CS pin
    				<NRF_PSEL(I2S_SDOUT, 1, 13)>,
    				<NRF_PSEL(I2S_SDIN, 0, 25)>;
    		};
    	};
    };
    
    
    &clock {
    	hfclkaudio-frequency = <11289600>;
    };
    
    i2s_rxtx: &i2s0 {
    	status = "okay";
    	pinctrl-0 = <&i2s0_default_alt>;
    	pinctrl-names = "default";
    	clock-source = "ACLK";
    };
    
    
    
    
    &spi1 {
        compatible = "nordic,nrf-spim";
    	status = "okay";
    	pinctrl-0 = <&spi1_default>;
    	pinctrl-1 = <&spi1_sleep>;
    	pinctrl-names = "default", "sleep";
    	cs-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>; //CS for SD
    	
    
        sdhc0: sdhc@0 {
            compatible = "zephyr,sdhc-spi-slot";
            reg = <0>;
            status = "okay";
            label = "SDHC0";
            spi-max-frequency = <24000000>;
    		mmc {
    			compatible = "zephyr,sdmmc-disk";
    			status = "okay";
    		};
        };
    };
    
    &pinctrl {
    	spi1_default: spi1_default {
    		
    		group1 {
    			psels = <NRF_PSEL(SPIM_SCK, 1, 0)>,
    						<NRF_PSEL(SPIM_MOSI, 1, 1)>,
    						<NRF_PSEL(SPIM_MISO, 0, 10)>;
    		};
    	};
    
    	spi1_sleep: spi1_sleep {
    		group1 {
    			// psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
    			// 			<NRF_PSEL(SPIM_MOSI, 0, 9)>,
    			// 			<NRF_PSEL(SPIM_MISO, 0, 10)>;
    				// low-power-enable;
    					psels = <NRF_PSEL(SPIM_SCK, 1, 0)>,
    						<NRF_PSEL(SPIM_MOSI, 1, 1)>,
    						<NRF_PSEL(SPIM_MISO, 0, 10)>;
    				low-power-enable;
    		};
    	};
    };
    
    &gpio1 {
        status = "okay";
    };
    / {
        aliases {
            button5 = &button5;
            button6 = &button6;
            button7 = &button7;
            button8 = &button8;
        };
    };
    
    / {
        buttons {
            compatible = "gpio-keys";
    
            button5: button_5 {
                gpios = <&gpio1 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "Button 5";
            };
            button6: button_6 {
                gpios = <&gpio1 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "Button 6";
            };
            button7: button_7 {
                gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "POWER Button";
            };
            button8: button_8 {
                gpios = <&gpio1 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
                label = "Button 7";
            };
        };
    };
    

    Here is the application code--reading from an SD card:

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/spi.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/sys/printk.h>
    
    #include <zephyr/fs/fs.h>
    #include <zephyr/storage/disk_access.h>
    #include <ff.h>
    #include <zephyr/logging/log.h>
    #include "SD_card.h"
    #define SPI_DEVICE_NODE DT_NODELABEL(spi1)
    
    void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins);
    
    //////////////////
    K_FIFO_DEFINE(i2s_block_fifo);
    bool opened_file = false;
    bool mounted_card = false;
    
    bool recoding_init = false;
    
    LOG_MODULE_REGISTER(Main, LOG_LEVEL_INF);
    
    // Define memory structures
    
    K_SEM_DEFINE(enable_recording, 0, 1);
    K_SEM_DEFINE(data_ready, 0, 1);
    
    
    
    /* SD Card Reading Operations*/
    
    // once initiatied, the SD card is repeatedly read from and the data read is displayed on the UART terminal
    
    void sd_reading(void) {
            LOG_INF("SD Card Reading Function\n");
        
            k_sem_take(&data_ready, K_FOREVER);
            if (sd_file_open() != 0) {
                LOG_ERR("Failed to open file\n");
                return;
            } else {
                opened_file = true;
                LOG_INF("File Opened Successfully\n");
            }
            // List all the files in the SD card
    
            
            while (1) {
                LOG_INF("Reading from SD card...\n");
                // Call the function to read from the SD card
                if (sd_file_read_line() != 0) {
                    LOG_ERR("Failed to read from SD card");
                    break;
                }
                
                k_sleep(K_MSEC(10)); // Sleep for 10 milli second before next read
            }
            
    }
    
    // Main Function
    int main(void) {
            LOG_INF("Starting main thread");
            
            // LOG_INF("Assuming a data file with binary data in the SD card, the program will be reading from it and displaying the data on ther UART terminal \n");
    
            if (init_button_led() != 0) {
                LOG_ERR("Failed to initialize button");
                return -1;
            }
    
            // initialize the SPI and SD card           
    
            if (spi_init() != 0) {
                LOG_ERR("Failed to initialize SPI");
                return -1;
            }
            
            // List all the files in the SD card
    
            list_files_on_sd();
            
            sd_reading();
    
    
            while (1) {
                k_sleep(K_FOREVER);
            }
            return 0;
        
        }
        

    The application code uses a custom SD_card.h library that successfully carries out read/write operations, that is, until CONFIG_BT=y is assigned in prj.conf. I am not including that here for brevity. 

    My build configuration is also for the application core not the network core. 

    Do you see any issues in the way I have written the overlay?

Related