U-boot片内启动移植

================== 准备工作=================2 i, T1 r1 M/ e) g9 m
1.阅读at91rm9200 官方文档有关“引导程序”的章节% V) o7 ]) A- V7 C$ n, [
对at91rm9200的启动流程有个大概的了解。
5 J+ F' B4 x3 ]2 n9 Eat91rm9200引导流程图
/ x" m$ f5 I" [+ H* R7 `Device Setup
2 v) H& P9 C; t$ ?& ||% V; u* ]$ F+ E: h# O4 R+ v
|( A* y# ~# l7 s( f N% i* M5 r
Boot SPI DataFlash Boot --> Download from DataFlash --> run w" t, B, v, J) ~
|) x& w! v6 o. G) V' y H# Q
|* z# J6 y* T0 b0 i; s
TWI EEPROM Boot --> Download from EEPROM --> run
- @! |+ K4 W1 H5 e5 M3 J|
3 S7 // P& S6 J8 {9 K|3 U4 r4 O, P! W, /" A' R
Parallel Boot --> Download from 8-bit Device -->run3 F1 r2 b4 l; u
|* a/ R B" d6 z; l6 v5 F' Q, P) Q4 x
|   Xmodem protocol
& X% V; g6 H# @6 G! b! ^) ?( k|   |---DBGU Serial Download ---------------------> run
# /, G$ n. `; Y3 `; x|____|
* y, X K+ S! ~/ o0 /|    DFU protocol
' @8 [8 l& D% |9 a% K|-----USB download -----------------------> run
' g% }" C( z5 P. E5 y! yat91rm9200有片内引导和片外引导 2 种启动方式,由一根跳线控制。
( C' n! @- _, d( D! J1>   片外引导  执行烧在flash上的引导程序。) w- Z) h6 L# X! k* c: d! R1 g
2>   片内引导  at91rm9200内部本身有128k的片内rom,其固化了一个bootloader和uploader,片内引导时启动uploader,uploader开启xmodem协议,等待用户上传程序,4 N; o: S0 u: H
上传的程序将载入片内SRAM,重映射,然后pc跳转到片内SRAM执行上传的用户程序。
6 @& f1 h2 s Q8 H! R( j注:片内SRAM只有16k,除去3-4k片内启动程序的占用的部分数据空间,因此下载的程序大小限制在12k内。
" A9 P7 D/ i9 i. H8 k) p. _
. @) S$ @0 v! j; S% ^: N' c, Q
) Y8 y' u/ f5 ]" w+ D2.开发板硬件配置
; U% c9 j) g: l" u- {# Z* N这块开发板硬件          ATMEL推荐硬件, N' F2 B* O8 B& W' U$ t
SDRAM  8MB             32MB1 j* ^/ j& b) i- ? D
Flash     1MB             8MB      
0 J% K- p% Z/ s- `6 v" L2 b注:Flash芯片也不一样,意味着驱动要重写。8 s" T2 |1 D4 X
/ y N8 z* ?/ /. v' V. p. o
3.移植思路) /8 P% n6 Q7 `+ f+ A
官方at91rm9200DK u-boot Flash Programming Solutions文档提供的解决方案如下。 q" k1 e# `4 P" {: |8 Y+ V: ?1 m

* P# ]4 Q0 ^5 h. b; a( n开发板flash上没有引导程序,于是只能用片内引导方式,载入一个12k以内的小程序到内部SRAM运行,而这个小程序初始化SDRAM后,再把u-boot下载到SDRAM运行(u-boot大于12k),pc跳到SDRAM的u-boot位置运行u-boot,. e. |$ J* f a
u-boot启动后再用u-boot自己的flash烧写命令把自己烧到flash去,以后就可以片外flash启动了。
/ J( [ X( y, |# F官方文档中并不是直接烧u-boot.bin,而是烧入了boot.bin和u-boot.gz2个文件7 X B! V8 p) B  /0 W3 h
原因后面将阐述。8 y! p0 h; h: R8 p6 M' n

/ p+ q5 m1 J4 h# ~) A* {: V+ E0 |" o8 s5 d, a
===================移植====================; X& S% S7 b& o5 y# w) i
1.loader.bin的移植; A8 K4 [" }8 C- N @
官方提供的loader.bin在SRAM启动会又启动了xmodem接收u-boot,但是- N2 z8 p7 b3 /3 `" b
xmodem接收数据出错。
2 h u2 N( ]0 N7 W查看其源码,发现它使用了固化的rom中的服务接口函数,没看出哪里出问题。
2 v# `+ m( |' k! |7 S/ }# f6 f! x
. V" D+ M& T; c* n0 { T8 ^2 ]于是准备自己写loader.bin,在at91rm9200提供的开发包中有个AT91RM9200-GettingStarted-ADS1_2-1_1.zip,用的是Arm Developer Suite 1.2编译器,就是一个简单的hello world程序,试一试可以运行。
 |* u  N# q- A6 U/ n+ n; o" B, N(注意:ADS编译的程序,定义变量要在main的开始出,后面定义将导致编译出错)+ C, s% ?. }$ A3 a' E7 T) v: w

1 T8 E& [! P) P, l用AT91RM9200-GettingStarted-ADS1_2-1_1.zip作为起点开始写loader.bin( |8 }" h' v5 ?$ d* C4 x O; A
lader.bin主要有3个功能,初始化SDRAM,启动xmodem接收u-boot并写到SDRAM中,pc跳转到SDRAM运行。# o% W' q) v3 F2 G* ~+ Y

4 x! f- e1 m. X- U% h/ B6 wAT91RM9200-GettingStarted-ADS1_2-1_1里面已经有了SDRAM和其他一次初始化,在init_ram.c中。
, q9 A0 ^. P+ u1 U5 j& s
7 r$ i! _8 l/ o+ Vxmodem的实现
/ l$ u9 K4 D! W  只需要接收部分,发送部分用win下的”超级终端”等工具就可。) r' u. A8 C- U0 n
  先找来协议文档,熟悉协议,看看现有的xmodem协议源码。协议本身并不复杂,只是它的握手部分实现有点技巧。 J# O/ r% v( ~7 K, d
  接收端要不停的发送字符“C”到串口(注意xmodem有3个版本,而超级终端对应的是xmodem-crc16),发送端收到“C”后发送数据SOH和第一个数据包。- k! D$ Z: Q B/ l" n+ W. D7 e6 Z
接收端检测到SOH后停止发送“C”并开始处理数据。官方的loader启动了一个时间服务,每隔1s发送一个“C”,在这个我使用了偷懒的算法。
" @, n% [5 ~7 y) /$ G0 G5 N   while(Getchar()!=AT91C_XMODEM_SOH)
 o2 u) @8 F9 K( m( v4 c. W! {   {
' Q$ h; L0 c; _- H$ O       if (0xFFFF==++n )
/ m8 x" v: Y9 q- K6 x0 m9 H5 `& w8 @       {
/ J/ q( F; N, X1 }. /5 w; C+ a6 k$ S           SendChar(AT91C_XMODEM_CRCCHR);
) a+ t' N( d w: s, w. U           n=0;' B: E1 a; s, t. N% N
      }
; z5 P7 [/ z7 Q( z% ^( `: N   }2 H- t+ h) x/ M. Z: s1 m& a
: _" P5 A4 R( Z+ _2 Z7 u
Getchar()和GetWaitchar()是添加的,GetWaitchar等待直到从串口接收到数据。
- Q1 n/ h, d; s8 }( `( /4 i# o& N显然不能用在上面的算法中,要导致忙等的。所以改了个Getchar()只用在这里。9 U |! ^9 f8 x
握手解决了,后面的处理都没什么问题。
8 T3 k- Y! | C/ E5 j1 e" ] N" H+ R2 [3 r
写SDRAM$ A& g/ I5 M/ O4 E. k
  unsigned char *pSdram = (unsigned char *)AT91C_UBOOT_BASE_ADDRESS; I3 H1 O# L% n& t4 O. ~
  for ( n = 0; n<128 ; n ++ ) V+ Q& p" S- K' q' W
  {+ u4 P: W: _7 I1 @
              *pSdram++=data[n];7 S2 f% s( ~% c, ~
  }
! z( g7 q+ `. _& h. u$ c5 J9 m3 D: L
PC跳转
6 O r6 _& v* w   添加一个文件jump.S到工程
2 d6 c8 ~3 Q) u, q3 C& H3 s;------------------------------------------------------------------------------
7 y# f% G% Q) k. q6 r;-     ATMEL Microcontroller Software Support  -   ROUSSET -
5 X4 q7 }; ~! g* i;------------------------------------------------------------------------------
; T0 X4 ~# `$ F2 Q9 w% F;- File source         : remap.s0 h4 U M, @% Y
;- Librarian           : Not applicable
 }) t% l8 b* b2 ?# |/ Z$ R;- Translator          :
/ k" |* S; O4 w+ Y9 Q;-
4 g B2 f, W- ]! O- n;- Treatment           : Execute the remap and branch to 0
/ h$ m B! }! u! j. C2 z;-
" E; G: P4 T* z! B* Q* x( ];- 03/10/01  HI         : Creation
& p' }- q& S' g- a* z+ i;------------------------------------------------------------------------------
* {- A9 m6 f" y. I5 N
( X/ N, J$ i( n" v9 `               AREA    reset, CODE, READONLY
! f. f, S7 R9 B0 N4 S [! g2 A
              EXPORT  Jump1 p7 y9 Z; j' M4 p% l
Jump1 f* {& k, [# L
      mov pc, r0                . h' y( z" y8 g0 }, I3 K
/ T8 H# z5 n+ ^- J7 w
             END
& r% x1 d! ~* L;---------------------------------------------------------------------------------( g" w' ]( u7 d8 x/ q& D9 l
/ Q6 @8 v5 q, K( z* W" t& c1 V
在main中使用下面的函数跳转
8 P! I$ j, g# Z$ L" QJump((unsigned int)AT91C_UBOOT_BASE_ADDRESS);
2 D9 ~3 i5 U4 e$ W/ o! l! d7 V& p% K! R7 |* u {

' B5 n) F8 n8 y0 j P% |loader的调试过程- _/ {, R* L: j; |3 [9 G: b
  xmodem部分可以传一个调试文件,传进去后全部send回串口,看返回的信息就可以判断是否正常工作。
+ {$ T2 S. h$ o1 A- X3 S5 m$ k   写SDRAM,依然是写入后再读出来看看是否一致,在这里卡了很久,发现每隔2个地址就不能使用,后来发现是SDRAM没有初始化,也就是init_ram.c中的InitSDRAM()无效,重写后正常。3 P8 S! c; L7 G/ h0 q) F/ Y
  Jump测试,得传入一个可以运行的程序到内存才能判断,用先前编译好的1.1.4的u-boot传入,没反应,可能是jump不对,也可能是u-boot不对,毕竟u-boot还未经过任何修改。灵光一闪,我换成u-boot-1.0.0试一试,出现u-boot的提示符了,?   也就是说jump没问题。9 r# z+ T9 f4 ~9 T& U6 t

' h* v! [+ I% u6 J1 [2 |
( B" D: `. T* R$ O2.u-boot的移植
% J: D( B! v1 b$ N4 J0 p- e8 [u-boot的编译需要ELDK(Embedded Linux Development Kit). e: F: k. `% e' D3 h# l8 n
ELDK是linux下的交叉开发环境,所以需要安装linux,在这里使用的是虚拟机vmware安装linux(red hat 9.0),并安装了vmware tools,方便和windows交换数据。; G- ]5 U3 L+ R
Linux版本选择以及安装ELDK参见“The DENX U-Boot and Linux Guide (DULG) for TQM8xxL”) p U3 |% `8 o2 M* b% a. M7 t
. F6 h$ p! y) p# Q, a
这里下载安装的是arm-2005-03-06.iso7 { n7 h  R- s" f* p: e! p
注意正确设置ELDK的环境变量,要不编译会出错。
" h- b0 Y/ M% K3 {+ R! M6 u5 Q* }
5 n3 {2 C7 `6 z5 i) K在编译u-boot前先仔细阅读README文档
0 p0 f7 e3 b, e2 T# {at91rm9200已经被u-boot支持6 T/ }1 b! C% ^ C. ^
编译如下' s* y8 t; ?3 z3 ]
#cd u-boot.x.x.x      (x.x.x代表版本号)! t, c- k& J$ @8 O
#make at91rm9200dk_config
+ |! G$ x5 }$ ?5 j4 L* F9 E X7 y#make all
# g; S7 s+ K7 n3 U4 X4 W) X# q在map那里会很慢,我的AMD64 3000+,虚拟机里编译u-boot要3分钟?
+ j* H. c0 /* n3 |) w3 J' n5 p/ d, W# m2 |$ g4 n
u-boot版本选择
+ G4 s- Q) [8 x7 s4 P$ f7 y   从1.1.2开始,u-boot有初始化SDRAM并拷贝自己到SDRAM运行的代码,而之前的版本就没有这个功能,官方文档提供的解决方案是针对1.1.2之前的版本。事实上官方开发包中代的u-boot是0.3.1?。9 X a: /9 l+ C8 Z: ]% q- ^

6 g) ^# U3 b. g! o在经过我的测试后,发现直接编译出来的u-boot1.0.0可以运行,而1.1.4没反应。
; Y. W! w& H0 h7 x# y% Z( u看来不一定最新的就是最好的。所以选择u-boot1.0.0移植。
: h: b+ W. n* d% O' G) P6 c! m
! m" ?& A7 K2 g5 xu-boot修改
) R$ w6 L+ /' ?4 i$ P* ` l   u-boot同样是对ATMEL推荐配子写的,所以需要修改。& p/ L y( D3 s: z- a) K5 C7 _
修改" [0 a6 M j3 ^5 N+ y% g
Board/at91rm9200dk/config.mk
# |! ?0 e* o( S# e3 t( N! |$ `TEXT_BASE = 0x21f00000
' /- x ^" U! o0 v改为
* v- t2 z, K" j! n7 xTEXT_BASE = 0x20700000 (u-boot将被载入SDRAM的高端部分). i5 K; J3 C9 e; e7 ]
2 K# A2 {8 h6 D* G4 T' {9 Z# ?- Z
修改
3 n( N b9 L. c1 s# O9 A8 Z( vinclude/configs/at91rm9200dk.h
" ] d8 Z" ], d! L( G2 /#define PHYS_SDRAM_SIZE 0x2000000 /* 32 megs */+ o( o9 /8 T9 f+ p
改为6 n g3 ~' n: E! /
#define PHYS_SDRAM_SIZE 0x800000 /* 8 MB */
# Q' V4 {' `/ a, e) N5 l9 t- w- c$ Z5 c0 X# C; N
#define PHYS_FLASH_SIZE           0x200000  /* 2 megs main flash */
8 t2 @) O/ t, t! K改为, c- M- S6 y! M- m
#define PHYS_FLASH_SIZE           0x100000  /* 1MB main flash */
$ M& D- E; K. [7 X /9 u- Y2 h' F# f" Q2 ]' [+ t
还有一个要修改的地方是Board/at91rm9200dk/flash.c
 z# F5 J3 Z% /) [$ i' ]参见自己的flash芯片datasheet,修改驱动。
9 Q7 n# a6 Q' E注意保持函数接口的一致性。其中外部会调用的几个函数是
: D3 l& g6 @! M1 m0 iunsigned long flash_init (void)
" V" Y. {! d' L% y% Ovoid flash_print_info (flash_info_t *info)
( ` g: d' v2 i. [; R6 gint   flash_erase (flash_info_t *info, int s_first, int s_last)" I" c$ R) Z; ^. Y: s
int write_buff (flash_info_t *info, uchar *source, ulong Base, ulong nbytes)2 n2 J5 k5 a) D6 C8 k( v: E% z
1 E0 o6 F! q: O; D' o# w; ]
只要保证这几个函数的接口一致性,其实现方法不一定要参照原来的模式。/ g# G% m. A9 b( k; Q+ J
flash_info_t *info其实不用也可以的。5 I5 g% K* G, z' @1 k+ j$ [0 o1 z
还有就是flash芯片的自动识别函数去掉为好,在生产过程中很有可能采用同类型的其它FLASH代替。
+ L3 q) W1 ?# O [$ B" L; @: O# I" j, {! B/ G& m2 c/ P0 S$ k
重新编译u-boot,然后测试用u-boot的flinfo、md和cp.b命令测试flash驱动。
+ C+ ?3 V/ W5 R D# U* S0 [7 f" ]0 O D. c
一切正常后u-boot部分完成5 Z8 J1 X2 g0 S
u-boot打包/ Z$ @% s% k; n0 d* R3 K
#gzip –c u-boot.bin > u-boot.gz# n( g, d3 j3 T9 G2 B+ a2 Q' B- h

+ g6 a4 {) K5 `3 l' s7 B5 e6 P1 r( N
; s9 D! w: t) a# N8 _3.boot.bin移植4 Q# p9 i) F; /& g7 W* G
先看看boot.bin的源码,它也是用的ELDK开发环境,我用先前安装的交叉开发环境编译,出错。。。提示ld命令错误。可能是与开发环境不兼容,换成官方包中的cross-2.95.3.zip,编译通过。3 j5 x+ N1 G _  f
/ /* g3 O6 A! z# f+ /! L+ M: [
修改main.c中下面2项
, }; B E$ @; K( H#define SRC 0x10010000  (u-boot.gz将烧入flash的位置)
& B. ]1 z2 Q" I Z% c#define DST 0x20700000 (u-boot.gz被解压后载入SDRAM的位置,和loader中保持一直)
9 M4 C) h' Z V% g" @
; B- F1 M- y( h同样修改initboot.c中的AT91F_InitSDRAM(),和loader的修改一样。
6 a* B/ H0 ^2 M. k4 c0 M6 m' E$ C8 l( p" }
编译$ S& l8 {+ g O. Y% M+ V
#make all
% i; @) ]( O9 r
2 b2 F q+ e9 E4 ~% J: ^% e% ?" w* ?! [2 _' v/ ?: O- X
; @7 G8 k2 L) m( e D
烧入flash测试
, p9 ^4 [8 @1 H$ x! @ p; j1 ?   片内启动,载入loader.bin+ m2 Y0 z/ r5 ^- [! u7 l6 O
  再用loader.bin载入u-boot运行。( E5 K; H, k, u: f# k
 
6 t! A. k q5 ~. {( V8 m, z) m下面是在u-boot提示符下的操作, P* a9 m. d4 q5 C) |
u-boot > loadb 20000000
, j7 X, } X+ f1 d8 t- D1 h--------------用kermit协议载入boot.bin文件到SDRAM的20000000地址-----
4 _. E3 `% ]2 G% Q" ku-boot > cp.b 20000000 10000000 xxx 6 I4 T5 f6 Q) Z. K5 x2 q ^
(上一步文件载入完后会显示下载字节数,xxx就是字节数的16进制表示)
$ Q, d7 G# S, W% V: C$ o" b接下来烧入u-boot.gz
; B4 k6 G6 [. ]5 Nu-boot > loadb 20000000
0 T( V" c, `# e B0 eu-boot > cp.b 20000000 10010000 xxx
* Z& h1 h+ Q9 y' F% A$ g c! ]9 z) [) f) J) g4 g
断开板子上的跳线,片外启动开发板。等几秒后u-boot启动了。
# h) z L& B" ~1 X到此u-boot移植结束

你可能感兴趣的:(U-boot片内启动移植)