2024-02-05 09:08 PM - last edited on 2024-09-24 05:17 AM by Amel NASRI
Hi,
I have a board with an STM32U575 at the core.
I'm attempting to set up SAI receiver in I2S mode, with 32-bit 48kHz sampling. See my configuration of SAI A below:
I also want to receive the data continuously in circular mode via DMA (or GPDMA in the case of this MCU).
Reading other sources, I've concluded that the following setup should be established:
The audio DMA functions can be seen below. The Audio_Init() function is called once in the main function, and the CpltCallback functions are called by DMA interrupts.
static uint16_t audio_rx[AUDIO_BUFFER_SIZE];
static uint16_t audio_tx[AUDIO_BUFFER_SIZE];
void Audio_Init(){
audio_ready_flag = AUDIO_DATA_FREE;
if(HAL_SAI_Receive_DMA(&AUDIO_RX_PORT, (uint8_t *)audio_rx, AUDIO_BUFFER_SIZE) != HAL_OK){
Error_Handler();
}
if(HAL_SAI_Transmit_DMA(&AUDIO_TX_PORT, (uint8_t *)audio_tx, AUDIO_BUFFER_SIZE) != HAL_OK){
Error_Handler();
}
}
void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hi2s){
audio_ready_flag = AUDIO_DATA_READY_HALF;
}
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hi2s){
audio_ready_flag = AUDIO_DATA_READY_FULL;
}
(I'm omitting all the HAL stuff, since I've already showed the setup in the above images. I want to note that all of the HAL code seems to be configured correctly --> no errors or warnings)
When my hardware has no audio source connected to it, I would assume that the audio data stored via DMA in the audio_rx buffer should be equal to 0 (and maybe some weak noise).
However, my buffer is filled with what appears to be 16-bit garbage values:
Why is this? I've successfully implemented this code on my old build, which used a STM32G4.
I'm very thankful for any help I can receive on this issue!
Best regards,
Max Borglowe
Solved! Go to Solution.
2024-02-24 05:06 AM - edited 2024-02-24 05:08 AM
Unfortunately, it seems like the Cortex-M33 is somewhat of a black sheep when it comes to documentation. If ever I find some material on GPDMA + SAI implementations, they're usually very muddy or unspecific. I will take another look around the web and let you know if I find anything useful.
I just found that the scope showed such strange readouts because the sampling frequency was too low...
Heres the full resolution scope when I increased the sampling frequency from 4MS/s to 16MS/s:
From the PCM1821 datasheet, I read that TDM or I2S should be used for this device:
It would be nice to try if TDM works, but unfortunately my hardware directly ties the FMT0 (mode select) pin to I2S.
2024-02-25 11:30 PM
Now things look much better on the scope!
The "noise" you see is perfectly okay for this ADC, there's nothing happening on the data line for the first 16 bit or so, so you're in the range of ~ 100 dB SNR, like the ADC is specified.
This might hint that your noisy ADC buffer data somehow shows only the noisy 16 LSB.
By the way, your DMA setup looks like WORD / 32bit, but your ADC buffers are 16 bit... so better change the ADC buffers to 32 bit, at least for testing.
2024-02-26 12:05 AM
Okay, so the CubeMX pictures say that DMA is configured as half-word.
SAI is configured for 32 bits = word.
Your code snippets show for DMA:
NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
I don't know the internals of the GPDMA, but it looks strange to me.
I would really start by setting all to WORD / 23bit: SAI/I2S, buffers, DMA.
2024-02-26 08:49 PM - edited 2024-02-26 08:50 PM
Ok, let's start by clearing out any doubts on the CubeMX side. As you stated, I see that my initial setup was wrong. Here's the corrected setup, which I've been using since a few posts back.
Here, the data width of the SAI and GPDMA are matching, which are set to "32 bits" and "word" respectively.
My audio buffers are also declared as uint32_t arrays, but let's just focus on the RX/ADC side of things for the time being:
uint32_t audio_rx[AUDIO_BUFFER_SIZE];
//uint32_t audio_tx[AUDIO_BUFFER_SIZE];
Here's the current readouts, which seem to indicate that the SAI is properly setup in 32-bit mode.
If I'm not mistaken, the data is transmitted MSB first, which should mean that there are some heavy "noise" spikes that seem way off in terms of amplitude (I mean, 0xFFFFxxxx can hardly be acceptable?).
The RX buffer is still filling with these noisy values. Here's another picture to show the reoccurrence of the large values:
Thank you so much for your continued patience and support, it's very much appreciated.
2024-02-26 10:45 PM
I think those large values are just "slightly negative" values, right? For example array index 15 is 0xffff fdd8 which is -552. So all those values you have in the buffer are some noise around 0.
2024-02-26 10:45 PM - edited 2024-02-26 10:56 PM
You are lucky, your SAI and your ADC are working correctly.
Now your 32bit buffer shows perfect noise values around 0, with about 100 dB SNR, the least 15 to 16 bits noisy only.
Check the 2's complement data format: https://en.wikipedia.org/wiki/Two%27s_complement
Your ADC ist just noisy around 0, example for 2's complement:
8 bit 2'sc:
1111 1111 = -1 !
0000 0000 = 0
0111 1111 = +127
1000 000 = -127
When working with audio formats, you should have heard about that. ;)
If not, now you know... :D
So it was mostly a 16 / 32 bit problem.
2024-02-27 09:02 PM
Sweet Jesus, you guys are absolutely right!!! I have definitely heard of and used two complements before, but I had no clue it was used this way in audio codecs. It must be very standard, since the ADC datasheet doesn't care to mention 2's complement even once. But I won't blame them for my ignorance :face_with_tears_of_joy:
Anyways: Intuitively, all I should do is store the received data in an int32_t buffer, instead of a uint32_t buffer.
int32_t audio_rx[AUDIO_BUFFER_SIZE];
I tried this, and I'm actually getting some neat waveforms in the SWV view now! So we're one step closer, but something is still off - the input waveform is a ~2Hz triangle wave (confirmed with scope), but the image below presents a garbled non-triangular wave. I'm assuming there's some more steps I need to take when I acquire the RX data, like rearranging some bits, or something?
Here's a picture of channel 0 (left):
Channel 1 (right) is also working btw :)
Please let me know if you know of some standard procedure, or have examples on how to receive the ADC data properly.
Once again, deeply grateful for all the help. Could not have done this without your efforts! :folded_hands:
2024-02-27 11:00 PM
There should be no bit shifting or whatever needed. I think 2's complement is the format in gcc for signed integers.
Are you sure that this SWV shows the data correctly?
How do the buffers look? With such a slow input signal, it should be easy to check the numbers in the buffer. Calculate after how many samples there must be a minimum and maximum, then check the buffers.
Another thing: the last few audio ADCs I used did not use standard I2S format, but "MSB left justified" or so, which is almost the same (I think except for the first bit).
I know we already talked about that, but I'd check again. Could be an ADC setting.
2024-02-28 10:58 AM
Here's the SWV in "I2S MSB Justified" mode (can't find left-justified in CubeMX?). Doesn't look quite right compared to the waveform in my last post:
Tried in "I2S LSB Justified" mode as well, for good measure:
So I'm assuming that the above is a dead end, and the data sheet is correct in specifying that I2S Standard mode is the way to go.
Here are all the available I2S modes for the SAI, in case you have more suggestions:
Below is also the SWV setup, where I print the first element of the array. Values in the RX buffer audio_rx also look OK.
2024-02-29 12:33 AM
I have no idea about SWV.
Does it know that data is interleaved in the buffer?
DMA fills the buffer LRLRLRLR... Left / Right channel from stereo ADC.