2024-03-27 07:55 PM
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):
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:
#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:
////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)
HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)SPDIF_out_test, (uint16_t)sizeof(SPDIF_out_test) / sizeof(uint32_t));
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:
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:
Also not really clear for me:
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)
Solved! Go to Solution.
2024-04-02 12:45 AM
OK, I can confirm:
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.
2024-03-27 09:13 PM
If I understand correctly:
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.
2024-03-27 09:24 PM
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.
2024-03-27 09:34 PM
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).
2024-03-28 08:53 PM
OK, still not yet working - but I found two major issues:
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:
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:
It has also another implication:
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").
2024-04-02 12:45 AM
OK, I can confirm:
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.