cancel
Showing results for 
Search instead for 
Did you mean: 

{Novice} Unable to diagnose artifacts in sound synthesized on an STM32F407G:

APara.6
Associate II

I'm trying to teach myself digital signal processing on an STM32F407-based Discovery board, and I'm hitting a wall with audio glitches. I'm hoping someone with more experience can find what I cannot.

My goal is to synthesize audio (initially sine/triangle waves) in real-time and output it through the on-board CS43L22 DAC. I’m using STM32CubeIDE for programming, including its CubeMX module for device setup.

The problem is that I'm getting persistent audio artifacts - clicks, pops, or buzzing - that I can't seem to eliminate. The nature of the artifacts has changed as I've tried different fixes, but root the cause remains mysterious.

What I've Tried:

  • Basic Blocking I2S: Started with the simplest approach: HAL_I2S_Transmit() in the main loop. Got lots of clicking and buzzing. Learned this was a bad idea because it blocks the CPU.
  • DMA with Circular Buffer: Switched to HAL_I2S_Transmit_DMA() with a circular buffer. This is supposed to be the right way to do continuous audio. Still got clicks.
  • Phase Accumulation: Implemented a phase accumulator to ensure smooth waveform transitions, even across buffer boundaries. No change in the artifacts.
  • Amplitude Scaling: Made sure I wasn't clipping by scaling the combined amplitude of multiple waves. Reduced the harshness, but the clicks remained.
  • Triangle Waves: Switched to triangle waves to see if the simpler waveform helped. There were no artifacts, but this failed to help me diagnose the issue with sine waves.
  • Buffer Size Changes: Larger buffers reduce the frequency of the clicks, but don't eliminate them. The clicks seem loosely tied to buffer size and sample rate (e.g., buffer size = sample rate gives clicks about once per second).
  • Sample Rate Changes: Lowering the sample rate (from 48kHz to 22kHz, then 16kHz) changes the character of the artifacts, but doesn't eliminate them. At 8kHz, the clicks disappear, but there's a slight static.
  • Stereo Handling: Made sure I'm filling both left and right channels correctly. Trying to mute either channel works as expected, and does not eliminate the clicking.
  • Callback Overlap Checks: Added code to detect if the half-transfer and full-transfer callbacks were overlapping. Sometimes they do overlap, but, importantly, not always when a click is heard.
  • Watchdog Checks: Added checks for amplitude clipping, channel disagreement, and phase discontinuities. The channel disagreement was caught sometimes, but never when checked manually. Overall, this approach failed because adding so debug break points slowed down the program too much for it to produce real-time audio, and caused additional artifacts.
  • Eliminated Division: Replaced all divisions with multiplications, on the theory that decreasing performance load might eliminate the problem. No improvement.

Ruled Out (or Unlikely) Suspects:

  • Basic I2S/DMA Setup: The DMA is transferring data, and I can hear the generated tones. The CubeMX settings for I2S and DMA seem correct (Circular mode, Half Word data width, FIFO enabled).

  • Phase Calculation Errors: The phase accumulator approach should ensure smooth transitions, and the artifacts persist even with a global sample counter.

  • Bit Rate: Changing this does not alter the character of the artifacts.

  • Sine phase modulo: I can increase the cutoff from 2x pi to 200x pi, and the rate of clicks is unchanged.

Outstanding, but unproven, suspects:

  • Buffer Boundary Transition: The clicks seem related to buffer transitions (larger buffer = fewer clicks), but they don't coincide precisely when I use LED indicators to show buffer transition events. Clicks are most common just after the "first half of buffer is ready to be refilled" LED turns on, but they can happen at any point in the process.

  • Channel Disagreement: When I did use a watchdog breakpoint, sometimes it would flag channel differences, but the buffer contents look correct when inspected.

  • Callback Overlap: The overlap detection sometimes triggers, but not always when clicks occur.

  • Sine wave addition: The artifacts never happen with a single sine wave, and always happen with 2+ sine waves. They also never happen with triangle waves.

  • Computational Load: The amount of trouble is proportional to how many sine waves I try to layer, but is not linear:

    • 1 500hz sine wave: no artifacts

    • 2 500hz sine waves: buzzes once every 10 seconds or so

    • 3 500hz sine waves: clicks about once every two seconds

    • 4+ 500hz sine waves: same clicks, but proportionately more frequent

Find the most recent version of my project attached. I apologize for the lack of comments; this code has been in constant flux.

I have spent weeks on this. I’m out of ideas. I would be so grateful to anyone who can spot the cause of this problem.

1 REPLY 1
Ozone
Lead III

As I understand your post, you mostly verified that the artifacts are not related to buffer switches, i.e. transitions from one buffer to another.

Perhaps the problem is the internal bus structure and load.
DMA does not happen by magic, while it does not need core cycle while running, it still uses internal busses to transfer data between memory and peripherals. And those transfers can surely interfere with each other.
I would review the "memory and bus architecture" section of the reference manual, and check with the code.
And doing some profiling runs of your code, perhaps with some instrumentation to mark DMA transfers.

Although I am not really an expert in this matter.
In most of my projects I avoided getting into high-load issues, by being more 'generous' with the core choosen.