少年易老学难成, 一寸光阴不可轻。
未觉池塘春草梦, 阶前梧叶已秋声。
《劝学》 朱熹
都说万事开头难,作为一名大学只接触过单片机,且多年未用的选手,我对这个难字深有感触。毕业以来一直都在做整体设计方案,对大学用过的单片机已放下多时,最近由于项目需要,俺要自己去使用arm A9构架的嵌入式板卡。无奈之下只得拿着该开发板的使用手册依葫芦画瓢瞎操作一番,由于手册并没有详细说明指令的意思,自己只能一个个baidu它们,经常出现缺少符号或者字母操作失败的情况。
后来机缘巧合看到了韦东山老师的视频,学了几课以后,顿觉脑子不在一桶浆糊。韦东山老师讲得非常透彻,我激动不已于是一口气下载了视频的全部三期(后来才知道2,3期是需要付费的)。手机里一份,家里电脑里一份,经常在公交车上看看,在家里看看。对于uboot和内核、文件系统这三课看了有三四遍,慢慢的对这三部分有了一些意识和理解,并且学会操作他们。 原来uboot的最终目的是为了启动内核kernel,但是在启动之前需要完成初始化时钟、关看门狗、初始化串口以及读写flash等操作,具体操作流程如下: 对于uboot的编译操作只需要执行: make100ask24x0.config 配置文件 make 编译文件 解释: make 100ask24x0.config 相当于执行@$(MKCONFIG)$(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0 uboot启动流程: 第一阶段: 板卡上电执行uboot第一个程序start.S,该uboot的入口程序才用汇编编写,代码如下: /* a, 设置CPU为SVC32模式 */ mrs r0,cpsr bic r0,r0,#0x1f orr r0,r0,#0xd3 msr cpsr,r0 /* b, 关闭看门狗 */ /* c, 关中断 */ /* d, CPU初始化,初始化SDRAM */ adr r0, _start ldr r1, _TEXT_BASE cmp r0,r1 blne cpu_init_crit /* e, 设置stack */ stack_setup: ldr r0, _TEXT_BASE /* 顶部128 KiB重定位的u-boot */ sub r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo结构体地址空间 */ #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* 预留3个字 */ /* f, 时钟初始化 */ bl clock_init /* g, 重定位,代码从Flash拷贝到SDRAM中 */ /* h, 清bss段 */ clear_bss: ldr r0, _bss_start /* bss段起始地址 */ ldr r1, _bss_end /* bss段末尾地址 */ mov r2, #0x00000000 /* 清零 */ clbss_l:str r2, [r0] /* bss段地址空间清零循环... */ add r0, r0, #4 cmp r0, r1 bne clbss_l /* i, 调用start_armboot */ ldr pc, _start_armboot _start_armboot: .word start_armboot
第二阶段: start_armboot是uboot执行的第一个C语言函数,完成系统初始化工作,基本的初始化函数指针保存在init_sequence[]数组中。 函数void start_armboot (void) { mem_malloc_init(_armboot_start - CONFIG_SYS_MALLOC_LEN); /*配置Flash */ display_flash_config(flash_init ()); /* 配置环境变量*/ env_relocate(); ...... /*main_loop()循环不断执行 */ for(;;) { main_loop(); /* 主循环函数处理执行用户命令*/ } } 该程序通过main_loop函数一直等待用户在控制台输入命令,接收到命令后进行命令解析。 启动内核: s=getenv(“bootcmd”) run_command(s) 环境变量中bootcmd参数有一条bootm 0x30007F00指令,表示内核在该地址处启动。 当有启动命令bootm时,会调用do_bootm函数。这个函数专门用来引导各种操作系统映像,可以支持引导Linux、QNX等操作系统,该函数会调用do_bootm_linux()。 最终do_bootm_linux()函数会调用 theKernel(0, bd->bi_arch_number, bd->bi_boot_params)函数来启动内核,传递启动参数。 uboot就先写这么多吧,好多地方我也不是很清楚,希望以后在分析uboot源码的过程中可以深入理解。 不知不觉就看完了韦东山老师视频的第一期,回头看看第二期视频的目录,主要讲驱动的,非常吸引人,并且和目前的项目需求比较贴近。于是我迫不及待的购买了第二期视频好好学习一下。 最后聊聊韦东山老师的讲解风格吧,韦老师边讲解边写代码的风格非常棒,对于嵌入式高手来说些代码也许比较容易,但对于新手来说绝对是授人以渔方式的教学。以前经常在一些帖子里面仅仅只能看到“重要”代码,对于初学者来说这是很无奈的,因为你往往面对着大量代码的移植和修改工作,如无人指导的话,绝对是个噩梦的开始。但现在对于新手来说,咱们有了更好的选择。 |