2021-02-15 11:41 PM
Hello everyone!
I am struggling with playback via I2S to external DAC on STM32L051/53.
Audio:
file in external SPI flash,
WAV format
16KHz sampling rate
16bit depth
I run the core on internal oscillator.
My 'real' I2S clock (WS frequency) is 15,957kHz, which is -0.26% off the target sampling frequency.
This is pretty accurate with my read from oscilloscope.
I send 16 bits of data on 16-bit frame.
External DAC:
UDA1334
min. 16KHz sampling rate
16bit I2S Phillips compatible
I cannot fit even 1s audio to MCUs memory, so I am reading from external flash using DMA.
My algorithm:
2x 512byte uint8_t array (let's say bufferA and bufferB)
2x 256 byte uint16_t array (let's say bufferC and bufferD)
read 512byte chunk of audio to bufferA
read 512 byte chunk of audio to bufferB
convert bufferA to bufferC
transmit bufferC to I2S
on i2sHalfCpltCallback update bufferA or bufferB
on spiRxTxCpltCallback convert bufferA to bufferC or bufferB to bufferD
while (!endOfFile)
i2sTransmit (bufferC or bufferD)
The actual questions:
Can 0.26% devation on I2S clock cause crackly noises during playback?
Is it possible to calculate/esitmate the THD based on I2S clock devation?
If I was handling big-endian/little-endian wrong I would not hear the audio at all, right?
What can I look into further to investigate the issue?
2021-02-16 02:11 PM
> Can 0.26% devation on I2S clock cause crackly noises during playback?
If you read data synchronously with playback (i.e. you read exactly the amount of data you play back, for example if reading N bytes is triggered by spending N previously read bytes, and not by some other independently timed event), then no.
> What can I look into further to investigate the issue?
This depends on the details of application. Make sure you ALWAYS have ready next chunk of data to play back. One way to visualize this is to toggle one GPIO Out pin in the process which prepares the data, each time data are ready; and toggle other GPIO Out pin when the playback routine starts to play back the next chunk of data; and observe on LA whether these signals are regular and their mutual relationship is as expected.
JW
2021-04-12 09:06 AM
Hello Jan,
thank you for your reply very much.
It took me while since I was reassigned somewhere else - obviously.
I did check it how you advised though. I toggle some pin (ch4) when I finish reading and converting data from the external flash, and togggle another pin (ch3) when I finish transmission of previous chunk of data.
The chunks read from flash and sent through I2S are the same of size:
256, 8-bit read from the flash, converted to 128, 16-bit.
128, 16-bit sent through I2S
As you may see on the screen shot appended, 'normal sittuation' is when:
ch4 rising edge is on high level ch3
and
falling edge of ch4 is on low level ch3.
I was trying to trigger for following events:
ch4 falling edge on high level ch3
ch4 rising edge on low level ch3.
These never happen, so I persume, that conversion of SPI Flash data is always finished before beginning of I2S transmission.
Should I provide some flow diagram or state machine to make it more clear?
Privately I could also share some code I believe.
With kind regards,
Michal
2021-04-12 09:19 AM
I just figured out another event, that might be alarming.
in HAL_SPI_TxRxCpltCallback I trigger conversion of the buffer from 8-bit to 16-bit buffer.
There I check the state of the buffers. Each run, after reste of MCU I get exactly 3 events, where the state is unexpected.
It should mean that the buffer which was supposed to be updated, was not transmitted yet.
2021-04-12 09:32 AM
Not sure there are many here to provide testing resources. Try the support engineers for your account, or those at the distributors.
Perhaps generate some pure sines and see if you get noise in them, or other repeating patterns you can store/generate without needing seconds of data, or reading via external memories.
Determine if the noise is coming from the codec, or supplies.
For short connections to SPI, etc, look carefully at just how aggressive a slew rate is used and the energy dumped into the pins. Drop the SPEEDR settings to the lower end. Consider if you need series resistors to stop ringing issues.
Look for gaps in the data or clocking.
2021-04-12 10:03 AM
Thanks!| I've already ruled out any clock gaps. Will look into other aspects you mentioned, tomorrow.
I do understand the rest, but I don't see how could I check the energy dumped to the pins. Do you mean energy from MCU to pins of external flash and codec? How should I measure that? With shunt resistors?
2021-04-12 12:48 PM
CMOS switching currents bleeding into the analogue signals, amplifiers, etc.
The SPEEDR setting is a bit deceptive, it really means how many banks of transistors are chained to drive the output pin into the board. There is typically a cascade of larger and larger transistor pairs acting a inverters than can drive more current into heavier capacitive loads across the board and into other parts. You're going to have very large current inrush as the drivers switch state. a) you need to pull this energy from somewhere, ie supply or local bulk capacitance, and b) dump it into a specific pin ie clock or data, and if these things are well matched/balanced it is going to create a very large amount of radiated noise.
Setting the pins to put 100 MHz edges on the signals, driving them a few inches to a CODEC, with relatively little capacitive load to overcome, is not recommended.
As I said, try some pure tones. Look at what you're doing with SPI and I2S. See where crackling noise comes from.
2021-04-16 01:40 AM
That's 1kHz sine wave that was sent via I2S to UDA1334 DAC, with it's FFT. Looks pretty awful too me, although it sounds pretty much like a 1KHz wave... I think it shouldn't look like that though. It looks pretty much the same with and without load. As load I am using BT speaker, connected via aux cable, powered of internal battery.
I think I will use some spare time to check if values sent via SPI I2S are the same and whether they create a nice clean sine wave at all. What do you think?
2021-04-16 02:57 AM
> I think I will use some spare time to check if values sent via SPI I2S are the same and whether they create a nice clean sine wave at all. What do you think?
It's easier to check something simpler, e.g. a sawtooth. It's also easy to generate - simply store an incrementing value to the output buffer.
W