FPGA在线升级 -- Multiboot

简介

本章节主要描述关于如何从Golden Image转换到Multiboot Image程序。

升级方案

Golden Image转换到Multiboot Image的方法主要又两种

1、使用ICAPE2 原语;

2、在XDC文件中加入升级约束命令;

以上两种方案都可以实现在线升级,第一种升级可控,第二种不可控下面主要针对第一种方案详细描述。

原语描述

原语顶层代码如下:

复制代码
/* 
 * file			: multiboot_ctrl.v
 * author		: 今朝无言
 * Lab			: WHU-EIS-LMSWE
 * date			: 2023-11-30
 * version		: v1.0
 * description	: ICAP 原语实现程控 multiboot(多重启动),K7需要使用 ICAPE2 原语
 * Copyright ? 2023 WHU-EIS-LMSWE, All Rights Reserved.
 */
//`default_nettype none
module multiboot_ctrl(
input	wire			clk,
input	wire			rst_n,

input	wire			multiboot_start,	//触发Multiboot, 上升沿有效
input	wire	[31:0]	multiboot_addr,		//要启动的Muliboot Image的起始地址

output	reg				busy
);

//-------------------ICAPE2原语-----------------------------
wire			ICAPE2_CLK;
wire	[31:0]	ICAPE2_O;
reg				ICAPE2_CSIB;
wire	[31:0]	ICAPE2_I;
reg				ICAPE2_RDWRB;

assign	ICAPE2_CLK	= clk;

ICAPE2 #(
     .DEVICE_ID			(32'h3636093),	// Specifies the pre-programmed Device ID value to be used for simulation purposes. K7-325T的为32'h3651093
     .ICAP_WIDTH		("X32"),		// Specifies the input and output data width.
     .SIM_CFG_FILE_NAME	("NONE")		// Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model.
)
ICAPE2_inst(
     .O					(ICAPE2_O),		// 32-bit output: Configuration data output bus
     .CLK				(ICAPE2_CLK),	// 1-bit input: Clock Input
     .CSIB				(ICAPE2_CSIB),	// 1-bit input: Active-Low ICAP Enable
     .I					(ICAPE2_I),		// 32-bit input: Configuration data input bus
     .RDWRB				(ICAPE2_RDWRB)	// 1-bit input: Read/Write Select input    1对应rd,0对应wr
);

wire	[31:0]	Dummy		= 32'hFFFFFFFF;
wire	[31:0]	Sync_Word	= 32'hAA995566;
wire	[31:0]	NOOP		= 32'h20000000;
wire	[31:0]	WR_WBSTAR	= 32'h30020001;

/*When using ICAPE2 to set the WBSTAR address, the 24 most significant address bits should be written
  to WBSTAR[23:0]. For SPI 32-bit addressing mode, WBSTAR[23:0] are sent as address bits [31:8]. The
  lower 8 bits of the address are undefined and the value could be as high as 0xFF. Any bitstream
  at the WBSTAR address should contain 256 dummy bytes before the start of the bitstream.*/
wire	[31:0]	WBSTAR		= {3'b000, 5'h0, multiboot_addr[31:8]};

wire	[31:0]	WR_CMD		= 32'h30008001;
wire	[31:0]	IPROG		= 32'h0000000F;

//ICAPE2位翻转
reg		[31:0]	wrdat;
assign	ICAPE2_I	= {wrdat[24], wrdat[25], wrdat[26], wrdat[27], wrdat[28], wrdat[29], wrdat[30], wrdat[31], 
					   wrdat[16], wrdat[17], wrdat[18], wrdat[19], wrdat[20], wrdat[21], wrdat[22], wrdat[23], 
					   wrdat[8], wrdat[9], wrdat[10], wrdat[11], wrdat[12], wrdat[13], wrdat[14], wrdat[15], 
					   wrdat[0], wrdat[1], wrdat[2], wrdat[3], wrdat[4], wrdat[5], wrdat[6], wrdat[7]};

//------------------------FSM----------------------------------
localparam	S_IDLE			= 16'h0001;
localparam	S_DUMMY			= 16'h0002;
localparam	S_SYN_WORD		= 16'h0004;
localparam	S_NOOP1			= 16'h0008;
localparam	S_WR_WBSTAR		= 16'h0010;
localparam	S_WBSTAR		= 16'h0020;
localparam	S_WR_CMD		= 16'h0040;
localparam	S_IPROG			= 16'h0080;
localparam	S_NOOP2			= 16'h0100;
localparam	S_STOP			= 16'h0200;

wire	multiboot_start_pe;
reg		multiboot_start_d0;
reg		multiboot_start_d1;

assign	multiboot_start_pe	= multiboot_start_d0 & (~multiboot_start_d1);

always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        multiboot_start_d0 <= 'd0;
        multiboot_start_d1 <= 'd0;
    end
    else begin
	   multiboot_start_d0		<= multiboot_start;
	   multiboot_start_d1		<= multiboot_start_d0;
	end
	
end

reg		[15:0]	state		= S_IDLE;
reg		[15:0]	next_state;

always @(posedge clk) begin
	if(~rst_n) begin
		state	<= S_IDLE;
	end
	else begin
		state	<= next_state;
	end
end

always @(*) begin
	case(state)
	S_IDLE: begin
		if(multiboot_start_pe) begin
			next_state	<= S_DUMMY;
		end
		else begin
			next_state	<= S_IDLE;
		end
	end
	S_DUMMY:		next_state	<= S_SYN_WORD;
	S_SYN_WORD:		next_state	<= S_NOOP1;
	S_NOOP1:		next_state	<= S_WR_WBSTAR;
	S_WR_WBSTAR:	next_state	<= S_WBSTAR;
	S_WBSTAR:		next_state	<= S_WR_CMD;
	S_WR_CMD:		next_state	<= S_IPROG;
	S_IPROG:		next_state	<= S_NOOP2;
	S_NOOP2:		next_state	<= S_STOP;
	S_STOP:			next_state	<= S_IDLE;
	default:		next_state	<= S_IDLE;
	endcase
end

always @(posedge clk) begin
	case(state)
	S_IDLE: begin
		wrdat			<= 32'd0;
		ICAPE2_CSIB		<= 1'b1;
		ICAPE2_RDWRB	<= 1'b1;
	end
	S_DUMMY: begin
		wrdat			<= Dummy;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_SYN_WORD: begin
		wrdat			<= Sync_Word;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_NOOP1: begin
		wrdat			<= NOOP;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_WR_WBSTAR: begin
		wrdat			<= WR_WBSTAR;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_WBSTAR: begin
		wrdat			<= WBSTAR;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_WR_CMD: begin
		wrdat			<= WR_CMD;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_IPROG: begin
		wrdat			<= IPROG;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_NOOP2: begin
		wrdat			<= NOOP;
		ICAPE2_CSIB		<= 1'b0;
		ICAPE2_RDWRB	<= 1'b0;
	end
	S_STOP: begin
		wrdat			<= 32'd0;
		ICAPE2_CSIB		<= 1'b1;
		ICAPE2_RDWRB	<= 1'b1;
	end
	default: begin
		wrdat			<= 32'd0;
		ICAPE2_CSIB		<= 1'b1;
		ICAPE2_RDWRB	<= 1'b1;
	end
	endcase
end

always @(*) begin
	case(state)
	S_IDLE:		busy	<= 1'b0;
	default:	busy	<= 1'b1;
	endcase
end

endmodule

以上代码参考网上编写,经过自己代码仿真信号输出如下:

在start的上升沿输出如上红色命令到ICAPE2原语内部,输入的内容介绍如下:

以上WBSTAR为翻转升级程序的起始地址,本文设置Multiboot Image的起始地址为0x0080_0000。

原语接口如下:

复制代码
ICAPE2 #(
     .DEVICE_ID			(32'h3636093),	// Specifies the pre-programmed Device ID value to be used for simulation purposes. K7-325T的为32'h3651093
     .ICAP_WIDTH		("X32"),		// Specifies the input and output data width.
     .SIM_CFG_FILE_NAME	("NONE")		// Specifies the Raw Bitstream (RBT) file to be parsed by the simulation model.
)
ICAPE2_inst(
     .O					(ICAPE2_O),		// 32-bit output: Configuration data output bus
     .CLK				(ICAPE2_CLK),	// 1-bit input: Clock Input
     .CSIB				(ICAPE2_CSIB),	// 1-bit input: Active-Low ICAP Enable
     .I					(ICAPE2_I),		// 32-bit input: Configuration data input bus
     .RDWRB				(ICAPE2_RDWRB)	// 1-bit input: Read/Write Select input    1对应rd,0对应wr
);

上文最终输入原语的数据是经过大小端重组的,官方原文解释如下:

本次设计使用的是A7 200T系列FPGA,根据官方提供的手册《ug470_7Series_Config》查询DEVICE_ID如下:

代码

以上就是原语设置内容,现使用两个LED作为工程,Golden Image工程如下:

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/11/20 16:33:43
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module updata_top(
	input SYS_CLK_clk_p,
	input SYS_CLK_clk_n,

    input updata_en,
    
	output fpga_led
    
    
);

wire test_data;
wire pll_locked;
wire sys_clk;
wire updata_clk_25m;
wire sys_rst_n;
wire updata_clk;
wire updata_clk_in;

assign sys_rst_n = pll_locked;
//wire updata_en;

//   IBUFDS #(
//      .DIFF_TERM("FALSE"),       // Differential Termination
//      .IBUF_LOW_PWR("TRUE"),     // Low power="TRUE", Highest performance="FALSE" 
//      .IOSTANDARD("DEFAULT")     // Specify the input I/O standard
//   ) IBUFDS_inst (
//      .O(updata_clk_in),  // Buffer output
//      .I(SYS_CLK_clk_p),  // Diff_p buffer input (connect directly to top-level port)
//      .IB(SYS_CLK_clk_n) // Diff_n buffer input (connect directly to top-level port)
//   );

//   BUFG BUFG_inst (
//      .O(updata_clk), // 1-bit output: Clock output.
//      .I(updata_clk_in)  // 1-bit input: Clock input.
//   );



sys_pll	sys_pll_inst(
  // Clock out ports
    .clk_out1(updata_clk),
    .clk_out2(updata_clk_25m),
  // Status and control signals
   . locked(pll_locked),
 // Clock in ports
    .clk_in1_p(SYS_CLK_clk_p),
    .clk_in1_n(SYS_CLK_clk_n)

);


fpga_led	fpga_led_inst(

    .sys_clk(updata_clk),
    .sys_rst_n('d1),
	.led_top(fpga_led)
    //.updata_en(updata_en)
);

//vio_test	vio_test_inst(
//	.clk(updata_clk),
//	.probe_out0(updata_en)

//);

multiboot_ctrl  multiboot_ctrl_inst(
	.clk				(updata_clk_25m),
	.rst_n				(sys_rst_n),

	.multiboot_start	(updata_en),
	.multiboot_addr		(32'h80000000),		//加载0x01000000处的Multiboot Image

	.busy				()
);


endmodule

multiboot_addr的地址这里写的是0x8000_0000,实际上在multiboot_ctrl内部做了8位偏移,而我使用的FLASH型号的S25FL128,采用的是24位地址。实际上跳转地址是0x0080_0000,经过仿真输出的是0x0080_0000;

约束文件如下:

复制代码
set_property BITSTREAM.CONFIG.CONFIGRATE 33 [current_design]
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]

第一条约束代表FPGA启动速度为33MHz;

第二条约束代表生成的程序经过压缩处理,本设计使用的FLASH是16MByte,不经过压缩无法放两个程序在FLASH里面。这里需要注意的是无需再放NEXT_CONFIG_ADDR、CONFIGFALLBACK等命令。

Multiboot Image的代码如下:

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/11/20 16:33:43
// Design Name: 
// Module Name: top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module updata_top(
	input SYS_CLK_clk_p,
	input SYS_CLK_clk_n,

    //input updata_clk_10m,
    
	output fpga_led
    
    
);

wire test_data;
wire pll_locked;
wire sys_clk;
//wire updata_clk_10m;
wire sys_rst_n;
wire updata_clk_25m;

wire updata_en;

assign sys_rst_n = pll_locked;


sys_pll	sys_pll_inst(
  // Clock out ports
    .clk_out1(sys_clk),
    .clk_out2(updata_clk_25m),
  // Status and control signals
   . locked(pll_locked),
 // Clock in ports
    .clk_in1_p(SYS_CLK_clk_p),
    .clk_in1_n(SYS_CLK_clk_n)

);


fpga_led	fpga_led_inst(

    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
	.led_top(fpga_led),
    .updata_en(updata_en)
);



//vio_test	vio_test_inst(
//	.clk(sys_clk),
//	.probe_out0(fpga_led)

//);	


multiboot_ctrl  multiboot_ctrl_inst(
	.clk				(updata_clk_25m),
	.rst_n				(1'b1),

	.multiboot_start	(updata_en),
	.multiboot_addr		(32'h00000000),		//加载0x00000000处的Golden Image

	.busy				()
);




endmodule

与Golden Image不同的是这里翻转地址multiboot_addr是0地址。

另外fpga_led模块主要是LED灯模块,Golden Image和Multiboot Image的灯显示频率不同以作区分。

Golden Image的LED灯代码如下:

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/10/29 15:47:28
// Design Name: 
// Module Name: fpga_led
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fpga_led(
	input sys_clk,
	input sys_rst_n,
	
	output reg updata_en,
	output reg led_top
    );

parameter led_time_num = 'd100_000_000;
parameter updata_delay_num = 'd400_000_000;
	
	
reg[31:0] led_cnt = 'd0;	
reg[31:0] updata_delay_cnt ='d0;	
	
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		led_top<= 'd0;
	end		
	else if(led_cnt >= led_time_num - 'd1)begin
		led_top <= ~led_top;
		led_cnt <= 'd0;
	end
	else begin
		led_cnt <= led_cnt + 'd1;
	end
end	
	

always @(posedge sys_clk or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		updata_en<= 'd0;
		updata_delay_cnt<= 'd0;
	end	
    else if(updata_delay_cnt >= updata_delay_num)begin
        updata_en <= 'd1;
    end
    else begin
        updata_delay_cnt <= updata_delay_cnt + 1'b1;
    end
 end  

	
	
	
endmodule

Multiboot Image的LED灯代码如下:

复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/10/29 15:47:28
// Design Name: 
// Module Name: fpga_led
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fpga_led(
	input sys_clk,
	input sys_rst_n,
	
	output reg updata_en,
	output reg led_top
    );

parameter led_time_num = 'd10_000_000;
parameter updata_delay_num = 'd400_000_000;
	
	
reg[31:0] led_cnt;	
reg[31:0] updata_delay_cnt;	
	
always @(posedge sys_clk or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		led_top<= 'd0;
	end		
	else if(led_cnt >= led_time_num - 'd1)begin
		led_top <= ~led_top;
		led_cnt <= 'd0;
	end
	else begin
		led_cnt <= led_cnt + 'd1;
	end
end	
	

always @(posedge sys_clk or negedge sys_rst_n)begin
	if(sys_rst_n == 'd0)begin
		updata_en<= 'd0;
		updata_delay_cnt<= 'd0;
	end	
    else if(updata_delay_cnt >= updata_delay_num)begin
        updata_en <= 'd1;
    end
    else begin
        updata_delay_cnt <= updata_delay_cnt + 1'b1;
    end
 end  

	
	
	
endmodule

对比可看出led_time_num参数的值不同,也就是闪烁频率不一样,两个程序各自持续4秒钟时间做跳转。

文件合成

两个工程生成的bit文件需要合成一个MCS或者BIN文件烧录到程序中,流程如下:

1、合并生成的文件类型;

2、选择FLASH型号;

3、生成的文件存储路径和名称;

4、烧录模式,选择SPIx1;

5、Golden Image程序起始地址;

6、Multiboot Image程序起始地址;

7、校验和覆盖功能,第三个根据自己习惯选择;

8、生成的脚本,该脚本可以再VIVADO直接执行。

生成的MCS文件烧录到板子里,可以看到Golden Image和Multiboot Image程序每执行4秒钟切换,两个程序通过LED灯的闪烁频率区分。

以上就是程序跳转功能,这个是远程升级的基础,后面需要FPGA通过以太网/串口等方式接收升级程序并写入到FLASH后,启动升级功能。

下一篇文章将描述如何实现在线控制FLASH擦除、写入等,完成远程升级功能。

相关推荐
北京青翼科技9 小时前
青翼基于PCIe总线架构的4路HD-SDI/3G-SDI视频图像模拟源丨图像处理
fpga开发·图像模拟源·fpga开发板·pcie板卡
涛tao讲道13 小时前
星载FPGA选型与抗辐射设计手册
fpga开发·抗单粒子翻转·涛tao悟道·涛的天道观·seu
艾芯微科技13 小时前
钰泰 ETA6973PQ3Y|QFN3×3 2A 同步降压 Buck,I2C 可配置多档输出,动态调压 PMIC
网络·单片机·嵌入式硬件·fpga开发·集成测试·51单片机
NamoAmitabha12813 小时前
lwIP 问答---deepseek
fpga开发
吉他英雄一里13 小时前
时钟IP核(MMCM PLL)
fpga开发
星夜离尘5614 小时前
FPGA实现CRC-8/SMBUS:从参数和位序核对到1041次自检
fpga开发·verilog·fpga·crc
星夜离尘5619 小时前
FPGA正交编码器非法跳变检测:把16种状态转移和采样边界测清楚
verilog·fpga·编码器
匠行科技1 天前
6U‑VPX 高密度异构处理板硬件方案实践
fpga开发·硬件工程
努力搬砖的小H1 天前
FPGA应用技巧之AXI4-FULL-uiFDMA IP仿真验证
经验分享·fpga开发·axi
hexiaoyan8271 天前
高速图像采集卡处理板卡设计原理图:10-基于TMS320C6678+XC7K325T的6U CPCI Full Camera Link图像处理平台
fpga开发·高速图像采集·图像采集卡·c6678板卡