SOLVED! Adafruit i2s DAC reducing pops / crackle help needed

Hello,
I’ve recently built a small mono speaker system for the bedroom using an old raspberry pi and a cheap Adafruit max98357 dac. While my woodworking skills leave something to be desired I’m fairly happy with the results except for the pops and crackles between tracks when playing Spotify.
Having done some research on why this happens a proposed solution has been offered by the manufacturers
I’ve read through what they are suggesting and the code they suggest breaks playback on a fresh install of Volumio and I’m afraid I don’t have enough technical knowledge to troubleshoot beyond following the detailed instructions (on the same page) and getting nowhere. When starting playback I just get an ALSA / Resource busy error in the GUI.Error

Any ideas where to start?
Many thanks

Hi, so to follow up on my earlier post I’ve spent some time trying to work out how to fix the startup and between tracks crackle I get on my Volumio system using the Adafruit MAX98357 i2S mono amp.

I’ve still not solved this issue and I am not very clear on how to proceed.

I have taken a few steps so far, but they have not solved the crackle between and at the start of playing tracks on Spotify, at the start of playing an internet station or when it stops.

The instructions are suggesting it is possible to play a software mixer to output a fixed sample rate to the DAC so the bit clock does not change. As Volumio uses ALSA the article suggests using dmix ALSA module. (The article is here.)

Is the dmix module included in Volumio’s build? I am having trouble setting up what is suggested.
I completed the first step by adding the following line to /boot/config.txt and rebooted.

dtoverlay=i2s-mmap

This caused no issue for me and survived the reboot.

Next, I switched back to the guide on the adafruit guide.

I added the following code to /etc/asound.conf

[code]pcm.speakerbonnet {
type hw card 0
}

pcm.!default {
type plug
slave.pcm “dmixer”
}

pcm.dmixer {
type dmix
ipc_key 1024
ipc_perm 0666
slave {
pcm “speakerbonnet”
period_time 0
period_size 1024
buffer_size 8192
rate 44100
channels 2
}
}

ctl.dmixer {
type hw card 0
}[/code]

with the exception of changing the value for the hw card from 0 to 1. Now both references read type hw card 1 .

Reboot but trying to play anything failed. Looking at the settings regenerated the original code and wiped my changes that are meant to generate the fixed sample rate.

Has anyone got any ideas?

IMHO, try increasing\decreasing those values, fine tune them according to results

You might end up having buffer underruns

Thanks, I’ll try that. See if I can improve the inappropriate crackles.

I have discovered someone else trying to solve this issue over on GitHub. And see if I can work my way through the adafruit instructions if those simple tweaks don’t solve things.

Many thanks

Thanks to timothyjward over on github to help me resolve this issue. For other users experiencing a crackle or pop between tracks or at the start or end music this may well help.

The adafruit guide I linked to was throwing me off as it assumed there was no prior setup on the system. Unlike on Volumio which knows about HiFiBerry type DACs such the Adafruit -MAX98357 iS2 DAC I was using.

So the steps to resolve this are:

  1. Install Volumio and set up the DAC as necessary in the GUI. Also, set the volume to soft volume.

  2. ssh into volumio

  3. Edit asound.conf in your favourite editor e.g. nano /etc/asound.conf

and modified pcm.softvol to use dmix. In my asound.conf it was the value for the second entry.

pcm.softvol { type softvol slave { pcm "dmix:1,0" } }

After that, I need to add a service and ensure it carried over reboot:

sudo nano /etc/systemd/system/aplay.service

And copied this into the blank document:

[code][Unit]
Description=Invoke aplay from /dev/zero at system start.

[Service]
ExecStart=/usr/bin/aplay -D dmix:1,0 -t raw -r 48000 -c 2 -f S32_LE /dev/zero

[Install]
WantedBy=multi-user.target[/code]

Ctrl-x to exit (yes to save)

then issued these commands to finish up.

sudo systemctl daemon-reload
sudo systemctl enable aplay.service
sudo systemctl start aplay.service

To check its working issue this command:

systemctl status aplay.service

Everything looked good for me - Spotify played with no crackles or pops. :smiley:

I rebooted the system and the changes are persistent.

I’ve been looking at ways to get this functionality working without having to manually mess around with the ALSA config.

So far I’ve managed a PR to enable “pluggable” ALSA config - next up is a dmix plugin which uses it.

1 Like

Hi Tim,
Great progress. Well done. No more sshing in to mess with config files looks like it will be a real thing! Good luck with getting a plugin up and running.
I look forward to further updates to Volumio.

I’ve been doing quite a bit of work in this area trying to see if I can make proper use of the shutdown pin on the MAX98357A. This reduces power usage (from approx 1.5mW to 10µW as far as I can tell) which is good for battery life on a system that I want to be portable. In doing that I have found that there is a kernel module and device overlay specifically for the device which uses the SD pin and avoids popping as a result!

The kernel module is included in the latest 5.4.y kernel, but not the stable 4.19.y used by Volumio. I have, however, worked out how to get it up and running.

  1. Enable SSH on your device
  2. Log in and get the kernel sources using volumio kernelsources
  3. Install the other things you need to build the kernel sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
  4. Edit /usr/src/rpi-linux/sound/soc/codecs/Kconfig to add:
config SND_SOC_TEST
        tristate "Select MAX 98375A"
        select SND_SOC_MAX98357A

between menu "CODEC drivers" and config SND_SOC_ALL_CODECS

  1. Run the first step of https://www.raspberrypi.org/documentation/linux/kernel/building.md#build_sources (i.e. selecting the build definition for the type of pi that you’re on)
  2. Run sudo make menuconfig and select the entry for the MAX98357A (drivers -> sound card -> soc -> codecs) to be a module (press m)
  3. Build the codec modules using sudo make M=sound/soc/codecs/ scripts prepare modules_prepare modules
  4. Copy the kernel module from sound/soc/codecs/snd-soc-max98357a.ko to your local modules folder
  5. Load the module, and you should have audio!
  6. Shutdown the pi, add a wire from GPIO 4 to the SD pin and you should have pop-free audio when you next boot and load the module

Hi Tim,
This sounds like a simple (certainly adding a one wire to my microsystem) and I but I’m not sure about how to issue the “kernalsources” command correctly to get what I need.

Could you confirm this for me?

When I’ve time later this week I’ll have a look at updating the kernal and configuring my little system.

You’re doing a great job of fixing up this little DAC for everyday usage. (WAF will improve greatly if there is no crackle!)

Hi TIme,
So I’ve got some time to look at this and I noticed why I couldn’t proceed last time - typo! The initial command should be volumio kernelsource not volumio kernelsources

Now I’ve done that and installed the build tools, I am unable to proceed as the /usr/src/rpi-linux/sound/soc/codecs/Kconfig isn’t on my system. When I follow the file tree through I only get to /usr/src as there is not rpi-linux in that folder.

Any ideas where I’ve gone wrong?
Thanks

So I’ve got some time to look at this and I noticed why I couldn’t proceed last time - typo! The initial command should be volumio kernelsource not volumio kernelsources

Sorry about that, completely my fault for trying to type out instructions at speed!

Now I’ve done that and installed the build tools, I am unable to proceed as the /usr/src/rpi-linux/sound/soc/codecs/Kconfig isn’t on my system. When I follow the file tree through I only get to /usr/src as there is not rpi-linux in that folder.

Did the volumio kernelsource command complete successfully? If you’re tight on SD card space then it may not have the space to download and unzip the kernel sources…

You can see the script that does the work at /volumio/app/plugins/system_controller/volumio_command_line_client/commands/kernelsource.sh It definitely does the following:

tar --strip-components 1 -xf rpi-linux.tar.gz -C /usr/src/rpi-linux
cd /usr/src/rpi-linux

Another thing to add:

  1. Shutdown the pi, add a wire from GPIO 4 to the SD pin and you should have pop-free audio when you next boot and load the module

This is true, but you may end up with audio only for the left channel (or possibly right channel) but not the (L+R)/2 that happens normally. I corrected this by using a 47kΩ resistor between GPIO4 and the SD pin, with another 10kΩ resistor between SD and ground. edit - I think a 10kΩ and 1kΩ would work, as would a 100kΩ and 22kΩ. The important thing is to drag the voltage below 0.15V when GPIO4 is low and up to about 0.5V when GPIO4 is high.

Another option would be to create a route plugin (or modified /etc/asound.conf) which does the (L+R)/2 in software, but the hardware approach is a bit more elegant.

Also, the volumio kernel is currently 4.19.y, which doesn’t include a fix for the MAX98357A driver that you might want. Specifically: ASoC: max98357a: add missing supported rates · raspberrypi/linux@fdf3436 · GitHub - it’s relatively simple to make the change by hand if you care about not resampling the audio, but the ALSA stack will cope without the patch.

Another another thing to add :slight_smile:

You will probably need to run sudo depmod after copying the module you’ve made into your local modules folder (the folder will be something like /lib/modules/4.19.118+/sound/soc/codecs). This scans the available modules and registers them so they can be loaded.

An update in case you’re interested. The latest Volumio Buster images use kernel 5.4.y and include the MAX98357A kernel module which prevents popping using the SD pin.

Obviously if you decide to do this you’ll need to plan how you’re going to control the SD pin, as Adafruit have helpfully connected it to Vin via a 1MΩ resistor. If you’re using 5V as Vin then connecting SD directly to the GPIO might fry your GPIO with 5V!

Hi Timothy,
Thanks for the update. I will be looking into doing this as I would like to get my volumio speaker working seamlessly.
I have just reread your earlier post about what resistors you used and I may need some further guidance as I’m not very knowledgable about electronics - but I can follow instructions (usually.)

I have just reread your earlier post about what resistors you used and I may need some further guidance as I’m not very knowledgable about electronics - but I can follow instructions (usually.)

Well you have a few options with varying levels of complexity. The end goal is to have the SD pin controlled by GPIO 4 (pin 7 on the GPIO header, and yes the numbering is a pain) so that the driver can mute the amp when nothing is playing.

Option 1: Removing the 1MΩ resistor and driving the pin directly

This option involves desoldering the surface mount resistor from the Adafruit board. It’s not that hard to do but may be more risk than you want to take.

The resistor is clearly visible on the board it’s the small component near the ground pin labelled 1004 (the code for 1MΩ). It also has a clear trace linking to the SD pin. There are plenty of guides to desoldering online. The main thing is to be sure that you don’t bridge the two connectors, or else you’ll be constantly forcing the SD pin to +5V.

Once the resistor is removed you can then either:

Option 1.a GPIO through a resistor

Connect the SD pin to GPIO 4 (the default control pin in the MAX98357a driver) using a resistor in the range 600-700kΩ. This will be SD “off” when the GPIO is low and “(L+R)/2” when the GPIO is high.

Option 1.b GPIO direct with software stereo to mono

Connect the SD pin directly to GPIO 4 (the default control pin in the MAX98357a driver). This will be SD “off” when the GPIO is low and “L” when the GPIO is high. To make sure that you hear your music properly you will need to configure ALSA to mix the left and right channels into the left channel. This would be best done as a plugin to Volumio (which doesn’t yet exist).

Option 1.c Stereo output

Get a second MAX98357A, desolder the 1MΩ resistor, then wire it up in parallel with the first amp. Connect one SD pin directly to GPIO 4 and the other SD pin to GPIO4 through a 220kΩ resistor. You will then have Left and Right output for two speakers

Option 2 No desoldering

If you don’t want to risk desoldering a component from the amplifier board then you can make things work using a potential divider between GPIO4, SD and GND to ensure that:

  • The GPIO pin is never pushed over 3.3V
  • The SD pin is pulled low enough to shutdown when the GPIO is low

I’ve tried this with reasonable success. My resistors were as follows:

  • A 47kΩ resistor between GPIO4 and the SD pin
  • A 10kΩ resistor between the SD pin and GND

When GPIO4 is low, this means that the connection to ground pulls the SD pin low (despite the 5V through 1MΩ as 10kΩ is 100 times smaller). When GPIO 4 is high the 47kΩ and 10kΩ divider sets the SD pin to about 0.58V, which what you want for the (L+R)/2 output.

I hope that this helps.

For reference, Option 1a is probably the best from a long-term power use and safety perspective (even if you accidentally short GPIO4 then 600kΩ will prevent excessive current) as long as you don’t accidentally bridge the contacts when desoldering the 1MΩ resistor.

I will therefore attempt the desoldering option. I’ll have to get some tools, but this is not a bad option. I can also get a couple of the MX98537A boards in case I ruin it and if not, I am sure I can make some more volumio mono speakers!

Hi Tim, thanks for the instructions on ways to fix this issue. I’ve not been 100% successful as of yet.

I successfully desoldered the 1MΩ and I’ve connected up 600KΩ worth of resistors (as 6 x 100K resistors in series - I didn’t have a 600kΩ single one) from GPIO4 to the SD pin and freshly installed volumio 3.015.

I still seem to be experiencing popping between tracks.

Any ideas about what to do next? More resistance between the GPIO4 and the SD pin?

edit: Actually it partially works - it no longer pops on stopping a track, just when starting playing.

Any ideas about what to do next?

It sounds like you’ve done everything right with the hardware, I’m just a bit unsure about where you got the 3.015 Volumio. To my knowledge the Volumio 3 beta hasn’t gone public yet, and if it had the version number would be a bit higher than that. My guess is that you have an image that someone in the community created?

The public beta should be starting very soon and I’ll let you know when it does.