Skip to main content
Explorer II
March 28, 2025
Solved

STM32H7 SPI and DMA transfer/receive issue

  • March 28, 2025
  • 2 replies
  • 656 views

I want to transfer a buffer and receive a buffer of data using a full duplex SPI port with DMA on a STM32H7S3L8H (on the NUCLEO-H7S3L8). My problem is I am not able to modify the transfer buffer and have the modified version sent. I only need to modify the 1st two bytes. Here's the code:

void ade9430_read_it(SPI_HandleTypeDef *hspi, uint16_t reg_addr, uint8_t *reg_data)
{
	//int ret = HAL_OK;

	//gTxData[0] = reg_addr	 >> 4;
	//gTxData[1] = ADE9430_SPI_READ | reg_addr	 << 4;

	uint16_t Size;			//in bytes
	if (reg_addr >= 0x800) {
		static uint8_t gTxDmaData[60] = {0};	//{0x80, 0x18};
		Size = 30; 	//debug test
		gTxDmaData[0] = reg_addr	 >> 4;
		gTxDmaData[1] = ADE9430_SPI_READ | reg_addr	 << 4;
		HAL_SPI_TransmitReceive_DMA(hspi, (uint8_t *)gTxDmaData, reg_data, Size);	//debug DMA test
	}

Here is the resulting SPI activity:

JBias_0-1743204832297.png

Based on the reg_addr being passed the first two values should of been 0x80, 0x18.

Setting a breakpoint on line 14 and looking at the gTxDmaData[] array the first two values have been changed to  0x80, 0x18. However, the original array values of 0x0, 0x0 are what end up being sent.

I have initialized the gTxDmaData array with a pattern and verified that the original pattern is being sent and that the first two bytes are not changed by my code.

If I initialize the first two bytes to 0x80, 0x18 I get a valid response from my SPI slave, however the first two bytes of the response data buffer have not been changed from the original array but the rest of the response matches.

I am using:

JBias_1-1743205158404.png

Here's the initialization code:

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

 GPIO_InitTypeDef GPIO_InitStruct = {0};
 RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 if(spiHandle->Instance==SPI5)
 {
 /* USER CODE BEGIN SPI5_MspInit 0 */

 /* USER CODE END SPI5_MspInit 0 */

 /** Initializes the peripherals clock
 */
 PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI45;
 PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK2;
 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
 {
 Error_Handler();
 }

 /* SPI5 clock enable */
 __HAL_RCC_SPI5_CLK_ENABLE();

 __HAL_RCC_GPIOF_CLK_ENABLE();
 /**SPI5 GPIO Configuration
 PF8 ------> SPI5_MISO
 PF7 ------> SPI5_SCK
 PF6 ------> SPI5_NSS
 PF9 ------> SPI5_MOSI
 */
 GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_9;
 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 GPIO_InitStruct.Alternate = GPIO_AF5_SPI5;
 HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

 /* SPI5 DMA Init */
 /* GPDMA1_REQUEST_SPI5_TX Init */
 handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
 handle_GPDMA1_Channel1.Init.Request = GPDMA1_REQUEST_SPI5_TX;
 handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel1.Init.Direction = DMA_MEMORY_TO_PERIPH;
 handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_INCREMENTED;
 handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_FIXED;
 handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel1.Init.Priority = DMA_HIGH_PRIORITY;
 handle_GPDMA1_Channel1.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel1.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
 handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel1) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(spiHandle, hdmatx, handle_GPDMA1_Channel1);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 /* GPDMA1_REQUEST_SPI5_RX Init */
 handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0;
 handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_SPI5_RX;
 handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
 handle_GPDMA1_Channel0.Init.Direction = DMA_PERIPH_TO_MEMORY;
 handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_FIXED;
 handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_INCREMENTED;
 handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
 handle_GPDMA1_Channel0.Init.Priority = DMA_HIGH_PRIORITY;
 handle_GPDMA1_Channel0.Init.SrcBurstLength = 1;
 handle_GPDMA1_Channel0.Init.DestBurstLength = 1;
 handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT1;
 handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
 handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL;
 if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK)
 {
 Error_Handler();
 }

 __HAL_LINKDMA(spiHandle, hdmarx, handle_GPDMA1_Channel0);

 if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK)
 {
 Error_Handler();
 }

 /* SPI5 interrupt Init */
 HAL_NVIC_SetPriority(SPI5_IRQn, 3, 0);
 HAL_NVIC_EnableIRQ(SPI5_IRQn);
 /* USER CODE BEGIN SPI5_MspInit 1 */
 HAL_SPI_RegisterCallback(&hspi5, HAL_SPI_TX_RX_COMPLETE_CB_ID, SPI_ReceiveCompleteCallback);
 HAL_SPI_RegisterCallback(&hspi5, HAL_SPI_TX_COMPLETE_CB_ID, SPI_TransmitCompleteCallback);
 HAL_SPI_RegisterCallback(&hspi5, HAL_SPI_ERROR_CB_ID, SPI_ErrorCallback);

 //HAL_SPI_RegisterCallback(&hspi5, HAL_SPI_RxCpltCallback, SPI_ReceiveCompleteCallback);
 //HAL_SPI_RegisterCallback(&hspi5, HAL_SPI_TX_COMPLETE_CB_ID, SPI_TransmitCompleteCallback);
 /* USER CODE END SPI5_MspInit 1 */
 }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

 if(spiHandle->Instance==SPI5)
 {
 /* USER CODE BEGIN SPI5_MspDeInit 0 */

 /* USER CODE END SPI5_MspDeInit 0 */
 /* Peripheral clock disable */
 __HAL_RCC_SPI5_CLK_DISABLE();

 /**SPI5 GPIO Configuration
 PF8 ------> SPI5_MISO
 PF7 ------> SPI5_SCK
 PF6 ------> SPI5_NSS
 PF9 ------> SPI5_MOSI
 */
 HAL_GPIO_DeInit(GPIOF, GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_6|GPIO_PIN_9);

 /* SPI5 DMA DeInit */
 HAL_DMA_DeInit(spiHandle->hdmatx);
 HAL_DMA_DeInit(spiHandle->hdmarx);

 /* SPI5 interrupt Deinit */
 HAL_NVIC_DisableIRQ(SPI5_IRQn);
 /* USER CODE BEGIN SPI5_MspDeInit 1 */

 /* USER CODE END SPI5_MspDeInit 1 */
 }
}

Any insight is appreciated!

 

 

    This topic has been closed for replies.
    Best answer by TDK

    Is data cache enabled? Try disabling it. Could also make gTxDmaData volatile.

    2 replies

    TDKAnswer
    Super User
    March 28, 2025

    Is data cache enabled? Try disabling it. Could also make gTxDmaData volatile.

    JBiasAuthor
    Explorer II
    March 29, 2025

    TDK

    Disabling the data cache fixed the issue.

    I started with gTxDmaData as a volatile global and ended up with it just local to try to find a fix. I will be setting it back to a global volatile.

    I will also be setting up a dedicated memory block for these data buffers (64KB) and I will make sure data cache is disabled.

    Thanks!

    Super User
    March 29, 2025

    You can keep cache enabled if you align it properly and clean/invalidate at appropriate times. Sure is simpler to just disable it if you don't need the speed, though. Or disable it on only a portion of memory using MPU settings.

    How to use STM32 cache to optimize performance and power efficiency for STM32 MCUs - Application note