Noisy square wave with Teensy 4.1 & PCM5102A

I have been trying to clean up the output coming from a generic PCM5102A chipset. When I output a triangle/saw the wave is mostly noise free, except near a pulse width approaching zero (sawtooth). The square wave is incredibly noisy with digital noise.

I have grounded the FLT/DEMP/FMT pins and looped the chip's 3.3V to XSMT. I have a 470 Ohm/2.35nf RC low pass filter on the output of the L channel. R goes to ground since I am not using it yet. I have also tried sending the signal into a non-inverting unity gain op-amp in case something was pulling too much current.

One thing is that the noise has stayed exactly the same regardless of what additional components I add to clean it up. So far the program I use is pretty basic. I have also tried switching between waveform pulse, square and square bandwidth limited.

I am guessing I am missing something simple, but I have no idea what.
 
Can you post some plots of the noise? Non-bandwidth-limited square wave will have a lot of high frequency energy by its nature.
 
Did you connect SCK input of PCM5102A to the ground?

Also full scale square or saw without band limiting in software would cause builtin FIR reconstruction filter to apply ringing at the edges that might get distorted (hard clipped) and be perceived as noise.

You just have to band limit those hard edges.
 
I do have SCK connected to ground and VIN is 3.3V from the the Teensy.

Here are images of the square (no pulse width) and the sawtooth with the pulse set to about zero.

How exactly do I band limit? I see it mentioned all over but without enough details to know what the writers mean.

square.png

sawtooth.png
 
I guess this is kind of "tiny" scope like DSO138 ($20). FWIW: that is not really a tool to observe and analyse output of 24 bit DAC.

Anyway, do you actually hear the noise, or you are referring to "noise" to what you are seeing on the scope?

If you are concerned about the waveforms that can be seen on scope, what you see is pretty normal. It is result of DAC internal reconstruction filter doing its job and applying sinc() function to hard edges.

This is NOT noise. This is proper operation of DAC performing its filtering to ensure that output doesn't go above Nyquist.
Band-limiting is very wide subject, can't be explained in one sentence.

If you really want TLDR: bandlimited waveform is the waveform that doesn't include any harmonic components above Fsampling/2.
In practice means NO hard edges. Square and saw with hard edges have INFINITE number of harmonics.

More on that subject: https://en.wikipedia.org/wiki/Bandlimiting

From coding perspective:

 
Last edited:
The noise is quite audible and makes it unusable as a synth oscillator, the scope images don't really show it well.

As for your judgement on my scope, you'll have to be a bit more specific about what you want to see.

My frequencies are between 120-3000hz and a search showed the default sampling rate for teensy audio to be 44.1khz, so no issue with the frequency.

I am using the audio library and not trying to write my own digital oscillator specifically because I am not an engineer and signal analysis and the math behind it aren't where I want to go. I was planning to stick to tried and true solutions. From looking at your links, I am not sure what the audio library is already doing for me behind the scenes or what others are already doing to get clean oscillator output from the library and this particular I2S chip, which seems popular or at least common.
 
PCM5102A is perfectly fine. I am using it. It produces no noise if fed with proper audio input. In fact it is better (less noisy) than Teensy 4 audio shield.
Unless you have faulty part (that might happen), that is not the issue with DAC. Noise can have different sources, including improper grounding, ground loops and many others.
You need to approach this as engineer, in small steps, one step at a time. First make sure that hardware is actually correctly wired and operates correctly.
Use sine first, 75% of full scale - if it is clean and has absolutely no noise, then the hardware is fine. Sine must be pristine clean and absolutely no noise at all. Only then you can assume no problem with hardware.

As for the software, Teensy Audio-library is basic.
Basic Audio-library oscillators are aliased (produce audible artifacts).

You would need to use 3rd party code to get good sound, examples can be found on the forum:

 
To verify that hardware is working properly, I suggest you try some basic code like this:

C++:
#include <Arduino.h>
#include <Audio.h>
#include <Wire.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine1;          //xy=146.3333282470703,351.3333282470703
AudioSynthWaveform       waveform1;      //xy=155.3333282470703,453.3333282470703
AudioEffectEnvelope      envelope1;      //xy=378.3333282470703,347.3333282470703
AudioEffectEnvelope      envelope2;      //xy=400.3333282470703,451.3333282470703
AudioMixer4              mixer1;         //xy=638.3333282470703,469.3333282470703
AudioOutputI2S           i2s1;           //xy=822.3333282470703,357.3333282470703
AudioConnection          patchCord1(sine1, envelope1);
AudioConnection          patchCord2(waveform1, envelope2);
AudioConnection          patchCord3(envelope1, 0, mixer1, 0);
AudioConnection          patchCord4(envelope2, 0, mixer1, 1);
AudioConnection          patchCord5(mixer1, 0, i2s1, 0);
AudioConnection          patchCord6(mixer1, 0, i2s1, 1);
// GUItool: end automatically generated code



void setup()
{
    Serial.begin(115200);

    Serial.print("Starting....");
    // put your setup code here, to run once:
    AudioMemory(2);

    sine1.frequency(220);
    sine1.amplitude(0.75);
    waveform1.begin(WAVEFORM_BANDLIMIT_SAWTOOTH);
    waveform1.amplitude(0.25);
}

void loop()
{
    // put your main code here, to run repeatedly:
    float ftable[] = {55, 72.25, 110, 146.5, 220, 293, 440, 586, 880, 1760, 3520};
    //float ftable[ ] = {  14080 };

    for (int i = 0; i < sizeof(ftable) / sizeof(ftable[0]); i++)
    {
        Serial.printf("Playing SINE %g Hz\n", ftable[ i ] );
        sine1.frequency(ftable[i]);
        waveform1.frequency(ftable[i]);
        envelope1.sustain(1.0);
        envelope1.noteOn();
        delay(1000);
        envelope1.noteOff();

        Serial.printf("Playing SAW %g Hz\n", ftable[ i ] );
        delay(200);
        envelope2.sustain(1.0);
        envelope2.noteOn();
        delay(1000);
        envelope2.noteOff();
        delay(200);
    }
}

When you run it on PCM5102A it should sound like this recording: https://jumpshare.com/s/RoHA8XvhSjRIwFE2ivtF
 
Last edited:
The MicroDexed synthesizer project uses one of the PCM5102A modules available on Amazon and Aliexpress and have had great success with it from a performance standpoint. They also feel it is better than the Teensy Audio Adapter for noise. You might compare one of those canned modules that have been proven to work to what you are doing.
 
R goes to ground since I am not using it yet.
…but not, I hope, short circuited…
I guess this is kind of "tiny" scope like DSO138 ($20)
Looks like it might be one of these. $200-ish, and only 8 bit, but a lot of low-end ‘scopes are only 8-bit (albeit with moderately decent front ends). Pity it doesn’t have FFT, though.

Are you using 10x probes on this? It’s a bit hard to tell the actual amplitude you’re getting out; we have to assume there’s enough current capability from the PSU, and you’re not try to drive too close to the rails.

As noted by others, at the presented resolution, the traces look about right for an audio DAC output.
try some basic code like this:
C++:
void setup()
{
    Serial.begin(115200);

    Serial.print("Starting....");
    // put your setup code here, to run once:
    AudioMemory(2);
I’d strongly suggest using way more than 2 audio blocks when you’re debugging. Lack of available blocks gives all sorts of nasty results. Start with total overkill, like 50, and monitor usage. Once you know the maximum, allocate a few more than that for the final application.
 
FWIW, I actually ran the code before I posted and glitch-free audio attached to post was generated by exactly this code and PCM5102 and analog output was recorded. But generally I agree that adding more buffers won't hurt :) especially when you start adding more blocks to flow beyond very basic test.
 
Back
Top