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 | }
|