cancel
Showing results for 
Search instead for 
Did you mean: 

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

Jinal
Associate II

 

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

26 REPLIES 26
Jinal
Associate II

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




LCE
Principal II

> 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

Jinal
Associate II

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

 

 

LCE
Principal II

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

Also check if you have any uneven clock dividers.

Jinal
Associate II

 

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



LCE
Principal II

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.

LCE
Principal II

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