原理
关于Multiboot的原理参考《Xilinx 7系列FPGA Multiboot介绍-远程更新》,基本原理都在此文写的很清楚,本文主要从实例出发演示Multiboot。
补充
FPGA SPI闪存配置接口
7系列FPGA和具有x1数据宽度的SPI闪存之间的基本连接。读取和地址指令通过主输出-从输入(MOSI)引脚从FPGA发送到SPI闪存。数据通过主输入从输出(MISO)引脚从SPI闪存返回。SCK是时钟引脚,SS是低电平从选择引脚。
参考:UG470
Vivado工具流程(Multiboot大致流程)
为Multiboot程序准备bit流
本节概述了为多引导应用程序创建和更新比特流所需的比特流属性。对于未指定的位流选项,请使用默认设置。
表1概述了用于生成和更新具有每个属性描述的位流的基本多引导位流属性。有关这些属性的详细说明,请参阅Vivado Design Suite用户指南:编程和调试(UG908)。
具体含义如下:
启用在配置尝试失败时加载默认位流
使用下一个配置映像的启动地址设置热启动启动启动地址(WBSTAR[28:0]位)寄存器
指定启用FPGA位流文件压缩
在Vivado中打开黄金设计实现(Golden)的约束文件(.xdc)。将以下内容复制粘贴到约束文件中,然后保存对.xdc文件所做的更改:
set_propertyBITSTREAM.CONFIG.CONFIGFALLBACKENABLE[current_design]
set_propertyBITSTREAM.CONFIG.NEXT_CONFIG_ADDR0x0400000[current_design]
set_propertyBITSTREAM.GENERAL.COMPRESSTRUE[current_design]
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH1[current_design]
上述不理解没关系,后续实例会有使用教程。
接下来,可以在更新设计(将要更新的文件)中打开约束文件(.xdc),并将以下比特流属性添加到约束文件中,然后保存:
set_propertyBITSTREAM.CONFIG.CONFIGFALLBACKENABLE[current_design]
set_propertyBITSTREAM.GENERAL.COMPRESSTRUE[current_design]
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH1[current_design]
注:默认情况下,SPI_BUS为x1,如果未使用默认x1模式,请确保设置此属性。
生成SPI闪存编程文件
具体查看《【Vivado那些事】Vivado两种生成、固化烧录文件》。
使用write_cfgmem Tcl命令创建闪存编程文件(.mcs)。
write_cfgmem获取FPGA位流(.bit)并生成可用于编程SPI闪存的闪存文件(.mcs)。
例如,生成包含两个FPGA位流(.bit文件)的闪存编程文件(.mcs)文件,如下所示:
write_cfgmem-formatmcs-interfaceSPIX1-size16-loadbit"up0/golden.bitup
0x0400000/update.bit" /filename.mcs
注:地址值0x0400000是参考设计中使用的示例。应使用黄金图像(更新图像的起始地址)中设置的Addr A1值(见表1)。
请参阅Vivado Design Suite用户指南:编程和调试(UG908或使用Vivado中的-help命令,以了解每个write_cfgmem命令选项的详细说明:
write_cfgmem -help
硬件验证
硬件验证其实很简单,我们分别建立两个工程,两个工程都是流水灯程序,分别从左到右和从右到左流水灯,这样可以很清楚知道FPGA运行了哪个程序。接下来破坏golden程序,按照上述制作MCS文件后运行,看下运行哪个程序。
建立工程
详细的Verilog文件如下:
golden工程
moduleTop_MultiBoot_Module_A(
inputCLK,
outputreg[3:0]LED_Out
);
////////////////////////////////////////////
wireRESET;
assignRESET=1'b1;
////////////////////////////////////////////
//
//首先定义一个时间计数寄存器counter,每当达到预定的100ms时,
//计数寄存器就清零,否则的话寄存器就加1??//然后计算计数器计数的最大值。时钟频率为12MHZ??//也就是周期为1/12M ??3ns,要计数的最大值为T100MS= 100ms/83ns-1 = 120_4818??//
reg[31:0]counter;
parameterT100MS=25'd920_4818;
always@(posedgeCLK)
if(counter==T100MS)
counter<=25'd0;
else
counter<=counter+1'b1;
////////////////////////////////////////////
always@(posedgeCLKornegedgeRESET)
if(!RESET)
LED_Out<=4'b0001;//初值,最低位led[0]灯亮
elseif(counter==T100MS)
begin
if(LED_Out==4'b0000)//当溢出最高位时
LED_Out<=4'b0001;//回到复位时的状态
else
LED_Out<=LED_Out<<1; //循环左移一位
end
endmodule // Run_LED
update工程
moduleTop_MultiBoot_Module_B(
inputCLK,
outputreg[3:0]LED_Out
);
////////////////////////////////////////////
wireRESET;
assignRESET=1'b1;
////////////////////////////////////////////
//
//首先定义一个时间计数寄存器counter,每当达到预定的100ms时,
//计数寄存器就清零,否则的话寄存器就加1��//然后计算计数器计数的最大值。时钟频率为12MHZ��//也就是周期为1/12M ��3ns,要计数的最大值为T100MS= 100ms/83ns-1 = 120_4818��//
reg[31:0]counter;
parameterT100MS=25'd920_4818;
always@(posedgeCLK)
if(counter==T100MS)
counter<=25'd0;
else
counter<=counter+1'b1;
////////////////////////////////////////////
always@(posedgeCLKornegedgeRESET)
if(!RESET)
LED_Out<=4'b0001;//初值,最低位led[0]灯亮
elseif(counter==T100MS)
begin
if(LED_Out==4'b0000)//当溢出最高位时
LED_Out<=4'b0001;//回到复位时的状态
else
LED_Out<=LED_Out<<1; //循环左移一位
end
endmodule // Run_LED
两个工程基本一样,流水的操作是在约束里实现的。
golden工程约束
#CLOCKS
#SYSCLK
set_propertyIOSTANDARDLVCMOS18[get_portsCLK]
set_propertyPACKAGE_PIND27[get_portsCLK]
#GPIOLEDs
#set_propertyPACKAGE_PINAB8[get_portsLED_REVXX[7]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[7]]
#set_propertyPACKAGE_PINAA8[get_portsLED_REVXX[6]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[6]]
#set_propertyPACKAGE_PINAC9[get_portsLED_REVXX[5]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[5]]
#set_propertyPACKAGE_PINAB9[get_portsLED_REVXX[4]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[4]]
#set_propertyPACKAGE_PINAE26[get_portsLED_Out[3]]
#set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[3]]
set_propertyPACKAGE_PINT21[get_portsLED_Out[2]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[2]]
set_propertyPACKAGE_PINT20[get_portsLED_Out[1]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[1]]
set_propertyPACKAGE_PINR24[get_portsLED_Out[0]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[0]]
#CFGBVSandSPImodeproperties
set_propertyCFGBVSVCCO[current_design]
set_propertyCONFIG_VOLTAGE2.5[current_design]
set_propertyCONFIG_MODESPIX1[current_design]
#Compressthebitstreamtofiton128MQSPIoftheK7
set_propertyBITSTREAM.GENERAL.COMPRESSTRUE[current_design]
#BITSTREAMPROPERTIESREQUIREDFORGOLDENIMAGE:
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH1[current_design]
set_propertyBITSTREAM.CONFIG.CONFIGFALLBACKENABLE[current_design]
set_propertyBITSTREAM.CONFIG.NEXT_CONFIG_ADDR0x0400000[current_design]
#(IftheSPIflashisequaltoorgreaterthan256Mb,uncommenttheconstraintbelow):
#set_propertyBITSTREAM.CONFIG.SPI_32BIT_ADDRYES[current_design]
这里解释一下,前面物理约束不重要,因为“穷”,我的板子只有3颗LED,所以只进行了三个物理约束。
CFGBVS and SPI mode properties及Compress the bitstream to fit on 128M QSPI of the K7、BITSTREAM PROPERTIES REQUIRED FOR GOLDEN IMAGE是重点约束的对象,具体解释看下表一。
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH1[current_design]
set_propertyBITSTREAM.CONFIG.CONFIGFALLBACKENABLE[current_design]
set_propertyBITSTREAM.CONFIG.NEXT_CONFIG_ADDR0x0400000[current_design]
这三个约束是和UPDATE工程有关,一个是SPI的BUSWIDTH,一个是否开启CONFIGFALLBACK,最后一个是地址,这是非常重要的。
接下来是update工程的约束文件
#CLOCKS
#SYSCLK
set_propertyIOSTANDARDLVCMOS18[get_portsCLK]
set_propertyPACKAGE_PIND27[get_portsCLK]
#GPIOLEDs
#set_propertyPACKAGE_PINAB8[get_portsLED_REVXX[7]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[7]]
#set_propertyPACKAGE_PINAA8[get_portsLED_REVXX[6]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[6]]
#set_propertyPACKAGE_PINAC9[get_portsLED_REVXX[5]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[5]]
#set_propertyPACKAGE_PINAB9[get_portsLED_REVXX[4]]
#set_propertyIOSTANDARDLVCMOS15[get_portsLED_REVXX[4]]
#set_propertyPACKAGE_PINAE26[get_portsLED_Out[3]]
#set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[3]]
set_propertyPACKAGE_PINR24[get_portsLED_Out[2]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[2]]
set_propertyPACKAGE_PINT20[get_portsLED_Out[1]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[1]]
set_propertyPACKAGE_PINT21[get_portsLED_Out[0]]
set_propertyIOSTANDARDLVCMOS33[get_portsLED_Out[0]]
#CFGBVSandSPImodeproperties
set_propertyCFGBVSVCCO[current_design]
set_propertyCONFIG_VOLTAGE2.5[current_design]
set_propertyCONFIG_MODESPIX1[current_design]
#Compressthebitstream
set_propertyBITSTREAM.GENERAL.COMPRESSTRUE[current_design]
#BITSTREAMPROPERTIESREQUIREDFORGOLDENIMAGE:
set_propertyBITSTREAM.CONFIG.SPI_BUSWIDTH1[current_design]
set_propertyBITSTREAM.CONFIG.CONFIGFALLBACKENABLE[current_design]
#(IftheSPIflashisequaltoorgreaterthan256Mb,uncommenttheconstraintbelow):
#set_propertyBITSTREAM.CONFIG.SPI_32BIT_ADDRYES[current_design]
物理约束同样不重要,重要的还是下面的和multiboot相关的约束,具体解释和上面一样。
生成Bit流并运行
上述两个工程分别生成Bit流并运行,查看两个流水灯是否是两个不同方向的。
合成MCS文件并运行
将两个BIT流文件合成一个MCS文件,命令如下:
write_cfgmem-formatmcs-interfaceSPIX1-size16-loadbit"up0/golden.bitup
0x0400000/update.bit" /filename.mcs
两个bit流文件位置;
filename: mcs文件名称。
将上诉mcs文件下载到FPGA开发板上,可以看见update工程文件运行。
破坏Golden文件
回退到Golden可以通过不同的方式触发。主要有以下几种方式:
- ID Code错误
- CRC错误
- Watchdog超时
- BPI地址越界
有关更多信息,请参阅UG470中的重新配置和多引导章节。
本应用说明演示了由CRC错误触发的回退。可以手动损坏更新位流以导致CRC错误。在RESET CRC命令和CRC命令之间有许多可以翻转位的位置。下图显示了一个示例。
- 1.使用十六进制编辑器(HxD Hex Editor)中打开更新(update)比特流(.bit),在比特流中间翻转一些数据字节,例如从00到11,如图所示。
为了保证破坏彻底,可以多更改几处。
- 保存损坏的更新位流,并使用此损坏的位流生成新的闪存编程文件(.mcs)。
write_cfgmem-formatmcs-interfaceSPIX1-size16-loadbit"up0/golden.bitup
0x0400000/update.bit" /filename.mcs
- 3.重新下载文件
观察是Golden还是update文件运行,同理可以将上诉命令修改,将golden和update更换一下mcs文件位置,对比测试,上诉两个情况本人都有亲自测试过,都是golden文件运行,证明multiboot已经生效。
-
FPGA
+关注
关注
1624文章
21608浏览量
601075 -
led
+关注
关注
240文章
23039浏览量
656628 -
闪存编程
+关注
关注
0文章
9浏览量
6652
原文标题:Xilinx Multiboot实例演示
文章出处:【微信号:Open_FPGA,微信公众号:OpenFPGA】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论