cancel
Showing results for 
Search instead for 
Did you mean: 

Issue in using two channels of Timer 2, one as input capture and another as output compare.

sarojj7
Associate III

Dear All,

Board: Nucleo - H745ZI-Q

What am I trying to do ?

I am using 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.

What have I done?

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

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

I configure the channel 1 as input capture mode , sensitive to both rising and falling edge.

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

I enable interrupt for channel 1.

Start the timer.

When the rising edge occur, in ISR , I read CNT value.

When the fallig edge occurs, in ISR , I read CNT value, find the pulse width, multiply the valur by two, stop the counter, reset the counter, load CCR2 by the computed value and enable the channel 2 and start the timer again.

Present Issue: Pulse width calculation using input capture is working fine. But the output compare output is always becoming high after a fixed time after the input falling edge(after around 500 ns). Its behaving as if CCR2 has zero value.

Its baffling because in debug mode CCR2 is getting the value that I am loading with but the output doesnot seem to follow ccr2 value, it is always assuming ccr2 as zero somehow.

Am I doing something fundamentally wrong.

Any help is appreciated.

Thank you

Code Snippet:

Configuring Timer:

void readingPWTimer2()
{	
RCC -> APB1LENR |= RCC_APB1LENR_TIM2EN;
 
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS); /* Select the up counter mode */
TIM2->CR1 |= 0x00000000U;
TIM2->CR1 &= ~TIM_CR1_CKD;
 
TIM2->ARR = 0xFFFF; /* Set the Autoreload value */
 
TIM2->PSC = 0x9; /* Set the Prescaler value */
TIM2->SMCR = RESET;
TIM2->CCMR1 |= TIM_CCMR1_CC1S_0;
TIM2->CCER |= (TIM_CCER_CC1P | TIM_CCER_CC1NP) ;
TIM2->CCER |= TIM_CCER_CC1E;
TIM2->SR = ~TIM_SR_CC1IF;
 TIM2->DIER |= TIM_DIER_CC1IE;
 TIM2->EGR  |= TIM_EGR_UG;
 
// Setting up channel2
TIM2->CCMR1 |= (TIM_CCMR1_OC2M_0);
TIM2->CCMR1 |= TIM_CCMR1_OC2FE;
 
TIM2->EGR  |= TIM_EGR_UG;
 
TIM2->CR1 |= TIM_CR1_CEN; /* Enable the TIM peripheral */
 
NVIC_EnableIRQ(TIM2_IRQn);
 
return;
}

Interrupt Handler:

void Timer2CaptureCompare_Callback(void)
{
	if(TIM2->SR & TIM_SR_CC1IF)
	{
		
	         //clear the interrupt
		TIM2->SR &= ~(TIM_SR_CC1IF);
 
		if( timer2Ch1Is_First_Captured == 0)
		{
			timer2Ch1IC_Val1 = TIM2->CCR1 ;
			timer2Ch1Is_First_Captured = 1;
			
		}
		else if(timer2Ch1Is_First_Captured == 1)
		{
			timer2Ch1IC_Val2 = TIM2->CCR1 ;
			if(timer2Ch1IC_Val2 > timer2Ch1IC_Val1)
			{
				timer2Ch1Difference = timer2Ch1IC_Val2 - timer2Ch1IC_Val1 ;
			}
			timer2Ch1Is_First_Captured = 0;
 
                        // stop the timers counter
			TIM2->CR1 &= ~(TIM_CR1_CEN);	
			// Resetting the counter
			TIM2->EGR  |= TIM_EGR_UG;
 
			TIM2->CCR2 = 20*timer2Ch1Difference;
				
                          TIM2->CCER |= TIM_CCER_CC2E;
 
 
			TIM2->CR1 |= TIM_CR1_CEN; /* Enable the TIM peripheral */
			
 
		}
				
 
			
	}
	else
	{
		printf("Inside timer2 interrupt but CC1F not set");
	}
	
}

 Also I have tried with ch4 instead of ch2 as output but same result.

1 ACCEPTED SOLUTION

Accepted Solutions

In readingPWTimer2() line 21 you set CCMR1.OC2M to Set Active On Match. At that point, TIMx_CNT=0 from the previous TIMx_EGR.UG=1, and presumably TIMx_CCR2 is still 0 after reset. That means, that the output comparator is immediately Match and sets OC2REF to 1. You don't notice as at that point TIMx_CCER.CC2E is still 0.

There's nothing in the further program which would clear OC2REF, so when you finally enable CH2, it immediately outputs the 1 which was there internally long ago.

JW

View solution in original post

7 REPLIES 7

Don't you have TIM2_CCMR1.OC2FE set?

Post content of TIM registers.

JW

TDK
Guru

You can disable preload by setting OCxPE=0 in the CCMRx register. Otherwise the new value will only take effect on the next update. Sounds like this may be happening.

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

Thanks for the reply.

Code snippet is added in the post. Thoroughly debugged, TIM register content at all stages is as expected. But output in scope does not follow the time. Also OC2FE is set as suggested but same result.

Kindly have a look.

sarojj7
Associate III

Thanks for the reply.

Code snippet is added in the post. After reset OC2PE is anyways zero but even after explicitly doing it, same result.

Kindly have a look at the code.

TDK
Guru

Not real sure. I didn't see anything after a brief look.

This line does nothing, maybe it's supposed to have another effect?

> TIM2->CR1 |= 0x00000000U;

Maybe step through the logic in Timer2CaptureCompare_Callback to ensure things are set up correctly prior to enabling the timer.

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

In readingPWTimer2() line 21 you set CCMR1.OC2M to Set Active On Match. At that point, TIMx_CNT=0 from the previous TIMx_EGR.UG=1, and presumably TIMx_CCR2 is still 0 after reset. That means, that the output comparator is immediately Match and sets OC2REF to 1. You don't notice as at that point TIMx_CCER.CC2E is still 0.

There's nothing in the further program which would clear OC2REF, so when you finally enable CH2, it immediately outputs the 1 which was there internally long ago.

JW

Thank you, thanks a lot. Got what I was looking for.