FPGA进阶篇--SPI控制双通道16bit串行DAC8532
文章目錄
- 一、芯片手冊關鍵點筆記
- 1、時序
- 2、寄存器
- 二、FPGA控制DAC8532驅動
- DAC8532_drive_project
- DAC8532_DATA_Ctrl模塊:
- spi_data_transfer模塊:
- 仿真:
- 約束:
- 仿真結果:
- 門級仿真:
- signaltap在線調試
- 三、福利:工程鏈接
一、芯片手冊關鍵點筆記
1、時序
2、寄存器
看完了,時序部分,我們來看看寄存器部分,通過配置寄存器,可以控制我們的輸出,所以寄存器也非常重要。
這里就說了,如果SYNC(取反)信號的突然上升,在數據還沒有傳完的時候就上升,這種中斷的方式,數據緩沖器內容,DAC寄存器內容的更新或操作模式的更改都不會發生,已經寫入的這一段數據都會被丟棄,移位寄存器會重新置位。
上圖為這幾種模式的介紹,我們一般來說用正常模式就行,其余模式,可以根據實際需求更改。
上圖是三種powerdown模式,但是我們一般就設置為00,正常模式即可,不需要用到powerdown模式
下面,還給出了操作的例子
例子1是在等待兩個24sclk序列加載完畢后,此時,A B 的寄存器都加載了數據后,再同時進行數模轉換。
例子2是24個SCLK加載完數據到A后,立馬就開始輸出,第二個SCLK加載完數據到B后,B開始輸出。
二、FPGA控制DAC8532驅動
時隔3天,終于調好了程序,非常適合幾乎所有的SPI控制的ADC和DAC芯片。
只需要改動參數parameter即可。
這也是我寫程序的一個良好習慣,盡量參數化,盡量讓寫過的程序以后復用,而不要今天用SPI寫一次,隔天換了個DA的時序,也是SPI控制的,又用SPI再寫一次,這樣效率相當低下,盡量一次就寫好,寫工整。
軟件:quartus 13.1
modelsim 10.1 c
代碼:
頂層模塊
DAC8532_drive_project
//功能描述:驅動雙通道16bit的DAC同時產生正弦波形,或者三角波形 //author: ciscomonkey //思路分析:組合控制+數據,組合完畢,發出傳輸指令,SPI模塊開始傳輸,傳輸完畢信號給控制模塊,控制模塊接收到傳輸完畢信號, //進入等待DA芯片的轉換時間,等待結束,再次進入組合狀態。 `timescale 1 ns/ 1 ns module DAC8532_drive_project # ( parameter data_width=24,//控制+DAC_data數據長度 parameter DAC_data_width=16,//DAC_data數據長度 parameter wait_conversion_time=10,//轉換時間,100M(10ns),100ns parameter SPI_RATE=10_000_000, parameter CLOCK_RATE=100_000_000 ) ( input clk, input rst, input start, //觸發啟動程序input switch, //波形選擇,1為電平1,2為電平2output sclk, //輸出時鐘信號output SYNC_n, //輸出同步信號output Din //輸出數據 ); // // // //reg [DAC_data_width-1:0] voltage_1_reg=16'b1010_1010_1010_1010; reg [DAC_data_width-1:0] voltage_2_reg=16'b0101_0101_0101_0101; wire [DAC_data_width-1:0] voltage_1; wire [DAC_data_width-1:0] voltage_2;assign voltage_1=voltage_1_reg; assign voltage_2=voltage_2_reg;wire [DAC_data_width-1:0] DAC_a_data = switch ? voltage_1 : voltage_2; wire [DAC_data_width-1:0] DAC_b_data = switch ? voltage_1 : voltage_2; wire spi_data_done; wire mosi; wire start_spi; wire [data_width-1:0] miso_data_reg; wire [data_width-1:0] data_reg; wire write_busy; wire data_DAC_ab_finish; //------------------------------------------------------------- DAC8532_DATA_Ctrl # ( .data_width(data_width),//控制+DAC_data數據長度.DAC_data_width(DAC_data_width),//DAC_data數據長度.wait_conversion_time(wait_conversion_time) )DAC8532_DATA_Ctrl_inst ( .clk(clk), .rst(rst), .DAC_a_data(DAC_a_data), .DAC_b_data(DAC_b_data), .start(start), //啟動DAC8532 .spi_data_done(spi_data_done), //24位寬的數據傳輸完的標志.data_reg(data_reg), //串行輸出一幀數據(控制+數據) .start_spi(start_spi), //組合好一幀數據后開始傳輸命令 .data_DAC_ab_finish(data_DAC_ab_finish) );//----------------------------------------------------------------------spi_data_transfer # (.data_width(data_width) , // SPI一次寫入數據長度.SPI_RATE(SPI_RATE) , // SPI時鐘速率.CLOCK_RATE(CLOCK_RATE) // 系統時鐘速率)spi_data_transfer_inst ( .clk(clk), .rst(rst), .data_reg(data_reg), //輸入數據,用于mosi .start_spi(start_spi),//開啟傳輸指令 .miso_data_reg(miso_data_reg), //miso,主機(FPGA)接收的數據,從機發送 .miso(0), .sclk(sclk), //時鐘 .write_busy(write_busy), //寫入繁忙 .spi_data_done(spi_data_done), //數據傳輸完的標志 .mosi(mosi), //主發從收,主機(FPGA)發送,從機接收 .SYNC_n(SYNC_n)); assign Din=mosi;endmoduleDAC8532_DATA_Ctrl模塊:
//功能描述:驅動雙通道16bit的DAC同時產生正弦波形,或者三角波形 //author: ciscomonkey //思路分析:組合控制+數據,組合完畢,發出傳輸指令,SPI模塊開始傳輸,傳輸完畢信號給控制模塊,控制模塊接收到傳輸完畢信號, //進入等待DA芯片的轉換時間,等待結束,再次進入組合狀態。 `timescale 1 ns/ 1 ns module DAC8532_drive_project # ( parameter data_width=24,//控制+DAC_data數據長度 parameter DAC_data_width=16,//DAC_data數據長度 parameter wait_conversion_time=15,//轉換時間,100M(10ns),100ns parameter SPI_RATE=10_000_000, parameter CLOCK_RATE=100_000_000 ) ( input clk, input rst, input start, //觸發啟動程序input switch, //波形選擇,1為電平1,2為電平2output sclk, //輸出時鐘信號output SYNC_n, //輸出同步信號 // output [5:0] next_state_test, //狀態機測試信號 output [5:0] now_state_test,output Din //輸出數據 ); // // // //reg [DAC_data_width-1:0] voltage_1_reg=16'b1010_1010_1010_1010; reg [DAC_data_width-1:0] voltage_2_reg=16'b0101_0101_0101_0101; wire [DAC_data_width-1:0] voltage_1; wire [DAC_data_width-1:0] voltage_2;assign voltage_1=voltage_1_reg; assign voltage_2=voltage_2_reg;wire [DAC_data_width-1:0] DAC_a_data = switch ? voltage_1 : voltage_2; wire [DAC_data_width-1:0] DAC_b_data = switch ? voltage_1 : voltage_2; wire spi_data_done; wire mosi; wire start_spi; wire [data_width-1:0] miso_data_reg; wire [data_width-1:0] data; wire write_busy; wire data_DAC_ab_finish; //------------------------------------------------------------- DAC8532_DATA_Ctrl # ( .data_width(data_width),//控制+DAC_data數據長度.DAC_data_width(DAC_data_width),//DAC_data數據長度.wait_conversion_time(wait_conversion_time) )DAC8532_DATA_Ctrl_inst ( .clk(clk), .rst(rst), .DAC_a_data(DAC_a_data), .DAC_b_data(DAC_b_data), .start(start), //啟動DAC8532 .spi_data_done(spi_data_done), //24位寬的數據傳輸完的標志 .now_state_test(now_state_test), .next_state_test(next_state_test),.data(data), //串行輸出一幀數據(控制+數據) .start_spi(start_spi), //組合好一幀數據后開始傳輸命令 .data_DAC_ab_finish(data_DAC_ab_finish) );//----------------------------------------------------------------------spi_data_transfer # (.data_width(data_width) , // SPI一次寫入數據長度.SPI_RATE(SPI_RATE) , // SPI時鐘速率.CLOCK_RATE(CLOCK_RATE) // 系統時鐘速率)spi_data_transfer_inst ( .clk(clk), .rst(rst), .data_reg(data), //輸入數據,用于mosi .start_spi(start_spi),//開啟傳輸指令 .miso_data_reg(miso_data_reg), //miso,主機(FPGA)接收的數據,從機發送 .miso(0), .sclk(sclk), //時鐘 .write_busy(write_busy), //寫入繁忙 .spi_data_done(spi_data_done), //數據傳輸完的標志 .mosi(mosi), //主發從收,主機(FPGA)發送,從機接收 .SYNC_n(SYNC_n)); assign Din=mosi;endmodulespi_data_transfer模塊:
//module:DAC8532_DATA_Ctrl //author:Ciscomonkey //functional description:提供mosi的數據,用于傳輸,發出傳輸指令則可以開啟傳輸,并控制好時序,在傳輸完畢后,等待轉換時間 `timescale 1 ns/ 1 ns module DAC8532_DATA_Ctrl # ( parameter data_width=24,//控制+DAC_data數據長度parameter DAC_data_width=16,//DAC_data數據長度parameter wait_conversion_time=15//A通道傳輸后,轉換時間至少100ns(100M(10ns)),實際測試:+1 ) ( input clk, input rst, input [DAC_data_width-1:0] DAC_a_data, input [DAC_data_width-1:0] DAC_b_data, input start,//啟動DAC8532 input spi_data_done, //24位寬的數據傳輸完的標志output [data_width-1:0] data, //串行輸出一幀數據(控制+數據) output start_spi, //組合好一幀數據后開始傳輸命令 output [5:0] now_state_test, output [5:0] next_state_test, output data_DAC_ab_finish //conversion轉換結束標志 );reg start_spi_reg; reg [data_width-1:0] data_reg; reg data_DAC_ab_finish_reg; //狀態機 三段式localparam IDLE_state=6'b000_000; localparam combine_DAC_a_data_state=6'b000_001; //控制+DAC_a_data localparam spi_DAC_A_trans_state=6'b000_010; //A通道SPI的傳輸 localparam conversion_DAC_a_data_state=6'b00_100; //DAC_a_data的轉換等待時間 localparam combine_DAC_b_data_state=6'b001_000; //控制+DAC_b_data localparam spi_DAC_B_trans_state=6'b010_000; //B通道SPI的傳輸 localparam conversion_DAC_b_data_state=6'b100_000; //DAC_b_data的轉換等待時間reg [5:0] now_state=IDLE_state; reg [5:0] next_state=IDLE_state;//---------- assign now_state_test=now_state; assign next_state_test=next_state; reg [DAC_data_width-1:0] conversion_time_cnt='d0;//1、實現狀態轉換 always @ (posedge clk or negedge rst) beginif(!rst) //低電平復位now_state<=IDLE_state;elsenow_state<=next_state; end//2、根據條件產生下一個狀態 always@(*) begincase(now_state)IDLE_state:beginif(start)beginnext_state=combine_DAC_a_data_state; endelsebeginnext_state=IDLE_state;endendcombine_DAC_a_data_state:beginnext_state=spi_DAC_A_trans_state; endspi_DAC_A_trans_state:beginif(spi_data_done)//如果傳輸完畢,則進入轉換狀態next_state=conversion_DAC_a_data_state; elsenext_state=spi_DAC_A_trans_state;endconversion_DAC_a_data_state:beginif(conversion_time_cnt==wait_conversion_time-1)beginnext_state=combine_DAC_b_data_state; endelsebeginnext_state=conversion_DAC_a_data_state; endendcombine_DAC_b_data_state:beginnext_state=spi_DAC_B_trans_state;endspi_DAC_B_trans_state:beginif(spi_data_done)//如果傳輸完畢next_state=conversion_DAC_b_data_state;elsenext_state=spi_DAC_B_trans_state;endconversion_DAC_b_data_state:beginif(conversion_time_cnt==wait_conversion_time-1)beginnext_state=IDLE_state; //如果需要傳輸多個數據,比如正弦,那么就next_state回到combine_DAC_a_data_state endelsebegin next_state=conversion_DAC_b_data_state;end endendcaseend //3、狀態條件輸出 always @ (posedge clk) begincase(next_state)IDLE_state:beginconversion_time_cnt<='d0;data_reg<='d0;//用于組合數據(控制+數據)start_spi_reg<=0;endcombine_DAC_a_data_state:begindata_reg<={2'b00, 2'b00, 1'b0, 1'b0, 2'b0, DAC_a_data}; start_spi_reg<=1;//發出傳輸數據指令endspi_DAC_A_trans_state:beginstart_spi_reg<=0;endconversion_DAC_a_data_state:beginconversion_time_cnt<=conversion_time_cnt+1'd1;endcombine_DAC_b_data_state:beginconversion_time_cnt<=0;data_reg<={2'b00, 2'b11, 1'b0, 1'b1, 2'b0, DAC_b_data}; start_spi_reg<=1;//發出傳輸數據指令 endspi_DAC_B_trans_state:beginstart_spi_reg<=0;endconversion_DAC_b_data_state:beginconversion_time_cnt<=conversion_time_cnt+1'd1;endendcaseend //4、每個狀態輸出的值 always @ (posedge clk)//data_DAC_ab_finish轉換完畢的標志 beginif(conversion_time_cnt==wait_conversion_time-1)data_DAC_ab_finish_reg<=1;elsedata_DAC_ab_finish_reg<=0; end// assign start_spi=start_spi_reg; assign data=data_reg; assign data_DAC_ab_finish=data_DAC_ab_finish_reg; endmodule仿真:
// Copyright (C) 1991-2013 Altera Corporation // Your use of Altera Corporation's design tools, logic functions // and other software and tools, and its AMPP partner logic // functions, and any output files from any of the foregoing // (including device programming or simulation files), and any // associated documentation or information are expressly subject // to the terms and conditions of the Altera Program License // Subscription Agreement, Altera MegaCore Function License // Agreement, or other applicable license agreement, including, // without limitation, that your use is for the sole purpose of // programming logic devices manufactured by Altera and sold by // Altera or its authorized distributors. Please refer to the // applicable agreement for further details.// ***************************************************************************** // This file contains a Verilog test bench template that is freely editable to // suit user's needs .Comments are provided in each section to help the user // fill out necessary details. // ***************************************************************************** // Generated on "02/28/2019 16:07:31"// Verilog Test Bench template for design : DAC8532_drive_project // // Simulation tool : ModelSim (Verilog) // `timescale 1 ns/ 1 ns module DAC8532_drive_project_vlg_tst(); // constants // general purpose registers reg eachvec; // test vector input registers reg clk; reg rst; reg start; reg switch; // wires wire Din; wire SYNC_n; wire [5:0] next_state_test; wire [5:0] now_state_test; wire sclk;// assign statements (if any) DAC8532_drive_project i1 ( // port map - connection between master ports and signals/registers .Din(Din),.SYNC_n(SYNC_n),.clk(clk),.next_state_test(next_state_test),.now_state_test(now_state_test),.rst(rst),.sclk(sclk),.start(start),.switch(switch) ); initial begin #0 clk=0; #0 rst=0; #0 start=0;#10 switch=1; #60 rst=1; #100 start=1; #110 start=0;end always #5 begin clk<=~clk; end endmodule約束:
create_clock -name {clk} -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]derive_pll_clocks derive_clock_uncertainty仿真結果:
兩個通道,同時輸出一個電壓,有兩種電壓選擇(根據switch 0 or 1)
第一個給了一個start,
先給一個start,然后隔了一段時間,再給一個start。
每start一次,就傳輸一次。
下圖,兩個通道均輸出16‘b1010101010101010的電壓
門級仿真:
signaltap在線調試
注意:
//wire start=1;如果要使用signal_tap在線調試沒有外部觸發,就把這個start一直置位為1即可
經過測試:即使主頻時鐘設置為跑到200M,也不會出現時序違規
三、福利:工程鏈接
https://download.csdn.net/download/ciscomonkey/10981766
總結
以上是生活随笔為你收集整理的FPGA进阶篇--SPI控制双通道16bit串行DAC8532的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SPI配置8通道ADC128S022
- 下一篇: 记录一次quartus II prime