我是靠谱客的博主 纯情发带,这篇文章主要介绍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完成调制中的乘法操作。

复制代码
1
2
3
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),再调用乘法器完成乘法运算,再将乘法器结果进行加减运算,再进行除法,即可得到解调结果。

        

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部