ALTERA MAX10 FPGA 串口远程升级教程
ALTERA MAX10 FPGA 串口远程升级教程
一、前言
MAX10系列FPGA的远程升级实现,需要一些准备工作。在开发过程中,作者遇到了一些问题,比如两块板卡的报废(找不到FPGA器件),最初以为是擦除写入FPGA片内Flash的问题,浪费了很多时间。后来发现是电源模块的问题。本文将重点介绍MAX10 FPGA的远程升级过程,由于与Cyclone IV系统升级过程相似且更简单,因此只挑重点讲解。
二、升级原理
MAX10 FPGA上电后会自动加载片内Flash上的镜像,片内Flash空间结构如下图所示:
除了10M02,所有CFM都包含三个扇区:CFM0、CFM1和CFM2。选择内部配置模式时,对这些扇区的编程方式会有所不同。本文使用双压缩镜像模式,两个镜像分别存储在image1和image0中。官方提供的升级教程中会使用到config_sel这个引脚,上电后自动检测config_sel引脚电平,为高加载image1,如果加载失败会自动加载image0,因此这个引脚默认拉高即可。
通过Onchip_Flash IP可以操作片内Flash(即image0和image1)的数据,从而完成远程升级的数据更新。
三、Onchip_Flash IP使用
与之前的Flash IP操作基本一致,主要涉及擦除和写入两个操作,不需要读操作。略有不同的是增加了关闭写保护寄存器的操作,使用的接口是两个Avalon-MM接口(一个数据、一个控制)。IP中的image12对应文档中的image01。
(1)关闭写保护寄存器
需要操作的image2(IP核为准)对应的扇区为sector3和sector4,通过Avalon-MM-csr接口将控制寄存器对应位写0即可。写时序如图所示:
(2)擦除对应扇区
关闭写保护模式后,通过Avalon-MM-csr接口写入相应的位到控制寄存器选择扇区擦除位置。写入第一个擦除地址后持续读状态寄存器值,擦除过程中值为32'hfffffc01,直到读出32'hfffffc10表示扇区擦除完成;开始写入第二个擦除地址后持续读状态寄存器值,擦除过程中值为32'hfffffc11,直到读出32'hfffffc10表示扇区擦除完成。
(3)写数据到对应扇区
将新镜像生成的RPD文件通过串口写入FPGA,再通过Avalon-MM-data接口将数据写入对应的扇区,使用并行模式,写数据时序如下图所示。
四、操作步骤
以下是关键操作步骤:
(1)设置器件模式
在Quartus中打开工程后,右键选择Device/Device and Pin Options,选择Internal Configuration和Dual Compressed Image(一定要首先选择这个,否则生成IP后编译会报错)。
(2)生成Onchip_Flash IP
按照图示生成即可。
(3)生成双镜像工程factor.pof
(4)新版本镜像可以用两个新版本的sof生成rpd然后删除一半既可。
(5)串口操作
- 串口输入8'hCC读版本寄存器输出8'h03
- 串口输入8’hBB关闭写保护寄存器并擦除sector3-4扇区,输出8'h55表示擦除完成
- 串口发送剪裁后的rpd文件写入sector扇区,重启设备
- 串口输入8'hCC读版本寄存器输出8'h04升级完成
五、总结
使用MAX10 10M08器件生成的RPD文件只有300K,裁剪过后为140K,升级时间大概半分钟左右。还有一个dual configuration IP,作用与remote_update IP类似,可以不断电通过写寄存器实现FPGA重配置以及看门狗等功能。由于MAX10器件存在上电后自动检测config_sel引脚电平,为高加载image1,如果加载失败会自动加载image0这个功能(擦除完成后不写入新版本直接断电重启读版本寄存器会输出image0镜像版本号),因此dual configuration IP作用不大。在工程中例化了但没有使用。有兴趣的可以自己查阅一下手册使用比较简单就不多做描述了感谢观看欢迎一起讨论。
reg [2:0] avmm_rcv_address;
reg avmm_rcv_read;
reg [31:0] avmm_rcv_writedata;
reg avmm_rcv_write;
wire [31:0] avmm_rcv_readdata;
dual_config dual_config_inst(
.clk (clk_80m_o ),
.nreset (GRst_n ),
.avmm_rcv_address (avmm_rcv_address ),
.avmm_rcv_read (avmm_rcv_read ),
.avmm_rcv_writedata (avmm_rcv_writedata ),
.avmm_rcv_write (avmm_rcv_write ),
.avmm_rcv_readdata (avmm_rcv_readdata )
);