cancel
Showing results for 
Search instead for 
Did you mean: 

Issue with reading pulse widths in input capture mode using two timers.

sarojj7
Associate III

Dear All,

Board: Nucleo - H745ZI-Q

What am I trying to do ?

I am trying to measure pulse width of an signal using input capture mode of timer 2 channel 1. Then multiply that width by two and wait for that much time and generate an output pulse using output compare mode of timer 2 channel 2. Also, I use timer 3 channel 1 in input capture mode to measure pulse width of another signal. The second signal pulse width should start sequentially, only after pulse measurement of timer2 channel1.

What have I done?

I configure the GPIOs for Timer 2 channel 1 and Channel 2,that is pins PA0, PB3.

I configure the timer2 and timer 3 with ARR = 0xFFFF, PSC = 0x9, thus effective timer clock is 20MHz.

I configure the timer 2 channel 1 as input capture mode

I configure timer 2 channel 2 as output compare mode, mode "0001", upon match PB3 should go high.

I enable interrupt for timer 2 channel 1.

I configure the tim 3 ch 1 as input capture mode(PA6)

Code

Timer 2 config;

void readingPWTimer2()
{
	
	RCC -> APB1LENR |= RCC_APB1LENR_TIM2EN;
	TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS); /* Select the up counter mode */
TIM2->CR1 &= ~TIM_CR1_CKD;	
TIM2->ARR = 0xFFFF; /* Set the Autoreload value */
	TIM2->PSC = 0xC8 - 1; /* Set the Prescaler value, 1MHz*/
 
TIM2->EGR  |= TIM_EGR_UG;
TIM2->SMCR = RESET; 
 
//For Channel 1
/* Set the TIM2 timer channel 1 as input */
TIM2->CCMR1 |= TIM_CCMR1_CC1S_0;
//Sensitive to falling edge only
TIM2->CCER |= (TIM_CCER_CC1P) ;
TIM2->CCER |= TIM_CCER_CC1E;
TIM2->SR = ~TIM_SR_CC1IF; 
// Enable the hardware capture compare interrupt for channel 1.
TIM2->DIER |= TIM_DIER_CC1IE;
 TIM2->EGR  |= TIM_EGR_UG;
 
//For channel 2
TIM2->SR = ~TIM_SR_CC2IF; 
TIM2->CCMR1 |= TIM_CCMR1_OC2FE;
//Update event generation
TIM2->EGR  |= TIM_EGR_UG;
TIM2->CCER |= TIM_CCER_CC2E;
 
TIM2->CR1 |= TIM_CR1_CEN; /* Enable the TIM peripheral */
//Enabling Interrupt..
NVIC_SetPriority(TIM2_IRQn, 0x05);
NVIC_EnableIRQ(TIM2_IRQn);
return;
 
}

Timer 3 config:

void readingPWTimer3()
{
		
	RCC -> APB1LENR |= RCC_APB1LENR_TIM3EN;
	TIM3->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
	TIM3->CR1 &= ~TIM_CR1_CKD;	
	TIM3->ARR = 0xFFFF; 
	TIM3->PSC = 0xC8 - 1; 
	TIM3->EGR  |= TIM_EGR_UG;
	TIM3->SMCR = RESET; 	
//For Channel 1
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
//Sensitive to falling edge only
TIM3->CCER |= (TIM_CCER_CC1P);
//TIM3->CCER |= TIM_CCER_CC1E;
/* Clear the Capture event flag for channel 1 */
TIM3->SR = ~TIM_SR_CC1IF; 
//TIM3->DIER |= TIM_DIER_CC1IE;
//// Generate update evnent so that all constants can be loaded
TIM3->EGR  |= TIM_EGR_UG;
 
//For channel 2
TIM3->SR = ~TIM_SR_CC2IF; 
TIM3->CCMR1 |= TIM_CCMR1_OC2FE;
//Update event generation
TIM3->EGR  |= TIM_EGR_UG;
TIM3->CCER |= TIM_CCER_CC2E;
 
TIM3->CR1 |= TIM_CR1_CEN;
 
NVIC_SetPriority(TIM3_IRQn, 0x05);
 
NVIC_EnableIRQ(TIM3_IRQn);
return;
}

IRQ Handler Tim2

void TIM2_IRQHandler(void)
{
if((TIM2->SR & TIM_SR_CC1IF)) 
  Timer2CaptureCompare_CallbackCh1();
}
void Timer2CaptureCompare_CallbackCh1(void)
{ 
 
		TIM2->SR &= ~(TIM_SR_CC1IF);
		if( timer2Ch1Is_Falling_Captured == 0)
		{
			
			TIM2->EGR  |= TIM_EGR_UG;
			//set polarity to rising edge only
			TIM2->CCER &= ~(TIM_CCER_CC1P) ;
			timer2Ch1Is_Falling_Captured = 1;		
		}
		else if(timer2Ch1Is_Falling_Captured == 1)
		{			
			timer2Ch1IC = TIM2->CCR1 ;			
			TIM2->CCR2 = (2*timer2Ch1IC);
		        TIM2->CCMR1 |= (TIM_CCMR1_OC2M_0);
 
			TIM2->CCER &= ~TIM_CCER_CC1E;
			//TIM2->DIER &= ~TIM_DIER_CC1IE;
 
			TIM3->CCER |= TIM_CCER_CC1E;
			TIM3->SR = ~TIM_SR_CC1IF; 
			TIM3->DIER |= TIM_DIER_CC1IE;
			TIM3->EGR  |= TIM_EGR_UG;
			
			TIM2->EGR  |= TIM_EGR_UG;
 
		}				

IRQ Handler Tim 3:

void TIM3_IRQHandler(void)
{
	if((TIM3->SR & TIM_SR_CC1IF)) 
   Timer3CaptureCompare_CallbackCh1();
}
void Timer3CaptureCompare_CallbackCh1(void)
{
		TIM3->SR &= ~(TIM_SR_CC1IF);
		if( timer3Ch1Is_Falling_Captured == 0)
		{
			
			TIM3->EGR  |= TIM_EGR_UG;
			//set polarity to rising edge	only
		      TIM3->CCER &= ~(TIM_CCER_CC1P) ;
                      timer3Ch1Is_Falling_Captured = 1;
			
		}
		else if(timer3Ch1Is_Falling_Captured == 1)
		{			
			timer3Ch1IC = TIM3->CCR1 ;			
			TIM3->CCR2 = (2*timer3Ch1IC);
		       TIM3->CCMR1 |= (TIM_CCMR1_OC2M_0);
			
			TIM3->CCER &= ~TIM_CCER_CC1E;
			//TIM3->DIER &= ~TIM_DIER_CC1IE;
			
			TIM3->EGR  |= TIM_EGR_UG;
	}
}

Issue: The pulse width read by tim2 ch 1 in variable timer2Ch1IC is correct and as expected but pulse width read by tim3 ch1 in variable timer3Ch1IC is not correct, its gives unexpectedly large value. Interesting thing is that if I user tim 2 ch 4 instead of tim3 ch 1 to measure pulse width of second signal, then its comes absolutely correct as expected.

Possible Approaches: Timer 3 ch1 may be getting interrupted by tim 2 ch 1 because of noise at its input pin.

For this I make priority of both the timer same but it does not help.

Also I try and disable interrupt for tim 2 ch1 after its job is done, but that does not help either.

I am missing something here.

Kindly help.

Thank you.

1 REPLY 1

Code looks good (except formal stuff see below), I don't understand where may be the source of the problem.

Have you observed the value in timer3Ch1IC directly (in debugger), or only through the TIM3_CH2 pin toggle? What is the expected and the observed value? Isn't the observed value close to as if the falling edge would occur immediately after the rising edge of TIM2_CH1?

Toggle a GPIO output pin when entering the TIM3 ISR and observe.

JW

PS. formal stuff:

> TIM3->SR &= ~(TIM_SR_CC1IF);

Don't RMW the status register (although it is not a problem here), write directly. Interestingly, at some places you do it correctly.

> TIM3->EGR |= TIM_EGR_UG;

There's no point in RMW here, although harmless - EGR is a write-only register, always reads 0.

> = RESET

Unnecessarily confusing symbol. Use 0.

JW