基于FPGA的在线升级的验证以及实现

      在线升级指的是程序不通过JTAG,仅仅是上位机发数据给fpga,fpga在将数据写到flash, 断电上电后,程序自动加载到fpga中,相当于仅仅通过一个接口(网口,usb接口或者串口),更新了fpga中的程序,对于一款成熟的产品,在线升级功能是必须的。下面将通过验证和实现两个方面分别介绍。

  1, 在线升级的验证。

         数据的大致流向是:  串口调试助手通过串口发数据到fpga,fpga用spi接口发数据到flash.  

 首先需要了解的是MCS文件的数据结构。

每个记录包含5个域,它们按以下格式排列:   :llaaaatt[dd...]cc  

  每一组字母对应一个不同的域,每一个字母对应一个十六进制编码的数字。每一个域由至少两个十六进制编码数字组成,它们构成一个字节,就像以下描述的那样:

      : 每个Intel HEX记录都由冒号开头.  

      ll 是数据长度域,它代表记录当中数据字节(dd)的数量。  

     aaaa 是地址域,它代表记录当中数据的起始地址。

      tt 是代表HEX记录类型的域,它可能是以下数据当中的一个:   00 – 数据记录   01 – 文件结束记录   02 – 扩展段地址记录   04 – 扩展线性地址记录  

     dd 是数据域,它代表一个字节的数据。一个记录可以有许多数据字节.记录当中数据字节的数量必须和数据长度域(ll)中指定的数字相符。  

     cc 是校验和域,它表示这个记录的校验和。校验和的计算是通过将记录当中所有十六进制编码数字对的值相加,以256为模进行以下补足。

    :10246200464C5549442050524F46494C4500464C33  

    其中:   10 是这个记录当中数据字节的数量。  

                2462 是数据将被下载到存储器当中的地址。  

                00 是记录类型(数据记录)  

               464C…464C是数据。  

               33 是这个记录的校验和。

       :02000004FFFFFC  

  其中:   02 是这个记录当中数据字节的数量。  

             0000 是地址域,对于扩展线性地址记录,这个域总是0000。  

             04 是记录类型 04(扩展线性地址记录)  

             FFFF 是地址的高16位。

             FC 是这个记录的校验和。

具体可参考https://wenku.baidu.com/view/5feed5d6195f312b3169a5f7.html?sxts=1539592612656

我们只需要将记录类型为00中的数据取出来即可,组成能够被串口调试助手识别的TXT文件,然后以16进制的方式往下发。

通过串口进入到fpga中数据送到fifo中,作为缓存和跨时钟域,接收到数据后,执行flash擦除操作,当数据存到256个时,一次将这些数据写入到flash中,持续这样,当延时1s后,fifo中有数据但是还是不足256个,判断该数据是最后的数据,将这些数据写完后,升级过程完成。

       回读了flash中的数据与写进的数据作对比,完全一样;并且断电上电后,更新到flash中的数据能够加载到FPGA中,并能正常运行。依此判断:该方案可行。

2,在线升级的实现。

       验证过程将调试助手替代上位机软件,并不科学,不能用于实际的产品中,所以需要上位机根据相应的协议发相应的指令到fpga,并执行相应的操作。

        上位机发数据的波特率是9600bps,一bit起始位位,8bit数据位,1bit停止位。spi时钟是25M,上位机将mcs文件拆分为一包一包的数据,每包数据256个字节,在写命令之前需要发出擦除指令,每包数据后面跟着相应的CRC校验位,校验结果通过串口返回给上位机,,正确则继续发下一包数据,不正确则重发该包数据。3个字节的地址和256个字节的数据缓存到ram中,之后开始启动flash操作,完成相应操作,操作完成够,返回 信息给上位机,上位机下发下一包数据。

          CRC16用的是CRC16--XMODEM模型,代码来自https://www.cnblogs.com/youngforever/archive/2013/05/26/3104648.html

充分利用crc信号,即可算出相应的crc结果。

          module CRC_GEN(    

           input            rst,     /*async reset,active low*/    

        input            clk,     /*clock input*/    

       input     [7:0]  data_in, /*parallel data input pins */    

       input            d_valid, /* data valid,start to generate CRC, active high*/    

     output reg[15:0] crc

       );  

    integer i;

    reg feedback;

    reg [15:0]  crc_tmp; /* * sequential process */

     always @(posedge clk or negedge rst)

      begin    

      if(!rst)        

     crc <= 16'b0;          /*触发器中的初始值十分重要 */    

      else if(d_valid==1'b0)      

        crc <= crc;  

       else        

       crc <= crc_tmp;

        end  /* *   combination process */

        always@( data_in or crc)

        begin  

        crc_tmp = crc;  

         for(i=7; i>=0; i=i-1)  

         begin        

           feedback    = crc_tmp[15] ^ data_in[i];      

           crc_tmp[15]  = crc_tmp[14];        

          crc_tmp[14]  = crc_tmp[13];        

          crc_tmp[13]  = crc_tmp[12];      

         crc_tmp[12]  = crc_tmp[11] ^ feedback;        

          crc_tmp[11]  = crc_tmp[10] ;      

           crc_tmp[10]  = crc_tmp[9];        

           crc_tmp[9]   = crc_tmp[8];        

           crc_tmp[8]   = crc_tmp[7];        

           crc_tmp[7]   = crc_tmp[6];      

         crc_tmp[6]   = crc_tmp[5];        

          crc_tmp[5]   = crc_tmp[4] ^ feedback;        

         crc_tmp[4]   = crc_tmp[3];      

          crc_tmp[3]   = crc_tmp[2];      

        crc_tmp[2]   = crc_tmp[1];        

        crc_tmp[1]   = crc_tmp[0];        

          crc_tmp[0]   = feedback;    

           end

      end

  endmodule

    

经过仿真后,结果也没问题。

经过反复调试,将节拍对上后。本以为工作告一段落,却出现了两个意料之外的问题。

a, 上位机写数据写到几十包几百包的时候,fpga没有返回校验结果。操作无法继续执行。 后来发现是我用分频时钟驱动好几个 模块,(从黑金借鉴来的代码,坑爹啊。)大概是驱动能力不足导致数据接收错误。换个底层的串口模块后,问题解决。

 b.   当几万包的数据写完后,第一包数据总是有问题,后面的正确。反复确认发现,当数据能凑成是256的整数时,数据正常,当

    最后的数据不足256时,第一包数据异常。发现是上位机写错了位置,它重写了第一包数 据。

猜你喜欢

转载自blog.csdn.net/walkmaner/article/details/83687216