資料介紹
描述
這個項目是我完整詳細介紹帶有 ADC 和 DAC ZMOD 的 Eclypse Z7 的延續(xù)。正如我在那個項目中提到的那樣,我通過將 DDS Complier IP 模塊集成到模塊設計中并使用它來生成數(shù)字 1 MHz 正弦波數(shù)據(jù)以供 DAC ZMOD 輸出到其通道之一,從而添加到設計中。為了驗證數(shù)據(jù),它將在 ADC ZMOD 的一個通道上讀取。我還將把它連接到我的信號分析儀上,看看物理 1MHz 波是什么樣子的。
首先,我將 DAC ZMOD 的第一個通道連接到 ADC ZMOD 的第一個通道:
作為參考的旁注,我再次使用 Vivado 和 Vitis 2019.2 版,并且我使用的項目與我在上一篇關于Eclypse Z7 的項目帖子中詳細介紹了如何創(chuàng)建的項目完全相同。
從 Vivado 中現(xiàn)有的硬件設計開始,首先需要修改的是塊設計。我非常喜歡使用 DDS 編譯器生成正弦波,因為它們是結構資源利用率和輸出波精度之間的最佳折衷。
打開模塊設計并將 DDS 編譯器添加到 IP 模塊設計,雙擊它以打開其定制窗口。
使用 DDS 編譯器 IP 的最大優(yōu)勢之一是在更改輸出信號的頻率/相位時平滑/無縫過渡(因此您不必擔心相位不連續(xù))。這就是為什么我喜歡使用流選項來實現(xiàn)輸出頻率/相位的可編程性。
我現(xiàn)在選擇只關注更改輸出頻率(通過相位增量可編程性)并將相位偏移可編程性設置為無:
對于帶有 DMA 的 AXI 流協(xié)議與 DAC ZMOD 接口以將正弦波寫出,流需要被打包,輸出tready,并在正弦波的每個周期結束時斷言 tlast。在 Data has TLAST 下選擇“Packet Framing”選項,并選中“Output TREADY”復選框。
DDS 編譯器會將其輸出寫入 Eclypse 的 DDR 內(nèi)存,供 DAC 通過 DMA 引擎讀取。為了使集成盡可能簡單,我只是為 DDS 的輸出啟用了 DMA 引擎的寫入通道。由于數(shù)據(jù)一次傳輸一個周期的正弦波,因此還需要為寫入通道啟用 DRE(數(shù)據(jù)重新對齊引擎)。選中寫入通道的“允許未對齊傳輸”框(僅適用于寫入通道,因為裸機 Zmod 庫負責對齊數(shù)據(jù)以在讀取通道上傳輸)。
手動將 DDS 編譯器的 M_AXIS_DATA 輸出連接到 DAC 的 DMA 引擎的 S_AXIS_S2MM。DMA 的 S_AXIS_S2MM 端口的 tkeep 信號需要在其總線上保持高電平,以表示所有傳入數(shù)據(jù)都是有效的(包括任何零值數(shù)據(jù)字節(jié))。為此,在設計中添加一個常量 IP 塊,將輸出寬度設置為與 DMA 的 S_AXIS_S2MM 端口的 tkeep 匹配,并將該值設置為總線上的高電平(在這種情況下,tkeep 信號為兩位寬,因此常數(shù)值將設置為 3,即 2'b11)。然后手動將其輸出連接到 DMA 的 S_AXIS_S2MM 端口。
我認為從 Zynq 芯片的可編程邏輯控制 DDS 編譯器的輸入會更容易。為了做到這一點,DDS 編譯器的相位輸入端口需要在框圖外部可用,方法是右鍵單擊端口名稱并選擇“Make external”選項。您將看到 DDS 編譯器輸入的 AXI 流總線端口出現(xiàn)。
來自 Zynq 處理系統(tǒng)的 FCLK_CLK1 時鐘也需要引出到模塊設計中的端口,以便在 Zynq 芯片的可編程邏輯中可供 HDL 使用。只需右鍵單擊 Zynq 處理系統(tǒng) IP 塊上的 FCLK_CLK1 端口名稱并選擇“創(chuàng)建端口...”:
塊設計現(xiàn)在應該類似于以下內(nèi)容:
后面要添加邏輯分析儀進行調(diào)試,標記DDS的相位輸入,連同DDS數(shù)據(jù)輸出,DAC的DMA的AXIS_MM2S和ADC的DMA的AXIS_S2MM進行調(diào)試。只需右鍵單擊每一行并選擇“調(diào)試”:
片刻之后,將出現(xiàn)連接自動化選項。選擇它并確保選中 AXI 協(xié)議檢查器選項的復選框。
連接自動化完成運行后,驗證模塊設計以檢查是否存在任何錯誤或嚴重警告,然后保存并關閉它。
由于已添加新的外部端口,因此需要為模塊設計創(chuàng)建新的 HDL 實例化。只需右鍵單擊 Sources Hierarchy 選項卡中的塊設計文件并選擇“Create HDL Wrapper...”選項即可完成此操作。它只會使用新的框圖實例化更新現(xiàn)有的框圖(就像在上一個項目中一樣,選擇讓 Vivado 自動更新和管理它的選項)。
然而,由于沒有一個新的外部端口將路由到 Zynq 芯片上的實際封裝引腳,并且還需要添加其他自定義 HDL,因此需要從頭開始創(chuàng)建一個新的頂級文件。即使有一個選項允許用戶在最后一步管理包裝器,我發(fā)現(xiàn)使用 Vivado 最好始終選擇自動管理選項,然后從頭開始創(chuàng)建自己的頂級文件并簡單地復制+粘貼來自自動生成的包裝器的框圖實例化。
對于這個設計,我正在創(chuàng)建我自己的三個設計源:新的自定義頂層文件、用于生成相位增量值以發(fā)送到 DDS 編譯器的邏輯,以及用于 AXI 流協(xié)議以與 DDS 編譯器通信的狀態(tài)機.
從 Flow Navigator 中選擇 Add Sources 選項,然后在彈出窗口中選擇 Add or create design sources。然后,該窗口將為您提供創(chuàng)建所需文件數(shù)量的選項(在本例中為三個 Verilog 模塊文件)。
我將頂層文件命名為“eclypse_top”,將相位增量邏輯文件命名為“bb_logic”,并將 AXI 流狀態(tài)機文件命名為“axis_sm”。
頂層文件主要是為塊設計實例化自動生成的 design_wrapper 文件的復制 + 粘貼。它還將實例化相位增量邏輯模塊。請注意,用于 DDS 編譯器和 FCLK_CLK1 的從 AXI 流信號從模塊端口說明符中被注釋掉,因為它們被重定向到相位增量邏輯模塊,而不是被路由到 Zynq 芯片上的封裝引腳。然后相位增量邏輯模塊負責例化 AXI 流狀態(tài)機模塊。
自定義頂級文件 Verilog:
module eclypse_top(
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
// input [31:0]DDS_S_AXIS_PHASE_tdata,
// input DDS_S_AXIS_PHASE_tlast,
// output DDS_S_AXIS_PHASE_tready,
// input DDS_S_AXIS_PHASE_tvalid,
input DcoClk_0,
// output FCLK_CLK1,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb,
output adcClkIn_n_0,
output adcClkIn_p_0,
output adcSync_0,
input [1:0]btn_2bits_tri_i,
input [13:0]dADC_Data_0,
inout pmod_ja_pin10_io,
inout pmod_ja_pin1_io,
inout pmod_ja_pin2_io,
inout pmod_ja_pin3_io,
inout pmod_ja_pin4_io,
inout pmod_ja_pin7_io,
inout pmod_ja_pin8_io,
inout pmod_ja_pin9_io,
inout pmod_jb_pin10_io,
inout pmod_jb_pin1_io,
inout pmod_jb_pin2_io,
inout pmod_jb_pin3_io,
inout pmod_jb_pin4_io,
inout pmod_jb_pin7_io,
inout pmod_jb_pin8_io,
inout pmod_jb_pin9_io,
output [5:0]rgbled_6bits_tri_o,
output sADC_CS_0,
inout sADC_SDIO_0,
output sADC_Sclk_0,
output sCh1CouplingH_0,
output sCh1CouplingL_0,
output sCh1GainH_0,
output sCh1GainL_0,
output sCh2CouplingH_0,
output sCh2CouplingL_0,
output sCh2GainH_0,
output sCh2GainL_0,
output sDAC_CS_0,
output sDAC_ClkIO_0,
output sDAC_Clkin_0,
output [13:0]sDAC_Data_0,
output sDAC_EnOut_0,
output sDAC_Reset_0,
output sDAC_SCLK_0,
inout sDAC_SDIO_0,
output sDAC_SetFS1_0,
output sDAC_SetFS2_0,
output sRelayComH_0,
output sRelayComL_0,
input sys_clock
);
wire FCLK_CLK1;
wire [31:0]DDS_S_AXIS_PHASE_tdata;
wire DDS_S_AXIS_PHASE_tlast;
wire DDS_S_AXIS_PHASE_tready;
wire DDS_S_AXIS_PHASE_tvalid;
// block diagram instantiation
design_1 design_1_i(
.DDR_addr(DDR_addr),
.DDR_ba(DDR_ba),
.DDR_cas_n(DDR_cas_n),
.DDR_ck_n(DDR_ck_n),
.DDR_ck_p(DDR_ck_p),
.DDR_cke(DDR_cke),
.DDR_cs_n(DDR_cs_n),
.DDR_dm(DDR_dm),
.DDR_dq(DDR_dq),
.DDR_dqs_n(DDR_dqs_n),
.DDR_dqs_p(DDR_dqs_p),
.DDR_odt(DDR_odt),
.DDR_ras_n(DDR_ras_n),
.DDR_reset_n(DDR_reset_n),
.DDR_we_n(DDR_we_n),
.DDS_S_AXIS_PHASE_tdata(DDS_S_AXIS_PHASE_tdata),
.DDS_S_AXIS_PHASE_tlast(DDS_S_AXIS_PHASE_tlast),
.DDS_S_AXIS_PHASE_tready(DDS_S_AXIS_PHASE_tready),
.DDS_S_AXIS_PHASE_tvalid(DDS_S_AXIS_PHASE_tvalid),
.DcoClk_0(DcoClk_0),
.FCLK_CLK1(FCLK_CLK1),
.FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
.FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
.FIXED_IO_mio(FIXED_IO_mio),
.FIXED_IO_ps_clk(FIXED_IO_ps_clk),
.FIXED_IO_ps_porb(FIXED_IO_ps_porb),
.FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
.adcClkIn_n_0(adcClkIn_n_0),
.adcClkIn_p_0(adcClkIn_p_0),
.adcSync_0(adcSync_0),
.btn_2bits_tri_i(btn_2bits_tri_i),
.dADC_Data_0(dADC_Data_0),
.pmod_ja_pin10_i(pmod_ja_pin10_i),
.pmod_ja_pin10_o(pmod_ja_pin10_o),
.pmod_ja_pin10_t(pmod_ja_pin10_t),
.pmod_ja_pin1_i(pmod_ja_pin1_i),
.pmod_ja_pin1_o(pmod_ja_pin1_o),
.pmod_ja_pin1_t(pmod_ja_pin1_t),
.pmod_ja_pin2_i(pmod_ja_pin2_i),
.pmod_ja_pin2_o(pmod_ja_pin2_o),
.pmod_ja_pin2_t(pmod_ja_pin2_t),
.pmod_ja_pin3_i(pmod_ja_pin3_i),
.pmod_ja_pin3_o(pmod_ja_pin3_o),
.pmod_ja_pin3_t(pmod_ja_pin3_t),
.pmod_ja_pin4_i(pmod_ja_pin4_i),
.pmod_ja_pin4_o(pmod_ja_pin4_o),
.pmod_ja_pin4_t(pmod_ja_pin4_t),
.pmod_ja_pin7_i(pmod_ja_pin7_i),
.pmod_ja_pin7_o(pmod_ja_pin7_o),
.pmod_ja_pin7_t(pmod_ja_pin7_t),
.pmod_ja_pin8_i(pmod_ja_pin8_i),
.pmod_ja_pin8_o(pmod_ja_pin8_o),
.pmod_ja_pin8_t(pmod_ja_pin8_t),
.pmod_ja_pin9_i(pmod_ja_pin9_i),
.pmod_ja_pin9_o(pmod_ja_pin9_o),
.pmod_ja_pin9_t(pmod_ja_pin9_t),
.pmod_jb_pin10_i(pmod_jb_pin10_i),
.pmod_jb_pin10_o(pmod_jb_pin10_o),
.pmod_jb_pin10_t(pmod_jb_pin10_t),
.pmod_jb_pin1_i(pmod_jb_pin1_i),
.pmod_jb_pin1_o(pmod_jb_pin1_o),
.pmod_jb_pin1_t(pmod_jb_pin1_t),
.pmod_jb_pin2_i(pmod_jb_pin2_i),
.pmod_jb_pin2_o(pmod_jb_pin2_o),
.pmod_jb_pin2_t(pmod_jb_pin2_t),
.pmod_jb_pin3_i(pmod_jb_pin3_i),
.pmod_jb_pin3_o(pmod_jb_pin3_o),
.pmod_jb_pin3_t(pmod_jb_pin3_t),
.pmod_jb_pin4_i(pmod_jb_pin4_i),
.pmod_jb_pin4_o(pmod_jb_pin4_o),
.pmod_jb_pin4_t(pmod_jb_pin4_t),
.pmod_jb_pin7_i(pmod_jb_pin7_i),
.pmod_jb_pin7_o(pmod_jb_pin7_o),
.pmod_jb_pin7_t(pmod_jb_pin7_t),
.pmod_jb_pin8_i(pmod_jb_pin8_i),
.pmod_jb_pin8_o(pmod_jb_pin8_o),
.pmod_jb_pin8_t(pmod_jb_pin8_t),
.pmod_jb_pin9_i(pmod_jb_pin9_i),
.pmod_jb_pin9_o(pmod_jb_pin9_o),
.pmod_jb_pin9_t(pmod_jb_pin9_t),
.rgbled_6bits_tri_o(rgbled_6bits_tri_o),
.sADC_CS_0(sADC_CS_0),
.sADC_SDIO_0(sADC_SDIO_0),
.sADC_Sclk_0(sADC_Sclk_0),
.sCh1CouplingH_0(sCh1CouplingH_0),
.sCh1CouplingL_0(sCh1CouplingL_0),
.sCh1GainH_0(sCh1GainH_0),
.sCh1GainL_0(sCh1GainL_0),
.sCh2CouplingH_0(sCh2CouplingH_0),
.sCh2CouplingL_0(sCh2CouplingL_0),
.sCh2GainH_0(sCh2GainH_0),
.sCh2GainL_0(sCh2GainL_0),
.sDAC_CS_0(sDAC_CS_0),
.sDAC_ClkIO_0(sDAC_ClkIO_0),
.sDAC_Clkin_0(sDAC_Clkin_0),
.sDAC_Data_0(sDAC_Data_0),
.sDAC_EnOut_0(sDAC_EnOut_0),
.sDAC_Reset_0(sDAC_Reset_0),
.sDAC_SCLK_0(sDAC_SCLK_0),
.sDAC_SDIO_0(sDAC_SDIO_0),
.sDAC_SetFS1_0(sDAC_SetFS1_0),
.sDAC_SetFS2_0(sDAC_SetFS2_0),
.sRelayComH_0(sRelayComH_0),
.sRelayComL_0(sRelayComL_0),
.sys_clock(sys_clock));
IOBUF pmod_ja_pin10_iobuf(
.I(pmod_ja_pin10_o),
.IO(pmod_ja_pin10_io),
.O(pmod_ja_pin10_i),
.T(pmod_ja_pin10_t));
IOBUF pmod_ja_pin1_iobuf(
.I(pmod_ja_pin1_o),
.IO(pmod_ja_pin1_io),
.O(pmod_ja_pin1_i),
.T(pmod_ja_pin1_t));
IOBUF pmod_ja_pin2_iobuf(
.I(pmod_ja_pin2_o),
.IO(pmod_ja_pin2_io),
.O(pmod_ja_pin2_i),
.T(pmod_ja_pin2_t));
IOBUF pmod_ja_pin3_iobuf(
.I(pmod_ja_pin3_o),
.IO(pmod_ja_pin3_io),
.O(pmod_ja_pin3_i),
.T(pmod_ja_pin3_t));
IOBUF pmod_ja_pin4_iobuf(
.I(pmod_ja_pin4_o),
.IO(pmod_ja_pin4_io),
.O(pmod_ja_pin4_i),
.T(pmod_ja_pin4_t));
IOBUF pmod_ja_pin7_iobuf(
.I(pmod_ja_pin7_o),
.IO(pmod_ja_pin7_io),
.O(pmod_ja_pin7_i),
.T(pmod_ja_pin7_t));
IOBUF pmod_ja_pin8_iobuf(
.I(pmod_ja_pin8_o),
.IO(pmod_ja_pin8_io),
.O(pmod_ja_pin8_i),
.T(pmod_ja_pin8_t));
IOBUF pmod_ja_pin9_iobuf(
.I(pmod_ja_pin9_o),
.IO(pmod_ja_pin9_io),
.O(pmod_ja_pin9_i),
.T(pmod_ja_pin9_t));
IOBUF pmod_jb_pin10_iobuf(
.I(pmod_jb_pin10_o),
.IO(pmod_jb_pin10_io),
.O(pmod_jb_pin10_i),
.T(pmod_jb_pin10_t));
IOBUF pmod_jb_pin1_iobuf(
.I(pmod_jb_pin1_o),
.IO(pmod_jb_pin1_io),
.O(pmod_jb_pin1_i),
.T(pmod_jb_pin1_t));
IOBUF pmod_jb_pin2_iobuf(
.I(pmod_jb_pin2_o),
.IO(pmod_jb_pin2_io),
.O(pmod_jb_pin2_i),
.T(pmod_jb_pin2_t));
IOBUF pmod_jb_pin3_iobuf(
.I(pmod_jb_pin3_o),
.IO(pmod_jb_pin3_io),
.O(pmod_jb_pin3_i),
.T(pmod_jb_pin3_t));
IOBUF pmod_jb_pin4_iobuf(
.I(pmod_jb_pin4_o),
.IO(pmod_jb_pin4_io),
.O(pmod_jb_pin4_i),
.T(pmod_jb_pin4_t));
IOBUF pmod_jb_pin7_iobuf(
.I(pmod_jb_pin7_o),
.IO(pmod_jb_pin7_io),
.O(pmod_jb_pin7_i),
.T(pmod_jb_pin7_t));
IOBUF pmod_jb_pin8_iobuf(
.I(pmod_jb_pin8_o),
.IO(pmod_jb_pin8_io),
.O(pmod_jb_pin8_i),
.T(pmod_jb_pin8_t));
IOBUF pmod_jb_pin9_iobuf(
.I(pmod_jb_pin9_o),
.IO(pmod_jb_pin9_io),
.O(pmod_jb_pin9_i),
.T(pmod_jb_pin9_t));
// phase increment logic module instantiation
bb_logic bb_logic_i(
.clk(FCLK_CLK1),
.DDS_S_AXIS_PHASE_tdata(DDS_S_AXIS_PHASE_tdata),
.DDS_S_AXIS_PHASE_tlast(DDS_S_AXIS_PHASE_tlast),
.DDS_S_AXIS_PHASE_tready(DDS_S_AXIS_PHASE_tready),
.DDS_S_AXIS_PHASE_tvalid(DDS_S_AXIS_PHASE_tvalid));
endmodule
對于 DDS 的輸出頻率,我暫時選擇對其進行硬核,以確保模塊設計中的 DDS 編譯器集成是正確的。由于 DAC 和 ADC 的最大采樣率為 100Ms/s,因此按照 Nyquist 的最大輸出頻率為 50MHz。我決定將 1MHz 作為一個簡單的數(shù)字(請參閱我最初的DDS 編譯器教程,了解我如何計算 1MHz 的十六進制值相位增量輸入)。
相位增量邏輯模塊文件 Verilog:
module bb_logic(
input clk,
output [31:0] DDS_S_AXIS_PHASE_tdata, // input to block design
output DDS_S_AXIS_PHASE_tlast, // input to block design
input DDS_S_AXIS_PHASE_tready, // output from block design
output DDS_S_AXIS_PHASE_tvalid // input to block design
);
wire [31:0] Freq;
wire [31:0] Freq_period;
// setting the phase increment value to static for now
assign Freq = 32'h28f5c2;
assign Freq_period = 32'd100; // 1000ns/10ns = 100 --> max value here is 16384
wire latch_tdata;
// AXI stream state machine instantiation
axis_sm axis_sm_i(
.clk(clk),
.reset(1'b1),
.start(1'b1),
.latch_tdata(latch_tdata),
.s_phase_tvalid(DDS_S_AXIS_PHASE_tvalid), // output
.s_phase_tlast(DDS_S_AXIS_PHASE_tlast), // output
.s_phase_tready(DDS_S_AXIS_PHASE_tready), // input
.s_phase_tdata(DDS_S_AXIS_PHASE_tdata), // output
.carrier_freq(Freq),
.carrier_period(Freq_period)
);
endmodule
AXI Stream 協(xié)議狀態(tài)機:
module axis_sm(
input clk,
input reset,
input start,
output reg latch_tdata,
output reg s_phase_tvalid,
output reg s_phase_tlast,
input s_phase_tready,
output reg [31:0] s_phase_tdata,
input [31:0] carrier_freq,
input [31:0] carrier_period
);
reg [4:0] state_reg;
reg [31:0] period_wait_cnt;
parameter init = 5'd0;
parameter WaitForStart = 5'd1;
parameter SetTvalidHigh = 5'd2;
parameter SetSlavePhaseValue = 5'd3;
parameter LatchTdata = 5'd4;
parameter CheckTready = 5'd5;
parameter WaitState = 5'd6;
parameter SetTlastHigh = 5'd7;
parameter WaitOneState = 5'd8;
parameter SetTlastLow = 5'd9;
parameter set_freq = 1'b0;
parameter set_phase = 1'b1;
parameter default_tdata = 32'h0;
always @ (posedge clk or posedge reset)
begin
// Default Outputs
latch_tdata <= 1'b0;
if (reset == 1'b0)
begin
s_phase_tdata[31:0] <= default_tdata;
state_reg <= init;
end
else
begin
case(state_reg)
init : //0
begin
latch_tdata <= 1'b0;
s_phase_tlast <= 1'b0;
s_phase_tvalid <= 1'b0;
period_wait_cnt <= 32'd0;
state_reg <= WaitForStart;
end
WaitForStart : //1
begin
if (start == 1'b1)
begin
state_reg <= SetTvalidHigh;
end
else
begin
state_reg <= WaitForStart;
end
end
SetTvalidHigh : //2
begin
s_phase_tvalid <= 1'b1;
state_reg <= SetSlavePhaseValue;
end
SetSlavePhaseValue : //3
begin
s_phase_tdata[31:0] <= carrier_freq;
state_reg <= LatchTdata;
end
LatchTdata : //4
begin
latch_tdata <= 1'b1;
state_reg <= CheckTready;
end
CheckTready : //5
begin
if (s_phase_tready == 1'b1)
begin
state_reg <= WaitState;
end
else if (start == 1'b0)
begin
state_reg <= init;
end
else
begin
state_reg <= CheckTready;
end
end
WaitState : //6
begin
if (period_wait_cnt >= carrier_period)
begin
period_wait_cnt <= 32'd0;
state_reg <= SetTlastHigh;
end
else
begin
period_wait_cnt <= period_wait_cnt + 1;
state_reg <= WaitState;
end
end
SetTlastHigh : //7
begin
s_phase_tlast <= 1'b1;
state_reg <= WaitOneState;
end
WaitOneState : //8
begin
state_reg <= SetTlastLow;
end
SetTlastLow : //9
begin
s_phase_tlast <= 1'b0;
state_reg <= WaitForStart;
end
endcase
end
end
endmodule
新的頂級文件與其他兩個文件一起完成后,保存所有文件,您將看到 Sources Hierarchy 自動更新。通過右鍵單擊 Sources Hierarchy 選項卡中的 eclypse_top 文件并選擇“設置為頂部”選項,將 eclypse_top 文件設置為項目的新頂部文件。
有了新的自定義頂級文件,暫時不再需要自動生成的文件。不過我發(fā)現(xiàn)如果以后再更新積木設計,還是有它就好了。再加上我多次了解到刪除 Vivado 自動生成的文件會導致工具出現(xiàn)未定義行為這一事實,我只是禁用了該文件。在 Sources Hierarchy 選項卡中右鍵單擊它,然后選擇“Disable”。更新后,您的 Sources Hierarchy 選項卡應類似于以下內(nèi)容:
正如我在之前的項目中提到的那樣,基礎項目的時間安排已經(jīng)結束。輸出到 SYZYGY 連接器上的 DAC Zmod 的數(shù)據(jù)線的保持時間不夠長。我在之前的項目中沒有修復它,因為我知道我在這個項目中的添加會在實現(xiàn)過程中改變設計的位置和布線,并最終在一定程度上改變時序。幸運的是,這個項目中的添加增加了足夠的延遲,我能夠簡單地延長約束文件中 DAC 數(shù)據(jù)線的保持時間(最后四行):
set_output_delay -clock [get_clocks sDAC_Clkin_0] -clock_fall -min -add_delay 0.330 [get_ports {sDAC_Data_0[*]}]
set_output_delay -clock [get_clocks sDAC_Clkin_0] -clock_fall -max -add_delay 0.250 [get_ports {sDAC_Data_0[*]}]
set_output_delay -clock [get_clocks sDAC_Clkin_0] -min -add_delay 0.330 [get_ports {sDAC_Data_0[*]}]
set_output_delay -clock [get_clocks sDAC_Clkin_0] -max -add_delay 0.150 [get_ports {sDAC_Data_0[*]}]
約束文件更新后,運行綜合、實現(xiàn)并生成比特流。完成后,驗證沒有錯誤或嚴重警告并導出硬件以在 Vitis 中使用。在“文件”菜單下,選擇“導出”下的“導出硬件...”選項。確認您正在導出到與 Vitis 工作區(qū)中現(xiàn)有硬件平臺(XSA 文件)相同的位置,并選中包含比特流的選項。
從 Vivado 的工具菜單中啟動 Vitis,然后選擇項目的現(xiàn)有工作區(qū)。同樣,我只是在此處修改我上一個項目教程中的現(xiàn)有裸機應用程序,因此請參閱創(chuàng)建新的 Vitis 項目和應用程序。
ZMOD 裸機庫對 ADC 和 DAC 起作用的方式是,它們通過 DMA 交換從 Eclypse 上的 DDR 存儲器填充緩沖區(qū)。對于 DAC,Digilent 的原始設計僅啟用了讀取通道(內(nèi)存映射到流或 MM2S)。由于我們啟用了寫入通道(流到內(nèi)存映射或 S2MM),因此還需要更新庫以反映現(xiàn)在有一個雙向的 DMA 實例。
從
修改dma.h:
#ifndef DMA_H_
#define DMA_H_
#include
/**
* Direction of a DMA transfer.
*/
enum dma_direction {
DMA_DIRECTION_TX, ///< TX transfer
DMA_DIRECTION_RX, ///< RX transfer
DMA_DIRECTION_TRX ///< TX & RX transfer
};
uint32_t fnInitDMA(uintptr_t addr, enum dma_direction direction, int dmaInterrupt);
void fnDestroyDMA(uintptr_t addr);
int fnOneWayDMATransfer(uintptr_t addr, uint32_t *buf, size_t length);
int fnS2MM_DMATransferCont(uintptr_t addr, uint32_t *buf, size_t transfer_size, int num_transfers);
int fnMM2S_DMATransfer(uintptr_t addr, uint32_t *buf, size_t transfer_size);
uint8_t fnIsDMATransferComplete(uintptr_t addr);
void* fnAllocBuffer(uintptr_t addr, size_t size);
void fnFreeBuffer(uintptr_t addr, void *buf, size_t size);
#endif /* DMA_H_ */
dma.c 中添加了新的 DMA 傳輸函數(shù):
S2MM DMA傳輸功能:
int fnS2MM_DMATransferCont(uintptr_t addr, uint32_t *buf, size_t transfer_size, int num_transfers){
DMAEnv *dmaEnv = (DMAEnv *)addr;
if (!dmaEnv)
return -1;
dmaEnv->complete_flag = 0;
if(dmaEnv->direction != DMA_DIRECTION_TRX){
return -1;
} else {
// S2MM - read in DDS data
// Associate data buffer
writeDMAReg(dmaEnv->base_addr, AXIDMA_REG_ADDR_S2MM_DA, (uint32_t)buf);
// Set DMA RX Run bit, value 1, DMA register
writeDMARegFld(dmaEnv->base_addr, AXIDMA_REGFLD_S2MM_DMACR_RUNSTOP, 1);
for (int i=0;i<num_transfers;i++){
// Start DMA Transfer
writeDMAReg(dmaEnv->base_addr, AXIDMA_REG_ADDR_S2MM_DA_LENGTH, transfer_size);
}
}
return 0;
}
MM2S DMA傳輸功能:
int fnMM2S_DMATransfer(uintptr_t addr, uint32_t *buf, size_t transfer_size){
DMAEnv *dmaEnv = (DMAEnv *)addr;
if (!dmaEnv)
return -1;
dmaEnv->complete_flag = 0;
if(dmaEnv->direction != DMA_DIRECTION_TRX){
return -1;
} else {
// MM2S - write out to DAC
// Associate data buffer
writeDMAReg(dmaEnv->base_addr, AXIDMA_REG_ADDR_MM2S_SA, (uint32_t)buf);
// Set DMA RX Run bit, value 1, DMA register
writeDMARegFld(dmaEnv->base_addr, AXIDMA_REGFLD_MM2S_DMACR_RUNSTOP, 1);
// Start DMA Transfer
writeDMAReg(dmaEnv->base_addr, AXIDMA_REG_ADDR_MM2S_SA_LENGTH, transfer_size);
}
return 0;
}
DMA 函數(shù)是從 ZMOD 基礎庫中調(diào)用的,因此還需要添加兩個函數(shù)。一個啟動 MM2S DMA 事務,一個啟動 S2MM DMA 事務(不要忘記將這些函數(shù)原型也添加到 Zmod.h)。
新的 Zmod.cpp 功能:
/**
* Start a DMA S2MM transfer using the transfer length configured previously.
*
* @return 0 on success, any other number on failure
*/
int ZMOD::startS2MMTransferCont(uint32_t* buffer, int num_transfers){
// transfer length is not configured
if (transferSize < 1) {
return ERR_FAIL;
}
return fnS2MM_DMATransferCont(dmaAddr, buffer, transferSize, num_transfers);
}
/**
* Start a DMA MM2S transfer using the transfer length configured previously.
*
* @return 0 on success, any other number on failure
*/
int ZMOD::startMM2STransfer(uint32_t* buffer){
// transfer length is not configured
if (transferSize < 1) {
return ERR_FAIL;
}
return fnMM2S_DMATransfer(dmaAddr, buffer, transferSize);
}
最后,在 DAC ZMOD 特定庫中,需要兩個新函數(shù)通過 DMA S2MM 事務從 DDS 編譯器向 DDR 寫入一段正弦波,并將該數(shù)據(jù)從 DDR 讀取到緩沖區(qū)以通過 DMA 發(fā)送到 DAC MM2S 交易。還需要修改 DAC 實例的初始化,以指示附加到它的 DMA 現(xiàn)在是雙向的(能夠進行讀取/MM2S 和寫入/S2MM 事務)。
修改了 DAC ZMOD 的 init 實例函數(shù)以對 DMA 使用新的雙向類型:
ZMODDAC1411::ZMODDAC1411(uintptr_t baseAddress, uintptr_t dmaAddress, uintptr_t iicAddress, uintptr_t flashAddress, int dmaInterrupt)
: ZMOD(baseAddress, dmaAddress, iicAddress, flashAddress, DMA_DIRECTION_TRX, -1, dmaInterrupt)
{
ZMOD::initCalib(sizeof(CALIBECLYPSEDAC), ZMODDAC1411_CALIB_ID, ZMODDAC1411_CALIB_USER_ADDR, ZMODDAC1411_CALIB_FACT_ADDR);
}
將 DDS 編譯器輸出寫入 DDR 內(nèi)存的函數(shù):
/*
* Reads in the data values being output by the DDS Compiler and writes them to a
* memory location in the DDR
* @param none
* @return the status: ERR_SUCCESS for success*/
int ZMODDAC1411::readInDDSdata(uint32_t* buffer, size_t &length, int num_transfers){
uint8_t Status;
if(length > ZmodDAC1411_MAX_BUFFER_LEN){
length = ZmodDAC1411_MAX_BUFFER_LEN;
}
// DMA TX transfer length in number of elements
// multiply by the size of the data
setTransferSize(length * sizeof(uint32_t));
// Start DMA Transfer
Status = startS2MMTransferCont(buffer, num_transfers);
if (Status) {
return ERR_FAIL;
}
return ERR_SUCCESS;
}
將 DDS 輸出數(shù)據(jù)從 DDR 讀取到 DAC ZMOD 緩沖區(qū)的函數(shù):
int ZMODDAC1411::sendDDSdataToDAC(uint32_t* buffer, size_t &length){
uint8_t Status;
if(length > ZmodDAC1411_MAX_BUFFER_LEN)
{
length = ZmodDAC1411_MAX_BUFFER_LEN;
}
// DMA TX transfer length in number of elements
// multiply by the size of the data
setTransferSize(length * sizeof(uint32_t));
// Start DMA Transfer
Status = startMM2STransfer(buffer);
if (Status) {
return ERR_FAIL;
}
// // Wait for DMA to Complete transfer
// while(!isDMATransferComplete()) {}
return ERR_SUCCESS;
}
隨著 ZMOD 裸機庫的更新,主要功能相當簡單。主函數(shù)首先創(chuàng)建 DAC ZMOD 的實例,然后設置 14 位輸出采樣分頻器和通道一的增益值。然后為緩沖區(qū)分配內(nèi)存,以 DMA 能夠達到的最大長度(0x3fff 或 16384)將數(shù)據(jù)從 DDS 讀取到 DDR,并分配另一個緩沖區(qū)以將數(shù)據(jù)發(fā)送到 DAC。
一個周期的 1MHz 正弦波正從 DDR 內(nèi)存(相當于 50 個樣本)讀取到第一個緩沖區(qū)中。然后將其冗余復制到第二個緩沖區(qū)中,直到緩沖區(qū)已滿。然后將該緩沖區(qū)發(fā)送到 DAC 并啟動 DAC。一旦數(shù)據(jù)成功發(fā)送到 DAC,兩個緩沖區(qū)的內(nèi)存都會被釋放,DAC 會無限運行,輸出 1MHz 正弦波。
對于 ADC,我只是重用了我在上一個項目中使用的 Digilent 的 ADC 演示功能。此 ADC 演示功能啟動 ADC 以連續(xù)捕獲和無限循環(huán)并格式化數(shù)據(jù)以輸出到 UART 控制臺。
主要功能代碼:
#include
#include
#include
#include "xaxidma.h"
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h"
#include "./zmodlib/Zmod/zmod.h"
#include "./zmodlib/ZmodADC1410/zmodadc1410.h"
#include "./zmodlib/ZmodDAC1411/zmoddac1411.h"
#include "./zmodlib/Zmod/dma.h"
#define TRANSFER_LEN 0x400
// ZMOD ADC parameters
#define ZMOD_ADC_BASE_ADDR XPAR_AXI_ZMODADC1410_0_S00_AXI_BASEADDR
#define DMA_ADC_BASE_ADDR XPAR_AXI_DMA_ADC_BASEADDR
#define IIC_BASE_ADDR XPAR_PS7_I2C_1_BASEADDR
#define FLASH_ADDR_ADC 0x30
#define ZMOD_ADC_IRQ XPAR_FABRIC_AXI_ZMODADC1410_0_LIRQOUT_INTR
#define DMA_ADC_IRQ XPAR_FABRIC_AXI_DMA_ADC_S2MM_INTROUT_INTR
//ZMOD DAC parameters
#define ZMOD_DAC_BASE_ADDR XPAR_AXI_ZMODDAC1411_V1_0_0_BASEADDR
#define DMA_DAC_BASE_ADDR XPAR_AXI_DMA_DAC_BASEADDR
#define FLASH_ADDR_DAC 0x31
#define DMA_DAC_IRQ XPAR_FABRIC_AXI_DMA_DAC_MM2S_INTROUT_INTR
#define IIC_BASE_ADDR XPAR_PS7_I2C_1_BASEADDR
//DMA for DDS output - XPAR_AXI_DMA_DDS_DEVICE_ID
#define MEM_BASE_ADDR (XPAR_PS7_DDR_0_S_AXI_BASEADDR + 0x1000000)
#define TRX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)
#define TRX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF)
/*
* Simple ADC test, puts the ADC in the test mode (ramp),
* performs an acquisition under specific trigger conditions
* and verifies the acquired data to be consistent with these conditions.
*/
void testZMODADC1410Ramp_Auto(){
ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_ADC,
ZMOD_ADC_IRQ, DMA_ADC_IRQ);
if(adcZmod.autoTestRamp(1, 0, 0, 4, TRANSFER_LEN) == ERR_SUCCESS){
xil_printf("Success autotest ADC ramp\r\n");
} else {
xil_printf("Error autotest ADC ramp\r\n");
}
}
/*
* Format data contained in the buffer and sends it over UART.
* It displays the acquired value (in mV), raw value (as 14 bits hexadecimal value)
* and time stamp within the buffer (in time units).
* @param padcZmod - pointer to the ZMODADC1410 object
* @param acqBuffer - the buffer containing acquired data
* @param channel - the channel where samples were acquired
* @param gain - the gain for the channel
* @param length - the buffer length to be used
*/
void formatADCDataOverUART(ZMODADC1410 *padcZmod, uint32_t *acqBuffer, uint8_t channel, uint8_t gain, size_t length){
char val_formatted[15];
char time_formatted[15];
uint32_t valBuf;
int16_t valCh;
float val;
xil_printf("New acquisition ------------------------\r\n");
xil_printf("Ch1\tRaw\tTime\t\r\n");
for (size_t i = 0; i < length; i++){
valBuf = acqBuffer[i];
valCh = padcZmod->signedChannelData(channel, valBuf);
val = padcZmod->getVoltFromSignedRaw(valCh, gain);
padcZmod->formatValue(val_formatted, 1000.0*val, "mV");
if (i < 100){
padcZmod->formatValue(time_formatted, i*10, "ns");
} else {
padcZmod->formatValue(time_formatted, (float)(i)/100.0, "us");
}
xil_printf("%s\t%X\t%s\r\n", val_formatted, (uint32_t)(valCh&0x3FFF), time_formatted);
}
}
/*
* Simple ADC test, acquires data and sends it over UART.
* @param channel - the channel where samples will be acquired
* @param gain - the gain for the channel
* @param length - the buffer length to be used
*/
void adcDemo(uint8_t channel, uint8_t gain, size_t length){
ZMODADC1410 adcZmod(ZMOD_ADC_BASE_ADDR, DMA_ADC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_ADC,
ZMOD_ADC_IRQ, DMA_ADC_IRQ);
uint32_t *acqBuffer;
adcZmod.setGain(channel, gain);
while(1){
acqBuffer = adcZmod.allocChannelsBuffer(length);
adcZmod.acquireImmediatePolling(acqBuffer, length);
formatADCDataOverUART(&adcZmod, acqBuffer, channel, gain, length);
adcZmod.freeChannelsBuffer(acqBuffer, length);
sleep(2);
}
}
int main(){
init_platform();
xil_printf("Eclypse Z7 SDR baseband data generator...\r\n");
// init DAC Zmod
ZMODDAC1411 dacZmod(ZMOD_DAC_BASE_ADDR, DMA_DAC_BASE_ADDR, IIC_BASE_ADDR, FLASH_ADDR_DAC, DMA_DAC_IRQ);
// max buffer length:
size_t length = 0x3fff;
dacZmod.setOutputSampleFrequencyDivider(2);
dacZmod.setGain(0, 1);
int Status = 0;
uint32_t *TrxBufferPtr;
TrxBufferPtr = dacZmod.allocChannelsBuffer(length);
for (int i=0;i<16383;i++){
TrxBufferPtr[i] = 0;
}
uint32_t *acqBufferPtr;
acqBufferPtr = dacZmod.allocChannelsBuffer(length);
Status = dacZmod.readInDDSdata(TrxBufferPtr, length, 1);
if (Status) {
xil_printf("DMA MM2S error!...\r\n");
}
int start_index = 0;
// copy the one period of sine wave into the buffer until its full
while (start_index<16000){
for (int i=0;i<50;i++){
acqBufferPtr[start_index+i] = TrxBufferPtr[i];
}
start_index = start_index + 50;
}
Status = dacZmod.sendDDSdataToDAC(acqBufferPtr, length);
if (Status) {
xil_printf("DMA S2MM error!...\r\n");
}
// start the instrument
dacZmod.start();
// free the buffers since it's been transferred to the DAC
dacZmod.freeChannelsBuffer(TrxBufferPtr, length);
dacZmod.freeChannelsBuffer(acqBufferPtr, length);
// start channel 0 of the ADC collecting infinitely
adcDemo(0, 0, length);
cleanup_platform();
return 0;
}
保存所有文件并構建項目。
要運行應用程序并同時查看 ILA,首先通過右鍵單擊資源管理器窗口中的應用程序名稱并選擇“Program FPGA”來對 Eclypse 進行編程。
請務必將比特流更改為新的比特流。當您單擊比特流字段旁邊的“搜索...”按鈕時,您會看到 Vitis 在項目中檢測到這兩者。
對 Ecylpse 進行編程后,再次右鍵單擊資源管理器窗口中的應用程序名稱并在“調(diào)試為”下選擇“在硬件上啟動(單個應用程序調(diào)試)”,啟動應用程序的調(diào)試運行。
一旦應用程序遇到主函數(shù)入口斷點,使用 Vitis 串行終端連接到 Eclypse 的 UART。
在單步執(zhí)行或運行應用程序之前,切換回 Vivado 并從 Flow Navigator 打開硬件管理器。從 Open Target 選項中選擇自動連接。
如果 ILA 窗口打開并且不存在調(diào)試內(nèi)核,您可能需要從硬件管理器重新編程 FPGA。我發(fā)現(xiàn)這是 Vivado 版本 2019.2 的一個錯誤。
在任何感興趣的 AXI 流協(xié)議上觸發(fā) ILA 中的觸發(fā)器并在 Vitis 中運行應用程序。我監(jiān)視了 DDS 編譯器的主 AXI 流端口和 DAC 的 DMA 的 AXI 流 S2MM 端口,以便在這個項目上進行調(diào)試。
一旦我能夠看到 ILA 中的正弦波環(huán)回工作以及 ADC ZMOD 的 UART 控制臺中的打印輸出,我決定啟動我的老式頻譜分析儀,它位于我書柜的頂部架子上,看看 1MHz 正弦波是什么波實際上看起來像是從 DAC 端口的 SMA 端口出來的。
我的頻譜分析儀實際上是用于電視維修的,因此射頻輸入為 75 歐姆,因此使用 75 至 50 歐姆的巴倫和一些適配器電纜將其 BNC 輸入轉(zhuǎn)換為 ZMOD 的 SMA 端口并獲得日蝕相連。
正如你所看到的,對于一個應該是單一頻率的純連續(xù)正弦波,它與一系列額外的頻率分量相當混亂。我確信這與我荒謬的長 SMA 電纜和破解連接轉(zhuǎn)換有關。該頻譜分析儀自 1984 年以來還沒有進行過正確校準,但使用它仍然可以很好地看到 DAC ZMOD 確實以 1MHz 的頻率發(fā)出了模擬信號。
我發(fā)現(xiàn)我擁有的 SMA 電纜比我擁有的任何 USB 電纜都長得多,所以我最終將信號分析儀留在了我的書架頂部,并將 Eclypse 板放在我的辦公桌窩上,放在我的電腦上。
為什么我擁有比 USB 電纜更長的 SMA 電纜???好問題。我自己剛剛發(fā)現(xiàn)了這個異常。
總體而言,可以以非常簡單的方式修改設計,使 DDS 編譯器的相位增量和偏移輸入可編程,并最終使用 ZMOD 制作出 Eclypse 的基帶數(shù)據(jù)生成器。我會把它保存到另一個項目教程中!
- 利用DAC實現(xiàn)正弦波輸出
- 使用單片機和DAC0832產(chǎn)生正弦波
- 基于STM32f103使用的DAC正弦波 113次下載
- 用超純正弦波振蕩器測試18位ADC
- 基于AD7226四進制DAC的AN-321:三相正弦波產(chǎn)生
- DAC輸出正弦波的實驗程序和工程文件免費下載 7次下載
- 實用電源技術叢書之正弦波逆變器 170次下載
- DAC—輸出正弦波 74次下載
- 正弦波逆變器基礎知識及應用 91次下載
- 基于SPWM的正弦波設計與實現(xiàn) 19次下載
- 正弦波數(shù)據(jù)生成器(正弦波表) 141次下載
- 正弦波發(fā)生電路基礎
- 使用集成運放LM324制作正弦波發(fā)生器
- 使用集成運放LM324制作正弦波發(fā)生器
- dsp正弦波發(fā)生器
- 示波器怎么調(diào)正弦波 1004次閱讀
- 方波 正弦波 三角波信號是如何產(chǎn)生的? 4655次閱讀
- 有源晶振的波形是正弦波嗎?怎么測量? 2283次閱讀
- 分享三個簡單的正弦波發(fā)生器電路 1.9w次閱讀
- 正弦波逆變器的判定方法_如何將正弦波變成方波 1.5w次閱讀
- 正弦波逆變器和修正波有什么不同 2.5w次閱讀
- 正弦波逆變器制作過程詳解 2w次閱讀
- 正弦波濾波器原理_正弦波濾波器的作用 2.6w次閱讀
- 正弦波逆變器原理_正弦波逆變器的優(yōu)缺點 3.3w次閱讀
- 通過觀察正弦波和無源元件來研究相位的概念 6131次閱讀
- 正弦波逆變器介紹_正弦波逆變器工作原理 4.9w次閱讀
- 純正弦波逆變器哪個好_純正弦波逆變器排行榜 9.2w次閱讀
- lc正弦波振蕩電路詳解_LC正弦波振蕩電路振蕩的判斷方法 4.3w次閱讀
- 正弦波信號發(fā)生器基本原理與設計 8.1w次閱讀
- 什么是正弦波逆變器_正弦波逆變器的工作原理及相關電路圖 8.6w次閱讀
下載排行
本周
- 1山景DSP芯片AP8248A2數(shù)據(jù)手冊
- 1.06 MB | 532次下載 | 免費
- 2RK3399完整板原理圖(支持平板,盒子VR)
- 3.28 MB | 339次下載 | 免費
- 3TC358743XBG評估板參考手冊
- 1.36 MB | 330次下載 | 免費
- 4DFM軟件使用教程
- 0.84 MB | 295次下載 | 免費
- 5元宇宙深度解析—未來的未來-風口還是泡沫
- 6.40 MB | 227次下載 | 免費
- 6迪文DGUS開發(fā)指南
- 31.67 MB | 194次下載 | 免費
- 7元宇宙底層硬件系列報告
- 13.42 MB | 182次下載 | 免費
- 8FP5207XR-G1中文應用手冊
- 1.09 MB | 178次下載 | 免費
本月
- 1OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 2555集成電路應用800例(新編版)
- 0.00 MB | 33566次下載 | 免費
- 3接口電路圖大全
- 未知 | 30323次下載 | 免費
- 4開關電源設計實例指南
- 未知 | 21549次下載 | 免費
- 5電氣工程師手冊免費下載(新編第二版pdf電子書)
- 0.00 MB | 15349次下載 | 免費
- 6數(shù)字電路基礎pdf(下載)
- 未知 | 13750次下載 | 免費
- 7電子制作實例集錦 下載
- 未知 | 8113次下載 | 免費
- 8《LED驅(qū)動電路設計》 溫德爾著
- 0.00 MB | 6656次下載 | 免費
總榜
- 1matlab軟件下載入口
- 未知 | 935054次下載 | 免費
- 2protel99se軟件下載(可英文版轉(zhuǎn)中文版)
- 78.1 MB | 537798次下載 | 免費
- 3MATLAB 7.1 下載 (含軟件介紹)
- 未知 | 420027次下載 | 免費
- 4OrCAD10.5下載OrCAD10.5中文版軟件
- 0.00 MB | 234315次下載 | 免費
- 5Altium DXP2002下載入口
- 未知 | 233046次下載 | 免費
- 6電路仿真軟件multisim 10.0免費下載
- 340992 | 191187次下載 | 免費
- 7十天學會AVR單片機與C語言視頻教程 下載
- 158M | 183279次下載 | 免費
- 8proe5.0野火版下載(中文版免費下載)
- 未知 | 138040次下載 | 免費
評論
查看更多