cancel
Showing results for 
Search instead for 
Did you mean: 

Problem in input capturing to measure the rpm

Bud
Associate III

I want to measure the rpm of bldc motor, so by using hall sensor (H.S) output we can capture the frequency. With help of Hall sensor frequency and num of motor poles, we can able to measure the RPM. I captured the frequency successfully by using input capture mode in stm32f103 .

Works well without running motor:

  • I use an8008 multi-meter to generate frequency ( say 500 HZ ).
  • And i use the timer pin to capture the frequency and it works well.

Works too bad while running motor: ( PROBLEM )

  • But when i run motor and capture the frequency of H.S or multi-meter anything, the captured output frequency is not good varies rapidly.
  • And i am using single MCU to run the motor as well as to capture the frequency.

// Input capture mode...
 
#include "stm32f10x.h"
 
int n;	int gap;
float counter0,counter1,Counter,Frequency,RPM;
 
int main()
{
	
	RCC->APB2ENR |=RCC_APB2ENR_TIM1EN;
  GPIOA->CRH&=~GPIO_CRH_CNF8;
	GPIOA->CRH|=(1<<3);
	GPIOA->ODR|=(1<<8);
	
	TIM1->PSC|=719;
	TIM1->CCMR1 |=TIM_CCMR1_CC1S_0;      // set T1[1] as input capture
	TIM1->CCER  &=~TIM_CCER_CC1P;        // Rising edge
	TIM1->CCMR1 &=~TIM_CCMR1_IC1PSC;     // Diabling the PSC
	TIM1->DIER |=TIM_DIER_UIE|TIM_DIER_CC1IE;
	TIM1->CCER |=TIM_CCER_CC1E;
	TIM1->CR1 |= TIM_CR1_CEN;
	
	NVIC_EnableIRQ(TIM1_CC_IRQn);
	
 
	while(1)
	{
 
	}
}
 
void TIM1_CC_IRQHandler(void)
{ 
 
	if ((TIM1->SR & TIM_SR_CC1IF) != 0)
{
 if ((TIM1->SR & TIM_SR_CC1OF) != 0) /* Check the overflow */
 {
 /* Overflow error management */
 gap = 0; /* Reinitialize the laps computing */
 TIM1->SR &= ~(TIM_SR_CC1OF | TIM_SR_CC1IF); /* Clear the flags */
 }
 if (gap == 0) /* Test if it is the first rising edge */
 {
	
 counter0 = TIM1->CCR1; /* Read the capture counter which clears the
 CC1ICF */
		
	 
 gap = 1; /* Indicate that the first rising edge has yet been detected */
 }
 else
 {
 counter1 = TIM1->CCR1; /* Read the capture counter which clears the
 CC1ICF */
	 
 if (counter1 > counter0) /* Check capture counter overflow */
 {
 Counter = counter1 - counter0;
	Frequency=100000/Counter; 
	 RPM=(Frequency*60)/4;
 }
 else
 {
 Counter = counter1 + 0xFFFF - counter0 + 1;
	 	Frequency=100000/Counter; 
			 RPM=(Frequency*60)/4;
 
 }
 counter0 = counter1;  
 }
}
else
{
 /* Unexpected Interrupt */	
 /* Manage an error for robust application */
} 
		
}

MCU - stm32f103

Timer pin - A8

5 REPLIES 5
Bud
Associate III

Guys i don't know if i am asked anything wrong , kindly guide me.

Waiting for your reply guys.

Bud
Associate III

Waiting for your reply gugs

Piranha
Chief II

> But when i run motor and ... multi-meter anything

Can You elaborate on this?

I haven't worked with input capture mode, so can't comment on that much, but there rises one general question - have You looked at that signal with oscilloscope?

Bud
Associate III

@Piranha​  Input capturing is used to capture the signals frequency. I am running bldc motor using stm32 and want to measure the rpm of the motor. So by pinging the H.S pin we can able to capture the H.S frequency, with that we can calculate the RPM.

-By using stm32 i programmed to run bldc motor (code 1), which runs good.

-For input capture method also, i programmed it using register language(code 2) and i tested by giving 500hz square wave using multi-meter. which works well.

But when i combine the code 1&2 to run the bldc motor and to capture signals frequency. The motor runs good, but stm32 cant able to capture the signals frequency.

I uploaded only code 2. Because i cannot upload code 1.

Piranha
Chief II

Just for fun (for me) I improved Your code "a little bit"...

#include "stm32f10x.h"
 
uint16_t nRPM;
 
int main(void)
{
	RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
	GPIOA->CRH = (GPIOA->CRH & ~GPIO_CRH_CNF8) | (1ul << 3);
	GPIOA->BSRR = 1ul << 8;
 
	TIM1->PSC = 720 - 1;
	TIM1->CCMR1 = 1ul << TIM_CCMR1_CC1S_Pos;
	TIM1->CCER = TIM_CCER_CC1E;
	TIM1->DIER = TIM_DIER_CC1IE;
	TIM1->CR1 = TIM_CR1_CEN;
 
	NVIC_EnableIRQ(TIM1_CC_IRQn);
 
	for (;;) {
	}
}
 
void TIM1_CC_IRQHandler(void)
{
	// Does not need interrupt flag checking as we have only one interrupt enabled
	static bool fRun;
	uint16_t tCapture1 = TIM1->CCR1; // Read capture register first to minimize possibility of overcapture
 
	if (TIM1->SR & TIM_SR_CC1OF) {
		TIM1->SR = ~TIM_SR_CC1OF;
		fRun = false;
	}
 
	static uint16_t tCapture0_;
 
	if (fRun && (tCapture1 != tCapture0_)) { // Prevent tDelta == 0 and division by zero
		uint16_t tDelta = tCapture1 - tCapture0_; // Subtracts correctly at integer overflow
		nRPM = (60 * 100000 / 4) / tDelta; // No floating point operations needed
	} else {
		fRun = true;
	}
	tCapture0_ = tCapture1;
}

Though I left only comments related to key aspects. General logic restructuring, no floating point operations (particularly important as Cortex-M3 doesn't have FPU), integer arithmetic respective to overflow, static variables, not doing unnecessary/wrong reads and bitwise operations when assigning register values, code formatting - You can learn much from this. =)

Also take a note that this code (both versions) is not able to capture or detect speeds lower than 23 RPM (tDelta == 0xFFFF) - it'll calculate wrong speed.

P.S. You didn't answer about signal on oscilloscope.