An alternative to the obsolescent CS42448: the PCM3168

h4yn0nnym0u5e

Well-known member
Hi folks

I've been playing around with the PCM3168, a near-alternative to the CS42448 which is now shown as discontinued on Cirrus Logic's website. From a functionality point of view, the PCM3168 doesn't have the ability to add another pair of inputs via an auxiliary interface, so you're limited to 6 in 8 out, but otherwise it seems a fairly straightforward replacement.

From a software point of view, it works with the existing Audio TDM objects, barring the bug I recently found. I does of course need a control object, which can be found at https://github.com/h4yn0nnym0u5e/Audio/tree/feature/PCM3168

I've had 5 evaluation PCBAs built by JLCPCB, using the following schematic. I allowed for multiple options on which Wire and TDM interfaces to use, and the option to use I²S instead of TDM; as manufactured, it uses Wire and TDM2, which is all I've tested for now. The RST, ZERO and OVF pins are connected, but only RST is needed. The I²C address pins are also selectable - as-built it uses address 0x44.

PCM3168:
PCM3168.png

Teensy:
Teensy.png


Analogue I/O:
Eval.png

The PCBA as built has several issues:
  • the analogue section doesn't work from the 5V supply: it needs ±12V connected to ANA_AVCC and ANA_AVMM
    • fix by removing R53 and R34, and wiring a 5V -> ±12V DC-DC converter to the headers
    • there's a track cut needed at U5 pin 4, and then that pin wiring to ANA_AVMM
  • I messed up on the BoM, so many of the resistors are 100R rather than as-marked on the schematic
I'm sure the schematic, layout and component choices could be significantly improved with regard to analogue performance! It really is just for evaluation / messing about with, rather than serious use.

All that said, I probably don't need all 5 PCBAs, so I'm willing to let three go at cost (say £25 each inc. shipping) , ideally to people in the UK as I really don't fancy messing with Customs forms. I'm not interested in making any more, but I will post the Gerbers and (corrected) BoM if people want ... unless someone has the knowledge of how to make a project public on JLCPCB.
 

Attachments

  • PCM3168.png
    PCM3168.png
    91.7 KB · Views: 20
  • Teensy.png
    Teensy.png
    84.8 KB · Views: 25
  • Eval.png
    Eval.png
    131.3 KB · Views: 26
Looking forward to seeing this when it's built.

One quick question now. I don't quite understand capacitors C50 and C52 on the analog schematic. What do they do?
 
Here you go! The dangly bit at the right is the DC-DC converter, and the DuPont cabling is connecting two differential outputs back to inputs for testing.

I have no idea on C50 and C52, I cribbed them straight from “Figure 60. Buffer and Anti-Aliasing LPF for Single-Ended ADC Input” of the datasheet’s System Examples.
1708284146883.jpeg
 
C46/47/50/52 provide very low impedance (at HF) to the ADCs while they are sampling - usually needed to get to datasheet levels of SNR. The opamp by itself will have quite high output impedance at HF, allowing ADC input currents to inject noise into the signal they are trying to measure - at least that's how I understand it.
 
Thanks Mark, good to know. I did find it slightly weird to have just C46 / C47 grounding the VIN- pins: seemed one step away from leaving them floating. But as a software guy who knows just enough about hardware to be dangerous, I'll go with the datasheet.
 
Do you have a code snippet that you can show that uses your PCM3168 control object to setup the Codec?
 
It's pretty much all in the github repo, but...
control_pcm3168.cpp:
C++:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <Arduino.h>
#include "control_pcm3168.h"


bool AudioControlPCM3168::enable(void)
{
    wire->begin();
    // TODO: wait for reset signal high??
    return write(DAC_CONTROL_1, DC1_24_BIT_I2S_TDM)
        && write(ADC_CONTROL_1, AC1_24_BIT_I2S_TDM)
        && write(DAC_SOFT_MUTE_CONTROL, 0x00)
        && write(ADC_SOFT_MUTE_CONTROL, 0x00)
        ;
}


bool AudioControlPCM3168::disable(void)
{
    // not really disabled, but it is muted
    return write(DAC_SOFT_MUTE_CONTROL, 0x00)
        && write(ADC_SOFT_MUTE_CONTROL, 0x00)
        ;
}

bool AudioControlPCM3168::volumeInteger(uint32_t n)
{
    return write(DAC_ATTENUATION_ALL, n);
}


bool AudioControlPCM3168::volumeInteger(int channel, uint32_t n)
{
    bool rv = false;
   
    if (0 != channel && channel <= DAC_CHANNELS)
        rv = write(DAC_ATTENUATION_BASE + channel - 1, n);

    return rv;
}


bool AudioControlPCM3168::inputLevelInteger(int32_t n)
{
    uint8_t levels[ADC_CHANNELS];
   
    for (int i=0; i < ADC_CHANNELS;i++)
        levels[i] = n;
   
    return write(ADC_ATTENUATION_BASE, levels, ADC_CHANNELS);
}


bool AudioControlPCM3168::inputLevelInteger(int channel, int32_t n)
{
    bool rv = false;
   
    if (0 != channel  && channel <= ADC_CHANNELS)
        rv = write(ADC_ATTENUATION_BASE + channel - 1, n);

    return rv;
}


bool AudioControlPCM3168::invertDAC(uint32_t data)
{
    return write(DAC_OUTPUT_PHASE, data); // these bits will invert the signal polarity of their respective DAC channels (1-8)
}


bool AudioControlPCM3168::invertADC(uint32_t data)
{
    return write(ADC_INPUT_PHASE, data); // these bits will invert the signal polarity of their respective ADC channels (1-6)
}


bool AudioControlPCM3168::write(uint32_t address, uint32_t data)
{
    wire->beginTransmission(i2c_addr);
    wire->write(address);
    wire->write(data);
    return wire->endTransmission() == 0;
}


bool AudioControlPCM3168::write(uint32_t address, const void *data, uint32_t len)
{
    wire->beginTransmission(i2c_addr);
    wire->write(address);
    const uint8_t *p = (const uint8_t *)data;
    wire->write(p,len);
   
    return wire->endTransmission() == 0;
}

and control_pcm3168.h:
C++:
/* Audio Library for Teensy 3.X
 * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
 *
 * Development of this audio library was funded by PJRC.COM, LLC by sales of
 * Teensy and Audio Adaptor boards.  Please support PJRC's efforts to develop
 * open source software by purchasing Teensy or other PJRC products.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice, development funding notice, and this permission
 * notice shall be included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef control_pcm3168_h_
#define control_pcm3168_h_

#include "Wire.h"
#include "AudioControl.h"
#include <math.h>


/*
From SBAS452A –SEPTEMBER 2008–REVISED JANUARY 2016

    9.5 Register Maps
    Table 12. Register Map
    ADDRESS  DATA
    DAC HEX   B7     B6     B5     B4     B3     B2     B1     B0
    64  40  MRST   SRST     —      —      —      —    SRDA1  SRDA0
    65  41  PSMDA  MSDA2  MSDA1  MSDA0  FMTDA3 FMTDA2 FMTDA1 FMTDA0
    66  42  OPEDA3 OPEDA2 OPEDA1 OPEDA0 FLT3   FLT2   FLT1   FLT0
    67  43  REVDA8 REVDA7 REVDA6 REVDA5 REVDA4 REVDA3 REVDA2 REVDA1
    68  44  MUTDA8 MUTDA7 MUTDA6 MUTDA5 MUTDA4 MUTDA3 MUTDA2 MUTDA1
    69  45  ZERO8  ZERO7  ZERO6  ZERO5  ZERO4  ZERO3  ZERO2  ZERO1
    70  46  ATMDDA ATSPDA DEMP1  DEMP0  AZRO2  AZRO1  AZRO0  ZREV
    71  47  ATDA07 ATDA06 ATDA05 ATDA04 ATDA03 ATDA02 ATDA01 ATDA00
    72  48  ATDA17 ATDA16 ATDA15 ATDA14 ATDA13 ATDA12 ATDA11 ATDA10
    73  49  ATDA27 ATDA26 ATDA25 ATDA24 ATDA23 ATDA22 ATDA21 ATDA20
    74  4A  ATDA37 ATDA36 ATDA35 ATDA34 ATDA33 ATDA32 ATDA31 ATDA30
    75  4B  ATDA47 ATDA46 ATDA45 ATDA44 ATDA43 ATDA42 ATDA41 ATDA40
    76  4C  ATDA57 ATDA56 ATDA55 ATDA54 ATDA53 ATDA52 ATDA51 ATDA50
    77  4D  ATDA67 ATDA66 ATDA65 ATDA64 ATDA63 ATDA62 ATDA61 ATDA60
    78  4E  ATDA77 ATDA76 ATDA75 ATDA74 ATDA73 ATDA72 ATDA71 ATDA70
    79  4F  ATDA87 ATDA86 ATDA85 ATDA84 ATDA83 ATDA82 ATDA81 ATDA80
    80  50    —      —      —      —      —      —    SRAD1  SRAD0
    81  51    —    MSAD2  MSAD1  MSAD0    —    FMTAD2 FMTAD1 FMTAD0
    82  52    —    PSVAD2 PSVAD1 PSVAD0   —    BYP2   BYP1   BYP0
    83  53    —      —    SEAD6  SEAD5  SEAD4  SEAD3  SEAD2  SEAD1
    84  54    —      —    REVAD6 REVAD5 REVAD4 REVAD3 REVAD2 REVAD1
    85  55    —      —    MUTAD6 MUTAD5 MUTAD4 MUTAD3 MUTAD2 MUTAD1
    86  56    —      —    OVF6   OVF5   OVF4   OVF3   OVF2   OVF1
    87  57  ATMDAD ATSPAD    —      —      —      —      —   OVFP
    88  58  ATAD07 ATAD06 ATAD05 ATAD04 ATAD03 ATAD02 ATAD01 ATAD00
    89  59  ATAD17 ATAD16 ATAD15 ATAD14 ATAD13 ATAD12 ATAD11 ATAD10
    90  5A  ATAD27 ATAD26 ATAD25 ATAD24 ATAD23 ATAD22 ATAD21 ATAD20
    91  5B  ATAD37 ATAD36 ATAD35 ATAD34 ATAD33 ATAD32 ATAD31 ATAD30
    92  5C  ATAD47 ATAD46 ATAD45 ATAD44 ATAD43 ATAD42 ATAD41 ATAD40
    93  5D  ATAD57 ATAD56 ATAD55 ATAD54 ATAD53 ATAD52 ATAD51 ATAD50
    94  5E  ATAD67 ATAD66 ATAD65 ATAD64 ATAD63 ATAD62 ATAD61 ATAD60
   
   
    Table 13. User-Programmable Mode Control Functions
    FUNCTION                                               RESET DEFAULT      REGISTER  LABEL
    Mode control register reset for ADC and DAC operation  Normal operation      64     MRST
    System reset for ADC and DAC operation                 Normal operation      64     SRST
    DAC sampling mode selection                            Auto                  64     SRDA[1:0]
    DAC power-save mode selection                          Power save            65     PSMDA
    DAC master/slave mode selection                        Slave                 65     MSDA[2:0]
    DAC audio interface format selection                   I2S                   65     FMTDA[3:0]
    DAC operation control                                  Normal operation      66     OPEDA[3:0]
    DAC digital filter roll-off control                    Sharp roll-off        66     FLT[3:0]
    DAC output phase selection                             Normal                67     REVDA[8:1]
    DAC soft mute control                                  Mute disabled         68     MUTDA[8:1]
    DAC zero flag                                          Not detected          69     ZERO[8:1]
    DAC digital attenuation mode                           Channel independent   70     ATMDDA
    DAC digital attenuation speed                          N × 2048/fS           70     ATSPDA
    DAC digital de-emphasis function control               Disabled              70     DEMP[1:0]
    DAC zero flag function selection                       Independent           70     AZRO[2:0]
    DAC zero flag polarity selection                       High for detection    70     ZREV
    DAC digital attenuation level shifting                 0 dB, no attenuation 71–79   ATDAx[7:0]
    ADC sampling mode selection                            Auto                  80     SRAD[1:0]
    ADC master/slave mode selection                        Slave                 81     MSAD[2:0]
    ADC audio interface format selection                   I2S                   81     FMTAD[2:0]
    ADC power-save control                                 Normal operation      82     PSVAD[2:0]
    ADC HPF bypass control                           Normal output, HPF enabled  82     BYP[2:0]
    ADC input configuration control                        Differential          83     SEAD[6:1]
    ADC input phase selection                              Normal                84     REVAD[6:1]
    ADC soft mute control                                  Mute disabled         85     MUTAD[6:1]
    ADC overflow flag                                      Not detected          86     OVF[6:1]
    ADC digital attenuation mode                           Channel independent   87     ATMDAD
    ADC digital attenuation speed                          N × 2048/fS           87     ATSPAD
    ADC overflow flag polarity selection                   High for detection    87     OVFP
    ADC digital attenuation level setting          0 dB, no gain or attenuation  88–94  ATADx[7:0]
*/

class AudioControlPCM3168 : public AudioControl
{
    const uint8_t I2C_BASE = 0x44;
    const int ADC_CHANNELS = 6;
    const int DAC_CHANNELS = 8;
   
    enum PCM3168reg {RESET_CONTROL = 0x40, DAC_CONTROL_1, DAC_CONTROL_2,
                     DAC_OUTPUT_PHASE, DAC_SOFT_MUTE_CONTROL, DAC_ZERO_FLAG,
                     DAC_CONTROL_3, DAC_ATTENUATION_ALL, DAC_ATTENUATION_BASE /* 8 registers */,
                     ADC_SAMPLING_MODE = 0x50, ADC_CONTROL_1, ADC_CONTROL_2,
                     ADC_INPUT_CONFIGURATION, ADC_INPUT_PHASE, ADC_SOFT_MUTE_CONTROL,
                     ADC_OVERFLOW_FLAG, ADC_CONTROL_3,
                     ADC_ATTENUATION_ALL, ADC_ATTENUATION_BASE /* 6 registers */
    };
    const int DC1_24_BIT_I2S_TDM = 0x06; // DAC_CONTROL_1: set 24-bit I²S mode, TDM format
    const int AC1_24_BIT_I2S_TDM = 0x06; // ADC_CONTROL_1: set 24-bit I²S mode, TDM format
                   
public:
    AudioControlPCM3168(void) : wire(&Wire), i2c_addr(I2C_BASE), muted(true) { }
    void setAddress(uint8_t addr) { i2c_addr = I2C_BASE | (addr & 3); }
    void setWire(TwoWire& w) { wire = &w; }
    bool enable(void);
    bool disable(void);
    bool volume(float level)
    {
        return volumeInteger(volumebyte(level));
    }
    bool inputLevel(float level) {
        return inputLevelInteger(inputlevelbyte(level));
    }
    bool inputSelect(int n) {
        return (n == 0) ? true : false;
    }
    bool volume(int channel, float level) {
        if (channel < 1 || channel > DAC_CHANNELS) return false;
        return volumeInteger(channel, volumebyte(level));
    }
    bool inputLevel(int channel, float level) {
        if (channel < 1 || channel > DAC_CHANNELS) return false;
        return inputLevelInteger(channel, inputlevelbyte(level));
    }
    bool invertDAC(uint32_t data);
    bool invertADC(uint32_t data);

private:
    bool volumeInteger(uint32_t n);
    bool volumeInteger(int channel, uint32_t n);
    bool inputLevelInteger(int32_t n);
    bool inputLevelInteger(int chnnel, int32_t n);
   
    // convert level to volume byte, Table 21, page 45
    uint32_t volumebyte(float level) {
        if (level >= 1.0f) return 255;
        if (level <= 1.0e-5f) return 54; // below -100dB, mute
        return 255 + roundf(log10f(level) * 40.0f); // 0.5dB steps: 0dB attenuation is 255
    }
   
    // convert level to input gain, Table 20, page 50
    int32_t inputlevelbyte(float level) {
        if (level > 10.0)    return 255;
        if (level < 1.0e-5f) return  15;
        return 215 + roundf(log10f(level) * 40.0f);
    }
    bool write(uint32_t address, uint32_t data);
    bool write(uint32_t address, const void *data, uint32_t len);
    TwoWire* wire;
    uint8_t i2c_addr;
    bool muted;
};

#endif // control_pcm3168_h_

In the sketch I have:

C++:
// usual audio topology exported from Design Tool,
// ending with...

AudioControlPCM3168      pcm3168;        //xy=717,546
// GUItool: end automatically generated code


//--------------------------------------
// change this #define to suit where you connected the RST pin to Teensy:
#define PCM3168_RST 17

void resetPCM3168(void)
{
  pinMode(PCM3168_RST,OUTPUT);
  digitalWriteFast(PCM3168_RST,0);
  delay(1);
  digitalWriteFast(PCM3168_RST,1);
  delay(100);
}
//--------------------------------------

void setup()
{
  // stuff here, then ...

  resetPCM3168();
  pcm3168.enable();
 
  // ... and so on
Hope that helps.
 
That is what I was looking for. I was wondering how you handled the RST pin. Thx
Very simply! I think it's quite important, but there's no very good way to force the programmer to use it, because you don't know which pin's in use. The 100ms delay is probably excessive, and certainly should be dealt with much better in proper code.
 
I am in the process of retrofitting an existing PCB that currently uses the CS42448. It looked pretty straightforward to me, so the fact you got it working is good confirmation.

FYI - One interesting observation is that the nominal supply current for the PCM3168 digital 3.3v supply is 162mA. It is only 60mA for the CS42448. This could cause a problem is some retrofit applications.
 
That’s about what I’m seeing. It certainly gets pretty warm … I have some thermistors on the way to track it. Though if I can borrow the IR camera from work, that’d be fun!

I seem to recall Paul observed the CS42448 gets quite toasty, too.
 
I've added a reset(pin#) function to the AudioControlPCM3168 object - it's pushed to the repo linked in post #1.

Before you call AudioControlPCM3168::enable(), you should call AudioControlPCM3168::reset(pin), using the Teensy pin number you connected to the PCM3168's RST pin. That pulses the pin low for 1µs, returns it high, and sets an internal timestamp. When you call enable(), the timestamp is checked, and if RST has been high for >200µs then the register setting process starts immediately. If not, there's a delayMicroseconds() for the remainder of the 200µs. Something like this may help explain:
C++:
//...
AudioControlPCM3168      pcm3168;      //xy=1128,446
// GUItool: end automatically generated code

#define PCM3168_RESET_PIN 17

void setup()
{
  AudioMemory(100); // plenty, for queues and TDM

  pinMode(LED_BUILTIN,OUTPUT);
  pcm3168.reset(PCM3168_RESET_PIN);
 
  while(!Serial)
    ;

  if (CrashReport)
    Serial.print(CrashReport);   
    
  while (!SD.begin(BUILTIN_SDCARD))
  {
    Serial.println("SD.begin() failed!");
    delay(500);
  } 
 
  pcm3168.enable();
  pcm3168.volume(0.5f);
  pcm3168.inputLevel(0.5f);

// ... and so on
This avoids burning 200µs of execution time for nothing, when you could be doing something useful. If you don't use reset(), enable() just assumes you've managed it some other way.
 
The CS42448 does run very hot. The CS42448 DOES NOT have a thermal power pad on its bottom side, however.

Since the PCM3168 has a thermal power pad, I was hoping it would run much cooler if properly connected to a good ground plane on the PCB.

I can't tell from your photos, but am I correct in assuming you have the PCM3168 power pad soldered and connected to a solid ground plane on the bottom side of the PCB with thermal bias as described in the TI data sheet?
 
The CS42448 does run very hot. The CS42448 DOES NOT have a thermal power pad on its bottom side, however.

Since the PCM3168 has a thermal power pad, I was hoping it would run much cooler if properly connected to a good ground plane on the PCB.

I can't tell from your photos, but am I correct in assuming you have the PCM3168 power pad soldered and connected to a solid ground plane on the bottom side of the PCB with thermal bias as described in the TI data sheet?
Yes, though I could probably have made a better job of it, in hindsight. There's copper under the chip on all 4 layers, with top and bottom layers being the pad ground so tied together by the vias in the part's footprint. I'd imagine it might be better to have put a few more vias in, and possibly to have made the inner layer pours a bit bigger.

Some of the silkscreen went a bit off piste, too ... ah well :whistle:
1708454704955.png
 
Some objective values for "quite warm". Here's a couple of FLIR camera images without a heatsink, after allowing the board to warm up. Ambient is about 20°C, images are top and bottom of board and targeted as best I could at the hottest point.
FLIR1161.jpg
FLIR1165.jpg


I then put on a 14x14x10mm aluminium 5-fin heatsink, and let it warm up again:
FLIR1183.jpg
FLIR1185.jpg
 
Good information. So for free air-unheatsinked, using the spec'd Junction-to-case thermal resistance of 7.7 C/W and the typical spec'd power dissipation of 1.16 W puts the junction temperature at about 74 C - well below the spec'd maximum Tj of 150 C. But 65 C is very hot to the touch.

But if this is put into a small enclosure, things could get pretty hot and the Tj will increase. Attention to venting and heatsinking and PCB thermal design will be important.

I wish there was a simple way to measure what my current design using the CS42448 chip surface temperature is for comparison. As Paul has pointed out - it is pretty hot to the touch. But it has been working fine in one of my current designs for a few years.
 
I've just knocked up a very simple thermistor-based probe, on the basis I probably won't be allowed to keep the work FLIR camera :giggle:

It's not likely to be super accurate unless I can find a way of calibrating it, as the thermistor has ±5% tolerance on resistance and ±3% on β, plus so far it's only held lightly against an outside face of the heatsink, in a blob of thermal goop. But it's just trickled up to 50°C, so it's definitely in the right ballpark.

You're quite right about thermal design for a real application, of course ... I'm just having fun at the moment, and hopefully providing some useful information for future users. So many threads start "I'm gonna have a go at this", and then you never find out if the butler did it or what.
 
Here is an interesting online source that might help calibrate things the old fashion way. Can you touch the PCM3168A continuously without pain, or only for short periods?
Screenshot 2024-02-23 at 4.03.57 PM.png
 
" it works with the existing Audio TDM objects, barring the bug I recently found"

Would you point me to somewhere that describes this TDM bug you mentioned here?
 
Adding some support files: Gerbers, zipped PNG schematics, and annotated BoM with notes on how to fix the errors I made :eek:
 

Attachments

  • Schematic_teensy-pcm3168-eval_2024-02-18.zip
    313.7 KB · Views: 12
  • Gerber_PCB_teensy-pcm3168-eval (1).zip
    100.5 KB · Views: 11
  • BOM_PCB_teensy-pcm3168-eval_2024-02-18.zip
    75.8 KB · Views: 13
I've had 5 evaluation PCBAs built by JLCPCB, using the following schematic. I allowed for multiple options on which Wire and TDM interfaces to use, and the option to use I²S instead of TDM; as manufactured, it uses Wire and TDM2, which is all I've tested for now. The RST, ZERO and OVF pins are connected, but only RST is needed. The I²C address pins are also selectable - as-built it uses address 0x44.
So, if I understood correctly, with your examples, it is not possible to use the SD card in conjunction with this library? Or can I use it with this library by using just TDM?
Not an expert but I'm a bit confused
 
You should be able to use an SD card just fine, I don’t think it clashes with either TDM or TDM2. If you use the Teensy 4.1 built in slot then that’s definitely OK, I’ve tried it.

Note the EasyEDA Teensy footprint uses conventional pin numbering, not Arduino-style numbering. So though it looks as if pins 10 (CS) and 11 (MOSI) are in use, actually they aren’t.
 
This looks very cool indeed! Thanks for posting it. I have been searching for a small/cheap DSP for active-crossovers for my tri-amped speakers.

Speaking of which, if I wanted the board to support 4 single channel outputs (RCA or solder) should I just remove the CN3 entirely and route the 28-25 pins to the analog out assemblies similar to both out channels on CN1? Note, I'm definitely an electronics novice, don't be afraid to tell me that this is a horrible idea.
 
It’s slightly easier than that. The output stage is only connected if you fit 4 jumpers to CN3, jumping 1-2, 3-4, 5-6 and 7-8. So just design your analogue out as you see fit, and connect to the odd-numbered pins on CN3 (VOUTn+/-). VCOMAD_B on pin 14 is the output offset reference, you’ll need that, but I messed up the power supply to the buffer U5 so that needs fixing. To use all 8 outputs you need CN4 as well. I forgot to check the alignment of the headers, so there’s no reason to expect them to be on a 0.1” grid :( .

If you’re rolling your own PCB then the above is academic. Just use as much of the Teensy and PCM3168 pages as is useful, and the analogue page for guidance only. Bearing in mind that I designed for evaluation so there’s lots of flexibility by swapping resistors in and out, and there’s the buffer power supply error…
 
Back
Top