uboot移植日记.docx
《uboot移植日记.docx》由会员分享,可在线阅读,更多相关《uboot移植日记.docx(11页珍藏版)》请在冰点文库上搜索。
![uboot移植日记.docx](https://file1.bingdoc.com/fileroot1/2023-5/11/d37d06c3-7f1a-4c6d-a9d5-f44a17679dff/d37d06c3-7f1a-4c6d-a9d5-f44a17679dff1.gif)
uboot移植日记
在at91rm9200上移植u-boot
1前言:
最近写驱动写应用感觉有点乏味了,像玩点新鲜的,于是我拿手里的那块H9200E开发板玩玩移植UBOOT,参考开发板提供的uboot的源码我移植了一个ubot-1.1.1。
目的是通过移植了解掌握atmel的at91rm9200的启动流程个uboot的启动流程和移植要点及其方法。
我把在移植uboot过程中遇到的问题记录下来,希望能帮助自己在以后的移植过程中更快的找到方向,也希望能帮助初学的朋友少走些弯路。
开发板的硬件配置
SDRAM32M
NORFLASH4M(atmel的AT49BV322A)
NANDFLASH64M(SAMSUNG的K9F1208U0B)
2移植思路
我认为要想真正的理解和成功的移植uboot得先弄明白at91rm9200的启动流程和ubot的启动方法
at91rm9200有片内引导和片外引导2种启动方式,由一根跳线控制。
上电MCU检测BMS的电平,如果是高则选择片内ROM启动,如果是低则从外部flash启动。
(1)片外引导 执行烧在flash上的引导程序。
(2)片内引导 at91rm9200内部本身有128k的片内rom,其固化了一个bootloader和uploader,片内引导时启动uploader,uploader开启xmodem协议,等待用户上传程序,上传的程序将载入片内SRAM,重映射,然后pc跳转到片内SRAM执行上传的用户程序。
注:
片内SRAM只有16k,除去3-4k片内启动程序的占用的部分数据空间,因此下载的程序大小限制在12k内。
官方at91rm9200DKu-bootFlashProgrammingSolutions文档提供的解决方案如下。
开发板flash上没有引导程序,于是只能用片内引导方式,载入一个12k以内的小程序到内部SRAM运行,而这个小程序初始化SDRAM后,再把u-boot下载到SDRAM运行(u-boot大于12k),pc跳到SDRAM的u-boot位置运行u-boot,u-boot启动后再用u-boot自己的flash烧写命令把自己烧到flash去,以后就可以片外flash启动了。
官方文档中并不是直接烧u-boot.bin,而是烧入了boot.bin和u-boot.gz2个文件。
Loader.bin和boot.bin我暂时用的是板子提供的修改好的,这里重点先研究研究uboot的启动和移植。
不过我还是了解了一下它们的启动流程,以便更好的去移植uboot。
loader.bin,boot.bin,u-boot.bin代码执行流分析.
以上三个文件时at91rm9200启动所需要的三个bin,他们的实现代码并不难。
如果是你是采用at91rm9200的评估版,应该能得到其源码。
loader.bin执行流程,这个文件主要在片内启动从串口下载代码时会用到
loader/entry.S初始化CPU
bmain--->crt0.S
-->copydata-->clearbss-->bboot
main.c-->boot-->
/*Getinternelromserviceaddress*/
/*InitofROMservicesstructure*/
pAT91=AT91C_ROM_BOOT_ADDRESS;
/*XmodemInitialization*/
-->pAT91->OpenSBuffer
-->pAT91->OpenSvcXmodem
/*SystemTimerinitialization*/
--->AT91F_AIC_ConfigureIt
/*EnableSTinterrupt*/
AT91F_AIC_EnableIt
AT91F_DBGU_Printk("XMODEM:
DownloadU-BOOT");
Jump.S
//JumptoUbootBaseAddrexec
Jump((unsignedint)AT91C_UBOOT_BASE_ADDRESS)
boot.bin执行流程该文件会在从片内启动时被下载到板子上,以后还会被烧写到片外Flash中,以便在片外启动时用它来引导并解压u-boot.bin.gz,并跳转到u-boot来执行。
boot/entry.S
bmain-->crt0.S-->copydata-->clearbss-->bboot
boot/misc.s/*unzipuboot.bin.gz*/
---->decompress_image(SRC,DST,LEN)-->gunzip
//jumptoubootBaseAddrexec这里跳转到解压u-boot.bin.gz的地址处直接开始执行u-boot
asm("movpc,%0":
:
"r"(DST));
u-boot.bin执行流程
u-boot/cpu/at91rm9200/start.S
start--->reset
--->copyex--->cpu_init_crit
--->/*setupthestack*/-->start_armboot
u-boot/lib_arm/board.c
init_fnc_t*init_sequence[]={
cpu_init,/*basiccpudependentsetup*/
board_init,/*basicboarddependentsetup*/
interrupt_init,/*setupexceptions*/
env_init,/*initializeenvironment*/
init_baudrate,/*initialzebaudratesettings*/
serial_init,/*serialcommunicationssetup*/
console_init_f,/*stage1initofconsole*/
display_banner,/*saythatwearehere*/
dram_init,/*configureavailableRAMbanks*/
display_dram_config,
checkboard,
NULL,
};
--->start_armboot--->callinit_sequence
--->flash_init-->display_flash_config
--->nand_init--->AT91F_DataflashInit
--->dataflash_print_info-->env_relocate
--->drv_vfd_init-->devices_init-->jumptable_init
--->console_init_r-->misc_init_r-->enable_interrupts
--->cs8900_get_enetaddr-->board_post_init-->
u-boot/common/main.c
for(;;)
{/*shellparser*/
main_loop()-->u_boot_hush_start-->readline
-->abortboot
-->printf("Hitanykeytostopautoboot:
%2d",bootdelay);
}
以上是at91rm9200启动并进入u-boot的执行流分析。
后面u-boot还会将uImage解压到特定的位置并开始启动内核代码。
3修改loaderboot
3.1修改Loader.bin的源码
1.修改include/main.h
#defineAT91C_UBOOT_BASE_ADDRESS0x21f00000
此开发板SDRAM为32M地址空间为0x20000000—0x22000000uboot被解压缩后要被拷贝到RAM的高端地址,防治与其他地址冲突
2.修改init.c中对SDRAM的初始化
AT91C_BASE_SDRC->SDRC_MR=0x02
根据具体的SDRAM芯片修改:
MR[4]=1(表示16位)
MR[4]=0(表示32位)
3.2修改Boot.bin的源码
1.在main.c中添加两个外部函数的定义
Externintdeampress_image(void*src,void*dst,unsignedintlen);解压缩函数,用来解压缩UBOOT
ExternvoidJump()跳转函数
2.在main.c中修改宏定义
#defineSRC0x10010000uboot在flash中的基地址
#defineDST0x21f00000解压缩UBOOT后载入到SDRAM中的地址
#defineLEN0x20000uboot的大小(最大大小)
3修改main.c中打印语句
AT91F_DBGU_Pringk()………
AT91F_DBGU_Pringk()………
AT91F_DBGU_Pringk()………
……
…
修改成自己希望的开机文字图样
4动手移植uboot
4.1从网上下载官方的ubot-1.1.1
4.2在/board下建立myboard文件夹,从/board/at91rm9200dk/..下拷贝文件。
At91rm9200dk.cflash.cconfig.mkmakefileu-boot.lds
4.2.1将at91rm9200dk.c改名为myboard.c,修改其部分代码。
由于这个开发板支持nandflash所以需要修改myboard.c下关于nandflash初始化的部分,nand_init().
具体修改如下:
将*AT91C_PIOC_ASR=AT91C_PC0_BFCK|AT91C_PC1_BFRDY_SMOE|
AT91C_PC3_BFBAA_SMWE;
改为*AT91C_PIOC_ASR=AT91C_PC1_BFRDY_SMOE|
AT91C_PC3_BFBAA_SMWE;//AT91C_PC0_BFCK
将*AT91C_PIOC_PDR=AT91C_PC0_BFCK|AT91C_PC1_BFRDY_SMOE|
AT91C_PC3_BFBAA_SMWE;
改为*AT91C_PIOC_PDR=AT91C_PC1_BFRDY_SMOE|
AT91C_PC3_BFBAA_SMWE;
增加两句
*AT91C_PIOC_PER|=AT91C_PC0_BFCK;
*AT91C_PIOC_OER=AT91C_PC0_BFCK;
注:
AT91C_PC0_BFCK是BrustFlash控制器的时钟信号线。
AT91C_PC1_BFRDY_SMOE是BrustFlash控制器的读信号。
AT91C_PC3_BFBAA_SMWE是BrustFlash控制器的脉冲前沿地址。
AT91C_PIOC_ASR是外设A寄存器。
AT91C_PIOC_PDR是GPIO禁用寄存器。
AT91C_PIOC_PER是GPIO使能寄存器。
AT91C_PIOC_OER是GPIO使能输出寄存器。
上述修改的目的是,使能BFCK信号线的GPIO输出。
在/*ConfigurePC2asinput(signalREADYoftheSmartMedia)*/后增加
*AT91C_PMC_PCER|=(unsignedint)(1<<4);此句。
目的:
开启外设时钟。
4.2.2修改flash.c
根据不同的flash芯片采用不同的flash程序接口,本开发板选用的是atmel的AT49BV322A。
由于芯片不同所以需要根据datasheet对flash.c进行修改。
①修改扇区大小和数目的定义
OrgDefOrgAT49BV16x4A[]=
{
{8,8*1024},/*8*8kBytessectors*/
{31,64*1024}/*31*64kBytessectors*/
};
改为
OrgDefOrgAT49BV16x4A[]=
{
{8,8*1024},/*8*64kBytessectors*/
{63,64*1024}/*63*8kBytessectors*/
};
本芯片为71个扇区。
②根据datasheet修改关于地址和读写命令的宏定义。
#defineFLASH_BANK_SIZE0x200000/*2MB*/
改为#defineFLASH_BANK_SIZE0x400000/*4MB*/
/*AT49BV1614ACodes*/
#defineFLASH_CODE10xAA
#defineFLASH_CODE20x55
#defineID_IN_CODE0x90
#defineID_OUT_CODE0xF0
#defineCMD_READ_ARRAY0x00F0
#defineCMD_UNLOCK10x00AA
#defineCMD_UNLOCK20x0055
#defineCMD_ERASE_SETUP0x0080
#defineCMD_ERASE_CONFIRM0x0030
#defineCMD_PROGRAM0x00A0
#defineCMD_UNLOCK_BYPASS0x0020
#defineMEM_FLASH_ADDR1(*(volatileu16*)(CFG_FLASH_BASE+(0x00005555<<1)))
#defineMEM_FLASH_ADDR2(*(volatileu16*)(CFG_FLASH_BASE+(0x00002AAA<<1)))
#defineIDENT_FLASH_ADDR1(*(volatileu16*)(CFG_FLASH_BASE+(0x0000555<<1)))
#defineIDENT_FLASH_ADDR2(*(volatileu16*)(CFG_FLASH_BASE+(0x0000AAA<<1)))
修改为:
/*MBM29LV320BECodes*/
#defineFLASH_CODE10x00AA00aa
#defineFLASH_CODE20x00550055
#defineID_IN_CODE0x00900090
#defineID_OUT_CODE0x00F000f0
#defineCMD_READ_ARRAY0x00F000F0
#defineCMD_UNLOCK10x00AA
#defineCMD_UNLOCK20x0055
#defineCMD_ERASE_SETUP0x0080
#defineCMD_ERASE_CONFIRM0x0030
#defineCMD_PROGRAM0x00A0
#defineCMD_UNLOCK_BYPASS0x00200020
#defineMEM_FLASH_ADDR1(*(volatileu16*)(CFG_FLASH_BASE+(0x0000555<<1)))
#defineMEM_FLASH_ADDR2(*(volatileu16*)(CFG_FLASH_BASE+(0x00002AA<<1)))
#defineIDENT_FLASH_ADDR1(*(volatileu32*)(CFG_FLASH_BASE+(0x0000555<<2)))
#defineIDENT_FLASH_ADDR2(*(volatileu32*)(CFG_FLASH_BASE+(0x0000AAA<<2)))
③去掉芯片自动识别,防治出以外错误。
注视掉if((flash_info[i].flash_id&FLASH_TYPEMASK)……到else144行-152行。
4.2.3修改config.mk
将TEXT_BASE=0x21f80000修改为TEXT_BASE=0x21f00000
这个地址是要根一级boot中定义保持一致。
Boot中的main.c
#defineDST0x21f00000//UBOOT被解压缩后载入到SDRAM中的位置。
4.2.4修改makefile
将OBJS:
=at91rm920dk.oflash.o
修改为OBJS:
=myboard.oflash.o自己命名的开发板的名字
4.3修改include下面的头文件
⑴在/include/configs/下建立myboard.h,可以复制at91rm9200dk.h改名。
具体注意修改如下:
#defineCONFIG_MYBOARD1//目标板
#defineCONFIG_NR_DRAM_BANKS1//SDRAMbank数
#definePHYS_SDRAM0x20000000//基地址
#definePHYS_SDRAM_SIZE0x2000000//大小32M
#definePHYS_FLASH_10x10000000//基地址
#definePHYS_FLASH_SIZE0x400000//大小4M
#defineCFG_FLASH_BASEPHYS_FLASH_1//别名
#defineCFG_MAX_FLASH_BANKS1//总bank数
#defineCFG_MAX_FLASH_SECT71//扇区总数
根据ubot-1.1.1的/include/configs/at91rm9200dk.h修改的比较少,大部分是修改容量和扇区总数及其基地址。
⑵修改/include/cmd_confdefs.h
修改#defineCFG_CMD_NONSTD(………
…)
这个宏定义是决定ubot支持的功能,如果需要支持就从括号中删除此行。
利于源码支持CFG_CMD_LOADB
CFG_CMD_MEMORY等。
我们这里的修改是删除“CFG_CMD_NAND|\”这行,是uboot支持nandflash。
4.4修改根目录下的MAKEALL和Makefile
⑴修改MAKEALL:
在LIST_ARM9="\
at91rm9200dkintegratorcpintegratorap\
omap1510innomap1610h2omap1610inn\
smdk2400smdk2410trab\
VCMA9versatilemyboard\"中加入对目标板的定义。
⑵修改Makefile
修改当前交叉编译器的绝对路径:
ifeq($(ARCH),arm)
CROSS_COMPILE=/usr/local/arm/2.95.3/bin/arm-linux-
添加目标板配置选项
#########################################################################
##AT91RM9200Systems
#########################################################################
at91rm9200dk_config:
unconfig
@./mkconfig$(@:
_config=)armat91rm9200at91rm9200dk
myboard_config:
unconfig
@./mkconfig$(@:
_config=)armat91rm9200myboard
5编译,调试
至此,uboot的修改基本完成,让我们编译下看看吧。
在纯linux环境下编译(不要在VM里linux和windows的共享目录里编译)
进入uboot的根目录,键入如下命令
makeclean(清除过程文件)
makemyboard_config(生成目标板的配置文件)
makeall(开始编译)
我等,我等,我等等等~!
啊~!
出问题了
从错误中看是提示未定义。
好吧,那就找错误。
这时候就体现出SourceInsight的优势了,全工程搜索,快捷的查找任意的函数或者宏的定义位置。
最后在/include/common.h中添加
#include包含与硬件相关的寄存器的定义,这个跟uboot版本有关系,比如uboot-1.0.0的include/common.h里就有这句话。
好了再编译一次吧……
Makeclean
Makeall
VM虚拟机编译还真是不快,不过这次没出问题,成功了。
编译结束后在根目录下会生成u-boot.bin大概104k
然后将其压缩为gz格式的
gzip–cu-boot.bin>u-boot.gz
因为一级boot中的解压缩函数是解压缩的gz格式然后拷贝到RAM的高端地址中去的。