Ich hab leider erneut Probleme bei der Peripherie-Konfiguration des STM32H7. Diesmal ist ist es SPI DMA welches nicht funktioniert. Ich versuche gesteuert von einem Falling-Edge Interrupt eines GPIOs einen SPI DMA Transmit/Receive auszulösen. Dazu meine GPIO-Konfiguration:
1 | __HAL_RCC_GPIOD_CLK_ENABLE(); |
2 | |
3 | GPIO_InitTypeDef drdy_typedef; |
4 | drdy_typedef.Pin = GPIO_PIN_15; |
5 | drdy_typedef.Mode = GPIO_MODE_IT_FALLING; |
6 | drdy_typedef.Pull = GPIO_NOPULL; |
7 | HAL_GPIO_Init(GPIOD, &drdy_typedef); |
8 | |
9 | /* EXTI interrupt init*/ |
10 | HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); |
11 | HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); |
mit Interrupt:
1 | void EXTI15_10_IRQHandler(void) { |
2 | // trigger |
3 | |
4 | HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); |
5 | HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15); |
6 | } |
Meine SPI-Konfiguration:
1 | spi_handle.Instance = SPI1; |
2 | spi_handle.Init.Mode = SPI_MODE_MASTER; |
3 | spi_handle.Init.Direction = SPI_DIRECTION_2LINES; |
4 | spi_handle.Init.DataSize = SPI_DATASIZE_8BIT; |
5 | spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW; |
6 | spi_handle.Init.CLKPhase = SPI_PHASE_2EDGE; |
7 | spi_handle.Init.NSS = SPI_NSS_SOFT; |
8 | spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; |
9 | spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB; |
10 | spi_handle.Init.TIMode = SPI_TIMODE_DISABLE; |
11 | spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; |
12 | spi_handle.Init.CRCPolynomial = 0x00; |
13 | spi_handle.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; |
14 | spi_handle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; |
15 | spi_handle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA; |
16 | spi_handle.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; |
17 | spi_handle.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN; |
18 | spi_handle.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; |
19 | spi_handle.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; |
20 | spi_handle.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; |
21 | spi_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; |
22 | spi_handle.Init.IOSwap = SPI_IO_SWAP_DISABLE; |
23 | |
24 | const HAL_StatusTypeDef ret = HAL_SPI_Init(&spi_handle); |
25 | if(ret != HAL_OK) { |
26 | std::cout << "[Error] HAL_SPI_Init failed!\r\n"; |
27 | exit(-1); |
28 | } |
29 | |
30 | |
31 | HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0); |
32 | HAL_NVIC_EnableIRQ(SPI1_IRQn); |
und SPI DMA:
1 | HAL_DMA_MuxSyncConfigTypeDef pSyncConfig; |
2 | |
3 | __HAL_RCC_DMA1_CLK_ENABLE(); |
4 | |
5 | hdma_spi1_rx.Instance = DMA1_Stream0; |
6 | hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX; |
7 | hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; |
8 | hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE; |
9 | hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE; |
10 | hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
11 | hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
12 | hdma_spi1_rx.Init.Mode = DMA_NORMAL; |
13 | hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW; |
14 | hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; |
15 | if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK) |
16 | { |
17 | Error_Handler(); |
18 | } |
19 | |
20 | pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_EXTI0; |
21 | pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_NO_EVENT; |
22 | pSyncConfig.SyncEnable = DISABLE; |
23 | pSyncConfig.EventEnable = ENABLE; |
24 | pSyncConfig.RequestNumber = 1; |
25 | if (HAL_DMAEx_ConfigMuxSync(&hdma_spi1_rx, &pSyncConfig) != HAL_OK) |
26 | { |
27 | Error_Handler(); |
28 | } |
29 | |
30 | __HAL_LINKDMA(&spi_handle,hdmarx,hdma_spi1_rx); |
31 | |
32 | /* SPI1_TX Init */ |
33 | hdma_spi1_tx.Instance = DMA1_Stream1; |
34 | hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX; |
35 | hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; |
36 | hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE; |
37 | hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE; |
38 | hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; |
39 | hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; |
40 | hdma_spi1_tx.Init.Mode = DMA_NORMAL; |
41 | hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW; |
42 | hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; |
43 | if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK) |
44 | { |
45 | Error_Handler(); |
46 | } |
47 | |
48 | pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_EXTI0; |
49 | pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_NO_EVENT; |
50 | pSyncConfig.SyncEnable = DISABLE; |
51 | pSyncConfig.EventEnable = ENABLE; |
52 | pSyncConfig.RequestNumber = 1; |
53 | if (HAL_DMAEx_ConfigMuxSync(&hdma_spi1_tx, &pSyncConfig) != HAL_OK) |
54 | { |
55 | Error_Handler(); |
56 | } |
57 | |
58 | __HAL_LINKDMA(&spi_handle,hdmatx,hdma_spi1_tx); |
59 | |
60 | /* DMA interrupt init */ |
61 | /* DMA1_Stream0_IRQn interrupt configuration */ |
62 | HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0); |
63 | HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); |
64 | /* DMA1_Stream1_IRQn interrupt configuration */ |
65 | HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0); |
66 | HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); |
67 | /* DMAMUX1_OVR_IRQn interrupt configuration */ |
68 | HAL_NVIC_SetPriority(DMAMUX1_OVR_IRQn, 0, 0); |
69 | HAL_NVIC_EnableIRQ(DMAMUX1_OVR_IRQn); |
Was passiert: - EXTI15_10_IRQHandler (GPIO-Interrupt) feuert, ich starte die Übertragung mit:
1 | SCB_CleanDCache_by_Addr(reinterpret_cast<uint32_t*>(((uint32_t)spiTxBuffer) & ~uint32_t(0x1F)), sizeof(spiTxBuffer) + 32); |
2 | SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)spiRxBuffer) & ~(uint32_t)0x1F), sizeof(spiRxBuffer) + 32); |
3 | const auto ret = HAL_SPI_TransmitReceive_DMA(this->spi_handle, spiTxBuffer, spiRxBuffer, BytesPerTimerInterval); |
4 | |
5 | if(ret != HAL_OK) { |
6 | std::cout << "HAL_SPI_TransmitReceive failed: " << (int)ret << "\r\n"; |
7 | } |
(Übertragung liefert "HAL_OK") - DMA1_Stream0_IRQHandler und DMA1_Stream1_IRQHandler feuern:
1 | void DMAMUX1_OVR_IRQHandler(void) { |
2 | HAL_DMAEx_MUX_IRQHandler(&hdma_spi1_rx); |
3 | HAL_DMAEx_MUX_IRQHandler(&hdma_spi1_tx); |
4 | } |
5 | void DMA1_Stream0_IRQHandler(void) { |
6 | std::cout << "DMA1 Stream 0 (RX)\r\n"; |
7 | HAL_DMA_IRQHandler(&hdma_spi1_rx); |
8 | } |
9 | void DMA1_Stream1_IRQHandler(void) { |
10 | std::cout << "DMA1 Stream 0 (TX)\r\n"; |
11 | // Handle Interrupt |
12 | HAL_DMA_IRQHandler(&hdma_spi1_tx); |
13 | } |
- ich überprüfe das Ergebnis:
1 | std::cout << "FIRST 4 STATUS BITS: ["; |
2 | std::cout << (int)( spiRxBuffer[0] >> 4 ) << "]\r\n"; |
Ergebnis ist 0 (sollte es eigentlich nicht sein) und hab hier wird nie wieder ein EXTI15_10_IRQHandler (GPIO) gefeuert, sobald ich das DMA_Transmit weglasse feuert er wieder ständig (mit Oszi gemessen liegt auch ein entsprechendes Signal an). Warum ich das mit dem Cache gemacht hab: https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices Konkret hab ich die Buffer so global definiert:
1 | __attribute__((section(".dma_buffer"))) __attribute__ ((aligned (32))) uint8_t spiTxBuffer[BytesPerInterval]; |
2 | __attribute__((section(".dma_buffer"))) __attribute__ ((aligned (32))) uint8_t spiRxBuffer[BytesPerInterval]; |
Weiterhin hab ich mit dem Oszi festgestellt, dass kein SPI-Transmit stattfindet (also SCLK immer auf low Pegel). Bei diesem Transmit sollen eigentlich keine Daten übertragen sondern nur empfangen werden (deswegen ist der spiTxBuffer-Inhalt auch auf 0 gesetzt), allerdings sehe ich auch keine Daten am MISO-Pin. Hat jemand eine Idee? Vor allem das mit dem GPIO-Interrupt verwirrt mich. P.S: Alle Interrupts sind diesmal in "extern "C"" definiert, daran sollte es also nicht liegen (und sie feuern ja auch)