Skip to main content
Graduate II
December 10, 2021
Question

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

  • December 10, 2021
  • 11 replies
  • 4086 views

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_Init(OUTPUT_DEVICE_BOTH, 80, 48);

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!

    This topic has been closed for replies.

    11 replies

    Graduate II
    December 10, 2021

    Show here your dataI2S array values for example first ten values as in memory debuger screenshot...

    KneepatchAuthor
    Graduate II
    December 13, 2021

    0693W00000HoOvsQAF.png

    KneepatchAuthor
    Graduate II
    December 13, 2021

    Here are screenshots of the oscilloscope for both sides L and R:

    0693W00000HoP38QAF.bmp0693W00000HoP1SQAV.bmp

    Graduate II
    December 13, 2021

    for output same signals need data be equal [0]=[1] [2]=[3]

    and too need check BSP support for 16bit data

    KneepatchAuthor
    Graduate II
    December 17, 2021

    That’s exactly my point, one side has all zeros but it produces the same exact wave, just time shifted. And the HAL library asks for my data in a 16-bit buffer, so I am pretty sure that means it supports 16-bit data.

    Graduate II
    December 17, 2021

    Maybe use BSP need more info from example code is here mix chaos for pointer to data

    typedef struct {
     uint8_t buff[AUDIO_BUFFER_SIZE];
     uint32_t fptr;
     BUFFER_StateTypeDef state;
     uint32_t AudioFileSize;
     uint32_t *SrcAddress;
    }AUDIO_BufferTypeDef;

    primary buff in example is uint8

    call is converted

     if(bytesread > 0)
     {
     BSP_AUDIO_OUT_Play((uint16_t *)&buffer_ctl.buff[0], AUDIO_BUFFER_SIZE);

    and in BSP back to 8

    uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
    {
     uint8_t ret = AUDIO_OK;
     
     /* Call the audio Codec Play function */
     if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0)
     { 
     ret = AUDIO_ERROR;
     }
     
     /* Initiate a DMA transfer of PCM samples towards the serial audio interface */ 
     if(ret == AUDIO_OK)
     {
     if (HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE))!= HAL_OK)
     {
     ret = AUDIO_ERROR;
     }
     }
     
     return ret;
    }

    but seems your screenshot data isnt real filled with sine and too i mean your init call is bad

    /**
     * @brief Configures the audio peripherals.
     * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
     * or OUTPUT_DEVICE_BOTH.
     * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
     * @param AudioFreq: Audio frequency used to play the audio stream.
     * @note The SAI PLL input clock must be done in the user application. 
     * @retval AUDIO_OK if correct communication, else wrong communication
     */
    uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, 
     uint8_t Volume, 
     uint32_t AudioFreq)
    {

    and this call audio codec init maybe set mono , need check all.for error returned

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

    KneepatchAuthor
    Graduate II
    December 27, 2021

    Thanks for the response, I've been thinking over it this past week with my co-workers.

    I am still not convinced that the audio data size is 8-bit. In the code that you show me, the 8-bit input seems to be for DMA, but the code still accepts 16-bits for the audio buffer. Here is another consideration, because in the stm32469i_discovery_audio.c header it has the following notes for limitations (see 3 and 4 bolded below):

    Known Limitations:

    ------------------

      1- If the TDM Format used to paly in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second

       Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams.

      2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size,

       File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.

      3- Supports only Stereo audio streaming.

      4- Supports only 16-bits audio data size.

    ==============================================================================*/

    Based on this note, it makes me think that we are already streaming Stereo audio and it's 16-bits for the data size. Am I wrong?

    Super User
    December 27, 2021

    Try playing back something else, e.g. a sawtooth waveform.

    Cube is open source, so you can read the sources to find out how exactly given functions work.

    JW

    KneepatchAuthor
    Graduate II
    December 28, 2021

    Great idea, I will try that out!

    KneepatchAuthor
    Graduate II
    January 15, 2022

    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:

    0693W00000JM5mAQAT.png0693W00000JM5mKQAT.png 

    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:

    0693W00000JM5mZQAT.png 

    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:

     0693W00000JM5nhQAD.bmp 

    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:

    0693W00000JM5ncQAD.bmp 

    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.

    Graduate II
    December 28, 2021

    As i write you

     if (HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE))!= HAL_OK)

    you call this BSP_AUDIO_OUT_Play(dataI2S, (uint32_t)32); , but your buffer size is 1000 16bit then real byte size is 2000.

    Then in your size 32 entered here DMA_MAX(Size / AUDIODATA_SIZE) result to ...

    This SAI interface is initialized and you need check this init. 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 .

    KneepatchAuthor
    Graduate II
    December 28, 2021

    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.

    DMA_MAX(Size / AUDIODATA_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 */

     __HAL_SAI_DISABLE(&haudio_out_sai);

     /* 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 */

     __HAL_SAI_ENABLE(&haudio_out_sai);

     return ret;

    }

    KneepatchAuthor
    Graduate II
    January 15, 2022

    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:

    0693W00000JM5lvQAD.png 

    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)

     {

      Error_Handler();

     }

     /* USER CODE BEGIN SAI1_Init 2 */

     /* USER CODE END SAI1_Init 2 */

    }

    KneepatchAuthor
    Graduate II
    January 15, 2022

    @MM..1​ 

    Graduate II
    January 15, 2022

    > 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... ;)