T-Flash卡热插拔案例分析

来源:互联网 发布:插画软件sai 编辑:程序博客网 时间:2024/05/22 00:39

 

转载时请注明出处和作者联系方式

文章出处:http://blog.csdn.net/Victor_1

作者联系方式:冰心明悦 <mingfucui at gmail dot com>

 

【摘要】

 

本文主要分析和讨论在智能手机中实现T-Flash卡热插拔的三种方法:单线热插拔、带检测信号线的四线热插拔和不带检测信号线的四线热插拔。其中单线热插拔,使用数据线3作为卡的检测口,数据线的传输宽度为1,此种方法简单、方便容易实现,但其速度受到限制。带检测信号线的四线热插拔方式,使用的是卡槽中的一个检测位来检测卡的存在与否,此种方法在实现热插拔的同时最大限度的提高了卡的读写速度,但其需要额外的机械装置和硬件支持。第三种方法,使用不带检测信号线的四线热插拔方法,综合考虑了第一种和第二种方法的优点,避免了其缺点,动态使用数据线3的卡检测功能和数据传输功能,使其综合性能达到最优。

一、问题的提出

现在的手机不仅仅满足其通话和短消息的功能,其娱乐性和可扩展性越来越多的受到人们的重视,例如:audiovideogps和移动办公等等。在这种广大的需求面前同时对手机的性能提出了更高的要求,要求其处理速度要快,存储容量要大,安全性要好。对于存储容量的要求,最佳的方法就是使用外接的扩展卡,其中T-Flash卡是一种很好的选择,其成本较低,安全性好,同时可以通过读卡器和PC机交互,从而得到了很好的应用。但我们现有的智能手机,如***虽然支持T-Flash卡,但并不能满足其热插拔的要求,不方便用户使用。而其同类的产品,如moto系列、多普达系列等等都是支持T-Flash卡的热插拔功能,所以为了提高公司产品的竞争力,我们在今后的产品中必须添加T-Flash卡的热插拔功能。

二、解决思路

   卡的插入和拔出是通过连接在检测位上GPIO的电平状态来通知系统的。系统根据其具体的状态来判别是插入还是拔出,然后通过设置标志位,调用系统脚本hotplug来实现卡的mountumount操作,更新文件系统的状态,实现卡的热插拔操作。其处理流程如下图1所示:

 

1.       定义检测GPIO口,通过该位的状态来标识卡的插入或拔出操作。

2.       设置GPIO口开中断标志,设置上升沿和下降沿中断触发,其中上升沿触发表示插入操作,下降沿触发表示拔出操作。

3.       在系统中注册中断函数来具体响应中断过程。 

4.       中断处理函数的实现,判断是否是有效中断和区别插入还是拔出,然后设置标志。其具体实现还要根据原来卡槽中的状态和当前卡槽中的状态来判定:(如下表所示)

原来

现在

无卡

0

有卡

1

无卡

0

无卡

00

拔出

10

有卡

1

插入

01

有卡

11

原来卡槽的状态通过记录标识符而产生,每次插入或者拔出时进行改变;现在是否有卡通过GPIO检测位的电平状态产生,然后通过原来状态和当前状态的组合,来判断是卡的插入还是拔出,或者无变化。

5.       调用hotplug系统脚本,来具体实现看的mountumount操作,实现卡的插入和拔出操作。

三、实践情况

首先定义热插拔的处理模块,如下图2所示,其中注册中断函数是在设备初始化的时候进行注册;然后分别介绍三种在现有平台上实现T-Flash卡的热插拔操作的具体处理流程:

 

1.       单线热插拔模式:使用T-Flash卡的Data3引脚来检测卡的状态,此时Data3为通用GPIO口,用来产生中断,告知系统卡的状态,数据传输的宽度为1位。如图3所示

2.       带检测信号线的四线热插拔模式:即另外配置一个检测中断位,来代替方法1Data3功能。这个中断位一般是安装在卡槽上的机械装置,同样系统要根据该位的状态来确定是否有卡的插入和拔出操作。此种情况的数据宽度可以为4位。如图4所示

 

3.       不带检测信号线的四线热插拔模式:即动态使用Data3的检测功能和数据传输功能。其基本思路是,当没有命令传输时将Data3设置为通用检测gpio口,此时在等待检测热插拔;当有命令传输时将data3关闭检测功能作为数据线,传输数据。此种方法的数据宽度为4位。如图5

 

 

四、效果评价

试验证明分时使用Data3的检测功能和数据传输功能,既可以实现热插拔的检测又可以满足其速度的要求,使手机的功能和性能都得到了满足。

五、推广建议

以往T-Flash卡的热插拔操作,要么使用方法一,单线热插拔,但其速度受到影响;要么使用方法二,速度虽然得到了保证,但其多了一个结构件,增加了硬件成本。使用文中介绍的第三种方法,在不影响速度和不增加成本的情况下,最大程度的满足了功能和性能的要求。这不仅仅在智能手机平台中得到很好的使用,其他平台也有其借鉴意义。最大限度的在满足功能和性能的要求下,用软件代替硬件,节约成本。

参考资料

1.  Intel® PXA27x Processor Family Developer’s Manual     January 2006

2.  SanDisk Secure Digital Card Product Manual  Version 1.9  Document No. 80-13-00169

December 2003

3.  SD Memory Card Specification  Version 1.0  March 2000

4.  Moto A1200 代码

 

 

—— ——

 

附录:部分实现代码

下面以linux的代码为例介绍其具体实现

  1. 公共部分

a.设置检测GPIO

#define GPIO_HOTPLUG_DETECT ***

b.开中断

  set_GPIO_IRQ_edge(GPIO_HOTPLUG_DETECT, GPIO_FALLING_EDGE | GPIO_RISING_EDGE);

c.注册中断函数

  retval = request_irq(GPIO_2_80_TO_IRQ(GPIO_HOTPLUG_DETECT), mstone_detect_int,

                                         SA_INTERRUPT | SA_SAMPLE_RANDOM,

                                         "MMC card detect", (void *)1);

if (retval) {

                        printk(KERN_ERR "MMC/SD: can't request MMC card detect IRQ/n");

                        bvd_mmc_slot_cleanup();

                        return -1;

            }

d.中断处理函数的实现

  static int mstone_mmc_slot_is_empty(int slot)

{

            /* Check MSCRD for MMC card detection ([1], 3.2.2.7) */

#ifdef HOTPLUG_MMC

       GPDR(GPIO_HOTPLUG_DETECT) &= ~GPIO_bit(GPIO_HOTPLUG_DETECT);

              GAFR(GPIO_HOTPLUG_DETECT) &= 0x3FFFFFFF;//~(3<<((111%16)<<1));  

                  udelay(50);

            /* set it in, gpio func */

            printk( (GPLR3 & 0x8000)!=0? "Card inserted/n": "Card empty/n");

            mmc_not_inserted =  ((GPLR3 & 0x8000)!=0)?0:1;

#endif

 

            return mmc_not_inserted;

}

 

  static void mstone_detect_handler(unsigned long data)

{

            int empty;

            DEBUG(2, "card detect handler/n");

            empty = mstone_mmc_slot_is_empty(0);

            if (slot_state == MMC_CARD_INSERTED && empty) {

                        DEBUG(3, "no card in slot/n");

                        mstone_mmc_slot_down();

                        mmc_eject(0);

            } else if (slot_state == MMC_CARD_REMOVED && !empty) {

                        DEBUG(3, "found the card in slot/n");

                        mstone_mmc_slot_up();

                        mmc_insert(0);

            }

}

 

static void mstone_detect_int(int irq, void *dev, struct pt_regs *regs)

{

            DEBUG(2, "card detect IRQ/n");

            mod_timer(&mstone_detection, jiffies + HZ);

}

e.调用hotplug脚本

static void run_sbin_hotplug(struct mmc_dev *dev, int id, int insert)

{

            int i;

            char *argv[3], *envp[8];

            char media[64], slotnum[16];

 

            if (!hotplug_path[0])

                        return;

 

            DEBUG(0,": hotplug_path=%s id=%d insert=%d/n", hotplug_path, id, insert);

 

            i = 0;

            argv[i++] = hotplug_path;

            argv[i++] = "mmc";

            argv[i] = 0;

 

            /* minimal command environment */

            i = 0;

            envp[i++] = "HOME=/";

            envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

           

            /* other stuff we want to pass to /sbin/hotplug */

            sprintf(slotnum, "SLOT=%d", id );

            if ( dev->slot[id].media_driver && dev->slot[id].media_driver->name )

                        sprintf(media, "MEDIA=%s", dev->slot[id].media_driver->name );

            else

                        sprintf(media, "MEDIA=unknown");

 

            envp[i++] = slotnum;

            envp[i++] = media;

 

            if (insert)

                        envp[i++] = "ACTION=add";

            else

                        envp[i++] = "ACTION=remove";

            envp[i] = 0;

 

            call_usermodehelper (argv [0], argv, envp);

}

  1. 各自的具体实现

a.  方法一(单线热插拔)

(1)     初始化数据线的宽度,设置为1位,仅仅初始化数据线0

   set_GPIO_mode(92  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);   //Data0

(2)     同时要设置寄存器来确定是按照1位的数据宽度来传输数据的

   mmc_simple_cmd(dev, SET_BUS_WIDTH,  0, RESPONSE_R1);

b. 方法二(带检测信号线的四线热插拔)

(1)     初始化4位数据线宽度

   set_GPIO_mode(92  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);  //Data0

   set_GPIO_mode(109  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);//Data1

   set_GPIO_mode(110  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);//Data2

   set_GPIO_mode(111  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);//Data3 

(2)     设置寄存器来确定是按照4位的数据宽度来传输数据的

   mmc_simple_cmd(dev, SET_BUS_WIDTH,  2, RESPONSE_R1);

c.  方法三 (不带检测信号线的四线热插拔)

(1)     同方法二配置和初始化相同,唯一的不同在于检测位仍旧使用Data3

(2)     动态配置Data3的检测功能和数据传输功能

a)      函数static int mmc_has_valid_request( struct mmc_dev *dev )

表示开中断,启动热插拔功能,单线传输

if ( !request ) {

                 bit_width_flag = 0;

                 GPDR(111) &= ~GPIO_bit(111);

                GAFR(111) &= 0x3FFFFFFF;//~(3<<((111%16)<<1));  

                 GRER3 |= 0x8000;

                 GFER3 |=  0x8000;

                return 0;

                }

    表示关闭中断检测,四线传输数据

          bit_width_flag = 1;

          GRER3 &= 0x1FF7FFF;

          GFER3 &=  0x1FF7FFF;

          set_GPIO_mode(111  | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);//for 4-bits

b)       函数static void mstone_detect_int(int irq, void *dev, struct pt_regs *regs)

中的修改,表示关闭中断,打开四线传输功能。

bit_width_flag = 1;

GRER3 &= 0x1FF7FFF;

GFER3 &=  0x1FF7FFF;

c)      添加数据宽度的记录标志bit_width_flag,并在函数

static int bvd_mmc_exec_command(struct mmc_request *request)中添加命令

        if (bit_width_flag)

              cmdat |= MMC_CMDAT_SD_4DAT;

 

 

 

 

 

 

 

 

原创粉丝点击