一、项目硬件环境 S3C2442 + DM9000A + WINCE 5.0 其中DM9000采用EINT1,接到片选NGCS7(0X20000000)
二、驱动结构 DM9000和CS8900驱动不一样。 在EBOOT中,由于没有用到中断和协议,下载NK只是建立TFTP服务(EBOOT建立),然后通过DM9000收发数据。因此,在S3C的BSP包中,EBOOT调用的DM9000收发的函数在BSP\Src\common\Dm9000a\Dm9000a.c文件中。即,EBOOT完全与驱动分开。 驱动的结构。驱动主要包含三个文件:driver.cpp、device.cpp、dm9000.cpp。 可以把三个文件看成三层结构。最上面是driver.cpp,然后是device.cpp,最下面是dm9000.cpp。他们之间driver.cpp提供NDIS微端口函数,这些微端口函数调用device.cpp, device.cpp和dm9000.cpp通过类的继承相关联。dm9000.cpp则是完成收发的基本的驱动部分。
三、调试现象与问题描述(以时间为顺序) 最开始从EBOOT开始调试。首先遇到的问题是DM9000能读到ID号,但是通过PB下载时显示不出平台名字,通过抓包工具检测到DM9000不能发送和接受数据包,用示波器打INT脚的波形也看不到中断。后来发现是DM9000的RX没有打开,并且RX和TX的中断也没有打开。(由此可见,官方网站的BSP包不一定可靠。) 能够使用EBOOT下载NK镜像后至少证明DM9000和S3C2442能够通讯,即硬件上没有问题。(这个时候公司开始投PCB板量产)接下来的工作是DM9000驱动的调试。 直接采用官方的BSP包,修改INDEX和DATA的地址后编译。DM9000无中断产生。后来发现是中断GPIO的触发电平设置不正确。(这里的触发电平与DM9000的SSCK管脚的上下拉有关)。修改后中断能触发。系统异常,后来发现是DM9000的中断处理函数不正常。该中断处理程序由Dm9000a.c中的DeviceInterruptEventHandler函数完成相关工作。进一步跟踪发现,NSR寄存器的读操作并没有将其清零(DM9000A手册中写明读或写1至NSR会使其相应位清零),因此驱动将TXbuffer可用的消息发个上层NDIS时,NDIS检测实际上没有空间可用,于是产生异常。 另外,本平台未接EEPROM,因此,MAC地址需要自己设置。 至此,驱动调试完毕。 PS:驱动中有一个比较关键的函数完成注册驱动的功能(NdisMRegisterInterrupt) 该函数的参数以及具体的用法参考网上资料。
四、修改的地方: 1. OEM层的中断处理函数OEMInterruptHandler (该函数位于BSP\Src\common\Intr\Intr.c文件中) 在本次项目中网口中断使用EINT1,在原三星的BSP包中在OEM层未对该中断进行处理,一般来说,当中断触发后,首先执行OEMInterruptHandler,然后根据返回的系统中断号,转入相对应的IRQ程序。OEMInterruptHandler完成的工作包括:关中断,设SPEND、以及返回系统中断号(Sysintr由系统分配),分配代码如下: // First find if IRQ is claimed by chain sysIntr = NKCallIntChain((UCHAR)irq); if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) { // IRQ wasn't claimed, use static mapping sysIntr = OALIntrTranslateIrq(irq);} (最初调试的时候因为此处未对中断进行处理,因此中断不断被触发,程序停止在这里) 2. 自己设置MAC地址 Device.cpp文件DeviceMacAddres函数中。 修改如下: PU8 NIC_DEVICE_OBJECT::DeviceMacAddress( PU8 ptrBuffer) { if(!ptrBuffer) return ptrBuffer; PU16 pcurr=(PU16)&m_szEeprom[ m_szEepromFormat[EID_MAC_ADDRESS]]; //*(PU16)ptrBuffer = *pcurr++; //*(PU16)(ptrBuffer+2) = *pcurr++; //*(PU16)(ptrBuffer+4) = *pcurr++; *(PU16)ptrBuffer = MAC21; *(PU16)(ptrBuffer+2) = MAC43; *(PU16)(ptrBuffer+4) = MAC65; return ptrBuffer; } 3. 驱动的中断处理函数 添加写1清除NSR语句 void C_DM9000::DeviceInterruptEventHandler( U32 uValue) { // check RX activities if(uValue & 0x01) Dm9LookupRxBuffers(); // return if not TX latch if(!(uValue & 0x02)) return; U32 nsr; nsr = DeviceReadPort(DM9_NSR); // check TX-END2 if(nsr & 0x08) { m_nTxPendings--; DeviceSendCompleted(m_TQWaiting.Dequeue()); } // check TX-END1 if(nsr & 0x04) { m_nTxPendings--; DeviceSendCompleted(m_TQWaiting.Dequeue()); } // report tx available now if( nsr & 0x0C ) { NdisMSendResourcesAvailable(m_pUpper->GetNdisHandle()); } DeviceWritePort(DM9_NSR,nsr); //clear nsr by set 1 } PS: DM9000A是一款应用相当广泛的成熟产品了,可是手册居然会犯这样的错误而网上也没有用户说明.实在是令人费解.如果读者用到该芯片,还请注意NSR. |