u-uboot uart驱动不初始化内存 可以使用 uart 吗

 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
u-boot初始化函数序列分析
下载积分:900
内容提示:u-boot初始化函数序列分析
文档格式:TXT|
浏览次数:5|
上传日期: 02:36:49|
文档星级:
全文阅读已结束,如果下载本文需要使用
 900 积分
下载此文档
该用户还上传了这些文档
u-boot初始化函数序列分析
官方公共微信U-boot启动第二阶段代码分析问题与笔记整理 - 柠檬守护的博客 -
中国电子技术论坛 -
最好最受欢迎电子论坛!
U-boot启动第二阶段代码分析问题与笔记整理
已有 293 次阅读 21:41
1.问题整理第一课 学习armboot基础知识问题整理 17'第二课&init_fnc_t&函数与&DECLARE_GLOBAL_DATA_PTR的定义分析 28'第三课 内存使用排布 26'
作者的其他最新博客
评论 ( 个评论)
Powered byu-boot第二阶段简要讲解
tq2440的uboot目录有点繁琐. 用nor中的uboot下载uboot到nand中可以使用tftp方式. 1.连接开发板与pc 2.选择tftp下载
3. 设置pc与开发板同一个网段
之后在pc上安装tftp server软件. 然后在uboot的tftp下载模式下输入 1. 因为tq2440的uboot源码写死了通过tftp下载的uboot文件名称为 u-boot.bin, 所以将天嵌提供的uboot改名为 u-boot.bin 放到 tftp工具的同级目录里即可自动完成下载, 下载前最好先格式化nand.
个人感觉uboot第一阶段就是为了芯片能够运行起来保证最最低的运行要求, 第二阶段才是真正干活的代码.
第二阶段总体概览
uboot启动的第二阶段流程大致如图所示:
进入 start_armboot 之后首先为 gd , gd-&bd 安排存储空间, 然后将该空间清0.
一 init_sequence中的函数
1. board_init
int board_init (void)
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();//获取S3C24X0_GPIO_BASE, GPIO寄存器的基地址
/* set up the I/O ports */
gpio-&GPACON = 0x007FFFFF;
gpio-&GPJUP = 0x00001
/* arch number of TQ2440-Board */
gd-&bd-&bi_arch_number = MACH_TYPE_S3C2440;
/* adress of boot parameters */
gd-&bd-&bi_boot_params = 0x;
//机器ID和ram中taglist的基地址在do_boot_linux中作为参数传递给kernel, [theKernel(0, machid, bd-&bi_boot_params)]
/* 开启 指令/数据 cache*/
icache_enable();
dcache_enable();
2. interrupt_init
int interrupt_init (void)
S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();
/* use PWM Timer 4 because it has no output */
/* prescaler for Timer 4 is 16 */
timers-&TCFG0 = 0x0f00;
if (timer_load_val == 0)
/* for 10 ms clock period @ PCLK with 4 bit divider = 1/2 (default) and prescaler = 16. Should be 1MHz and 15625 @ 50 MHz */
timer_load_val = get_PCLK()/(2 * 16 * 100);
/* load value for 10 ms timeout */
lastdec = timers-&TCNTB4 = timer_load_
/* auto load, manual update of Timer 4 */
timers-&TCON = (timers-&TCON & ~0x0700000) | 0x600000;
/* auto load, start Timer 4 , 自动重装*/
timers-&TCON = (timers-&TCON & ~0x0700000) | 0x500000;
timestamp = 0;
return (0);
(1) 预分频值计算
这里使用没有输出引脚的定时器 TIM4, 定时 10ms, 自动重装.
Description
Prescaler 1
These 8 bits determine prescaler value for Timer 2, 3 and 4.
Prescaler 0
These 8 bits determine prescaler value for Timer 0 and 1.
TCFG0=0x0F00, 预分频值Prescaler 1 = 1/16;
TCFG1=0x0000, 分频值
1/2 (默认值0000为2分频)
(2) 定时器初值计算
timer_load_val = get_PCLK()/(2 * 16 * 100);
get_PCLK()位于cpu/arm920t/s3c24x0/speed.c 中,取得pclk的过程如下
FCLK =& HCLK = FCLK / 2 =& PCLK = HCLK / 2, FCLK : HCLK : PCLK = 4 : 2 : 1
即先通过MPLLCON的值计算得出FCLK,然后根据CLKDIVN的分频率比得出HCLK 和 PCLK. 要做一个10ms的定时器,所以这里计算初值。上面prescaler1 = 16, 且此处没有设置TCFG1,所以TCFG1为默认值0, 则divider选择了1/2; 1s = 10ms * 100;
于是,需要的三个参数全都出来了, 分频后频率为 (clk /(2 * 16)),即每秒要做(clk/(2 * 16))次减计数,那么10ms就要做 clk / (2 * 16 * 100)次减计数。
(3) TCNTB4
lastdec = timers-&TCNTB4 = timer_load_
将定时器计数初值保存在 TCNTB4 中, 在减计数完成时自动将 TCNTB4 赋值给 TCNT4
timers-&TCON = (timers-&TCON & ~0x0700000) | 0x600000; // ==& bit[22:20] = 110
auto reload mode, update TCNTB4
timers-&TCON = (timers-&TCON & ~0x0700000) | 0x500000; // ==& bit[22:20] = 101
auto reload mode, start for timer4 此时,真正开始定时器4
后期版本的uboot中的interrupt_init貌似更新为timer_init了
3. env_init
环境变量应该是如果在flash里有环境变量那就使用flash里的, 如果没有就使用默认的环境变量.
这个函数在多个文件中定义, 但是每个文件开头都有一个宏定义来将整个文件包含起来, 如在env_nand.c中就有
#if defined(CFG_ENV_IS_IN_NAND)
/* Environment is in Nand Flash */
在 include/configs/smdk2440.h(EmbedSky.h)中如果定义了 CFG_ENV_IS_IN_NAND 就表示参数保存在nand中.
int env_init(){
gd-&env_addr
= (ulong)&default_environment[0];
gd-&env_valid = 1;
将默认的环境变量数组地址赋值给gd-&env_
default_environment[]定义在 common/env_common.c
4. init_baudrate
getenv_r ("baudrate", tmp, sizeof (tmp)); 这里是对应上一步的 env_init, 如果设置了环境变量就依据 env_ptr 去寻找 "baudrate" 这个变量, 如果找到就用环境变量配置的值, 如果没有找到就用 default_environment[]里的默认值: 115200
5. serial_init
* 使用给定的 波特率 初始化串口. 始终设置为 8个数据位
无校验 1个停止位 无开始位
int serial_init (void)
serial_setbrg ();
return (0);
void serial_setbrg (void)
S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
unsigned int reg = 0;
/* value is calculated so : (int)(PCLK/16./baudrate) -1 , 这里是为了计算波特率寄存器的值: RBRDIV*/
reg = get_PCLK() / (16 * gd-&baudrate) - 1;
/* FIFO enable, Tx/Rx FIFO clear */
uart-&UFCON = 0x07;
uart-&UMCON = 0x0;
/* Normal,No parity,1 stop,8 bit */
uart-&ULCON = 0x3;
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
uart-&UCON = 0x245;
uart-&UBRDIV =
#ifdef CONFIG_HWFLOW
uart-&UMCON = 0x1; /* RTS up */
for (i = 0; i & 100; i++);
使用上一步获取到的波特率来初始化串口, 串口默认设置为 8 N 1 无.
6. console_init_f
gd-&have_console = 1; 等于设置了一个标志位, 表示uboot使用命令终端.
7. display_banner & print_cpuinfo
这两个函数都是调试使用的, 他们打印出调试信息, 这里要注意的是打印函数,
在/common/console.c中它调用puts来实现输出
void puts (const char *s)
//GD_FLG_DEVINIT表示了是向自己还是串口输出
if (gd-&flags & GD_FLG_DEVINIT) {
/* Send to the standard output */
fputs (stdout, s);
/* Send directly to the handler */
serial_puts (s);
8. dram_init
首先要在 /include/configs/smdk2440.h(embedsky.h)中定义:
#define CONFIG_NR_DRAM_BANKS
/* 只有一块sdram */
#define PHYS_SDRAM_1
0x /* SDRAM Bank #1 起始地址*/
#define PHYS_SDRAM_1_SIZE
0x /* 128 MB */
int dram_init (void)
gd-&bd-&bi_dram[0].start = PHYS_SDRAM_1;
//bi_dram[0] 表示了 dram 起始地址和大小
gd-&bd-&bi_dram[0].size = PHYS_SDRAM_1_SIZE;
最后总结一下最重要的两个结构体:
(1) /include/asm-arm/global_data.h
中的 gd_t , 其中保存了 u-boot 的配置信息
global_data {
unsigned long
/* serial_init() was called */
unsigned long
/* Relocation Offset */
unsigned long
/* Address
of Environment struct */
unsigned long
/* Checksum of Environment valid? */
unsigned long
/* base address of frame buffer */
/* jump table */
(2) /include/asm-arm/u-boot.h 中的 bd_t
typedef struct bd_info {
/* serial console baudrate */
unsigned long
bi_ip_ /* IP Address */
unsigned char
bi_enetaddr[6]; /* Ethernet adress */
struct environment_s *bi_
//下面两个参数在进入内核时候会作为参数 r1 r2 传递给内核启动函数
bi_arch_ /* unique id for this board , 目标板id */
bi_boot_ /* where this board expects params , taglist的地址*/
/* RAM configuration */
bi_dram[CONFIG_NR_DRAM_BANKS];
在/include /configs/smdk2440.h(embedsky.h) 中定义的 CFG_GBL_DATA_SIZE 为 128 ,
gd_t 和 bd_t 都保存在该区域中.
二 以上为 init_sequence 中的函数, 下边为 start_armboot 中接下来的代码解析:
flash_init
由内部的代码可知这里是norflash的初始化
#define PHYS_FLASH_1
flashbase = PHYS_FLASH_1;
//因为cpu从0地址处开始执行代码, 2440在0地址处只可能有nor-flash和内部4k的sram, 所以这里是nor-flash的初始化无疑
该函数中初始化了nor-flash的各个sector起始地址和大小, 在display_flash_config中打印出了flash的配置信息
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
//计算 framebuffer内存地址
size = lcd_setmem (addr);
//设置 framebuffer尺寸大小
gd-&fb_base =
//设置 framebuffer起始地址
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
//将 堆区(malloc) 全部清零
初始化nand
注意要在 /include/configs/smdk2440.h(embedsky.h) 中打开 CONFIG_COMMANDS 和 CFG_CMD_NAND 对 nand 的支持
nand_init();
初始化环境变量参数
/* initialize environment */
env_relocate ();
//初始化环境变量
设置ip地址
gd-&bd-&bi_ip_addr = getenv_IPaddr ("ipaddr");
从网卡读出mac地址
/* MAC Address */
//从网卡寄存器读出mac地址
char *s, *e;
char tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i & 0) ? tmp : NULL;
for (reg = 0; reg & 6; ++reg) {
gd-&bd-&bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;//这里问号表达式的优先级高于 =
即:先判断s是否为真, 根据结果再赋值
s = (*e) ? e + 1 :
开发板上的设备初始化
devices_init();
//初始化 iic/lcd/video/logbuff/system/serial等设备
初始化跳转表
jumptable_init();
//初始化跳转表
初始化控制台
console_init_r();
enable_interrupt();
保存"加载地址"
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL)
load_addr = simple_strtoul (s, NULL, 16);
查找环境变量里是否含有 load_addr , 有的话将他的值写入到 load_addr 中, 他是加载地址, 在bootm中还会见到他. 他表示uboot将kernel加载到内存的地址.
保存framebuffer
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
//保存framebuffer
开发板初始化
board_late_init ();
//因为每个板子都不一样, 板子特殊的初始化可以写在这个函数里
网卡信息打印
eth_initialize
/* main_loop() can return to retry autoboot, if so just run it again. */
main_loop ();
//进入主循环
截止目前还没有讲到uboot如何启动linux, 而这最关键的一部分代码就在main_loop中.
main_loop中主要是完成了 1. 设置启动次数, 有些项目需要检测设备的启动次数, 如果大于某值则不予启动
2. modem功能
3. uboot版本号 4. 命令自动补全功能(类似shell的自动补全命令)
5. 启用倒计时启动功能
6. 进入死循环 执行 read_line(), 读取控制台(一般都是串口)输入的命令. 执行命令 run_command() 如果想要知道如何解析命令可以去跟踪一下 run_command() 函数 7. 启动linux
可见main_loop函数的重要性, 我们在下一篇中继续分析main_loop函数
Copyright (C) , All Rights Reserved.
版权所有 闽ICP备号
processed in 0.039 (s). 13 q(s)pcDuino嵌入式linux开发: 修改u-boot(一)
u-boot是boot loader的一种,boot loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。通常,boot loader 是严重地依赖于硬件而实现的,特别是在嵌入式世界。因此,在嵌入式世界里建立一个通用的 boot loader&几乎是不可能的。
官方u-boot介绍
官方提供的u-boot的可以完美的引导内核,但是如果用来学习嵌入式linux开发就不合适了,原因是官方提供的u-boot的没有网络配置信息。具体的查看方法是当系统启动的时候用串口连接调试,当有3秒停留的时候迅速按电脑上任何一个按键。然后执行
ping 局域网网关
它会提示没有ping这个命令,也没有tftp,nfs相关命令。然而这些命令在学习嵌入式开发过程中是相当有必要的。怎么办?这里给大家提供修改方法,后面把修改的源代码上传到git,你可以直接下载使用。
具体的修改过程如下:
宿主机:ubuntu-12.04(64位)
目标机:pcDuino
交叉编译器:arm-linux-gnueabihf-gcc (安装sudo apt-get install& g++-arm-linux-gnueabihf)
下载u-boot源码:
git clone&
下载之后执行,查看分支
pillar :~/study/kernel/u-boot-sunxi/u-boot-sunxi$ git branch -a
& remotes/origin/HEAD -& origin/sunxi
& remotes/origin/lichee-dev
& remotes/origin/lichee-dev-a20
& remotes/origin/lichee/lichee-dev
& remotes/origin/lichee/lichee-dev-ICS
& remotes/origin/lichee/lichee-dev-mmc
& remotes/origin/old/sunxi-current
& remotes/origin/sunxi
& remotes/origin/wip/a20
可以看到官网下载的u-boot有很多分支,这里要对几个看不明白的分支说明一下:
lichee-dev:支持nand和TF卡启动,但是不支持网络,现pcDuino官方发布的版本;
sunxi和sunxi-current:支持TF卡启动,也支持网络,但是不支持nand启动;
这里只能在官方的版本上改了,将git切换到官方版本。
git& checkout& lichee-dev
关于git的使用,有空我会单独发布一个帖子来指导使用。
在修改这个源码之前,先给大家讲讲启动顺序。
NAND启动是ROM-&Boot0-&boot1-&uboot-&linux kernel
SD启动是ROM-&spl-&uboot-&linux kernel
如果用livesuite的image做的SD也有boot0和boot1的。ROM的启动我的理解是这样子的,当系统上电的时候,cpu会自动将nand中前几k的代码拷贝到RAM中运行,这几k的代码即Boot0,Boot1,但是全志的Boot0,Boot1是不开源的,所以我们无法知晓,另外关于u-boot的nand启动部分也是不开源的,你就不要纠结去彻底的分析这个u-boot。
另外除了tftp和nfs这种开发方法,全志也提供了其他的方法,这里跟跟你介绍一下。
首先硬件按照一下方式连接:
& &-& 串口调试 &-& PC USB
&-&& OTG&&&& &-& PC USB
打开串口调试助手,例如putty 或者xshell之内的工具。系统上电,然后按住电脑上的”1”键,第一次的时候系统会自动安装驱动,最后弹出nanda分区。
如下图所示:
可以看到这个里面有uImage, u-boot在linux文件夹里面,只需要将你开发的uImage和u-boot拷贝到相应的位置就可以。
这种方式对于学习比较麻烦了,例如你开发调试一个uImage,你要先从虚拟机里面拷贝出来,然后按照刚才哪种方式把nanda给显示出来,整个调试过程效率相当低。
下面介绍怎么修改u-boot,然后介绍一个高效的方法。
编译配置u-boot
官网上下载的支持的u-boot,名字并不叫pcDuino,它叫a10-evb,这里看不惯可以做相应的修改。
vim boards.cfg
189 sun4i&&&&&&&&&&&&&&&&&&&&&&& arm&&&&&&&& armv7&&&&&& pcDuino&&&&&&&&&&&& allwinner&&&&& sunxi&&&&&& sun4i:SUNXI_EMAC
190 sun4i_sd&&&&&&&&&&&&&&&&&&&& arm&&&&&&&& armv7&&&&&& a10-evb&&&&&&&&&&&& allwinner&&&&& sunxi&&&&&& sun4i:SD_UART
191 sun5i_a12&&&&&&&&&&&&&&&&&&& arm&&&&&&&& armv7&&&&&& a12-evb&&&&&&&&&&&& allwinner&&&&& sunxi
192 sun5i_a13&& &&&&&&&&&&&&&&&&&arm&&&&&&&& armv7&&&&&& a13-evb&&&&&&&&&&&& allwinner&&&&& sunxi
193 sun5i_a13_sd&&&&&&&&&&&&&&&& arm&&&&&&&& armv7&&&&&& a13-evb&&&&&&&&&&&& allwinner&&&&& sunxi
在189行位置修改,然后在加上配置网络sun4i:SUNXI_EMAC,在源码里面加上板级支持包。
pillar :~/study/kernel/u-boot-sunxi$ cd board/allwinner/
a10-evb/ a13-evb/ pcDuino/
就是将a10-evb拷贝成,进入pcDuino,修改里面的文件名为pcDuino.c,然后修改Makefile。
29 COBJS&& := pcDuino.o
修改pcDuino
160 #ifdef CONFIG_DISPLAY_BOARDINFO
161 int checkboard(void)
163&&&& puts(“Board: pcDuino\n”);
164&&&& return 0;
166 #endif
下面开始编译u-boot
&cd u-boot-sunxi
&mkdir build
&make distclean CROSS_COMPILE=arm-linux-gnueabihf-
&make sun4i_config CROSS_COMPILE=arm-linux-gnueabihf-& O=build
&make CROSS_COMPILE=arm-linux-gnueabihf- O=build
编译完了之后放到上运行,怎么放呢?
scp u-boot.bin Ubuntu@pcDuino的IP:/home/ubuntu/
sudo mount&&& /dev/nanda&& /mnt
sudo& chmod u+w linux
sudo& cd linux
sudo& rm& u-boot.bin
sudo& cp& /home/Ubuntu/u-boot.bin& .
sudo& cd ..
sudo&& chmod u-w linux
sudo&& reboot
重启之后在3秒停留位置停下来
这是的u-boo依然是不支持网络功能的,这一节仅仅只是修改了一下板子名
修改支持网络功能
先看sunxi-current里面的源码,发现他在boards里面就已经初始化了网络,我们就从这里开始。
vim ./arch/arm/cpu/armv7/sunxi/board.c& #添加
157 #if defined(CONFIG_SUNXI_EMAC)
159& * Initializes on-chip ethernet controllers.
160& * to override, implement board_eth_init()
162 int cpu_eth_init(bd_t *bis)
164&&&& sunxi_emac_initialize(bis);
166&&&& return 0;
168 #endif
然后将sunxi-current里面的网卡驱动拷贝到lichee-dev里面
cp ~/u-boot/drivers/net/sunxi_emac.c &&&&drivers/net/
修改Makefile
vim drivers/net/Makefile&&&&& #添加
29 COBJS-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o
保存之后编译,这里肯定有错误的,现在你只需要解决这些错误,就可以完成u-boot的修改。下面是我的所有修改:
这里跟你解释里面++和—是什么意思。++表示添加,–表示删除。如果你觉得麻烦,请看我的git仓库:
下载测试:
sun4i# tftp 0& uImage
Using emac device
TFTP from server 192.168.2.3; our IP address is 192.168.2.22
Filename ‘uImage’.
Load address: 0&
Loading: #################################################################
&&&&&&&& &#############################################
Bytes transferred = 9720 hex)
sun4i#tftp 0& dts/sun4i-a10-cubieboard.dtb
Using emac device
TFTP from server 192.168.2.3; our IP address is 192.168.2.22
Filename ‘dts/sun4i-a10-cubieboard.dtb’.
Load address: 0&
Loading: #
Bytes transferred =
sun4i#bootm 0& – 0&
## Booting kernel from Legacy Image at
&& Image Name:&& Linux-3.12.0-10089-gf16892f-dirt
&& Created:&&&&& & 12:28:56 UTC
&& Image Type:&& ARM Linux Kernel Image (uncompressed)
&& Data Size:&&& 1611488 Bytes = 1.5 MiB
&& Load Address:
&& Entry Point:&
&& Verifying Checksum … OK
&& Loading Kernel Image … OK
Starting kernel …
看到已经完美支持tftp下载,后面讲解怎么大家tftp服务器,nfs服务器等内容。}

我要回帖

更多关于 uboot 内存初始化 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信