fpga dac8830驱动

dac8830是一种16分辨率的基于spi通信的dac模块,且spi时钟速率最高50mhz,支持单极性与双极性输出,支持5v和10v两种挡位,制作成电子模块后的样子如下

通过黄色跳线帽来决定输出幅度和极性,所谓极性可以简单理解为,单极性会输出0v以上的直流电,双极性输出正负电压的交流电

时序图如下,可以看到只是一个简单的spi协议

由于电子模块采用双通道,因此要交替执行cs1和cs2的片选,代码如下


module da8830_driver(
	input				i_clk		,
	input				i_rst		,
	input				i_da_en		,
	input		[15:0]	i_cha_data	,
	input		[15:0]	i_chb_data	,
	input				i_cha_dvld	,
	input				i_chb_dvld	,
	output	reg			o_cha_cs	,
	output	reg			o_chb_cs	,
	output				o_mosi		,
	output	reg			o_sclk		,
	output				o_ready
    );
	
	localparam	S_IDLE 		= 4'b0001,
				S_CS_DOWN	= 4'b0010,
				S_DATA		= 4'b0100,
				S_CS_UP		= 4'b1000;
	
	reg		[3:0]	r_cstate	;
	reg		[3:0]	r_nstate	;
	
	wire 			w_busy		;
	assign	w_busy = r_cstate == S_DATA;
	assign	o_ready = r_cstate == S_IDLE;

	// 分频计数器
	reg		[1:0]	r_clk_cnt	;
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst)
			r_clk_cnt <= 'd0;
		else if(r_cstate == S_DATA)
			r_clk_cnt <= r_clk_cnt + 1;
		else
			r_clk_cnt <= 'd0;
	end
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst)
			o_sclk <= 'b0;
		else if(r_cstate == S_DATA)
			o_sclk <= r_clk_cnt[0] ? ~o_sclk : o_sclk;
		else 
			o_sclk <= 'b0;
	end
	//通道选择
	reg			r_ch_sel	;
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst)
			r_ch_sel <= 'b0;
		else if(r_cstate == S_CS_UP)
			r_ch_sel <= !r_ch_sel;
		else
			r_ch_sel <= r_ch_sel;
	end
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst) begin
			o_cha_cs <= 'b1;
			o_chb_cs <= 'b1;
		end
		else if(r_cstate == S_CS_UP) begin
			o_cha_cs <= 'b1;
			o_chb_cs <= 'b1;
		end
		else if(r_cstate == S_CS_DOWN) begin
			o_cha_cs <= r_ch_sel ? 'b1 : 'b0;
			o_chb_cs <= r_ch_sel ? 'b0 : 'b1;	
		end
		else begin
			o_cha_cs <= o_cha_cs;
			o_chb_cs <= o_chb_cs;
		end
	end
	//数据
	reg		[15:0]	r_cha_data	;
	reg		[15:0]	r_chb_data	;
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst) begin
			r_cha_data <= 'd0;
			r_chb_data <= 'd0;
		end
		else if(w_busy & r_clk_cnt == 2'b11) begin
			r_cha_data <= r_ch_sel ? r_cha_data : r_cha_data << 1;
			r_chb_data <= r_ch_sel ? r_chb_data << 1 : r_chb_data;
		end
		else begin
			r_cha_data <= i_cha_dvld ? i_cha_data : r_cha_data;
			r_chb_data <= i_chb_dvld ? i_chb_data : r_chb_data;
		end
	end
	
	assign o_mosi = r_ch_sel ? r_chb_data[15] : r_cha_data[15];
	
	reg		[3:0]	r_bit_cnt	;
	wire			w_txdone	;
	
	assign	w_txdone = r_clk_cnt == 2'b10 & r_bit_cnt == 4'b1111;
	
	always@(posedge i_clk or posedge i_rst) begin
        if(i_rst)
            r_bit_cnt <= 'd0;
        else if(r_cstate == S_DATA)
            r_bit_cnt <= r_clk_cnt == 2'b11 ? r_bit_cnt + 1 : r_bit_cnt;
        else
            r_bit_cnt <= 'd0;
    end
	
	always@(posedge i_clk or posedge i_rst) begin
		if(i_rst)	
			r_cstate <= S_IDLE;
		else
			r_cstate <= r_nstate;
	end
	
	always@(*) begin
		case(r_cstate)
			S_IDLE:		r_nstate = i_da_en ? S_CS_DOWN : S_IDLE;
			S_CS_DOWN:	r_nstate = S_DATA;
			S_DATA:		r_nstate = w_txdone ? S_CS_UP : S_DATA;
			S_CS_UP:	r_nstate = r_ch_sel ? S_IDLE : S_CS_DOWN;
			default:r_nstate = S_IDLE;
		endcase
	end
	
endmodule

采用下面代码测试

`timescale 1ns / 1ps

module test_top(
	input			i_clk	,
	input			i_rst_n	,
	output			o_mosi	,
	output			o_cha_cs,
	output			o_chb_cs,
	output			o_sclk	
    );
	
	wire 		w_clk200m;
	wire		w_clk200m_lked;
clk_wiz_0 
mmcm(
    .clk_out1	(w_clk200m	),   
    .reset		(!i_rst_n	),   
    .locked		(w_clk200m_lked),       // output locked
    .clk_in1	(i_clk		)
);      
	
	reg		[15:0]	r_cha_data	;
	reg		[15:0]	r_chb_data	;
	reg				r_cha_dvld	;
	reg				r_chb_dvld	;
	
	wire			w_ready		;
	wire 			w_dds_ovld	;
	wire	[31:0]	w_dds_out	;
	
	reg		[31:0]	r_dds_out	;
	always@(posedge w_clk200m or negedge w_clk200m_lked) begin
		if(~w_clk200m_lked) 
			r_dds_out <= 'd0;
		else if(w_dds_ovld)
			r_dds_out <= w_dds_out;
		else 
			r_dds_out <= r_dds_out;
	end
	
	always@(posedge w_clk200m or negedge w_clk200m_lked) begin
		if(~w_clk200m_lked) begin
			r_cha_data <= 'd0;
			r_chb_data <= 'd0;
			r_cha_dvld <= 'd0;
			r_chb_dvld <= 'd0;
		end
		else if(w_ready) begin
			r_cha_data <= $signed(r_dds_out[31:16]) + $signed(16'h8000);
			r_chb_data <= $signed(r_dds_out[15:0]) + $signed(16'h8000);
			r_cha_dvld <= 'd1;
			r_chb_dvld <= 'd1;
		end
		else begin
			r_cha_data <= r_cha_data;
			r_chb_data <= r_chb_data;
			r_cha_dvld <= 'd0;
			r_chb_dvld <= 'd0;
		end
	end
	
dds_200m 
dds (
	.aclk				(w_clk200m	),	// input wire aclk
	.aresetn			(w_clk200m_lked),   
	.m_axis_data_tvalid	(w_dds_ovld	),	// output wire m_axis_data_tvalid
	.m_axis_data_tdata	(w_dds_out	)	// output wire [31 : 0] m_axis_data_tdata
);
da8830_driver
da8830_driver_u(
	.i_clk		(w_clk200m	),
	.i_rst		(!w_clk200m_lked	),
	.i_da_en	(w_clk200m_lked	),
	.i_cha_data	(r_cha_data	),
	.i_chb_data	(r_chb_data	),
	.i_cha_dvld	(r_cha_dvld	),
	.i_chb_dvld	(r_chb_dvld	),
	.o_cha_cs	(o_cha_cs	),
	.o_chb_cs	(o_chb_cs	),
	.o_mosi		(o_mosi		),
	.o_sclk		(o_sclk		),
	.o_ready    (w_ready	)
);
ila_1 your_instance_name (
	.clk(w_clk200m), // input wire clk


	.probe0(r_cha_data), // input wire [15:0]  probe0  
	.probe1(r_chb_data), // input wire [15:0]  probe1 
	.probe2(w_dds_ovld) // input wire [0:0]  probe2
);

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值