zephyr使用的device大多是内置几十K到几M Flash, 如果有较大量的数据需要本地存储就需要扩展外部Flash,对于数据存储的情况挂总线flash有io需求,挂SPI Flash容量单价又比较高。然后想起SDCard 有SPI Mode,当然就选它了。
本文的使用的device问nrf53832.
代码说明
原本打算移植或者重写SPI Mode 访问SD Card ,后来在制定API的时候要参考disk_access统一接口,发现zephyr已经有代码可以支援SPI Mode 访问SD CARD,这就省下不少功夫。
源代码参考1
subsys/disk/disk_access_spi_sdhc.c
原理不做介绍,只是按照预定的方式通过SPI接口向TF卡发命令和读写数据,感兴趣可以看文末参考内容。
配置
修改DTS
在你板子的dts下添加如下内容1
2
3
4
5
6
7
8
9
10
11
12
13
14
15&spi2 {
status = "okay";
sck-pin = <31>;
mosi-pin = <2>;
miso-pin = <3>;
cs-gpios = <&gpio0 30 0>;
sdhc0: sdhc@0 {
compatible = "zephyr,mmc-spi-slot";
reg = <0>;
status = "okay";
label = "SDHC0";
spi-max-frequency = <24000000>;
};
上面的dts内容解释如下:
- tf卡(SDHC)使用spi2作为通信接口
- spi2的pin配置情况是sck-31, mosi-2, miso-3,cs-pin30
- spi通信速率为24M
修改配置文件
配置文件prj.conf添加如下内容1
2
3
4
5
6CONFIG_SPI_2=y
CONFIG_SPI_2_NRF_SPI=y
CONFIG_DISK_ACCESS=y
CONFIG_DISK_ACCESS_SDHC=y
CONFIG_DISK_ACCESS_SPI_SDHC=y
CONFIG_DISK_SDHC_VOLUME_NAME="SD"
在zephyr 上面SDHC是专为disk access访问用的,因此必须同时配置启动DISK ACCESS
使用
配置
zephyr上SDHC被放入了disk access,因此我们可以直接搭配文件系统使用,这里配置为FAT1
2
3
4
5
6#使用文件系统
CONFIG_FILE_SYSTEM=y
#使用FAT文件系统
CONFIG_FAT_FILESYSTEM_ELM=y
#启动文件系统shell,可选如果只是代码使用文件系统可以不开这项
CONFIG_FILE_SYSTEM_SHELL=y
代码使用文件系统
在app中建立如下代码,可以访问TF卡,详细请看注释说明
初始化disk
1 | static const char *disk_pdrv = "SD"; |
Mount文件系统
1 | static const char *disk_mount_pt = "/SD:"; //mount点参看CONFIG_DISK_SDHC_VOLUME_NAME |
文件操作
统一的文件操作接口,可以参考如何使用Zephyr文件系统一文1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44int res;
struct fs_dir_t dirp;
static struct fs_dirent entry;
//开启mount点文件夹
res = fs_opendir(&dirp, disk_mount_pt);
if (res) {
printk("Error opening dir %s [%d]\n", disk_mount_pt, res);
return res;
}
//列出mount点文件夹下所有的文件
printk("\nListing dir %s ...\n", disk_mount_pt);
for (;;) {
/* Verify fs_readdir() */
res = fs_readdir(&dirp, &entry);
/* entry.name[0] == 0 means end-of-dir */
if (res || entry.name[0] == 0) {
break;
}
if (entry.type == FS_DIR_ENTRY_DIR) {
printk("[DIR ] %s\n", entry.name);
} else {
printk("[FILE] %s (size = %zu)\n",
entry.name, entry.size);
}
}
//关闭开启的文件夹
fs_closedir(&dirp);
//创建文件
res = fs_open(&file, "/SD:/log/file.log");
//seek到末尾
res =fs_seek(&file, 0, FS_SEEK_END);
//写文件
res = fs_write(&file, data, len);
printk("%02x ", data[0]);
//sync文件
fs_sync(&file);
//关闭文件
fs_close(&file);
示例log
前文代码示log例如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20[00:00:00.007,934] <inf> spi_nrfx_spi: CS control inhibited (no GPIO device)
[00:00:00.076,965] <inf> sdhc_spi: Found a ~30436 MiB SDHC card.
[00:00:00.078,460] <inf> sdhc_spi: Manufacturer ID=3 OEM='SD' Name='ACLCD' Revision=0x80 Serial=0x1bd93ca8
[00:00:00.078,491] <inf> fstest: Block count 62333952
Sector size 512
Memory Size(MB) 1764
Disk mounted.
Listing dir /SD: ...
[DIR ] LOST.DIR
[DIR ] ANDROI~1
[DIR ] ANDROID
[DIR ] DATAST~1
[DIR ] ICON_P~1
...
[DIR ] LSSPOR~1
[DIR ] LIFESE~1
[DIR ] RECORD~1
open file success.
shell使用文件系统
只要配置CONFIG_FILE_SYSTEM_SHELL后就可以通过shell来通过操作文件系统来读写TF卡,详细请参考如何使用Zephyr文件系统一文
其它事项
- 因为zephyr内没有直接提供创建文件系统的API,所以需要先将TF卡在电脑上格式化为FAT32格式
- 目前测试FAT32下创建文件夹比较慢
参考
http://elm-chan.org/docs/mmc/mmc_e.html
https://www.microchip.com/forums/m530149.aspx