转载请注明出处
作者:小马
公司的一个项目,要做一个基于CE6.0的应用,无奈手上的板子是5.0的, 本来想节省时间,直接向厂家要一个该板子的6.0的BSP,联系他们的客服说没有这个板子的6.0的BSP,让我自力更生.
截至到写这篇文章时, OAL部分已经移植成功, 从DNW的输出信息看出,系统成功启动起来了. 剩下就是外设驱动部分了, 驱动我是不打算全部移植的,因为我的目标是做上层的应用,这个上层应用程序会用到一些硬件资源,比如串口, LCD等, 用到哪个外设,才移植哪个驱动. 这样可以快速的完成.
bootloader我没有移植, 因为我这个板子用的是用ADS独立开发一个loader, 它本身有eboot和nboot的功能, 没有用到wince的eboot, 所以,可以不用移植. 所以也就可以把yourBSPName/SRC下的bootloader目录去掉,因为没有用到. 另外还要感谢csdn上的yashi以及gooogleman在论坛上对自己的一些疑问的解答, 十分受用.
先大概说一下我的方法, 先clone的一个6.0的自带的BSP, 用的是DEVICEEMULATOR, 因为这个是基于2410的CPU的BSP,与我的板子最接近. 然后,对照着5.0的BSP,一点点移植, 需要说明的,我并不是把5.0的OAL相关的文件和目录直接替换掉6.0,而是直接在这个clone的6.0的BSP里修改OAL相关的源代码, 不改变6.0的原来的目录结构和文件名. 虽然比较繁琐,但这样得到的BSP更规范. 因为微软是建议移植到6.0时,保留其原本的目录结构.
下面是具体步骤:
1 clone BSP
打开vs2005—tools—pfatform builder for CE 6.0—clone bsp.
Clone的source 选DEVICEEMULATOR, 自己的BSP取名为My2410.
2 新建一个操作系统工程
用My2410的BPS 新建一个操作系统的工程, 为了方便调试OAL,可以建一个最简单的系统, 可以在定制系统时,先选择custom,然后直接点finish. 后面移植好LCD驱动时,可以定制一个 有shell的系统, 毕竟能看到界面是很让人兴奋的.
3 启动代码
找到startup.s文件(My2410/SRC/OAL/OALLIB/ARM)
把 SLEEPDATA_BASE_PHYSICAL 的值改为如下:
SLEEPDATA_BASE_PHYSICAL EQU 0x30058000
找到下面两行
if software reset
mov r1, #0
改为
mov r1, #0x38000000
到cpupoweroff.s文件(My2410/SRC/OAL/OALLIB)
把SLEEPDATA_BASE_VIRTUAL的值改为如下:
SLEEPDATA_BASE_VIRTUAL EQU 0xAC058000
找到 CPUPowerReset函数. 用5.0的BSP中的该函数替换.如下:
LEAF_ENTRY CPUPowerReset 改为如下的(用5.0的BSP替换)
同样替换 PhysicalStart函数(该函数的实现省略)
ldr r3, =SLEEPDATA_BASE_VIRTUAL ; base of Sleep mode storage mov r2, #0x38000000 ; store Virtual return address str r2, [r3], #4 ; Disable MMU ldr r2, = PhysicalStart ldr r3, = (0x8C000000 - 0x30000000) sub r2, r2, r3 mov r1, #0x0070 ; Disable MMU mcr p15, 0, r1, c1, c0, 0 nop mov pc, r2 ; Jump to PStart nop
找到cpupoweroff函数的实现, 找到下面一句:
ldr r6, =0x88000000改为:
ldr r6, =0x92000000
4 调试串口的移植.
Clone的My2410 BSP 默认是用UART1作为调试串口的, 把它改为UART0
首先找到OEMInitDebugSerial函数(My2410/SRC/OAL/OALLIB/debug.c), 把下面几行代码:
CLRREG32(&pIOPortReg->GPHCON, (3 << 8)|(3 << 10)); SETREG32(&pIOPortReg->GPHCON, (2 << 8)|(2 << 10)); SETREG32(&pIOPortReg->GPHUP, (1 << 4)|(1 << 5)); g_pUARTReg = (S3C2410X_UART_REG *)OALPAtoVA(S3C2410X_BASE_REG_PA_UART1, FALSE); OUTREG32(&g_pUARTReg->UFCON, BSP_UART1_UFCON); OUTREG32(&g_pUARTReg->UMCON, BSP_UART1_UMCON); OUTREG32(&g_pUARTReg->ULCON, BSP_UART1_ULCON); OUTREG32(&g_pUARTReg->UCON, BSP_UART1_UCON); OUTREG32(&g_pUARTReg->UBRDIV, BSP_UART1_UBRDIV);
改为:
CLRREG32(&pIOPortReg->GPHCON, (3 << 4)|(3 << 6)); SETREG32(&pIOPortReg->GPHCON, (2 << 4)|(2 << 6)); SETREG32(&pIOPortReg->GPHUP, (1 << 2)|(1 << 3)); g_pUARTReg = (S3C2410X_UART_REG *)OALPAtoVA(S3C2410X_BASE_REG_PA_UART0, FALSE); OUTREG32(&g_pUARTReg->UFCON, BSP_UART0_UFCON); OUTREG32(&g_pUARTReg->UMCON, BSP_UART0_UMCON); OUTREG32(&g_pUARTReg->ULCON, BSP_UART0_ULCON); OUTREG32(&g_pUARTReg->UCON, BSP_UART0_UCON); OUTREG32(&g_pUARTReg->UBRDIV, BSP_UART0_UBRDIV);
然后到bsp_cfg.h(My2410/SRC/INC)修改相关的宏定义
#define BSP_UART1_ULCON 0x03 // 8 bits, 1 stop, no parity #define BSP_UART1_UCON 0x0005 // pool mode, PCLK for UART #define BSP_UART1_UFCON 0x00 // disable FIFO #define BSP_UART1_UMCON 0x00 // disable auto flow control #define BSP_UART1_UBRDIV (S3C2410X_PCLK/(38400*16) - 1)
把上面五行修改值如下:
#define BSP_UART0_ULCON 0x03 // 8 bits, 1 stop, no parity #define BSP_UART0_UCON 0x0245 // pool mode, PCLK for UART #define BSP_UART0_UFCON 0x00 // disable FIFO #define BSP_UART0_UMCON 0x00 // disable auto flow control #define BSP_UART0_UBRDIV (S3C2410X_PCLK/(115200*16) - 1)
5 LCD的初始化
OAL的OEMInit函数会调用InitDisplay函数, 所以要根据自己的LCD(我的型号是LTV350QV-F04, 320*240的TFT屏)
首先修改s3c2410x_lcd.h(My2410/SRC/INC),改动的地方如下:
#define LCD_XSIZE_TFT (320) #define LCD_YSIZE_TFT (240) #define LCD_VBPD ((8)&0xff) #define LCD_VFPD ((4)&0xff) #define LCD_VSPW ((4)&0x3f) #define LCD_HBPD ((13)&0x7f) #define LCD_HFPD ((4)&0xff) #define LCD_HSPW ((18)&0xff) #define CLKVAL_TFT (7)
这里要注意,LCD是慢显示器件,对时序要求很高, 所以像VBPD(和回扫时间有关)等值要设置好, 具体原理以及如何设置可以参看我的另外一篇专门讲LCD 的文章.
http://blog.csdn.net/pony_maggie/archive/2010/01/29/5270147.aspx
另外,到InitDisplay(My2410/SRC/OAL/OALLIB/init.c)里修改:
把s2410LCD->LCDCON1里的LCD_MVAL改为LCD_MVAL_USED
s2410LCD->LCDCON5改为如下的设置.
s2410LCD->rLCDCON5 = (0 << 12) |1<< 11) | (1<< 10) | (1<<9) |(1 <<8) |(0 <<7)|(0<<6)| (0<<5)|(0<<4)| (1<<3)|(0<<2)| (0<< 1) | (1 << 0) ;
6 内存空间的配置
内存的配置包括以下几个部分:
首先打开oemaddrtab_cfg.inc 文件(My2410/SRC/INC), 把g_oalAddressTable变量按如下值配置:
DCD 0x80000000, 0x02000000, 30 ; 30 MB SROM(SRAM/ROM) BANK 0 DCD 0x82000000, 0x08000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 1 DCD 0x84000000, 0x10000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 2 DCD 0x86000000, 0x18000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 3 DCD 0x88000000, 0x20000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 4 DCD 0x8A000000, 0x28000000, 32 ; 32 MB SROM(SRAM/ROM) BANK 5 DCD 0x8C000000, 0x30000000, 64 ; 64 MB DRAM BANK 0,1 DCD 0x90800000, 0x48000000, 1 ; Memory control register DCD 0x90900000, 0x49000000, 1 ; USB Host register DCD 0x90A00000, 0x4A000000, 1 ; Interrupt Control register DCD 0x90B00000, 0x4B000000, 1 ; DMA control register DCD 0x90C00000, 0x4C000000, 1 ; Clock & Power register DCD 0x90D00000, 0x4D000000, 1 ; LCD control register DCD 0x90E00000, 0x4E000000, 1 ; NAND flash control register DCD 0x91000000, 0x50000000, 1 ; UART control register DCD 0x91100000, 0x51000000, 1 ; PWM timer register DCD 0x91200000, 0x52000000, 1 ; USB device register DCD 0x91300000, 0x53000000, 1 ; Watchdog Timer register DCD 0x91400000, 0x54000000, 1 ; IIC control register DCD 0x91500000, 0x55000000, 1 ; IIS control register DCD 0x91600000, 0x56000000, 1 ; I/O Port register DCD 0x91700000, 0x57000000, 1 ; RTC control register DCD 0x91800000, 0x58000000, 1 ; A/D convert register DCD 0x91900000, 0x59000000, 1 ; SPI register DCD 0x91A00000, 0x5A000000, 1 ; SD Interface register DCD 0x92000000, 0x00000000, 2 ; 2 MB SROM(SRAM/ROM) BANK 0 DCD 0x00000000, 0x00000000, 0 ; End of Table (MB MUST BE ZERO!)
这是按原来5.0的BSP中oemAddressTable的值来修改的.
接着把5.0的BSP中的config.big替换掉6.0的config.bib(My2410/FILES)
然后到image_cfg.h文件(My2410/SRC/INC)下,把下面几个宏定义改为如下的值:
#define IMAGE_SHARE_ARGS_UA_START 0xAC020000 #define IMAGE_SHARE_ARGS_CA_START 0x8c020800 #define IMAGE_SHARE_ARGS_SIZE 0x00000800 //------------------------------------------------------------------------------ #define IMAGE_FRAMEBUFFER_UA_BASE 0xAC100000 #define IMAGE_FRAMEBUFFER_DMA_BASE 0x30100000
另外找到如下四行:
#define EBOOT_CONFIG_OFFSET 0x000F0000 #define EBOOT_CONFIG_SIZE 0x00010000 #define EXTENDED_RAM_BASE 0x94000000 // This must match the "Extended RAM" #define EXTENDED_RAM_MEGS 192 // 192 Megs
这四行直接注释掉, 前两行是eboot的相关配置, 它在My2410/SRC/BOOTLOADER/EBOOT下的文件会被用到. 前面说了, 我没有用wince的这个eboot,所以可以不要. 后两行是扩展内存用的. 这两个宏在OEMGetExtensionDRAM函数(My2410/SRC/OAL/OALLIB/init.c) 会用到, 因为根据OEMAddressTabel的配置, 并没有扩展内存, 所以这个也可以不要, 然后清空OEMGetExtensionDRAM的实现,只留一行:Return FALSE. 这个函数在内核的KernelFindMemory里会被调用, 做扩展内存的相关设置.
7 电源管理
到power.c文件(SRC/OAL/POWER), 找到CPUClearCS8900(void)函数, 把它的实现改为如下的:
PRIVATE void CPUClearCS8900(void) { USHORT temp; do { temp = *((volatile USHORT *)(BSP_BASE_REG_PA_CS8900A_IOBASE + 8)); } while (temp != 0); }
在power.c里加入void ConfigMiscReg和ConfigStopGPIO两个函数. 这两个函数被OEMPowerOff函数调用,这两个函数用于在系统关机时, 关闭一些IO资源. 它们的实现分别参见原5.0 BSP下的power.c文件, 但注意不是直接copy过来就能用, 因为它们获到地址的方法不一样, 举例来说,原来的BSP这样获取IO口的虑拟地址:
volatile IOPreg *s2410IOP = (IOPreg *)IOP_BASE;
移植到6.0后就要改成如下的形式:
static volatile S3C2410X_IOPORT_REG *s2410IOP = (S3C2410X_IOPORT_REG *)OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT, FALSE);
到Powerstub.c(SRC/OAL/POWER) 里的函数全部都只有一句实现, return TRUE,比如:
BOOL OALIoCtlHalPresuspend( UINT32 code, VOID* pInpBuffer, UINT32 inpSize, VOID* pOutBuffer, UINT32 outSize, UINT32 *pOutSize ) { return TRUE; }
8 中断处理
找到BSPIntrInit函数(SRC/OAL/OALLIB/intr.c), 根据原来的BSP中OEMInitInterrupts函数的实现,修改BSPIntrInit如下:
BOOL BSPIntrInit() { S3C2410X_IOPORT_REG *pOalPortRegs; ULONG value; OALMSG(OAL_INTR&&OAL_FUNC, (L"+BSPIntrInit/r/n")); // Then get virtual address for IO port pOalPortRegs = OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT, FALSE); /***************************************************************************/ value = INREG32(&pOalPortRegs->GPGCON); OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 10))|(2 << 10)); //GPG5 == EINT13. value = INREG32(&pOalPortRegs->GPGUP);// Disable pullup OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 5)); value = INREG32(&pOalPortRegs->EXTINT1);// High level interrupt OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 20))|(0x4 << 20)); /***************************************************************************/ value = INREG32(&pOalPortRegs->GPGCON);// Set GPG1 as EINT9 for CS8900A OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 2))|(2 << 2)); value = INREG32(&pOalPortRegs->GPGUP);// Disable pullup OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 1)); value = INREG32(&pOalPortRegs->EXTINT1);// High level interrupt OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 4))|(0x1 << 4)); /***************************************************************************/ value = INREG32(&pOalPortRegs->GPGCON);// Configure EINT14 for dm9000 interrupt. OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 12))|(2 << 12)); value = INREG32(&pOalPortRegs->GPGUP);// Disable pullup OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 6)); value = INREG32(&pOalPortRegs->EXTINT1);// High level interrupt OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 24))|(0x1 << 24)); /***************************************************************************/ // Configure EINT8 for PD6710 interrupt value = INREG32(&pOalPortRegs->GPGCON); OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 0))|(2 << 0)); // Disable pullup value = INREG32(&pOalPortRegs->GPGUP); OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 0)); // Low level interrupt value = INREG32(&pOalPortRegs->EXTINT1); OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 0))|(0x1 << 0)); /***************************************************************************/s // Add static mapping for Built-In OHCI OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH ); OALMSG(OAL_INTR&&OAL_FUNC, (L"-BSPIntrInit(rc = 1)/r/n")); return TRUE; }
9 其它
找到init.c(SRC/OAL/OALLIB/init.c)函数里加上两个函数. 这两个函数分别叫
InitSDMMC和HzhInitPIO,两个函数的实现可从原BSP(在cfw.c文件中)直接copy过来.
然后在职OEMInit函数里调用这两个函数.
OAL部分应该还有些东西要移植, 不过到目前为止, 系统已经可以启动了, 下面移植外围驱动
时,如果遇到哪里有问题,再回过头来修改吧.
到这里,系统已可以启动起来了, 目前启动信息如下:
Windows CE Kernel for ARM (Thumb Enabled) Built on Sep 25 2009 at 11:06:11 ProcessorType=0920 Revision=0 OEMAddressTable = 8c205c10 INFO:OALLogSetZones: dpCurSettings.ulZoneMask: 0xb DCache: 8 sets, 64 ways, 32 line size, 16384 size ICache: 8 sets, 64 ways, 32 line size, 16384 size this is initDisplay2............ SDMMC config current rGPGCON: 26898a SDMMC config set rGPGCON: 26898a SDMMC config Init Done. Setting up softlog at 0x8fffc000 for 0x800 entries Booting Windows CE version 6.00 for (ARM) &pTOC = 8e00ac1c, pTOC = 8c2d6a44, pTOC->ulRamFree = 8e00f000, MemForPT = 00001000 Old or invalid version stamp in kernel structures - starting clean! Configuring: Primary pages: 8167, Secondary pages: 0, Filesystem pages = 4083 Booting kernel with clean memory configuration: Memory Sections: [0] : start: 8e011000, extension: 00004000, length: 01fe7000 NKStartup done, starting up kernel. Windows CE KernelInit Reserve VM for kernel XIP DLls, first = c0010000, last = c0260000 g_pprcNK == 0x8e008aa0 Updated eptr->e32_vsize to = 00013000 Initializing Memory Mapped File Support Scheduling the first thread. Detecting VFP... VFP Not Found! LoaderInit: Initialing loader Updated eptr->e32_vsize to = 00013000 Updated eptr->e32_vsize to = 000a3000 PGPOOL: Reserved 768 pages for Loader pool PGPOOL: Reserved 256 pages for File pool OSAXST0: Platform Name = DeviceEmulator OSAXST1: >>> Loading Module 'kd.dll' (0x8FFDF744) at address 0xC0010000-0xC0045000 in Process 'NK.EXE' (0x8E008AA0) KD: Starting kernel debugger software probe (KdStub) - KD API version 22 OSAXST1: >>> Loading Module 'NK.EXE' (0x8E008AA0) at address 0x8C200000-0x8C213000 in Process 'NK.EXE' (0x8E008AA0) Message Queue support initialized, g_hMsgQHeap = d0080010 OSAXST1: >>> Loading Module 'filesys.dll' (0x8FFDFE88) at address 0xC0180000-0xC01E7000 in Process 'NK.EXE' (0x8E008AA0) OSAXST1: >>> Loading Module 'fsdmgr.dll' (0x8FFBA574) at address 0xC0210000-0xC0256000 in Process 'NK.EXE' (0x8E008AA0) FSDMGR!DllMain: DLL_PROCESS_ATTACH CertMod.dll not found, using old OEM Trust Model FileSystem Starting - starting with clean file system FSDMGR!STOREMGR_Initialize FSDMGR!InitializeStoreAPI FSDMGR!MountTable_t::RegisterVolumeName: Registered "StoreMgr" at index 2FSDMGR!MountTable_t::RegisterVolume: Registered volume at index 2 (Name="StoreMgr", MountFlags=0x1)FSDMGR!InitializeROMFileSystem: File System=ROM OSAXST1: >>> Loading Module 'romfsd.dll' (0x8FF9E3CC) at address 0xC01F0000-0xC01F7000 in Process 'NK.EXE' (0x8E008AA0) FSDMGR!MountTable_t::RegisterVolumeName: Registered "ROM" at index 3FSDMGR!MountTable_t::RegisterVolume: Registered volume at index 3 (Name="ROM", MountFlags=0x71)FSVOL: Opening existing volume FSVOL: Volume heap already initialized FSREG: Mounted ROM portion of boot registry FSVOL: Creating clean virtual volume FSVOL: Initializing volume heap FSREG: Mounted RAM portion of boot registry OALIoCtlDeviceEmulatorHalInitRegistry: Set Orientation to 0 pBSPArgs->ScreenOrientation = 205 OALIoCtlDeviceEmulatorHalInitRegistry: FMD reserve size 0x7fffdfff; base addr 0x7fffd7ff FS: HKLM/System/Events not available, no signal events created. FSREG: Unable to read value "Start DevMgr" under HKEY_LOCAL_MACHINE/init/BootVars FILESYS: Starting boot phase 0. FSDMGR!STOREMGR_StartBootPhase BootPhase=0 (PrevBootPhase=-1) FSDMGR: File security disabled. FSDMGR!AutoLoadFiFSDMGR!PNPThread: Using PNPUnloadDeleSystems: CurrentBootPhase=0, LoadFlags=lay of 4096 FSDMGR!PNPThread: PNP1 FSDMGR!AutoLoadFileSystem: CuThread starting! rrentBootPhase=0, RootKey=System/StorageManager/AutoLoad, FileSystem_t=ObjectStore FILESYS: RAM File System FSD_MountDisk registering folder "Object Store" FSDMGR!MountTable_t::RegisterVolumeName: Registered "Object Store" at index 4FSDMGR!MountTable_t::RegisterVolume: Registered volume at index 4 (Name="", MountFlags=0x46)FILESYS: Starting boot phase 1. FSDMGR!STOREMGR_StartBootPhase BootPhase=1 (PrevBootPhase=0) FSDMGR!AutoLoadFileSystems: CurrentBootPhase=1, LoadFlags=1 FILESYS: Waiting for bootable file system to be mounted. FILESYS: Device started. Boot file system ready. FSREG: Unable to read value "SystemHiveInitialSize" under HKEY_LOCAL_MACHINE/init/BootVars FSVOL: Opening existing volume FSVOL: Volume heap already initialized FSREG: Mounted ROM portion of system hive FILESYS: Loading system hive from /Documents and Settings/system.hv. FSREG: Mounting clean system hive BuildPath: Documents and Settings FSVOL: Creating new volume (size=28672 bytes) FSVOL: Initializing volume heap FSREG: Taking down boot registry. Any open keys will be invalid. FILESYS: Registry in place. FSREG: Unable to read value "RegistryFlags" under HKEY_LOCAL_MACHINE/init/BootVars FSREG: Unable to read value "RequireCertMod" under HKEY_LOCAL_MACHINE/init/BootVars FSREG: Unable to read value "NoDefaultUser" under HKEY_LOCAL_MACHINE/init/BootVars FSREG: Logging in default user. FSREG: Unable to read value "DefaultUser" under HKEY_LOCAL_MACHINE/init/BootVars SetCurrentUser: Logging out (nobody), logging in default BuildPath: Documents and Settings BuildPath: Documents and Settings/default FSREG: Mounting ROM portion of user hive FSVOL: Opening existing volume FSVOL: Volume heap already initialized Mounting user hive from /Documents and Settings/default/user.hv FSREG: Mounting clean user hive FSVOL: Creating new volume (size=28672 bytes) FSVOL: Initializing volume heap FSREG: Unable to read value "RegistryFlags" under HKEY_LOCAL_MACHINE/init/BootVars FSDMGR!STOREMGR_StartBootPhase BootPhase=2 (PrevBootPhase=1) FSDMGR!AutoLoadFileSystems: CurrentBootPhFSDMGR!AutoLoadFileSystems: CurrentBootPhaase=2, LoadFlags=2 se=2, LoadFlags=1 Filesystem initialized! FILESYS: Waiting for kernel to be ready to launch apps InitMUI: Langs=409 0 0 0 0 0 FS: HKLM/System/Events not available, no signal events created. FILESYS: Launching apps FILESYS: Done launching apps This device has booted 1 times !!!