S3C2440 WINCE4.2
BSP的串口修改
说明:在基于SMDK2440的BSP中,S3C2440的UART0初始化为了COM1,UART1用作了WindowsCE
系统的debug串口,用户程序不可用,而UART2则工作在IrDA模式.也就是说,用户程序只有一个串
口可以使用,如果要连接GPS,GPRS之类的模块,会很不方便.
本文档所做的修改,目的是剪裁掉IrDA,并且将UART2初始化为可用的COM2,即:
S3C2440硬件 WindowsCE系统中
UART0 COM1
UART1 Debug串口,用户程序不可见
UART2 COM2
【以下修改以wikee的2410修改文档为重要参考,特此鸣谢.】
1.修改"\FILES\platform.bib"
用分号注释掉:
irsir.dll $(_FLATRELEASEDIR)\irsir.dll NK SH
2. 修改注册表"\platform.reg"
【注意:把有关IRDA的注册表项全都用 ;号注释掉!】
修改后的串口部分:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; UART0 (physical COM1 connector P1) (Serial) 这是原有的串口1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IF BSP_NOSERIAL !
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\UART0]
"DeviceArrayIndex"=dword:0
"Irq"=dword:03
"IoBase"=dword:50000000
"IoLen"=dword:2C
"Prefix"="COM"
"Dll"="SER2440.Dll"
"Order"=dword:0
"Index"=dword:1
"Priority"=dword:0
"Port"="COM1:"
"DeviceType"=dword:0
"FriendlyName"="Serial Port 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; UART2 这是新增加的,把UART2作为COM2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\UART2]
"DeviceArrayIndex"=dword:1
"Irq"=dword:09
"IoBase"=dword:50008000
"IoLen"=dword:2C
"Prefix"="COM"
"Dll"="SER2440.Dll"
"Order"=dword:0
"Index"=dword:2
"Priority"=dword:0
"Port"="COM2:"
"DeviceType"=dword:0
"FriendlyName"="Serial Port 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
ENDIF BSP_NOSERIAL !
[HKEY_LOCAL_MACHINE\Comm\DefaultConnections]
LOC_19200=multi_sz:"Serial Port COM1","19200"
LOC_38400=multi_sz:"Serial Port COM1","38400"
LOC_115200=multi_sz:"Serial Port COM1","115200"
LOC_57600=multi_sz:"Serial Port COM1","57600"
3.中断注册的修改
1, 在"inc\Oalintr.h"文件中line27修改
#define SYSINTR_SERIAL2 (SYSINTR_FIRMWARE+9)
//#define SYSINTR_IR (SYSINTR_FIRMWARE+9)
2, 在 platform\smdk2410\inc\Oalintr.inc添加
SYSINTR_SERIAL2: .equ SYSINTR_FIRMWARE+9
;SYSINTR_IR: .equ SYSINTR_FIRMWARE+9
3, 在 platform\smdk2410\inc\Oalintra.inc添加
SYSINTR_SERIAL2 EQU SYSINTR_FIRMWARE+9
;SYSINTR_IR EQU SYSINTR_FIRMWARE+9
4. 修改文件"\KERNEL\HAL\cfw.c"
都是将'SYSINTR_IR'的处理修改为'SYSINTR_SERIAL2'
约在Line423:
case SYSINTR_SERIAL2: // modified by millin, from IrDA to nomal serial port mode.
s2440INT->rSUBSRCPND = (INTSUB_RXD2 | INTSUB_TXD2 | INTSUB_ERR2);
s2440INT->rINTSUBMSK &= ~INTSUB_RXD2;
s2440INT->rINTSUBMSK &= ~INTSUB_TXD2;
s2440INT->rINTSUBMSK &= ~INTSUB_ERR2;
s2440INT->rSRCPND = BIT_UART2;
// S3C2440X Developer Notice (page 4) warns against writing a 1 to a 0 bit in the INTPND register.
if (s2440INT->rINTPND & BIT_UART2) s2440INT->rINTPND = BIT_UART2;
s2440INT->rINTMSK &= ~BIT_UART2;
break;
约在Line631
case SYSINTR_SERIAL2: // modified by millin, from IrDA to nomal serial port mode.
s2440INT->rINTMSK |= BIT_UART2;
s2440INT->rINTSUBMSK |= INTSUB_RXD2;
s2440INT->rINTSUBMSK |= INTSUB_TXD2;
s2440INT->rINTSUBMSK |= INTSUB_ERR2;
break;
约在Line772
case SYSINTR_SERIAL2: // modified by millin, from IrDA to nomal serial port mode.
s2440INT->rINTMSK &= ~BIT_UART2;
s2440INT->rINTSUBMSK &= ~INTSUB_RXD2;
break;
5. 修改文件"\KERNEL\HAL\ARM\armint.c"
约Line555,同样是将'SYSINTR_IR'的修改为'SYSINTR_SERIAL2'
else if(IntPendVal == INTSRC_UART2) // modified by millin, from IrDA to nomal serial port mode.
{
SubIntPendVal = s2440INT->rSUBSRCPND;
if(SubIntPendVal & INTSUB_ERR2)
{
s2440INT->rINTSUBMSK |= INTSUB_ERR2;
}
else if(SubIntPendVal & INTSUB_RXD2)
{
s2440INT->rINTSUBMSK |= INTSUB_RXD2;
}
else if(SubIntPendVal & INTSUB_TXD2)
{
s2440INT->rINTSUBMSK |= INTSUB_TXD2;
}
else
{
return(SYSINTR_NOP);
}
// NOTE: Don't clear INTSRC:UART2 here - serial driver does that.
//
s2440INT->rINTMSK |= BIT_UART2;
if (s2440INT->rINTPND & BIT_UART2) s2440INT->rINTPND = BIT_UART2;
return(SYSINTR_SERIAL2);
}
6. 修改文件"\DRIVERS\serial\SER2440_SER.C"
在约Line460,增加一个函数,同时注释掉原有的SerInitIR()函数:
PVOID
SerInitSerial2(
ULONG Identifier, // @parm Device identifier.
PVOID pMddHead, // @parm First argument to mdd callbacks.
PHWOBJ pHWObj // @parm Pointer to our own HW OBJ for this device
)
{
return (SerInit(FALSE, Identifier, pMddHead, pHWObj));
}
在约Line,增加函数表IoVTbl2,同时注销原有的IrVTbl:
const
HW_VTBL IoVTbl2 = {
SerInitSerial2,
SL_PostInit,
SerDeinit,
SerOpen,
SerClose,
SL_GetInterruptType,
SL_RxIntr,
SL_TxIntrEx,
SL_ModemIntr,
SL_LineIntr,
SL_GetRxBufferSize,
SerPowerOff,
SerPowerOn,
SL_ClearDTR,
SL_SetDTR,
SL_ClearRTS,
SL_SetRTS,
SerEnableSerial,
SerDisableSerial,
SL_ClearBreak,
SL_SetBreak,
SL_XmitComChar,
SL_GetStatus,
SL_Reset,
SL_GetModemStatus,
SerGetCommProperties,
SL_PurgeComm,
SL_SetDCB,
SL_SetCommTimeouts,
};
extern const HW_VTBL SerCardIoVTbl;
在约Line910,增加以下常量结构,同时注销IrObj:
const HWOBJ IoObj2 = {
THREAD_AT_INIT,
SYSINTR_SERIAL2,
(PHW_VTBL) &IoVTbl2
};
如下修改数组HWObjects:
const PCHWOBJ HWObjects[] = {
&IoObj,
&IoObj2,
//&IrObj
// modified by millin, from IrDA to nomal serial port mode.
};
在约Line947,修改函数GetSerialObject(DWORD DeviceArrayIndex),使之按照注册表的
DeviceArrayIndex值选择不同的pSerObj:
PHWOBJ
GetSerialObject(DWORD DeviceArrayIndex)
{
PHWOBJ pSerObj;
RETAILMSG(DEBUGMODE,(TEXT("GetSerialObject : DeviceArrayIndex\r\n")));
// Now return this structure to the MDD.
if ( DeviceArrayIndex == 0 )
pSerObj = (PHWOBJ)(&IoObj);
else if ( DeviceArrayIndex == 1 ) // modified by millin, from IrDA to nomal serial port mode.
pSerObj = (PHWOBJ)(&IoObj2);
else
pSerObj = (PHWOBJ)(&IoObj);
return (pSerObj);
}
7. 修改文件"\DRIVERS\serial\SER2440_HW.C"
主要修改两个函数,都是使用PSER_INFO类型重新引用pHead指针,从而获得
pHWHead_INFO->dwIOBase的信息,区分进行多个串口的初始化操作(而原有的IrDA初始化是通过一个
bool变量区分的,不去改动它).
修改后的两个函数如下:
VOID
SL_Init(
PVOID pHead, // @parm points to device head
PUCHAR pRegBase, // Pointer to 16550 register base
UINT8 RegStride, // Stride amongst the 16550 registers
EVENT_FUNC EventCallback, // This callback exists in MDD
PVOID pMddHead, // This is the first parm to callback
PLOOKUP_TBL pBaudTable // BaudRate Table
)
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
// added by millin, from IrDA to nomal serial port mode.
PSER_INFO pHWHead_INFO = (PSER_INFO)pHead;
RETAILMSG(DEBUGMODE, (TEXT("SL_Init : UseIrDA = %d \r\n"), pHWHead->UseIrDA));
SER_VirtualAlloc();
if ( pHWHead->UseIrDA )
{
pHWHead->bINT = BIT_UART2;
pHWHead->bTxINT = INTSUB_TXD2;
pHWHead->bRxINT = INTSUB_RXD2;
pHWHead->bErrINT = INTSUB_ERR2;
pHWHead->s2440SerReg = (S2440_UART_REG *)v_pUART2regs;
pRegBase = (PUCHAR)pHWHead->s2440SerReg;
}
else
{
if(pHWHead_INFO->dwIOBase == 0x50000000)
{
pHWHead->bINT = BIT_UART0;
pHWHead->bTxINT = INTSUB_TXD0;
pHWHead->bRxINT = INTSUB_RXD0;
pHWHead->bErrINT = INTSUB_ERR0;
pHWHead->s2440SerReg = (S2440_UART_REG *)v_pUART0regs;
pRegBase = (PUCHAR)pHWHead->s2440SerReg;
}
else if(pHWHead_INFO->dwIOBase == 0x50008000)
{
pHWHead->bINT = BIT_UART2;
pHWHead->bTxINT = INTSUB_TXD2;
pHWHead->bRxINT = INTSUB_RXD2;
pHWHead->bErrINT = INTSUB_ERR2;
pHWHead->s2440SerReg = (S2440_UART_REG *)v_pUART2regs;
pRegBase = (PUCHAR)pHWHead->s2440SerReg;
}
}
pHWHead->UART_INTMASK = (volatile unsigned int *)&(v_pINTregs->rINTMSK);
pHWHead->UART_INTSUBMASK = (volatile unsigned int *)&(v_pINTregs->rINTSUBMSK);
pHWHead->UART_INTPND = (volatile unsigned int *)&(v_pINTregs->rINTPND);
pHWHead->UART_INTSRCPND = (volatile unsigned int *)&(v_pINTregs->rSRCPND);
pHWHead->UART_INTSUBSRCPND = (volatile unsigned int *)&(v_pINTregs->rSUBSRCPND);
pHWHead->vUMSTAT = 0;
if ( pHWHead->UseIrDA )
{
pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART2regs->rUTXH);
pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART2regs->rURXH);
}
else
{
if(pHWHead_INFO->dwIOBase == 0x50000000)
{
pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART0regs->rUTXH);
pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART0regs->rURXH);
}
else if(pHWHead_INFO->dwIOBase == 0x50008000)
{
pHWHead->pUFTXH = (volatile unsigned char *)&(v_pUART2regs->rUTXH);
pHWHead->pUFRXH = (volatile unsigned char *)&(v_pUART2regs->rURXH);
}
}
…………
略
…………
// Clear any interrupts which may be pending. Normally only
// happens if we were warm reset.
ClearPendingInts( pHWHead );
}
S2440_SetSerialIOP(PVOID pHead) // @parm points to device head
{
PS2440_UART_INFO pHWHead = (PS2440_UART_INFO)pHead;
PSER_INFO pHWHead_INFO = (PSER_INFO)pHead;
RETAILMSG(DEBUGMODE, (TEXT("S2440_SetSerialIOP \r\n")));
EnterCriticalSection(&(pHWHead->RegCritSec));
if(pHWHead_INFO->dwIOBase == 0x50000000)
{
v_pIOPregs->rGPHCON &= ~(0x3<<0 | 0x3<<2 | 0x3<<4 | 0x3
pHWHead->rDSRport = (volatile unsigned int *)&(v_pIOPregs->rGPDDAT);
pHWHead->DtrPortNum = 0;
pHWHead->DsrPortNum = 1;
#if USE_AFC
pHWHead->rCTSport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
pHWHead->rRTSport = (volatile unsigned int *)&(v_pIOPregs->rGPHDAT);
pHWHead->CtsPortNum = 0;
pHWHead->RtsPortNum = 1;
#endif
}
else if(pHWHead_INFO->dwIOBase == 0x50008000)
{
v_pIOPregs->rGPHCON &= ~(0x3<<12 | 0x3
LeaveCriticalSection(&(pHWHead->RegCritSec));
}
8. 最后发现驱动本身有几个小bug
板子上的COM1已经没有DTR和DSR引脚,COM2连CTS和RTS也没有,驱动中要做相应的判断,避免
对空指针的操作引起Exception.
(C++的Exception在普通函数里没问题,但是WindowsCE驱动的PowerOn和PowerOff函数是不允许发
生Exception的,否则系统会挂住报错.)
此外系统初始化时,调用了S2440_SetIrDAIOP函数,这不对.
此处应该调用S2440_SetIOP函数,由它进行判断,是按照IrDA初始化串口,还是应该按照普通串口调
用S2440_SetSerialIOP进行初始化.
9. 应该停用串口驱动的自动流量控制,否则COM2工作不正常.
在/Mivi2440/INC/s2440.h中,修改设置为:
#define USE_AFC 0
来源:http://hi.baidu.com/mikenoodle/blog/item/25f6d33f479684cb7d1e71ee.html