Skip to main content
Visitor II
February 13, 2023
Question

Receiving SPDIF data with STM32F446RET/CubeMX does not work

  • February 13, 2023
  • 11 replies
  • 4435 views

I'm trying to receive SPDIF data using an STM32F446RET using PB7 as SPDIFRX. The signal itself is perfect, a clear and sharp waveform can be seen directly at the input pin. The whole stuff is configured in CubeMX which also generated the code for interrupt data reception. From what I can see in the CubeMX-generated code, there is no obvious mistake. The major configuration looks like this:

 hspdif.Instance = SPDIFRX;
 hspdif.Init.InputSelection = SPDIFRX_INPUT_IN0;
 hspdif.Init.Retries = SPDIFRX_MAXRETRIES_63;
 hspdif.Init.WaitForActivity = SPDIFRX_WAITFORACTIVITY_ON;
 hspdif.Init.ChannelSelection = SPDIFRX_CHANNEL_A;
 hspdif.Init.DataFormat = SPDIFRX_DATAFORMAT_LSB;
 hspdif.Init.StereoMode = SPDIFRX_STEREOMODE_ENABLE;
 hspdif.Init.PreambleTypeMask = SPDIFRX_PREAMBLETYPEMASK_ON;
 hspdif.Init.ChannelStatusMask = SPDIFRX_CHANNELSTATUS_ON;
 hspdif.Init.ValidityBitMask = SPDIFRX_VALIDITYMASK_ON;
 hspdif.Init.ParityErrorMask = SPDIFRX_PARITYERRORMASK_ON;
 if (HAL_SPDIFRX_Init(&hspdif) != HAL_OK)
 {
 Error_Handler();
 }
 
 ...
 GPIO_InitStruct.Pin = GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF8_SPDIFRX;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 /* SPDIFRX interrupt Init */
 HAL_NVIC_SetPriority(SPDIF_RX_IRQn, 0, 5);
 HAL_NVIC_EnableIRQ(SPDIF_RX_IRQn);

Interrupts (both, global and the SPDIF-one) are enabled and data reception is initiated via a call to:

if (HAL_SPDIFRX_ReceiveDataFlow_IT(&hspdif,recvBuffer,8)==HAL_OK)
{
 spdifRecvComplete=0;
}

The interrupt routine to announce the completion of data reception looks like this:

void HAL_SPDIFRX_RxCpltCallback(SPDIFRX_HandleTypeDef *hspdif)
{
 spdifRecvComplete=1;
}

So the whole code is more or less some straight-forward stuff which makes use if the HAL-interface's interrupt data transfer functionality.

My problem: this routine is never called. More than this, the low-level interrupt service function SPDIF_RX_IRQHandler() is also never called. One strange thing: I see the function SPDIF_RX_IRQHandler(), its definition but I can not see where it is defined as interrupt handler/where a pointer to this function is handed over to some IRQ hardware register.

As said, the SPDIF input signal is perfect, the only special thing here: it comes with 100 kHz clock, not 96 kHz or 192 kHz or something common like that.

So what could be the reason for my problems? Why are no SPDIF data received?

    This topic has been closed for replies.

    11 replies

    Graduate II
    March 17, 2023

    As already said by LCE, the SPDIFRX peripheral has two clocks - the peripheral and the SPDIFRX_CLK (acquisition/kernel) clock. Check whether you are providing an adequate SPDIFRX_CLK. The sample rate of your signal doesn't matter as long as the SPDIFRX_CLK >= (11 * sample_rate * 64). Though the higher the SPDIFRX_CLK frequency, the more robust the reception is, because the incoming signal is resampled with SPDIFRX_CLK. On your device the best is to feed it with 180 MHz.

    I'm using SPDIFRX on F76x and it works like a charm. By the way, for such a non-trivial interface, it's super easy to manage. One can get it running with a single screen of code. And, by adding the second screen of code, one can also get the automatic re-synchronization, sample rate detection etc. Of course, I mean a normal code, not the HAL/Cube broken bloatware.

    CDupu.1Author
    Visitor II
    March 20, 2023

    > Of course, I mean a normal code, not the HAL/Cube broken bloatware.

    Is there an example of such a low-level SPDIF reception code available somewhere?

    Graduate II
    March 20, 2023

    To understand what's going wrong, it would be the best for you to:

    • read the ref manual
    • understand the registers
    • copy & rename the most important HAL functions and understand what these are doing
    • modify the HAL functions, throw out what you don't need (there will be a lot)
      • I prefer to not use the HAL macros like SET_BIT / CLEAR_BIT, but do it like: PERIPH->EXAMPLE_REG &= ~EXAMPLE_REG_BIT_X;
    • check what the HAL functions might have missed, (e.g. interrupt settings)

    That's basically how I "learned" the STM (work in progress...).

    I still use some HAL functions for some not so important stuff, or after I checked them if I could do "better": many HAL functions are "bloated" because they're made to fit many applications - not yours.