我是靠谱客的博主 纯情发带,最近开发中收集的这篇文章主要介绍FM调制解调---FPGA,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

        实验通过编写一个DMA读模块获取FM调制的数据源,DMA模块的实现是基于AXI协议。因为在数据的传输中,Xilinx提供的官方DMA IP核在传输完一次突发数据后需要在PS 端重新启动一次都或者写操作,如此的话,在进行大量数据的传输工作时,尤其是对DDR 不同地址区域同时进行读写操作时,IP 核不能有效工作。所以通过创建一个模块用于读取DDR,无需PS端参与即可完成读DDR操作。

 AXI_DMA_RD模块突发读时序:

        该模块读取的内容是先由PS端提前写入DDR某一地址区间的音频数据,按照AXI突发读时序进行数据读取,同时需要添加FIFO IP核来完成数据位宽转换和跨时钟域处理。为了防止数据丢失,当判断FIFO写入数据计数器为0,才启动一次突发读DDR。

 FIFO 读时序:

         FM调制模块:

        依据调频信号的数学表达式:

        

        实现图中公式高亮部分,需要用到两个ROM IP用于存放正余弦波形,正余弦波形可由matlab获得,以及一个乘法器IP完成调制中的乘法操作。

c = 0:1/1024:1023/1024; %ROM 中有 1024 点
c_rom = fix(1024*sin(2*pi*c));
%c_rom = fix(1024*cos(2*pi*c));

         重要参数:调频灵敏度Kf 和 最大频偏频率控制字 W

         

         FM解调模块:

        首先用两个寄存器将接收到的 I Q 两路数据进行缓存,再用两个寄存器进行延时一拍,就可以得到 i(i)i(i-1)q(i)q(i-1),再调用乘法器完成乘法运算,再将乘法器结果进行加减运算,再进行除法,即可得到解调结果。

        

module fm_demod(
		input	wire 			sclk,
		input	wire 			rst_n,
		input	wire 			adc_valid,
		input	wire 	[11:0]	adc_data_i,
		input	wire 	[11:0]	adc_data_q,
		input	wire 	[31:0]	end_count,

		output	reg 			dmsout,
		output	reg		[15:0]	dmout

	);

reg 	[11:0]	i_fm=0,q_fm=0,i_fm_r=0,q_fm_r=0;
reg 	isin,isin_r;
wire  [23:0] cr1,cr2,cj1,cj2;
reg 	[23:0] cr,cj;
reg 			flag1=0;
reg 	[23:0]	cjabs=0;
reg 	[23:0]	cj_r,cr_r;
reg 			flag2;
reg 	[23:0]	dividend=0;
reg 	[23:0]	divisor =1;
reg 			flag3;
wire 			div_valid;
wire 	[39:0]  div_dout;
reg 	[23:0]	cr_r3,cj_r3;
wire 	[23:0]	cr_fifo_data,cj_fifo_data;
reg 	[39:0]	angle=0;	
reg 			div_valid_r;	
wire 	[15:0]	pi4;
wire 	[55:0]	angle_r;
reg 	[23:0]	cj_r4;
reg 	[23:0]	cj_r5;
reg 	[55:0]	angle_dout;		
reg 			div_valid_rr;
reg 			angel_dsout;
reg 	[11:0]		cnt_mean;
reg 	[49:0]	dm_sum;

reg		[11:0]	i_data,q_data;
wire	[11:0]	i_data_16,q_data_16;
reg				adc_valid_r;


// LPF
assign i_data_16 = {i_data[11],i_data[11],i_data[11],i_data[11],i_data[11:4]};
assign q_data_16 = {q_data[11],q_data[11],q_data[11],q_data[11],q_data[11:4]};
always @(posedge sclk) begin
	if (rst_n == 1'b0) begin		// reset
		i_data	<=	0;
		q_data	<=	0;
	 end
	else if (adc_valid == 1'b1) begin
		i_data	<=	{adc_data_i[11],adc_data_i[11],adc_data_i[11],adc_data_i[11],adc_data_i[11:4]} + i_data - i_data_16;
		q_data	<=	{adc_data_q[11],adc_data_q[11],adc_data_q[11],adc_data_q[11],adc_data_q[11:4]} + q_data - q_data_16;
	 end
end

always @(posedge sclk) begin
	adc_valid_r <= adc_valid;
end


always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		{i_fm_r,i_fm} <= 'd0;
		{q_fm_r,q_fm} <= 'd0;
	end
	else if(adc_valid_r == 1'b1) begin
		{i_fm_r,i_fm} <= {i_fm,i_data};
		{q_fm_r,q_fm} <= {q_fm,q_data};
	end
end

always @(posedge sclk) begin
	{isin_r,isin} <= {isin,adc_valid_r};
end

mult_crcj mult_cr1 (
  .CLK(sclk),  // input wire CLK
  .A(i_fm),      // input wire [11 : 0] A
  .B(i_fm_r),      // input wire [11 : 0] B
  .P(cr1)      // output wire [23 : 0] P
);

mult_crcj mult_cr2 (
  .CLK(sclk),  // input wire CLK
  .A(q_fm),      // input wire [11 : 0] A
  .B(q_fm_r),      // input wire [11 : 0] B
  .P(cr2)      // output wire [23 : 0] P
);


mult_crcj mult_cj1 (
  .CLK(sclk),  // input wire CLK
  .A(q_fm),      // input wire [11 : 0] A
  .B(i_fm_r),      // input wire [11 : 0] B
  .P(cj1)      // output wire [23 : 0] P
);

mult_crcj mult_cj2 (
  .CLK(sclk),  // input wire CLK
  .A(i_fm),      // input wire [11 : 0] A
  .B(q_fm_r),      // input wire [11 : 0] B
  .P(cj2)      // output wire [23 : 0] P
);

always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		cr <= 'd0;
		cj <= 'd0;
	end
	else begin
		cr <= cr1+ cr2;
		cj <= cj1-cj2;
	end
end

always @(posedge sclk) begin
	flag1 <= isin_r;
end

always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		cjabs <= 'd0;
	end
	else if (flag1 == 1'b1 && cj[23] == 1'b1 ) begin
		cjabs <= (~cj) +1'b1;
	end
	else if (flag1 == 1'b1 && cj[23] == 1'b0 ) begin
		cjabs <= cj;
	end
end

always @(posedge sclk) begin
	{cj_r,cr_r} <= {cj,cr};
end

always @(posedge sclk) begin
	flag2 <= flag1;
end


always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		dividend <='d0;
		divisor <= 'd1;
	end
	else if (flag2 == 1'b1 && cr_r[23] == 1'b0) begin
		dividend <= cr_r - cjabs;
		divisor <= cr_r + cjabs;
	end
	else if (flag2 == 1'b1 && cr_r[23] == 1'b1) begin
		dividend <= cr_r + cjabs;
		divisor <= cjabs - cr_r;
	end
end

always @(posedge sclk) begin
	flag3 <= flag2;
end

div_gen_0 div_gen_0_inst (
  .aclk(sclk),                                      // input wire aclk
  .s_axis_divisor_tvalid(flag3),    // input wire s_axis_divisor_tvalid
  .s_axis_divisor_tdata(divisor),      // input wire [23 : 0] s_axis_divisor_tdata
  .s_axis_dividend_tvalid(flag3),  // input wire s_axis_dividend_tvalid
  .s_axis_dividend_tdata(dividend),    // input wire [23 : 0] s_axis_dividend_tdata
  .m_axis_dout_tvalid(div_valid),          // output wire m_axis_dout_tvalid
  .m_axis_dout_tdata(div_dout)            // output wire [39 : 0] m_axis_dout_tdata
);

always @(posedge sclk) begin
	cr_r3 <= cr_r;
	cj_r3 <= cj_r;
end


fifo_w24x64_r24x64 cr_buffer (
  .clk(sclk),      // input wire clk
  .din(cr_r3),      // input wire [23 : 0] din
  .wr_en(flag3),  // input wire wr_en
  .rd_en(div_valid),  // input wire rd_en
  .dout(cr_fifo_data),    // output wire [23 : 0] dout
  .full(),    // output wire full
  .empty()  // output wire empty
);

fifo_w24x64_r24x64 cj_buffer (
  .clk(sclk),      // input wire clk
  .din(cj_r3),      // input wire [23 : 0] din
  .wr_en(flag3),  // input wire wr_en
  .rd_en(div_valid),  // input wire rd_en
  .dout(cj_fifo_data),    // output wire [23 : 0] dout
  .full(),    // output wire full
  .empty()  // output wire empty
);

always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		angle <='d0;
	end
	else if(div_valid == 1'b1 && cr_fifo_data == 'd0 && cj_fifo_data == 'd0) begin
		angle <='d0;
	end
	else if (div_valid == 1'b1 && cr_fifo_data[23] == 1'b0) begin
		angle <= 40'd65536 - div_dout;
	end
	else if(div_valid == 1'b1 && cr_fifo_data[23] == 1'b1) begin
		angle <= 40'd196608 - div_dout;
	end
end


always @(posedge sclk) begin
	div_valid_r <= div_valid;
end

assign pi4 =16'd51472;//PI/4  (3.1415926/4)*65536
mult_a40xb16 mult_a40xb16_inst (
  .CLK(sclk),  // input wire CLK
  .A(angle),      // input wire [39 : 0] A
  .B(pi4),      // input wire [15 : 0] B
  .P(angle_r)      // output wire [55 : 0] P
);

always @(posedge sclk) begin
	cj_r4 <= cj_fifo_data;
end

always @(posedge sclk) begin
	cj_r5 <= cj_r4;
end

always @(posedge sclk) begin
	div_valid_rr <= div_valid_r;
end

always @(posedge sclk) begin
	if(rst_n==  1'b0) begin
		angle_dout <='d0;
	end
	else if (div_valid_rr == 1'b1 &&  cj_r5[23] == 1'b0) begin
		angle_dout <= angle_r;
	end
	else if (div_valid_rr == 1'b1 &&  cj_r5[23] == 1'b1) begin
		angle_dout <= (~angle_r) + 1'b1;
	end
end

always @(posedge sclk) begin
	angel_dsout <= div_valid_rr;
end

always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		cnt_mean <='d0;
	end
	else if (angel_dsout == 1'b1 && cnt_mean == end_count[12:1]-1) begin
		cnt_mean <= 'd0;
	end
	else if (angel_dsout == 1'b1) begin
		cnt_mean <= cnt_mean + 1'b1;
	end
end

always @(posedge sclk)begin
	if(rst_n == 1'b0) begin
		dm_sum <= 'd0;
	end
	else if (angel_dsout == 1'b1 && cnt_mean == end_count[12:1]-1) begin
		dm_sum <='d0;
	end
	else if (angel_dsout == 1'b1 ) begin
		dm_sum <= dm_sum + {{10{angle_dout[55]}},angle_dout[55:16]};
	end
end

always @(posedge sclk) begin
	if(rst_n == 1'b0) begin
		dmout <='d0;
		dmsout <= 'd0;
	end
	else if (angel_dsout == 1'b1 && cnt_mean == end_count[12:1]-1) begin
		dmout <= {dm_sum[49],dm_sum[24:10]};
		dmsout <= 1'b1;
	end
	else begin
		dmsout <= 1'b0;
		dmout <= dmout; 
	end
end

endmodule 

最后

以上就是纯情发带为你收集整理的FM调制解调---FPGA的全部内容,希望文章能够帮你解决FM调制解调---FPGA所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部