最近在调优龙ST2410的板子,总体来说,优龙的板子做的不错,技术支持也还可以~ 不过呢,优龙提供的WinCE BSP也只是在三星的公版BSP上少量修改而成的,虽然三星S3C2410能够提供3个UART支持,也就是说每个UART控制器都可以工作在Interrupt(中断)模式或DMA(直接内存访问)模式,但是三星提供的公版BSP上只添加了UART0(COM1)和UART2(红外)的支持,所以优龙提供的BSP也就只有一个串口能用,另外一个红外我也不知道怎么用(没有红外设备测试)。 这样的话,我买的板子上面的两个串口岂不是浪费了一个,这可不行,因为COM1是默认作为调试串口了,系统的启动信息都是靠这个串口输出的,总不能调试和使用共用一个吧! 在优龙官方论坛寻觅未果,他们好像就没做UART1的BSP支持,这样,只好自己动手,丰衣足食了。 我的平台是WinCE 5.0和Platform Builder 5.0,虽然手头的资料都是WinCE 4.2的,但根据修改比较,好像没有区别,不知道WinCE 5.0到底升级了什么? 首先列举一下要修改文件的清单: SMDK2410FILESplatform.reg SMDK2410INCoalintr.h SMDK2410DRIVERSSERIALser2410_hw.c SMDK2410DRIVERSSERIALser2410_ser.c SMDK2410KERNELHALcfw.c SMDK2410KERNELHALARMarmint.c SMDK2410smdk2410.cec
好了,Let's gooooooooo~ 1、打开platform.reg文件,这个是WinCE注册表文件,在这里,我们要修改并添加串口。 搜索:[HKEY_LOCAL_MACHINEDriversBuiltInSER2410],这就是串口1。 将其下面的键值改为: [HKEY_LOCAL_MACHINEDriversBuiltInSER2410] "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_MACHINEDriversBuiltInSER2410_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_MACHINEDriversBuiltInSER2410_2Unimodem] "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 再搜索:[HKEY_LOCAL_MACHINEDriversBuiltInIRDA2410],这个是红外,也要修改下: [HKEY_LOCAL_MACHINEDriversBuiltInIRDA2410] "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}" 好了,注册表就改到这里,以上要特别注意Irq的值,要和oalintr.h里面的中断定义对应,并且注意Order的顺序,DeviceArrayIndex的值以及IoBase,后面串口源代码中要用到该值作判断。 2、打开oalintr.h文件,我们添加一个新的串口,并定义中断号。 添加: #define SYSINTR_SERIAL1 (SYSINTR_FIRMWARE+19) 这里,我们可以看到SYSINTR_SERIAL1定义到16+19=35=0x23,与注册表中一致。 然后修改下这个地方: MapIrq2SysIntr(DWORD _Irq) { if( _Irq<=19 ) return ( SYSINTR_FIRMWARE + _Irq ); else return (0xffffffff); } 3、打开串口源文件中ser2410_hw.c文件。 搜索: S2410_SetSerialIOP( PVOID pHead // @parm points to device head ) 将其函数改为: { PS2410_UART_INFO pHWHead = (PS2410_UART_INFO)pHead; PSER_INFO pHWHead1 = (PSER_INFO)pHead; RETAILMSG(DEBUGMODE, (TEXT("S2410_SetSerialIOP "))); if(pHWHead1->dwIOBase == 0x50004000) { #if USEVIRTUAL EnterCriticalSection(&(pHWHead->RegCritSec)); v_pIOPregs->rGPHCON &= ~(0x3<<8 | 0x3<<10 /*| 0x3<<12 | 0x3<<14*/); // clear uart 1 - rx, tx v_pIOPregs->rGPHCON |= (0x2<<8 | 0x2<<10 /*| 0x1<<12 | 0x0<<14*/); 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/* | 0x3<<12 | 0x3<<14*/); // clear uart 1 - rx, tx s2410IOP->rGPHCON |= (0x2<<8 | 0x2<<10 /*| 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 } 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/* | 0x3<<12 | 0x3<<14*/); // clear uart 0 - rx, tx v_pIOPregs->rGPHCON |= (0x2<<4 | 0x2<<6/* | 0x1<<12 | 0x0<<14*/); 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)); } 接着搜索: 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 ) 在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); } 4、打开ser2410_ser.c文件。 搜索: const HWOBJ IoObj = { THREAD_AT_INIT, SYSINTR_SERIAL, (PHW_VTBL) &IoVTbl }; 在其后面添加: 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( DWORD DeviceArrayIndex ) 将其函数改为: { PHWOBJ pSerObj; DEBUGMSG(DEBUGMODE,(TEXT("GetSerialObject : DeviceArrayIndex = %d"), DeviceArrayIndex)); // Now return this structure to the MDD. if ( DeviceArrayIndex == 2 ) { RETAILMSG(1,(TEXT("GetSerialObject Io2Obj"))); pSerObj = (PHWOBJ)(&Io2Obj); } else if(DeviceArrayIndex == 1) pSerObj = (PHWOBJ)(&Io1Obj); else pSerObj = (PHWOBJ)(&IoObj); return (pSerObj); } 5、打开cfw.c文件,这就是中断处理。 搜索: BOOL OEMInterruptEnable(DWORD idInt, // @parm Interrupt ID to be enabled. See <l Interrupt ID's.Interrupt ID's> for a list of possble values. LPVOID pvData, // @parm ptr to data passed in in the <f InterruptInitialize> call DWORD cbData) // @parm Size of data pointed to be <p pvData> 找到这一句:case SYSINTR_SERIAL: 在其后面添加: 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; 搜索: void OEMInterruptDisable(DWORD idInt) // @parm Interrupt ID to be disabled. See <t Interrupt ID's> 还是这一句:case SYSINTR_SERIAL: 在其后面添加: case SYSINTR_SERIAL1: s2410INT->rINTMSK |= BIT_UART1; s2410INT->rINTSUBMSK |= INTSUB_RXD1; s2410INT->rINTSUBMSK |= INTSUB_TXD1; s2410INT->rINTSUBMSK |= INTSUB_ERR1; break; 搜索: void OEMInterruptDone(DWORD idInt) // @parm Interrupt ID. See <t Interrupt ID's> 依旧找到case SYSINTR_SERIAL: 在其后面添加: case SYSINTR_SERIAL1: s2410INT->rINTMSK &= ~BIT_UART1; s2410INT->rINTSUBMSK &= ~INTSUB_RXD1; break; 6、打开armint.c文件。 搜索:else if(IntPendVal == INTSRC_UART0) 在其后面添加: 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); } 7、打开smdk2410.cec文件,添加UART1这个feature。 搜索 ComponentType ( Name ( "Serial" ) GUID ( {6563AD6C-E71C-11D4-B892-0050FC049781} ) MaxResolvedImpsAllowed( 999 ) Implementations ( Implementation ( Name ( "S32410 Serial UART" ) 在其后面添加: Implementation ( Name ( "S32410 Serial UART1" ) GUID ( {7C4427A5-286C-4C7A-B687-4E3B364D079B} ) Description ( "Samsung S32410 serial UART controller." ) BSPPlatformDir ( "smdk2410" ) Version ( "5.0.0.0" ) Locale ( 0409 ) Vendor ( "Microsoft" ) Date ( "2003-1-13" ) SizeIsCPUDependent( 1 ) BuildMethods ( BuildMethod ( GUID ( {07DA2083-6261-4ED6-B5BB-70CF4D930D68} ) Step ( BSP ) CPU ( "ARMV4" ) CPU ( "ARMV4I" ) Action ( '#BUILD(SOURCES,"$(_WINCEROOT)PLATFORMSMDK2410driversserial")') ) ) ) 我感觉这个改不改没什么关系,反正网上有人这样改了,我也就改了,但是实际内核定制时中并没有添加上这个feature。 到这里,整个过程就结束了,耗费了我整整一天!其实改动量并不大,但是调试一次光编译就要15分钟,还要下载,烧写,启动~唉,没有仿真器就是麻烦。调了好多次没有成功,就是在注册表的中断号那儿出了问题,呵呵!
|