设为首页收藏本站
查看: 19718|回复: 1

[Bootloader] 【转】ZYNQ 7000 "Hello, World!"背后的故事

[复制链接]

231

主题

64

回帖

2145

积分

管理员

积分
2145
玉米糊 发表于 2015-6-5 10:19:35 | 显示全部楼层 |阅读模式
      我等电子爱好者拿到一块开发板当然首先就是让他输出Hello Word的啦。ZYNQ作为XILINX推出的最新的ALL PROGRAMME平台自然也无法逃离此等“厄运”。

      让ZYNQ输出"HELLO,WORLD"非常简单,ZEDBOARD.ORG网站上已有ZedBoard_CTT_v14.1文档,大家按照文档中的步骤就能通过串行接口看到输出了。如果不太明白也可以到BAIDU上搜索ZEDBOARD,很多前辈已经把输出"HELLO,WORLD"的步骤图文并茂的一步一步给出了。图1就是main函数的截图,可以看到该函数非常的简单,首先初始化 平台,然后利用“重定向把printf”函数的输出定位到串口上。
1093260465066.jpg

     注意到代码中把 init_platform cleanup_platform 函数已经被注释掉了,难道只有一个 printf 就能输出吗?
当然,查看 Init_platform() 和 cleanup_platform() 源码我们会发现,其实这两个函数和串口输出并没有任何关系,这两个函数的作用就是打开系统的cache和关闭系统cache。
Init_platform函数中包含有init_uart函数,但仔细观察发现只有在系统中定义了STDOUT_IS_16550宏,init_uart 函数中的语句才起作用,否则该函数就是一个空函数。而在本例子中我们是并没有用到STDOUT,所以根本没有定义 STDOUT_IS_16550宏 )。

     看到这个估计很多人都有个疑问:串口在使用之前不是应该初始化的吗至少要设置一下波特率啥的吧?看代码中,似乎没有对ZYNQ的串口进行初始化就使用了,难道ZYNQ太先进了不用初始化?


     在讨论这个问题之前,让我们先来看看ZYNQ的结构以及ARM的启动过程。

     ZYNQ中包含有2个ARM Cotex-A9的核(PS)PL逻辑单元。ZYNQ支持多种启动模块,总的来说包括安全和不安全的两种引导方式。引导主要是通过PS部分来完成。对于安全引导来说,PL部分必须启动,以便使用其中的安全模块,通过这些模块可以完成256位AES和SHA授权。在系统复位后,系统将会检测模式引脚上的电平状态,以此来决定从哪个设备(NOR,NAND,QUAD-SPI或JTAG)来引导系统。当然,JTAG方式只能工作在不安全引导方式下,通常该模式是用来调试系统的。

     在决定从哪个设备引导系统后,其中一个ARM A9的核开始执行片外ROM中的代码,并拷贝第一阶段BOOT LOADER(FSBL)到OCM(On Chip Memory)中。拷贝完成后,处理器开始执行FSBL,系统开始对PS部分进行初始化并可以开始配置PL模块(当然,你也可以不配置PL模块)。通常,在FSBL中需要包含对第二阶段代码(SSBL)的载入(如UBOOT)。SSBL继续对处理器进行配置直到系统完全完成初始化。

     既然在执行MAIN函数之前还有这么多步骤,那么这些代码到底写在哪里呢?打开工程目录下的SDK\SDK_Export\hello_world_bsp_0\ps7_cortexa9_0\libsrc\standalone_v3_05_a\路径下的SRC文件夹,里面有
  • asm_vectors.S
  • boot.S
  • cpu_init.S
  • translation_table.s
  • xil-crt0.S
等5个文件,它们都是.s结尾的汇编文件,根据以往的经验,这些都应该是最底层的,系统启动后首先执行的文件。

     我们知道ARM启动都是从0x00地址开始的,而在这个地址上放的应该是中断向量表,根据这个线索,我们首先查看asm_vectors.S文件,文件的最开头如图2所示:
1093627843673.jpg

     这里就是中断向量表,ZYNQ启动后所运行的第一句话就是B  _boot,这是一个跳转语句,直接跳转到 boot.s 文件中的  _boot  标号处开始执行后面的语句,由于后面的代码比较长,在此就不赘述了。boot.s 中的代码主要完成MMU、Cache的初始化以及ARM各种模式下栈基地址的配置,最后通过
[mw_shl_code=asm,true]b _start[/mw_shl_code]
语句跳转到_start标号中继续执行。_start 标号在xil-crt0.S文件中被实现,代码如下:
[mw_shl_code=asm,true]
_start:
bl      __cpu_init /* Initialize the CPU first (BSP provides this) */

mov r0, #0

/* clear sbss */
ldr  r1,.Lsbss_start /* calculate beginning of the SBSS */
ldr r2,.Lsbss_end /* calculate end of the SBSS */

.Lloop_sbss:
cmp r1,r2
bge .Lenclsbss /* If no SBSS, no clearing required */
str r0, [r1], #4
b .Lloop_sbss

.Lenclsbss:  
/* clear bss */
ldr r1,.Lbss_start /* calculate beginning of the BSS */
ldr r2,.Lbss_end /* calculate end of the BSS */

.Lloop_bss:
cmp r1,r2
bge .Lenclbss /* If no BSS, no clearing required */
str r0, [r1], #4
b .Lloop_bss

.Lenclbss:

/* set stack pointer */
ldr r13,.Lstack /* stack address */

/* Initialize STDOUT to 115200bps */
ldr r0, =UART_BAUDRATE
bl Init_Uart
#ifdef PROFILING /* defined in Makefile */
/* Setup profiling stuff */
bl _profile_init
#endif /* PROFILING */


/* Initialize the SMC interfaces for NOR and SRAM */
#ifndef USE_AMP
bl XSmc_NorInit

bl XSmc_SramInit
#endif

/* make sure argc and argv are valid */
mov r0, #0
mov r1, #0

/* Let her rip */
bl main[/mw_shl_code]
     代码首先通过语句 bl __cpu_init 跳转到_cpu_init标号处(该标号在cpu_init.S文件中,其中的代码主要对cp15寄存器进行操作),随后代码对SBSS段、BSS段以及栈指针R13进行初始化,紧接着通过语句bl Init_Uart跳转到UART.C文件中对串口进行初始化;通过语句 bl XSmc_NorInit bl XSmc_SramInit 对NOR和SRAM存储器进行初始化,最后调用bl main跳转到我们的MAIN函数中开始执行用户的程序。

        这下我们就可以解释开始所提出的问题了,实际中ZYNQ的串口并不是不需要初始化,而是在进入 main 函数之前就已经被初始化过了,其所用的波特率在 xil-crt0.S 文件的顶头被宏定义过,默认为115200BPS。如果我们要用其它的波特率的话,理论上来说在该处更改即可。为什么说理论上呢?因为在实际中更改此处是不行的,究其原因我认为是由于 xil-crt0.S 是系统生成,如果我们更改后不编译该文件那么自然不能更改波特率;如果编译该文件则EDK会自动从系统中重新拷一个x il-crt0.S 文件到项目中, 这也就把我们更改过的文件覆盖了。所以,如果我们需要更改串口的波特率的话,最简便的方法就是在main函数中再调用一次 Init_Uart函数,指定其输入参数为我们所需要的波特率,如9600。

     总结一下,其实ZYNQ中的ARM和我们平时所用的ARM启动方式上并没有任何差别,也是从中断向量表开始然后经过多次跳转最终调用用户程序的 main 函数。用流程图表示如下所示:
1105578308231.jpg

原文地址:http://blog.chinaaet.com/detail/30143

回复

使用道具 举报

1

主题

2

回帖

32

积分

新手上路

积分
32
suoma 发表于 2015-6-21 11:32:30 | 显示全部楼层
谢谢分享学习一下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录

本版积分规则

Archiver|手机版|小黑屋|米尔科技论坛   

GMT+8, 2024-5-6 18:42 , Processed in 0.054144 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表