[ZLG-ARM] wince SD卡驱动开发

[复制链接]
 楼主| armqt 发表于 2009-7-3 13:56 | 显示全部楼层 |阅读模式
1、&nbsp;WINCE&nbsp;下的SD卡驱动架构<br /><br />Wince&nbsp;下SD卡驱动协议栈组成&nbsp;:<br /><br />HOST硬件底层部分&nbsp;(主控制端驱动)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SDHC_XXX.DLL<br /><br />BUS&nbsp;中间逻辑命令层&nbsp;(总线驱动)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SDBUS.DLL<br /><br />CLIENT上层(客户端驱动)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SDMEMORY.DLL<br /><br />主控制端驱动<br /><br />&nbsp;&nbsp;&nbsp;主控制端驱动控制包含主控制器硬件,遵循主控制端驱动接口,它被用于总线驱动通信和设置操作参数。主控制器驱动接口提供一个硬件提取层,在总线和主控制端执行之间。即:SDHC_XXX.DLL是最底层,因为这层是硬件关联层,因此取名XXX便是为了对应的具体的硬件BSP包(如本项目的硬件平台是ZYLONITE,其硬件供应商给的BSP包名即为ZYLONITE,在实际项目中我们便将SDHC_XXX.DLL取代为SDHC_ZYLONITE.DLL),它负责具体的发命令,大多数情况下都需要修改。<br /><br />总线驱动<br /><br />&nbsp;&nbsp;&nbsp;总线驱动作为提取和管理层处于主控制驱动和客户端驱动之间。它包括在SDbus.dll文件。为客户端驱动提供了标准的API,允许运行在任何的基于windows&nbsp;ce设备。总线驱动将是独立于应用程序和主控制端驱动,在不同的处理器之间移植,并不需要改动。SDBus.dll是中间层,负责整合命令和管理。<br /><br />客户端驱动<br /><br />&nbsp;&nbsp;&nbsp;客户端驱动和SD客户端驱动通信接口允许客户端驱动去和SD设备通信。客户端驱动接口是有计划地抽象SD总线物理设备的执行,提供了客户端驱动最大的弹性。客户端驱动接口允许客户端驱动去衡量一个单一的,同步的访问存储卡驱动使用一个线程,异步通信设备驱动。SDMemory.dll是最高层,类似于应用层。<br /><br />2.立足微软SD卡协议栈开发Zylonite&nbsp;的BSP包的SD卡驱动<br /><br />当我们开发SD卡驱动时,并详细分析比较了Microsoft的SD驱动架构和Intel所提供的BSP内的参考SD卡驱动以后,可以得出如下结论:<br /><br />针对主控制端驱动(SDHC_XXX.DLL):因为这一层是直接操作硬件的一层,所以大多数情况下都需要修改。修改的内容基本为收发命令部分以及数据传输和硬件初始化部分.<br /><br />针对总线驱动(SDBUS.DLL):因为这一层处于主控制驱动和客户端驱动之间,用于他们之间的通信,SD卡总线请求都放在它里面,微软提供了非常完备的样例代码,所以我们一般都不需要改动,直接调用它的接口就可以了。<br /><br />针对客户端驱动(&nbsp;SDMEMORY.DLL):因为SDMemory就是所谓的Client层,类似于应用层,它还可用来识别卡的,不同种类的卡,比如sd&nbsp;memory&nbsp;card等,鉴于我们只需开发SD卡部分的驱动,所以也不需要怎么修改了(如果我要开发SD接口的SDIO设备,那么就得在这层做比较大的改动了)。<br /><br />Intel所提供的BSP内的参考SD卡驱动自己实现了主控制端驱动(SDHC_ZYLONITE.DLL),而调用并保留了总线驱动(SDBUS.DLL)和客户端驱动(&nbsp;SDMEMORY.DLL)。因此结合具体的硬件设计(SD卡的CONNECTOR等),我们的主要任务便是利用BSP内的SD卡主控制端驱动代码,开发(配置并改进)我们实际项目内的SD卡驱动。<br /><br />Zylonite&nbsp;BSP内的SD卡主控制端驱动概述<br /><br />SD卡的驱动程序是以流的形式提供的,而该SD卡主控制端驱动以sdhc_zylonite.dll&nbsp;的形式提供,入口在:&nbsp;WINCE500PLATFORMylonitepubliccspmonahanssdhc<br /><br />有如下两个文件:<br /><br />sdcontrol.c:内含一个非常重要的线程---SDControllerISTHandler,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主要负责卡与控制器的交互,处理控制器接收的消息等,具体的控制和处理函数均在此文件中。<br /><br />main.c:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SDH(主控制端驱动)的导出流接口在该文件中实现,并包含有主控制端驱动的(sdhc_zylonite.dll)的入口点。&nbsp;<br /><br />SD卡硬件初始化及其主控制端驱动的注册表信息设置路径为:<br /><br />WINCE500PLATFORMylonitePlatformYLONITESRCDRIVERSSDHC<br /><br />主要文件为:<br /><br />impl.c:&nbsp;主要是在加载SD卡主控制端驱动时初始化硬件。内含一个非&nbsp;<br /><br />常重要的线程----&nbsp;SDCardDetectIstThread,专门处理SD卡的插拔操作。但是具体的插拔操作也是在Sdcontrol.c文件实现的。<br /><br />SD卡的外部引脚及功能配置<br /><br />在实际项目(一款以WINCE为操作系统内核的GSM/PHS双模智能手机)中,SD卡的外部引脚与Monahans_L的GPIO连接图及连接控制器的电路图如下所示:<br /><br />先要配置SD卡的外部引脚及功能。而SD卡的引脚配置在其下的&nbsp;source&nbsp;文件夹的xllp_mmc_board.c文件XllpMMCConfigure函数内修改。(特别注意:GPIO34要配成检测SD卡插入的中断源。)<br /><br />分析修改并改进主控制端驱动重要线程及硬件初始化部分代码<br /><br />SD卡主控制端驱动加载及架构解析<br /><br />需要声明的是SD卡驱动加载顺序是:<br /><br />加载SDBus.dll→加载sdhc_zylonite.dll→加载sdmemory.dll<br /><br />我们在这里只详细讨论第2步(sdhc_zylonite.dll的加载),此时SDBus.dll已经加载成功。WINCE系统初始化后,会载入DEVICE.EXE,&nbsp;对应代码devload.C中的WINMAIN函数会被调用起来,从而启动InitDevice函数,此函数会搜寻(WINCE500PLATFORMylonitePlatformYLONITESRCDRIVERSSDHC下的sdhc_zylonite.reg)注册表根键,准备参数调用WIN32&nbsp;API接口-----Activedevice,接着利用Dllmaincrtstartup函数找到sdhc_zylonite.dll的入口,执行该文件的入口函数DllMain()然后继续返回到DEVICE.EXE(devload.C),调用launchdevice()函数,再调用sdhc_zylonite.dll的入口main.c文件内的SDH_Init(),自此将开始将开始SD卡主控制端驱动的初始化过程:<br /><br />1.&nbsp;调用SDH_Init()&nbsp;<br /><br />2.&nbsp;调用&nbsp;SDHCDAllocateContext()&nbsp;来分配一段主控制器的上下文&nbsp;a)Context&nbsp;是总线驱动和主控制端驱动共享的&nbsp;<br /><br />3.&nbsp;主控制端驱动使用SDHCDSetXxx宏来填充这个上下文结构&nbsp;<br /><br />a)这个步骤是把主控制器向总线驱动描述一下&nbsp;<br /><br />b)包括函数指针,支持的电流,最大时钟,槽数目,SDIO的支持等等。&nbsp;<br /><br />4.&nbsp;调用&nbsp;SDHCDRegisterHostController()&nbsp;来把自己向总线驱动注册一下&nbsp;<br /><br />5.&nbsp;当总线驱动准备处理SD事件时,它会调用主控制端驱动的init&nbsp;函数(pContext-&gtpInitHandler)&nbsp;<br /><br />接着便是sdbus.dll驱动部分的代码和SD卡主控制端驱动部分的交互设置:比如设置电源、时钟和总线宽度等。一般都是sdbus.dll发起请求,再去调用主控制端驱动部分的API,这里最后详细分析插槽状态交互确认,因为这是成功加载sdhc_zylonite.dll的关键。当有SD卡在插槽,sdbus.dll的slotstatuschange()调用并建立一个重要线程SDcardDetectIstThread(),当探测到有卡,即返回给sdbus.dll,&nbsp;总线驱动即可调用HandleAddDevice()函数,自此初始化结束,sdhc_zylonite.dll加载成功。<br /><br />对主控制端驱动重要线程SDcardDetectIstThread()代码的改进<br /><br />在前面的叙述中,可以看出线程SDcardDetectIstThread()在sdhc_zylonite.dll最后的加载起决定性作用。然而我们发现在INTEL所给的BSP中,在检测卡的过程里,其采用了轮询的方式----即每隔一定的时间,CPU都会去读一次GPIO34的电平,以确定SD卡是否被插入或拔出,以此来判定是否去加载或卸载SD卡的客户端和主控制端驱动。很显然,这种方式的弊端是占用了过多的CPU资源,效率很低,严重影响了整个系统的实时性。因此,最能解决这个问题的办法无外乎是使用中断检测的方式。中断绑定静态配置:<br /><br />1.在Bsp_cfg.h文件内定义一个系统中断号SYSINTR_SDMMC_DETECT<br /><br />#define&nbsp;SYSINTR_SDMMC_DETECT&nbsp;(SYSINTR_FIRMWARE+N)&nbsp;N为当前已定义的最大值(以保证此中断未使用过)。<br /><br />2.在Xllp_gpio_plat.h文件中找出GPIO34的定义:#define&nbsp;XLLP_GPIO_MMC_CD_0&nbsp;34<br /><br />3.在intr.c文件里将系统中断号和IRQ关联:<br /><br />OALIntrStaticTranslate(SYSINTR_SDMMC_DETECT,&nbsp;IRQ_GPIO_SHARE(XLLP_GPIO_MMC_CD_0));<br /><br />4.在主控制端驱动的硬件初始化代码Impl.c中的InitializeHardware()加入&nbsp;EnablesdcardInterrupt()函数。<br /><br />5.在Impl.c中完善EnablesdcardInterrupt(),加入GPIO上升沿或下降沿的检测和SET&nbsp;EVENT。&nbsp;&nbsp;&nbsp;<br /><br />6.在Impl.c文件中定义hCardInsertInterruptEvent并在SetupCardDetectIST()内创建hCardInsertInterruptEvent<br /><br />7.Impl.c文件中初始化dwSysintrCD=&nbsp;SYSINTR_SDMMC_DETECT,并绑定相应的EVENT:InterruptInitialize&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(dwSysintrCD,hCardInsertInterruptEvent,NULL,0)<br /><br />8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;改进线程SDcardDetectIstThread()的While部分代码,加入WaitForSingleObject(&nbsp;hCardInsertInterruptEvent,&nbsp;dwTimeout&nbsp;);只有当hCardInsertInterruptEvent被置上,才会往下走,否则一直在此处等待。<br /><br />9.同上原理改写CardremoveInterrupt用于动态卸载SD卡主控制端驱动。<br /><br />
qtopia 发表于 2009-7-4 12:47 | 显示全部楼层

只会Linux

  
tmake 发表于 2009-7-9 13:33 | 显示全部楼层

SD现在应用非常广泛啊

  
 楼主| armqt 发表于 2009-7-24 18:13 | 显示全部楼层

是啊

  
孤独行者 发表于 2009-7-25 18:03 | 显示全部楼层

不是很明白,有待深入了解
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

150

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部