自制zynq开发板bring up问题总结

我们拿到一块全新的板子,第一件是自然就是bring up了,如何快速的让他启动起来,不能启动的时候如何快速的定位问题,是我们首先要做的第一步。之前有幸与某大佬一起合作一块ZYNQ开发板,bring up的过程充满了曲折,但是也学到了很多东西(浪费了很多钱),很多问题都很基础,分享出来希望能起到一点点的帮助。

首先我们需要准备一份芯片的datasheet,这里就要说一下xilinx的docnav了,真的是一站式解决了所有文档问题,简直不能再方便了(对没错那个叫全志的连个手册都不给全)。

启动方式

我们先来了解一下z7020的启动方式:

  • master mode boot(flash)
    • Quad-SPI flash
    • SD card
    • NAND flash
    • NOR flash
  • slave mode boot(jtag)
    • Cascade JTAG chain (most popular)
      • Access DAP and TAP controllers through PL JTAG
    • Independent JTAG chain (common)
      • Access TAP controller through PL JTAG
      • Access DAP controller through EMIO JTAG via SelectIO pins after configuring the PL with a bitstream
    • Independent JTAG chain (rarely used)
      • Access TAP controller through PL JTAG
      • Access DAP controller through MIO PJTAG

这里可以看到启动方式主要分为两种,一种flash启动一种jtag启动。通常情况下我们肯定是使用flash启动的,比如我手里这片板子,可以支持qspi flash,sd卡这两种启动方法。slave mode主要是jtag调试的时候使用,datasheet中列举的几种方式,主要是DAP的访问方式不同。

启动流程

stage 0: bootrom

zynq的flash启动都是由内置的bootrom控制的,bootrom就是固化在芯片当中的一段代码(造成switch被破解的漏洞就是bootrom中的),可以根据选定模式的不同,搬运固定地址固定长度的数据到sram中。

stage 1:fsbl

fsbl的全称是first stage boot loader,这是xilinx提供的代码,假如我们并不需要启动操作系统,这里启动的可能就已经是我们的用户程序了。fsbl的功能其实很简单,初始化基本外设,比如串口,DDR,加载PL部分所需的bitstream,再根据之前所设定的启动模式,将uboot载入到DDR中,完成下一步的启动。看到这里,你可能会发现fsbl的作用和uboot中的spl作用非常相像。zynq自身的sram很小,往往并不足以完成uboot的启动,这时候fsbl和spl同样起到了初始化比如ddr这样的外设,为下一步做准备的作用。而zynq比较特殊的地方是,PL部分的bitstream也需要在启动时加载,所以变产生了fsbl这个相对特殊的东西。

stage 2:uboot

stage 3:kernel

最后这两步就和平台无关了,这里就不做详细的说明。

制作boot image

经过之前的说明,我们现在需要制作一个真正能启动的镜像了,那么一个能够正常启动的镜像需要哪些内容呢:

  • fsbl
  • bitstream
  • uboot
  • kernel
  • dtb
  • rootfs

fsbl是我们系统启动的第一步,bitstream是用于配置PL部分,uboot,kernel,dtb,rootfs也则是启动linux系统所需的内容。
根据我的需求,fsbl,bitstream和uboot并不需要经常更新,所以我将他们放在qspi flash上,而Linux相关的部分体积较大,也需要经常修改,所以我将它们放在SD卡上。
制作boot image需要使用SDK中的Create boot image工具。使用起来很简单,我们需要一个bif文件来描述需呀包含进去的文件以及分区属性,根据这些信息我们就可以直接输出一个boot image了。下面是我之前的一个截图,可以看到只有bootloader和u-boot。
《自制zynq开发板bring up问题总结》
这里需要注意的是在添加的时候我们可以配置的一些参数,通常来说,我们都希望boot image的分区能够尽量的固定,那么我们就需要对添加分区的参数做一些配置。可以在图里看到other中有五个选项可以配置。alignment表示地址的对齐,offset表示偏移地址,reserver表示保留的长度,load表示将该分区载入到的内存目的地址,startup表示程序的入口点。这些描述其实都可以在SDK的帮助文档里找到,我将它也一并截图放了上来,方便大家查阅。
《自制zynq开发板bring up问题总结》
《自制zynq开发板bring up问题总结》
制作好了boot image之后只要按照我们的启动配置,将它烧写到flash,或者拷贝到SD卡中就可以啦。

问题排查

然而看似简单的bring up在实际自己去做的时候还是遇到了非常多的问题

sd卡无法启动

由于sd卡烧录方便,使用简单,那么第一个想到的就是使用sd卡启动了,然而无论怎么样我都没办法让系统正常的从sd卡启动fsbl。最后的解决方法也很简单—-更换芯片。推测应该是淘宝货源不靠谱,买到了拆机的芯片或者是早期的测试芯片,bootrom有bug。

qspi flash烧录失败

连接jtag之后我们可以使用xilinx的SDK软件方便的进行flash的烧录,但是我最开始使用的时候却使用无法正常的烧录。原因是默认烧录使用的频率太高,我使用过的flash并不支持,通过修改XIL_CSE_ZYNQ_UBOOT_QSPI_FREQ_HZ降低频率频率之后即可正确烧录。这边只做简单的归纳总结,具体的debug以及修改方法还请参照这片博客:
定义环境变量解决SDK下载失败

fsbl及bootrom阶段的调试方法

fsbl debug输出

如果在fsbl部分启动失败了,其实我们的调试方法是十分多样的。首先我们可以用jtag启动zynq,这里就不多说了,有了jtag我们可以随意的去增加断点调试程序。fsbl其实还我们提供了丰富的debug log,在fsbl_debug.h中有这样一段代码:

#if defined (FSBL_DEBUG_INFO)
#define fsbl_dbg_current_types ((DEBUG_INFO) | (DEBUG_GENERAL))
#elif defined (FSBL_DEBUG)
#define fsbl_dbg_current_types (DEBUG_GENERAL)
#else
#define fsbl_dbg_current_types 0
#endif

这里我们只需要定义FSBL_DEBUG_INFO就可以打开调试信息打印了,调试信息会通过串口输出。

fsbl载入失败

那么假如这时候串口还是没有任何输出我们该怎么办呢,首先检查串口的配置,波特率是否正确。镜像烧录是否正确,启动方式是否选择正确。排除完了这些之后如果还是不行,那么我们怀疑的目光就要向更底层前进了,没错就是bootrom,我们要确保bootrom有正常的读取fsbl到OCM中。fsbl默认是被载入到从0地址开始的OCM当中,长度最大为256K。我们连接上jtag,正常启动目标板以后,在SDK中的XSCT console中使用mrd 0x0可以读取到OCM当中的内容,如果fsbl被正确的读取,那么这里应该有数据,否则这里就全都是0。
那么假如我们发现fsbl没有被正确加载呢,xilinx同样为我们提供了调试方法,一般来说这都是因为bootrom在访问存储设备的时候出现了错误。通过查阅zynq的手册(UG585)我们看到slcr的REBOOT_STATUS寄存器中有一部分叫做BOOTROM_ERROR_CODE,他可以用来表示bootrom发生错误的原因。错误的类型我这里就不列出来了,大家可以自行查阅UG585。
《自制zynq开发板bring up问题总结》

fsbl读取QSPI flash失败

成功烧录boot镜像到flash之后依旧没有能够正确的启动。通过debug log可以看出来,fsbl从flash中读取出来的数据并不正确。
QSPI也就是quad-spi,我们知道通常的SPI传输线是由miso,mosi,sck,cs组成的,为了提高spi协议的传输效率,我们可以扩展这些IO的用法,让他们都工作在半双工模式下,通过发送一个命令字节的方式,进入quad spi模式,增加两根IO,并且将mosi变成SIO0,miso变成SIO1,这样一个时钟内就可以传输4bit,大大提升了传输效率。
好了以上是问题的背景,到现在为止一切看来都很好,fsbl通过quad spi模式从flash当中快速的读取数据,载入到ddr当中。但是我们查阅一下手册就会发现,quad spi模式的开启是有条件的,我们在手册的quad output read这一项下面可以看到这样一段话:
《自制zynq开发板bring up问题总结》
那我们来看看CR bit1的default value是什么
《自制zynq开发板bring up问题总结》
看到这儿问题就很明确了,默认情况下,我们的flash只支持dual或者serial模式,而fsbl中采用的是quad模式,自然没办法读取到正确的数据。解决方法自然也很简单,写个简单的程序,将这位改写成1,再运行就好了。SDK已经为我们提供了QSPI的驱动,代码如何实现就留给大家自己解决啦。

参考资料:

  1. ZYNQ fsbl阶段的调试方法
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注