我是靠谱客的博主 坚强耳机,这篇文章主要介绍FPGA使用Delta-sigma(ΔΣ)ADC实现PDM音频输出,现在分享给大家,希望可以做个参考。

简书 FPGA使用Delta-sigma ADC实现PDM音频输出【DSP】 - 简书

文章代码托管在Delta-sigma-ADC-verilog。quartus目录内包含SDcard .wav播放示例。

FPGA实现音频输出的方式有:

  1. 使用I2S DAC芯片。
  2. 直接通过引脚输出PWM(脉冲宽度调制)信号。
  3. 直接通过引脚输出PDM(脉冲密度调制)信号。
  1. I2S DAC:成本敏感,但声音品质较好。
  2. 直接PWM:脉宽精度与计数器位数相关,而且需要很高的计数器时钟,一般不用计数器直接产生PWM,而使用比特取反计数器的方式产生伪PDM参考改进型PWM。PWM是PDM频率恒定时的特例,这种频率固定的方式实现简单,但效果不理想。

本文使用第三种方式PDM输出音频。这里使用Delta-sigma(ΔΣ)ADC产生PDM信号。ΔΣ ADC将模拟信号转成 PDM数字信号,PDM转成模拟信号只需外接低通滤波器。借用以上模拟的方法,使用FPGA进行全数字信号处理:

读取PCM数字音频 -> ΔΣ 调制 -> 输出PDM -> 外部RC低通滤波

一阶ΔΣ调制器的方块图,数字滤波器改用外部RC滤波

一阶ΔΣ调制器的方块图,数字滤波器改用外部RC滤波

ΔΣ 调制过程如上图所示,为方便解释,这里以有符号16bit PCM音频举例,16bit左边输入与1 bit DAC结果相减。1 bit DAC是指输入 1 ,输出 32767(16位有符号数最大值);输入 0 ,输出 -32768。相减结果的16bit符号数再进行一次积分,然后与 0 比大小,大于0输出1,小于等于0输出0。结果进入1 bit DAC反馈,以及输出为 1bit PDM信号。进行一次处理只输出了1bit PDM,需要将PCM数据保持住,同样的过程处理N次得到N位PDM,这N位PDM信号代表了原PCM数据的量化值。详细原理参见该文章。这里使用二阶ΔΣ:

二阶ΔΣ调制器的方块图

如果将图中左边减法器换成模拟比较器,并且去掉1-Bit DAC,直接将PDM输出到FPGA管脚然后经过低通滤波接到比较器负端,Digital Filter换成累加器,就变成了真正的1-Bit ADC。可以量化模拟比较器正端电平。参考见下图:



 

说回二阶数字方法,简单FPGA实现框图如下:

时钟未画出

时钟未画出

verilog:

复制代码
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
/************************************************************************************ * Name :Delta sigma ADC * Description :2阶Delta sigma ADC,Generate PDM audio,din的采样率 应该比clk慢N倍, * N量化位数,N=32,64,128,256...,32bit以上时人耳听不出区别 * Interface :N/A * Origin :190811 * Author :helrori2011@gmail.com * Reference :https://www.cnblogs.com/sci-dev/p/10428042.html ************************************************************************************/ module delta_sigma_adc #( parameter W = 16//输入位宽 ) ( input wire clk , input wire rst_n , input wire signed [W-1:0] din ,//signed analog signal output reg dout //PDM signal ); wire signed [W-1:0]adc1b_max = {1'b0,{(W-1){1'b1}}}; wire signed [W-1:0]adc1b_min = {1'b1,{(W-1){1'b0}}}; wire signed [W-1:0]adc1b_out = (dout == 1'b1)?adc1b_max: (dout == 1'b0)?adc1b_min: 'bx; reg signed [W*2-1:0]inte0,inte1; wire signed [W*2-1:0]diff0 = din - adc1b_out; wire signed [W*2-1:0]rd0 = diff0 + inte0; wire signed [W*2-1:0]diff1 = rd0 - adc1b_out; wire signed [W*2-1:0]rd1 = diff1 + inte1; wire comp = (rd1 > 0)?1'b1:1'b0; always@(posedge clk or negedge rst_n)begin if ( !rst_n ) begin dout <= 1'b0; inte0 <= 'b0; inte1 <= 'b0; end else begin dout <= comp; inte0 <= rd0; inte1 <= rd1; end end endmodule

仿真:

dout=PDM

dout=PDM

对该模块进行NATIVE FIFO接口的包装:

复制代码
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
/************************************************************************************ * Name :PDM audio * Description :当音频采样率为48Khz,并选择量化位数为32时,clk频率=48Khz x 32 = 1.536Mhz * rdclk频率=48Khz,rddat数据速率与rdclk一样。rdclk可以由clk分频得到。 * Interface :Native FIFO * Origin :190812 * Author :helrori2011@gmail.com * Reference : ************************************************************************************/ module pdm_audio ( input wire clk ,// FREQ input wire rst_n , // connect to FIFO input wire rdaccess,// The FIFO data is ready,FIFO not empty input wire rdclk ,// FREQ/32=48Khz output reg rden , input wire [31:0] rddat ,// {L[31:16],R[15:0]},signed // microphone output wire pdm_r , output wire pdm_l ); reg [1:0]bf0; wire rdaccess_b = bf0[1]; always@(posedge rdclk or negedge rst_n)begin if(!rst_n)bf0<='b0;else bf0<={bf0,rdaccess};end always@(posedge rdclk or negedge rst_n)begin if ( !rst_n ) begin rden<=1'd0; end else begin if(rdaccess_b) rden<=1'd1; end end delta_sigma_adc #(.W ( 16 )) delta_sigma_adc_r ( .clk ( clk ), .rst_n ( rst_n ), .din ( rddat [15:0] ), .dout ( pdm_r ) ); delta_sigma_adc #(.W ( 16 )) delta_sigma_adc_l ( .clk ( clk ), .rst_n ( rst_n ), .din ( rddat [31:16] ), .dout ( pdm_l ) );

顶层使用pdm_audio.v,如需使用该模块,还需要外接32bit宽FIFO,暂存两个声道PCM数据。rdaccess用来告诉pdm_audio.v模块外部FIFO数据准备了一些,可以开始读FIFO。注意clk与rdclk频率相差N倍,N=32,64,128,256...
附 delta_sigma_adc.v的testbench:

复制代码
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
`timescale 1ns / 1ps module tb_delta_sigma_adc; // delta_sigma_adc Parameters parameter PERIOD = 10; parameter W = 16; parameter N = 1024;//量化位数 // delta_sigma_adc Inputs reg clk = 0 ; reg rst_n = 0 ; reg signed [W-1:0] din = -32768 ; // delta_sigma_adc Outputs wire dout ; initial begin forever #(PERIOD/2) clk=~clk; end reg [31:0]cnt=0; always@(posedge clk)begin if(cnt == N-1) cnt <= 'd0; else cnt <= cnt + 1; if(cnt == N-1) din <= din + 1000; end delta_sigma_adc #( .W ( W )) u_delta_sigma_adc ( .clk ( clk ), .rst_n ( rst_n ), .din ( din [W-1:0] ), .dout ( dout ) ); initial begin $dumpfile("wave.vcd"); $dumpvars(0,tb_delta_sigma_adc); #(PERIOD*2) rst_n = 1; #(PERIOD*N*80)//65536 $finish; end endmodule

参考备忘用途
引用:https://www.cnblogs.com/sci-dev/p/10428042.html

最后

以上就是坚强耳机最近收集整理的关于FPGA使用Delta-sigma(ΔΣ)ADC实现PDM音频输出的全部内容,更多相关FPGA使用Delta-sigma(ΔΣ)ADC实现PDM音频输出内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部