基於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 是這個記錄的校驗和。
我們只需要將記錄型別為00中的資料取出來即可,組成能夠被串列埠除錯助手識別的TXT檔案,然後以16進位制的方式往下發。
通過串列埠進入到fpga中資料送到fifo中,作為快取和跨時鐘域,接收到資料後,執行flash擦除操作,當資料存到256個時,一次將這些資料寫入到flash中,持續這樣,當延時1s後,fifo中有資料但是還是不足256個,判斷該資料是最後的資料,將這些資料寫完後,升級過程完成。
回讀了flash中的資料與寫進的資料作對比,完全一樣;並且斷電上電後,更新到flash中的資料能夠載入到FPGA中,並能正常執行。依次判斷:驗證該方案可行。
2,線上升級的實現。
驗證過程將除錯助手替代上位機軟體,並不科學,不能用於實際的產品中,所以需要上位機根據相應的協議發相應的指令到fpga,並執行相應的操作。
上位機發資料的波特率是9600bps,一bit起始位位,8bit資料位,1bit停止位。上位機將mcs檔案拆分為一包一包的資料,每包資料256個位元組,在寫命令之前需要發出擦除指令,每包資料後面跟著相應的CRC校驗位,校驗結果通過串列埠返回給上位機,,正確則繼續發下一包資料,不正確則重發該包資料。3個位元組的地址和256個位元組的資料快取到ram中,之後開始啟動flash操作,完成相應操作,操作完成夠,返回 資訊給上位機,上位機下發下一包資料。
充分利用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 */
[email protected]( 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時,第一包資料異常。猜測是上位機寫錯了位置,它重寫了第一包數 據。