T 卡(SD 卡)¶
本文说明 Solution 工程中 T 卡的接入方式、设备注册逻辑、挂载关系以及插拔检测流程。这里的 T 卡既包括 SPI 模式下的 TF 卡,也包括 SDIO/SDHCI 模式下接入的 SD 卡。对应用层来说,最关键的是先确认“卡是否已注册为块设备”,再确认“文件系统是否已经挂载到 /external_sd”。
1. 参考代码¶
文件 |
作用 |
|---|---|
|
T 卡服务入口,负责插拔检测、状态同步和业务目录创建 |
|
T 卡路径、状态枚举和对外接口定义 |
|
TF 卡 OTA 包扫描、校验和安装流程 |
|
SPI 模式 TF/SD 卡驱动,将卡注册为 |
|
SDIO/SDHCI 模式下的卡识别流程 |
|
SDIO/SDHCI 模式下块设备注册、移除和卸载流程 |
|
T 卡检测脚、供电脚和设备名配置 |
|
SPI MSD 驱动配置项 |
2. 简介¶
T 卡在工程中最终会体现为两层结构:
块设备:SPI 方案通常注册为
sd0,SDIO 方案则使用host->name对应的设备名;文件系统挂载点:业务上通常使用
/external_sd作为根目录,music、video、ebook、photo、ota等目录都围绕这个挂载点展开。
因此,排查 T 卡问题时,建议按以下顺序进行:
设备有没有注册成功;
卡插拔有没有被检测到;
文件系统有没有挂载成功;
业务目录有没有创建出来。
对于应用开发者来说,真正需要关注的是:设备是否存在、挂载是否正常、读写是否可用,而不是只看底层驱动层面的实现细节。
4. 核心接入方式¶
4.1 SPI TF 卡¶
SPI 方案适合引脚资源紧张、仅需要基础读写能力的场景。当前代码中的初始化链路大致为:
查找名为
sdcard的 SPI 设备;若不存在,则将
sdcard绑定到spi1;打开 SPI 设备;
调用
msd_init("sd0", "sdcard")注册块设备;后续通过
sd0访问卡内容。
关键代码路径在 rt_spi_msd_init() 和 msd_init(),对应的是 SPI MSD 的标准初始化流程。
4.2 SDIO/SDHCI SD 卡¶
SDIO/SDHCI 方案使用芯片自带的 SDMMC 控制器,吞吐一般更高,也更适合标准 SD 卡场景。它不是由 spi_msd.c 直接注册设备,而是走 MMC/SD 框架:
检测到插卡事件后触发
mmcsd_detect();框架按检测顺序识别 SDCARD / EMMC / SDIO;
卡识别成功后,在
block_dev.c中注册块设备;设备名通常来自
host->name。
这类方案的特点是:卡的存在性判断依赖 MMC/SD 框架本身,而不是 T 卡服务层人为推断。
4.2.1 SD 卡切换 SDIO/SDHCI¶
58x / 57x / 55x / 56x 等平台通常支持两个 SDIO/SDHCI 设备,可用于 SD 卡接入。下面以 57x 平台中 SD 卡从 SDIO1 切换到 SDIO2 为例说明:
使能 SDIO2 总线,并将总线用途配置为
SDCARD;配置 TF 对应的 SDIO 总线为
sd1;修改
flashmap文件,将 TF 分区名称调整为SD1。



5. 初始化流程¶
5.1 SPI TF 卡¶
SPI TF 卡的关键初始化步骤如下:
rt_hw_spi_device_attach("spi1", "sdcard");
rt_device_t spi_dev = rt_device_find("sdcard");
rt_device_open(spi_dev, RT_DEVICE_FLAG_DMA_RX | RT_DEVICE_FLAG_DMA_TX | RT_DEVICE_FLAG_RDWR);
msd_init("sd0", "sdcard");
初始化完成后,系统中会出现一个名为 sd0 的块设备。驱动进行读写前还会进行状态更新;如果检测到卡已拔出,会直接返回失败,避免继续访问无效介质。
5.2 SDIO/SDHCI SD 卡¶
SDIO/SDHCI 路径下,卡识别交给 MMC/SD 框架。识别流程大致如下:
先通过
mmcsd_detect_orders决定优先检测类型;进入
MMCSD_HOST_DETECT_SDCARD分支后执行 SD 卡识别;识别成功后,
block_dev.c会把卡注册为块设备;设备名通常就是
host->name。
也就是说,SDIO 场景下“卡是否存在”主要取决于 MMC/SD 的识别结果,而不是 TF 服务组件单独判断。
6. TF 卡状态管理¶
6.1 TF 卡状态管理框图¶
SPI TF 卡通常仅有三种状态:MSD_CARD_STATUS_INVALID、MSD_CARD_STATUS_INACTIVE 和 MSD_CARD_STATUS_ACTIVE。其状态迁移逻辑可概括为:
开机时默认处于
MSD_CARD_STATUS_INVALID;上电初始化完成后切换到
MSD_CARD_STATUS_ACTIVE;待机时,掉电后切换到
MSD_CARD_STATUS_INACTIVE;唤醒后重新上电并恢复到
MSD_CARD_STATUS_ACTIVE;TF 卡拔除后切换为
MSD_CARD_STATUS_INVALID;重新插入并上电初始化完成后再切回
MSD_CARD_STATUS_ACTIVE。
6.2 SPI TF 设备状态管理¶
SPI TF 卡状态机变量通常位于 msd_device->status,状态枚举如下:
typedef enum
{
MSD_CARD_STATUS_UNKNOWN = 0, /**< unknown */
MSD_CARD_STATUS_INVALID, /**< TF card is invalid */
MSD_CARD_STATUS_INACTIVE, /**< TF card is inactive */
MSD_CARD_STATUS_ACTIVE, /**< TF card is active */
} msd_card_status;
状态管理接口示例:
void set_spi_msd_state(msd_card_status new_state);
msd_card_status get_spi_msd_state(void);
6.3 SDIO TF 卡设备状态管理¶
SDIO 卡状态机变量通常位于 sdio->state,状态枚举如下:
typedef enum
{
SDIO_STATE_UNKNOWN = 0,
SDIO_STATE_INVALID, /**< SDIO is invalid */
SDIO_STATE_INACTIVE, /**< SDIO is inactive */
SDIO_STATE_ACTIVE, /**< SDIO is active */
} sdio_state_t;
状态管理接口示例:
static void sifli_sdio_set_state(struct rthw_sdio *sdio, sdio_state_t new_state);
static sdio_state_t get_sifli_sdio_state(struct rthw_sdio *sdio);
7. 插拔检测¶
tf_init.c 中有一套统一的插拔处理逻辑:
GPIO 中断触发;
中断回调只负责释放信号量;
tf_task线程中做去抖和状态判断;根据当前状态调用插入或拔出处理。
代码中对检测脚的采样是两次比较,两个采样一致才会认为检测结果有效。当前实现中,检测脚低电平表示插入、高电平表示拔出,但最终仍要结合硬件电路和板级定义来判断。
7.1 插入时¶
SPI 方案:查找
sd0,如果尚未注册则初始化并注册;如果已有设备但状态无效,则尝试重新初始化。SDIO 方案:调用
mmcsd_change(host)触发重新识别,并等待设备就绪。
7.2 拔出时¶
SPI 方案:将
sd0状态标记为无效,阻止后续读写;SDIO 方案:注销对应块设备,并触发文件系统卸载流程。
8. 挂载和业务路径¶
tf_init.h 中定义了常见业务路径:
宏 |
路径 |
用途 |
|---|---|---|
|
|
T 卡根路径 |
|
|
音乐 |
|
|
视频 |
|
|
电子书 |
|
|
图片 |
|
|
TF OTA 升级包 |
T/SD 卡介质按 exFAT 格式使用,挂载点为 /external_sd。代码中仍通过 DFS 使用 ElmFat 挂载,工程需要开启 RT_DFS_ELM_USE_EXFAT。
这里需要注意:设备注册并不等于文件系统已经挂载成功。如果工程没有做自动挂载,则应在合适时机显式挂载,例如:
mkdir("/external_sd", 0);
dfs_mount("sd0", "/external_sd", "elm", 0, 0);
卸载时,通常需要先停止正在访问卡的业务,再执行卸载操作。
9. TF 卡的低功耗处理¶
9.1 SPI TF 卡低功耗¶
SPI TF 卡支持在读写后强制进入 idle,以降低空闲时功耗。系统待机时,如果不需要继续监测插拔,可以对 SPI TF 进行掉电处理。

实现方法如下:
睡眠时,在
BSP_SPI_MSD_Power_Down()中增加掉电逻辑,并将 TF 状态切换为MSD_CARD_STATUS_INACTIVE。
void BSP_SPI_MSD_Power_Down(void)
{
/* power off */
BSP_GPIO_Set(PIN_LCD_TF_POWER, 0, 1);
/* set state to inactive */
set_spi_msd_state(MSD_CARD_STATUS_INACTIVE);
}
唤醒后,在
BSP_SPI_MSD_Power_Up()中处理上电恢复,并在恢复过程中执行 TF 卡初始化。
void BSP_SPI_MSD_Power_Up(void)
{
/* power on */
if (!BSP_GPIO_Get(PIN_LCD_TF_POWER, 1))
{
BSP_GPIO_Set(PIN_LCD_TF_POWER, 1, 1);
HAL_Delay_us(50);
}
}
SPI TF 卡初始化分两类情况:
GUI 界面恢复完成后执行初始化;
读写接口在状态判断时,如果为
MSD_CARD_STATUS_INVALID,直接返回;如果为MSD_CARD_STATUS_INACTIVE,则执行初始化。
参考文件:app_pm.c 中 app_gui_pm_process(sleep_event_t event) 增加:
#ifdef MSD_INIT_ON_GUI_WAKEUP
extern void msd_request_reinit(void);
msd_request_reinit();
#endif
读写接口示例:
static rt_size_t rt_msd_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
/* if card removed, will return */
if (get_spi_msd_state() == MSD_CARD_STATUS_INVALID)
{
MSD_DEBUG("[err] SPI MSD is invalid!\r\n");
return 0;
}
if (get_spi_msd_state() == MSD_CARD_STATUS_INACTIVE)
{
#ifdef MSD_INIT_ON_GUI_WAKEUP
msd_request_reinit();
#endif
}
return 0;
}
static rt_size_t rt_msd_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
if (get_spi_msd_state() == MSD_CARD_STATUS_INVALID)
{
MSD_DEBUG("[err] SD card is invalid!\r\n");
return 0;
}
if (get_spi_msd_state() == MSD_CARD_STATUS_INACTIVE)
{
#ifdef MSD_INIT_ON_GUI_WAKEUP
msd_request_reinit();
#endif
}
return 0;
}
10. 快速上手¶
T 卡的验证顺序建议按下面的步骤进行:
在串口中查看设备列表,确认是否存在
sd0或对应 SDIO 设备;检查
/external_sd是否能正常访问,目录是否可列出;确认业务目录如
music、video、photo、ota是否存在;若需升级或读取文件,先确认文件系统和挂载状态正常,然后再操作。
10.1 常见日志¶
日志 |
含义 |
|---|---|
|
SPI 总线和 |
|
上电时检测到卡未插入,SPI MSD 初始化被跳过 |
|
SPI 模式卡初始化成功 |
|
|
|
SDIO 框架正在识别或已经识别成功 |
10.3 常见判定¶
设备列表无
sd0或主机名:通常是 SPI 绑定、Pinmux 或 SDIO 设备树配置有问题;卡已识别但无法访问挂载点:通常检查 FAT/ELM 文件系统是否成功挂载;
只识别不读写:需检查挂载参数、文件句柄是否释放、是否有读写权限问题;
热拔出后异常:需确认应用在拔卡前已停止读写,并按流程执行卸载。
11. 常见问题¶
11.1 找不到 sdcard¶
检查 SPI 总线名、Pinmux 配置和 rt_hw_spi_device_attach() 是否与实际硬件一致。
11.2 sd0 注册失败¶
检查卡座、供电、检测脚和 SPI 工作模式是否正确。若是 SDIO 路径,则需确认 SDMMC 控制器是否启用,以及卡类型是否正确识别。
11.3 只能识别不能读写¶
通常是文件系统格式不正确、挂载失败,或者有尚未关闭的文件句柄。建议先验证挂载点可否正常列目录,再继续读写。
11.4 热拔出后异常¶
拔卡前应先停止所有访问,再触发卸载流程,避免文件系统处于脏状态。
12. 说明¶
SPI TF 卡和 SDIO SD 卡的底层接法不同,但上层业务最终都应统一到“先确认卡存在,再访问挂载点”的思路。
当前代码里,SPI 方案默认使用
spi1、sdcard和sd0;SDIO 方案则更依赖host->name。/external_sd、music、video、ebook、photo、ota等目录是工程里已约定好的业务路径,实际挂载点和文件结构应与板级配置保持一致。对于 T 卡相关开发,最稳妥的排查方法是:先看“块设备是否存在”,再看“挂载点是否正常”,最后看“业务目录和文件操作是否正常”。
13. 结论¶
TF 卡的状态管理本质上是一个典型的三态生命周期:
MSD_CARD_STATUS_INVALID:未插入或已拔出,设备不可用;MSD_CARD_STATUS_INACTIVE:已掉电或休眠状态,需在唤醒/重入时恢复;MSD_CARD_STATUS_ACTIVE:卡已正常初始化并可供业务访问。
在实际开发中,关键不是单纯监测卡是否存在,而是统一管理“状态机 + 挂载点 + 插拔检测”三者之间的关系,避免在休眠、唤醒或热插拔场景中出现误判或访问无效块设备。