cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5xx: SPDIF out - how to configure?

tjaekel
Senior III

I am struggling since days to get "my audio" out via SPDIF (electrical).

What I see on scope (there is a voltage divider and cap for DC-free on PC12, Vpp is 0.6V, approx. 75 Ohm impedance):

MCU_SPDIF.png

It makes sense - but my SPDIF receiver (a STM32F769I-DISCO board, which works fine as SPDIF receiver with another source) does not get any audio (but it seems to sync and realize there is SPDIF signal, but completely silent).

Intention:

  • any audio I have in MCU (it will be PDM MIC via CODEC to I2S, as 24bit, 48 KHz) should be forwarded via SPDIF Tx
  • I want to use SAI2_B as SPDIF Tx (with PC12), also as 24bit (both are 48 KHz)
  • I tried with "faking", sending buffer content for SPDIF Out as a sine wave (24bit, 48 KHz)

 

#ifdef SPDIF_TEST
#define SPDIF_TIME		100
#define SPDIF_WORDS		4		/* 24bit values, but 32bit word */
#define SPDIF_CHANNELS	2
#define	SPDIF_AUDIOFREQ	48
#define SPDIF_DOUBLEBUF	2
int32_t SPDIF_out_test[SPDIF_CHANNELS * SPDIF_AUDIOFREQ * SPDIF_TIME * SPDIF_DOUBLEBUF] __aligned(4);
void GenerateSPDIFOut(void)
{
	int i;
	int32_t val = 0;
	double d;

	for (i = 0; i < (SPDIF_CHANNELS * SPDIF_AUDIOFREQ * SPDIF_TIME); i++)
	{
		d  = sin(((2 * M_PI) * i) / SPDIF_AUDIOFREQ);
		d *= (double)0x00700000;		//volume scaling
		val = (int32_t)d;
		val &= 0x00FFFFFF;
		val |= 0x01000000;
		SPDIF_out_test[2 * i + 0] = val;
		SPDIF_out_test[2 * i + 1] = val;
	}
}
#endif

 

I play this via this code (using DMA Ch5):

 

ifdef SPDIF_TEST
	GenerateSPDIFOut();
	MX_SAI_Init();
#endif
#ifdef SPDIF_TEST
	HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)sizeof(SPDIF_out_test) / sizeof(uint32_t));
#else

 

The configuration is this:

 

  hsai_BlockB1.Instance = SAI2_Block_B;
  hsai_BlockB1.Init.Protocol = SAI_SPDIF_PROTOCOL;
  hsai_BlockB1.Init.AudioMode = SAI_MODEMASTER_TX;
  hsai_BlockB1.Init.Synchro = SAI_ASYNCHRONOUS;
  hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
  hsai_BlockB1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;	//SAI_MASTERDIVIDER_ENABLE;
  hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  hsai_BlockB1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K;
  ////hsai_BlockB1.Init.DataSize = SAI_DATASIZE_32;
  hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
  hsai_BlockB1.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE;
  hsai_BlockB1.Init.MonoStereoMode = SAI_STEREOMODE;
  hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING;
  hsai_BlockB1.Init.PdmInit.Activation = DISABLE;
  hsai_BlockB1.Init.PdmInit.MicPairsNbr = 1;
  hsai_BlockB1.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;
  if (HAL_SAI_Init(&hsai_BlockB1) != HAL_OK)
  {
	    Error_Handler();
  }
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
    PeriphClkInit.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLL3;
    PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
    PeriphClkInit.PLL3.PLL3M = 1;

    /* 48 KHz SPDIF            with scope       CubeMX cfg */
    PeriphClkInit.PLL3.PLL3N = 18;				//36;
    PeriphClkInit.PLL3.PLL3P = 96;				//96;
    PeriphClkInit.PLL3.PLL3Q = 2;
    PeriphClkInit.PLL3.PLL3R = 2;
    PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1;
    PeriphClkInit.PLL3.PLL3FRACN = 3544;		//7080

    PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
          Error_Handler();
    }
void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
{
  if(hsai->Instance==SAI2_Block_B)
  {
        /* Peripheral clock enable */
        if (SAI2_client == 0)
        {
        	 __HAL_RCC_SAI2_CLK_ENABLE();

        	 /* Peripheral interrupt init*/
        	 HAL_NVIC_SetPriority(SAI2_IRQn, 0, 0);
        	 HAL_NVIC_EnableIRQ(SAI2_IRQn);
        }
        SAI2_client++;

        /**SAI1_B_Block_B GPIO Configuration
        PB5     ------> SAI1_SD_B
        */

        GPIO_InitStruct.Pin = GPIO_PIN_12;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Alternate = GPIO_AF13_SAI2;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        /* Peripheral DMA init*/
        NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
        NodeConfig.Init.Request = GPDMA1_REQUEST_SAI2_B;
        NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
        NodeConfig.Init.Direction = DMA_MEMORY_TO_PERIPH;
        NodeConfig.Init.SrcInc = DMA_SINC_INCREMENTED;
        NodeConfig.Init.DestInc = DMA_DINC_FIXED;
        NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
        NodeConfig.Init.DestDataWidth = DMA_SRC_DATAWIDTH_WORD;
        NodeConfig.Init.SrcBurstLength = 1;
        NodeConfig.Init.DestBurstLength = 1;
        NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
        NodeConfig.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
        NodeConfig.Init.Mode = DMA_NORMAL;
        NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
        NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
        NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
        if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel5) != HAL_OK)
        {
          Error_Handler();
        }

        if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel5, NULL, &Node_GPDMA1_Channel5) != HAL_OK)
        {
          Error_Handler();
        }

        if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel5) != HAL_OK)
        {
          Error_Handler();
        }

        handle_GPDMA1_Channel5.Instance = GPDMA1_Channel5;
        handle_GPDMA1_Channel5.InitLinkedList.Priority = DMA_LOW_PRIORITY_MID_WEIGHT;
        handle_GPDMA1_Channel5.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
        handle_GPDMA1_Channel5.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
        handle_GPDMA1_Channel5.InitLinkedList.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
        handle_GPDMA1_Channel5.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
        if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel5) != HAL_OK)
        {
          Error_Handler();
        }

        if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel5, &List_GPDMA1_Channel5) != HAL_OK)
        {
          Error_Handler();
        }

        __HAL_LINKDMA(hsai, hdmatx, handle_GPDMA1_Channel5);

        if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel5, DMA_CHANNEL_NPRIV) != HAL_OK)
        {
          Error_Handler();
        }
    }
}

 

Besides the issue - "why I do not get the SPDIF signal on receiver", there are some major questions:

  • I do not need to set the datasize "as I understand" - forced anyway), e.g. via:

 

////hsai_BlockB1.Init.DataSize = SAI_DATASIZE_32;​

 

It should be forced automatically to 32bit (actually, the STM docs talk about 64bit and I see in drivers something with 64bit is used, I understand also the there is a DIV factor of 64 for SPDIF)

  • So, assuming the SPDIF needs really a SAI2 clock as 48 KHz * 64 = 3,072 KHz - I decided to use PLL3 and set the correct PLL out frequency for the SAI2 as SPDIF:
    Reusing PLL2, used for SAI1 and OCTOSPI cannot work, because I would not be able to set exactly this SAI_CLK value. So, PLL3 for the "nominal" SAI2 clock needed, just for SPDIF.
  •  Not really clear how to launch the DMA (with circular buffer):
    It the size the "number of words/samples" or the "number of bytes"? (I am using now "number of sample words", as seen that "size" is multiplied in driver with DMA word size)

 

HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)sizeof(SPDIF_out_test) / sizeof(uint32_t));​

 

  • The biggest confusion comes with CubeMX generated code!

If I use CubeMX and configure all (for my 8 MHz HSE) - I get this config:

 

PLL3P : PPL3M = 1
        PLL3N = 36
        PLL3P = 96
        factional = 7080
//resulting in: 3.07021 MHz, audio as: 48.0 KHz (minimum error)

 

I tried to trim in CubeMX that audio frequency error is minimum (or 0).

But when I run this config - it seems to be completely wrong. I check with a scope the SPDIF signal and its frequency. I assume to see this:

  • 48 KHz audio, two channels, 32bit samples (SPDIF uses 24bit, but a 32bit frame) - so, 3,072 KHz
  • but SPDIF is "marked encoded", so that I expect to see on SPDIF the fastest frequency (for values as 1) is doubled, so that a sequence of zeros is 48 KHz, but a sequence of ones is 96 KHz

So, I tried to trim the SPDIF frequency via scope and I had to configure this:

 

PLL3P : PLL3M = 1
        PLL3N = 18
        PLL3P = 96
        fractional = 3546
//resulting in 2x 48 KHz for SPDIF signal

 

So, what I see:

  • The CubeMX config says "correct 48 KHz as audio" but I have to double the frequency for SPDIF. And the PLL frequency seems to be a little bit off, but OK to tweak via "fractional" (or my scope is a bit off).

Also not really clear for me:

  • the SPDIF sample words (e.g. as 24bit) contain also the CS, U, V bits: MSB of audio sample is always at bit 23, but the upper next three bits are also transmitted via SPDIF: if, for instance, valid bit is "wrong" - receiver might ignore it.
  • I tried to play with these bits: no difference
  • assuming it would work (at the end) - there is a "dramatic impact" on my buffer handling:
    I CANNOT simply forward the same buffer: assume I get 24bit samples from my codec and I want to send out exactly the same buffer content as SPDIF - do I have to touch in every sample the bits [26:24] just to set a valid CS, U, V bit?
  • It sounds to as (OK): process the audio buffer received from codec (via I2S), flip the SPDIF bits (or shift the audio sample value? ...) and send out via SPDIF as a different buffer...?
    Not possible to forward a 32bit buffer (with 24bit sample words) via SPDIF...?

Even I saw the SPDIF working already (with a lot of distortion) - I cannot replicate neither send a test signal via SPDIF (from a prefilled buffer with sine wave samples).
What is wrong? (I want to see SPDIF working, esp. when I am sure, the SPDIF out via SAI2_B is generated and out there)

 

1 ACCEPTED SOLUTION

Accepted Solutions

OK, I can confirm:

  1. SPDIF Out on SAI2_SD_B works:
    Even on STM32U5A5 LQFP64 package ("officially" not a SAI2 and CubeMX does not let me configure pins for SAI2) - the SAI2_SD_B can be used as SPDIF out - IT WORKS! (even on the LQFP64 package!)
  2. Yes, the CubeMX generated clock config for SPDIF is wrong - but I could fix
  3. There is no need to set the CS bits: even I have assumed it is needed to add the V, U, CS bits: no: they can remain all zero (getting 24bit audio samples from SAI1 and forward to SAI2 without modification - great) - IT WORKS!

Just:

The issue is!:
The DMA from memory to SAI_SD_B as SPDIF Out FAILS!
It writes all zero (or nothing), even the memory is properly filled with audio samples.

I have used a scope (SALEAE) and SPDIF decoder: yes, I see all words on SPDIF signal are zero on scope!

Why? No idea: the DMA from memory to SAI2 peripheral as SPDIF out is the issue.
I have generated the code via CubeMX, as circular buffer - but it does not work.

When I use Polling mode or INT mode to send the audio to SAI2_B - all works fine. Just the DMA fails.
Here, what I do now:

#if 1
	////HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)));		//FAILS!!!!!!!!
	HAL_SAI_Transmit_IT(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)));			//WORKS!
#else
	while (1)
	{
		HAL_SAI_Transmit(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)), 5000);	//WORKS!
	}
#endif

Why is the DMA to SAI2 not working?
It looks like I have also trouble meanwhile - even it was working - to get PDM MIC via SAI1 into memory - the DMA is "so crazy" (and seems to be the main issue when it does not work).

BTW: I run the MCU with 1V8: with a modified voltage divider for SPDIF out (and the cap) - it works fine.
I can receive with a STM32F769I-DISCO board and the SPDIF signal level is similar to running with 3V3.
Maybe just a need to set the speed to fastest for SAI2_B_SD out (PC12).

So,
YES, even on a STM32U5A5RJT6Q (LQFP64 package) - there is an SAI2 and SPDIF out on it works!
(the STM datasheet is wrong!)

I will close this thread and open a new one for DMA issue.

View solution in original post

5 REPLIES 5
tjaekel
Senior III

If I understand correctly:

  • 48KHz, 2 channels, a 32bit (for SPDIF) = 3,072 KHz (bit clock)
  • SPDIF seems to take 64 (bit or clock ratio), so, also = 48 * 64 = 3,072 KHz
  • On SPDIF, with the "bi-marking", I should see sequences (for zeros) as 3,072 KHz and sequences (for ones) as doubled, as 6,144 KHz

But, with the setting as 48KHz:

hsai_BlockB1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_48K;

I can never reach this frequency on SPDIF (via tweaking the PLL).

Remark:

I have to set to 96K:

hsai_BlockB1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_96K;

Now I can trim the PLL to get 3,072 KHz on SPDIF (for the zeros):

    /* 48 KHz SPDIF            with scope       CubeMX cfg */
    PeriphClkInit.PLL3.PLL3N = 36;		//36;
    PeriphClkInit.PLL3.PLL3P = 24;		//96;
    PeriphClkInit.PLL3.PLL3Q = 2;
    PeriphClkInit.PLL3.PLL3R = 2;
    PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1;
    PeriphClkInit.PLL3.PLL3FRACN = 7400;	//7080

Remark:
This setting, to doubled audio frequency (96KHz), even all is 48KHz - I saw already on other projects, on older HAL drivers. It seems to me, the "bug" that the SPDIF clock config is not correct and needs a setting for the doubled audio frequency is still there.

Never mind - even I get now reasonable waveform on SPDIF, with 3.086 MHz and 3.06 MHz frequencies (as average 3.074 MHz - it should be 3.072 MHz but not possible to tweak further) - I still do not see any audio volume on receiver.

MCU_SPDIF_2.png

I am so lost how to get SPDIF working (and why my receiver does not get any audio samples, even it seems to sync).

BTW:
I "trust" the DMA: during debugging I saw that the DMA src pointer (from memory) is moving and seems to transmit the audio samples to SPDIF DR (data register, also correct address - but no idea what was transferred as value).

I am not sure, if 32bit with DMA works really: I have another (separate issue) where a 32bit word transfer on I2S, from Codec into memory, fails as well (I get just all zeros, even the I2S signal is completely fine).
Based on the changed bit pattern on scope (due to my sine wave in test buffer for SPDIF out) - I assume it should come out on SPDIF as well as a sine audio signal (1 KHz).

Any ideas why my SPDIF receiver does not see any audio samples?
(I have debugged a bit my STM32F769I-DISCO as SPDIF Rx: I do not see any error flags set but the receiver buffer is really all zero - why?) I trust a bit this SPDIF receiver because it works if I play SPDIF from another setup (mainly the same used as Tx) and it works.

So, something wrong with my new STM32U5A5 setup, maybe the signal levels (external circuit) or the clock configuration for SPDIF, or the buffer content, or the STM32U5xx has an issue with SPDIF via SAI.

If you have any clues... very appreciated: I am out of ideas.

Meanwhile I think: the CubeMX generated code - even I tweak for best match of 48 KHz as audio frequency in CubeMX - is completely wrong. I get just 48 KHz (or 96 KHz) as bit clock on SPDIF signal (instead of 3,072 KHz or doubled). It does not make any sense. Also this "trick" to set 96KHz as audio frequency for SPDIF makes me suspicious.

Is there any example for SPDIF on STM32U5xx MCU?
(no need to reference SPDIF sample code for STM32F769 etc. - I have this working since years). 

OK, still not yet working - but I found two major issues:

  1. The bits CS, U, V must be provided: together with the audio samples (e.g. 24bit PCM words), at least the CS (Channel Status) bits must be provided (see more details below)
  2. The SPDIF clock configuration in the HAL driver seems to be a bit "strange" (even looking wrong).

Dear STM team:
I think, the clock config for SPDIF on any SAI is wrong: the MCLKDIV can be set wrong (with +1), generating just half of the clock needed (a separate thread coming).

The CS, U, V bits:

These bits must be "driven": it means: they have to be set in the audio sample words (bit 26..24). Especially the CS bits (bit 26) provide info about the sample rate, for which channel is this sample, etc.

So, I do this now (even it does not seem to work yet):

#define SPDIF_FRAMES	192
#define SPDIF_WORDS		4				/* 24bit values, but 32bit word */
#define SPDIF_CHANNELS	2
#define	SPDIF_AUDIOFREQ	48
#define SPDIF_DOUBLEBUF	2
#define SPDIF_CS_WORD	0x02010204;		/* 48KHz, no copy..., but w/o channel */

int32_t SPDIF_out_test[SPDIF_CHANNELS * SPDIF_FRAMES] __aligned(4);
void GenerateSPDIFOut(void)
{
	int i;
	int32_t val = 0;
	double d;
	unsigned long CSword = SPDIF_CS_WORD;

	for (i = 0; i < SPDIF_FRAMES; i++)
	{
		d  = sin(((2 * M_PI) * i) / SPDIF_AUDIOFREQ);
		d *= (double)0x00700000;		//volume scaling
		val = (int32_t)d;
		val &= 0x00FFFFFF;
		if (i < 32)
		{
			val |= (CSword & 0x1) << 26;
			CSword >>= 1;
		}

		if (i == 20)
		{
			SPDIF_out_test[SPDIF_CHANNELS * i + 0] = val | (1 << 26);	/* channel A */
			SPDIF_out_test[SPDIF_CHANNELS * i + 1] = val;
		}
		else if (i == 21)
		{
			SPDIF_out_test[SPDIF_CHANNELS * i + 0] = val;
			SPDIF_out_test[SPDIF_CHANNELS * i + 1] = val | (1 << 26);	/* channel B */
		}
		else
		{
			SPDIF_out_test[SPDIF_CHANNELS * i + 0] = val;
			SPDIF_out_test[SPDIF_CHANNELS * i + 1] = val;
		}
	}
}

It sets the CS bits in all the 192 frames for SPDIF.

And I play this via SPDIF Out (using DMA):

#ifdef SPDIF_TEST
	GenerateSPDIFOut();
	MX_SAI_Init();
	HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) /*/ sizeof(uint32_t)*/));
#else

Remark: not sure if the size for the DMA start function is in bytes or in words.

What I have learned today by studying all what I could find about SPDIF and STM related documents:

  • the 32bit sample word for SPDIF contains also the CS, U, and V bits - they "must" be set (and sent to SPDIF DR)
  • these bits must be set (driven) correctly, esp. the CS channel contains important info for a receiver
  • SPDIF has 192 frames (with 2 sub-frames, one for each channel, as stereo)
  • The CS bits contain the encoding info about the audio (sample rate), if copy protected, also for which channel (A or B, left or right) this audio sample is
  • so, the CS bits as 12 words a 16bit = 24 bytes * 8 bit, are transferred with 1 bit per frame = 192 bits, as 192 frames, they are spread as single bits per frame, over the 192 SPDIF frames
  • the CS "word" is identical on every sub-frame (a 32bit word for a channel A or B), except: the channel coding bit differs on some place, on some particular bits
  • and: 192 frames for one SPDIF "packet": so, I have aligned with 192 stereo sample words, to make sure, that every new frame starts with the correct bit 0 of the CS channel. We cannot use any "random" buffer size for SPDIF.

At the end: it is a bit annoying to prepare the 32bit words for 24bit audio samples plus the CS, U and V bits. It means: I cannot directly forward 24bit audio samples, e.g. from I2S and play the same buffer as SPDIF out. I have to modify all audio samples and add these SPDIF bits. But OK: the DMA handler for HalfCplt and Cplt can do (if I am running fast enough).

It would be cool to have this feature - but I think it is not there:

  • preset the memory with 192 SPDIF frames (384 times 32bit words with stereo samples) with the correct CS, U, V bits set already
  • let me receive from I2S just 24bits, but fill it into this SPDIF buffer by overwriting just 24bits (3 bytes), do not touch the SPDIF bits set already. Transfer "audio words" via DMA as 24bit and write just 24bit - I think, this is not possible to do (if DMA support only byte, 16bit or 32bit words, nothing for 24bit "words").

It has also another implication:

  • Because of using SPDIF as Tx - the buffer must be aligned with the SPDIF!
  • it means: I have to have 192 SPDIF frames (for stereo: 384 int (32bit) words) as buffer or N times 192.
  • The buffer size depends now on the 192 SPDIF frames needed! (because the SPDIF CS bits start again with a new transmission of SPDIF frames 0..191).

It makes sense to me now (after understanding SPDIF a bit better), but still not receiving on STM32F769I-DISCO board, used as SPDIF Rx. Let's see (the SPDIF clock config in HAL drivers is "strange").

 

OK, I can confirm:

  1. SPDIF Out on SAI2_SD_B works:
    Even on STM32U5A5 LQFP64 package ("officially" not a SAI2 and CubeMX does not let me configure pins for SAI2) - the SAI2_SD_B can be used as SPDIF out - IT WORKS! (even on the LQFP64 package!)
  2. Yes, the CubeMX generated clock config for SPDIF is wrong - but I could fix
  3. There is no need to set the CS bits: even I have assumed it is needed to add the V, U, CS bits: no: they can remain all zero (getting 24bit audio samples from SAI1 and forward to SAI2 without modification - great) - IT WORKS!

Just:

The issue is!:
The DMA from memory to SAI_SD_B as SPDIF Out FAILS!
It writes all zero (or nothing), even the memory is properly filled with audio samples.

I have used a scope (SALEAE) and SPDIF decoder: yes, I see all words on SPDIF signal are zero on scope!

Why? No idea: the DMA from memory to SAI2 peripheral as SPDIF out is the issue.
I have generated the code via CubeMX, as circular buffer - but it does not work.

When I use Polling mode or INT mode to send the audio to SAI2_B - all works fine. Just the DMA fails.
Here, what I do now:

#if 1
	////HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)));		//FAILS!!!!!!!!
	HAL_SAI_Transmit_IT(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)));			//WORKS!
#else
	while (1)
	{
		HAL_SAI_Transmit(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)(sizeof(SPDIF_out_test) / sizeof(uint32_t)), 5000);	//WORKS!
	}
#endif

Why is the DMA to SAI2 not working?
It looks like I have also trouble meanwhile - even it was working - to get PDM MIC via SAI1 into memory - the DMA is "so crazy" (and seems to be the main issue when it does not work).

BTW: I run the MCU with 1V8: with a modified voltage divider for SPDIF out (and the cap) - it works fine.
I can receive with a STM32F769I-DISCO board and the SPDIF signal level is similar to running with 3V3.
Maybe just a need to set the speed to fastest for SAI2_B_SD out (PC12).

So,
YES, even on a STM32U5A5RJT6Q (LQFP64 package) - there is an SAI2 and SPDIF out on it works!
(the STM datasheet is wrong!)

I will close this thread and open a new one for DMA issue.