Skip to main content
Visitor II
September 18, 2025
Question

Noisy audio output with TAS2110 codec over SAI on STM32U5G9J-DK1

  • September 18, 2025
  • 7 replies
  • 991 views

 

Post edited by ST moderator to be inline with the community rules especially with the code sharing. In next time please use </> button to paste your code. Please read this post: How to insert source code

Hi,

On checking, I noticed a mismatch between the expected sampling frequency (44.1 kHz) and the actual frequency (46.875 kHz). Could this be the cause of the noise? Any suggestions on what might be going wrong?

For reference, I’m using SAI1_A with circular linked-list channel 12 of GPDMA1. The configuration details for SAI and GPDMA are provided below.
 

GPDMA Configuration: 

handle_GPDMA1_Channel12.Instance = GPDMA1_Channel12;

handle_GPDMA1_Channel12.InitLinkedList.Priority = DMA_HIGH_PRIORITY;

handle_GPDMA1_Channel12.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;

handle_GPDMA1_Channel12.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;

handle_GPDMA1_Channel12.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;

handle_GPDMA1_Channel12.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;



SAI Configuration:

hsai_BlockA1.Instance = SAI1_Block_A;

hsai_BlockA1.Init.Protocol = SAI_FREE_PROTOCOL;

hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX;

hsai_BlockA1.Init.DataSize = SAI_DATASIZE_16;

hsai_BlockA1.Init.FirstBit = SAI_FIRSTBIT_MSB;

hsai_BlockA1.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;

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_1QF;

hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K;

hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;

hsai_BlockA1.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE;

hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE;

hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;

hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;

hsai_BlockA1.Init.PdmInit.Activation = DISABLE;

hsai_BlockA1.Init.PdmInit.MicPairsNbr = 1;

hsai_BlockA1.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;

hsai_BlockA1.FrameInit.FrameLength = 32;

hsai_BlockA1.FrameInit.ActiveFrameLength = 16;

hsai_BlockA1.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;

hsai_BlockA1.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;

hsai_BlockA1.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;

hsai_BlockA1.SlotInit.FirstBitOffset = 0;

hsai_BlockA1.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;

hsai_BlockA1.SlotInit.SlotNumber = 2;

hsai_BlockA1.SlotInit.SlotActive = 0x00000003;
LinkList configuration:

pNodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;

pNodeConfig.Init.Request = GPDMA1_REQUEST_SAI1_A;

pNodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;

pNodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;

pNodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;

pNodeConfig.Init.DestInc = DMA_DINC_FIXED;

pNodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_HALFWORD;

pNodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;

pNodeConfig.Init.SrcBurstLength = 1;

pNodeConfig.Init.DestBurstLength = 1;

pNodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;

pNodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;

pNodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;

pNodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;

pNodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;

pNodeConfig.SrcAddress = 0;

pNodeConfig.DstAddress = 0;

pNodeConfig.DataSize = 0;

 

 Thanks,

Jinal

    This topic has been closed for replies.

    7 replies

    Technical Moderator
    September 25, 2025

    Hello @Jinal 

    To help us further investigate the sampling frequency mismatch, could you please share the configuration details of your SAI kernel clock? For accurate 44.1 kHz audio output, the SAI kernel clock should be set to a frequency that is multiple of 44.1 kHz.

    JinalAuthor
    Visitor II
    September 30, 2025

    Hi @Saket_Om 

    Thanks for your response. My clock configuration is shown in the image, and I’ve attached the IOC file for reference. Appreciate your support!

    Jinal_0-1759256321669.png

    Thanks,

    Jinal

     

    Technical Moderator
    October 1, 2025

    Hello @Jinal 

    Could you try with the flowing config please. 

    Saket_Om_0-1759313328850.png

    In this config the SAI kernel clock is around 11.294 which is nearly multiple of 44.1 Khz.

    JinalAuthor
    Visitor II
    October 7, 2025

    Hi @Saket_Om 

    Thanks for response,

    I configured the SAI kernel clock as per your suggestion, and the audio output is now slightly clearer.
    When we play a mono-converted audio file using the existing configuration, the sound quality has improved — it’s more audible, though still not perfect.

    Could you please suggest the recommended configuration for mono audio playback?

    Thank you

    Jinal



    Graduate II
    October 29, 2025

    Maybe you have some problem not with the SAI or clocks, but with loading from flash, and / or buffering, and / or DMA ?

    Have you checked the output with a simple sine / triangle / square wave from SRAM ?

    JinalAuthor
    Visitor II
    November 3, 2025

    Hi @LCE ,

    Thanks for response. 

    The data read from flash and stored in the buffer matches the original WAV file data — we’ve verified this.
    We also confirmed using a logic analyzer that the same data from the WAV file is being transmitted correctly on the I²S data line.

    Additionally, a sine wave generated through code was played, which seems to be functioning correctly; however, this cannot be conclusively confirmed.

    Now, how can we confirm whether the issue is related to the SAI peripheral, DMA, or something else?

    Thanks,

    Jinal




    Graduate II
    November 3, 2025

    > Additionally, a sine wave generated through code was played,
    > which seems to be functioning correctly;
    > however, this cannot be conclusively confirmed.

    Why not?

    > Now, how can we confirm whether the issue is related to the SAI peripheral, DMA, or something else?

    As I said, make the sine output work.

    I would do it this way:

    • before main loop starts, calculate a sine wave and save it to a buffer with the same size you want to to use later on for data from flash
    • make sure that the sine fits perfectly into the buffer, so that continuous playback will always output a sine without any glitches = distortion (also mind the sine's amplitude)
    • set up the DMA in CIRCULAR mode so that it plays the sine "forever"
    • check the analog output

    If that doesn't give a good sine at the amp's / DAC's output, then your SAI setup is at least part of the problem.

    If that output is good, then your flash reading (maybe your sample "re-building" from bytes to 16/24/32 bits is bad?) and / or DMA setup and / or re-starting is the issue. Or maybe even the original file / waveform / amplitude?

     

    It's important to not just do stuff, but to do it methodically. Step by step, only one change at a time, peripheral after peripheral, ... :D

    JinalAuthor
    Visitor II
    November 4, 2025

    Hi @LCE ,

    Thanks for your response.

    We observed an anomaly in the clock and FSYNC signals. Specifically, the first clock pulse appears wider (duty cycle: 36.36%, frequency: 2.182 MHz, width: 3.429 MHz), while the subsequent clock pulses (duty: 50%, frequency: 3 MHz, width: 6 MHz) behave as expected.

    Additionally, we noticed that the FSYNC signal begins in the middle of a clock cycle.
    Could you please review this behavior and suggest possible causes?
    If this could be contributing to the noisy audio issue, please advise how we can resolve it.

    Please refer to the attached images for the observed issue with the FSYNC and clock signals.

    Thanks,

    Jinal

     

    Jinal_0-1762239581233.png

    Jinal_1-1762239880012.png

     

     

    Graduate II
    November 4, 2025

    Do you still have 2 SAI slots active? Not good for mono amp.

    Also check if you have any uneven clock dividers.

    JinalAuthor
    Visitor II
    November 4, 2025

     

    ChatGPT said:

    Hi,

    Thanks for quick response,

    We are transmitting stereo audio data, which is why the stereo mode is configured.
    Kindly review our SAI and clock configuration as well.

    Also, we have also tried to restart the SAI and start the SAI before playing audio but observed that CLK is not stopping and FSYNC getting delayed as per given delay.

    __HAL_SAI_DISABLE(&hsai_BlockA1);

      HAL_Delay(1);

      __HAL_SAI_ENABLE(&hsai_BlockA1);

      HAL_Delay(1);

    Clock Configuration

     < PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC|RCC_PERIPHCLK_DSI

                                  |RCC_PERIPHCLK_OSPI|RCC_PERIPHCLK_SAI1;

      PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2;

      PeriphClkInit.OspiClockSelection = RCC_OSPICLKSOURCE_PLL2;

      PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;

      PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;

      PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;

      PeriphClkInit.PLL3.PLL3M = 4;

      PeriphClkInit.PLL3.PLL3N = 125;

      PeriphClkInit.PLL3.PLL3P = 8;

      PeriphClkInit.PLL3.PLL3Q = 2;

      PeriphClkInit.PLL3.PLL3R = 24;

      PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0;

      PeriphClkInit.PLL3.PLL3FRACN = 0;

      PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP|RCC_PLL3_DIVR;

      PeriphClkInit.PLL2.PLL2Source = RCC_PLLSOURCE_HSE;

      PeriphClkInit.PLL2.PLL2M = 4;

      PeriphClkInit.PLL2.PLL2N = 45;

      PeriphClkInit.PLL2.PLL2P = 15;

      PeriphClkInit.PLL2.PLL2Q = 2;

      PeriphClkInit.PLL2.PLL2R = 1;

      PeriphClkInit.PLL2.PLL2RGE = RCC_PLLVCIRANGE_0;

      PeriphClkInit.PLL2.PLL2FRACN = 0;

      PeriphClkInit.PLL2.PLL2ClockOut = RCC_PLL2_DIVP|RCC_PLL2_DIVQ;/>

    SAI Configuration

    <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.AudioFrequency = SAI_AUDIO_FREQUENCY_48K;

      hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;

      hsai_BlockA1.Init.MckOutput = SAI_MCK_OUTPUT_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, 4) != HAL_OK)/>

    Thanks,

    Jinal



    Graduate II
    November 4, 2025

    Please edit your post and make it readable.

    Use the </> button to post source code.

     

    TAS2110:

    oh my, a TDM device with a few registers, not the easiest way to start...

    Are you sure that all registers are set correctly? For example, by default it wants to have 32 bit samples.

    Graduate II
    November 4, 2025

    Start looking at the SAI registers, learn to understand the direct register settings, CubeMx & HAL are not perfect.

    In the H733 the SAI only needs 3 to 4 registers for setup: CR1, (CR2,) FRCR, SLOTR.

    The below example is for master RX, and as said above for a H733:

    	/* CR1: most important settings here
    	 * 	DMA and SAI enable are set when started
    	 *	SAI_xCR1_MCKEN		= 0		MCLK is OFF, we use extra I2S for MCLK cause we need OSR 128 at 200 kHz
    	 * 	SAI_xCR1_OSR 		= 0 	x256 oversampling
    	 * 	SAI_xCR1_NODIV 		= 0 	use SAI_xCR1_MCKDIV for sampling rate settings
    	 *	SAI_xCR1_SYNCEN 	= 00	async mode, SAI_1_A is master
    	 * 	SAI_xCR1_CKSTR 		= 1 	I2S: sample on SCK rising
    	 * 	SAI_xCR1_LSBFIRST	= 0 	MSB first
    	 *	SAI_xCR1_DS 		= 111	32 bit data size
    	 *	SAI_xCR1_PRTCFG 	= 00	free protocol
    	 *	SAI_xCR1_MODE 		= 01 	master receiver
    	 */
    	SAI1_Block_A->CR1 = ( 	SAI_CR1_MCKDIV_SR_200K | SAI_xCR1_CKSTR |
    								SAI_CR1_DS_XBIT | SAI_CR1_MODE_MSTR_RCV );
    
    #if( 1 )
    	/* CR2 - unused: compander, FIFO flush and threshold EMPTY, tristate */
    	SAI1_Block_A->CR2 = 0;
    #else
    	/* CR2 - unused: compander, FIFO flush and threshold HALF FULL, tristate */
    	SAI1_Block_A->CR2 = SAI_xCR2_FTH_1;
    #endif
    
    	/* FRCR: frame configuration -> FS = LRCK */
    	SAI1_Block_A->FRCR = ( 	SAI_xFRCR_FSPOL |			/* FS active high */
    									SAI_xFRCR_FSDEF |			/* FS is start of frame AND channel side ID -> LeftRightCK */
    									SAI_FRCR_FSALL_32 |			/* frame length active in bit clocks = 32 (-1) */
    									SAI_FRCR_FRL_64 );			/* frame length in bit clocks = 64 (-1) */
    
    	/* SLOTR: slot configuration -> SCLK / LRCK */
    	SAI1_Block_A->SLOTR = ( SAI_SLOTR_SLOTEN_12 |		/* slots 1 & 2 active */
    									SAI_SLOTR_NBSLOT_2 |		/* number of slots in frame = 2 (-1) */
    									SAI_SLOTR_SLOTSZ_32 );		/* slot size = bits per channel */