虽然我不觉得这有什么技术难度,因为微软已经把驱动做好了,但是有很多人问我这个问题,其实我也不知道该怎么回答你们。因为可能不同的厂家有不同的硬件中断映射的做法。这里我只是把我之前作完之后整理的笔记放在这里,希望对你们有帮助。
由于我所使用bsp包已经预先设定了系统中断,所以微软所提供的sd主控制驱动在动态分配系统中断时就会失败。修改的地方就是这里,去掉动态中断,在bsp中加入静态关联。基本上就是做这个工作。以下介绍一些这次修改中相关的内容:
首先要讨论中断:
#define SYSINTR_SDMMC_CARD_DETECT (SYSINTR_FIRMWARE+15) 用于发线sd卡的中断,实际中断号18在armint.c中定义并将中断与逻辑中断关联。
#define SYSINTR_SDMMC (SYSINTR_FIRMWARE+14) 实际中断号21在armint.c中定义并将中断与逻辑中断关联
#define SYSINTR_SDMMC_SDIO_INTERRUPT (SYSINTR_FIRMWARE+16) 实际中断号21在armint.c中定义并将中断与逻辑中断关联,但是这两个中断对应的系统中断不一样 。
对于sd 存储卡应该使用 SYSINTR_SDMMC 。所以导入sd主控制驱动的中断应该是它。dma0使用17--34。
这三个中断就是我老搞不清的地方。大家可以多看看硬件中断和系统中断之间的关系,这方面的资料上网查查就能看到。这里给大家一个简单的概念:针对于sd卡的硬件检测中断来说,不同的厂家板子可能设定的中断是不一样的,有的是18,有的是19,(三星的公板是18,所以大部分厂家都应该是18)。如果硬件中断不同就会造成上层驱动可能就会不同,然而只有中断号不同,其他的地方可能都相似或是相同,针对于这一点写不同的驱动有点浪费,所以出现了系统中断这个概念。当系统中断产生的时候,驱动才会工作。我们的驱动只认系统中断。
具体的过程就是sd卡插上之后,sd卡座上的11个管脚中有一个电平会变化(下面有说明)。2410芯片对这一变化产生硬件中断18,这个中断通知系统中断,系统中断通知驱动程序。对于不同的板子,系统中断是相同的,硬件中断可是不同的。只要在初始中断映射的时候将硬件中断与系统中断关联起来就好了。我的问题就是出现在这里。在微软的驱动里系统中断是动态分配的。但是这个动态分配的的系统中断号我的驱动每一次向系统申请都不成功(这里可能有很多原因:申请的系统中断已经被使用等等,我的能力有限,没有深入研究)。于是我就考虑在硬件中断与系统中断关联的时候,就直接静态申请。
接下来讨论sd卡:
sd卡使用的是中断18来发现卡的存在、使用中断21来作为sd卡的中断,17作为sd的dma0中断。
中断18来源于io口G10
中断17、21来源于中断寄存器。
使用io口E5-10连接sd卡:
5--SDCLK
6--SDCMD
7--SDDATA0
8--SDDATA1
9--SDDATA2
10--SDDATA3
通过G10与sd卡的nCD(10)交相连,检查sd是否插入。
驱动中有3个线程:
1 卡检测线程:用于检测卡目前所处状态。
2 dma传输线程:用于传输数据,采用4线制。
3 sdio中断线程:这个线程我还没搞清,它是专门服务于sdio,还是所有sd,但是好像运行中没问题,就没太研究它。
最后具体实现如下:
1 pb5.0更新微软的《Windows CE 5.0 支持仅 SD 1.1 兼容的内存卡所小于 2 GB
》中提到的更新2007年4月30号的那个。
2 工程里将 IMGSDBUS2 变量的值设置为 1。
3 直接加载CataLog里的sd memory以及samsung 2410 sdio host. 同时在
platform.bib中加入
; SD host
sdhc_sc2410.dll $(_FLATRELEASEDIR)/sdhc_sc2410.dll NK SH
4 注册表
修改
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SDHC_SC2410]
"Dll"="sdhc_sc2410.dll"
5 去掉SDIOControllerBase.cpp中的动态加载。(InterpretCapabilities( LPCTSTR pszRegistryPath )函数)
// read the SDIO SYSINTR value
m_dwSDIOIrq = regDevice.ValueDW( SDIO_IRQ_TEXT, 0xffffffff );
m_dwSDIOIrq=21;
if( m_dwSDIOIrq == 0xffffffff )
{
// invalid SDIO IRQ value!
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO IRQ value!/n")));
//RETAILMSG(1,(TEXT(" invalid SDIO IRQ value!/r/n")));
fRetVal = FALSE;
goto FUNCTION_EXIT;
}
// convert the SDI hardware IRQ into a logical SYSINTR value
m_dwSDIOSysIntr=30;
//RETAILMSG(1,(TEXT(" m_dwSDIOSysIntr : %d /n"), m_dwSDIOSysIntr));
/* if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_dwSDIOIrq, sizeof(DWORD), &m_dwSDIOSysIntr, sizeof(DWORD), NULL))
{
// invalid SDIO SYSINTR value!
*DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO SYSINTR value!/n")));
//RETAILMSG(1,(TEXT(" InterpretCapabilities invalid SDIO SYSINTR value!/r/n")));
//RETAILMSG(1,(TEXT(" m_dwSDIOIrq : %d /n"), m_dwSDIOIrq));
//RETAILMSG(1,(TEXT(" m_dwSDIOSysIntr : %d /n"), m_dwSDIOSysIntr));
m_dwSDIOSysIntr = SYSINTR_UNDEFINED;
fRetVal = FALSE;
// goto XIT;
goto FUNCTION_EXIT;
}*/
//RETAILMSG(1,(TEXT(" m_dwSDIOIrq : %d /n"), m_dwSDIOIrq));
// read the SDIO IST priority
m_nSDIOIstThreadPriority = regDevice.ValueDW( SDIO_IST_PRIORITY_TEXT, 0xffffffff );
// read the DMA channel number
m_dwDMAChannel = regDevice.ValueDW( DMA_CHANNEL_TEXT, 0xffffffff );
// read the DMA IRQ value
m_dwDMAIrq = regDevice.ValueDW( DMA_IRQ_TEXT, 0xffffffff );
m_dwDMAIrq = 17;
//RETAILMSG(1,(TEXT(" m_dwDMAIrq : %d /n"), m_dwDMAIrq));
if( m_dwDMAIrq == 0xffffffff )
{
// invalid DMA IRQ value!
m_dwDMAChannel = 0xffffffff; // disable DMA
}
m_dwDMASysIntr=34;
// convert the DMA hardware IRQ into a logical SYSINTR value.
/*if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_dwDMAIrq, sizeof(DWORD), &m_dwDMASysIntr, sizeof(DWORD), NULL))
{
// invalid DMA IRQ value!
m_dwDMAChannel = 0xffffffff; // disable DMA
//RETAILMSG(1,(TEXT("123-in CSDIOControllerBase::InterpretCapabilities invalid SDdma SYSINTR value!/r/n")));
//RETAILMSG(1,(TEXT("122-in CSDIOControllerBase::InterpretCapabilities m_dwDMAIrq : %d /n"), m_dwDMAIrq));
//RETAILMSG(1,(TEXT("122-in CSDIOControllerBase::InterpretCapabilities m_dwDMASysIntr : %d /n"), m_dwDMASysIntr));
}*/
//RETAILMSG(1,(TEXT(" m_dwDMASysIntr : %d /n"), m_dwDMASysIntr));
6然后对于sdhc协议的存储卡,要加一个命令响应:具体如下:
1)
sdhcslot.cpp里BusRequestHandler( PSD_BUS_REQUEST pRequest)函数有
case ResponseR7:
wRegCommand |= CMD_RESPONSE_R1_R5_R6_R7;
break;
2)
sdiocontrollerbase.cpp里SendCommand(UINT16 Cmd, UINT32 Arg, UINT16 respType, BOOL bDataTransfer)函数里在case ResponseR6:下面加case ResponseR7:
case ResponseR1: // Short response required
case ResponseR1b:
case ResponseR3:
case ResponseR4:
case ResponseR5:
case ResponseR6:
case ResponseR7:
DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("sendSDICommand short response required")));
// vm_pSDIReg->SDICCON = uiNewCmdRegVal | WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE);
vm_pSDIReg->SDICCON = WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE);
break;
3)
函数GetCommandResponse(PSD_BUS_REQUEST pRequest)中加在case ResponseR1b:下面
case ResponseR1:
case ResponseR1b:
case ResponseR7:
//--- SHORT RESPONSE (48 bits total)---
// Format: { START_BIT(1) | TRANSMISSION_BIT(1) | COMMAND_INDEX(6) | CARD_STATUS(32) | CRC7(7) | END_BIT(1) }
// NOTE: START_BIT and TRANSMISSION_BIT = 0, END_BIT = 1
//
*(respBuff ) = (BYTE)(START_BIT | TRANSMISSION_BIT | pRequest->CommandCode);
*(respBuff + 1) = (BYTE)(vm_pSDIReg->SDIRSP0 );
*(respBuff + 2) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 8 );
*(respBuff + 3) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 16);
*(respBuff + 4) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 24);
*(respBuff + 5) = (BYTE)(END_RESERVED | END_BIT);
break;
7 在bsp包的cfw.c文件中断初始化函数中加入静态关联(OEMInitInterrupts(void)函数)
OALIntrStaticTranslate(SYSINTR_SDMMC, INTSRC_MMC);
OALIntrStaticTranslate(SYSINTR_DMA0, INTSRC_DMA0);
OALIntrStaticTranslate(SYSINTR_SDMMC_CARD_DETECT, 18);
基本上就是这些,不过我觉得不同的板子可能有不同的问题。我所知道的有些人加上驱动根本不用修改就好用。所以可能大家的问题都不相同。而目前调试驱动的方法又很不方便,需要加很多调试语句来判断。所以刚入门的人应该多看看代码。我当时在所有关键代码上都加了调试语句,才大概了解程序是怎么走的,希望能对大家有一点帮助。现在由于工作的需要,已经不做arm了,小公司就是这样,让你干什么你就干什么,最后什么都干不精。
这篇文章可能有很多错误,请高手多多指教,初学者仅供参考!!