Showing results for 
Search instead for 
Did you mean: 

How do I get independent stereo audio output on STM32F469I-DISCO board?

Associate III

I am having trouble getting independent stereo audio output on the STM32F469I-DISCO development board. I am passing data to the cirrus audio codec using the stm32469i_discovery_audio.h functions:


BSP_AUDIO_OUT_Play(dataI2S, (uint32_t)32);

dataI2S is an array that has my audio data which is a calculated sine wave. From what I understand, the odd indices of the array go to one side of the audio (i.e left) and the even indices go to the other side of the audio output (i.e. right). What I am seeing on the oscilloscope is that both sides display the same sine wave, just slightly shifted in time. This occurs even if I zero out the even indices of the array.

Can someone please point me in the right direction here? Please let me know if you have any additional details that you want me to provide!


OK, trying to make sense of what you are telling me. When I look at the header for the BSP_AUDIO_OUT_Play function:


 * @brief Starts playing audio stream from a data buffer for a determined size.

 * @param pBuffer: Pointer to the buffer

 * @param Size: Number of audio data BYTES.

 * @retval AUDIO_OK if correct communication, else wrong communication


uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)

Based on the above, it should not matter what my pBuffer size is as long as it is as big or larger than the number of bytes I want to send. I tell it how many bytes to read based on the Size parameter. So, I point to the buffer memory address and tell it how many bytes to read from it based on the Size.


When I look at AUDIODATA_SIZE, I see that it's a constant set to 2. So that means it's 32/8 = 16. So that means that I am telling my code that I am sending 16 bytes? Are you saying in my example it should be 16/2 = 8?

Here is my initialization of the SAI, which I think is initialized to 16 bits for the data size based on the SAI_DATASIZE_16 parameter:

static uint8_t SAIx_Init(uint32_t AudioFreq)


 uint8_t ret = AUDIO_OK;

 /* Initialize the haudio_out_sai Instance parameter */

 haudio_out_sai.Instance = AUDIO_SAIx;

 /* Disable SAI peripheral to allow access to SAI internal registers */


 /* Configure SAI_Block_x

 LSBFirst: Disabled

 DataSize: 16 */

 haudio_out_sai.Init.AudioFrequency = AudioFreq;

 haudio_out_sai.Init.ClockSource = SAI_CLKSOURCE_PLLI2S;

 haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX;

 haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;

 haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL;

 haudio_out_sai.Init.DataSize = SAI_DATASIZE_16;

 haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB;

 haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;

 haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS;

 haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;

 haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;


 haudio_out_sai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV;

 haudio_out_sai.Init.SynchroExt   = SAI_SYNCEXT_DISABLE;

 haudio_out_sai.Init.Mckdiv     = SAIClockDivider(AudioFreq);

 haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE;

 haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING;

 haudio_out_sai.Init.TriState    = SAI_OUTPUT_NOTRELEASED;


 /* Configure SAI_Block_x Frame

 Frame Length: 64

 Frame active Length: 32

 FS Definition: Start frame + Channel Side identification

 FS Polarity: FS active Low

 FS Offset: FS asserted one bit before the first bit of slot 0 */

 haudio_out_sai.FrameInit.FrameLength = 64;

 haudio_out_sai.FrameInit.ActiveFrameLength = 32;

 haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;

 haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;

 haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;

 /* Configure SAI Block_x Slot

 Slot First Bit Offset: 0

 Slot Size : 16

 Slot Number: 4

 Slot Active: All slot actives */

 haudio_out_sai.SlotInit.FirstBitOffset = 0;

 haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;

 haudio_out_sai.SlotInit.SlotNumber = 4;

 haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123;

 /* Initializes the SAI peripheral*/

 if (HAL_SAI_Init(&haudio_out_sai) != HAL_OK)


  ret = AUDIO_ERROR;


 /* Enable SAI peripheral to generate MCLK */


 return ret;


Great idea, I will try that out!

But I think you are on to something based on your last comment: "For example if is initialised to 32 bit for one channel then your data is send as left + right 16bit to left 32 and sample 2 left+right to right ... result to bad freq and shift and bad playback in both ."

My data on the left is the exact same as the data on the right but shifted in time by a little bit. So I think you are getting to the root of the issue, I am just not understanding what the relationship between the SAI data size / DMA / the Play function I am working with.

Seems as first you need understand your discovery and SAI and , that codec seems be four channel usw...

As you can see in code stereo is commented out...

And HAL_SAI transmit DMA can overide some your init setupo...

Associate III

Yes, that's exactly why I am here. I am new to SAI and audio. Do you have any good resources that I can use to learn more about SAI? The biggest question that I have is, am I approaching the theory of stereo audio right with my buffer? Can one have two different things playing out the Left and Right side simply by putting the Left data in odd indicies and the Right data in even indicies on the same buffer? Let's assume for a moment that I had everything configured correctly. Or is that the root of the problem? How do I tell my codec / SAI config where to get R data and L data from?

Also, the code does have four channels, but I am only using one of them:


Looks like stereo is being implemented in the Main function in the SAI init:

static void MX_SAI1_Init(void)


 /* USER CODE BEGIN SAI1_Init 0 */

 /* USER CODE END SAI1_Init 0 */

 /* USER CODE BEGIN SAI1_Init 1 */

 /* USER CODE END SAI1_Init 1 */

 hsai_BlockA1.Instance = SAI1_Block_A;

 hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX;

 hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS;

 hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;

 hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;

 hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;

 hsai_BlockA1.Init.ClockSource = SAI_CLKSOURCE_PLLSAI;

 hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K;

 hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;

 hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE;

 hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;

 hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;

 if (HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_16BIT, 2) != HAL_OK)




 /* USER CODE BEGIN SAI1_Init 2 */

 /* USER CODE END SAI1_Init 2 */



Been a while, but I finally tried your suggestion of a sawtooth wave:

You can see that example below in my oscilloscope capture of the sawtooth wave.

I generated my data in Octave (alternative to MATLAB) and copied over to the STM32 IDE in C. Here are my graphs of a sawtooth and sine wave:


I combine them into one array of 1000 data points with the sawtooth data in the odd indices and the sine data in the even indices:


So, if the stereo sound was truly coming out L for even indices and R for odd indices, we should see a sawtooth on one side and a sine on the other side. The data being fed into the wave is good based on the graphs above! This is what I get when I run on one side on the STM board, however:


I think this looks similar to the last picture where all the data is graphed, so maybe it's trying to output both the sine and the sawtooth wave at the same time and the codec is filtering or smoothing it out?

Here is what it looks like with just a sawtooth data in the indices:


So I am back to my original issue. I can output a single waveform on both left and right. I cannot make left and right independent. I hope it's a simple misunderstanding on my part of how to do this, or something that I need to configure, and not a limitation of the technote on the Discovery board.

Chief II

> Do you have any good resources that I can use to learn more about SAI?

MCU's reference manual.

> How do I tell my codec / SAI config where to get R data and L data from?

Again - read the DAC's datasheet! Section "7.22 PCM Channel Swap" shows it.

> Can one have two different things playing out the Left and Right side simply by putting the Left data in odd indicies and the Right data in even indicies on the same buffer?

Yes, channels are independent, but the left channel comes the first and therefore sits at even indexes because indexes of the C language arrays and SAI slots are zero-based. And again - datasheet section "4.7 Digital Interface Formats" shows it clearly.

> The biggest question that I have is, am I approaching the theory of stereo audio right with my buffer?

Not reading documentation and doing blind guessing definitely is not the right approach... 😉

Chief II

Your image say more info as all texts.

0693W00000JM61AQAT.pngi mark input signals, that you need check and is controlled by STM SAI. STM test board is as any other example from STM ... not perfect ...

SDIN LRCK on scope you check if have two channels if yes all problem is as i write in

if(ret == AUDIO_OK)
    /* Initialize the audio codec internal registers */
    if (audio_drv->Init(AUDIO_I2C_ADDRESS,
                        AudioFreq) != AUDIO_OK)
      ret = AUDIO_ERROR;
  return ret;

This code init CS chip mode and as i mark on image in speaker mode have only one channel then maybe for both HP+SPEAKER demo set mono mix mode usw...

Try write your own CS chip init.

You are coder then write code and not only odd even data in array...