常州網(wǎng)站設(shè)計制作推廣類軟文
在尋找APD最合適的偏壓的過程中,一般會用到廠商提供一條曲線,橫坐標(biāo)是溫度的變化,縱坐標(biāo)表示擊穿偏壓的變化,但每個產(chǎn)品真正的擊穿偏壓是有差異的。 為了能夠快速的找到當(dāng)前溫度下真實的擊穿偏壓,我們可以這樣做,我先根據(jù)溫度,得到廠商提供的擊穿偏壓。 然后再用廠商提供的擊穿偏壓,減去幾伏。 我們以此作為尋找真實擊穿偏壓的起點(diǎn)。以一個固定的步長提升APD的偏壓,直到滿足我們設(shè)定的擊穿判斷條件。 但是呢,在整個這個流程中,我們需要解決一個問題,就如何在FPGA程序中實時的去獲取當(dāng)前溫度下對應(yīng)的擊穿偏壓。 如果是dsp或者stm32等嵌入式平臺,可以直接把溫度-擊穿偏壓數(shù)據(jù)做成一個數(shù)據(jù)表存到一個數(shù)組,然后直接查表。 但是在FPGA中,我們不能用數(shù)組了,但可以選擇用ROM IP核 去實現(xiàn)。 在FPGA中,一些固定的初始化參數(shù)也可以用ROM來保存。 本文記錄ROM的使用方法。
1 ROM是什么
ROM 是只讀存儲器(Read-Only Memory)的簡稱,是一種只能讀出事先所存數(shù)據(jù)的固態(tài)半導(dǎo)體存儲器。其特性是一旦儲存資料就無法再將之改變或刪除,且資料不會因為電源關(guān)閉而消失。而事實上在 FPGA 中通過 IP 核生成的 ROM 或 RAM 調(diào)用的都是 FPGA 內(nèi)部的 RAM 資源,掉電內(nèi)容都會丟失(這也很容易解釋,FPGA 芯片內(nèi)部本來就沒有掉電非易失存儲器單元)。用 IP 核生成的 ROM 模塊只是提前添加了數(shù)據(jù)文件(.coe 格式),在 FPGA 運(yùn)行時通過數(shù)據(jù)文件給 ROM 模塊初始化,才使得 ROM 模塊像個“真正”的掉電非易失存儲器;也正是這個原因,ROM 模塊的內(nèi)容必須提前在數(shù)據(jù)文件中寫死,無法在電路中修改。
簡單說就是FPGA的ROM你隨便搞,不用擔(dān)心一次寫死后,后面再也不能改了。
2 .coe文件生成
ROM 作為只讀存儲器,在進(jìn)行?IP?核設(shè)置時需要指定初始化文件,即寫入存儲器中的 數(shù)據(jù),數(shù)據(jù)要以規(guī)定的格式才能正確寫入 ROM,這種格式就是?coe?文件。coe?是Vivado?規(guī)定的一種文件格式,下圖為文件格式示意圖
?下面提供一個.coe文件的 MatLAB生成代碼,一鍵即可生成你想要的.coe
clear;clear all;clc;FileName=['mycoe','.coe']; fid = fopen(FileName,'w'); fprintf(fid,'memory_initialization_radix = 16;\n');
fprintf(fid,'memory_initialization_vector =\n');
% 位寬
Width = 16;
% 深度
Depth = 20;Hexlen = Width / 4;for i=1:Depthdata = i;% 根據(jù)位寬補(bǔ)0HexCode = dec2hex(data);HexSize = size(HexCode,2);ZeroCode='';for j=1:(Hexlen-HexSize)ZeroCode=['0',ZeroCode];endstr0 = [ZeroCode,HexCode];% 判斷是否為最后一行if i < DepthHexstr = [str0,','];fprintf(fid,'%s\n',Hexstr);elseif i==DepthHexstr = [str0,';'];fprintf(fid,'%s',Hexstr);end
end
fclose(fid);open(FileName);
3 ROM IP 配置
ROM分單口ROM和雙口ROM,它們配置的區(qū)別僅僅只是Basic這一頁Memory Type的選項的區(qū)別,其他的都是一樣的。 所以本文僅以單口ROM的配置為例。
?傻瓜式截圖,從最原始的IP Catalog開始
?
取名這里,還是關(guān)注一下,比如我是用的單口rom,深度20,位寬16位。我的IP核命名就可以是 s_rom_20x16b。 比如我是用雙口rom,深度256,位寬8位呢,那IP核命名則為 d_rom_256x8b。 這樣的命名,能做到一目了然。
?👆上面這個圖有個值得關(guān)注的點(diǎn): Totoal Port A Read Latency :1 Clock Cycle?。 意思是讀的時候要輸出要延遲一個時鐘周期。👆
IP生成了,這個參數(shù)文件也被成功加載過來了。? | 瞅一眼是怎么例化的。 |
?4 Modelsim仿真
ROM在讀取數(shù)據(jù)的時候,要給ROM IP核輸入你的ROM地址。 而ROM地址應(yīng)該是從0開始的。 比如你Rom的深度是20(= 0x14),那你的ROM讀地址就是 0x00 ~ 0x13(10進(jìn)制是19)。那地址 0x00對應(yīng)的是ROM存的第一個數(shù)據(jù)(本例中是0x0001)。 0x13對應(yīng)的是ROM存的最后一個數(shù)據(jù)(本例中是0x0014)。
源碼如下:
`timescale 1ns / 1psmodule lab_rom(input wire clk,input wire rst_n
);//==================================================================
// Parameter define
//==================================================================
parameter MAX_ADDRA = 20 - 1;//==================================================================
// Internal Signals
//==================================================================
reg [4:0] addra;
wire [15:0] douta;//----------------------------- addra自增 -----------------------------
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginaddra <= 'd0; endelse if(addra == MAX_ADDRA)beginaddra <= 'd0;endelse beginaddra <= addra + 1'b1;end
end//----------------------------- s_rom_20x16b例化 -----------------------------
s_rom_20x16b s_rom_20x16b_inst (.clka(clk), // input wire clka.addra(addra), // input wire [4 : 0] addra.douta(douta) // output wire [15 : 0] douta
);endmodule
?約束文件
create_clock -period 20.000 [ get_ports clk ]set_property PACKAGE_PIN N18 [ get_ports clk ]
set_property PACKAGE_PIN T12 [ get_ports rst_n ]set_property IOSTANDARD LVCMOS33 [ get_ports clk ]
set_property IOSTANDARD LVCMOS33 [ get_ports rst_n ]
仿真代碼
`timescale 1ns/1ps
module tb_lab_rom (); /* this is automatically generated */// clockreg clk;initial beginclk = 1'b0;forever #(10) clk = ~clk;end// asynchronous resetreg rst_n;initial beginrst_n <= 1'b0;#10rst_n <= 1'b1;end// (*NOTE*) replace reset, clock, othersparameter MAX_ADDRA = 20 - 1;lab_rom #(.MAX_ADDRA(MAX_ADDRA)) inst_lab_rom (.clk(clk), .rst_n(rst_n));endmodule
?仿真結(jié)果
5 ila在線調(diào)試
本著再復(fù)習(xí)一下ila在線調(diào)試的原則,這里做一個在線調(diào)試的測試。
代碼
`timescale 1ns / 1psmodule lab_rom(input wire clk,input wire rst_n
);//==================================================================
// Parameter define
//==================================================================
parameter MAX_ADDRA = 20 - 1;//==================================================================
// Internal Signals
//==================================================================
(* MARK_DEBUG="true" *) reg [4:0] addra; // 修改🔺
(* MARK_DEBUG="true" *) wire [15:0] douta; // 修改🔺//----------------------------- addra自增 -----------------------------
always @(posedge clk or negedge rst_n) beginif (rst_n == 1'b0) beginaddra <= 'd0; endelse if(addra == MAX_ADDRA)beginaddra <= 'd0;endelse beginaddra <= addra + 1'b1;end
end//----------------------------- s_rom_20x16b例化 -----------------------------
s_rom_20x16b s_rom_20x16b_inst (.clka(clk), // input wire clka.addra(addra), // input wire [4 : 0] addra.douta(douta) // output wire [15 : 0] douta
);endmodule
?Run Synthesis - Open Synthesized Design? ? 運(yùn)行綜合 - 打開已綜合的設(shè)計
?Set up Debug → Next? ?設(shè)置調(diào)試→下一步?
添加要觀測的信號并設(shè)置時鐘域
?由于項目比較簡單,剛剛截圖的瞬間,系統(tǒng)剛剛應(yīng)該是自動Run?synthesis了一遍,并且還Run完了。
?編譯完之后直接 Open Hareware Manager 打開硬件管理器 - 直接燒寫程序,刷新設(shè)備
?在線調(diào)試功能正常。
參考文獻(xiàn)
Vivado 下 IP核 之ROM 讀寫_OliverH-yishuihan的博客-CSDN博客
在給rom IP核命名的時候,我發(fā)現(xiàn)FPGA的代碼應(yīng)該有一個統(tǒng)一遵循的規(guī)范,包括ip核 模塊 變量 參數(shù)的命名規(guī)則、注釋、縮進(jìn)風(fēng)格等都應(yīng)該有一個規(guī)范,?后續(xù)應(yīng)該會有一篇博客講規(guī)范,不過目前初學(xué)階段接觸的FPGA相關(guān)內(nèi)容還不夠全面,因此這篇博客應(yīng)該是在初學(xué)階段的尾聲部分。 另外,約束文件中關(guān)于時序部分的約束也是后續(xù)關(guān)注的一個重點(diǎn)。??