分类: 嵌入式
2010-05-16 10:16:04
经过数个星期的研究,终于完成了一个能在TQ2440开发板上运行的简单bootloader,其实目前功能很简单,就是做一些初始化并在串口显示一段文字,好多功能还没有实现。经过这一番“痛苦”的过程,自己还是有一些感想的:
多看源码
所谓“书读百变,其意自现”,读代码也是同样的道理。多读几遍之后,你就会发现原来让你一看就烦躁、郁闷的代码,其实也并不那么难理解。推荐看开发板提供给我们的代码,以及目前比较流行的通用bootloader(例如UBoot)。
多查文档
对于写这种偏底层的开发,文档时必需的。bootloader大部分的工作其实就是读写各种寄存器(或是某内存单元),其实有时令人郁闷的不是怎么设置一些值,而是查找这些值背后含义以及原理的过程。文档上面写的清清楚楚,就看你能不能找到以及理解背后的原理。
多做试验
bootloader还是很复杂的,一下子就把所有功能实现基于是不可能的。那就要从一个最简单的功能做起,比如LED或是串口输出,以这个目标去做bootloader应该会比较容易实现。可以把开发板提供给我们的bootloader仔细研究研究,注释掉一些功能,看看有什么影响,如果有影响,说明这段代码对于某个功能起了作用,这样可以把研究范围缩小。
下面就是bootloader的主要代码,供大家参考,欢迎留言讨论。
startup.s
;CPSR[4:0]中各模式
USRMODE * 0X10 ;用户模式
FIQMODE * 0X11 ;FIQ模式
IRQMODE * 0X12 ;IRQ模式
SUPMODE * 0X13 ;管理模式
ABTMODE * 0X17 ;中断模式
UDFMODE * 0X1B ;未定义模式
SYSMODE * 0X1F ;系统模式
MODEMSK * 0X1F ;00011111 用于清除[4:0]
NOINT * 0XC0 ;AIFT = 1100
;The location of stacks
_STACK_BASEADDRESS EQU 0×33ff8000
USRSTACK EQU (_STACK_BASEADDRESS-0×3800) ;0×33ff4800 ~
SUPSTACK EQU (_STACK_BASEADDRESS-0×2800) ;0×33ff5800 ~
UDFSTACK EQU (_STACK_BASEADDRESS-0×2400) ;0×33ff5c00 ~
ABTSTACK EQU (_STACK_BASEADDRESS-0×2000) ;0×33ff6000 ~
IRQSTACK EQU (_STACK_BASEADDRESS-0×1000) ;0×33ff7000 ~
FIQSTACK EQU (_STACK_BASEADDRESS-0×0) ;0×33ff8000 ~
;UPLL
U_MDIV * 56
U_PDIV * 2
U_SDIV * 2
;MPLL
M_MDIV * 92
M_PDIV * 1
M_SDIV * 1
BIT_SELFREFRESH * 1<<22
IMPORT |Image$$RO$$Base| ; Base of ROM code
IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data)
IMPORT |Image$$RW$$Base| ; Base of RAM to initialise
IMPORT |Image$$ZI$$Base| ; Base and limit of area
IMPORT |Image$$ZI$$Limit| ; to zero initialise
GET 2440addr.s
GET memcfg.s
AREA init, CODE, READONLY
ENTRY
resetEntry
B reset ;复位
; B undefined_instruction ;未定义指令
; B software_interupt ;软件中断
; B prefetch_abort ;预取指令错误
; B data_abort ;预取数据错误
; B . ;保留中断向量
; B irq ;irq异常
; B fiq ;fiq异常
EXPORT reset
reset
;关闭看门狗
ldr r0, =WTCON
ldr r1, =0×0
str r1, [r0]
;关闭所有中断
ldr r0, =INTMSK
ldr r1, =0xFFFFFFFF
str r1, [r0]
ldr r0, =INTSUBMSK ;关闭所有子中断
ldr r1, =0×7FFFF ;INTSUBMSK只有[14:0]被使用
str r1, [r0]
;初始化时钟
ldr r0, =LOCKTIME
ldr r1, =0xFFFFFFFF
str r1, [r0]
ldr r0, =CLKDIVN
ldr r1, =5 ;1:4:8
str r1, [r0]
;UPLL
ldr r0, =UPLLCON
ldr r1, =(U_MDIV<<12) + (U_PDIV<<4) + U_SDIV ;Fin = 12MHz UCLK = 48MHz
str r1, [r0]
nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.
nop
nop
nop
nop
nop
nop
;MPLL
ldr r0, =MPLLCON
ldr r1, =(M_MDIV<<12) + (M_PDIV<<4) + M_SDIV ;Fin = 12MHz PCLK = 400MHz
str r1, [r0]
;工作在异步模式
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000
mcr p15,0,r0,c1,c0,0
;LED显示
ldr r0,=GPBCON
ldr r1,=0×155500
str r1,[r0]
ldr r0,=GPBDAT
ldr r1,=0×0
str r1,[r0] ;LED=****
;初始化SDRAM
ldr r0, =BWSCON
ldr r1, =(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
str r1, [r0]
ldr r0, =BANKSIZE
ldr r1, =0×32
str r1, [r0]
ldr r0, =REFRESH
ldr r1, =((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+(Tchr<<16)+REFCNT)
str r1, [r0]
ldr r0, =MRSRB6
ldr r1, =0×32
str r1, [r0]
;初始化堆栈
bl InitStack
;copy_proc_beg
adr r0, resetEntry
ldr r2, BaseOfROM
cmp r0, r2
beq Over
ldr r3, TopOfROM
0
ldmia r0!, {r4-r7}
stmia r2!, {r4-r7}
cmp r2, r3
bcc %B0
IMPORT Main
Over
bl Main ;C程序入口
b .
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;初始化堆栈
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
InitStack
mrs r0, cpsr
bic r0, r0, #MODEMSK
;初始化未定义模式栈
orr r1, r0, #UDFMODE|NOINT
msr cpsr_cxsf, r1 ;cpsr_all = cpsr_cxsf
ldr sp, =UDFSTACK
;初始化FIQ栈
orr r1, r0, #FIQMODE|NOINT
msr cpsr_cxsf, r1
ldr sp, =FIQSTACK
;初始化IRQ栈
orr r1, r0, #IRQMODE|NOINT
msr cpsr_cxsf, r1
ldr sp, =IRQSTACK
;初始化ABORT栈
orr r1, r0, #ABTMODE|NOINT
msr cpsr_cxsf, r1
ldr sp, =ABTSTACK
;初始化管理模式栈
orr r1, r0, #SUPMODE|NOINT
msr cpsr_cxsf, r1
ldr sp, =SUPSTACK
mov pc, lr
BaseOfROM DCD |Image$$RO$$Base|
TopOfROM DCD |Image$$RO$$Limit|
BaseOfBSS DCD |Image$$RW$$Base|
BaseOfZero DCD |Image$$ZI$$Base|
EndOfBSS DCD |Image$$ZI$$Limit|
END
main.c
#include "2440addr.h"
#include
#include
#include
#include
#include
int PCLK = 50000000; //50MHz
void Port_Init(void)
{
//CAUTION:Follow the configuration order for setting the ports.
// 1) setting value(GPnDAT)
// 2) setting control register (GPnCON)
// 3) configure pull-up resistor(GPnUP)
//32bit data bus configuration
//*** PORT A GROUP
//Ports : GPA22 GPA21 GPA20 GPA19 GPA18 GPA17 GPA16 GPA15 GPA14 GPA13 GPA12
//Signal : nFCE nRSTOUT nFRE nFWE ALE CLE nGCS5 nGCS4 nGCS3 nGCS2 nGCS1
//Binary : 1 1 1 , 1 1 1 1 , 1 1 1 1
//Ports : GPA11 GPA10 GPA9 GPA8 GPA7 GPA6 GPA5 GPA4 GPA3 GPA2 GPA1 GPA0
//Signal : ADDR26 ADDR25 ADDR24 ADDR23 ADDR22 ADDR21 ADDR20 ADDR19 ADDR18 ADDR17 ADDR16 ADDR0
//Binary : 1 1 1 1 , 1 1 1 1 , 1 1 1 1
rGPACON = 0×7fffff;
//**** PORT B GROUP
//Ports : GPB10 GPB9 GPB8 GPB7 GPB6 GPB5 GPB4 GPB3 GPB2 GPB1 GPB0
//Signal : nXDREQ0 nXDACK0 nXDREQ1 nXDACK1 nSS_KBD nDIS_OFF L3CLOCK L3DATA L3MODE nIrDATXDEN Keyboard
//Setting: INPUT OUTPUT INPUT OUTPUT INPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT OUTPUT
//Binary : 00 , 01 00 , 01 00 , 01 01 , 01 01 , 01 01
//rGPBCON = 0×000150;(youlong)
rGPBCON = 0×015550;
rGPBUP = 0×7ff; // The pull up function is disabled GPB[10:0]
//*** PORT C GROUP for youlong
//Ports : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0
//Signal : VD7 VD6 VD5 VD4 VD3 VD2 VD1 VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND
//Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10
//rGPCCON = 0xaaaaaaaa;
//rGPCUP = 0xffff; // The pull up function is disabled GPC[15:0]
//*** PORT C GROUP
//Ports : GPC15 GPC14 GPC13 GPC12 GPC11 GPC10 GPC9 GPC8 GPC7 GPC6 GPC5 GPC4 GPC3 GPC2 GPC1 GPC0
//Signal : VD7 VD6 VD5 VD4 VD3 VD2 VD1 VD0 LCDVF2 LCDVF1 LCDVF0 VM VFRAME VLINE VCLK LEND
//Binary : 10 10 , 10 10 , 10 10 , 10 01 , 01 01 , 01 10 , 10 10 , 10 10
rGPCCON = 0xaaa956aa;
rGPCUP = 0xffff; // The pull up function is disabled GPC[15:0]
//*** PORT D GROUP
//Ports : GPD15 GPD14 GPD13 GPD12 GPD11 GPD10 GPD9 GPD8 GPD7 GPD6 GPD5 GPD4 GPD3 GPD2 GPD1 GPD0
//Signal : VD23 VD22 VD21 VD20 VD19 VD18 VD17 VD16 VD15 VD14 VD13 VD12 VD11 VD10 VD9 VD8
//Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 10 ,10 10
rGPDCON = 0xaaaaaaaa;
rGPDUP = 0xffff; // The pull up function is disabled GPD[15:0]
//*** PORT E GROUP
//Ports : GPE15 GPE14 GPE13 GPE12 GPE11 GPE10 GPE9 GPE8 GPE7 GPE6 GPE5 GPE4
//Signal : IICSDA IICSCL SPICLK SPIMOSI SPIMISO SDDATA3 SDDATA2 SDDATA1 SDDATA0 SDCMD SDCLK IN
//Binary : 10 10 , 10 10 , 10 10 , 10 10 , 10 10 , 10 00 ,
//——————————————————————————————————-
//Ports : GPE3 GPE2 GPE1 GPE0
//Signal : IN IN IN IN
//Binary : 00 00 , 00 00
//rGPECON = 0xaaaaaaaa;
//rGPEUP = 0xffff; // The pull up function is disabled GPE[15:0]
rGPECON = 0xa02aa800; // For added AC97 setting
rGPEUP = 0xffff;
//*** PORT F GROUP
//Ports : GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0
//Signal : nLED_8 nLED_4 nLED_2 nLED_1 nIRQ_PCMCIA EINT2 KBDINT EINT0
//Setting: Output Output Output Output EINT3 EINT2 EINT1 EINT0
//Binary : 01 01 , 01 01 , 10 10 , 10 10
rGPFCON = 0×55aa;
rGPFUP = 0xff; // The pull up function is disabled GPF[7:0]
//*** PORT G GROUP
//Ports : GPG15 GPG14 GPG13 GPG12 GPG11 GPG10 GPG9 GPG8 GPG7 GPG6
//Signal : nYPON YMON nXPON XMON EINT19 DMAMODE1 DMAMODE0 DMASTART KBDSPICLK KBDSPIMOSI
//Setting: nYPON YMON nXPON XMON EINT19 Output Output Output SPICLK1 SPIMOSI1
//Binary : 11 11 , 11 11 , 10 01 , 01 01 , 11 11
//—————————————————————————————–
//Ports : GPG5 GPG4 GPG3 GPG2 GPG1 GPG0
//Signal : KBDSPIMISO LCD_PWREN EINT11 nSS_SPI IRQ_LAN IRQ_PCMCIA
//Setting: SPIMISO1 LCD_PWRDN EINT11 nSS0 EINT9 EINT8
//Binary : 11 11 , 10 11 , 10 10
rGPGCON = 0×00a2aaaa;// GPG9 input without pull-up
rGPGUP = 0xffff; // The pull up function is disabled GPG[15:0]
//*** PORT H GROUP
//Ports : GPH10 GPH9 GPH8 GPH7 GPH6 GPH5 GPH4 GPH3 GPH2 GPH1 GPH0
//Signal : CLKOUT1 CLKOUT0 UCLK nCTS1 nRTS1 RXD1 TXD1 RXD0 TXD0 nRTS0 nCTS0
//Binary : 10 , 10 10 , 11 11 , 10 10 , 10 10 , 10 10
rGPHCON = 0×00faaa;
rGPHUP = 0×7ff; // The pull up function is disabled GPH[10:0]
// Added for S3C2440X, DonGo
//*** PORT J GROUP
//Ports : GPJ12 GPJ11 GPJ10 GPJ9 GPJ8 GPJ7 GPJ6 GPJ5 GPJ4 GPJ3 GPJ2 GPJ1 GPJ0
//Signal : CAMRESET CAMPCLKOUT CAMHREF CAMVSYNC CAMPCLKIN CAMDAT[7] CAMDAT[6] CAMDAT[5] CAMDAT[4] CAMDAT[3] CAMDAT[2] CAMDAT[1] CAMDAT[0]
//Binary : 10 10 10 10 10 10 10 10 10 10 10 10 10
rGPJCON = 0×02aaaaaa;
rGPJUP = 0×1fff; // The pull up function is disabled GPH[10:0]
//External interrupt will be falling edge triggered.
rEXTINT0 = 0×22222222; // EINT[7:0]
rEXTINT1 = 0×22222222; // EINT[15:8]
rEXTINT2 = 0×22222222; // EINT[23:16]
}
void Uart_Init(int pclk,int baud)
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0×0; //UART channel 0 FIFO control register, FIFO disable
rUFCON1 = 0×0; //UART channel 1 FIFO control register, FIFO disable
rUFCON2 = 0×0; //UART channel 2 FIFO control register, FIFO disable
rUMCON0 = 0×0; //UART chaneel 0 MODEM control register, AFC disable
rUMCON1 = 0×0; //UART chaneel 1 MODEM control register, AFC disable
//UART0
rULCON0 = 0×3; //Line control register : Normal,No parity,1 stop,8 bits
// [10] [9] [8] [7] [6] [5] [4] [3:2] [1:0]
// Clock Sel, Tx Int, Rx Int, Rx Time Out, Rx err, Loop-back, Send break, Transmit Mode, Receive Mode
// 0 1 0 , 0 1 0 0 , 01 01
// PCLK Level Pulse Disable Generate Normal Normal Interrupt or Polling
rUCON0 = 0×245; // Control register
rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 ); //Baud rate divisior register 0
/*
//UART1
rULCON1 = 0×3;
rUCON1 = 0×245;
rUBRDIV1=( (int)(pclk/16./baud+0.5) -1 );
//UART2
rULCON2 = 0×3;
rUCON2 = 0×245;
rUBRDIV2=( (int)(pclk/16./baud+0.5) -1 );
*/
for(i=0;i<100;i++);
}
void Uart_SendByte(int data)
{
if(data==’\n’)
{
while(!(rUTRSTAT0 & 0×2));
// Delay(1); //because the slow response of hyper_terminal
WrUTXH0(‘\r’);
}
while(!(rUTRSTAT0 & 0×2)); //Wait until THR is empty.
// Delay(1);
WrUTXH0(data);
}
void Uart_SendString(char *pt)
{
while(*pt)
Uart_SendByte(*pt++);
}
void Uart_Printf(char *fmt,…)
{
va_list ap;
char string[256];
va_start(ap,fmt);
vsprintf(string,fmt,ap);
Uart_Printf(string);
va_end(ap);
}
void Led_Display(int data)
{
//Active is low.(LED On)
// GPF7 GPF6 GPF5 GPF4
//nLED_8 nLED4 nLED_2 nLED_1
// rGPFDAT = (rGPFDAT & 0xf) | !((data & 0xf)<<4);
// rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4);
//Active is low.(LED On)
// GPF7 GPF6 GPF5 GPF4
//nLED_8 nLED4 nLED_2 nLED_1
// rGPFDAT = (rGPFDAT & 0xf) | !((data & 0xf)<<4);
rGPBDAT = (rGPBDAT & ~(0xf<<5)) | ((~data & 0xf)<<5);
//rGPCDAT = (rGPBDAT & ~(0xf<<5)) | ((~data & 0xf0)<<5);
}
char* msg = "Hello, embedded!\n";
int Main ()
{
Led_Display(10);
Port_Init();
Uart_Init(0, 115200);
Uart_SendString(msg);
return 0;
}