cancel
Showing results for 
Search instead for 
Did you mean: 

GPDMA SPI tx+rx circular mode on STM32H5 possible incorrect initialization code

On a Nucleo-H563ZI with CubeIDE 1.14.0 and firmware package for H5 1.1.1.

I managed to get SPI transmit and receive using DMA, triggered by a timer, going not using linked lists. I get my requested number of transmissions and results into my buffers as witnessed on an oscilloscope and a live watchpoint.

But when I enable circular mode, no other modifications, in MX_SPI1_Init - HAL_SPI_Init - HAL_SPI_MspInit it sets up

 NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_HALFWORD;

builds the node (whatever that is), inserts it into the correct DMA channel, sets circular mode, basically looks like magic but I can imagine what it is doing. But then the stuff in the NodeConfig doesn't get applied to handle_GPDMA1_Channel1, so later when I finally call HAL_SPI_TransmitReceive_DMA, it gets grumpy around line 2230 because hspi->hdmarx->Init is all zeros still. It never got updated maybe?

I think there is a problem with HAL_SPI_MspInit in stm32h5xx_hal_msp.c .

 

Thanks,

Andrei (from the Great (not very) White North)

10 REPLIES 10

Here's the project. 

In HAL_SPI_MspInit (in spi.c with separate files for each peripheral or main.c without), the initialization of NodeConfig.Init looks correct, but there doesn't seem to be any code to transfer it from NodeConfig.Init into the Init member of the spiHandle passed into the function.

 

UL
Associate III

Were you able to solve this issue? I have been struggling to do something similar on the STMU5 MCU

I suppose I did.

SPI set up as a full-duplex master. With DMA for SPI TX set up as a standard request rather than a linked-list request, with trigger on TIM15 TRGO. SPI RX pretty much out of the box, peripheral to memory, source address increment disabled, destination enabled.

Transfers started using:

halStatus = HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t*) &forceData, (uint8_t*) rawADCCounts, 

NUMBER_OF_VALUES_TO_TRANCEIVE * 2);

And then call HAL_SPI_TransmitReceive_DMA again in HAL_SPI_TxRxCpltCallback, or else it will stop automatically after one request.

But I gave up on using linked-list mode. I seem to remember finding a YouTube video from the ST MOOC for the H5 that went over DMA and used standard mode. They never went into linked-list mode and I was more interested in getting ANYTHING working than chasing the linked-list bone.

 

A

Got it. Okay I was able to get something similar working in linked-list mode by using this function: __HAL_LINKDMA(&hspi1, hdmarx, handle_GPDMA1_Channel15);

 

 

bbchili72
Associate

Check Plz!

Okay, I'd like to bring up this issue again.

Now Nucleo-H563ZI, CubeMX 5.16.1, CubeIDE 2.0.0, firmware package for H5 1.5.1.

As described in the original post, a call to HAL_SPI_TransmitReceive_DMA (see the previously attached project) always fails in the code:

  /* Packing mode management is enabled by the DMA settings */
  if (((hspi->Init.DataSize > SPI_DATASIZE_16BIT) && \
       ((hspi->hdmarx->Init.DestDataWidth != DMA_DEST_DATAWIDTH_WORD) || \
        (hspi->hdmatx->Init.SrcDataWidth != DMA_SRC_DATAWIDTH_WORD)) && \
       (IS_SPI_FULL_INSTANCE(hspi->Instance))) || \
      ((hspi->Init.DataSize > SPI_DATASIZE_8BIT) && \
       ((hspi->hdmarx->Init.DestDataWidth == DMA_DEST_DATAWIDTH_BYTE) || \
        (hspi->hdmatx->Init.SrcDataWidth == DMA_SRC_DATAWIDTH_BYTE))))
  {
    /* Restriction the DMA data received is not allowed in this mode */
    /* Unlock the process */
    __HAL_UNLOCK(hspi);
    return HAL_ERROR;
  }

because hspi->hdmarx->Init.DestDataWidth is 0, even though it is set up in HAL_SPI_MspInit to have:

    NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;

 So, somewhere in the initialization sequence, the NodeConfig structure is not being applied to the SPI handle.

Can I ask someone in ST support to take a look at this please? 

Do not use HAL_SPI_TransmitReceive_DMA().

"I am using Gemini for Korean-to-English translation. Please understand that there may be some unnatural phrasing."

  • The attached archive provides an example implementation for sampling 8-channel data at 1 kHz using the Analog Devices AD7689.
  • This example utilizes SPI1, Timer 15, GPDMA1 (channels 0 and 1), and LINKEDLIST on the STM32.
  • Please refer to the nucleo_u575zi.ioc file for the specific configurations.
  • The SPI1 settings have been configured to match the AD7689's SPI timing requirements.
  • Timer 15 is configured to trigger update events at a 1 kHz interval.
  • Channels 0 and 1 of GPDMA1 operate in circular mode.
  • The LINKED LIST structure defines dedicated queues and nodes for both SPI1 transmission (TX) and reception (RX).
  • Configure the source address of Node_tx with (uint32_t)adc_cfg_value and the destination address of Node_rx with (uint32_t)adc_out_value. Both are defined as arrays within ad7689.c. The adc_cfg_value array holds the command sequences for AD7689 channel switching and configuration, whereas adc_out_value serves as the buffer for incoming SPI data.
  • The implementation is finalized by following the sequence in the adc_start() function within ad7689.c. Commented code blocks are provided as a reference for performance verification between interrupt-driven and polling methods. Key callbacks for the interrupt implementation include the DMA Rx Complete Callback and the Timer 15 Period Elapsed Callback.
  • As you can see in the code, the HAL_SPI_TransmitReceive_DMA() function is not called. I initially made several attempts to use this function myself. However, I concluded that it does not yet support the GPDMA + linked-list circular mode configuration.
  • You can test this using the Nucleo board even without the AD7689. When I verified the SPI pin signals using an oscilloscope, the output was excellent. Probing the TX pin shows the exact output pattern I intended, though, of course, nothing is received on the RX pin.
  • The code provided here was actually used in the production of an 8-channel EMG sensor. 
  • Although I tested this on the STM32U5, I believe it will work perfectly fine on the STM32H5 as well.

 

 
 
 
 
 

Yeah, I even tried that code this morning. My SPI bus didn't start, and adding another layer of voodoo just rubbed me the wrong way. I've seen this same issue brought up thrice in these communities and ST even opened an issue on it in 2023. I'd like to see a proper example using HAL code before hacking registers. But thanks.