Forum: Mikrocontroller und Digitale Elektronik STM32 H7 - SPI "echo" funktioniert nicht


von Stefan H. (cheeco)


Lesenswert?

Hallo Forum,

ich möchte auf einem STM32H750 Mikrocontroller ein simples SPI-Slave 
"echo" ans laufen bekommen. Dafür sollen über SPI ein Zeichen über 
Interrupt empfangen werden und dann direkt wieder über SPI 
herausgeschrieben werden soll. Zur Zeit kommt allerdings nur ein 0x00 
zurück. Was schon funktioniert:

- Der RX-Interrupt wird korrekt ausgelöst und empfängt die Zeichen.
- Physikalisch ist die Verbindung zwischen Slave und Master in Ordnung 
(Ich habe den Pin manuell auf high gezogen und 0xFF empfangen).

Ich habe etwas ähnliches schon auf dem STM32F767 implementiert, aber 
irgendwie scheint das SPI Interface anders zu ticken. Ich vermute, dass 
das Problem mit den TSIZE und CSTART-Variablen / Flags zusammenhängt.

Vielleicht hat ja schonmal jemand so was ähnliches gehabt - danke für 
die Hilfe!

Hier ist der Code:
1
void SPI1_IRQHandler(void) {
2
3
    /* Check RXP flag value in ISR register */
4
    if(LL_SPI_IsActiveFlag_RXP(SPI1) && LL_SPI_IsEnabledIT_RXP(SPI1))
5
    {
6
      uint8_t dataecho;
7
      dataecho = LL_SPI_ReceiveData8(SPI1);
8
      LL_SPI_TransmitData8(SPI1, dataecho);
9
    }
10
}
11
12
static void GPIOPins_SPI1_Config(void)
13
{
14
  /* (1) Enables GPIO clock and configures the SPI1 pins ********************/
15
  /* Enable the peripheral clock of GPIOE */
16
  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
17
18
  /* SPI1 SCK GPIO pin configuration*/
19
  GPIO_InitStruct.Pin       = LL_GPIO_PIN_4 | LL_GPIO_PIN_5 | LL_GPIO_PIN_6 | LL_GPIO_PIN_7;
20
  GPIO_InitStruct.Mode      = LL_GPIO_MODE_ALTERNATE;
21
  GPIO_InitStruct.Pull      = LL_GPIO_PULL_DOWN;
22
  GPIO_InitStruct.Speed     = LL_GPIO_SPEED_HIGH;
23
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
24
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
25
26
  /* (2) Configure NVIC for SPI4 transfer complete/error interrupts **********/
27
  /* Set priority for SPI4_IRQn */
28
  NVIC_SetPriority(SPI1_IRQn, 0);
29
  /* Enable SPI1_IRQn           */
30
  NVIC_EnableIRQ(SPI1_IRQn);
31
}
32
33
static void SPI1_Config (void)
34
{
35
  /* Configure SPI SLAVE *****************************************************/
36
  /* Enable SPI4 Clock */
37
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
38
39
  /* Configure the SPI4 parameters */
40
  SPI_InitStruct.BaudRate          = LL_SPI_BAUDRATEPRESCALER_DIV2;
41
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
42
  SPI_InitStruct.ClockPhase        = LL_SPI_PHASE_1EDGE;
43
  SPI_InitStruct.ClockPolarity     = LL_SPI_POLARITY_LOW;
44
  SPI_InitStruct.BitOrder          = LL_SPI_MSB_FIRST;
45
  SPI_InitStruct.DataWidth         = LL_SPI_DATAWIDTH_8BIT;
46
  SPI_InitStruct.NSS               = LL_SPI_NSS_HARD_INPUT;
47
  SPI_InitStruct.CRCCalculation    = LL_SPI_CRCCALCULATION_DISABLE;
48
  SPI_InitStruct.Mode              = LL_SPI_MODE_SLAVE;
49
  LL_SPI_Init(SPI1, &SPI_InitStruct);
50
51
// Set FIFO threshold
52
  LL_SPI_SetFIFOThreshold(SPI1,LL_SPI_FIFO_TH_01DATA);      
53
54
  /* Lock GPIO for master to avoid glitches on the clock output */
55
  LL_SPI_DisableGPIOControl(SPI1);
56
  LL_SPI_DisableMasterRxAutoSuspend(SPI1);
57
58
  /* Set number of data to transmit */
59
  LL_SPI_SetTransferSize(SPI1, 1);
60
61
  /* Enable SPI1 */
62
  LL_SPI_Enable(SPI1);
63
64
  /* Enable RXP Interrupt */
65
  LL_SPI_EnableIT_RXP(SPI1);
66
}

von Stefan F. (Gast)


Lesenswert?

Wenn der Master 1 Byte an den Slave sendet, muss der Master noch ein 
weiteres (dummy) Byte senden, damit der Slave antworten kann, denn der 
Master gibt den Takt vor. Hast du das berücksichtigt?

von Stefan H. (cheeco)


Lesenswert?

Hallo Stefanus,

ich sende eine ganze Reihe von Bytes (vielleicht 30), aber leider sind 
alle Antworten 0x00.

Das Problem scheint wohl nicht ganz einfach zu sein - oder der H7 ist 
noch nicht so sehr weit verbreitet.

Grüße,

Stefan

von Stefan H. (cheeco)


Lesenswert?

Ich habe die Lösung gefunden. Das Problem ist, dass beim ersten Empfang 
ein Transmit Underrun auftritt. Sobald dieser Underrun einmal auftritt, 
dann wird der Transmitter abgeschaltet und auch nicht wieder 
angeschaltet, wenn Daten vorhanden sind. Erst wenn man das Flag wieder 
löscht, dann geht die Übertragung weiter. Die ISR muss also 
folgendermaßen geändert werden:
1
void SPI1_IRQHandler(void) {
2
3
    /* Check RXP flag value in ISR register */
4
    if(LL_SPI_IsActiveFlag_RXP(SPI1) && LL_SPI_IsEnabledIT_RXP(SPI1))
5
    {
6
      uint8_t dataecho;
7
      dataecho = LL_SPI_ReceiveData8(SPI1);
8
      LL_SPI_TransmitData8(SPI1, dataecho);
9
      LL_SPI_ClearFlag_UDR(SPI1);
10
    }
11
}

Vielleicht hilft's ja jemandem.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.