Good day,
I have been making use of the nRF54LM20A SoC with ncs v3.2.0. I am currently trying to use the high-speed SPI (SPIM00) lines on Port 2 to communicate with an SD card. I intend to mount it and be able to write to and read from the card. I am using a custom board (Fanstel EV-BM20C), however that seems to be irrelevant to the issue at hand.
The problem is that the high-speed SPI lines on the chip seem to have a minimum clock speed of around 1-2MHz. This poses an issue because the SD card initializes at 400kHz. Zephyr RTOS seems to force the initialization process of an SD card to 400kHz, preventing the SPI lines from even starting communication.
This yields this error, along with many more after the fact:
<err> spi_nrfx_spim: Failed to initialize nrfx driver: -22
I then attempted to use the same pins as GPIO pins to first bitbang the SPI initialization sequence onto the SD card, before ultimately returning back to the high speed SPI bus. I used both manual bitbanging the commands to initialize the SD card, as well as the embedded spi-bitbang library within Zephyr. While both methods initialized smoothly, switching to the high speed bus during runtime proved to be problematic and throw a whole host of errors no matter what I did.
My overall question is, is it possible to mount the SD card properly on the nRF54LM20A SoC using the SPIM00 SPI lines? And if not, is it possible to mount the SD card some other way using bitbanging, while switching to the SPIM00 lines only after initialization?
prj.conf:
CONFIG_SPI=y CONFIG_SPI_BITBANG=y CONFIG_SPI_NRFX=y CONFIG_LOG=y CONFIG_PRINTK=y CONFIG_DISK_DRIVER_SDMMC=y CONFIG_DISK_ACCESS=y CONFIG_FILE_SYSTEM=y CONFIG_FAT_FILESYSTEM_ELM=y CONFIG_MAIN_STACK_SIZE=4096
nrf54lm20dk_nrf54lm20a_cpuapp.overlay:
&spi00 {
status = "okay";
compatible = "nordic,nrf-spim";
cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi00_default>;
pinctrl-1 = <&spi00_sleep>;
pinctrl-names = "default", "sleep";
max-frequency = <4000000>;
sdhc0: sdhc@0 {
status = "okay";
compatible = "zephyr,sdhc-spi-slot";
spi-max-frequency = <4000000>;
reg = <0>;
label = "SD";
mmc {
compatible = "zephyr,sdmmc-disk";
disk-name = "SD";
status = "okay";
};
};
};
&pinctrl {
spi00_default: spi00_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 2, 6)>,
<NRF_PSEL(SPIM_MOSI, 2, 8)>,
<NRF_PSEL(SPIM_MISO, 2, 9)>;
};
};
spi00_sleep: spi00_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 2, 6)>,
<NRF_PSEL(SPIM_MOSI, 2, 8)>,
<NRF_PSEL(SPIM_MISO, 2, 9)>;
low-power-enable;
};
};
};
// If bitbanging is necessary
/ {
/* Define the bit-bang SPI bus */
spi_bb: spi-bitbang {
compatible = "zephyr,spi-bitbang";
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
clk-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
mosi-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
miso-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;
cs-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
sdhc_bb: sdhc@0 {
compatible = "zephyr,sdhc-spi-slot";
reg = <0>;
status = "okay";
label = "SD_BB";
mmc {
compatible = "zephyr,sdmmc-disk";
status = "okay";
disk-name = "SD_BB";
};
spi-max-frequency = <400000>; // Keep it slow for bit-banging
};
};
};
main.c:
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <string.h>
#include <zephyr/devicetree.h>
#include <zephyr/storage/disk_access.h>
#include <zephyr/fs/fs.h>
#include <ff.h>
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);
static struct fs_mount_t fs_mnt;
int main(void)
{
k_sleep(K_MSEC(200));
static FATFS fat_fs;
fs_mnt.type = FS_FATFS;
fs_mnt.fs_data = &fat_fs;
fs_mnt.mnt_point = "/SD:";
fs_mount(&fs_mnt);
k_msleep(500);
char filename[255];
struct fs_file_t file;
int rc;
fs_file_t_init(&file);
snprintf(filename, sizeof(filename), "%s/test_file.txt", fs_mnt.mnt_point);
rc = fs_open(&file, filename, FS_O_CREATE | FS_O_WRITE);
if (rc < 0) {
LOG_ERR("FAIL: open %s: %d", filename, rc);
return rc;
}
LOG_INF("File created!");
rc = fs_write(&file, "Text written", 12);
if (rc < 0) {
LOG_ERR("FAIL: write %s: %d", filename, rc);
return rc;
}
LOG_INF("Data written");
rc = fs_close(&file);
return 0;
}