WINCE下三串口驱动程序
三星2410的BSP中只支持一个串口和一个红外串口,并且第三个串口仅支持红外,第一个串口用于调试。还有一个串口就浪费掉了!
首先确定一下需要修改的文件列表
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}"
到这里,三串口驱动就全部添加完毕了,添加完成之后,要保证他没有问题,还需要多加测试,有不对的地方需要修改,这里的代码也只是个大概,用到不同的地方,可能修改的参数也有些不同的。
需要添加三串口的时候,可以先照这个上面的修改,之后再自己慢慢修改一下,应该就不会出现大问题了!