Skip to main content
Associate
January 11, 2024
Question

STM32H7 periodical TIM triggered SPI transfer w/o DMA?

  • January 11, 2024
  • 28 replies
  • 5809 views

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. 

This topic has been closed for replies.

28 replies

MasterT
Lead II
January 11, 2024

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

MSZBAuthor
Associate
January 11, 2024

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.

TDK
January 11, 2024

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""."
MSZBAuthor
Associate
January 11, 2024

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

ST Technical Moderator
January 11, 2024

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 "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
MSZBAuthor
Associate
January 12, 2024

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
Lead
January 12, 2024

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. 

MSZBAuthor
Associate
January 15, 2024

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.

Michal Dudka
Lead
January 15, 2024

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).


MSZBAuthor
Associate
January 15, 2024

Thanks for all the suggestions so far. Before trying these - back to the original question:
Is it possible to the trigger transfer start of the SPI peripheral directly by a timer TRGO, without having to generate the SPI timings (SCK and/or CS) by timers, and without using DMA, on the STM32H745ZI?

Michal Dudka
Lead
January 15, 2024

As far as i know, without DMA no.

ST Technical Moderator
January 15, 2024

Hello @MSZB 

Have you tried different clock prescaler, source ? Which VOS used? Please check Table 117 in DS for SPI dynamic characteristics as reference.

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
LCE
Principal II
January 15, 2024

DMA jitter might be caused by too much traffic on the busses. I had that problem when the CPU never slept and constantly checked some variables / peripherals much too often. As soon as I put the CPU to sleep most of the time, DMAs ran much "smoother". Maybe take a look at that when using DMA.

LCE
Principal II
January 15, 2024

Just to make sure... what's your clock source?

HSI is terrible concerning jitter, the clock on the Nucleo from ST-link is much better, but surely not as good as a dedicated decent crystal or oscillator.

waclawek.jan
Super User
January 15, 2024

> HSI is terrible concerning jitter, the clock on the Nucleo from ST-link is much better,

This Nucleo contains STLink V3, which by default outputs MCO generated from the same horrible-jittery HSI. It might be switchable to crystal-generated non-8-MHz, though.

JW

LCE
Principal II
January 16, 2024

Oh my, I forgot that the ST-link clock might come from its HSI...

@MSZB so this is really something you should check.
Unless you are sure that your initial clock source is not any HSI from anywhere, you really should check this.
And somewhere you can change the ST-link's MCO. Probably something ugly like 25 MHz / 3 = 8.333 MHz from its external crystal, but that will be much better than what comes from HSI.

MSZBAuthor
Associate
January 16, 2024

HSE is used, 8 MHz MCO from ST-LINK. It's jitter is roughly 1 ns.

The jitter of the TIM12 output, which triggers the DMA, is ca. 40 ns (!). Maybe I'll have too look at the supply configuration in more detail. The board runs in Supply Config  3 (Internal SMPS and LDO cascaded).

Thats the clock configuration:

Screenshot 2024-01-16 154123.png

MasterT
Lead II
January 16, 2024

Jitter is likely be a frquency beating, since SPI has it's own clock prescaler (MBR). Simple solution is to make SPI in "free run" mode - no issue with NSS pin driving, H7 has advenced SPI hardware, 

hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_02CYCLE;

Changing this parameter allows to make a "fine tunning" of the sampling rate. 

Than configure timers to run synchronously with SPI, divider steps to be about +- MBR divider values. Or route SCLK line to input capture of the timer and generate PWM back. 

waclawek.jan
Super User
January 16, 2024

@MasterT,

> Jitter is likely be a frquency beating, since SPI has it's own clock prescaler (MBR).

Do you know for fact that the baudrate clock generator is free-running?

I don't doubt it, I'm genuinely curious; this never occured to me as a possibility, but of course the SPI may've been designed in this way.

JW

MasterT
Lead II
January 16, 2024

Yes, sure. SPI clock divider (MBR) is just same thing as prescaler in timers. So you can't run two timers in sync if one has prescaler set = 0 and another to something else. It would be possible only if first timer has ClockDivision1 = ClockDivision2 x Prescaler2