cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407VG sometimes reads one additional Timer overflow.

EmbeddedPepe
Associate III

Hello!

I'm writing a software to read the frequency that I receive on two channels of the same 16bit timer. (Channel 1 and Channel 2)

The channels are set on rising edge captures. Timer prescaler is set 21 - 1. ARR = 0xFFFF.

Given: 

  • X1 = First Capture
  • X2 = Second Capture
  • OV = number of overflow
  • ARR = Period

Formula = X2 + (OV * ARR) - X1.

I have the TIM interrupt where I basically read the SR register for which interrupt got fired, clear the flag and proceed to do the operations.

 

The problem is that given the same frequency (with a frequency generator ) at 400hz I read 400hz (most of the time) but I sometimes read 52ish HZ which is basically the formula with an additional overflow, although I reset the overflow counter at every first capture. Sometimes the problem is on CH1, sometimes on CH2.

 

Additional info:

  • The code assign to a global variable, which is not declared as volatile, and used in the main process. Volatile doesn't make any difference.
  • I disable interrupts in CRITICAL SECTIONS of other interrupts, but this should not cause the issue (?)
  • Can't access in debug mode to check value.
  • Signals are phase shifted of 90 degrees ( in this case)
  • Edit: The IRQ of various interfaces is set to the same priority.

code below:

 

void TIM4_IRQHandler_FRQ(void)
{
	static uint8_t  CH1_capture_flag = 0;
	static uint8_t  CH2_capture_flag = 0;

	static uint32_t CH1_captures[2] = {0, 0};
	static uint32_t CH2_captures[2] = {0, 0};

	static uint32_t result_ch1 = 0;
	static uint32_t result_ch2 = 0;


	tmyFRQ2Input *p = &Z; //(Global variable, not declared as volatile)




	if( TIM4->SR & TIM_FLAG_Update )//  overflow occurs
	{
		TIM4->SR = ~TIM_FLAG_Update;

       	if(p->overflow < 0xFFFFFFFF)
		{
			p->overflow++;
		}
		if(p->overflow2 < 0xFFFFFFF)
		{
			p->overflow2++;
		}

    }

	if(TIM4->SR & TIM_FLAG_CC1)
    {
		TIM4->SR = ~TIM_FLAG_CC1;


				p->pulseCount1++;


				if ( CH1_capture_flag == 0)
				{
					p->overflow = 0;
					CH1_captures[0] = TIM4->CCR1;
					CH1_capture_flag = 1;
				}
				else
				{
					CH1_captures[1] = TIM4->CCR1;

					result_ch1 = (uint32_t)((p->my_clk) / CH1_captures[1] + (p->overflow * p->TIM_TimeBaseStructure.TIM_Period ) - CH1_captures[0] + 1);
					CH1_capture_flag = 0;

				}

			}


    }

	if(TIM4->SR & TIM_FLAG_CC2)
    {
		TIM4->SR = ~TIM_FLAG_CC2;




			
				p->pulseCount2++;
				if ( CH2_capture_flag == 0 )
				{
					p->overflow2 = 0;
					CH2_captures[0] = TIM4->CCR2;
					CH2_capture_flag = 1;
				}
				else
				{
					CH2_captures[1] = TIM4->CCR2;
					result_ch2 = ((p->my_clk )/ CH2_captures[1] + (p->overflow2 * p->TIM_TimeBaseStructure.TIM_Period) - CH2_captures[0] + 1;);
					CH2_capture_flag = 0;
				}
			}

    }

	//Both calculation are done
	if ( result_ch1 != 0 && result_ch2 != 0)
	{
		p->Frequency = result_ch1;
		p->Frequency2 = result_ch2;

		result_ch1 = 0;
		result_ch2 = 0;

	}



}

 

4 REPLIES 4
gbm
Lead III

Forget the overflow, simply subtract two capture values and store the result as uint16_t.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

But if the signal changes to (for example 5hz) how do I manage to calculate it?

gbm
Lead III

First, decide on the input frequency range, then setup the timer to cover the required range. Overflow counting in software is almost never reliable.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Unfortunately the range depends. It could go from 1 hz to 10khz or more. Can't do much about that.