BootloaderMain
在进行全局变量重定位后,执行的便是
OEMDebugInit
操作,主要完成调试串口的初始化工作,这部分内容比较简单。从函数名
OEM
可以看出,该函数是需要用户自己开发的,而且与硬件有关。
BOOL OEMDebugInit(void)
{
// Set up function callbacks used by blcommon.
g_pOEMVerifyMemory = OEMVerifyMemory; // Verify RAM.
g_pOEMMultiBINNotify = OEMMultiBINNotify;
// Call serial initialization routine (shared with the OAL).
OEMInitDebugSerial();
return(TRUE);
}
{
// Set up function callbacks used by blcommon.
g_pOEMVerifyMemory = OEMVerifyMemory; // Verify RAM.
g_pOEMMultiBINNotify = OEMMultiBINNotify;
// Call serial initialization routine (shared with the OAL).
OEMInitDebugSerial();
return(TRUE);
}
从上面的实现看,前面两条语句定义的是函数指针,在
blcommom.c
中会调用这两个函数。
OEMVerifyMemory
函数负责检测某一段虚拟内存地址区域是否映射到用户实际可使用的物理存储,包括
Flash
和
RAM
;当
BootLoader
要下载多区段的操作系统镜像时会调用函数
OEMMultiBINNotify
向用户发出通知。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
OEMInitDebugSerial
才是该函数的重点,实现代码在
/WINCE600/PLATFORM/<BSP name>/SRC/OAL/OALLIB/debug.c
文件中。
VOID OEMInitDebugSerial()
{
UINT32 DivSlot;
UINT32 uPCLK;
float Div;
// Map SFR Address
//
if (g_pUARTReg == NULL)
{
#if (DEBUG_PORT == DEBUG_UART0)
// UART0
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART0, FALSE);
#elif (DEBUG_PORT == DEBUG_UART1)
// UART1
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART1, FALSE);
#elif (DEBUG_PORT == DEBUG_UART2)
// UART2
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART2, FALSE);
#elif (DEBUG_PORT == DEBUG_UART3)
// UART3
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART3, FALSE);
#else
INVALID_DEBUG_PORT // Error
#endif
}
if (g_pGPIOReg == NULL)
{
g_pGPIOReg = (S3C6410_GPIO_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_GPIO, FALSE);
}
if (g_pSysConReg == NULL)
{
g_pSysConReg = (S3C6410_SYSCON_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_SYSCON, FALSE);
}
// UART I/O port initialize
#if (DEBUG_PORT == DEBUG_UART0)
// UART0 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<1); // UART0
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART0 Port Initialize (RXD0 : GPA0, TXD0: GPA1)
g_pGPIOReg->GPACON = (g_pGPIOReg->GPACON & ~(0xff<<0)) | (0x22<<0); // GPA0->RXD0, GPA1->TXD0
g_pGPIOReg->GPAPUD = (g_pGPIOReg->GPAPUD & ~(0xf<<0)) | (0x1<<0); // RXD0: Pull-down, TXD0: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART1)
// UART1 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<2); // UART1
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART1 Port Initialize (RXD1 : GPA4, TXD1: GPA5)
g_pGPIOReg->GPACON = (g_pGPIOReg->GPACON & ~(0xff<<16)) | (0x22<<16); // GPA4->RXD1, GPA5->TXD1
g_pGPIOReg->GPAPUD = (g_pGPIOReg->GPAPUD & ~(0xf<<8)) | (0x1<<8); // RXD1: Pull-down, TXD1: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART2)
// UART2 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<3); // UART2
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART2 Port Initialize (RXD2 : GPAB0, TXD2: GPB1)
g_pGPIOReg->GPBCON = (g_pGPIOReg->GPBCON & ~(0xff<<0)) | (0x22<<0); // GPB0->RXD2, GPB1->TXD2
g_pGPIOReg->GPBPUD = (g_pGPIOReg->GPBPUD & ~(0xf<<0)) | (0x1<<0); // RXD2: Pull-down, TXD2: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART3)
// UART3 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<4); // UART3
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART3 Port Initialize (RXD3 : GPB2, TXD3: GPB3)
g_pGPIOReg->GPBCON = (g_pGPIOReg->GPBCON & ~(0xff<<8)) | (0x22<<8); // GPB2->RXD3, GPB3->TXD3
g_pGPIOReg->GPBPUD = (g_pGPIOReg->GPBPUD & ~(0xf<<4)) | (0x1<<4); // RXD3: Pull-down, TXD3: pull up/down disable
#endif
// Initialize UART
//
g_pUARTReg->ULCON = (0<<6)|(0<<3)|(0<<2)|(3<<0); // Normal Mode, No Parity, 1 Stop Bit, 8 Bit Data
g_pUARTReg->UCON = (0<<10)|(1<<9)|(1<<8)|(0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0); // PCLK divide, Polling Mode
g_pUARTReg->UFCON = (0<<6)|(0<<4)|(0<<2)|(0<<1)|(0<<0); // Disable FIFO
g_pUARTReg->UMCON = (0<<5)|(0<<4)|(0<<0); // Disable Auto Flow Control
uPCLK = System_GetPCLK();
Div = (float)((float)uPCLK/(16.0*(float)DEBUG_BAUDRATE)) - 1; //< S3C6410_PCLK is macro code defined in soc_cfg.h
DivSlot = (UINT32)((Div-(int)Div)*16);
g_pUARTReg->UBRDIV = (UINT32)Div; // Baud rate
g_pUARTReg->UDIVSLOT = aSlotTable[DivSlot];
}
{
UINT32 DivSlot;
UINT32 uPCLK;
float Div;
// Map SFR Address
//
if (g_pUARTReg == NULL)
{
#if (DEBUG_PORT == DEBUG_UART0)
// UART0
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART0, FALSE);
#elif (DEBUG_PORT == DEBUG_UART1)
// UART1
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART1, FALSE);
#elif (DEBUG_PORT == DEBUG_UART2)
// UART2
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART2, FALSE);
#elif (DEBUG_PORT == DEBUG_UART3)
// UART3
g_pUARTReg = (S3C6410_UART_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_UART3, FALSE);
#else
INVALID_DEBUG_PORT // Error
#endif
}
if (g_pGPIOReg == NULL)
{
g_pGPIOReg = (S3C6410_GPIO_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_GPIO, FALSE);
}
if (g_pSysConReg == NULL)
{
g_pSysConReg = (S3C6410_SYSCON_REG *)OALPAtoVA(S3C6410_BASE_REG_PA_SYSCON, FALSE);
}
// UART I/O port initialize
#if (DEBUG_PORT == DEBUG_UART0)
// UART0 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<1); // UART0
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART0 Port Initialize (RXD0 : GPA0, TXD0: GPA1)
g_pGPIOReg->GPACON = (g_pGPIOReg->GPACON & ~(0xff<<0)) | (0x22<<0); // GPA0->RXD0, GPA1->TXD0
g_pGPIOReg->GPAPUD = (g_pGPIOReg->GPAPUD & ~(0xf<<0)) | (0x1<<0); // RXD0: Pull-down, TXD0: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART1)
// UART1 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<2); // UART1
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART1 Port Initialize (RXD1 : GPA4, TXD1: GPA5)
g_pGPIOReg->GPACON = (g_pGPIOReg->GPACON & ~(0xff<<16)) | (0x22<<16); // GPA4->RXD1, GPA5->TXD1
g_pGPIOReg->GPAPUD = (g_pGPIOReg->GPAPUD & ~(0xf<<8)) | (0x1<<8); // RXD1: Pull-down, TXD1: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART2)
// UART2 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<3); // UART2
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART2 Port Initialize (RXD2 : GPAB0, TXD2: GPB1)
g_pGPIOReg->GPBCON = (g_pGPIOReg->GPBCON & ~(0xff<<0)) | (0x22<<0); // GPB0->RXD2, GPB1->TXD2
g_pGPIOReg->GPBPUD = (g_pGPIOReg->GPBPUD & ~(0xf<<0)) | (0x1<<0); // RXD2: Pull-down, TXD2: pull up/down disable
#elif (DEBUG_PORT == DEBUG_UART3)
// UART3 Clock Enable
g_pSysConReg->PCLK_GATE |= (1<<4); // UART3
g_pSysConReg->SCLK_GATE |= (1<<5); // UART0~3
// UART3 Port Initialize (RXD3 : GPB2, TXD3: GPB3)
g_pGPIOReg->GPBCON = (g_pGPIOReg->GPBCON & ~(0xff<<8)) | (0x22<<8); // GPB2->RXD3, GPB3->TXD3
g_pGPIOReg->GPBPUD = (g_pGPIOReg->GPBPUD & ~(0xf<<4)) | (0x1<<4); // RXD3: Pull-down, TXD3: pull up/down disable
#endif
// Initialize UART
//
g_pUARTReg->ULCON = (0<<6)|(0<<3)|(0<<2)|(3<<0); // Normal Mode, No Parity, 1 Stop Bit, 8 Bit Data
g_pUARTReg->UCON = (0<<10)|(1<<9)|(1<<8)|(0<<7)|(0<<6)|(0<<5)|(0<<4)|(1<<2)|(1<<0); // PCLK divide, Polling Mode
g_pUARTReg->UFCON = (0<<6)|(0<<4)|(0<<2)|(0<<1)|(0<<0); // Disable FIFO
g_pUARTReg->UMCON = (0<<5)|(0<<4)|(0<<0); // Disable Auto Flow Control
uPCLK = System_GetPCLK();
Div = (float)((float)uPCLK/(16.0*(float)DEBUG_BAUDRATE)) - 1; //< S3C6410_PCLK is macro code defined in soc_cfg.h
DivSlot = (UINT32)((Div-(int)Div)*16);
g_pUARTReg->UBRDIV = (UINT32)Div; // Baud rate
g_pUARTReg->UDIVSLOT = aSlotTable[DivSlot];
}
从代码可以看出,里面加了很多编译选项,增强移植性的。当需要更改调试串口时,只需要更改编译选项就可以了。
通过
OALPAtoVA
先将获得调试串口、
GPI
以及系统控制器的虚拟地址,方便后面的初始化设置。
g_pSysConReg->PCLK_GATE
为
UART1
选通
PLCK
,
g_pSysConReg->SCLK_GATE
为
UART0~3
选通特殊时钟。
g_pGPIOReg->GPACON
设置复用
IO
端口为
UART
功能,
g_pGPIOReg->GPAPUD
设置相应的串口管脚位下拉使能。
g_pUARTReg->ULCON
设置串口为普通模式、无校验、
1
个停止位和
8
个数据位;
g_pUARTReg->UCON
设置选择
PCLK
作为
UART
的波特率时钟,接收和发送中断请求类型为电平模式,而且以中断请求或轮询模式来写发送数据到
UART
发送缓冲寄存器或者从
UART
接收缓冲寄存器读数据。
最后几条代码是获得
PCLK
后设置波特率参数。
转载于:https://blog.51cto.com/jazka/602183