cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to read correct pulse width using busy loop and timer.

sarojj7
Associate III

Dear All,

Board: Nucleo - H745ZI-Q

What am I trying to do ?

I want to measure pulse width of an input signal using a busy loop and a timer. I keep monitoring a pin configured as input , when a zero is detected (by default input is around 3 volts), a function count is called in which I reset pre-configured timer 2(configured as up counter) and start the timer peripheral. Again I look for the same input pin to become 1, I stop the counter and return the counter value.

What have I done?

  1. I configure the required pin as input.
  2. I Configure Timer 2 with input clock 200 MHz, PSC =199, effective clock is 1 MHZ

Code Snippet:

Timer Config:

void initTimer2Counter()
{
	// Enable the TIM2 clock.	
	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; 
	TIM2->SR = 0;
}

part of main:

while (1)
  {
		
		//HAL_Delay(1000);
              //__disable_irq();	
	
		while((GPIOA->IDR & 1<<0));
		
		PW1 = count1();
		printf("PW1 is %d\r\n", PW1 ); // prints to serial monitor
                break;
}

count 1 function:

unsigned int count1(void)
{
 //printf("Inside count1\r\n");
TIM2->EGR  |= TIM_EGR_UG;//reset
TIM2->CR1 |= TIM_CR1_CEN;	/* Enable the TIM peripheral */
while(!(GPIOA->IDR & 1<<0) );
TIM2->CR1 &= ~TIM_CR1_CEN; /* Stop the TIM peripheral */
return (TIM2->CNT);
}

Issue: the read pulse width is inconsistent that for 100 us pulse input, at time it shows 100 , or 6 or 37 any value upto 100 randomly.

Possible approaches tried out:

  1. I suspect some interrupt is causing this randomness as the code has systick for that I use //__disable_irq(); and //__enable_irq(); at appropriate places, but it doesn't help.
  2. I understand that there is no need to enable timer2 interrupt and corresponding handler.

Measuring pulse width using this method is the goal, I am able to measure pulse width using input capture method fairly well.

Am I doing something fundamentally wrong.

Any help is appreciated.

Thank you

2 REPLIES 2

TIM2 should be 32-bit, could get higher resolution, and expand wrapping interval.

I would read the CNT on entry/exit, and delta the difference rather than enable/disable, and reset.

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

Not the greatest way to measure pulses, as clive mentions. Your reading will be off by the amount of overhead and delays you introduce between edges.

The issue is probably that printf() takes a while to complete, so by the time the code gets to "while((GPIOA->IDR & 1<<0));", you're already in the middle of the pulse. Instead, wait for the transition to actually occur:

                // wait for falling edge
		while(!(GPIOA->IDR & 1<<0));
		while((GPIOA->IDR & 1<<0));

 Note also you'll need to disable interrupts if you want it to be accurate. You said you did that, but it's not in the code you posted.

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