本专栏由非官方人员 王小小海 所著,其内容主要记录了在开发NCS的过程中遇到的一些问题和解决方法,还有一些应用的例程。作者本人也是在实践应用中遇到的问题,想着把这些问题分享给可能遇到的朋友。仅仅做个人技术交流分享,不做任何商业用途。如有不对之处,请留言,本人及时更改。
本专栏不涉及基础的安装和环境搭建问题,本例程开发使用NCS 2.9.0开发,还请注意!。
所有分享内容
笔记分享
- 【笔记分享】NCS下radio_test添加FEM
- 【笔记分享】5340基于 BLE LBS 自定义网络核固件点亮LED并合并固件
- 【笔记分享】5340基于LBS自定义网络核双核DFU实现
- 【笔记分享】5340 设置public address 和 random address
- 【笔记分享】NCS nRF52/53 添加LVGL组件驱动屏幕
- 【笔记分享】VirtualBox Ubuntu22.04 不能使用nrfjprog问题记录
- 【笔记分享】5340使用内部负载电容调频偏
- 【笔记分享】基于 LE Audio 例程移植到nRF52840上运行思路
- 【nRF52/53】【笔记分享】基于 BLE LBS DFU使用内部外部Flash 升级
- 【nRF54H20】基础介绍与使用介绍
- 【笔记分享】nRF54H20 SPI速率范围记录
应用分享
暂无
前言
在使用 nRF5340 LE Audio的时候需要记录音频数据,这时候我们可以使用 SPI Nor Flash 或者 SD卡,当然最性价比高的当然是使用SD卡,那么这次我们主要分享如何在NCS上使能SPI SD卡,并且挂载SD卡进行读写。
操作步骤
-
首先我们任意创建一个工程。这里我使用的 BLE的 LBS工程,当然不管是什么工程,方法都是一样的。
-
添加一个设备树,app.overlay (这是最快的,当然可以建立 boards 文件夹然后建立对应板子的.overlay文件)
-
在pj.conf文件中添加 文件系统和 DISK 驱动。

- 编写驱动,测试对应SD卡注册状态。这里我们创建一个 sd_card.c文件里面 包含了 初始化SD卡、查询卡的大小、文件系统的打开、读写、关闭功能。并将此文件添加到CMakeLists.txt中。

具体代码
设备树
需要根据具体SPI修改对应设备树
&pinctrl {
spi4_default: spi4_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
<NRF_PSEL(SPIM_MOSI, 0, 9)>;
/* Workaround for issue with PCA10121 v0.7.0
* related to SD-card
*/
nordic,drive-mode = <NRF_DRIVE_H0H1>;
};
group2 {
psels = <NRF_PSEL(SPIM_MISO, 0, 10)>;
};
};
spi4_sleep: spi4_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
<NRF_PSEL(SPIM_MISO, 0, 10)>,
<NRF_PSEL(SPIM_MOSI, 0, 9)>;
low-power-enable;
};
};
};
&spi4 {
compatible = "nordic,nrf-spim";
status = "okay";
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi4_default>;
pinctrl-1 = <&spi4_sleep>;
pinctrl-names = "default", "sleep";
sdhc0: sdhc@0 {
compatible = "zephyr,sdhc-spi-slot";
reg = <0>;
status = "okay";
sdmmc {
compatible = "zephyr,sdmmc-disk";
status = "okay";
};
spi-max-frequency = <32000000>;
};
};
pj.conf文件
# Enable SDHC interface
CONFIG_DISK_DRIVERS=y
CONFIG_FILE_SYSTEM=y
CONFIG_FAT_FILESYSTEM_ELM=y
CONFIG_FS_FATFS_LFN=y
SD卡测试代码
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/storage/disk_access.h>
#include <zephyr/fs/fs.h>
#include <ff.h>
#include <string.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/devicetree.h>
#include <string.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(sd_card);
#define SD_ROOT_PATH "/SD:/"
/* Round down to closest 4-byte boundary */
#define PATH_MAX_LEN ROUND_DOWN(CONFIG_FS_FATFS_MAX_LFN, 4)
static const char *sd_root_path = "/SD:";
static FATFS fat_fs;
static bool sd_init_success;
static struct fs_mount_t mnt_pt = {
.type = FS_FATFS,
.fs_data = &fat_fs,
};
int sd_card_open(char const *const filename, struct fs_file_t *f_seg_read_entry)
{
int ret;
char abs_path_name[PATH_MAX_LEN + 1] = SD_ROOT_PATH;
size_t available_path_space = PATH_MAX_LEN - strlen(SD_ROOT_PATH);
if (!sd_init_success)
{
return -ENODEV;
}
if (strlen(filename) > CONFIG_FS_FATFS_MAX_LFN)
{
LOG_ERR("Filename is too long");
return -ENAMETOOLONG;
}
if ((strlen(abs_path_name) + strlen(filename)) > PATH_MAX_LEN)
{
LOG_ERR("Filepath is too long");
return -EINVAL;
}
strncat(abs_path_name, filename, available_path_space);
LOG_INF("abs path name:\t%s", abs_path_name);
fs_file_t_init(f_seg_read_entry);
ret = fs_open(f_seg_read_entry, abs_path_name, FS_O_READ);
if (ret)
{
LOG_ERR("Open file failed: %d", ret);
return ret;
}
return 0;
}
int sd_card_read(char *buf, size_t *size, struct fs_file_t *f_seg_read_entry)
{
int ret;
ret = fs_read(f_seg_read_entry, buf, *size);
if (ret < 0)
{
LOG_ERR("Read file failed. Ret: %d", ret);
return ret;
}
*size = ret;
return 0;
}
int sd_card_close(struct fs_file_t *f_seg_read_entry)
{
int ret;
ret = fs_close(f_seg_read_entry);
if (ret)
{
LOG_ERR("Close file failed: %d", ret);
return ret;
}
return 0;
}
int sd_card_init(void)
{
int ret;
static const char *sd_dev = "SD";
uint64_t sd_card_size_bytes;
uint32_t sector_count;
size_t sector_size;
ret = disk_access_init(sd_dev);
if (ret)
{
LOG_DBG("SD card init failed, please check if SD card inserted");
return -ENODEV;
}
ret = disk_access_ioctl(sd_dev, DISK_IOCTL_GET_SECTOR_COUNT, §or_count);
if (ret)
{
LOG_ERR("Unable to get sector count");
return ret;
}
LOG_DBG("Sector count: %d", sector_count);
ret = disk_access_ioctl(sd_dev, DISK_IOCTL_GET_SECTOR_SIZE, §or_size);
if (ret)
{
LOG_ERR("Unable to get sector size");
return ret;
}
LOG_DBG("Sector size: %d bytes", sector_size);
sd_card_size_bytes = (uint64_t)sector_count * sector_size;
LOG_INF("SD card volume size: %lld B", sd_card_size_bytes);
mnt_pt.mnt_point = sd_root_path;
ret = fs_mount(&mnt_pt);
if (ret)
{
LOG_ERR("Mnt. disk failed, could be format issue. should be FAT/exFAT");
return ret;
}
sd_init_success = true;
return 0;
}
结束语
好的,本次分享基本上就是这些。
有不明白的地方欢迎提问,也厚脸皮要个赞或者关注,谢谢各位啦。
如果有哪位朋友需要定制方案,也可以联系私信我。感谢大家的浏览。
本系列文章大多数是本人遇到和解决过的问题,难有疏忽之处,有什么问题或者不明白的地方,欢迎留言询问!