做了三年四个项目最近才第一次需要深入的搞一下FPGA 烧写。在这里简单总结一下FPGA烧写的具体过程和玩的花样
大家常用的办法
对于大部分人来说,至少入门时会用到的烧写方式就两种:
① 通过JTAG直接将bitsteam 烧录到FPGA。 断电后信息丢失。这种方式多用于发开调试阶段,板子一直连着电脑。通过ISE 或者 Vivado (2020年开始估计还有Vitis)使用JTAG接口烧录。
② 在设计release以后,到产品上一般都是把配置文件通过IDE工具保存存在Nor Flash里。上电后自动编程FPGA。
较为进阶的一种方法
通常情况下这两种方式也就可以满足大部分需求了。开发调试直接JTAG。产品出货前,配置文件通过JTAG接口,用VIVADO或者SDK等工具烧进Flash。之后把接口封起来。产品需要更新的时候,派技术支持去,重新打开接口,插上JTAG,把新的配置文件烧入Flash。
但是这次项目是个小型手持测量设备,JTAG接口只有在设备拆散状态下通过扩展板才能使用。组装好后FPGA只能通过Flash来编程。由于是个精密仪器,每次拆开再组装,整个设备都需要重新校准,非常费事费力。组装后更新Flash里面的配置文件只能用别的办法了。这种情况下常用的方法是通过一个和外界有通信能力的微控制器将image发送给FPGA, 再由FPGA写入Flash。
这种remote update Xilinx提供了一种解决方案,相对应的Application Note 是 :
QuickBoot Method for FPGA DesignRemote Update (文档号码XAPP1081)
采用这种方案的前提是理解FPGA通过Flash配置的细节,所以以7系FPGA为例先需要看一下这个文档:
7 Series FPGAsConfiguration (UG470) 主要是看第五章:Chapter 5 Configuration Details
Xilinx 远程烧录FPGA方法
远程烧录一般是为了设备出厂以后还需对FPGA进行更新或者升级。为了避免在烧录过程中新的配置文件损坏,导致FPGA不能正常启动。通常采取的是双保险策略,有个gold bitstream,是出厂是写入Flash的,是测试过绝对可以启动FPGA的,还有一个是update bistream,出厂时就是一个gold bitstream的copy,FPGA每次启动都是默认写读取这个update bitstream。之后的更新也就是去重写这个 update bitstream, 一旦在更新过程出了问题,比如突然断电。update bistream损害或者残缺,FPGA在尝试从update bitstream启动失败后就会去读取gold bitstream。这种方法保证了一个相对安全的update方法,所以也是一种非常经典的方法。
去掉废话来概括这种方法
每一个bitstream都长这样:
FPGA会先去找synchro word (7系列的spi接口的话就是0xAA995566)找到以后读取首地址,然后跳到首地址,开始读取所有的配置数据。
此文介绍的这种双保险策略就是在Flash中存入两个bitstream。但是精髓所在是这两个Bitstream在内存中怎么放。
如下图所示,update的bitstream会被拆成两段,synchron word和首地址会被存在goldbitstream前面,然后其他部分存在goldstream之后。而且update bitsteam尾部还会人为加入一个CRC。
这种鬼畜结构的目的
这种结构可以提供一种非常安全可靠的update模式。为什么会安全可靠。先来说一下这种结构下的update流程:
当我们想要update bistream的时候:
① 首先 update synchro word和首地址所在的sector(Flash里可以擦除的最小单元)会被擦除。
② 然后开始在update所在的地方擦除所有内容,写入新的bitstream。包括CRC。(这个CRC是生成bitstream的时候加入的。具体操作看下一章)。
③ 当写入结束后整个新写入的内容会被读出来计算CRC,然后和嵌入的CRC来做比较。当CRC一致时,说明在传输和写入过程没有出现问题。新写入的配置内容完整,有效。这时update的synchro word和首地址才会写入最开始被擦除sector。
这样一来,如果CRC不一致,说明这是个bad update,新写入的配置内容不可用。那么被擦除的synchro word 和首地址不会被写入。第一个sector是空的。当FPGA上电后,它是在这个sector里找不的update image的同步字和首地址的,继续读下去会读到属于goldbitstream的同步字和首地址。
如下图所示:
实际操作步骤和文档中的坑
首先好消息是,上述的这些Flash擦除,写入,各种地址,sector,page等等Xilinx已经写好了VHDL的模块。可以直接拿来用。自己需要实现的是remote端往FPGA的数据传输。具体如下图:
具体实现步骤如下:
① 实现remote端的update程序,该程序需要读取update image 然后通过某种接口和通信协议将image发送给FPGA。这一步该需求和情况自由发挥。例如物联网的可以用蓝牙或者WIFI。
② 实现FPGA端的数据接收。该模块将数据写入Xilinx提供的FlashProgrammer
③ 下载XAPP1081文档中的例子 KC705 Board Demonstrations, page 33。例子中两个VHDL模块按下图实例化。注意 这两个模块必须共用一个时钟,而且这个时钟就是SPI的时钟,所以注意不要太快。一般20Mhz一下。
④ 集成前三条实现的模块,调试。可以实现将数据从remote端发送给FPGA,经过SPiFlashProgrammer写入Flash。
⑤ 把bitstream格式转换成mcs格式。将gold bistream。bit格式转换成mcs格式。VIVADO下使用tcl 命令write_cgfmen -format mcs -interface spix1。一定要加 -interface spix1,不然所有的bits都会被swap!
⑥ 通过Xilinx例子中提供的Perl Script生成 gold init image。script的输入就是刚才转换的mcs格式的goldbitstream.mcs。输出之一是gold init image这个image就是图4中描述的那种鬼畜布局的双bitstream,只不过两个bitstream是一样的。update bitstream是gold的copy。
⑦ 将gold inital.mcs通过VIVADO 或者PROMgen用JTAG直接烧入Flash
⑧ 同样的方式用Perl Script生成 update image。 输入是xxx.mcs。输出之一是xxx_update.mcs。这个就是上文所属的加了CRC的update image。生成过程中perl script会给出Flash的首地址和结束地址。将SpiFlashProgrammer中的首尾地址改成这两个地址。注意:因为首尾地址是写在VHDL里的,也就是说Image的大小是固定的。为了防止在未来,update image变大。可以预留一部分出来。例如:目前的大小是3.3MB。我们预留0.7MB给未来可能出现的更新。那么我们需要生成的image需要4MB大。这是要给perl script一个附加的agrument: -imagesize 32
⑨ 将xxx_update.mcs转换成.hex文件。网上有不少工具可以。实在不行谷歌一下mcs格式,自己写个script转换一下。
⑩ FPGA上电,取消SpiFlashProgrammer的reset。 remote的软件读取xxx_update.hex,传输给FPGA,经由SpiFlashProgrammer写入Flash。
⑪ 写入后,查看Programmer的Status. Done输出1,所有Error Port输出是0的话,说明update成功!
⑫ FPGA重新上电,检查FPGA内是否是由新的image配置的
责任编辑:gt
评论
查看更多