历史上的今天
返回首页

历史上的今天

今天是:2025年11月18日(星期二)

正在发生

2022年11月18日 | U-Boot-1.1.6移植到MINI2440开发板(4) —— 源码分析第二阶段(1)

2022-11-18 来源:zhihu

下面开始分析U-Boot第二阶段:


/lib_arm/board.c:


由前述分析可知,在start.S中对CPU进行了基本的设置,准备好了C程序的运行环境(设置好了堆栈并清BSS),并调用C函数start_armboot,进入lib_arm目录下的board.c文件,第236行开始即为start_armboot函数:


------- /lib_arm/board.c -------

236 void start_armboot (void)

237 {

238     init_fnc_t **init_fnc_ptr;

239     char *s;

240 #ifndef CFG_NO_FLASH

241     ulong size;

242 #endif

243 #if defined(CONFIG_VFD) || defined(CONFIG_LCD)

244     unsigned long addr;

245 #endif

一些变量的定义,其中init_fnc_ptr为初始化函数序列的指针。

接下来初始化全局变量gd与gd->bd的内存区域(清0),第55行的宏定义声明了gd:


------- /lib_arm/board.c -------

55 DECLARE_GLOBAL_DATA_PTR;

这个宏定义在/include/asm-arm/global_data.h中,(凡是用到gd的文件中都会引用这个宏定义):


------- /include/asm-arm/global_data.h -------

64 #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

register volatile gd_t *gd asm ("r8"):声明一个寄存器变量gd,用R8寄存器来存储其指针,不占用内存,且避免编译器再将R8分配给其他变量。

第248行设置gd指针的具体地址,其中_armboot_start表示0x33F80000地址,CFG_MALLOC_LEN定义的大小为0x30000=192kB,然后调用memset函数将gd指针开始的、大小为sizeof(gd_t)的内存区域初始化为0:


------- /lib_arm/board.c -------

247     /* Pointer is writable since we allocated a register for it */

248     gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

249     /* compiler optimization barrier needed for GCC >= 3.4 */

250     __asm__ __volatile__("": : :"memory");

251 

252     memset ((void*)gd, 0, sizeof (gd_t));

__asm__:在此插入汇编语句;

__volatile__:禁止优化,即编译器将按照此处的语句处理;

"memory":强制编译器假设所有内存单元均被汇编指令修改,即CPU必须重新读取内存中的数据,而不是利用cache的缓存数据。

举个栗子(来自网络博客):

1 int a = 5, b = 6;

2 __asm__ __volatile__("": : :"memory");

3 a = b;

此时第3行的处理,编译器不会用存放b的寄存器给a赋值,而是让CPU重新读取内存中b的值,并赋给a。


第253行、254行设置bd的指针,并将其内存区域初始化为0:


------- /lib_arm/board.c -------

253     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

254     memset (gd->bd, 0, sizeof (bd_t));

255

256     monitor_flash_len = _bss_start - _armboot_start;

接下来按照初始化函数序列的顺序,执行所有的初始化函数:


------- /lib_arm/board.c -------

258     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

259         if ((*init_fnc_ptr)() != 0) {

260             hang ();

261         }

262     }

初始化函数正确执行的返回值应该为0,否则将调用hang()函数,输出错误信息并进入死循环暂停。

初始化函数序列包括CPU的初始化、板级初始化、中断初始化、环境变量初始化、波特率初始化、串口初始化、控制台初始化、显示U-Boot信息以及DRAM的初始化等:


------- /lib_arm/board.c -------

212 typedef int (init_fnc_t) (void);

...

216 init_fnc_t *init_sequence[] = {

217     cpu_init,        /* basic cpu dependent setup */

218     board_init,        /* basic board dependent setup */

219     interrupt_init,        /* set up exceptions */

220     env_init,        /* initialize environment */

221     init_baudrate,        /* initialze baudrate settings */

222     serial_init,        /* serial communications setup */

223     console_init_f,        /* stage 1 init of console */

224     display_banner,        /* say that we are here */

225 #if defined(CONFIG_DISPLAY_CPUINFO)

226     print_cpuinfo,        /* display cpu info (and speed) */

227 #endif

228 #if defined(CONFIG_DISPLAY_BOARDINFO)

229     checkboard,        /* display board info */

230 #endif

231     dram_init,        /* configure available RAM banks */

232     display_dram_config,

233     NULL,

234 };

下面对初始化函数序列进行详细说明(可以先初始化波特率和串口,便于输出调试信息,这里按顺序进行分析修改)。




初始化函数序列分析:


cpu_init:


位于/cpu/arm920t/cpu.c文件中,主要用于设置中断的堆栈,在这里并没有定义CONFIG_USE_IRQ,因此实际上无作用,不需进行修改:


------- /cpu/arm920t/cpu.c -------

92 int cpu_init (void)

93 {

94     /*

95      * setup up stacks if necessary

96      */

97 #ifdef CONFIG_USE_IRQ

98     IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;

99     FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;

100 #endif

101     return 0;

102 }



board_init:


位于/board/mini2440/mini2440.c文件中,主要用于CPU时钟与引脚设置:


------- /board/mini2440/mini2440.c -------

68 int board_init (void)

69 {

70     S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

71     S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

S3C24X0_CLOCK_POWER:在/include/s3c24x0.h中定义,而S3C2440多一个CAMDIVN寄存器,因此在添加修改(不修改也没事):


------- /include/s3c24x0.h -------

120 /* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */

121 /*                          (see S3C2410 manual chapter 7) */

122 typedef struct {

123     S3C24X0_REG32    LOCKTIME;

124     S3C24X0_REG32    MPLLCON;

125     S3C24X0_REG32    UPLLCON;

126     S3C24X0_REG32    CLKCON;

127     S3C24X0_REG32    CLKSLOW;

128     S3C24X0_REG32    CLKDIVN;

129 #ifdef CONFIG_S3C2440

130     S3C24X0_REG32    CAMDIVN;

131 #endif

132 } /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;

...

845 /* CLOCK & POWER MANAGEMENT */

846 #define rLOCKTIME       (*(volatile unsigned *)0x4C000000)

847 #define rMPLLCON        (*(volatile unsigned *)0x4C000004)

848 #define rUPLLCON        (*(volatile unsigned *)0x4C000008)

849 #define rCLKCON         (*(volatile unsigned *)0x4C00000C)

850 #define rCLKSLOW        (*(volatile unsigned *)0x4C000010)

851 #define rCLKDIVN        (*(volatile unsigned *)0x4C000014)

852 #define rCAMDIVN        (*(volatile unsigned *)0x4C000018)

S3C2440还有一些寄存器与S3C2410不同,在后续遇到时将进行修改。

S3C24X0_GPIO:在/include/s3c24x0.h中定义,在前面已经添加了S3C2440的GPIO寄存器:


------- /include/s3c24x0.h -------

385 /* I/O PORT (see manual chapter 9) */

386 typedef struct {

...

470 #ifdef CONFIG_S3C2440

471     S3C24X0_REG32    GPACON;

472     S3C24X0_REG32    GPADAT;

473     S3C24X0_REG32    res1[2];

474     S3C24X0_REG32    GPBCON;

475     S3C24X0_REG32    GPBDAT;

476     S3C24X0_REG32    GPBUP;

477     S3C24X0_REG32    res2;

478     S3C24X0_REG32    GPCCON;

479     S3C24X0_REG32    GPCDAT;

480     S3C24X0_REG32    GPCUP;

481     S3C24X0_REG32    res3;

482     S3C24X0_REG32    GPDCON;

483     S3C24X0_REG32    GPDDAT;

484     S3C24X0_REG32    GPDUP;

485     S3C24X0_REG32    res4;

486     S3C24X0_REG32    GPECON;

487     S3C24X0_REG32    GPEDAT;

488     S3C24X0_REG32    GPEUP;

489     S3C24X0_REG32    res5;

490     S3C24X0_REG32    GPFCON;

491     S3C24X0_REG32    GPFDAT;

492     S3C24X0_REG32    GPFUP;

493     S3C24X0_REG32    res6;

494     S3C24X0_REG32    GPGCON;

495     S3C24X0_REG32    GPGDAT;

496     S3C24X0_REG32    GPGUP;

497     S3C24X0_REG32    res7;

498     S3C24X0_REG32    GPHCON;

499     S3C24X0_REG32    GPHDAT;

500     S3C24X0_REG32    GPHUP;

501     S3C24X0_REG32    res8;

502 

503     S3C24X0_REG32    MISCCR;

504     S3C24X0_REG32    DCLKCON;

505     S3C24X0_REG32    EXTINT0;

506     S3C24X0_REG32    EXTINT1;

507     S3C24X0_REG32    EXTINT2;

508     S3C24X0_REG32    EINTFLT0;

509     S3C24X0_REG32    EINTFLT1;

510     S3C24X0_REG32    EINTFLT2;

511     S3C24X0_REG32    EINTFLT3;

512     S3C24X0_REG32    EINTMASK;

513     S3C24X0_REG32    EINTPEND;

514     S3C24X0_REG32    GSTATUS0;

515     S3C24X0_REG32    GSTATUS1;

516     S3C24X0_REG32    GSTATUS2;

517     S3C24X0_REG32    GSTATUS3;

518     S3C24X0_REG32    GSTATUS4;

519 #endif

520 } /*__attribute__((__packed__))*/ S3C24X0_GPIO;

通过设置MPLLCON和UPLLCON来改变时钟频率:

修改时钟设置宏定义如下:


------- /board/mini2440/mini2440.c -------

33 //#define FCLK_SPEED 1

34 #define FCLK_SPEED 200

...

44 #elif FCLK_SPEED==200

45 #define M_MDIV    0x5C

46 #define M_PDIV    0x1

47 #define M_SDIV    0x2

...

50 //#define USB_CLOCK 1

51 #define USB_CLOCK 48

...

61 #elif USB_CLOCK==48

62 #define U_M_MDIV    0x38

63 #define U_M_PDIV    0x2

64 #define U_M_SDIV    0x2

在board_init函数中通过时钟设置的宏定义对时钟频率进行修改:


------- /board/mini2440/mini2440.c -------

83     /* to reduce PLL lock time, adjust the LOCKTIME register */

84     clk_power->LOCKTIME = 0xFFFFFF;

85 

86     /* the CLKDIVN register, FCLK:HCLK:PCLK=4:2:1 */

87     clk_power->CLKDIVN = 0x3;

88     __asm__(

89             "mrc p15, 0, r0, c1, c0, 0n"

90             "orr r0, r0, #0xC0000000n"

推荐阅读

史海拾趣

Crystalfontz America Inc公司的发展小趣事

为了保证产品质量和客户满意度,Crystalfontz America Inc公司建立了完善的质量管理体系。公司从原材料采购、生产制造到产品出厂等各个环节都严格把控质量,确保产品符合相关标准和客户要求。同时,公司还不断优化生产流程和管理制度,提高生产效率和产品质量稳定性。这些措施为公司赢得了良好的市场声誉和客户口碑。

Daco Semiconductor Co Ltd公司的发展小趣事

在快速发展的过程中,Daco始终注重产品品质和用户体验。公司建立了严格的质量管理体系,对每一批产品都进行严格的检测和测试,确保产品的性能和质量达到客户的要求。同时,Daco也积极倾听客户的反馈和建议,不断改进产品和服务。这种对品质和用户体验的执着追求,使得Daco在客户中树立了良好的口碑。

EETools公司的发展小趣事

面对快速变化的市场环境和不断涌现的新技术,EETools始终保持开放和创新的姿态。公司不仅持续关注行业动态和技术趋势,还积极探索新的业务领域和增长点。例如,EETools正在研发基于人工智能和物联网技术的嵌入式开发工具,以满足未来市场的需求。同时,公司还计划进一步拓展海外市场,提升品牌在国际市场的竞争力。这些举措将为EETools的未来发展奠定坚实的基础。

FTCAP Fischer & Tausche Capacitor Group公司的发展小趣事

EETools始终坚持以客户为中心的服务理念。公司深入了解不同行业客户的需求和痛点,为他们提供定制化的嵌入式系统解决方案。无论是医疗设备、汽车电子还是工业自动化等领域,EETools都能为客户提供高效、可靠的嵌入式开发工具和服务。这种以客户需求为导向的服务模式不仅赢得了客户的信任和好评,还为公司赢得了更多的商业机会。

EPCOS (TDK)公司的发展小趣事

EPCOS的前身是西门子松下有限公司(Siemens Matsushita Components),于1989年在德国慕尼黑成立。这家合资公司的诞生标志着西门子和松下两大电子巨头在电子元器件领域的强强联合。通过整合双方的技术和市场优势,EPCOS迅速崛起为全球电子元器件市场的重要参与者。

华宇创公司的发展小趣事

华宇创深知品质是企业生存和发展的关键。因此,公司建立了严格的质量管理体系,从原材料采购到生产过程再到成品检测,每一个环节都严格把控。同时,华宇创还积极参与各类国际认证和标准制定工作,不断提升产品的品质和性能。这些努力使华宇创的产品在市场上赢得了良好的口碑和信誉,品牌知名度也逐渐提升。

问答坊 | AI 解惑

DIY xds100

本人手里有XDS100若干个,空板子若干,打算在这里弄个DIY XDS100,不知道大家对这个感兴趣不…

查看全部问答>

电子基础

供初学者学习…

查看全部问答>

你家的灯该LED了吗?LED已掀起新光源革命!

replyreload += \',\' + 377584;Timson,如果您要查看本帖隐藏内容请回复…

查看全部问答>

6410 的CAMERA问题 急!

我想问下  我的CAMERA最近一直没点起来  我是自己写程序裸奔的  ,我想问下  我是不是需要对POST  PROCESS进行必要的设置  这样才可以让CAMERA的数据顺利的到我的内存开辟的空间去&nb ...…

查看全部问答>

VS2005 开发WINCE 5.0程序PictureBox加载图片时异常

VS2005 开发WINCE 5.0程序PictureBox加载图片时异常…

查看全部问答>

STM32的AD做交流采样线型性不太好

我调整AD的采样时间,发现采样时间越长,线性性相对好点,但是还是达不到要求。 检查了电路,电压输入的值,线性性能达到要求,但是AD采集的线性性达不到要求。 我初步估计是AD的充放电的原因,目前的输入阻抗是2k左右。 那位高手遇到过这 ...…

查看全部问答>

纯单片机与CPLD设计的优缺点分析

  自20世纪80年代单片机引入我国以来,学习和应用单片机的热潮始终不减,特别是MCS51系列。这是由单片机的特点决定的。实际上,从单片机/CPLD应用通用数字集成电路系统,到广泛应用单片机,是我国电子设计在智能化应用水平上质的飞跃。据统计分析 ...…

查看全部问答>

请问

想装一套简单的智能家居,只是想红外控制空调电视电动窗帘,无线控制6-7个灯开关。 网上产品很多,最后选择了完美E家的 Control838主机+IR838红外 不清楚合不合适。 初次发帖,不合规及勿怪。…

查看全部问答>

STM32F103 LCD1602源程序及资料

手上有一STM32F103的板子,有一部分关于LCD1602的,网上找了一些资料,整理一下,现将资源共享一下!!…

查看全部问答>