当前位置:首页 > 单片机 > 单片机
[导读]在介绍该函数之前,我们需要看一看几个数据结构,这些是u-boot中几个重要的数据结构:1)、gd_t该数据结构保存了u-boot需要的配置信息(我暂时称它为全局信息表),typedef struct global_data { bd_t *bd;//与板子

在介绍该函数之前,我们需要看一看几个数据结构,这些是u-boot中几个重要的数据结构:
1)、gd_t该数据结构保存了u-boot需要的配置信息(我暂时称它为全局信息表),
typedef struct global_data {
bd_t *bd;//与板子相关的结构,见下面
unsigned long flags;
unsigned long baudrate;//波特率
unsigned long have_console; /* serial_init() was called */
unsigned long reloc_off; /* Relocation Offset,重定位偏移*/
unsigned long env_addr; /* Addressof Environment struct ,存放环境变量结构的地址*/
unsigned long env_valid; /* Checksum of Environment valid? */
#ifdef CONFIG_VFD//我们一般没有配置这个,这个是frame buffer的首地址
unsigned long fb_base; /* base address of frame buffer,显存缓存区基址*/
#endif
#if 0
unsigned long cpu_clk;/* CPU clock in Hz! CPU的时钟频率*/
unsigned long bus_clk;//总线的时钟频率
unsigned long ram_size;/* RAM size, RAM的大小*/
unsigned long reset_status;/* reset status register at boot */
#endif
void**jt;/* jump table ,保存着些函数的入口地址,在common/Exports.c中进行填充*/
} gd_t;
2)、bd_t保存与板子相关的配置参数
typedef struct bd_info

{
int bi_baudrate; /* serial console baudrate ,串口波特率*/
unsigned long bi_ip_addr; /* IP Address ,IP地址*/
unsigned char bi_enetaddr[6];/* Ethernet adress ,以太网地址*/
struct environment_s *bi_env;//环境变量地址指针
ulong bi_arch_number; /* unique id for this board架构号码*/
ulong bi_boot_params; /* where this board expects params */
struct /* RAM configuration */
{
ulong start;//RAM的起始地址
ulong size;//RAM的大小
}

bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
3).初始化函数列表(以数组的形式)
init_fnc_t *init_sequence[] =

{

cpu_init,/* basic cpu dependent setup|| cpu/arm920t/cpu.c ,cpu的初始化,有待于分析*/
//这个是对板子的初始化,
board_init,/* basic board dependent setup|| board/smdk2440/smdk2440.c */
interrupt_init,/* set up exceptions || cpu/arm920t,s3c24x0/interrupts.c */
env_init, /* initialize environment */
init_baudrate,/* initialze baudrate settings */
serial_init,/* serial communications setup || cpu/arm920t/s3c24x0/serial.c */
//串口初始化后我们就可以打印信息了
console_init_f,/* stage 1 init of console */
display_banner,/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,/* display board info */
#endif
dram_init,/* configure available RAM banks */
display_dram_config,
NULL,
};
//===========================================
int cpu_init (void)//cpu/arm920t/Cpu.c中的函数
{
/*
* setup up stacks if necessary
*/
//这里只是做了对中断栈和快速中断栈空间地址的定义
//IRQ_STACK_START和FIQ_STACK_START的值在start.S的开始几行中有定义
//其中的那个-4操作是难道是为PC跳转留的一个地址???
#ifdef CONFIG_USE_IRQ
IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
return 0;
}
//===================================================
//---------mem_malloc_init----------------
//参数: malloc内在区的起始地址
//功能:完成malloc函数所要用到的静态变量的初始化.
//返回值:无
//----------------------------------------
static void mem_malloc_init (ulong dest_addr)
{
mem_malloc_start = dest_addr;//缓冲区起始地址
mem_malloc_end = dest_addr + CFG_MALLOC_LEN;//缓冲区结束地址
mem_malloc_brk = mem_malloc_start;//已使用块的地址,初始时应指向起始地址
memset ((void *) mem_malloc_start, 0, mem_malloc_end - mem_malloc_start);//把这段空间初始化为0
}
......
init_fnc_t *init_sequence[] = {
//该函数只是做了对中断栈和快速中断栈空间地址的定义
cpu_init, /* basic cpu dependent setup|| cpu/arm920t/cpu.c */
//完成各时钟和端口还有gd中的两个成员的初始化
board_init,/* basic board dependent setup|| board/smdk2440/smdk2440.c */
//PWM(Pulse Width Modulation脉宽调制器) TIMER的初始化,
interrupt_init,/* set up exceptions || cpu/arm920t,s3c24x0/interrupts.c */
//环境的初始化,没深入分析
env_init, /* initialize environment */
//初始化波特率,并写进gd的成员变量中
init_baudrate,/* initialze baudrate settings */

//串口初始化后我们就可以打印信息了
serial_init,/* serial communications setup || cpu/arm920t/s3c24x0/serial.c */

console_init_f,/* stage 1 init of console */

//打印一些信息
display_banner,/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo,/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard,/* display board info */
#endif
//DRAM的初始化,这里只是对gd中的bi_dram结构中的两个成员赋值,
//也即BANK的起始地址和大小
dram_init,/* configure available RAM banks */

//打印BANK的相关信息
display_dram_config,
NULL,//用以标识列表数组的结束
};
//------------start_armboot--------------------
//功能:完成uboot第二阶级的一系列的硬件初始化工作,然后转入main函数.
//备注:该函数是C程序的入口函数,从汇编语言跳转到此.
//---------------------------------------------
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;//init_fnc_t是各初始化函数的数组
char *s;
#ifndef CFG_NO_FLASH
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it
gd_t:定义在/include/asm-arm/Global_data.h中,包含一些全局通用的变量.
_armboot_start:代码的起始地址,它定义在start.S中的前几行中,定义为_start当系统第一次加电时,指令是从0x0地址开始执行的,所以此时的_start值应为0x0;而当uboot经过代码重定位后,指令会从_TEXT_BASE处开始执行,此时的_start值就成了_TEXT_BASE的值. CFG_MALLOC_LEN:在/include/configs/smdk2440.h中有定义,该变量表示供malloc函数使用的内存池空间,代码中定义值为:0x10000+128*1024
|-------|<--- _armboot_start基址
|4 |
|-------|<--- malloc函数池基址
|3 |
|-------|<--- (gd_t)gd(全局变量表)基址
|2 |
|-------|<--- (bt_t)bd(板卡信息表)基址
|1 |
-------
4就是为malloc函数预留的数据空间
3是全局信息表gd的数据区
2是板卡信息表bd的数据区
网上找了个图片,更能反应这个空间的分配关系:

*/
//分配区域3给gd ,gd是一个全局静态变量
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
//把gd变量的内容填充为0 ,填充3区的数据为0 ,即初始化gd表.注意:这里并没有初始化bd表,在gd表中的bd成员只是一个指针,因为对初始化的是个指针地址
memset ((void*)gd, 0, sizeof (gd_t));
/*bd_t结构体在/include/asm-arm/U-boot.h中定义,定义板子的一些信息,包括:
波特率,IP地址,以太网地址,架构编码,启动参数,BANK的起始地址和大小等*/
//分配区域2给bd, bd的基址= gd的基址- bd的尺寸
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
//把区域2填充为0 ,即初始化bd表
memset (gd->bd, 0, sizeof (bd_t));
/*monitor_falsh_len定义在/lib_arm/Board.c
在bin文件中BSS段和TEXT段和DATA段存放的顺序同前向后依次是:
TEXT(代码段RO) DATA(已初始化数据段RW) BSS(未初始化数据段ZI)
所以_bss_start的基址等于TEXT的长度加上DATA的长度.
即: _bss_start(BSS段基址) =代码段长度+数据段长度

BSS(Block Started by Symbol)段是未被初始化的数据段,是存放程序中未被初始化的全局变量的一块内存区域,初始化时应清零;该段只有名称和大小却没有值;该段不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零,它在应用程序的映像文件(ARM中也即bin文件)中并不存在.
text :代码段,是包含程序代码的段
data:已经初始化的数据段,保存已经初始化的全局变量.
在嵌入式系统中,bin文件(又称Image文件)中只包含text和data段,而bss段不在其中,它是由系统初始化为零. */
//_armboot_start在start.S中定义为_start,而_start为代码的起始地址只包含RO(TEXT)和RW(DATA)段.重定位前的值为0x0,此时指向flash,重定位后则指向RAM中的某一地址由此可以知道:_bss_start - _armboot_start的值即是在第一阶段从flash中重定位到RAM中的那部分代码的长度,也即可TEXT和DATA段,这个值与start.S中的重定位那部分代码所计算的值是相等的;所以,monitor_flash_len表示从flash中搬来的代码的长度
monitor_flash_len = _bss_start - _armboot_start;//_bss_start在u-boot.lds中定位
//各设置的初始化.当返回值不为0时表示初始化失败,此时会调用hang()函数
//打印一错误提示信息,然后进入死循环
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
//CFG_NO_FLASH表示没有flash,如果没定义该常量则表示板子上有flash,此时调用flash_init()对其进行初始化.
#ifndef CFG_NO_FLASH
/* configure available FLASH banks */
size = flash_init ();
display_flash_config (size);//打印flash的信息,这里仅输出它的大小
#endif /* CFG_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
//把视频帧缓冲区设置在bss_end后面

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭