cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 SPI and DMA transfer/receive issue

JBias
Associate III

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!

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

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

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

3 REPLIES 3
TDK
Guru

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

If you feel a post has answered your question, please click "Accept as Solution".
JBias
Associate III

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!

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

If you feel a post has answered your question, please click "Accept as Solution".