嵌入式技术论坛
直播中

王波

7年用户 1437经验值
私信 关注
[经验]

为什么要选择基于rt-thread开发板制作SD卡的热插拔功能呢

我这个SD卡的热插拔功能是基于“...
t-threadspSTM32stm32f469-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 detection 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已注册

更多回帖

发帖
×
20
完善资料,
赚取积分