STM32 empfängt keine SPDIF-Daten

Gast #7346660
Lesenswert?

Ich versuche hier, mit einem STM32F466RE einen SPDIF-Datenstrom an PB7 zu empfangen. Der Code ist mit CubeMX erzeugt und sollte daher eigentlich passen, wenn ich mir ansehe, was CubeMX generiert hat, kann ich keinen offensichtlichen Fehler erkennen. Der SPDIF-Datenstrom ist - direkt am Eingangspin gemessen - ein perfektes und astrein sauberes Signal. Der zugehörige sowie die globalen Interrupts sind aktiviert. Trotzdem wird nichts empfangen, die Receive-Interruptfunktion wird nie aufgerufen:

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

Die Initialisierung von CubeMX sieht inklusive des Pinmappings so aus (zumindest die relevanten Teile, der Rest ist ja eh' der immer gleiche, generierte Code):

1
   hspdif.Instance = SPDIFRX;
2
   hspdif.Init.InputSelection = SPDIFRX_INPUT_IN0;
3
   hspdif.Init.Retries = SPDIFRX_MAXRETRIES_63;
4
   hspdif.Init.WaitForActivity = SPDIFRX_WAITFORACTIVITY_ON;
5
   hspdif.Init.ChannelSelection = SPDIFRX_CHANNEL_A;
6
   hspdif.Init.DataFormat = SPDIFRX_DATAFORMAT_LSB;
7
   hspdif.Init.StereoMode = SPDIFRX_STEREOMODE_ENABLE;
8
   hspdif.Init.PreambleTypeMask = SPDIFRX_PREAMBLETYPEMASK_ON;
9
   hspdif.Init.ChannelStatusMask = SPDIFRX_CHANNELSTATUS_ON;
10
   hspdif.Init.ValidityBitMask = SPDIFRX_VALIDITYMASK_ON;
11
   hspdif.Init.ParityErrorMask = SPDIFRX_PARITYERRORMASK_ON;
12
   if (HAL_SPDIFRX_Init(&hspdif) != HAL_OK)
13
   {
14
      Error_Handler();
15
   }
16
  
17
  ...
18

19
   GPIO_InitStruct.Pin = GPIO_PIN_7;
20
   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
21
   GPIO_InitStruct.Pull = GPIO_PULLUP;
22
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
23
   GPIO_InitStruct.Alternate = GPIO_AF8_SPDIFRX;
24
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
25

26
   /* SPDIFRX interrupt Init */
27
   HAL_NVIC_SetPriority(SPDIF_RX_IRQn, 0, 5);
28
   HAL_NVIC_EnableIRQ(SPDIF_RX_IRQn);

An der Funktion, die den Empfang der Daten starten sollte, ist auch nichts dramatisch kompliziertes:

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

Google hilft nicht wirklich weiter, entweder finde ich Beispielcode, der auch nur aus CubeMX stammt, oder der für einen anderen STM32-Typen ist und letztenendes auch keine Erkenntnisse bringt, die das Problem lösen würden.

Das Einzige, was in meinem Fall speziell ist: die eingehenden Daten haben 100 kHz statt 96 kHz oder 192 khz oder irgend ein anderes Vielfaches von 24 kHz - aber ich kann nirgendwo im Handbuch erkennen, dass das ein Problem wäre, es ist nur von einer Maxialfrequenz von 192 kHz die Rede.

Was könnte hier falsch sein/fehlen?

Gast #7346686
Lesenswert?

Lothar J. schrieb:

IRQ Receive Routine?

...wird von dem CubeMX-Code gemacht. Wenn es so funktioniert, wie es soll, erhalte ich ein "Receive Complete" über die Funktion HAL_SPDIFRX_RxCpltCallback() und finde dann die empfangenen Daten in meinem per HAL_SPDIFRX_ReceiveDataFlow_IT() übergebenen recvBuffer. Aber eben dieses "Receive Complete" kommt nie.

#7346715
Lesenswert?

Shinner schrieb:

...wird von dem CubeMX-Code gemacht. Wenn es so funktioniert, wie es soll, erhalte ich ein "Receive Complete" über die Funktion HAL_SPDIFRX_RxCpltCallback() und finde dann die empfangenen Daten in meinem per HAL_SPDIFRX_ReceiveDataFlow_IT() übergebenen recvBuffer. Aber eben dieses "Receive Complete" kommt nie.

Dann würde ich in dieser IRQ Routine suchen per Debugger.
Meine Erfahrungen kommen aus der EFM32 Ecke, die sind ja ähnlich und eine HAL gibt es da auch. Nur hat die selten vollständigen Code generiert, wie soll sie auch.

Blackbird

Gast #7346965
Lesenswert?

Das wäre SPDIF_RX_IRQHandler() - die wird niemals aufgerufen.

Tatsächlich kann ich nicht erkennen, wo die jemals als IRQ-Einsprungpunkt gesetzt werden würde. Allerdings sehe ich das bei USART2_IRQHandler() auch nicht, aber der UART-Interrupt funktioniert.

Gast #7347237
Lesenswert?

Shinner schrieb:

Tatsächlich kann ich nicht erkennen, wo die jemals als IRQ-Einsprungpunkt gesetzt werden würde.

Üblicherweise ist diese Funktion in der Datei <stm32f4xx_it.c> zu finden ....

1
/******************************************************************************/
2
/* STM32F4xx Peripheral Interrupt Handlers                                    */
3
/* Add here the Interrupt Handlers for the used peripherals.                  */
4
/* For the available peripheral interrupt handler names,                      */
5
/* please refer to the startup file (startup_stm32f4xx.s).                    */
6
/******************************************************************************/
7
/**
8
  * @brief This function handles SPDIF-RX global interrupt.
9
  */
10
void SPDIF_RX_IRQHandler(void)
11
{
12
  /* USER CODE BEGIN SPDIF_RX_IRQn 0 */
13

14
  /* USER CODE END SPDIF_RX_IRQn 0 */
15
  HAL_SPDIFRX_IRQHandler(&hspdif);
16
  /* USER CODE BEGIN SPDIF_RX_IRQn 1 */
17

18
  /* USER CODE END SPDIF_RX_IRQn 1 */
19
}
Gast #7347312
Lesenswert?

mitlesa schrieb:

Shinner schrieb:

Tatsächlich kann ich nicht erkennen, wo die jemals als IRQ-Einsprungpunkt gesetzt werden würde.

Üblicherweise ist diese Funktion in der Datei <stm32f4xx_it.c> zu finden ....

Nein, die Funktion selber ist im Usercode zu finden, weil dort auch das SPDIF-Handle liegt, welches für die weitere Bearbietung des Interrupt benötigt wird.

Die Frage ist, wo wird der POINTER auf diese Funktion in die Hardware geschrieben? Das muss ja irgendwo passieren, so dass der Interrupt weiß, wo hingesprungen werden muss. Und diese Zuweisung Hardware Interrupt -> aufzurufende Funktion SPDIF_RX_IRQHandler() fehlt mir hier irgendwie komplett.

#7347325
Lesenswert?

mitlesa hat schon recht

normalerweise ist SPDIF_RX_IRQHandler als weak definiert in einem deiner startup files. startup_stm32f...s dürfte das heißen

dort findest du dann ein EXPORT SPDIF_RX_IRQHandler [WEAK] und das wird in der xxx_it.c implementiert. Dort wird dann der HAL IRQHandler aufgerufen, der dann wiederum deinen callback aufruft.

Gast #7347415
Lesenswert?

A. B. schrieb:

normalerweise ist SPDIF_RX_IRQHandler als weak definiert

Auch dann fehlt mir die Verbindung zwischen Code und Hardware! Die MCU springt ja keinen String "SPDIF_RX_IRQHandler" an, sondern eine Adresse, hinter der sich dieser IRQ-Handler verbirgt, der halt zufällig "SPDIF_RX_IRQHandler" heißt.

Gast #7347787
Lesenswert?

Shinner schrieb:

Auch dann fehlt mir die Verbindung zwischen Code und Hardware! Die MCU springt ja keinen String "SPDIF_RX_IRQHandler" an, sondern eine Adresse, hinter der sich dieser IRQ-Handler verbirgt, der halt zufällig "SPDIF_RX_IRQHandler" heißt.

Das klingt deutlich nach Beratungsresistenz bzw. Faulheit einfach nachzusehen wo was ist. Also hier noch im Detail für die Faulen unter uns: Im Anhang ein Auszug aus <startup_stm32f446xx.s>. Dort sind am Anfang viele 32-Bit Worte (also Vektoren) definiert wobei für jeden Offset von Null ein bestimmter auf die Hardware zugeschnittener Platz für einen Interrupt reserviert ist. Der Offset bestimmt welcher Hardware-IRQ gemeint ist, der Wert bestimmt wo hingesprungen werden soll. Wer's jetzt nicht kapiert dem ist nicht mehr zu helfen.

Angehängte Dateien:
#7406608
Lesenswert?

Ich finde das Thema S/P-DIF mit STM32 hochspannend. Denn es gibt von TI Class-D Verstärkerchips, die einen Digital-Eingang haben und man kann mit dem STM32 dann auch über die I2C Schnittstelle bei dem TI Class-D Verstärker einiges einstellen, z.b. Mehrkanal-EQ, Lautstärke etc. Mit einem Bluetoothmodul könnte man auch eine Fernbedienung übers Handy realisieren, etc. Aktivboxen mit digitaler Frequenzweiche, die Frequenzcharakteristik übers Handy konfiguieren etc. Raumkorrektur. Da wäre ein STM32 in der Mitte als Controller mit SP-DIF Eingang für den ganzen Spaß eine interessante Option.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren