cancel
Showing results for 
Search instead for 
Did you mean: 

Thread "Weird jitter in TIM4 -> DACs -> DMA1 waveform generator 32F417" is invisible

PHolt.1
Senior III

I have tried different browsers.

It was started by me and there have been some responses because I got notifications.

https://community.st.com/s/question/0D53W00001DlhkcSAB

10 REPLIES 10

Yes, two answer seem to have been deleted would be my guess

https://community.st.com/s/global-search/weird%20jitter

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
PHolt.1
Senior III

I posted some detail about a project, with DSO screenshots, in the hope that someone may have an idea. I won't do it again; don't have a copy, and having spent a day or two on it I did eventually find a usable solution. I posted it at the end of here

https://www.eevblog.com/forum/microcontrollers/32f417-a-cunning-way-to-reset-two-dma-pointers-from-an-edge-on-a-pin-etc/msg3841010/#msg3841010

The reason for the jitter is now fairly obvious but why the solution works I have no idea. The 32F4 is so complex...

MM..1
Chief III

I write response, but i repeat here, you plan generate clean sine with variable freq, simple way is DAC DMA circular on sine table. You cant stop DMA or DAC you need only manage timer that triggers DMA sample rate. Try this as first.

PHolt.1
Senior III

Yes that's exactly what I am doing. TIM4 triggers both DACs (actually I think only one DAC actually needs triggering) and one of them triggers DMA1 stream 5 to load the data, which goes into both DACs in the dual (32 bit) mode.

The challenge - see the eevblog link above - was to sync the generated waveform to the zero crossings of an input reference waveform. I have nan ISR which occurs very accurately on the reference waveform edges and is very short - a few us. This ISR a) resets the DMA pointers (DMA is in circular double buffer mode) and transfer count and b) zeroes TIM4.

b) is not totally necessary if you have lots of samples per cycle, otherwise just resetting the DMA will make the output drift around within 1 sample period, which is very visible with say 64 samples per cycle, hence I am resetting TIM4 as well.

When I started doing the TIM4 bit, I found strange effects. After much experimentation I got it all going nicely but the solution doesn't make sense - it involves not zeroing TIM4 but loading a fairly large value into it.

This ISR a) resets the DMA this is first fail dma can be reconfigured only in dma transfer complete ISR

try as i write setup dma circular and dont touch his config

touch only TRG source for DAC

PHolt.1
Senior III

The RM says DMA has to be disabled (and you wait for the EN bit to go to 0) before you can change the registers. I am doing that, hopefully correctly.

 
/*
* TIM1 input compare event interrupt handler. Used by waveform period measurement function.
* Process TIM1 CC1IE (CH1 capture) interrupt, generated by CH1 capture of CNT into CCR1, which
* is generated from a +ve edge on PE9.
* There was a problem with jitter in the first two samples after the TIM1 interrupt occurs, which
* is probably related to the zeroing of TIM4 count which is itself necessary to get the subsequent
* output to have the first sample output with the proper constant width.
* Much time was spent on it and the /8L CNT fix below magically works but no idea why.
*
*/
 
void TIM1_IC_CaptureISR(void)
{
 
	if ( (TIM4->CR1 && ~1) == 1 )  				// check wavegen (basically TIM4) is enabled!
	{
 
		// Reset TIM4 prescaler+counter chain, to avoid 1-sample-width jitter on output
 
		TIM4->PSC = isr_tim_pre;
		// This should obviously be 0 but that produces jitter. This value was determined experimentally
		// Works 42Hz (the KDE_config_TIM1_period_measure lower limit) to >1kHz.
		TIM4->CNT = isr_tim_tc/8L;
 
		// Update period of wave gen derived from input reference (period=TIM1->CCR1)
		// This doesn't need doing often; it is only to track variations in the input frequency but
		// here we do it every cycle because it doesn't produce any jitter etc.
		// The full formula if pclk1 != pclk2 is wave_tc = (pclk1*2L*(ccr1/((pclk2*2)/32)))/SPC
		// The simpler one if pclk1=pclk2 is (ccr1*32)/SPC
		// 32 is the prescaler in the measuring code (chosen at 32 to support 50Hz)
 
		TIM4->ARR = (( (TIM1->CCR1-1) * 32 )/isr_num_values);
 
		// Reset DMA pointers and transfer count
 
		dma_s5_copy &= ~1;						// disable DMA (to access its cfg regs) & avoiding RMW
		DMA1_Stream5->CR = dma_s5_copy;
 
		hang_around_us(1);						// wait for DMA to stop (delay not actually needed)
 
		DMA1->HISR = 0x0F40;					// 1111 0100 0000 - clear pending int flags (per RM)
 
		DMA1_Stream5->NDTR = isr_num_values; 	// buffer size
		DMA1_Stream5->M0AR = isr_buffer0;		// base of table 0
		DMA1_Stream5->M1AR = isr_buffer1;		// base of table 1
 
		dma_s5_copy |= 1;						// re-enable DMA
		DMA1_Stream5->CR = dma_s5_copy;
 
	}
 
	TIM1->SR = 0;								// Clear CC1IF & UIF - clear pending interrupt
 
}

My original post was PMd to me - not sure how he found it : - ) It is here:

Hi All,

I am building a sinewave generator which needs to track an input square wave (just the zero crossings of it). The frequency range is 50-500Hz.

I prefill two RAM buffers with sin(x) - using the double buffer DMA mode so that, later on, another RTOS task can modify the amplitude values while the system is running.

I have a frequency meter. I am feeding the input to TIM1 CH1 (PE9) and on +ve edges the counter value gets stored in CCR1. The counter is then zeroed (automatic process). The waveform period can be obtained anytime by reading TIM1-CCR1 and this is done entirely in hardware; no CPU involvement. Typical value in CCR1 is 6560 for 400Hz so the resolution is very good. However, I also interrupt from the event; the ISR is used as described below.

Then I have the waveform generator, which is TIM4 triggering both DACs, and they trigger DMA1 Stream 5 which loads both DACs together in 32 bit mode. I am running with 64 samples per cycle.

The above mentioned ISR does three things:

1) it resets TIM4 (prescaler and counter) to phase-lock the generator to the input. TIM4 is disabled during this counter load (but that doesn't seem to be needed).

2) it resets the DMA buffer pointers and the byte count to the buffer start. DMA is disabled during this counter load, per the RM and it doesn't work otherwise.

3) it uses the TIM1 CCR1 value to update TIM4 speed (ARR), to maintain a frequency match. This needs to happen only every ~1000 cycles but actually I am now doing it on every interrupt because is not the source of the issue described here.

It is all running, but I have (had) two problems:

a) There is amplitude jitter at the +ve going zero crossing of the output sinewave. This extends over the first two DAC samples; about 80us - much longer than the duration of the ISR which I have verified (by waggling an output pin) takes about 4us. The jitter is obviously the previous DAC value along the table being repeated, so it is as if the DMA was taking a long time to get going. More likely the delay is further back i.e. TIM4 taking time to restart counting, or the DACs taking time to generate the DMA request.

b) there is a general phase shift in the output, relative to the input. This is fixed in degrees (around 5 deg) over the whole frequency range. It is actually two DAC sample periods i.e. two TIM4 periods. The ISR is all done in a miniscule fraction of that time, however, and it happens very fast after the input waveform +ve edge, as it should. It is as if there was a two-sample FIFO somewhere. I can program around this by shifting the RAM tables back...

The obvious questions might be:

Q1) Is there any obvious gotcha in this scheme?

Q2) What should be the right way to reset TIM4? It isn't clear that it should be disabled, and it works without that

Q3) Is there a "FIFO" somewhere which is two TIM4 cycles (two whole ARR to CNT reload cycles, not two input clocks etc) long?

The image below shows the jitter around zero, as well as the 2-sample phase lag. Obviously, with 256 samples per cycle the issue becomes insignificant, especially with a lowpass filter, but then I get perf issues with recomputing the larger table. The bottom sinewave is inverted because I am using DAC2 to generate -sin(x) and it shows the same jitter. Below is the ISR.

As mentioned in the comments, after days of experimenting and YES reading the RM I found that resetting TIM4 with CNT value a lot bigger than zero avoids the jitter. It needs to be at least 1/10 of the ARR reload value, and if = or > than ARR that obviously breaks it. But this is the only workaround I found for the jitter. It introduces an issue in that the sync frequency range is a lot more limited but it still does the job I need.

===

I now know there is indeed a FIFO on the DACs, which explains 1 of the sample delays. The other one is explained by "wek" in that eevblog thread.

> The RM says DMA has to be disabled (and you wait for the EN bit to go to 0) before you can change the registers.

Yes, but MM said, leave DMA alone.

JW

PHolt.1
Senior III

How do I do that, when it is a circular buffer?

Do you mean allowing the transfer count to be exhausted, and then DMA should stop? I am wondering what that would give me, in the context of implementing frequency tracking, when the next cycle could be shorter or longer.

The process of stopping DMA seems to be well documented, while the requirements for updating or zeroing TIM4 don't appear to be.

MM..1
Chief III

I try be simply:

  1. Is signal sine ? Can you skip any sample from sine table for clean signal ?
  2. example for you sine table size 1000 samples
  3. start your code measure square wide = 3937us (high part from 127Hz...)
  4. setup dma circular table 1000 and dac trig
  5. set time between sample calculated in 3 ... 3937*2/1000 = ... (arange timer divider pll)
  6. sync with square start dac
  7. first transfer complete int start measure shift on out vs square .... second complete calculate shift plus minus ...
  8. correct time between smples and repeat 7