cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H745 problem with SPI in DMA and DMAMUX synchronization with LPTIM2

DMast.1
Associate II

Hello,

I'm working on a board with STM32H745. The mcu has to interface with an external ADC

(LTC2335-16) to permit a max sample rate of 1M/s (during software develop 20KHz see images).

So, i've decide to use LPTIM2 to generate the 1MHz signal (50% duty) to generate the

start conversion for ADC (positive edge). After 500nsec the converted data is ready to

get out the 3 bytes read (see the attached images). So I configure the SPI with transmit and

receive DMA with the synchronization event for DMA TX with the falling edge of LPTIM2 signal.

Here is the peripheral initialization software.

  SpiHandle.Instance               = SPI4;
  SpiHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;    // Recommended setting to avoid glitches
  SpiHandle.Init.Mode = SPI_MODE_MASTER;
 
  SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; //SPI_BAUDRATEPRESCALER_128,
  SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
 
  SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
  SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
 
  SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
  SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
  SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
 
  SpiHandle.Init.NSS = SPI_NSS_HARD_OUTPUT;
  SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  SpiHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
 
  SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  SpiHandle.Init.CRCPolynomial = 7;
  SpiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
 
  SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
 
  if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
  {
    // Initialization Error
    while(1){};
  }
  
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  SPI4_SCK_PORT_CLK_EN();          //PE2: SPI4_SCK
  SPI4_NSS_PORT_CLK_EN();          //PE4: SPI4_NSS
  SPI4_MISO_PORT_CLK_EN();         //PE5: SPI4_MISO
  SPI4_MOSI_PORT_CLK_EN();         //PE6: SPI4_MOSI
  SPI4_SCK_EN();                   //Peripheral clock
 
  /*##-2- Configure peripheral GPIO ##########################################*/
  /* SPI SCK GPIO pin configuration  */
  GPIO_InitStruct.Pin       = SPI4_SCK_PIN;
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull      = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.Alternate = SPI4_SCK_AF;
  HAL_GPIO_Init(SPI4_SCK_GPIO_PORT, &GPIO_InitStruct);
 
  /* SPI NSS GPIO pin configuration  */
  GPIO_InitStruct.Pin       = SPI4_NSS_PIN;
  GPIO_InitStruct.Alternate = SPI4_NSS_AF;
  HAL_GPIO_Init(SPI4_NSS_GPIO_PORT, &GPIO_InitStruct);
 
  /* SPI MISO GPIO pin configuration  */
  GPIO_InitStruct.Pin = SPI4_MISO_PIN;
  GPIO_InitStruct.Alternate = SPI4_MISO_AF;
  HAL_GPIO_Init(SPI4_MISO_GPIO_PORT, &GPIO_InitStruct);
 
  /* SPI MOSI GPIO pin configuration  */
  GPIO_InitStruct.Pin = SPI4_MOSI_PIN;
  GPIO_InitStruct.Alternate = SPI4_MOSI_AF;
  HAL_GPIO_Init(SPI4_MOSI_GPIO_PORT, &GPIO_InitStruct);
 
  /*##-3- Configure the DMA ##################################################*/
  /* Enable DMA clock */
  DMA1_CLK_ENABLE();
 
  /* Configure the DMA handler for Transmission process */
  hdma_tx.Instance                 = SPIx_TX_DMA_STREAM;
  hdma_tx.Init.FIFOMode            = DMA_FIFOMODE_ENABLE;//>>DMA_FIFOMODE_DISABLE;
  hdma_tx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_tx.Init.MemBurst            = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_MBURST_INC4;
  hdma_tx.Init.PeriphBurst         = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_PBURST_INC4;
  hdma_tx.Init.Request             = SPIx_TX_DMA_REQUEST;
  hdma_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
  hdma_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_tx.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  hdma_tx.Init.Mode                = DMA_PFCTRL;//>>DMA_NORMAL;
  hdma_tx.Init.Priority            = DMA_PRIORITY_LOW;
 
  HAL_DMA_Init(&hdma_tx);
 
  /* Configure the DMAMUX with the Synchronization parameters */
  DmaSyncConfig.EventEnable   = ENABLE;                       /* Enable DMAMUX event generation each time  RequestNumber are passed from DMAMUX to the DMA */
  DmaSyncConfig.SyncPolarity  = HAL_DMAMUX_SYNC_FALLING;      /* Synchronization edge is Rising  */
  DmaSyncConfig.RequestNumber = 3;//3;//4;                        /* 4 requests are autorized after each edge of the sync signal */
  DmaSyncConfig.SyncSignalID  = HAL_DMAMUX1_SYNC_LPTIM2_OUT;  /* Sync signal is LPTIM1_OUT */
  DmaSyncConfig.SyncEnable    = ENABLE;                       /* Synchronization is enabled */
 
  HAL_DMAEx_ConfigMuxSync(&hdma_tx, &DmaSyncConfig);
 
  /* Associate the initialized DMA handle to the the SPI handle */
  __HAL_LINKDMA(hspi, hdmatx, hdma_tx);
 
  /* Configure the DMA handler for Transmission process */
  hdma_rx.Instance                 = SPIx_RX_DMA_STREAM;
 
  hdma_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
  hdma_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
  hdma_rx.Init.MemBurst            = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_MBURST_INC4;
  hdma_rx.Init.PeriphBurst         = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_PBURST_INC4;
  hdma_rx.Init.Request             = SPIx_RX_DMA_REQUEST;
  hdma_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
  hdma_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
  hdma_rx.Init.MemInc              = DMA_MINC_ENABLE;
  hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
  hdma_rx.Init.Mode                = DMA_PFCTRL;//DMA_NORMAL;
  hdma_rx.Init.Priority            = DMA_PRIORITY_HIGH;
 
  HAL_DMA_Init(&hdma_rx);
 
  /* Associate the initialized DMA handle to the the SPI handle */
  __HAL_LINKDMA(hspi, hdmarx, hdma_rx);
 
  /*##-4- Configure the NVIC for DMA #########################################*/
  /* NVIC configuration for DMA transfer complete interrupt (SPIx_TX) */
  HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 1);
  HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
 
  /* NVIC configuration for DMA transfer complete interrupt (SPIx_RX) */
  HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
 
  /*##-5- Configure the NVIC for SPI #########################################*/
  /* NVIC configuration for SPI transfer complete interrupt (SPIx) */
  HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(SPIx_IRQn);

And the ISR for SPI (I started from SPI_FullDuplex_ComDMA example)

/**
  * @brief  This function handles SPIx interrupt request.
  * @param  None
  * @retval None
  */
void SPI4_IRQHandler(void)
{
  HAL_SPI_IRQHandler(&SpiHandle);
}
 
/**
  * @brief  This function handles DMA Rx interrupt request.
  * @param  None
  * @retval None
  */
void SPI4_DMA_RX_IRQHandler(void)
{
  HAL_DMA_IRQHandler(SpiHandle.hdmarx);
}
 
/**
  * @brief  This function handles DMA Tx interrupt request.
  * @param  None
  * @retval None
  */
void SPI4_DMA_TX_IRQHandler(void)
{
  HAL_DMA_IRQHandler(SpiHandle.hdmatx);
}

This is the on period LPTIM2 isr

void LPTIM2_IRQHandler(void)
{
   /* Clear interrupt flags */
   __HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_IT_ARRM);
 
//read from DMA last conversion data
 
//Check if conversion sequence end
 
 
//If no prepare next packet to transmit
   HAL_StatusTypeDef zResult = HAL_SPI_TransmitReceive_DMA(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE);
}

I configured the LPTIM2 to get the on period interrupt event (on every rising edge):

so inside this ISR I prepare the 3bytes to trasmit on the next falling edge and read the

3 bytes of last conversion.

As you can see only the first SPI packet exit on falling edge and no more other.

Furthermore is it possible to get correct timing and data configuring without all the SPI,

DMA_TX amd DMA RX interrupt routines?

Thanks in advance foy any help to resolve this issue.0693W000005CzaxQAC.png0693W000005Czb7QAC.png0693W000005Czb2QAC.png

4 REPLIES 4
TDK
Guru

Break it down into smaller steps. Make sure your HAL_SPI_TransmitReceive_DMA calls work correctly on their own, then try to integrate them into the system. Ensure HAL_SPI_TransmitReceive_DMA returns HAL_OK as opposed to an error code.

Calling anything but the most trivial ISRs at 1 MHz is going to be a nonstarter. You can probably get away with 20 kHz.

For development, I'd slow things down even more so your scope waveforms look more square.

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

Post a foto of your setup.

Use Circular mode of DMA.

In case of unexpected behaviour, read out and check content of SPI and DMA registers.

JW

DMast.1
Associate II

Hello to all.....I followed yours suggestions to split the step by step the setup sequence. After setting circular mode it seems to goes well...I'm doing few tests in these days. I will give you the final result in a few days.

Thanks for support,

regards

DM

fma23
Associate II

do you mind sharing your code on github?