This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] PCM3060:全双工、DAC 工作正常、ADC 不工作

Guru**** 2375080 points
Other Parts Discussed in Thread: PCM3060
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1039414/pcm3060-full-duplex-dac-works-adc-not

部件号:PCM3060

大家好、我在这几个月前尝试提交、当时我注册了 TI 帐户、但我从未收到激活电子邮件

今天、我上次尝试了一次、激活电子邮件很快就送达、所以我在这里

我制作了一个具有基于 ARM Cortex-M4F 的 MCU 和 PCM3060音频编解码器的电路板

我需要全双工、输入(2个通道)和输出(2个通道)

我还希望音频是直流耦合的

MCU 以3.3V 运行、PCM3060已按照数据表的建议(5V 和3.3V)进行了最佳设置

MCU 生成 I2S 信号(包括时钟)并驱动音频编解码器、I2S 上没有其他信号

MCU 还通过 SPI 控制音频编解码器、没有其他 SPI 器件

我尝试先使音频输出工作、因为这应该更简单、一旦工作正常、我就可以使用它来测试音频输入是否工作、方法是在软件中将输入数据作为输出数据进行馈送

音频输出工作正常

音频输入、我无法使其正常工作- CODE_SDO (来自编解码器的 DOUT)为0V 平坦输出

mainMCUaudio codec

PCB

我正在使用24.576MHz 晶体、然后所有 I2S 时钟都通过 MCU 的 I2S 外设从该晶体导出

尝试将编解码器设置为全双工从操作、频率为 fs=96kHz

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    以下是代码:

    // pcm3060 header -------------------------------
    #include "as_bitfield.hpp"
    
    namespace pcm3060
    {
    template
    <
        typename T, // this should be an integer type
        size_t Offset,
        size_t Bits = 1,
        typename TV = T // this may be an enum
    >
    using BitField = asacmp::BitField<T, Offset, Bits, TV>;
    
    enum _fmt : uint8_t
    {
        // all formats are MSB-First, 2s complement (i think that means signed int)
        fmt_i2s_24bit = 0b00, // default, I2S 24bit (left-justified, one bit delay)
        fmt_lj_24bit  = 0b01, // left-justified 24bit
        fmt_rj_24bit  = 0b10, // right-justified 24bit
        fmt_rj_16bit  = 0b11, // right-justified 16bit
    };
    
    struct _write_command_t
    {
        uint8_t a; // address (top bit should always be zero)
        uint8_t r; // register value
    } __attribute__((packed));
    
    union _reg64
    {
        using _t = uint8_t;
        _t reg;
        //enum _comState : _t
        //BitField<_t, 0, 3, _comState> comState;
        BitField<_t, 0> SingleEnded; //!< 0=Differential or 1=SingleEnded, for DAC VoutX
        //BitField<_t, 1> _rsvd1; //!<
        //BitField<_t, 2> _rsvd2; //!<
        //BitField<_t, 3> _rsvd3; //!<
        BitField<_t, 4> DAPSV; //!< DAC Power-Save Control. Default: 1 (on)
        BitField<_t, 5> ADPSV; //!< ADC Power-Save Control. Default: 1 (on)
        BitField<_t, 6> SRST; //!< System Reset. Default: 1 (normal operation)
        BitField<_t, 7> MRST; //!< Mode Control Register Reset (ADC and DAC). Default: 1 (normal operation)
        // The MRST bit controls reset of the mode control registers to their default values. Pop noise may be generated. Returning the MRST bit to 1 is not required, as the MRST bit is automatically set to 1 after a mode control register reset.
        // Default value    : 0b1111xxx1
        // suggested value  : 0b1100xxx0
    };
    union _reg67
    {
        using _t = uint8_t;
        _t reg;
    
        enum _ms2 : _t
        {
            ms2_slave           = 0b000, // default
            ms2_master_768fs    = 0b001,
            ms2_master_512fs    = 0b010,
            ms2_master_384fs    = 0b011,
            ms2_master_256fs    = 0b100,
            ms2_master_192fs    = 0b101,
            ms2_master_128fs    = 0b110
            // reserved     = 0b111
        };
    
        BitField<_t, 0, 2, _fmt> FMT2; //!< Audio Interface Format for DAC, Default: 00
        //BitField<_t, 1> ; //!<
        //BitField<_t, 2> _rsvd2; //!<
        //BitField<_t, 3> _rsvd3; //!<
        BitField<_t, 4,3,_ms2> MS2; //!< Audio Interface Mode for DAC, Default 000
        //BitField<_t, 5> ; //!<
        //BitField<_t, 6> ; //!<
        BitField<_t, 7> CSEL2; //!< Clock Select for DAC operation. Default 0 (DAC uses Clocks2)
        // ... SCKI2, BCK2, LRCK2 are used for DAC operation if CSEL2 = 0 (default),
        // and SCKI1, BCK1, LRCK1 are used for DAC operation if CSEL2 = 1.
    
        // Default : 0b0000xx00
    };
    union _reg72
    {
        using _t = uint8_t;
        _t reg;
    
        enum _ms1 : _t
        {
            ms1_slave           = 0b000, // default
            ms1_master_768fs    = 0b001,
            ms1_master_512fs    = 0b010,
            ms1_master_384fs    = 0b011,
            ms1_master_256fs    = 0b100,
            // reserved         = 0b101
            // reserved         = 0b110
            // reserved         = 0b111
        };
    
        BitField<_t, 0, 2, _fmt> FMT1; //!< Audio Interface Format for ADC, Default: 00
        //BitField<_t, 1> ; //!<
        //BitField<_t, 2> _rsvd2; //!<
        //BitField<_t, 3> _rsvd3; //!<
        BitField<_t, 4,3,_ms1> MS1; //!< Audio Interface Mode for ADC, Default 000
        //BitField<_t, 5> ; //!<
        //BitField<_t, 6> ; //!<
        BitField<_t, 7> CSEL1; //!< Clock Select for ADC operation. Default 0 (ADC uses Clocks1)
        // ....SCKI1, BCK1, LRCK1 are used for ADC portion if CSEL1 = 0 (default),
        // and SCKI2, BCK2, LRCK2 are used for ADC portion if CSEL1 = 1.
    
        // Default : 0b0000xx00
    };
    
    union _reg68
    {
        using _t = uint8_t;
        _t reg;
    
        BitField<_t, 0> MUT21; //!< Soft Mute Control (DAC) for VoutL
        BitField<_t, 1> MUT22; //!< Soft Mute Control (DAC) for VoutR
        BitField<_t, 2> DREV2; //!< Output Phase Select (DAC) - inverts the phase
        //BitField<_t, 3> ; //!<
        //BitField<_t, 4> ; //!<
        //BitField<_t, 5> ; //!<
        BitField<_t, 6> OVER; //!< Oversampling Rate Control (DAC)
        //BitField<_t, 7> ; //!<
        // Default: 0bx0xxx000
    };
    
    union _reg69
    {
        using _t = uint8_t;
        _t reg;
    
        enum _dmf : _t
        {
            dmf_44k1    = 0b00,
            dmf_48k     = 0b01,
            dmf_32k     = 0b10
            // reserved = 0b11
        };
    
        BitField<_t, 0> AZRO; //!< Zero-Flag Function Select (DAC)
        BitField<_t, 1> ZREV; //!< Zero-Flag Polarity Select (DAC)
        //BitField<_t, 2> ; //!<
        //BitField<_t, 3> ; //!<
        BitField<_t, 4> DMC; //!< Digital De-Emphasis Function Control (DAC)
        BitField<_t, 5,2,_dmf> DMF; //!< Sample Freq Selection for the De-Emphasis Function (DAC)
        //BitField<_t, 6> DMF1; //!<
        BitField<_t, 7> FLT; //!< Digital Filter Rolloff Control (DAC) - 0=Sharp, 1=Slow
    };
    
    union _reg73
    {
        using _t = uint8_t;
        _t reg;
    
        BitField<_t, 0> MUT11; //!< Soft Mute Control (ADC) L
        BitField<_t, 1> MUT12; //!< Soft Mute Control (ADC) R
        BitField<_t, 2> DREV1; //!< Input Phase Select (ADC) - inverts the phase
        BitField<_t, 3> BYP; //!< HPF Bypass Control (ADC)
        BitField<_t, 4> ZCDD; //!< Zero-Cross Detection Disable for Digital Attenuation (ADC)
        //BitField<_t, 5> ; //!<
        //BitField<_t, 6> ; //!<
        //BitField<_t, 7> ; //!<
    };
    
    /*
        // default values:
        0b1100xxx0,
        255,
        255,
        0b0000xx00,
        0bx0xxx000,
        0b0000xx00,
        215,
        215,
        0b0000xx00,
        0bxxx00000
    */
    
    } // namespace pcm3060
    
    struct AS_PCM3060
    {
        // there are 10 registers
        // their addresses are from 64 to 73
        using _write_command_t = pcm3060::_write_command_t;
        static_assert(sizeof(_write_command_t) == sizeof(uint16_t));
    
        constexpr const uint8_t * get_reg(uint8_t addr)
        {
            _cmd.a = addr;
            switch (addr)
            {
                case 64: _cmd.r = r64.reg; break;
                case 65: _cmd.r = r65; break;
                case 66: _cmd.r = r66; break;
                case 67: _cmd.r = r67.reg; break;
                case 68: _cmd.r = r68.reg; break;
                case 69: _cmd.r = r69.reg; break;
                case 70: _cmd.r = r70; break;
                case 71: _cmd.r = r71; break;
                case 72: _cmd.r = r72.reg; break;
                case 73: _cmd.r = r73.reg; break;
                default: _cmd.a = 0; break; // ERR
            };
            return reinterpret_cast<const uint8_t*>(&_cmd);
        }
        _write_command_t _cmd;
    
        // registers:
        pcm3060::_reg64 r64;
        // attenuation from 255 (0dB, default) to 55 (-100dB) in 0.5dB steps, 54 to 0 is Muted
        uint8_t         r65; //!< Digital Attenuation Level Setting (DAC) for VoutL
        uint8_t         r66; //!< Digital Attenuation Level Setting (DAC) for VoutR
        pcm3060::_reg67 r67; //!< DAC stuff
        pcm3060::_reg68 r68; //!< DAC stuff
        pcm3060::_reg69 r69; //!< DAC stuff
        // attenuation from 255 (+20dB) to 215 (0dB, default), to 15 (-100dB), 14 to 0 is Muted
        uint8_t         r70; //!< Digital Attenuation Level Setting (ADC) L
        uint8_t         r71; //!< Digital Attenuation Level Setting (ADC) R
        pcm3060::_reg72 r72; //!< ADC stuff
        pcm3060::_reg73 r73; //!< ADC stuff
    
    };
    // pcm3060 header ------ EOF
    
    // #############################################################################
    
    // main.cpp -----------------
    
    AS_PCM3060 sac; // stereo audio codec
    
    // initialize PINs:
    AS_IPin i2s_sdi     ( PinB10, PULL_R::OFF,  PMUX_FUNC::J_I2S );
    AS_OPin codec_reset ( PinB11, 1 ); // initial value: 1 (logic-high)
    
    AS_OPin i2s_mck0    ( PinA08, 0, PMUX_FUNC::J_I2S );
    AS_OPin i2s_fs0     ( PinA09, 0, PMUX_FUNC::J_I2S );
    AS_OPin i2s_sck0    ( PinA10, 0, PMUX_FUNC::J_I2S );
    AS_OPin i2s_sdo     ( PinA11, 0, PMUX_FUNC::J_I2S );
    
    AS_OPin spi6_ss     ( PinC10, 1,            PMUX_FUNC::C_SERCOM ); // sercom6 pad2 PMUX_FUNC C
    AS_IPin spi6_miso   ( PinC11, PULL_R::UP,   PMUX_FUNC::C_SERCOM ); // sercom6 pad3 PMUX_FUNC C
    AS_OPin spi6_sck    ( PinC12, 1,            PMUX_FUNC::D_SERCOM ); // sercom6 pad1 PMUX_FUNC D
    AS_OPin spi6_mosi   ( PinC13, 1,            PMUX_FUNC::D_SERCOM ); // sercom6 pad0 PMUX_FUNC D
    
    int main(void)
    {
    	atmel_start_init();
    
    	uint32_t test1, test2;
    	cyccnt::init();
    	{
            cyccnt::BlockCounter bc(&test1);
            delay_ms(1);
    	}
    	delay_ms(100);
    	delay_ms(1);
    	uint32_t ufreq;
    
    	{
            constexpr auto r = calc_optimal_baud_async(96000000, 115200.f, 0.001f);
            ufreq = r.freq;
            dbg.init(r.baud, 0, 2); // tx on PB31, rx on PB00
            NVIC_DisableIRQ     (SERCOM5_0_IRQn);
            NVIC_ClearPendingIRQ(SERCOM5_0_IRQn);
            NVIC_DisableIRQ     (SERCOM5_2_IRQn);
            NVIC_ClearPendingIRQ(SERCOM5_2_IRQn);
            NVIC_EnableIRQ      (SERCOM5_0_IRQn);
            NVIC_EnableIRQ      (SERCOM5_2_IRQn);
    	}
    	delay_ms(100);
    	dbg.print("\n");
    
    	dbg.print("\n" "::: same54_audio :::\n"
               "Built: " __DATE__ " " __TIME__ "\n"
               "Initializing...\n");
    	dbg.print("  USART bitrate: "); dbg.printn(ufreq); dbg.print("\n");
    
    	print_pin_info(midi_rx, dbg);
    	print_pin_info(u5_rx, dbg);
    	print_pin_info(midi_tx, dbg);
    	print_pin_info(u5_tx, dbg);
    	dbg.print("--------\n");
    
    	delay_ms(20);
    	out0led.on();
    
    	codec_reset.on();
    	delay_ms(100);
    	codec_reset.off(); // ----
    
    	dbg.print("  audio codec reset\n");
    
    	delay_ms(100);
    	{
            // intended settings: 96kHz with 256*Fs MCK (system clock)
            // that gives 24.576MHz
            // i can't get the required SCK (bitclock) freq of 4.608MHz with the divisor
            // thus using 32bit samples, even tho the audio codec will be set to 24bit
            // so with 32bit samples, SCK = 6.144MHz
            // same54_audio board has I2S signals going only to "Clocks1", set DAC and ADC to use that one
            sac.r64.reg = 0;
            sac.r64.MRST = 0; // mode control register reset to default values
            sac.r64.SRST = 1;
            sac.r64.SingleEnded = 1;
            sac.r64.ADPSV = 1; // power save
            sac.r64.DAPSV = 1; // power save
    
            sac.r67.reg = 0;
            sac.r67.CSEL2 = 1; // DAC should use Clock1 signals
            sac.r67.FMT2 = pcm3060::fmt_i2s_24bit;
            sac.r67.MS2 = pcm3060::_reg67::ms2_slave;
    
            sac.r68.reg = 0;
            sac.r68.OVER = 1;
    
            // ------------- ADC -----------
            // ADC attenuation, 215 = 0dB
            sac.r70 = 215;
            sac.r71 = 215;
    
            sac.r72.reg = 0;
            sac.r72.CSEL1 = 0; // ADC should use Clock1 signals
            sac.r72.FMT1 = sac.r67.FMT2;
            sac.r72.MS1 = pcm3060::_reg72::ms1_slave;
    
            sac.r73.reg = 0;
            sac.r73.ZCDD = 1; // disable zero-crossing detection for the attenuator
            sac.r73.BYP = 1; // disable the HPF on the ADC
    
            struct io_descriptor *io;
            spi_m_sync_get_io_descriptor(&SPI_0, &io);
    
            spi_m_sync_enable(&SPI_0);
    
            delay_ms(20);
    
            // write registers 64, 67, 68, 70, 71, 72, 73 over SPI to the audio codec
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(64), 2);
    
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(67), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(68), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(70), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(71), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(72), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(73), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
    
            codec_reset.on(); // start
            delay_ms(100);
    
            sac.r64.MRST = 1;
            sac.r64.SRST = 0; // system reset, resyncs the ADC and DAC
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(64), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
            delay_ms(100);
            sac.r64.ADPSV = 0; // normal operation
            sac.r64.DAPSV = 0; // normal operation
            {
                spi6_ss.off(); delay_us(100);
                io_write(io, sac.get_reg(64), 2);
                delay_us(100);
                spi6_ss.on(); delay_us(100);
            }
    
            #if 1
            // print all codec registers:
            {
                dbg.print("    r64: "); dbg.printhex(&sac.r64.reg, 1); dbg.print("\n");
                dbg.print("    r65: "); dbg.printhex(&sac.r65,     1); dbg.print("\n");
                dbg.print("    r66: "); dbg.printhex(&sac.r66,     1); dbg.print("\n");
                dbg.print("    r67: "); dbg.printhex(&sac.r67.reg, 1); dbg.print("\n");
                dbg.print("    r68: "); dbg.printhex(&sac.r68.reg, 1); dbg.print("\n");
                dbg.print("    r69: "); dbg.printhex(&sac.r69.reg, 1); dbg.print("\n");
                dbg.print("    r70: "); dbg.printhex(&sac.r70,     1); dbg.print("\n");
                dbg.print("    r71: "); dbg.printhex(&sac.r71,     1); dbg.print("\n");
                dbg.print("    r72: "); dbg.printhex(&sac.r72.reg, 1); dbg.print("\n");
                dbg.print("    r73: "); dbg.printhex(&sac.r73.reg, 1); dbg.print("\n");
            }
            #endif // 0
    	}
    	dbg.print("  audio codec configured\n");
    	out0led.on();
    
    	dbg.print("  setting up MIDI\n");
        delay_ms(100);
    	{
            constexpr auto r = calc_optimal_baud_async(32000000, 31250.f, 0.000001f);
            midi.fifo_reset();
            midi.init(r.baud, 0, 1); // tx on PA04, rx on PA05
            NVIC_EnableIRQ(SERCOM0_0_IRQn);
            NVIC_EnableIRQ(SERCOM0_2_IRQn);
    
            midi_in.reset();
    
            dbg.print("  MIDI bitrate: ");
            dbg.printn(r.freq);
            dbg.print("\n");
    	}
        {
            cyccnt::BlockCounter bc(&test2);
            delay_ms(1);
        }
        dbg.print("- Tests: "); dbg.printn(test1); dbg.print(", "); dbg.printn(test2); dbg.print("\n");
    
        delay_ms(500);
        dbg.print("  setting up I2S\n");
        as_i2s.sw_reset();
    
        if (as_i2s.init()) { dbg.print("  - okay\n"); }
    
        dbg.print("Initialization done.\n");
        dbg.print("Main loop...\n");
        // main loop here
    }

    这里是 MCU 的串行输出:

    ::: same54_audio :::
    Built: Sep  4 2021 15:45:00
    Initializing...
      USART bitrate: 115173
    ------
      audio codec reset
        r64: 81
        r65: 00
        r66: 00
        r67: 80
        r68: 40
        r69: 00
        r70: D7
        r71: D7
        r72: 80
        r73: 18
      audio codec configured
      setting up MIDI
      MIDI bitrate: 31250
    - Tests: 120083, 120738
      setting up I2S
      - okay
    Initialization done.
    Main loop...

    由于 PCB 尚未安装固件、因此 PCB 已部分组装、因此当我编写初始 SPI/PCM3060代码时、我已组装 PCM3060及其相关组件

    之后、我花了相当多的时间来编写和调整 I2S+DMA 代码、直到我最终开始从模拟输出中获得第一个声音

    最终、我在两个音频通道上都获得了流畅、无干扰的音频输出

    这是在查看音频输入时、不管我尝试了什么、它都无法正常工作

    然后、我想、也许由于 DOUT 是来自 PCM 的唯一输出信号(所有其他信号都是输入)、我可能有一段时间的电气配置意外不良、例如、 我的 MCU 的 SDI 引脚(引脚 B10)可能已设置为输出、然后中间唯一的事情是33R 电阻器太低、无法防止损坏(我想)

    因此、当我的固件"正在构建"时、我可能已经炸了 PCM3060的 DOUT 引脚... 因此、我对 R85 (33R 电阻器)和 PCM3060进行了去焊、然后非常仔细地焊接了一个全新的 PCM3060、并为其通电

    我仍然在(现在缺失)电阻器的 DOUT 侧获得平缓的0V

    从那时起、我实际上仍然没有重新焊接 R85

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    您能否使用显示相关时钟和数据的逻辑分析仪/示波器获取以下信号?

    -。 /RST、SCK1、LRCK1、BCK1和 DOUT

    您已检查 VINR 和 VINL 上是否有输入-正确吗?

    您是否曾尝试将工作中的 DAC 模拟输出回路到 VINL/R 并检查 DOUT?

    此致。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    不是现在、不是

    我可以在接下来的几天中进行示波器

    在我处理 I2S+DMA 代码的期间、我对 I2S 信号进行了范围划分、它们看起来很好(在50MHz 范围内)

    -假定两个通道上的模拟输出工作无干扰(我正在 MCU 上的软件中生成/合成音频)、这意味着编解码器 SPI 初始化不会完全错误、并且至少 framesync/bitclock/systemclock 和 DIN (编解码器上)工作正常

    DOUT (来自编解码器)提供平坦的0V、正如我已经说过的、是的、编解码器模拟输入上有音频、但我认为即使是"嘈杂的静音"也会变成 DOUT 上的某些"1"位、不是吗?

    现在、我实际上甚至没有模拟输出工作。 不知道发生了什么 在过去的几个月中、该板只是坐在这里收集灰尘

    I2S_SDO (来自 MCU)持续工作、因为我可以在使用声卡通过电阻器进行探测时听到数字数据位(并且能够区分软件振荡器的间距变化)、但音频编解码器的模拟输出没有任何结果

    我认为我有第三块芯片、但这感觉不正确

    在此之前、我还在网络上搜索 PCM3060、我发现有几个不同的人报告无法使音频输入正常工作(他们只有音频输出正常工作、就像我一样)、这些人最终没有报告成功、这似乎令人沮丧

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    好的、让我们从回送开始、一旦 DAC 再次工作、至少我们知道所有时钟都是正确的。

    DOUT 将在复位状态下强制为零、因此也可以检查它。

    此致。