首先关于Cyclone IV系列的配置和远程系统更新需要阅读《Configuration and Remote System Upgrades in Cyclone IV Devices》这个手册,该手册在官网上可以找到。阅读这个手册可以了解到有关Cyclone IV的配置方式,如并行方式PS方式,串行方式AS这两种,以及主被动配置。还有就是配置的整个流程。这里笔者研究的是AS方式的主动配置,即通PC把配置文件通过串口发送到FPGA上然后FPGA通过一段小逻辑将接收到的文件写入到EPCS存储器里头,这里笔者用的是EPCS16的Flash存储器。烧写的文件格式是rpd(Raw Programming Data File)。

rpd文件的生成

首先在Quartus软件下,笔者用的是Quartus16.1版本,点击Assignments->Device->Device and Pin Optins->Configuration,勾选Use configuration device,然后选择使用的存储器件,这里笔者使用的是EPCS16所以选择EPCS16,如下图所示,然后点击ok,关闭对话框。

再次点击全编译,会自动生成.pof,这个.pof就是要生成.rpd文件的中间文件。当编译生成.pof文件后点击File->Convert Programming Files...,出现如下对话框,并按照如下对话框设置。

需要注意的是这里生成的.rpd文件是小端模式的,而FPGA里头需要的是大端的形式,解决的办法有两种,第1种:点击上述对话框中的Options/Boot info...按钮选择Big endian。第2种:在往Flash芯片里头写入的时候将高低位互换,笔者在这里用的就是第2中方法。

rpd文件的传输

这里笔者用的是matlab编写的一段串口发送小程序,仿照ymodem协议进行稳定可靠的传输。代码如下:

clc;
clear all;
close all;%%
file_name = 'E:\JIYI_Work_Space\Projects\FPGA_Remote_Update\JIYI_FPGA_RSU_20200921\output_files\JIYI_FPGA_RSU_Little.rpd';
file_id=fopen(file_name,'r');      %以读的方式打开串口原始数据
fseek(file_id,0,'eof');            %将位置索引号指向文件最后
read_total_bytes = double(ftell(file_id)); %获取将要读取的总字节数   127302624
fprintf('读取总字节数:%dBytes,%fKB,%fMB\n',read_total_bytes,read_total_bytes/1024,read_total_bytes/1024/1024);
fseek(file_id,0,'bof');                                  %将位置索引号指向文件开始
binary_data = uint8(fread(file_id,read_total_bytes,'uint8'));
figure;
plot(binary_data);%%
scom1 = serial('com3');%%%%%%%%%%%%%%%%open com5
scom1.Terminator = 'CR';
scom1.BaudRate = 115200;
scom1.InputBufferSize = 1024*1024;
scom1.OutputBufferSize = 1024*1024;
scom1.Timeout = 60;  %等待时延 单位:秒
scom1.RequestToSend ='on';fopen(scom1);   %打开串口
%%
start_str = [36 70 80 71 65 66];   % $FPGAB  24 46 50 47 41 42
while 1fwrite(scom1, start_str, 'uint8');   %发送开始传输字符fprintf('Flash整片擦除开始...\n');ack = fread(scom1,1,'uint8');   %0x55  85if(ack(1) == 85)  %收到正确回复fprintf('收到正确开始回复,Flash整片擦除完毕:ack = %s\n',ack(1));break;elsefprintf('收到错误开始回复:ack = %s\n',ack(1));  end
end%%
head = uint8(250);  %0xFA
transmit_over = uint8(170);  %0xAA
frame_num_bytes = 2;
section_bytes = 128;  % 1024*1024/128
frame_bytes = 1+1+frame_num_bytes+section_bytes+1;
frame_str = uint8(zeros(1,frame_bytes));
section_num = read_total_bytes/section_bytes;
i = 1;
error_flag = 0;
bar = waitbar(0,'读取数据中...');    % waitbar显示进度条
while i <= section_numtemp = binary_data(((i-1)*section_bytes+1):(i*section_bytes));frame_str(1) = head;                       %帧头 0xFAframe_str(2) = uint8(section_bytes);       %要传输的字节数量frame_str(3) = uint8(mod(i,256));          %帧编号的低8位frame_str(4) = uint8(fix(i/256));          %帧编号的高8位frame_str(5:(section_bytes+4)) = temp;     %填充数据sum8 = sum(frame_str(1:end-1));            %得到校验和frame_str(end) = uint8(mod(sum8,256));fwrite(scom1, frame_str, 'uint8');    %发送生成的数据ack = fread(scom1,1,'uint8');   %0x55  85if(ack(1) == 85)  %收到正确回复str=['loading...',num2str(i/section_num*100),'%'];     waitbar(i/section_num,bar,str)                       % 更新进度条bar,配合bar使用i = i + 1;elseif(ack(1) == 102)   %  0x66 收到的回复不正确时重复发送该帧数据fprintf('错误帧:i = %d\n',i);else fprintf('过程出错,已退出\n');error_flag = 1;   %标志出错break;end
end
if error_flag == 0   %前面传输没有错误时
%数据结束while 1fwrite(scom1, transmit_over, 'uint8');   %发送结束字符 0xAAack = fread(scom1,1,'uint8');   %0x55  85if(ack(1) == 85)  %收到正确回复fprintf('收到正确结束回复,Flash烧写完成:ack = %s\n',ack(1));break;elsefprintf('收到错误结束回复:ack = %s\n',ack(1));  endend
endclose(bar);
fclose(scom1);   %关闭串口

FPGA接收与烧写逻辑

这里笔者用的是官方自带的ASMI ip核,用它就可以很轻松的将接收到的数据写入到Flash芯片里面。关于它的使用可以参考官方的手册《ASMI Parallel Intel® FPGA IP Core User Guide》。整个更新过程如下所述,1:接收到开始烧写命令后,FPGA触发对Flash芯片的整片擦除操作(写之前一定要先擦除,否则结果会不正确)。2:擦除完成后向PC回复擦除完成,PC接着开始传输正式的数据,并接受来自FPGA的校验结果,如果校验结果正确了,才会开始传输下一帧数据,如果校验结果不对,则重新传输该帧数据,直到结果正确为止,一直到最后一帧数据传输完成。3:最后一帧数据传输完成后,PC发送传输完成指令告诉FPGA,FPFA接收到回复PC确认烧写完成,退出烧写程序。实现的主要FPGA逻辑代码如下:

module FPGA_Remote_Update
(input wire MAIN_CLK,         //全局50MHz时钟    input wire nRST,              //全局复位信号input wire UART_RX,output wire UART_TX
);parameter ACK_CODE = 8'h55;
parameter ERROR_CODE = 8'h66;
parameter FRAME_HEAD = 8'hFA;    //帧头
parameter TX_OVER = 8'hAA;       //传输结束标志reg [3:0] state/*synthesis preserve*/;
reg [1:0] flash_clk_sam;
reg [1:0] busy_sam;
reg [7:0] bytes_max;
reg [7:0] bytes_cnt;
reg [7:0] check_sum;
reg check_sum_right;
reg data_get_valid;
always @(posedge MAIN_CLK)
beginif(~nRST)  begin state <= 0;flash_clk_sam <= 0;busy_sam <= 0;check_sum <= 0;bytes_max <= 0;bytes_cnt <= 0;data_get_valid <= 0;check_sum_right <= 0;end else begin flash_clk_sam <= {flash_clk_sam[0], CLK_12_5M};  //对Flash时钟采样busy_sam <= {busy_sam[0], busy};                 //对Flash控制模块的busy信号采样case(state)0: begin if(boot_start)              //等待串口的 boot_start 发起begin state <= 1; end    //3wren <= 0; bulk_erase <= 0;check_sum <= 0;bytes_cnt <= 0;bytes_max <= 0;data_get_valid <= 0;check_sum_right <= 0;uart_tx_byte <= 0; uart_tx_valid <= 0;end 1: begin if(flash_clk_sam == 2'b01)          //发起芯片整片擦除信号,状态转移 flash_clk_sam[0], CLK_12_5M} == 2'b11begin wren <= 1; bulk_erase <= 1; state <= 2;end end 2:beginif({flash_clk_sam[0], CLK_12_5M} == 2'b11)          //停止发起芯片整片擦除信号,状态转移begin wren <= 0; bulk_erase <= 0; state <= 3;endend 3:beginif(busy_sam == 2'b10)   //等待擦除完毕,并回复上位机已准备好,并状态转移begin uart_tx_byte <= ACK_CODE; uart_tx_valid <= 1; state <= 4; end end 4:   //接收除帧头部分的数据beginuart_tx_byte <= 0; uart_tx_valid <= 0;if(uart_rx_valid)    //检测串口数据输出是否有效beginif(bytes_cnt)   //接收字节数据计数beginif(bytes_cnt >= 3) begin bytes_cnt <= 0; endelse               begin bytes_cnt <= bytes_cnt + 1; end endelse begin if(uart_rx_bytes == FRAME_HEAD)   //判读第一个字节是否为帧头begin bytes_cnt <= 1; endendif(bytes_cnt == 0) begin if(uart_rx_bytes == TX_OVER)  //判断是否为传输结束标志begin state <= 10; end end else if(bytes_cnt == 3) begin state <= 5; end   //状态转移,标志地址初始化完成 case(bytes_cnt)0:beginif(uart_rx_bytes == FRAME_HEAD)   //判读第一个字节是否为帧头begin bytes_max <= 0; addr <= 0; end end1: begin bytes_max <= uart_rx_bytes; end2: begin addr <= uart_rx_bytes;      end                      //输入地址低8位3: begin addr <= {addr[23:16], uart_rx_bytes, addr[7:0]} - 1; end //输入地址高8位default:;  endcaseif(bytes_cnt)  //校验求和逻辑begin check_sum <= check_sum + uart_rx_bytes; end     //累加8位校验和else begin check_sum <= uart_rx_bytes; end end     end5: //准备写入的地址beginaddr <= addr*{16'b0, bytes_max}; //输入基地址state <= 6;data_get_valid <= 0;write <= 0;wren <= 0; shift_bytes <= 0;end6:  //接收有效的数据begin if(uart_rx_valid)    //检测串口数据输出是否有效beginbytes_cnt <= bytes_cnt + 1;datain <= uart_rx_bytes;data_get_valid <= 1;   //标志获取一个后效的字节check_sum <= check_sum + uart_rx_bytes;   //累加8位校验和endelse beginif(data_get_valid)beginif({flash_clk_sam[0], CLK_12_5M} == 2'b11)begin    wren <= 1; shift_bytes <= 1; data_get_valid <= 0; end endelse beginif({flash_clk_sam[0], CLK_12_5M} == 2'b11)begin wren <= 0; shift_bytes <= 0;if(bytes_cnt >= bytes_max)    begin state <= 7; end   //判断是否到达指定接收数量条件了 end end end end7:    //等待接收最后的校验和数据begin bytes_cnt <= 0;   //清零if(uart_rx_valid)    //检测串口数据输出是否有效begindata_get_valid <= 1;   //标志获取一个后效的字节check_sum <= 0;        //校验和清零if(check_sum == uart_rx_bytes)   //判读校验和是否正确begin check_sum_right <= 1; end else begin check_sum_right <= 0; end endelsebeginif(data_get_valid)  //接收到有效的一个字节了beginif(check_sum_right)   //校验和正确时begin if({flash_clk_sam[0], CLK_12_5M} == 2'b11)   //打开写入使能begin   wren <= 1; write <= 1; state <= 8; end end elsebegin uart_tx_valid <= 1; uart_tx_byte <= ERROR_CODE; state <= 4; end   //校验和不正确时,串口回复出错了,并返回状态4重新接收该帧数据  end  end end8:begin check_sum_right <= 0; //校验和正确状态清零  if(data_get_valid)beginif({flash_clk_sam[0], CLK_12_5M} == 2'b11)   //关闭写入使能begin  wren <= 0; write <= 0; data_get_valid <= 0; state <= 9; endend end 9:  //等待Flash烧写控制忙完begin if(busy_sam == 2'b10)   //等待烧写完毕,并回复上位机准备好接收下一帧数据,并状态转移begin uart_tx_byte <= ACK_CODE; uart_tx_valid <= 1; state <= 4; endend10: //回复已收到结束命令begin uart_tx_byte <= ACK_CODE; uart_tx_valid <= 1; state <= 0;end default: begin state <= 0; end endcase end
end //-------------------------------------------- Flash控制模块 ---------------------------------------------
reg  read;
reg  rden;
reg  [23:0] addr;
wire [7:0]  dataout/*synthesis keep*/;
wire busy/*synthesis keep*/;
wire data_valid/*synthesis keep*/;
reg  wren;
reg  write;
reg  shift_bytes;
reg  [7:0]  datain;
wire illegal_write/*synthesis keep*/;
reg  bulk_erase;
wire illegal_erase/*synthesis keep*/;
ASMI ASMI_inst
(.clkin         ( CLK_12_5M ),         //         clkin.clk.read          ( read ),          //          read.read.rden          ( rden ),          //          rden.rden.addr          ( addr ),          //          addr.addr.reset         ( ~nRST ),         //         reset.reset.dataout       ( dataout ),       //       dataout.dataout.busy          ( busy ),          //          busy.busy.data_valid    ( data_valid ),    //    data_valid.data_valid.shift_bytes   ( shift_bytes ),.wren          ( wren ),          //          wren.wren.write         ( write ),         //         write.write.datain        ( {datain[0],datain[1],datain[2],datain[3],datain[4],datain[5],datain[6],datain[7]} ),  //小端文件需要按位反转一下.illegal_write ( illegal_write ), // illegal_write.illegal_write.bulk_erase    ( bulk_erase ),    //    bulk_erase.bulk_erase.illegal_erase ( illegal_erase )  // illegal_erase.illegal_erase
);//------------------------------------ PLL IP核生成Flash控制模块的时钟 ---------------------------------------
wire CLK_12_5M/*synthesis keep*/;
PLL_12_5M   PLL_12_5M_inst
(.inclk0 ( MAIN_CLK ),.c0 ( CLK_12_5M )      //实际12.5MHz
);
//------------------------------------------- 例化串口应答模块 -----------------------------------------------
reg [7:0] uart_tx_byte;
reg uart_tx_valid;
ACK_Uart_TX  ACK_Uart_TX_inst
(.MAIN_CLK(MAIN_CLK),.RST_N(nRST),.UART_TX(UART_TX),.Tx_Bytes(uart_tx_byte),       //接收的数据.Tx_valid(uart_tx_valid)
);
//------------------------------------------- 例化串口接收模块 -----------------------------------------------
wire boot_start/*synthesis keep*/;
wire [7:0] uart_rx_bytes/*synthesis keep*/;
wire uart_rx_valid/*synthesis keep*/;
FPGA_data_Uart_RX  FPGA_data_Uart_RX_inst
(.MAIN_CLK(MAIN_CLK),.RST_N(nRST),.UART_RX(UART_RX),.boot_start(boot_start),     //标志boot开始.Rx_Bytes(uart_rx_bytes),   //接收到的有效数据.Rx_valid(uart_rx_valid)    //接收到的有效标志
);endmodule 

至此,整个流程已介绍完成,笔者已经在实际的硬件上测试通过了。

Cyclone IV系列FPGA串口远程烧写详解相关推荐

  1. FPGA串口接收与发送详解( part 3 )

    之前的part1~2已经详解完了单个数据的串口接收与发送,链接如下: FPGA串口接收与发送 详解 (part 1 )_居安士的博客-CSDN博客 FPGA串口接收与发送详解( part 2 )_居安 ...

  2. ADSP-21489的开发详解:SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)

    硬件准备 ADSP-21489EVB:ADI 21489处理器的开发板 AD-HP530ICE:ADI DSP专用仿真器 USBi:ADI SigmaDSP和SHARC DSP的图形化编程调试器 软件 ...

  3. ADSP-21489的开发详解:Norflash的硬件设计及程序烧写详解(含源代码)

    编者的话 Flash 编程与烧写,原本应该是开发的最后一步,当所有程序都做好了,在线编译运行正常,才会通过 Flash 编程,生成二进制的可执行文件 LDR,再通过 JTAG 仿真器将 LDR 文件烧 ...

  4. cyclone IV 系列轻量级FPGA 芯片ep4ce6e22c8 引脚分布图

    目录 简介 EP4CE6E22C8 IO分布 BANK IO分布 补充 简介 EP4CE6E22C8作为可以手动焊接的一款轻量级cyclone IV系列芯片,百度了一大圈都只有一个用户手册,找不到引脚 ...

  5. Altera Cyclone IV系列命名规则

    1.Cyclone IV E系列命名规则 1.首先是EP4C,这是Cyclone IV的代号简称,只要是Cyclone IV系列都以EP4C开头 2.然后是一个字母E,E代表是E系列,Enhanced ...

  6. (札记)Altera Stratix IV系列FPGA TRUE LVDS RX input termination 在Quartus工程中的设置方法...

    Altera Stratix IV系列FPGA Row bank的TRUE LVDS_RX支持oct(on chip termination),所以设计的时候不需要外接一个100ohm电阻.备注:我使 ...

  7. 的远程烧写_农用气象环境远程监测管理系统

    秋收十月,一个传统行业的收获的季节.在我国农业领域,是农民最忙碌的季节,蔬菜,粮食,水果.都在忙着收货.等收获完还有准备下一季的种植.气候环境是对农业种植起到至关重要的作用.下面给介绍一下农用气象站的 ...

  8. 【蓝牙串口无线烧写程序】适用于STM32F405RG的Bootloader

    [下载链接] 链接:https://pan.baidu.com/s/1gCQ2ayH2OQz0bQBAciNJ4w 提取码:qljc [使用说明] (1)用ST-Link或JLink将Bootload ...

  9. Altera的FPGA用烧写器烧写POF文件,烧写成功,显示100%,但是逻辑做的点灯没亮,一般会是哪的问题呀?烧写sof,灯亮。

    Altera的FPGA用烧写器烧写POF文件,烧写成功,显示100%,但是逻辑做的点灯没亮,一般会是哪的问题呀?烧写sof,灯亮. 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markd ...

  10. 学习日记——FPGA实验平台板级电路详解

    一.板级电路整体架构 我接下来一段时间学习的就是"勇敢的芯"FPGA 实验平台,它是特权同学和至芯科技携手打造的一款基于Altera Cyclone IV FPGA 器件的入门级 ...

最新文章

  1. 计算机录入速度标准,怎么提高电脑录入速度?
  2. Linux学习之遇到的小问题---查看系统版本,虚拟机创建共享文件夹,用到的命令记录。
  3. 服务器损坏mysql修复_云服务器mysql数据库损坏修复mysql
  4. 了解Spring Web初始化
  5. mysql 动态索引_MySQL的索引
  6. w ndows7文档加密取消,win7文件夹怎么加密?windows7文件加密方法
  7. 【微软亚洲研究院院长洪小文专访---谈大学生实习就业】
  8. 不止命令行-自定义VS生成事件
  9. Struts2 - Action no cache
  10. Julia: 关于Array排序函数sortslices
  11. 推荐一个springboot和springcloud系列的博客专家--方志朋
  12. [中文/英文]VC6 sp6补丁下载|VS6 sp6补丁下载 [防VC6link死机]
  13. ESXI7.0与6.7官网下载地址
  14. linux卸载usb声卡,Linux alsa 声卡驱动 安装 卸载 设置默认声卡
  15. 采购人必须明白的八大发展趋势及原则
  16. brew mysql_brew mysql指定版本
  17. 【职场加油站】给职场新人的几条忠告
  18. 好用的记事本app推荐 记事待办极简便签
  19. linux内核的挂载,通过Linux内核使用RDT
  20. MySQL 5.7.17.0 下载安装笔记

热门文章

  1. uni-app -- 小程序添加激励视频(字节-抖音小程序)
  2. Small RNA测序
  3. 高光谱图像处理之目标检测技术(CEM算法)(图像处理)
  4. C语言中变长数组的陷阱
  5. 人工智能数学基础8:两个重要极限及夹逼定理
  6. office Word中手动添加MathType插件
  7. 项目管理商业文件(第一章)
  8. 最新鑫迪自助建站系统源码V1.1完整版
  9. hover事件获取当前元素信息
  10. 如何下载秦皇岛市卫星地图高清版大图