cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 periodical TIM triggered SPI transfer w/o DMA?

MSZB
Associate II

On a STM32H745ZI-Q - Board I want to create periodical 4-byte SPI transfers  triggered by a timer. 

So far I got this working the following way:

TIM triggers DMA
DMA initiates the SPI transfer.

However, the SPI transfer timing (CS low) has a high jitter of 100 ns, which is not acceptable.

To reduce the jitter: Is there any known way to trigger the SPI transfer start directly by a timer on this specific MCU (from reading the RM, I don't think so)? 

The data to be transfered could be written to the SPI FIFO in advance by an ISR triggered with a proper delay. 

28 REPLIES 28
MasterT
Senior III

Why not use SPI w/o timer, it has its own divider?

TDK
Guru

Do the clock/data also have a 100ns jitter? I wouldn't expect it to be different, but I also wouldn't expect a 100ns jitter on a DMA transfer.

There's definitely ideas of generating the SCK signal through a timer and running the SPI in slave mode. It could be done such that timing is exact.

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

Yes, clock/data have the same jitter. 
The slave mode idea sounds interesting.  

Then the SPI must be able to generate burst transfers (send 32 bits at say 20 MHz and then wait until a period of 10 us has passed). And it would be necessary to trigger timers for the generation of dependent signals from the 100 kHz SPI transfer period.

FBL
ST Employee

Hi @MSZB 

Would you add more details about your software configuration resulting in jitter? Using STM32H745ZI-Q, you mean NUCLEO-H745ZI-Q? 

To configure a timer to trigger the DMA transfer at the desired interval, you can use the timer's compare match to generate an interrupt at the desired interval. Also, if you can disable the SPI master temporarily during DMA config, you can set AFCNTR to prevent glitches on outputs.

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

MSZB
Associate II

Hi F.Belaid,

yes I mean NUCLEO-H745ZI-Q.

In the current test configuration, it's as follows:

TIM4 is the master timer triggering the start of TIM12, TIM1 and TIM 8. All Timers run at the same frequency (50 kHz for now). TIM1 and TIM8 are used for PWM generation (total 8 channels).

TIM4:

  • Clock source internal
  • TRGO Parameters: MSM Enabled, TRGO = CNT_EN

TIM12 is a TIM4 slave and provides the Trigger output for DMA

  • Slave Mode = Trigger mode, Trigger Source = ITR0
  • Clock source internal
  • TRGO Parameters: MSM Enabled, Trigger Event Selection: Compare Pulse (OC1)
  • Channel 1 = PWM Generation CH

DMA Stream 1: DMA Request = SPI4_TX

  • DMA Request Synchronisation settings:
  • Enable yes, Synch. Signal = TIM12 TRGO
  • Event enable = False
  • Request number = 4

Special SPI4 Settings

  • Mode: Full-Duplex Master
  • Hardware NSS Output Signal used
  • Baud Rate 15 MBit /s (Prescaler =6)

After CubeMX-generated HAL-based initialization of the peripherals, the ARR registers of all timers are set up for 50 kHz and individual CCR values are set. Afterwards the SPI transfer is started by:

  HAL_SPI_Transmit_DMA(&hspi4, (unsigned char *)&data, 4);

After starting the DMA transfer, there is (currently) no further software interaction with TIM, DMA or SPI.

Here are the CubeMX-Konfigurations of the above modules from the .ioc-File:

TIM4.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM4.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
TIM4.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
TIM4.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,TIM_MasterSlaveMode,TIM_MasterOutputTrigger
TIM4.TIM_MasterOutputTrigger=TIM_TRGO_ENABLE
TIM4.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE

TIM12.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
TIM12.IPParameters=TIM_MasterOutputTrigger,TIM_MasterSlaveMode,Channel-PWM Generation1 CH1
TIM12.TIM_MasterOutputTrigger=TIM_TRGO_OC1
TIM12.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE

Dma.Request0=SPI4_RX
Dma.Request1=SPI4_TX
Dma.RequestsNb=2
Dma.SPI4_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.SPI4_RX.0.EventEnable=DISABLE
Dma.SPI4_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.SPI4_RX.0.Instance=DMA1_Stream0
Dma.SPI4_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.SPI4_RX.0.MemInc=DMA_MINC_ENABLE
Dma.SPI4_RX.0.Mode=DMA_NORMAL
Dma.SPI4_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.SPI4_RX.0.PeriphInc=DMA_PINC_DISABLE
Dma.SPI4_RX.0.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.SPI4_RX.0.Priority=DMA_PRIORITY_LOW
Dma.SPI4_RX.0.RequestNumber=1
Dma.SPI4_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.SPI4_RX.0.SignalID=NONE
Dma.SPI4_RX.0.SyncEnable=DISABLE
Dma.SPI4_RX.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
Dma.SPI4_RX.0.SyncRequestNumber=1
Dma.SPI4_RX.0.SyncSignalID=NONE
Dma.SPI4_TX.1.Direction=DMA_MEMORY_TO_PERIPH
Dma.SPI4_TX.1.EventEnable=DISABLE
Dma.SPI4_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.SPI4_TX.1.Instance=DMA1_Stream1
Dma.SPI4_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.SPI4_TX.1.MemInc=DMA_MINC_ENABLE
Dma.SPI4_TX.1.Mode=DMA_CIRCULAR
Dma.SPI4_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.SPI4_TX.1.PeriphInc=DMA_PINC_DISABLE
Dma.SPI4_TX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING
Dma.SPI4_TX.1.Priority=DMA_PRIORITY_LOW
Dma.SPI4_TX.1.RequestNumber=1
Dma.SPI4_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
Dma.SPI4_TX.1.SignalID=NONE
Dma.SPI4_TX.1.SyncEnable=ENABLE
Dma.SPI4_TX.1.SyncPolarity=HAL_DMAMUX_SYNC_RISING
Dma.SPI4_TX.1.SyncRequestNumber=4
Dma.SPI4_TX.1.SyncSignalID=HAL_DMAMUX1_SYNC_TIM12_TRGO

 

SPI4.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8
SPI4.CalculateBaudRate=15.0 MBits/s
SPI4.DataSize=SPI_DATASIZE_8BIT
SPI4.Direction=SPI_DIRECTION_2LINES
SPI4.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,VirtualNSS,BaudRatePrescaler,DataSize,TIMode
SPI4.Mode=SPI_MODE_MASTER
SPI4.TIMode=SPI_TIMODE_DISABLE
SPI4.VirtualNSS=VM_NSSHARD
SPI4.VirtualType=VM_MASTER

 

Michal Dudka
Senior III

Between what do you need to eliminate jitter ? Only in CS period ? If yes, then you can simply generate CS signal by timer output, and use compare event (from the same timer) to generate DMA request to SPI to transfer data. 

The jitter that needs to be eliminated occurs between the PWM output signals of the timers (synchronization master) and the SPI signals.

The SPI signals (CS, SCK, MOSI) alone are jitter-free.

Since the sample timing reference of the SPI connected external ADC is SCK (not CS!) it doesn't help to use timer based CS generation.

OK. If i understood correctly you need to eliminate jitter between CS and SCK. Then you should generate SCK and CS by timer(s) and set SPI to slave mode (As TDK recommended a few posts above). There are multiple ways how to setup (or cascade) timers to generate your signal. Way how to setup timers depends if you need SCK to be "muted" between readings (when CS is deasserted), or SCK can be continuous (typical SPI is compatible with that).