您的位置:首页 > 编程语言

U-boot移植步骤详解_附:bin文件和所需文件(代码+流程图+遇到的错误及解决办法)

2012-03-05 16:17 573 查看
S3C2440的U-Boot移植

按照视频教程,直接使用老大(韦东山老师)提供的补丁文件,直接对下载的u-boot源码打补丁,然后make
100ask24x0_config,就可以编译成功,编译下载就可以在开发板Jz2440上实现U-Boot的各种功能。
但是要真正自己学会u-boot的移植,能独立修改u-boot源码,移植到另一款开发板上,还是要好好研究移植过程的。
在学习的过程中,想不使用补丁文件,自己通过修改将u-boot移植到Jz2440开发板上,按照《嵌入式Linux应用开发完全手册》操作后,发现还是存在问题,所以研究了一下,最终实现将U-Boot移植到Jz2440上,到了串口打印输出这一步,暂未实现网卡支持等高级功能。现将笔记整理如下。

一、移植环境
1.u-boot版本1.1.6
2.开发板Jz2440(ARM9
S3C2440
NAND K9F2G08
SDRAM K4S561632 * 2)
3.Linux: ubuntu 9.10

二、U-Boot移植概况
因为只是为了实验,为了方便的讲述这个过程,解压u-boot后,直接基于smdk2410修改,失败了删除再解压,所以修改文件直接在smdk2410文件夹下修改。如果使用其他开发板,请按照书中做法,新建开发板相关文件夹,这样比较规范。
没有特别说明,当前文件夹为u-boot-1.1.6根目录。
需要修改的文件及其路径:
文件
路径
start.S
cpu/arm920t/start.S
lowlevel_init.S
board/smdk2410/lowlevel_init.S
smdk2410.c
board/smdk2410/smdk2410.c
speed.c
cpu/arm920t/s3c24x0/speed.c
增加boot_init.c
board/smdk2410/boot_init.c

board/smdk2410/Makefile
s3c24x0.h
include/s3c24x0.h
各文件的作用说明:
start.S:u-boot启动执行的第一个汇编文件。修改完成堆栈初始化、时钟初始化、SDRAM初始化(只是跳转,具体实现在lowlevel_init.S中)、拷贝代码到SDRAM中。

lowlevel_init.S:初始化Jz2440板上SDRAM。

smdk2410.c:

最主要函数board_init(),初始化时钟MPLL、UPLL、FCLK、HCLk、PCLK、GPIO。

Speed.c:

实现get_PCLK、get_PCLK、get_HCLK、get_PLLCLK等时钟函数,关系到UART等外设。

boot_init.c:

实现start.S中调用的的两个C函数clock_init(初始化时钟)、CopyCode2Ram(实现从NAND FLASH拷贝代码到SDRAM)

s3c24x0.h:

各种结构体的定义。我们需要针对Jz2440开发板增加NAND FLASH的结构体、在S3C24X0_CLOCK_POWER结构体中增加一个成员CAMDIVN。增加一个宏isS3C2410,用于U-Boot自动识别是s3c2410还是s3c2440。

三、U-Boot移植操作

我们先根据书上的指导,完成部分操作,然后根据开发板的实际情况(只有NAND,没有Nor FLASH)进行调整,最后针对遇到的问题,各个击破,从而解决问题。

1.引经据典

韦东山老师编著的《嵌入式Linux应用开发完全手册》是一部内容详实、通俗明了、非常适合自学的一本书。下面就根据书中提示,开始我们的移植工作。

(1)修改SDRAM的配置

参考《嵌入式Linux应用开发完全手册》第十五章15.2.5节,修改SDRAM的配置,主要修改lowlevel_init.S(路径:board/smdk2410/lowlevel_init.S)中 REFCNT寄存器的值。将

#define REFCNT 1113

改为

#define REFCNT 0x4f4

至于为什么这样修改,请参考《嵌入式Linux应用开发完全手册》,里面讲的很透彻。

(2)增加对S3C2440的支持

由于S3C2440与S3C2410的MPLL与UPLL计算公式不一样,FCLK、HCLK、和PCLK的分频设置也不一样,所以需要修改smdk2410.c

(路径:board/smdk2410/smdk2410.c)中board_init()函数。由于代码太多,再次就不一一贴代码了,请参阅《嵌入式Linux应用开发完全手册》P266页的代码,完全一样。

(3)修改系统获取时钟的函数

最后一步:获取系统时钟的函数需要针对S3C2410、S3C2440的不同进行修改。

在后面设置串口波特率时需要获取系统时钟,如果此处没有设置,可能U-Boot启动后串口无输出或工作不正常。所以需要修改speed.c

(路径:cpu/arm920t/s3c24x0/speed.c)中的get_PLLCLK()、get_HCLK()、get_PCLK()这三个函数。代码太多,请参阅《嵌入式Linux应用开发完全手册》P269—P272页,与其一样即可。

按照书上提示,完成以上三步,编译下载U-Boot就能看见串口有输出。我照着做了,可是很不幸,没有输出。不过没有关系,聪明的读者一眼就能发现问题,书上移植前提是代码在Nor FLASH上,而Jz2440开发板只有NAND FLASH,没有Nor FLASH,也就是说代码是存在NAND FLASH上的,怎么办?请看下一小节。

2.系统调整

(1)增加NAND支持

既然只有NAND FLASH,也就是说U-Boot存在于NAND FLASH上,在U-Boot启动的过程中,需要将U-Boot从NAND FLASH拷贝到已经初始化了的SDRAM中去运行,我们就额外增加一个文件boot_init.c实现读NAND FLASH的功能。文件boot_init.c是韦东山老师为Jz2440编写,主要根据NAND FLASH型号,实现了CopyCode2Ram()函数,将NAND FLASH上数据复制到SDRAM中。

我们需要做的是,获取boot_init.c文件,放在board/smdk2410/boot_init.c处,并修改该目录下的Makefile(board/smdk2410/Makefile)。

COBJS := smdk2410.o flash.o

改为

COBJS := smdk2410.o boot_init.o flash.o

然后在start.S(路径:cpu/arm920t/start.S)中修改,以调用CopyCode2Ram()函数,实现代码拷贝。

修改前:

relocate: /* relocate U-Boot to RAM */

adr r0, _start /* r0 <- current position of code */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp r0, r1 /* don't reloc during debug */

beq stack_setup

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot */

add r2, r0, r2 /* r2 <- source end address */

copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0] */

stmia r1!, {r3-r10} /* copy to target address [r1] */

cmp r0, r2 /* until source end addreee [r2] */

ble copy_loop

修改后:

relocate: /* relocate U-Boot to RAM */

adr r0, _start /* r0 <- current position of code */

ldr r1, _TEXT_BASE /* test if we run from flash or RAM */

cmp r0, r1 /* don't reloc during debug */

beq stack_setup

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot */

bl CopyCode2Ram /* 调用函数CopyCode2Ram()*/

#if 0

add r2, r0, r2 /* r2 <- source end address */

copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0] */

stmia r1!, {r3-r10} /* copy to target address [r1] */

cmp r0, r2 /* until source end addreee [r2] */

ble copy_loop

#endif其中红色部分为添加的代码,蓝色部分为注释掉的代码。

(2)修改启动时钟初始化

在smdk2410的U-Boot启动代码中,第一阶段,start.S中将系统时钟初始化为120MHz,对于Jz2440,我们需要将时钟初始化为100MHz。

初始化函数clock_init()存放于boot_init.c中(board/smdk2410/boot_init.c)。在启动代码中我们调用clock_init()函数即可。在start.S(路径:cpu/arm920t/start.S)中,我们修改如下:

#if 0

/* FCLK:HCLK

CLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr r0, =CLKDIVN

mov r1, #3

str r1, [r0]

#endif

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl clock_init

#endif

绿色为预编译注释掉的代码(也就是smdk2410中将时钟设置为120MHz),蓝色是在其后增加的代码,用于调用clock_init()函数,初始化系统时钟。

四、疑难杂症

现在,按照书《嵌入式Linux应用开发完全手册》讲述的操作已经完成,也添加了从NAND FLASH启动的代码,想想 应该是可以了,我们编译试试看。

(1)初步编译

首先配置u-boot。在u-boot-1.1.6根目录(u-boot-1.1.6#)输入命令make smdk2410_config,回车运行。出现提示:

Configuring for smdk2410 board...

表示配置完成。

然后编译,输入make命令,回车,开始编译。

出现了一堆错误:

boot_init.c: In function `s3c2440_wait_idle':

boot_init.c:133: error: `S3C2440_NAND' undeclared (first use in this function)



boot_init.c:221: error: `isS3C2410' undeclared (first use in this function)



make[1]: *** [boot_init.o] Error 1

make[1]: Leaving directory `/home/book/workspace/U-Boot/Jz_u-boot-1.1.6/board/smdk2410'

make: *** [board/smdk2410/libsmdk2410.a] Error 2

看来还是不行,还有很多问题要解决,下面就根据各种错误进行修改。

(2)S3C2440_NAND未定义

经过仔细分析,发现一个文件s3c24x0.h (路径:include/s3c24x0.h)中有类似的定义S3C2410_NAND:

/* NAND FLASH (see S3C2410 manual chapter 6) */

typedef struct {

S3C24X0_REG32 NFCONF;

S3C24X0_REG32 NFCMD;

S3C24X0_REG32 NFADDR;

S3C24X0_REG32 NFDATA;

S3C24X0_REG32 NFSTAT;

S3C24X0_REG32 NFECC;

} /*__attribute__((__packed__))*/ S3C2410_NAND;

我们就仿照其定义S3C2440_NAND,在文件s3c24x0.h (路径:include/s3c24x0.h)中增加如下代码:

typedef struct {

S3C24X0_REG32 NFCONF;

S3C24X0_REG32 NFCONT;

S3C24X0_REG32 NFCMD;

S3C24X0_REG32 NFADDR;

S3C24X0_REG32 NFDATA;

S3C24X0_REG32 NFMECCD0;

S3C24X0_REG32 NFMECCD1;

S3C24X0_REG32 NFSECCD;

S3C24X0_REG32 NFSTAT;

S3C24X0_REG32 NFESTAT0;

S3C24X0_REG32 NFESTAT1;

S3C24X0_REG32 NFMECC0;

S3C24X0_REG32 NFMECC1;

S3C24X0_REG32 NFSECC;

S3C24X0_REG32 NFSBLK;

S3C24X0_REG32 NFEBLK;

} /*__attribute__((__packed__))*/ S3C2440_NAND;

然后再次make编译,看看还有什么错误。

提示:

boot_init.c: In function `nand_reset':

boot_init.c:221: error: `isS3C2410' undeclared (first use in this function)

boot_init.c:221: error: (Each undeclared identifier is reported only once

boot_init.c:221: error: for each function it appears in.)

……

make[1]: *** [boot_init.o] Error 1

make[1]: Leaving directory `/home/book/workspace/U-Boot/Jz_u-boot-1.1.6/board/smdk2410'

make: *** [board/smdk2410/libsmdk2410.a] Error 2

原来是isS3C2410未定义

(3)isS3C2410未定义

还是在文件s3c24x0.h (路径:include/s3c24x0.h)中,在其末尾增加两行宏定义,用于自动识别cpu是s3c2410还是s3c2440:

#define rGSTATUS1 (*(volatile unsigned *)0x560000B0)

#define isS3C2410 ((rGSTATUS1 & 0xffff0000) == 0x32410000)

添加完毕,再次make编译。出现错误:

speed.c: In function `get_HCLK':

speed.c:123: error: structure has no member named `CAMDIVN'

speed.c: In function `get_PCLK':

speed.c:171: error: structure has no member named `CAMDIVN'

make[1]: *** [speed.o] Error 1

make[1]: Leaving directory `/home/book/workspace/U-Boot/Jz_u-boot-1.1.6/cpu/arm920t/s3c24x0'

make: *** [cpu/arm920t/s3c24x0/libs3c24x0.a] Error 2

提示成员CAMDIVN未定义。

(4)CAMDIVN未定义

根据提示找到其结构体,发现是s3c2440中引入了一个寄存器CAMDIVN ,s3c2410中没有,所以S3C24X0_CLOCK_POWER中未定义。我们自己加上即可。

修改前:

typedef struct {

S3C24X0_REG32 LOCKTIME;

S3C24X0_REG32 MPLLCON;

S3C24X0_REG32 UPLLCON;

S3C24X0_REG32 CLKCON;

S3C24X0_REG32 CLKSLOW;

S3C24X0_REG32 CLKDIVN;

} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;

修改后

typedef struct {

S3C24X0_REG32 LOCKTIME;

S3C24X0_REG32 MPLLCON;

S3C24X0_REG32 UPLLCON;

S3C24X0_REG32 CLKCON;

S3C24X0_REG32 CLKSLOW;

S3C24X0_REG32 CLKDIVN;

S3C24X0_REG32 CAMDIVN;}

/*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;

红色就是我们自己添加的成员CAMDIVN。

然后再次make。提示:

arm-linux-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec

arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

编译成功!


然后使用oflash下载到Jz2440开发板。连接好开发板与PC串口,打开串口工具(波特率:115200 8N1),重启开发板,观察串口输出。

串口没有输出!!!


看来还是存在问题,纠结啊!

(5)串口无输出

仔细分析串口文件serial.c(cpu/arm920t/s3c24x0/serial.c)发现没有问题,时钟初始化也没有问题,百思不得其解!

后来从头开始分析,从start.S(路径:cpu/arm920t/start.S)开始,分析u-boot第一阶段启动流程,U-Boot第一阶段启动流程如图1 所示。






流程图1.jpg(50.96
K)

2012-3-2 22:22:38

图1 U-Boot第一阶段启动流程

通过分析,很快就发现了问题所在,在跳转到时钟初始化C函数之前没有设置堆栈!

由于时钟初始化调用的是C函数clock_init(),根据韦东山老师视频讲解,调用C语言函数之前一定要先设置堆栈!所以调用时钟初始化函数clock_init()一定要先设置堆栈。

知道了错误所在之处,改起来就方便了,将堆栈初始化的汇编代码调整一下位置,整体移到clock_init()函数之前就行了。

调整后的代码如下:

/*Setup the stack */

stack_setup:

ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */

sub r0, r0, #CFG_MALLOC_LEN /* malloc area */

sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

#ifdef CONFIG_USE_IRQ

sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

sub sp, r0, #12 /* leave 3 words for abort-stack */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl clock_init

#endif

红色部分为堆栈初始化代码,蓝色部分为时钟初始化代码。调整后的启动流程图如图2所示。






流程图2.jpg(49.76
K)

2012-3-2 22:22:38

图2 调整后的U-Boot启动流程

编译烧写,串口终于有输出了!


U-Boot 1.1.6 (Mar 2 2012 - 16:53:23)

DRAM: 64 MB

Flash: 512 kB

*** Warning - bad CRC, using default environment

In: serial

Out: serial

Err: serial

SMDK2410 #

然后还可以更改串口提示符前缀,修改文件smdk2410.h(路径:include/configs/smdk2410.h)

#define CFG_PROMPT "SMDK2410 # "

改为

#define CFG_PROMPT "JZ2440 # "

然后编译烧写,重启开发板,提示符就变了

U-Boot 1.1.6 (Mar 2 2012 - 16:58:35)

DRAM: 64 MB

Flash: 512 kB

*** Warning - bad CRC, using default environment

In: serial

Out: serial

Err: serial

JZ2440 #

JZ2440 #

JZ2440 #

smdk2410.h(路径:include/configs/smdk2410.h)里面主要是一些配置选项,比如配置开发板MAC地址,配置开发板ip等,具体内容请参阅《嵌入式Linux应用开发完全手册》。

五、总结

学习Linux是一项非常繁杂的事情,需要了解的知识也很多,出现的问题也是千奇百怪,但是只要我们有足够的耐心,坚忍不拔的毅力,一定可以成为韦东山老师那样的高手。

出现问题,要学会自己分析,尝试自己解决,借用韦东山老师的一句话“遇到问题,自己纠结,痛苦个两三天就明白了”,通过不断的解决问题,我们才能不断积累经验,不断进步。

在这里和大家分享一下学习方法,我是先看的韦东山老师的视频,然后再看书学习的,感觉这样效果比较好。看视频学到的不仅仅是教你如何操作,还讲解了各种硬件比如LCD、NAND FLASH的各种原理,分析了U-Boot的启动流程,对自己理解非常有帮助,里面还穿插了一些遇到错误的处理办法,很值得我们学习。

附件:
移植好的bin文件下载:


u-boot_bin.rar( 46.56 K, 下载次数:3)

直接通过Jtag烧写即可运行于Jz2440开发板。

移植中涉及的文件(已修改好):


boot_init.rar( 2.95 K, 下载次数:1)


lowlevel_init.rar( 1.79 K, 下载次数:1)


Makefile.rar( 960 Bytes, 下载次数:1)


smdk2410.rar( 1.9 K, 下载次数:1)


s3c24x0.rar( 4.98 K, 下载次数:1)

声明:本文为个人原创,边移植边写,完全来自实践。本文首先发表在百问网(www.100ask.net)转载请指明出处。

原文地址:http://www.100ask.net/forum/showtopic-3624.aspx

免费视频下载地址:

第1期共33个视频,免费,下载后可以直接观看,下载地址:

http://115.com/folder/fa55184z#

http://dl.dbank.com/c03o1ebwlo

第一期视频从Linux安装开始,讲解了SDRAM、NAND
FLASH、LCD等硬件操作,U-Boot的移植、内核移植、简单字符驱动的编写,非常详尽。

第二期视频主要是驱动深入讲解,精华啊!

第二期视频需要收费的哦,具体见韦东山老师淘宝店铺:

http://100ask.taobao.com/

书籍资料下载:

《嵌入式Linux应用开发完全手册》及相关资源电炉可以下载:
http://www.verycd.com/topics/2828590/
嵌入式linux应用开发完全手册光盘里的驱动和例子源代码.rar详情

嵌入式linux应用开发完全手册.pdf详情

如果能买一块韦东山老师的开发板,加上视频讲解,加上书,那学起来就太Easy了!

淘宝店铺上http://100ask.taobao.com/全套都有了!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐