我这个SD卡的热插拔功能是基于“...
t-threadsp
STM32stm32f469-st-disco”
开发板制作的,为什么选择这款开发板制作SD卡的热插拔,请听我慢慢道来。
昨天,看到RT-Thread的GitHub上有个issue,,描述如图1:
图1 issue
于是乎萌生出解决它的想法,想到就去做了。
我的思路很简单,通过检测SD卡的check pin脚的电平边沿变化来检测SD卡时候插入和拔出。不过这个思路是有局限性的,因为有些板子的check pin是悬空的,并没有接在stm32的任何脚上,这种情况下,使用上面所述的方法进行热插拔检测就不可行了。比方说,野火的F429挑战者开发板,它的SD卡的check pin就是悬空的,如图2所示:
图2 野火挑战者板子的SD卡原理图
刚好,ST官方的F469-DISCO开发板的check pin是接到PG2上的,可用上述方法实现热插拔,如图3所示:
图3 ST-F469-DISCO板子的SD卡原理图
废话不多说,先把代码po上来,代码如下
#include
#ifdef BSP_USING_SDCARD
#include
#include
#include
#include "drv_gpio.h"
#include "drv_sdio.h"
#define DBG_TAG "app.card"
#define DBG_LVL DBG_INFO
#include
/* SD Card hot plug detec
tion pin */
#define SD_CHECK_PIN GET_PIN(G, 2)
static void _sdcard_mount(void)
{
rt_device_t device;
device = rt_device_find("sd0");
if (device == NULL)
{
mmcsd_wait_cd_changed(0);
stm32_mmcsd_change();
mmcsd_wait_cd_changed(RT_WAITING_FOREVER);
device = rt_device_find("sd0");
}
if (device != RT_NULL)
{
if (dfs_mount("sd0", "/", "elm", 0, 0) == RT_EOK)
{
LOG_I("sd card mount to '/'");
}
else
{
LOG_W("sd card mount to '/' failed!");
}
}
}
static void _sdcard_unmount(void)
{
rt_thread_mdelay(200);
dfs_unmount("/");
LOG_I("Unmount "/"");
mmcsd_wait_cd_changed(0);
stm32_mmcsd_change();
mmcsd_wait_cd_changed(RT_WAITING_FOREVER);
}
static void sd_mount(void *parameter)
{
rt_uint8_t re_sd_check = 1;
while (1)
{
rt_thread_mdelay(200);
if(re_sd_check && !rt_pin_read(SD_CHECK_PIN))
{
_sdcard_mount();
}
if (!re_sd_check && rt_pin_read(SD_CHECK_PIN))
{
_sdcard_unmount();
}
re_sd_check = rt_pin_read(SD_CHECK_PIN);
}
}
int stm32_sdcard_mount(void)
{
rt_thread_t tid;
rt_pin_mode(SD_CHECK_PIN, PIN_MODE_INPUT_PULLUP);
tid = rt_thread_create("sd_mount", sd_mount, RT_NULL,
1024, RT_THREAD_PRIORITY_MAX - 1, 20);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
}
else
{
LOG_E("create sd_mount thread err!");
}
return RT_EOK;
}
INIT_APP_EXPORT(stm32_sdcard_mount);
#endif /* BSP_USING_SDCARD */
上面的代码中最关键的代码是54行~71行,也就是“static void sd_mount(void *parameter)”这个线程入口函数。
这里解读一下这个函数,这个函数读懂了,热插拔检测思路就清楚了:
1、首先,对于ST-F469-DISCO这个板子,当SD卡插进去的时候,check pin是低电平,不插的时候check pin是高电平,这一点可以通过观察图3得知。
2、在这段代码里,SD卡热插拔检测放在了一个线程入口函数里面去执行,通过高低电平的边沿检测来实现热插拔检测,“rt_uint8_t re_sd_check = 1”的作用是为了让SD卡在未上电的时候已经插进去了这种情况下制造电平边沿用的。因为如果SD卡一直插着,是没有电平变化的,“rt_uint8_t re_sd_check = 1”就是为了手动制造一个电平变化出来。否则无法通过if语言的电平边沿检测,也就是说无法执行“_sdcard_mount()”。需要注意的是,这段代码中的两个if语句之后都会跟着一个“re_sd_check = rt_pin_read(SD_CHECK_PIN)”去记录上次的的电平值。
3、在上电后SD卡拔出的这种情况下,电平变化是从低电平跳变至高电平,此时第二个if语句“!re_sd_check && rt_pin_read(SD_CHECK_PIN)”为真,执行“_sdcard_unmount()”。
4、在上电后SD卡插进卡槽的这种情况下,电平变化是从高电平跳变至于低电平,此时第一个if语句“re_sd_check && !rt_pin_read(SD_CHECK_PIN)”为真,执行“_sdcard_mount()”。
5、没有第五点了,说完了。这就是原理。
热插拔检测原理说完了,理解清楚的话,_sdcard_unmount()和_sdcard_mount()就更好理解了,这两部分这里不作解释,各位自行读代码吧。
我们来看看热插拔检测的结果吧。
SD卡不插,板子上电,msh输出的只有RTT版本号:
图4 SD卡不插
SD卡未上电的时候就一直插着的,板子上电之后,msh输出信息如下:
图5 SD卡插着上电
SD卡连续插拔,msh输出信息如下:
图6 插拔插拔插拔...
SD卡拔出来之后,在msh上输入list_device查看已注册设备,并没有sd0,如图7所示:
图7 没有sd0
SD卡插进去之后,在msh上输入list_device查看已注册设备,sd0出来了,如图8所示:
图8 sd0已注册