2020-09-15 08:37 AM
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?
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:
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
2020-09-15 08:45 AM
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.
2020-09-15 11:17 AM
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.