Chinaunix首页 | 论坛 | 博客
  • 博客访问: 431746
  • 博文数量: 56
  • 博客积分: 2262
  • 博客等级: 大尉
  • 技术积分: 711
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-08 20:04
文章分类

全部博文(56)

文章存档

2013年(1)

2012年(9)

2011年(10)

2010年(7)

2009年(7)

2008年(22)

我的朋友

分类: WINDOWS

2008-07-22 22:35:39

WINCE下三串口驱动程序
三星2410BSP中只支持一个串口和一个红外串口,并且第三个串口仅支持红外,第一个串口用于调试。还有一个串口就浪费掉了!
首先确定一下需要修改的文件列表
SMDK2410\FILES\platform.reg
SMDK2410\INC\oalintr.h
SMDK2410\DRIVERS\SERIAL\ser2410_hw.c
SMDK2410\DRIVERS\SERIAL\ser2410_ser.c
SMDK2410\KERNEL\HAL\cfw.c
SMDK2410\KERNEL\HAL\ARM\armint.c
1.首先三个串口使用不同的中断,因此需要添加串口2的中断号,在SMDK2410\INC\oalintr.h文件中添加一个宏
#define SYSINTR_SERIAL1                            (SYSINTR_FIRMWARE+19)
串口三就直接使用他的SYSINTR_IR好了。我们会发现很多厂家的BSP包都没有添加这个。
2. 修改SMDK2410\KERNEL\HAL\cfw.c文件,OEMInterruptEnable()函数中添加串口的中断使能,我的修改如下
case SYSINTR_SERIAL0:  // Serial port.
                   s2410INT->rSUBSRCPND  = (INTSUB_RXD0 | INTSUB_TXD0 | INTSUB_ERR0);
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD0;
                   s2410INT->rINTSUBMSK &= ~INTSUB_TXD0;
                   s2410INT->rINTSUBMSK &= ~INTSUB_ERR0;
                   s2410INT->rSRCPND     = BIT_UART0;
// S3C2410X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
                   if (s2410INT->rINTPND & BIT_UART0) s2410INT->rINTPND = BIT_UART0;
                   s2410INT->rINTMSK    &= ~BIT_UART0;
                   break;
case SYSINTR_SERIAL1:  // Serial port1.
                   s2410INT->rSUBSRCPND  = (INTSUB_RXD1 | INTSUB_TXD1 | INTSUB_ERR1);
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD1;
                   s2410INT->rINTSUBMSK &= ~INTSUB_TXD1;
                   s2410INT->rINTSUBMSK &= ~INTSUB_ERR1;
                   s2410INT->rSRCPND        = BIT_UART1;
// S3C2410X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
                   if (s2410INT->rINTPND & BIT_UART1) s2410INT->rINTPND = BIT_UART1;
                   s2410INT->rINTMSK        &= ~BIT_UART1;
                   break;
case SYSINTR_IR:              // IrDA.
                   s2410INT->rSUBSRCPND  = (INTSUB_RXD2 | INTSUB_TXD2 | INTSUB_ERR2);
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD2;
                   s2410INT->rINTSUBMSK &= ~INTSUB_TXD2;
                   s2410INT->rINTSUBMSK &= ~INTSUB_ERR2;
                   s2410INT->rSRCPND     = BIT_UART2;
// S3C2410X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
                   if (s2410INT->rINTPND & BIT_UART2) s2410INT->rINTPND = BIT_UART2;
                   s2410INT->rINTMSK    &= ~BIT_UART2;
                   break;
又使能肯定也应该又禁用吧,再看OEMInterruptDisable()
case SYSINTR_SERIAL0:
                   s2410INT->rINTMSK    |= BIT_UART0;
                   s2410INT->rINTSUBMSK |= INTSUB_RXD0;
                   s2410INT->rINTSUBMSK |= INTSUB_TXD0;
                   s2410INT->rINTSUBMSK |= INTSUB_ERR0;
                   break;
case SYSINTR_SERIAL1:
                   s2410INT->rINTMSK    |= BIT_UART1;
                   s2410INT->rINTSUBMSK |= INTSUB_RXD1;
                   s2410INT->rINTSUBMSK |= INTSUB_TXD1;
                   s2410INT->rINTSUBMSK |= INTSUB_ERR1;
                   break;
case SYSINTR_IR:
                   s2410INT->rINTMSK    |= BIT_UART2;
                   s2410INT->rINTSUBMSK |= INTSUB_RXD2;
                   s2410INT->rINTSUBMSK |= INTSUB_TXD2;
                   s2410INT->rINTSUBMSK |= INTSUB_ERR2;
                   break;
这样好了,就像我们添加自定义中断中的一样,添加一个自定义的中断号,然后在使能和禁用函数中添加寄存器设置语句,这样,三串口的基本设置已经修改好了!
最后我们还要修改一下OEMInterruptDone()中断处理完成之后我们需要清楚中断。
case SYSINTR_SERIAL0:
                   s2410INT->rINTMSK    &= ~BIT_UART0;
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD0;
                   break;
case SYSINTR_SERIAL1:
                   s2410INT->rINTMSK        &= ~BIT_UART1;
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD1;
                   break;
case SYSINTR_IR:
                   s2410INT->rINTMSK    &= ~BIT_UART2;
                   s2410INT->rINTSUBMSK &= ~INTSUB_RXD2;
                   break;
3. 修改SMDK2410\KERNEL\HAL\ARM\armint.c,在添加中断号和中断寄存器设置代码之后,后面我们就需要添加中断处理函数,OEMInterruptHandler()
if(IntPendVal == INTSRC_UART0)    // SERIAL (UART0) (physical COM1: P1 connector).
         { 
                   SubIntPendVal = s2410INT->rSUBSRCPND;
                   // Note that we only mask the sub source interrupt - the serial driver will clear the
                   // sub source pending register.
                   if(SubIntPendVal & INTSUB_ERR0)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_ERR0;
                   }
                   else if(SubIntPendVal & INTSUB_RXD0)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_RXD0;
                   }
                   else if(SubIntPendVal & INTSUB_TXD0)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_TXD0;
                   }
                   else
                   {
                            return(SYSINTR_NOP);
                   }
                   // NOTE: Don't clear INTSRC:UART0 here - serial driver does that.
                   s2410INT->rINTMSK |= BIT_UART0;
                   if (s2410INT->rINTPND & BIT_UART0) s2410INT->rINTPND  = BIT_UART0;
                   return(SYSINTR_SERIAL0);
         }
         else if(IntPendVal == INTSRC_UART1)
          {
            SubIntPendVal = s2410INT->rSUBSRCPND;
            // Note that we only mask the sub source interrupt - the serial driver will clear the
            // sub source pending register.
            if(SubIntPendVal & INTSUB_ERR1)
            {
                    s2410INT->rINTSUBMSK |= INTSUB_ERR1;
            }
            else if(SubIntPendVal & INTSUB_RXD1)
            {
                    s2410INT->rINTSUBMSK |= INTSUB_RXD1;
            }
            else if(SubIntPendVal & INTSUB_TXD1)
            {
                    s2410INT->rINTSUBMSK |= INTSUB_TXD1;
            }
            else
            {
                    return(SYSINTR_NOP);
            }
            // NOTE: Don't clear INTSRC:UART1 here - serial driver does that.
            s2410INT->rINTMSK |= BIT_UART1;
            if (s2410INT->rINTPND & BIT_UART1) s2410INT->rINTPND  = BIT_UART1;
            return(SYSINTR_SERIAL1);
          }
         else if(IntPendVal == INTSRC_UART2)     // IrDA (UART2)
         {
                   SubIntPendVal = s2410INT->rSUBSRCPND;
                   if(SubIntPendVal & INTSUB_ERR2)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_ERR2;
                   }      
                   else if(SubIntPendVal & INTSUB_RXD2)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_RXD2;
                   }       
                   else if(SubIntPendVal & INTSUB_TXD2)
                   {
                            s2410INT->rINTSUBMSK |= INTSUB_TXD2;
                   }      
                   else
                   {
                            return(SYSINTR_NOP);
                   }
                   // NOTE: Don't clear INTSRC:UART2 here - serial driver does that.
                   s2410INT->rINTMSK |= BIT_UART2;
                   if (s2410INT->rINTPND & BIT_UART2) s2410INT->rINTPND  = BIT_UART2;
                   return(SYSINTR_IR);
         }
这个函数应该很好理解吧,当系统接收到中断之后,系统会跳转到这个函数去执行,然后判断是什么发出的中断,返回我们第一次定义的那个中断号!在应用层中我们就可以将一个事件和这个中断号联系起来,当发生这个中断之后,返回中断号,触发我们设置的事件!
4. 打开串口源文件中ser2410_hw.c文件
     修改S2410_SetSerialIOP()函数,我的S2410_SetSerialIOP()函数如下:
{
 PS2410_UART_INFO   pHWHead   = (PS2410_UART_INFO)pHead;
 PSER_INFO     pHWHead1  = (PSER_INFO)pHead;
 RETAILMSG(DEBUGMODE, (TEXT("S2410_SetSerialIOP \r\n")));
 if(pHWHead1->dwIOBase == 0x50004000)
 {
 #if USEVIRTUAL
   EnterCriticalSection(&(pHWHead->RegCritSec));
   v_pIOPregs->rGPHCON &= ~(0x3<<8 | 0x3<<10); // clear uart 1 - rx, tx
   v_pIOPregs->rGPHCON |= (0x2<<8 | 0x2<<10);
   v_pIOPregs->rGPHCON |= (0x2<<0 | 0x2<<2 );
   v_pIOPregs->rGPHUP  |= 0x03;
   pHWHead->rDTRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->rDSRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum = 1;
 #else
   volatile IOPreg *s2410IOP;
   s2410IOP   = (volatile IOPreg *)IOP_BASE;
   EnterCriticalSection(&(pHWHead->RegCritSec));
   s2410IOP->rGPHCON &= ~(0x3<<8 | 0x3<<10); // clear uart 1 - rx, tx
   s2410IOP->rGPHCON |= (0x2<<8 | 0x2<<10);
   s2410IOP->rGPHCON |= (0x2<<0 | 0x2<<2 );
   s2410IOP->rGPHUP  |= 0x03;
   pHWHead->rDTRport = (volatile unsigned int *)(IOP_BASE+0x74); //s2410IOP->rGPHDAT
   pHWHead->rDSRport = (volatile unsigned int *)(IOP_BASE+0x74);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum = 1;
 #endif
 }
 else if(pHWHead1->dwIOBase == 0x50008000)
 {
 #if USEVIRTUAL
   EnterCriticalSection(&(pHWHead->RegCritSec));
   v_pIOPregs->rGPHCON &= ~( 0x3<<12 | 0x3<<14); // clear uart 2 - rx, tx
   v_pIOPregs->rGPHCON |= ( 0x2<<12 | 0x2<<14);
   v_pIOPregs->rGPHCON |= (0x2<<0 | 0x2<<2 );
   v_pIOPregs->rGPHUP  &= ~0xc0;
   pHWHead->rDTRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->rDSRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum = 1;
 #else
   volatile IOPreg *s2410IOP;
   s2410IOP   = (volatile IOPreg *)IOP_BASE;
EnterCriticalSection(&(pHWHead->RegCritSec));
   s2410IOP->rGPHCON &= ~(0x3<<12 | 0x3<<14); // clear uart 2 - rx, tx
   s2410IOP->rGPHCON |= ( 0x02<<12 | 0x02<<14);
   s2410IOP->rGPHCON |= (0x2<<0 | 0x2<<2 );
   s2410IOP->rGPHUP  &= ~0xc0;
   pHWHead->rDTRport = (volatile unsigned int *)(IOP_BASE+0x74); //s2410IOP->rGPHDAT
   pHWHead->rDSRport = (volatile unsigned int *)(IOP_BASE+0x74);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum = 1;
 #endif   
 }
 Else
 {
 #if USEVIRTUAL
   EnterCriticalSection(&(pHWHead->RegCritSec));
   v_pIOPregs->rGPHCON &= ~(0x3<<0 | 0x3<<2 | 0x3<<4 | 0x3<<6); // clear uart 0 - rx, tx
   v_pIOPregs->rGPHCON |= (0x2<<4 | 0x2<<6);
   v_pIOPregs->rGPHCON |= (0x2<<0 | 0x2<<2 );
   v_pIOPregs->rGPHUP  |= 0x03;
   pHWHead->rDTRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->rDSRport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum = 1;
 #else
   volatile IOPreg *s2410IOP;
   s2410IOP   = (volatile IOPreg *)IOP_BASE;
   EnterCriticalSection(&(pHWHead->RegCritSec));
   s2410IOP->rGPHCON &= ~(0x3<<0 | 0x3<<2 | 0x3<<4 | 0x3<<6 /*| 0x3<<12 | 0x3<<14*/); // clear uart 0 - rx, tx
   s2410IOP->rGPHCON |= (0x2<<4 | 0x2<<6 /*| 0x1<<12 | 0x0<<14*/);
   s2410IOP->rGPHCON |= (0x2<<0 | 0x2<<2 );
   s2410IOP->rGPHUP  |= 0x03;
   pHWHead->rDTRport = (volatile unsigned int *)(IOP_BASE+0x74); //s2410IOP->rGPHDAT
   pHWHead->rDSRport = (volatile unsigned int *)(IOP_BASE+0x74);
   pHWHead->DtrPortNum = 0;
   pHWHead->DsrPortNum =1;
 #endif
 }
 LeaveCriticalSection(&(pHWHead->RegCritSec));
}
这里,相关的IO寄存器配置可以根据自己的需要进行配置。
1.       ser2410_hw.c这个文件里面还有一个函数是SL_Init()
PS2410_UART_INFO   pHWHead   = (PS2410_UART_INFO)pHead;后面添加下面语句:
PSER_INFO     pHWHead1  = (PSER_INFO)pHead;
接下来搜索:红色为添加部分
 if ( pHWHead->UseIrDA )
 {
   pHWHead->bINT = BIT_UART2;
   pHWHead->bTxINT = INTSUB_TXD2;
   pHWHead->bRxINT = INTSUB_RXD2;
   pHWHead->bErrINT = INTSUB_ERR2;
#if USEVIRTUAL
   pHWHead->s2410SerReg = (S2410_UART_REG *)v_pUART2regs;
   pRegBase = (PUCHAR)pHWHead->s2410SerReg;
#else   
   pRegBase = (PUCHAR)UART2_BASE;
   pHWHead->s2410SerReg = (S2410_UART_REG *)pRegBase;
#endif
 }
 else
 {
if(pHWHead1->dwIOBase == 0x50004000)//添加
   {
     pHWHead->bINT = BIT_UART1;
     pHWHead->bTxINT = INTSUB_TXD1;
     pHWHead->bRxINT = INTSUB_RXD1;
     pHWHead->bErrINT = INTSUB_ERR1;
   #if USEVIRTUAL
     pHWHead->s2410SerReg = (S2410_UART_REG *)v_pUART1regs;
     pRegBase = (PUCHAR)pHWHead->s2410SerReg;
   #else   
     pRegBase = (PUCHAR)UART1_BASE;
     pHWHead->s2410SerReg = (S2410_UART_REG *)pRegBase;
   #endif
        } 
else if(pHWHead1->dwIOBase == 0x50008000)  
 {    
 pHWHead->bINT = BIT_UART2;
     pHWHead->bTxINT = INTSUB_TXD2;
     pHWHead->bRxINT = INTSUB_RXD2;
     pHWHead->bErrINT = INTSUB_ERR2;
   #if USEVIRTUAL
     pHWHead->s2410SerReg = (S2410_UART_REG *)v_pUART2regs;
     pRegBase = (PUCHAR)pHWHead->s2410SerReg;
   #else   
     pRegBase = (PUCHAR)UART2_BASE;
     pHWHead->s2410SerReg = (S2410_UART_REG *)pRegBase;
   #endif
   }
   Else
   {
    
     pHWHead->bINT = BIT_UART0;
     pHWHead->bTxINT = INTSUB_TXD0;
     pHWHead->bRxINT = INTSUB_RXD0;
     pHWHead->bErrINT = INTSUB_ERR0;
   #if USEVIRTUAL
     pHWHead->s2410SerReg = (S2410_UART_REG *)v_pUART0regs;
     pRegBase = (PUCHAR)pHWHead->s2410SerReg;
   #else   
     pRegBase = (PUCHAR)UART0_BASE;
     pHWHead->s2410SerReg = (S2410_UART_REG *)pRegBase;
   #endif
   }//添加
 }
然后搜索下面的语句并添加代码:
 if ( pHWHead->UseIrDA )
 {
   pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART2regs->rUTXH);
   pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART2regs->rURXH);   
 }
 Else
 {
 if(pHWHead1->dwIOBase == 0x50004000)//添加
   {
     pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART1regs->rUTXH);
     pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART1regs->rURXH);
   }
   else if(pHWHead1->dwIOBase == 0x50008000)
   {
     pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART2regs->rUTXH);
     pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART2regs->rURXH);      
   }
   Else
   {
     pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART0regs->rUTXH);
     pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART0regs->rURXH);   
   }//添加
 }
 
2.       接下来,我们再打开ser2410_ser.c这个文件:
在这个Obj后面
const HWOBJ IoObj = {
 THREAD_AT_INIT,
 SYSINTR_SERIAL,
 (PHW_VTBL) &IoVTbl
};
添加下面的Obj
const HWOBJ Io1Obj = {
 THREAD_AT_INIT,
 SYSINTR_SERIAL1,
 (PHW_VTBL) &IoVTbl
};
const HWOBJ Io2Obj = {
 THREAD_AT_INIT,
 SYSINTR_IR,
 (PHW_VTBL) &IoVTbl
};
接着将
const PCHWOBJ HWObjects[] = { &IoObj, &IrObj};
修改为:
const PCHWOBJ HWObjects[] = { &IoObj, &Io1Obj, &Io2Obj};
这两个地方修改之后,我们就来修改GetSerialObject()函数,这个函数就是用来获取前面修改的Obj的,我们将其改为:
{
 PHWOBJ pSerObj;
 // Now return this structure to the MDD.
 if ( DeviceArrayIndex == 2 )
 { 
   RETAILMSG(1,(TEXT("GetSerialObject Io2Obj\r\n")));
   pSerObj = (PHWOBJ)(&Io2Obj);
 }
 else if(DeviceArrayIndex == 1)
   pSerObj = (PHWOBJ)(&Io1Obj);
 else
   pSerObj = (PHWOBJ)(&IoObj);
 return (pSerObj);
}
 
3.       在修改这些文件的时候也许你会注意到,有一个地方读取了注册表的!因此我们最后需要添加注册表,为第二、三个串口添加一个合适的注册表项。
这个是串口1
 [HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SER2410]
  "DeviceArrayIndex"=dword:0
  "Irq"=dword:13
  "IoBase"=dword:50000000
  "IoLen"=dword:2C
  "Prefix"="COM"
  "Dll"="SER2410.Dll"
  "Order"=dword:0
  "Priority"=dword:0
  "Port"="COM1:"
  "DeviceType"=dword:0
  "FriendlyName"="Serial Cable on COM1:"
  "Tsp"="Unimodem.dll"
  "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00
串口2
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SER2410_2]
  "DeviceArrayIndex"=dword:1
  "Irq"=dword:23
  "IoBase"=dword:50004000
  "IoLen"=dword:2C
  "Prefix"="COM"
  "Dll"="SER2410.Dll"
  "Order"=dword:1
  "Priority"=dword:0
  "Port"="COM2:"
  "DeviceType"=dword:0
  "FriendlyName"="Serial Cable on COM2:"
  "Tsp"="Unimodem.dll"
  "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SER2410_2\Unimodem]
  "Tsp"="Unimodem.dll"
  "DeviceType"=dword:0
  "FriendlyName"="SER2410_2 UNIMODEM"
  "DevConfig"=hex: 10,00, 00,00, 05,00,00,00, 10,01,00,00, 00,4B,00,00, 00,00, 08, 00, 00, 00,00,00,00
在添加这些项的时候需要注意”irq”和其他几个,一和二都添加了,接下来肯定也要添加第三个,也就是红外的,可以在原来红外注册表项的基础上修改:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\IRDA2410]
  "DeviceArrayIndex"=dword:2
  "Irq"=dword:19
  "IoBase"=dword:50008000
  "IoLen"=dword:2C
  "Prefix"="COM"
  "Dll"="IRDA2410.Dll"
  "Order"=dword:0
  "Priority"=dword:0
  "Port"="COM3:"
  "DeviceType"=dword:0  ; IRDA modem, 0 -> null modem
  "FriendlyName"="S2410 IRDA2410"
  "Index"=dword:2
  "IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"
到这里,三串口驱动就全部添加完毕了,添加完成之后,要保证他没有问题,还需要多加测试,有不对的地方需要修改,这里的代码也只是个大概,用到不同的地方,可能修改的参数也有些不同的。
     需要添加三串口的时候,可以先照这个上面的修改,之后再自己慢慢修改一下,应该就不会出现大问题了!
 
 
阅读(3215) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~