cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743 SPI DMA delay

Valeev.Kamil
Associate II

Hello.

I have a TIM3 configured to generate a PWM signal with frequency 1 MHz and duration 200 ns using CC1 channel. TIM3 also generates a DMA request on CC1.

DMA1 is configured to transfer value 0xFFFF from AXI SRAM to SPI2_TXDR register, triggering transfer from TIM3_CH1.

The problem is that there is a delay of 70 ns between the end of the PWM signal and the CLK signal of SPI2. Here's the image illustrating it.

DS2_2024112683659.png

Yellow channel is TIM3 PWM signal. Blue channel is SPI_CLK signal. DMA transfer is triggered on TIM_CH1 (at the moment of the falling edge of the yellow signal). As you can see there's a delay of 70 ns, which is a lot and not acceptable in my application.

Does anyone know the reason for this delay?

MCU: STM32H743, revision V

System clock: 480 MHz

AHB, APBs clocks: 240 MHz

SPI clock: 80 MHz

 

DMA1 configuration:

 

 

 

 

  // Disable stream
  DMA1_Stream1->CR &= ~DMA_SxCR_EN;
  
  // DMA is the flow controller
  DMA1_Stream1->CR &= ~DMA_SxCR_PFCTRL;
  // Direction: memory to peripheral
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_STREAM_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
  // Circular mode enabled
  DMA1_Stream1->CR |= DMA_SxCR_CIRC;
  // Peripheral increment disabled
  DMA1_Stream1->CR &= ~DMA_SxCR_PINC; 
  // Memory increment disabled
  DMA1_Stream1->CR &= ~DMA_SxCR_MINC;
  // Peripheral size: half-word
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_HALFWORD);
  // Memory size: half-word
  LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_MDATAALIGN_HALFWORD);  
  // Priority: very high
  LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_VERYHIGH); 
  // Double buffered mode disabled
  DMA1_Stream1->CR &= ~DMA_SxCR_DBM;  
  // Disable bufferable transfers (required for USART, read ERRATA)
  DMA1_Stream1->CR &= ~DMA_SxCR_TRBUFF;
  
  // Peripheral burst mode: single transfer (forced to single in Direct mode)
  LL_DMA_SetPeriphBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_PBURST_SINGLE);
  // Memory burst mode: single transfer (forced to single in Direct mode)
  LL_DMA_SetMemoryBurstxfer(DMA1, LL_DMA_STREAM_1, LL_DMA_MBURST_SINGLE);  
  
  // Direct mode enabled (note: direct mode is not allowed for mem-mem transfers)
  // The opposite of Direct mode is using FIFO and burst transfers.
  DMA1_Stream1->FCR &= ~DMA_SxFCR_DMDIS;
  
  // Peripheral address
  DMA1_Stream1->PAR = (uint32_t) &(SPI2->TXDR);
  
  // Memory address
  DMA1_Stream1->M0AR = (uint32_t) &(ad400x.mosiValue);
  
  // Data count (auto-reloads in circular mode)
  DMA1_Stream1->NDTR = 1;  
  
  // Disable Transfer Complete Interrupt
  DMA1_Stream1->CR &= ~DMA_SxCR_TCIE;
  
  // Set peripheral request type: TIM3_CH1
  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_STREAM_1, LL_DMAMUX1_REQ_TIM3_CH1); 

  // Enable stream
  DMA1_Stream1->CR |= DMA_SxCR_EN;

 

 

 

 

SPI2 configuration:

 

 

 

 

  // Disable SPI2
  SPI2->CR1 &= ~SPI_CR1_SPE;     
  
  // Select SPI1,2,3 kernel clock (spi_ker_ck): PLL1Q (160 MHz)
  LL_RCC_SetSPIClockSource(LL_RCC_SPI123_CLKSOURCE_PLL1Q);  
  
  // BaudRate: Fspi = PLL1Q / 2 = 80 MHz
  LL_SPI_SetBaudRatePrescaler(SPI2, LL_SPI_BAUDRATEPRESCALER_DIV2);
  
  // Data frame size: 16 bits (data is 16-bits when reading the result of the 
  // conversion and when in register access mode)
  LL_SPI_SetDataWidth(SPI2, LL_SPI_DATAWIDTH_16BIT);
  
  // Number of data frames in one data packet: 1
  LL_SPI_SetFIFOThreshold(SPI2, LL_SPI_FIFO_TH_01DATA);
  
  // Disable RX DMA
  SPI2->CFG1 &= ~SPI_CFG1_RXDMAEN;
  
  // Disable TX DMA
  SPI2->CFG1 &= ~SPI_CFG1_TXDMAEN;  
  
  // Number of idle cycles between two consecutive data frames
  LL_SPI_SetInterDataIdleness(SPI2, LL_SPI_ID_IDLENESS_00CYCLE);
  
  // Don't swap MOSI and MISO pins
  SPI2->CFG2 &= ~SPI_CFG2_IOSWP;
  
  // Transfer direction: full duplex
  LL_SPI_SetTransferDirection(SPI2, LL_SPI_FULL_DUPLEX);
  
  // Data format: MSB first
  SPI2->CFG2 &= ~SPI_CFG2_LSBFRST;
  
  // SPI Mode 1: CPOL = 0, CPHA = 0
  SPI2->CFG2 &= ~SPI_CFG2_CPOL;
  SPI2->CFG2 &= ~SPI_CFG2_CPHA;
  
  // Software slave management & select slave
  SPI2->CFG2 |= SPI_CFG2_SSM;              
  SPI2->CR1 |= SPI_CR1_SSI;  
  
  // SPI takes no control of its GPIOs while it is disabled
  SPI2->CFG2 &= ~SPI_CFG2_AFCNTR;
  
  // Master mode
  SPI2->CFG2 |= SPI_CFG2_MASTER;  
  
  // Enable SPI2
  SPI2->CR1 |= SPI_CR1_SPE;
  
  // TSIZE = 0, TSER = 0 (Transaction size in units of Data Packets). If set to 0,
  // then CSTART is never cleared and EOT events won't occur.
  SPI2->CR2 = 0;
  
  // Start Master Transfer (CSTART = 1)
  LL_SPI_StartMasterTransfer(SPI2);

 

 

 

 

 

Thank you!

 

0 REPLIES 0