本文主要是介绍icap对flash的在线升级,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 一、icap原语介绍(针对 S6 系列的 ICap),之后可以拓展到A7、K7当中去
- 二、程序1设计
- 2.1信号结构框图
- 2.2 icap_delay设计
- 2.3 icap_ctrl设计(可以当模板使用,之后修改关键参数即可)
- 三、程序2设计
- 四、下板操作
要求:设计区域 1 的程序,上电后自动加载此程序,此时开始计时如果 20 秒内没有检测到串口发送的擦除指令,那么我们启动 icap 跳转,跳转到区域 2 程序中。如果希望再次升级的话必须重新给板卡上电使得程序回到区域 1 中,并在20秒计时内通过fpga_update软件将新的应用程序更新到flash中,实现flash的在线升级。
设计思想:我们制作两个程序,第一个区域执行程序 1(包含flash_ctrl和icap)能实现flash控制和程序跳转功能,这个区域的程序是固定的不会被修改。第二个区域的程序 2 是我们用户设计的功能程序或者说产品程序(有更新需求的程序)。
一、icap原语介绍(针对 S6 系列的 ICap),之后可以拓展到A7、K7当中去
icap原语查找方式(ise软件):
- language template
- 在弹出的对话框中找到Internal Configuration Access Port。
- icap 实例化原语
信号解释:
1、DEVICE_ID:不同芯片的DEVICE_ID不相同,在使用该原语时,要查找对应芯片的ID ;
2、SIM_CFG_FILE_NAME:仿真使用,默认即可。
3、BUSY:原语对应的忙信号
4、O:配置数据的输出
5、CE:原语的使能信号,低电平有效
6、CLK:原语的时钟信号
7、I:原语配置数据的输入信号,位宽为16bit需要按照步骤传输以下数据,
(其中 opcode 指的是器件 read 的命令(基于 spi 的 flash read 命令为 03h)
8、WRITE:读写原语的使能信号,低电平有效
需要注意的是:在我们传输这些配置数据时,需要将这些配置数据按照 byte 为单位,进行高低位互换,如下:
二、程序1设计
2.1信号结构框图
其中flash_ctrl模块之前已经实现:
这里介绍一下icap_delay 模块和 icap_ctrl模块(重点)
2.2 icap_delay设计
module icap_delay(input wire sclk,input wire rst,output reg icap_flag,input wire rx_flag,input wire [7:0] rx_data,output wire led);parameter TIMER_END = 1000000000-1;
reg [31:0] time_cnt;
reg stop_flag;assign led = 1;// 接收到擦除指令的标志
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginstop_flag <= 1'b0;endelse if (rx_flag== 1'b1 && rx_data == 8'hee) beginstop_flag <= 1'b1;end
end// 接收到擦除指令之前保持计数,接收到指令后停止计数(不是清0)
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) begintime_cnt <= 'd0;endelse if (stop_flag == 1'b1) begintime_cnt <= time_cnt;endelse begintime_cnt <= time_cnt + 1'b1;end
end// icap执行跳转的标志,当计数超过20s后,执行icap完成跳转。
always @(posedge sclk or posedge rst) beginif (rst == 1'b1) beginicap_flag <= 1'b0;endelse if (time_cnt >= TIMER_END) beginicap_flag <= 1'b1;endelse beginicap_flag <= 1'b0;end
end
endmodule
2.3 icap_ctrl设计(可以当模板使用,之后修改关键参数即可)
上面介绍了icap执行的关键就是向icap中顺序输入数据,且数据需要按照字节进行高低位互换。
顺序执行采用状态机跳转的方式即可。
module icap_ctrl(
input wire sclk ,
input wire rst_n ,
input wire pi_flag
);wire clk ;
reg c_en ;
reg wr_en ;
reg[15:0] i_data ;
wire[15:0] i_crop ;reg[15:0] state ;//使用时每个byte高低位需要互换
parameter DUM_WORD = 16'hFFFF;//空闲字
parameter SYNC_WORD1 = 16'hAA99;//同步字1
parameter SYNC_WORD2 = 16'h5566;//同步字2
parameter GEN_WORD1 = 16'h3261;//向General1写1个type1的字数据
parameter LOW_ADDR = 16'h0000;//低16位起始地址 -----------------根据flash实际划分的地址进行修改
parameter GEN_WORD2 = 16'h3281;//向General2写1个type1的字数据
parameter HIG_ADDR = 16'h0310;//读操作码及高8位地址,操作码为0x03 read 0x0b fast Ready -----------------根据flash实际划分的地址进行修改
parameter GEN_WORD3 = 16'h32A1;//向General3写1个type1的字数据
parameter LOW_ADDR_BACK = 16'h0000;//fallback起始低16位地址 -----------------根据flash实际划分的地址进行修改
parameter GEN_WORD4 = 16'h32C1;//向General4写1个type1的字数据
parameter HIG_ADDR_BACK = 16'h0300;//读操作码及fallback高8位地址,操作码为0x03 -----------------根据flash实际划分的地址进行修改
parameter GEN_CMD_WORD = 16'h30A1;//向CMD写1个type1的字数据
parameter IPROG_CMD = 16'h000E;//IPROG命令
parameter NOP_CMD = 16'h2000;//空命令//状态
parameter S_DUM_WORD = 16'h0001;//空闲字
parameter S_SYNC_WORD1 = 16'h0002;//同步字1
parameter S_SYNC_WORD2 = 16'h0004;//同步字2
parameter S_GEN_WORD1 = 16'h0008;//向General1写1个type1的字数据
parameter S_LOW_ADDR = 16'h0010;//低16位起始地址
parameter S_GEN_WORD2 = 16'h0020;//向General2写1个type1的字数据
parameter S_HIG_ADDR = 16'h0040;//操作码及高8位地址,操作码为0x03 普通读 0x0b FAST read
parameter S_GEN_WORD3 = 16'h0080;//向General3写1个type1的字数据
parameter S_LOW_ADDR_BACK = 16'h0100;//fallback起始低16位地址
parameter S_GEN_WORD4 = 16'h0200;//向General4写1个type1的字数据
parameter S_HIG_ADDR_BACK = 16'h0400;//操作码及fallback高8位地址
parameter S_GEN_CMD_WORD = 16'h0800;//向CMD写1个type1的字数据
parameter S_IPROG_CMD = 16'h1000;//IPROG命令
parameter S_NOP_CMD1 = 16'h2000;//空命令
parameter S_NOP_CMD2 = 16'h4000;//空命令
parameter S_NOP_CMD3 = 16'h8000;//空命令always@(posedge sclk or negedge rst_n)if(rst_n==1'b0) state <= S_DUM_WORD;else case(state)S_DUM_WORD:if(pi_flag==1'b1)state <= S_SYNC_WORD1;S_SYNC_WORD1:state <= S_SYNC_WORD2;S_SYNC_WORD2:state <= S_GEN_WORD1;S_GEN_WORD1:state <= S_LOW_ADDR;S_LOW_ADDR:state <= S_GEN_WORD2;S_GEN_WORD2:state <= S_HIG_ADDR;S_HIG_ADDR:state <= S_GEN_WORD3;S_GEN_WORD3:state <= S_LOW_ADDR_BACK;S_LOW_ADDR_BACK:state <= S_GEN_WORD4;S_GEN_WORD4:state <= S_HIG_ADDR_BACK;S_HIG_ADDR_BACK:state <= S_GEN_CMD_WORD;S_GEN_CMD_WORD:state <= S_IPROG_CMD;S_IPROG_CMD:state <= S_NOP_CMD1;S_NOP_CMD1:state <= S_NOP_CMD2;S_NOP_CMD2:state <= S_NOP_CMD3;S_NOP_CMD3:state <= S_DUM_WORD;default:state <= S_DUM_WORD;endcase//先拉低写使能,再拉低时钟使能
always@(posedge sclk or negedge rst_n)if(rst_n==1'b0) c_en <= 1'b1;else if(state==S_SYNC_WORD2)c_en <= 1'b0;else if(state==S_DUM_WORD)c_en <= 1'b1;//先拉低写使能,再拉低时钟使能
always@(posedge sclk or negedge rst_n)if(rst_n==1'b0) wr_en <= 1'b1;else if(state==S_SYNC_WORD1)wr_en <= 1'b0;else if(state==S_DUM_WORD)wr_en <= 1'b1;//发送控制字
always@(posedge sclk or negedge rst_n)if(rst_n==1'b0) i_data <= DUM_WORD;else case(state)S_DUM_WORD:i_data <= DUM_WORD;S_SYNC_WORD1:i_data <= SYNC_WORD1;S_SYNC_WORD2:i_data <= SYNC_WORD2; S_GEN_WORD1: i_data <= GEN_WORD1; S_LOW_ADDR: i_data <= LOW_ADDR; S_GEN_WORD2: i_data <= GEN_WORD2; S_HIG_ADDR: i_data <= HIG_ADDR; S_GEN_WORD3: i_data <= GEN_WORD3; S_LOW_ADDR_BACK: i_data <= LOW_ADDR_BACK; S_GEN_WORD4: i_data <= GEN_WORD4; S_HIG_ADDR_BACK: i_data <= HIG_ADDR_BACK; S_GEN_CMD_WORD: i_data <= GEN_CMD_WORD; S_IPROG_CMD: i_data <= IPROG_CMD; S_NOP_CMD1: i_data <= NOP_CMD; S_NOP_CMD2: i_data <= NOP_CMD; S_NOP_CMD3: i_data <= NOP_CMD; default:i_data <= NOP_CMD;endcase//对输入的数据按字节为单位进行高低位互换
assign i_crop = {i_data[8],i_data[9],i_data[10],i_data[11],i_data[12],i_data[13],i_data[14],i_data[15],i_data[0],i_data[1],i_data[2],i_data[3],i_data[4],i_data[5],i_data[6],i_data[7]};//实例化icap原语
ICAP_SPARTAN6 #(
.DEVICE_ID('h4001093), //不同型号的芯片,ID号不同 x9 ID='h4001093
.SIM_CFG_FILE_NAME("NONE") // Specifies the Raw Bitstream (RBT) file to be parsed by the simulationendmodule// model
)
ICAP_SPARTAN6_inst (
.BUSY(BUSY), // 1-bit output: Busy/Ready output
.O(O), // 16-bit output: Configuartion data output bus
.CE(c_en), // 1-bit input: Active-Low ICAP Enable input
.CLK(sclk), // 1-bit input: Clock input
.I(i_crop), // 16-bit input: Configuration data input bus
.WRITE(wr_en) // 1-bit input: Read/Write control input
); endmodule
三、程序2设计
这里直接使用之前设计的一个呼吸灯
四、下板操作
关于操作方面,首先要有一个意识:fpga首先要有flash控制的功能(这是前提!!),然后才能执行对flash进行读写等操作)。
这里介绍一下老师提供的一个小软件,fpga_update,界面如下,可以实现flash的写操作。
这篇关于icap对flash的在线升级的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!