Forum: Mikrocontroller und Digitale Elektronik STM32G474 SPI Master mit DMA startet nicht neu


von Sven (sven01011986)


Lesenswert?

Guten Morgen zusammen,

ich habe eine Anwendung wo ein STM32G474 als SPI Master mit einem 
anderen ST-Controller als SPI Slave interagiert. Es handelt sich um 
Full-Duplex-DMA Übertragungen von etwa 500 Byte bei 10MBit 
Übertragungsrate. Der Slave signalisiert durch einen Digitalausgang, das 
er am Leben ist und dann startet die Kommunikation. Das klappt auch 
soweit stabil. Wenn der Slave allerdings nachdem die Kommunikation 
einmal gestartet ist sein "Lebenssignal" weg nimmt, sei es weil er 
selbst in einen Fehler gegangen ist oder weil die Daten durch 
Einkopplung fehlerhaft sind und das Ganze neu synchronisiert werden 
muss, dann startet der SPI-DMA nicht neu.

Ich kann nachvollziehen, dass der Master in die erwarteten Zustände geht 
um den SPI zurückzusetzen und dann neu zu starten allerdings erfolgt 
kein physischer Neustart. Das Clocksignal und auch MOSI bleiben 
dauerhaft auf low nachdem die Übertragung gestoppt wurde. Vermutlich 
fehlt mir nur eine Kleinigkeit um den SPI wieder zu starten aber aktuell 
komme ich nicht darauf. Vielleicht hat ja hier jemand eine Idee wo mein 
Fehler ist.

Nachfolgend mein Initialisierungscode und wie ich den SPI zurücksetze. 
Schonmal vielen Dank für die Unterstützung.

Die Initialisierung sind die Standard Cube Einstellungen.
1
void MX_SPI1_Init(void)
2
{
3
4
  /* USER CODE BEGIN SPI1_Init 0 */
5
6
  /* USER CODE END SPI1_Init 0 */
7
8
  /* USER CODE BEGIN SPI1_Init 1 */
9
10
  /* USER CODE END SPI1_Init 1 */
11
  hspi1.Instance = SPI1;
12
  hspi1.Init.Mode = SPI_MODE_MASTER;
13
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
14
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
15
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
16
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
17
  hspi1.Init.NSS = SPI_NSS_SOFT;
18
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
19
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
20
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
21
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
22
  hspi1.Init.CRCPolynomial = 7;
23
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
24
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
25
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
26
  {
27
    Error_Handler();
28
  }
29
  /* USER CODE BEGIN SPI1_Init 2 */
30
31
  /* USER CODE END SPI1_Init 2 */
32
33
}
1
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
2
{
3
4
  GPIO_InitTypeDef GPIO_InitStruct = {0};
5
  if(spiHandle->Instance==SPI1)
6
  {
7
  /* USER CODE BEGIN SPI1_MspInit 0 */
8
9
  /* USER CODE END SPI1_MspInit 0 */
10
    /* SPI1 clock enable */
11
    __HAL_RCC_SPI1_CLK_ENABLE();
12
13
    __HAL_RCC_GPIOA_CLK_ENABLE();
14
    /**SPI1 GPIO Configuration
15
    PA5     ------> SPI1_SCK
16
    PA6     ------> SPI1_MISO
17
    PA7     ------> SPI1_MOSI
18
    */
19
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
20
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
21
    GPIO_InitStruct.Pull = GPIO_NOPULL;
22
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
23
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
24
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
25
26
    /* SPI1 DMA Init */
27
    /* SPI1_RX Init */
28
    hdma_spi1_rx.Instance = DMA1_Channel4;
29
    hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX;
30
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
31
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
32
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
33
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
34
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
35
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
36
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
37
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
38
    {
39
      Error_Handler();
40
    }
41
42
    __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi1_rx);
43
44
    /* SPI1_TX Init */
45
    hdma_spi1_tx.Instance = DMA1_Channel5;
46
    hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;
47
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
48
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
49
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
50
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
51
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
52
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
53
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
54
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
55
    {
56
      Error_Handler();
57
    }
58
59
    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi1_tx);
60
61
  /* USER CODE BEGIN SPI1_MspInit 1 */
62
63
  /* USER CODE END SPI1_MspInit 1 */
64
  }
65
}

Der Code zum zurücketzen bzw. auch zum initialen Starten des SPI auf dem 
Master. Der Counter dient dazu um den evtl. noch laufenden SPI-DMA auch 
tatsächlich "leer" laufen zu lassen. Eigentlich sollte das nicht nötig 
sein da ich den SPI abbreche und zurücksetze. Es spielt auch für das 
verhalten keine Rolle ob ich den Counter abwarte um zurückzusetzen oder 
ob ich direkt zurücksetze wenn das Lebenssignal wegfällt. Clocksignal 
und MOSI werden nicht wieder gestartet und ohne Clock schickt 
logischerweise auch der Slave keine Daten.
1
  u16SPICounter++;
2
  if ((LL_GPIO_ReadInputPort(SPI1_INTERN_CS_GPIO_Port) & SPI1_INTERN_CS_Pin) == SPI1_INTERN_CS_Pin) {
3
    HAL_SPI_TransmitReceive_DMA(&hspi1, ((uint8_t*) u8SPIInternTXArr),
4
        ((uint8_t*) u8SPIInternRXArr), (MAX_PARAMS * 2));
5
    u16SPICounter = 0;
6
    LL_GPIO_ResetOutputPin(TEST_PIN1_DO_GPIO_Port, TEST_PIN1_DO_Pin);
7
  } else {
8
    if(u16SPICounter == 50){
9
      HAL_SPI_Abort_IT(&hspi1);
10
      __HAL_RCC_SPI1_FORCE_RESET();
11
      __HAL_RCC_SPI1_RELEASE_RESET();
12
      LL_GPIO_SetOutputPin(TEST_PIN1_DO_GPIO_Port, TEST_PIN1_DO_Pin);
13
    }
14
  }

von Andreas B. (abm)


Lesenswert?

Das SPI bei den STM32 klemmt gelegentlich mit BSY auf '1', s. die 
diversen Errata, aber ein Reset über RCC sollte eigentlich reichen ...
Wo wird der DMA-Controller nach Abbruch eigentlich zurückgesetzt?

Es bleibt wohl nichts übrig, als sich alle SPI- und DMA-Register 
(insbes. Status-Reg.) mal anzusehen, und zwar vor und nach dem 
HAL_SPI_Abort_IT und dem __HAL_RCC_SPI1_RELEASE_RESET, vielleicht gibt's 
da irgendwas Auffälliges.

von Sven (sven01011986)


Lesenswert?

@abm: Ich bin bisher anhand der Beschreibung des HAL_SPI_ABORT_IT davon 
ausgegangen, dass dieser den DMA zurücksetzt. Da werde ich aber jetzt 
mal genauer rein schauen.

Und auch Danke für die Info mit dem BSY, das werde ich nochmal testen 
und abfangen.

von Sven (sven01011986)


Lesenswert?

Noch eine Ergänzung weil mein vorheriger Beitrag nichtmehr editierbar 
ist:

__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();

haben den Restart des DMA verhindert, nachdem ich diese durch einen 
Hinweis aus einem anderen Forum deaktiviert habe läuft der SPI wieder 
an. Allerdings macht der Master das auch nur für 1 oder 2 Minuten bevor 
die SPI-Kommunikation dann nicht mehr neu startet.

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.