You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派SPI驱动TI DAC8568输出信号失真问题排查

树莓派SPI DAC(Boost 8568)输出信号失真问题排查

我在开展树莓派项目时,将原有的I2C接口HiFi DAC扩展板(PCM5122)替换为SPI接口的Boost 8568 DAC,目标是通过该DAC输出处理后的EEG数据模拟信号。但实际测试中发现两者输出信号质量差异显著:示波器检测显示,新SPI DAC输出的信号存在明显失真,而原I2C DAC的输出信号清晰正常。

信号对比图

  • HiFi DAC输出信号:HiFi DAC输出信号
  • BOOST DAC 8568输出信号:BOOST DAC 8568输出信号

我已尝试降低信号采样率与SPI最大传输速率,但问题仍未得到解决。目前怀疑问题与Boost DAC的时钟组件相关,或是需要调整其他SPI参数以匹配原DAC的信号输出质量。

当前使用的Python代码

import spidev
import numpy as np
import time
import RPi.GPIO as GPIO
from scipy.io import wavfile

# Define DAC channels and their corresponding addresses (assuming 8 channels)
CHANNELS = {
   'A': 0b0000,  # Channel A address
   'B': 0b0001,  # Channel B address
   'C': 0b0010,  # Channel C address
   'D': 0b0011,  # Channel D address
   'E': 0b0100,  # Channel E address
   'F': 0b0101,  # Channel F address
   'G': 0b0110,  # Channel G address
   'H': 0b0111,  # Channel H address
}

# LDAC GPIO pin (adjust as needed)
LDAC_PIN = 17

def initialize_ldac():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(LDAC_PIN, GPIO.OUT)
    GPIO.output(LDAC_PIN, GPIO.HIGH)  # Default to inactive state

def trigger_ldac():
    GPIO.output(LDAC_PIN, GPIO.LOW)
    time.sleep(0.001)
    GPIO.output(LDAC_PIN, GPIO.HIGH)

CHANNEL_MAP = {
    "A": 0,
    "B": 1,
    "C": 2,
    "D": 3,
    "E": 4,
    "F": 5,
    "G": 6,
    "H": 7
}

def build_command(channel, data):
    if isinstance(channel, str):
        channel = CHANNEL_MAP[channel.upper()]  # Map channel to integer
    data = int(data) & 0xFFFF  # Ensure data is a 16-bit value
    command = 0b0011 << 4 | (channel & 0x0F)  # Generate command
    msb = (command << 4) | ((data >> 12) & 0x0F)  # Upper nibble of data
    lsb = (data >> 4) & 0xFF  # Middle 8 bits of data
    return [msb, lsb]

def send_to_dac(spi, channel, value):
    command = build_command(channel, value)
    spi.xfer2(command)

def update_channels_with_ldac(spi, channel_values):
    for channel, value in channel_values.items():
        send_to_dac(spi, channel, value)
    trigger_ldac()

def set_all_channels_to_zero(spi):
    channel_values = {channel: 0 for channel in CHANNELS}
    update_channels_with_ldac(spi, channel_values)

def load_wav_file(file_path, desired_duration_seconds):
    # Load WAV file and normalize the signal
    sample_rate, signal = wavfile.read(file_path)
    if signal.ndim > 1:  # Handle multi-channel audio (stereo)
        signal = signal[:, 0]  # Use only the first channel
    max_amplitude = np.max(np.abs(signal))
    normalized_signal = signal / max_amplitude

    # Determine how many samples fit within the desired duration
    num_samples = int(sample_rate * desired_duration_seconds)
    if len(normalized_signal) > num_samples:
        normalized_signal = normalized_signal[:num_samples]
    else:
        # Repeat the signal to fit the desired duration
        repeated_signal = np.tile(normalized_signal, int(np.ceil(num_samples / len(normalized_signal))))
        normalized_signal = repeated_signal[:num_samples]

    # Clip and convert to 16-bit integers
    normalized_signal = np.clip(normalized_signal * 32767, -32768, 32767).astype(int)
    return normalized_signal, sample_rate

def play_wav_file(spi, wav_file, target_channel, desired_duration_seconds):
    audio_data, sample_rate = load_wav_file(wav_file, desired_duration_seconds)
    num_samples = len(audio_data)
    sample_interval = 1 / sample_rate  # Time interval between samples

    start_time = time.time()  # Record the start time
    for i, value in enumerate(audio_data):
        # Send data to the DAC
        channel_values = {channel: 0 for channel in CHANNELS}
        channel_values[target_channel] = value
        update_channels_with_ldac(spi, channel_values)

        # Ensure proper timing
        elapsed_time = time.time() - start_time
        expected_time = (i + 1) * sample_interval
        if elapsed_time < expected_time:
            time.sleep(expected_time - elapsed_time)

        # Stop playback if exceeded the desired duration
        if elapsed_time >= desired_duration_seconds:
            break

if __name__ == "__main__":
    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.max_speed_hz = 500000
    spi.mode = 0b00

    initialize_ldac()

    try:
        target_channel = input("Enter the target channel (A, B, C, D, E, F, G, H): ").strip().upper()
        if target_channel not in CHANNELS:
            raise ValueError("Invalid channel.")
        
        wav_file = 'wav file dest here'
        desired_duration_seconds = 7

        play_wav_file(spi, wav_file, target_channel, desired_duration_seconds)

    finally:
        set_all_channels_to_zero(spi)
        spi.close()
        GPIO.cleanup()

内容的提问来源于stack exchange,提问作者user28464365

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:50:02