开发板:JZ2440V3
U-Boot版本:u-boot-2012.04.01
1.首先下载源码,上传到服务器,解压缩。
tar -jxvf u-boot-2012.04.01.tar.bz2
2.新建一个项目,这个版本的uboot自带的有smdk2410项目的,通过阅读源码根目录下的README文件发现,新建一个项目主需要以下几步:
(1)在根目录下的boards.cfg文件中,仿照smdk2410项目,添加下面这段话:
jz2440 arm arm920t jz2440 samsung s3c24x0
(2)在board/samsung/目录先新建文件夹jz2440;
cp -fr smdk2410 jz2440
(3)在include/configs/配置文件目录下新建项目的配置文件jz2440.h;
cp smdk2410.h jz2440.h
3.编译之前的配置
make jz2440_config
4.进行编译
make
注意:这个版本的uboot使用3.4.5的编译工具会发生段错误,需要使用4.3.2版本的arm-linux-gcc工具。
将生产的u-boot.bin文件烧写进Nor Flash中,发现串口没有任何的输出。我们现在来分析源码是什么原因导致的?
我们先来看编译链接的过程:
arm-linux-ld -pie -T u-boot.lds -Bstatic -Ttext 0x0 $UNDEF_SYM arch/arm/cpu/arm920t/start.o
--start-group api/libapi.o arch/arm/cpu/arm920t/libarm920t.o arch/arm/cpu/arm920t/s3c24x0/libs3c24x0.o
arch/arm/lib/libarm.o common/libcommon.o disk/libdisk.o drivers/bios_emulator/libatibiosemu.o
drivers/block/libblock.o drivers/dma/libdma.o drivers/fpga/libfpga.o drivers/gpio/libgpio.o
drivers/hwmon/libhwmon.o drivers/i2c/libi2c.o drivers/input/libinput.o drivers/misc/libmisc.o
drivers/mmc/libmmc.o drivers/mtd/libmtd.o drivers/mtd/nand/libnand.o drivers/mtd/onenand/libonenand.o
drivers/mtd/spi/libspi_flash.o drivers/mtd/ubi/libubi.o drivers/net/libnet.o drivers/net/phy/libphy.o
drivers/pci/libpci.o drivers/pcmcia/libpcmcia.o drivers/power/libpower.o drivers/rtc/librtc.o
drivers/serial/libserial.o drivers/spi/libspi.o drivers/twserial/libtws.o drivers/usb/eth/libusb_eth.o
drivers/usb/gadget/libusb_gadget.o drivers/usb/host/libusb_host.o drivers/usb/musb/libusb_musb.o
drivers/usb/phy/libusb_phy.o drivers/usb/ulpi/libusb_ulpi.o drivers/video/libvideo.o drivers/watchdog/libwatchdog.o
fs/cramfs/libcramfs.o fs/ext2/libext2fs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o
fs/reiserfs/libreiserfs.o fs/ubifs/libubifs.o fs/yaffs2/libyaffs2.o lib/libfdt/libfdt.o lib/libgeneric.o
lib/lzma/liblzma.o lib/lzo/liblzo.o lib/zlib/libz.o net/libnet.o post/libpost.o
board/samsung/jz2440/libjz2440.o
--end-group
从编译链接过程可以得知,链接脚本时u-boot.lds;我们来看这个文件的内容,看看链接地址定的是多少?
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000; #链接地址
. = ALIGN(4);
.text :
{
__image_copy_start = .;
arch/arm/cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data)
}
. = ALIGN(4);
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__image_copy_end = .;
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
_end = .;
. = ALIGN(4096);
.mmutable : {
*(.mmutable)
}
.bss __rel_dyn_start (OVERLAY) : {
__bss_start = .;
*(.bss)
. = ALIGN(4);
__bss_end__ = .;
}
/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
}
从链接脚本可以知道,默认的链接地址是0x00000000;所以,默认只支持Nor Flash启动。从编译链接过程可以得知开发板一上电首先执行的是"arch/arm/cpu/arm920t/start.S"文件。我们现在来分析这个文件,查找为什么在Nor Flash启动时串口没有任何的输出。
记录start.S文件做了哪些事情:
1.set the cpu to SVC32 mode
2.turn off the watchdog
3.mask all IRQs by setting all bits in the INTMR
4.设置时钟比例;FCLK:HCLK:PCLK = 1:2:4
5.flush v4 I/D caches和disable MMU stuff and caches,跳转到lowlevel_init处,设置内存控制器;
6.设置栈,并调用board_init_f函数;
6.1.设置R8寄存器指向的指针gd,并将其指向的内存空间清零;
6.2.调用init_sequence数组中的函数指针指向的各个函数;
6.3.设置系统时钟,设置过GPIO端口;
6.4.最后是重定位代码;relocate_code(addr_sp, id, addr);
分析到这里发现有问题了,默认的是先设置时钟预分频系数,然后初始化内存,然后再C代码中初始化时钟。
而我们设置SDRAM控制器是有严格时序要求的,并不清楚时钟那个HCLK下设置的,所有极有可能出错。
为什么在最后才开始重定位代码呢?
是由于uboot的代码很大,后面的C代码有可能使用全局或静态变量,而全局或静态遍历在链接时的地址是其链接脚本中的地址规定的;在运行时就会去链接地址处寻找这些变量,而开发板的内存地址是从0X30000000地址开始的,所以需要进行重定位。而Nand启动时内部SRAM只有4K的大小,uboot.bin文件要远大于4K;所以要将uboot.bin文件重定位SDRAM中去执行。
这个版本的uboot默认支持Nor启动,为什么将代码重定位之后,还能执行呢?
可以将uboot复制到内存中的任意位置,复制之后为什么还能够执行,程序会自动修改代码;修改变量和函数的地址。假如原来变量的地址是0x100,将代码复制到0x32000000地址处,在访问这个变量的时候就要使用新地址0x32000100了。那么是修改的时候怎么知道原来的地址呢?这就需要在链接的时候添加"-pie"选项。pie选项的含义是:Create a position independent executable。创建位置无关的可执行程序。
当加上pie选项之后,就会在uboot中生成:
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
这两个段。程序在运行时可以根据这个两个段来修改变量和函数的地址。注意,有这两个段之后编译出来的bin文件会大很多。
上一篇:ARM体系结构(1)- 工作模式与工作状态
下一篇:UART协议介绍及编程
推荐阅读最新更新时间:2024-11-13 06:48
设计资源 培训 开发板 精华推荐
- ST1S41 4 A 降压开关稳压器的典型应用
- Spx29300 的典型应用电路,3A 低压差稳压器
- 具有 6V 输入 UVLO 的 LTC3633AIFE 3.3V/1.8V 顺序降压稳压器的典型应用电路
- 24CM-WS2812大灯环
- 具有关断功能的 LT1086IM-3.3 5V 稳压器的典型应用
- LTC2240CUP-12 演示板,CMOS 输出,VCC = 2.5V,170Msps,12 位,10MHz< AIN< 250MHz
- DC675A-A,演示电路采用 LT1568CGN,4 阶宽带通滤波器
- 5X5X5光立方
- 51+sl811读写U盘的源程序+原理图
- RT7250B 2A、17V、340/800kHz同步降压转换器典型应用