注意:
这个问题是在《RT-Thread:让W25Q128、U盘、SD卡同时搭载文件系统
》博文的工程下发现并修复的。
一、问题现象
1、如果上电前不把SD卡插上就会无法识别,即使电前把SD卡插上并识别到SD卡,也不能二次拔插。
二、问题原因
1、在mmcsd_core.c下有一个mmcsd_detect线程,该线程用于对SD卡进行检测和初始化。一开始会检测mmcsd_detect_mb邮箱是否有数据,系统运行后sdio初始化完成后会在某个地方发送邮件,在这个线程触发对SD卡进行初始化,流程:首先检查host->card是否为空,空的话就直接进行初始化,反之就先删除,后面再等待mmcsd_detect_mb邮箱有数据后才进行对SD卡初始化。无论是删除还是初始化都能发现最后都使用mmcsd_hotpluge_mb发送邮件,这样设计很明显就是为了能让其他线程知道已经删除或者初始化完成。
通过全局搜索mmcsd_detect_mb很容易发现在调用这个函数可以进行发送邮件触发SD卡初始化程序。
通过全局搜索mmcsd_hotpluge_mb发现在只有mmcsd_wait_cd_changed函数对这个邮箱进行检测接收,而mmcsd_wait_cd_changed函数没被使用过。
3、全局搜索mmcsd_change函数,可以发现在sdio_host_create函数中调用了mmcsd_change,从名字可以判断出这个函数是系统启动的时候调用的,且只调用一次。重点在于mmcsd_change函数只有一处调用,所以我们上电前未插入SD卡,或者上电前插入SD卡后面拔出再插入都无法被识别到。完美…破案!!
三、解决方案
1、host被定义为静态,我们在其他文件使用不了,但是在全局搜索mmcsd_change函数的时候发现有一个stm32_mmcsd_change函数使用了mmcsd_change函数,而且是在.h文件里被声明了的,很明显是给我们外部调用的。
2、在sdcard.c文件中添加下面函数。这个函数首先发送邮件触发SD卡初始化或删除,因为一开始不知道SD卡是否处于已删除状态,如果是已删除那么第一次触发就可以让SD卡初始化完成直接退出,如果第一次触发是删除,接下来的再次触发就是初始化。初始化SD卡完成后我们再对SD卡进行挂载即可食用。
int sdcard_init(void)
{
int res = RT_EOK;
//触发SD卡初始化或SD卡删除
stm32_mmcsd_change();
if((res = mmcsd_wait_cd_changed(1000)) == -RT_ETIMEOUT)
return -1;
//检测是否初始化成功
if(res == MMCSD_HOST_UNPLUGED)
return RT_EOK;
//触发SD卡初始化
stm32_mmcsd_change();
if((res = mmcsd_wait_cd_changed(1000)) == -RT_ETIMEOUT)
return -2;
//检测是否初始化成功
if(res == MMCSD_HOST_UNPLUGED)
return RT_EOK;
return -3;
}
MSH_CMD_EXPORT(sdcard_init,sdcard init);