本示例演示如何使用 MCU 的 SD 卡功能,通过写数据到 SD 卡,读取 SD 卡数据,并观察串口信息。
int disk_access_write (const char * pdrv, const uint8_t * data_buf, uint32_t start_sector, uint32_t num_sector)
函数将数据从内存缓冲区写入磁盘。
注意:如果磁盘是 NVMe 类型,用户需要确保指针data_buf 4 字节对齐。
参数说明
字段 | 说明 |
---|---|
pdrv | 磁盘名称 |
data_buf | 指向内存缓冲区的指针 |
start_sector | 启动要写入的磁盘扇区 |
num_sector | 要写入的磁盘扇区数 |
返回值说明
成功时为 0,失败时为负 errno 代码
int disk_access_read (const char * pdrv, uint8_t * data_buf, uint32_t start_sector, uint32_t num_sector)
将数据从磁盘读取到内存缓冲区的函数。
注意:如果磁盘是 NVMe 类型,用户需要确保指针data_buf 4 字节对齐。
参数说明
字段 | 说明 |
---|---|
pdrv | 磁盘名称 |
data_buf | 指向内存缓冲区以放置数据的指针 |
start_sector | 启动要从中读取的磁盘扇区 |
num_sector | 要读取的磁盘扇区数 |
返回值说明
成功时为 0,失败时为负 errno 代码
更多Disk Access Interface API接口可查看Zephyr官网Disk Access Interface APIs。
void * k_malloc ( size_t size )
参数说明
字段 | 说明 |
---|---|
size | 请求的内存量(以字节为单位 |
SDK 中提供了 sdmmc 的示例。
演示如何使用 MCU 的 SD 卡功能,通过写数据到 SD 卡,读取 SD 卡数据,并观察串口信息。
{SDK}\.sdk\csk\samples\driver\sdmmc
适用开发板:大模型开发套件
编译版型:csk6_duomotai_devkit
使用引脚:
SD卡
与网络模组
复用了相同的引脚,因此在读写SD卡
前,需先将SD_CARD
排针进行短接,使上述定义的引脚连接至 SD 卡电路上,如图:在 SDK 根目录(duomotai_ap
)下可通过执行以下指令进行对该示例工程的编译:
lisa zep build -b csk6_duomotai_devkit .sdk/csk/samples/driver/sdmmc/ -p
编译完成后,编译产物二进制文件位于 build\zephyr\zephyr.bin
使用 Type-C 数据线连接开发套件的 DAP_USB
接口,选中以下其中一种方式对固件进行烧录:
cskburn desktop
是一款聆思推出的桌面烧录工具,在下载并安装 cskburn desktop 烧录工具后,双击图标运行软件:
1.点击串口下拉框,选择连接开发套件后识别到的串口编号;
2.将编译输出的.bin
文件拖拽进烧录区域;
3.点击开始烧录,等待烧录完成。
若您已按照 《环境搭建》 教程完成开发环境的安装,可在编译完成后执行 lisa zep exec cskburn
指令完成烧录。
lisa zep exec cskburn -s \\.\COMxx -C 6 -b 1500000 0x000000 --verify-all .\build\zephyr\zephyr.bin
请将命令行中的的 COMx 替换为开发套件在 PC 上对应的串口号(可通过设备管理器查看)。例如:
COM3
。
lisa zep exec cskburn -s PORT -C 6 0x000000 --verify-all ./build/zephyr/zephyr.bin -b 1500000
请将命令行中的 PORT 替换为开发套件连接在 PC 上对应的串口号。例如:
/dev/ttyUSB0
。
本套件的SD卡
与网络模组
复用了相同的引脚,因此在读写SD卡
前,我们需先将SD_CARD
排针进行短接,使上述定义的引脚连接至 SD 卡电路上,如图:
烧录并将SD_CARD
排针短接完成后,连接串口终端,按下开发板复位按钮,可看到串口有对应的信息输出。
以下代码与注释已省略一部分非关键接口代码,主要呈现示例的主业务流程与主要接口的使用。
在工程目录prj.conf
文件中需配置以下模块:
CONFIG_DISK_ACCESS=y
CONFIG_DISK_DRIVER_SDMMC=y
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_HEAP_MEM_POOL_SIZE=20000
本示例SD卡的信号线:CMD、CLK、DAT0-DAT3分别使用使用以下引脚:
可通过boards
目录下 overlay 文件的方式完成信号线的设备树配置。
设备树文件csk6_duomotai_devkit.overlay
配置如下:
/*
* Copyright (c) 2023 Anhui(Shenzhen) Listenai Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
&pinctrl {
/* UART alternate function */
pinctrl_uart0_rx_default: uart0_rx_default{
};
pinctrl_uart0_tx_default: uart0_tx_default{
};
/* SDIO alternate function */
pinctrl_sdio_cmd_default: sdio_cmd_default{
pinctrls = <IO_SD_CMD_GPIOB_01>;
};
pinctrl_sdio_clk_default: sdio_clk_default{
pinctrls = <IO_SD_CLK_GPIOB_02>;
};
pinctrl_sdio_dat0_default: sdio_dat0_default{
pinctrls = <IO_SD_DAT0_GPIOB_06>;
};
pinctrl_sdio_dat1_default: sdio_dat1_default{
pinctrls = <IO_SD_DAT1_GPIOB_05>;
};
pinctrl_sdio_dat2_default: sdio_dat2_default{
pinctrls = <IO_SD_DAT2_GPIOB_04>;
};
pinctrl_sdio_dat3_default: sdio_dat3_default{
pinctrls = <IO_SD_DAT3_GPIOB_03>;
};
};
&sdmmc {
status = "okay";
bit-bus = <4>;
pinctrl-0 = <
&pinctrl_sdio_cmd_default
&pinctrl_sdio_clk_default
&pinctrl_sdio_dat0_default
&pinctrl_sdio_dat1_default
&pinctrl_sdio_dat2_default
&pinctrl_sdio_dat3_default
>;
pinctrl-names = "default";
};
1.从设备树中获取 SD 卡设备
static const char *disk_pdrv = CONFIG_SDMMC_VOLUME_NAME;
2. SD 卡设备初始化
ret = disk_access_init(disk_pdrv);
3.拿到 SD 卡的接口信息
ret = disk_access_ioctl(disk_pdrv, DISK_IOCTL_GET_SECTOR_SIZE, &cmd_buf);
4.分配数据发送缓存空间
wbuf = (uint8_t *)k_malloc(NUM_SECTORS * disk_sector_size);
5.写数据
ret = disk_access_write(disk_pdrv, wbuf, 1, NUM_SECTORS);
6.分配数据接收缓存空间
rbuf = (uint8_t *)k_malloc(NUM_SECTORS * disk_sector_size);
7.读数据
ret = disk_access_read(disk_pdrv, rbuf, 1, NUM_SECTORS);
8.判断数据,打印结果
int main(void)
{
int ret = 0;
uint32_t cmd_buf;
ret = disk_access_init(disk_pdrv);
ret = disk_access_ioctl(disk_pdrv, DISK_IOCTL_GET_SECTOR_COUNT, &cmd_buf);
if (ret != 0) {
LOG_ERR("Disk ioctl get sector count failed (%d)\n", ret);
return -1;
}
disk_sector_count = cmd_buf;
LOG_DBG("Disk reports %u sectors\n", cmd_buf);
ret = disk_access_ioctl(disk_pdrv, DISK_IOCTL_GET_SECTOR_SIZE, &cmd_buf);
if (ret != 0) {
LOG_ERR("Disk ioctl get sector size failed (%d)\n", ret);
return -1;
}
disk_sector_size = cmd_buf;
LOG_DBG("Disk reports sector size %u\n", cmd_buf);
wbuf = (uint8_t *)k_malloc(NUM_SECTORS * disk_sector_size);
if (wbuf == NULL) {
LOG_ERR(" wbuf malloc failed\n");
}
for (uint32_t i = 0; i < NUM_SECTORS * disk_sector_size; i++) {
wbuf[i] = i;
}
LOG_HEXDUMP_INF(wbuf, 256, "wbuf");
ret = disk_access_write(disk_pdrv, wbuf, 1, NUM_SECTORS);
if (ret) {
LOG_ERR("disk_access_write failed (%d)\n", ret);
return -1;
}
rbuf = (uint8_t *)k_malloc(NUM_SECTORS * disk_sector_size);
if (rbuf == NULL) {
LOG_ERR(" rbuf malloc failed\n");
}
memset(rbuf, 0, NUM_SECTORS * disk_sector_size);
ret = disk_access_read(disk_pdrv, rbuf, 1, NUM_SECTORS);
if (ret) {
LOG_ERR("disk_access_write failed (%d)\n", ret);
return -1;
}
LOG_HEXDUMP_INF(rbuf, 256, "rbuf");
for (uint32_t i = 0; i < NUM_SECTORS * disk_sector_size; i++) {
if (rbuf[i] != wbuf[i]) {
LOG_ERR("Read data did not match data written to disk %d\n", i);
return -1;
}
}
LOG_DBG("sdcard sample done \n");
return 0;
}