脉冲密度调制(PDM)是一种将模拟信号转换为数字脉冲序列的编码技术,在音频处理、电机控制等领域应用广泛。与PWM不同,PDM通过脉冲密度的变化而非宽度变化来传递信息,这使得它在抗噪声和信号重构方面具有独特优势。我在实际项目中发现,ZYNQ系列芯片的FPGA+ARM架构特别适合处理这类混合信号任务——PL端可高效生成精确的时序波形,PS端则方便实现算法控制和数据处理。
传统PDM生成常用锯齿波比较法,其核心原理就像用不断注水的水桶(计数器)和标尺(输入信号)进行比较:当水位(计数值)低于标尺高度时输出高电平,反之输出低电平。这种恒频后沿调制方法虽然简单,但在ZYNQ7020上实测时会遇到信号重构失真的问题。举个例子,当用8kHz正弦波作为输入信号时,RC滤波器恢复出的波形会出现明显的谐波失真,就像唱歌时麦克风突然接触不良产生的"咔咔"声。
在Vivado中创建PDM生成模块时,核心代码只需要一个计数器和比较器。下面这个经过实测的代码片段展示了典型实现:
verilog复制module pdm_basic (
input clk, rst,
input [15:0] audio_in, // 16位音频采样
output reg pdm_out
);
reg [9:0] counter; // 10位计数器
reg [9:0] threshold; // 比较阈值
always @(posedge clk or posedge rst) begin
if (rst) begin
counter <= 0;
pdm_out <= 0;
end else begin
counter <= counter + 1;
if (counter >= threshold)
pdm_out <= 0;
else
pdm_out <= 1;
if (counter == 1023) begin
threshold <= audio_in[15:7]; // 取高10位
counter <= 0;
end
end
end
endmodule
这个方案有几个关键点需要注意:
在驱动无刷电机时,我发现这种传统方法会产生两个典型问题:
通过示波器捕获的波形可以看到,脉冲下降沿总是出现在计数器溢出时刻,这种周期性突变就像用锤子定期敲击电路,必然会产生不必要的振动和噪声。在音频应用中,这直接表现为背景底噪;在电机控制中,则可能引起转矩脉动。
中心对齐调制将脉冲中心固定在计数周期中点,相当于把原来的单边比较改为双边比较。具体实现时,需要计算两个阈值:
code复制L = 中点值 - 输入信号/2
R = 中点值 + 输入信号/2
在ZYNQ中改进后的核心逻辑如下:
verilog复制module pdm_centered (
input clk, rst,
input [15:0] data_in,
output reg pdm_out
);
reg [10:0] counter; // 扩展到11位以处理中点
wire [10:0] midpoint = 1024;
wire [10:0] half_amplitude = data_in[15:6]; // 9位精度
always @(posedge clk or posedge rst) begin
if (rst) begin
counter <= 0;
pdm_out <= 0;
end else begin
counter <= (counter == 2047) ? 0 : counter + 1;
if ((counter >= midpoint - half_amplitude) &&
(counter <= midpoint + half_amplitude))
pdm_out <= 1;
else
pdm_out <= 0;
end
end
endmodule
在实际调试中,我总结出几个关键优化点:
位宽匹配:当输入信号位宽与计数器位宽不匹配时,会出现±1的舍入误差。建议保持half_amplitude比计数器少1-2位,例如11位计数器对应9位半幅值。
时序约束:双边比较会引入组合逻辑延迟,必须添加适当的时序约束:
tcl复制set_max_delay -from [get_pins pdm_centered/half_amplitude*] \
-to [get_pins pdm_centered/pdm_out] 2ns
滤波器设计:中心对齐PDM的频谱能量更分散,重建滤波器截止频率可以适当提高。对于音频应用,推荐使用四阶巴特沃斯滤波器,其群延迟特性更好。
使用ZYNQ的XADC捕获两种方案的输出波形,经过FFT分析得到如下对比数据:
| 指标 | 恒频后沿调制 | 中心对齐调制 |
|---|---|---|
| 信噪比(SNR) | 64dB | 72dB |
| 总谐波失真(THD) | 1.8% | 0.6% |
| 最大时钟频率 | 150MHz | 120MHz |
中心对齐方案虽然在最大频率上略有损失,但信号质量明显提升。特别是在电机控制场景下,转矩波动从原来的±5%降低到±1.5%。
在Vivado中综合后查看资源报告:
| 资源类型 | 锯齿波方案 | 中心对齐方案 | 增量 |
|---|---|---|---|
| LUT | 43 | 67 | +55% |
| 寄存器 | 22 | 35 | +59% |
| 最大路径延迟 | 3.2ns | 4.7ns | +47% |
虽然资源消耗增加,但在ZYNQ7020上仍然只占用了不到1%的逻辑资源,完全在可接受范围内。如果资源紧张,可以通过以下方法优化:
在真实项目中部署PDM生成器时,有几个容易踩坑的地方值得注意:
时钟域交叉:当PS端通过AXI总线配置参数时,务必使用双缓冲寄存器同步。我曾遇到过因为未同步导致参数变化时产生毛刺的问题:
verilog复制// 正确的跨时钟域处理
reg [15:0] param_cdc[0:1];
always @(posedge clk) begin
param_cdc[0] <= ps_param_in;
param_cdc[1] <= param_cdc[0];
end
动态范围调整:对于音频应用,建议添加自动增益控制(AGC)模块。当输入信号幅值超过最大调制深度时,可以采用软限幅而非硬截断:
verilog复制// 软限幅处理
wire [15:0] processed_input = (audio_in > MAX_AMPLITUDE) ?
MAX_AMPLITUDE - (audio_in - MAX_AMPLITUDE)/4 :
audio_in;
死区时间处理:在电机驱动等应用中,需要防止上下桥臂直通。可以在PDM生成器中集成死区控制:
verilog复制// 死区时间插入
reg pdm_delayed;
always @(posedge clk) pdm_delayed <= #DEADTIME pdm_out;
assign final_output = pdm_out & ~pdm_delayed;
实测表明,这些优化能使系统可靠性提升一个数量级。特别是在工业环境中,电气噪声更复杂,稳健的设计往往比单纯的性能指标更重要。