1、S3c2440启动是从文件vivi/arch/s3c2440/head.S开始的 1. 在这个文件中,做了这样的工作: (1) 关闭看门狗 (2) 禁止所有中断 (3) 初始化system clock (4) 初始化串口 (5) 初始化nand flash相关的控制寄存器 (6) 把vivi copy 到 SDRAM上,最后把pc指向ram (7) 设置堆栈 (8) call 一个叫做main的函数。这个函数是c写的 2. main()这个函数在vivi/init/main.c中 (1) 程序正常跳转到这里后,首先打印一些进本信息 (2) 调用若干个
2、初始化的函数 <1> reset_handler() vivi/lib/reset_handler.c中 (主要做了clear memory的工作) <2> board_init() (没找到) <3> mem_map_init() vivi/arch/mmu.c中 (如果使用nand flash,会在这里使它看起来线性化;清空cache;invalidate I & D tlb) mmu_init vivi/arch/mmu.c中 (初始化cache,load页表指针,mmu 使能等等) <4> heap_init 初始化堆
3、vivi/lib/heap.c (这里好像malloc了一段空间,具体的没看懂) <5> mtd_dev_init vivi/driver/mtd/mtdcore.c中 mtd_init() 在vivi/driver/mtd/maps/s3c2440_flash.c 中,这里根据所使用的flash,做相应的cpu控制初始化,分配内存 add_command(&flash_cmd) 注册了flash这个用户命令 <6> init_priv_data() vivi/lib/priv_data/rw.c中 读出boot的基本参数 <7> misc
4、) (没找到) init_builtin_cmds() vivi/lib/command.c中 (注册用户的基本命令,包括boot, bon, load, help 等等) <8> boot_or_vivi() 就在main.c中,等待用户输入,有输入进入vivi_shell,没有输入,超时后启动linux 到这里main就结束喽 好像还有一件事没有记下来,就是vivi是怎么启动到linux的。这是vivi执行了boot命令,调用了 vivi/lib/boot_kernel.c 中的command_boot()函数。这样linux就启动了。 S3C
5、2440启动过程兼示例代码分析 才开始学嵌入式没多久,用得友善之臂的2440板子,前段时间一直在搞linux系统,软件移植,内核裁剪等,最近发现还是应该从最基本的学起,想自己写一个bootloader,然后就研究了友善之臂那个板子上光盘里面配的一个示例程序,哎,搞了一天多才研究出来一点点东西,贴上来,免得忘了! S3C2440启动过程(约略): 1、关闭watch dog 2、屏蔽所有中断 3、屏蔽所有子中断 4、设置时钟更改稳定等待时间(LOCKTIME) 5、设置各部件时钟频率与CPU主频的比例关系(Fclk:Hclk:Pclk) 6、设置USB总线时钟频率(U
6、PLLCON) 7、nap * 7 8、设置主时钟(MPLLCON) 9、判断是否是从睡眠状态唤醒的,如果是,则做出相应处理(具体处理还没看) 10、初始化存储设备、包括外存,内存等(BWSCON,BANKCONn,BANKSIZE,MRSRB6,MRSRB7) 11、初始化处理器各模式的堆栈(还没看懂) 12、Setup IRQ handler(也没咋看懂,似乎是对IRQ终端进行处理) 13、进入C程序(bl Main) 代码分析: ;========================================= ; NAME: 2440INIT.S ; D
7、ESC: C start up codes ; Configure memory, ISR ,stacks ; Initialize C-variables ; HISTORY: ; 2002.02.25:kwtark: ver 0.0 ; 2002.03.20:purnnamu: Add some functions for testing STOP,Sleep mode ; 2003.03.14:DonGo: Modified for 2440. ; 2009.02.19:PuHao: Comments ;=========================
8、 ;========================= ; ENTRY 这里是关键的入口,正文数量超过最大限制,只有忽略其他我没看懂的了,等下能不能把那个文件传上来,好恶心的规定…… ;========================= ResetHandler ;WTCON定义在2440addr.inc里面,WTCON EQU 0x53000000 ;把WTCON地址放到R0里,然后在设置r1为0,最后把r1中的0值 ;拷贝到r0所指向的地址里面,即禁用watch dog ldr r0,=
9、WTCON ;watch dog disable ldr r1,=0x0 str r1,[r0] ;基本同上,INTMSK 0x4A000008 R/W Interrupt mask control ldr r0,=INTMSK ldr r1,=0xffffffff ;all interrupt disable str r1,[r0] ;基本同上 ldr r0,=INTSUBMSK ldr r1,=0x3ff ;all
10、sub interrupt disable,0x3ff => 0000 0011 1111 1111 str r1,[r0] ;由于条件为FALSE,我觉得这段根本就不会执行 [ {FALSE} ; rGPFDAT = (rGPFDAT & ~(0xf<<4)) | ((~data & 0xf)<<4); ; Led_Display ldr r0,=GPFCON ldr r1,=0x5500 str r1,[r0] ldr r0,=GPFDAT ldr
11、r1,=0x10 str r1,[r0] ] ;由于在更改了主时钟控制器(MPLL)之后,新的频率需要一定时间过后才能稳定 ;所以需要等待一段时间,而这个等待的时间就是使用LOCKTIME寄存器来设置的 ;LOCKTIME[15:00] MPLL lock time count value for FCLK, HCLK, and PCLK ;LOCKTIME[32:16] UPLL lock time count value for UCLK. ; FCLK用于CPU核 ; HCLK用于AHB总线的设备(
12、比如SDRAM) ; PCLK用于APB总线的设备(比如UART) ; UPLL为USB的控制时钟,根据USB规范,好像是48MHz ; ARM920T内核使用FCLK ; 内存控制器,LCD控制器等使用HCLK; ; 看门狗、串口等使用PCLK ;To reduce PLL lock time, adjust the LOCKTIME register. ldr r0,=LOCKTIME ldr r1,=0xffffff ;0000 0000 1111 1111 1111 1111 1111 1
13、111 str r1,[r0] ;为什么UPLL的等待时间要少一些呢? [ PLL_ON_START ; Added for confirm clock divide. for 2440. ; Setting value Fclk:Hclk:Pclk ; 这里设置的 Fclk:Hclk:Pclk = 1:3:6,因为 CLKDIV_VAL = 7 ldr r0,=CLKDIVN ldr r1,=CLKDIV_VAL ; 0=1:1:1, 1=1:1:2, 2=
14、1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6. str r1,[r0] ;UPLL和MPLL的控制参数 ;PLLCON Bit Description Initial State ;MDIV [19:12] Main divider control 0x96 / 0x4d ;PDIV [9:4] Pre-divider control 0x03 / 0x03 ;SD
15、IV [1:0] Post divider control 0x0 / 0x0 ;InputFrequency OutputFrequency MDIV PDIV SDIV ;12.0000MHz 48.00 MHz(Note) 56(0x38) 2 2 ;12.0000MHz 96.00 MHz(Note) 56(0x38) 2 1 ;12.0000MHz
16、 271.50 MHz 173(0xad) 2 2 ;12.0000MHz 304.00 MHz 68(0x44) 1 1 ;12.0000MHz 405.00 MHz 127(0x7f) 2 1 ;12.0000MHz 532.00 MHz 125(0x7d) 1 1 ;Configure UPLL ; 根据
17、手册,要对PLL进行设置的话,就需要先设置UPLLCON,再设置MPLLCON ; 并且中间需要有至少七个指令周期的延时 ; (Needs intervals approximately 7 NOP) ; U_MDIV EQU 56 ;Fin=12.0MHz Fout=48MHz ; U_PDIV EQU 2 ; U_SDIV EQU 2 ldr r0,=UPLLCON ldr r1,=((U_MDIV<<12)+(U_PDIV<<4)+U
18、SDIV) str r1,[r0] ;(Needs intervals approximately 7 NOP) nop ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed. nop nop nop nop nop nop ;Configure MPLL ; M_MDIV EQU 68
19、 ; 68 = 0x44 Fin=12.0MHz Fout=304.8MHz ; M_PDIV EQU 1 ; M_SDIV EQU 1 ; 2440A ; 设为(0x44 << 12)|(0x01 << 4)|(0x01),即0x00044011 ; Fclk:Hclk:Pclk = 1:3:6 => Fclk = 300MHz, Hclk = 100MHz, Pclk = 50MHz ; ldr r0,=MPLLCON ldr r1,=((M_MDIV<<
20、12)+(M_PDIV<<4)+M_SDIV) str r1,[r0] ] ;Check if the boot is caused by the wake-up from SLEEP mode. ; GSTATUS2 Bit Description ; Reserved [3] Reserved ; WDTRST [2] Boot is caused by Watch Dog Reset
21、 cleared by writing “1” ; SLEEPRST [1] Boot is caused by wakeup reset in sleep mode cleared by writing “1”. ; PWRST [0] Boot is caused by power on reset cleared by writing “1” ldr r1,=GSTATUS2 ldr r0,[r1]
22、 tst r0,#0x2 ;In case of the wake-up from SLEEP mode, go to SLEEP_WAKEUP handler. bne WAKEUP_SLEEP ;EXPORT伪指令声明一个全局标号 EXPORT StartPointAfterSleepWakeUp StartPointAfterSleepWakeUp ;Set memory control registers ldr r0,=SMRDATA ldr r1,=BWSCON
23、 ;BWSCON Address add r2, r0, #52 ;End address of SMRDATA ;r2 = r0 + 52 ; beq %F[ ]中,b为跳转指令,eq为相等条件标识,整条语句的意思就是 ; 如果相等,则在此条语句后面的代码中搜索[ ]标号并跳转。 ; 同样的 bcc %B[ ] 其中cc为无符号数小于,%B在此条语句前面的代码中搜索并跳转 ;下面是一个循环 ;首先把r0指向的地址单元的一个字(4字节)的内容复制到r3中, ;然后r0+4,这样的话下次取的
24、值将会是SMRDATA中的下一个个字 ; ;将r3中的值写入到r1的地址单元(BWSCON)中,并将r1+1,即 ;下一次将会写入到BWSCON的下一个控制器 ;控制器以此为:BWSCON - BANKCON0 - BANKCON1 - BANKCON2 ……BANKCON7 ; BANKSIZE - MRSRB6 - MRSRB7 0 ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 ;CPSR = r2 - r0
25、 bne %B0 ;不等于0时跳转,也就是说一直循环直到将上面所说的控制器全部 ;设置了值之后才继续执行下一步 ;Initialize stacks bl InitStacks ; Setup IRQ handler ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x
26、1c str r1,[r0] ;If main() is used, the variable initialization will be done in __main(). [ :LNOT:USE_MAIN ;Copy and paste RW data/zero initialized data LDR r0, =|Image$$RO$$Limit| ; Get pointer to ROM data LDR r1, =|Image$$RW$$Base| ; and RAM
27、copy LDR r3, =|Image$$ZI$$Base| ;Zero init base => top of initialised data CMP r0, r1 ; Check that they are different BEQ %F2 1 CMP r1, r3 ; Copy init data LDRCC r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
28、 STRCC r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4 BCC %B1 2 LDR r1, =|Image$$ZI$$Limit| ; Top of zero init segment MOV r2, #0 3 CMP r3, r1 ; Zero init STRCC r2, [r3], #4 BCC %B3 ] [ :LNOT:TH
29、UMBCODE bl Main ;Don't use main() because ......because what? b . ] [ THUMBCODE ;for start-up code for Thumb mode orr lr,pc,#1 bx lr CODE16 bl Main ;Don't use main() because
30、because what? b . CODE32 ] ;function initializing stacks ;初始化堆栈的代码还没仔细研究,正文字数超过最大限制,只有不贴下面的了…… 一:地址空间的分配 1:s3c2440是32位的,所以可以寻址4GB空间,内存(SDRAM)和端口(特殊寄存器),还有ROM都映射到同一个4G空间里. 2:开发板上一般都用SDRAM做内存flash(nor、nand)来当做ROM。其中nand flash没有地址线,一次至少要读一页(512B).其他两个有地址线 3:
31、norflash不用来运行代码,只用来存储代码,NORflash,SDRAM可以直接运行代码) 4:s3c2440总共有8个内存banks 6个内存bank可以当作ROM或者SRAM来使用 留下的2个bank除了当作ROM 或者SRAM,还可以用SDRAM(各种内存的读写方式不一样) 7个bank的起始地址是固定的 还有一个灵活的bank的内存地址,并且bank大小也可以改变 5:s3c2440支持两种启动模式:NAND和非NAND(这里是nor flash)。 具体采用的方式取决于OM0、OM1两个引脚 OM[1:0所决定的启动方式 OM[1:0]=00时,处理器从NAN
32、D Flash启动 OM[1:0]=01时,处理器从16位宽度的ROM启动 OM[1:0]=10时,处理器从32位宽度的ROM启动。 OM[1:0]=11时,处理器从Test Mode启动。 当从NAND启动时 cpu会自动从NAND flash中读取前4KB的数据放置在片内SRAM里(s3c2440是soc),同时把这段片内SRAM映射到nGCS0片选的空间(即0x00000000)。cpu是从0x00000000开始执行,也就是NAND flash里的前4KB内容。因为NAND FLASH连地址线都没有,不能直接把NAND映射到0x00000000,只好使用片内SRAM做一个载体
33、通过这个载体把nandflash中大代码复制到RAM(一般是SDRAM)中去执行 当从非NAND flash启动时 nor flash被映射到0x00000000地址(就是nGCS0,这里就不需要片内SRAM来辅助了,所以片内SRAM的起始地址还是0x40000000). 然后cpu从0x00000000开始执行(也就是在Norfalsh中执行)。 总结: Arm的启动都是从0地址开始,所不同的是地址的映射不一样。在arm开电的时候,要想让arm知道以某种方式(地址映射方式)运行,不可能通过你写的某段程序控制,因为这时候你的程序还没启动,这时候arm会通过引脚的电平来判断。
34、 1当引脚OM0跟OM1有一个是高电平时,这时地址0会映射到外部nGCS0片选的空间,也就是Norflash,程序就会从Norflash中启动,arm直接取Norflash中的指令运行。 2当OM0跟OM1都为低电平,则0地址内部bootbuf(一段4k的SRAM)开始。系统上电,arm会自动把NANDflash中的前4K内容考到bootbuf(也就是0地址),然后从0地址运行。 这时NANDFlash中的前4K就是启动代码(他的功能就是初始化硬件然后在把NANDFlash中的代码复制到RAM中,再把相应的指针指向该运行的地方) 为什么会有这两种启动方式,关键还是两种flas
35、h的不同特点造成,NOR FLASH容量小,速度快,稳定性好,输入地址,然后给出读写信号即可从数据口得到数据,适合做程序存储器。NAND FLASH 总容量大,但是读写都需要复杂的时序,更适合做数据存储器。这种不同就造成了NORflash可以直接连接到arm的总线并且可以运行程序,而NANDflash必须搬移到内存(SDRAM)中运行。 在实际的开发中,一般可以把bootloader烧入到Norflash,程序运行可以通过串口交互,进行一定的操作,比如下载,调试。这样就很可以很方便的调试你的一些代码。Norflash中的Bootloader还可以烧录内核到Norflash等等功能。
36、 我也在用这块板子. 说下我的看法吧. 主流的s3c2440A处理器,arm9内核 接口齐全,文档也比较丰富.利用板载资源可以学习不少东西.完整的嵌入式wince和linux都可以开发.还可以移植其它系统,当然这方面用的就少了. 目前来看是做学习板较好的厂商.售后没接触过,因为我还没遇到什么问题需要联系售后的. 有专门的交流论坛. 烧程序需要串口,jtag调试需要并口.一般笔记本都不带这些接口了.所以需要买个转接的,usb转串口的统统不好用,我试过N多的了,不好用.买个了华塑pc卡转串口的,可卡好像有毛病,有时超级终端输不进去.也许我买到假货了.后来我买了个OpenJtag,这个东西可以转串口,可以转Jtag,烧写速度也快.但是我不习惯在Eclipse下搞.所以只把它当串口用了. 有点扯远了,友善的板子不错.性价比高.推荐. micro2440和mini2440相比,micro是做的核心版和底板是分开的,所以用jtag调试时可以不用底板,micro多了点硬件资源,串口也多了.其它没什么区别. 性价比高的是mini2440,不用在这上面过多考虑了.用mini的人很多. 不管怎样,选个开发板后好好研究下,肯定有成果的.






