Measuring speed of a bldc motor from hall sensor

Last post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am working on controlling the speed of a 3phase bldc motor. I want to measure the speed of the motor usint timer/counter 0 and external interrupt(INT0) that measures the rising edges of a hall sensor. Could anyone guide me on how do i do this? I am a beginner in avr and C programming language. Your reply is highly appreciated. Thanks in advance!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need help with the algorithm, or the coding? Do you want to control the speed or measure the speed? (might be a language problem)

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would want to do both. But first i want to learn how to measure the speed of the motor. I have read stuff on the internet saying to measure the rising edges of a hall sensor. But im not so sure how do i do that in code. Some code might be able to give me a start. Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

do a Google search for tachometer avr. you will find several projects with source code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I went thorugh that. But I would have to use timer0 in my case as Timer1A/B and Timer 2 are being used to provide pwm for the high side switches. I have to use INT0 instead of AIN0 since ill be using timer0. So im not sure how to do that using timer0 and INT0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it should not be that difficult to adapt code between the different timers. It's a good way to learn about avr registers. Datasheets Datasheets.

Not many here will do the hard work for you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

many=any
;)

As a beginner, I suggest you start with (1) flash an LED at predictable rate (2) read state of switches (3) use timers/pwm to vary brightness of LED (4) control bldc motors.

--greg
Still learning, don't shout at me, educate me.
Starting the fire is easy; the hardest part is learning how to keep the flame!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I would have to use timer0 in my case as Timer1A/B and Timer 2 are being used to provide pwm for the high side switches. I have to use INT0 instead of AIN0 since ill be using timer0. So im not sure how to do that using timer0 and INT0


In all this, wouldn't it be helpful to tell what AVR model you are using?

Depending on the PWM setup, ICP can still be used as long as timer1 is running during the needed sensing period.

Quote:

I am a beginner in avr and C programming language.

Then why have you cast your other (PWM) requirements in stone before considering all the app requirements as a whole?

You can put lipstick on a pig, but it is still a pig.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ill be using the pwm in phase correct mode. I want to detect the rising edges of a hall sensor.(2 rising edges will give me 1 mechanical revolution) as this is a 4pole 3phase bldc motor. Would i be able to use the ICP to measure the rising edges still? and how?

Thank You.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

In all this, wouldn't it be helpful to tell what AVR model you are using?

Quote:

Ill be using the pwm in phase correct mode. ... Would i be able to use the ICP to measure the rising edges still? and how?

So, tell the AVR model and show the setup code for the timer. (But indeed, the up/down counting modes would make it difficult (not practical?) to use the ICP trips.) [It is perhaps interesting/ironic that in all of my production AVR apps over the years that use PWM, I've never once used any of the up/down modes. But you motor people will have to educate me--would this be the type of app where this mode would be useful?]

Also, tell the max speed that needs to be measured.

You can put lipstick on a pig, but it is still a pig.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include "avr/io.h"
#include "avr/interrupt.h"


ISR(TIMER0_OVF_vect)
{
	overflow++;

}


ISR(INT0_vect)
{
 //this is where the rising edges will be detected
//not sure how to put it in code


}


int main()
{

	MCUCR |= (1<<ISC01)|(1<<ISC00);//rising edges
	GICR |= (1<<INT0);
	
	TCCR0 |= (1<<CS01)|(1<<CS00);//prescaler 64 
	TCNT0 = 0x00;// initialise timer counter0
	TIMSK |= (1<<TOIE0); // enable timer0 interrupt overflow

	while(1)
	{
		if(PIND & (1<<PD2))
		{
			//usart sends the speed in rpm to the hyperterminal
		}
	}
	
	return 0;
}
	
	
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the max speed that needs to be measured is 5000rpm

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

5000 RPM; 2 counts/revolution; 10000 counts/minute. 166 counts/second max; 6ms/count. So that isn't going to stress AVR capabilities. In fact if there are clean edges a fast timer tick would allow polling, or even polling and debouncing. I poll banks of flowmeters with the max frequency in that 100Hz to 200Hz range.

But, hey, I'm out--unless you start answering questions and give the whole scenario. What AVR model? What clock speed? Type of clock source? Timer setup for PWM?

You can put lipstick on a pig, but it is still a pig.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry.
Im using ATmega8. The clock speed is 8Mhz and the timer setup is as follows:-

int main()
{	


	int pwm=255;

	TCCR1A |=  (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);//phase correct 8bit
	TCCR1B |= (1 << CS10);// no prescaling
	TCCR2 |= (1 << COM21)  | (1 << CS20)| (1 << WGM20);//phase correct 8bit with no prescaling
	 
	OCR1A = pwm; 
	OCR1B = pwm;    // initialises values for output compare of timers
	OCR2 = pwm;

	DDRB=0xff;
	PORTB=0b00001110;//toggle PB1, PB2 and PB3 for pwm
}

When you say type of clock source do you mean this?
"Int RC Osc. 8 MHz; Start-up time: 6 CK + 64 ms"

Thank You.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Might need to run at 16mhz from a crystal so the cpu has some more hump.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
ISR(INT0_vect)
{
//this is where the rising edges will be detected
//not sure how to put it in code

Then it is time to open the datasheet.
The behavior of Avr periferies is controlled via IO registers.
In datasheet section "External interrupts" you will find that those use 3 registers:
MCUCR
GICR
GIFR

MCUCR desription shows how to set the desired edge for an inerrupt.
In GICR you will learn how to enable and disable ext. interrupts.
In GIFR there are only interrupt flags. Need not change anything there.

So in main code set properly MCUCR and GICR so that your interrupt fires on rising edge.

In INT0 ISR clear and start timer (with prescaler)
and at next interrupt stop timer.
(You will need to note somewhere whether the current interrupt is odd or even.)

There are beter methods but you can start with this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So, what i did in the timer overflow interrupt is right? and how do i calculate the speed of the motor using the overflow++? that should be done in the INT0 ISR?
I have already set the MCUCR and GICR. why do i have to set up GIFR?
Thank You.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

asin209 wrote:
Sorry. Im using ATmega8.

You should. Hard piece of wood.

No RSTDISBL, no fun!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this

// Measures RPM, pulses on INT0 (PD2)
// One pulse for revolution 
// Range 30 to >10000 rpm

//Atmega8
#define F_CPU  8000000UL
#include 
#include          
#include       

//One timer step lasts 
//timer_step[microsec] = prescaler / F_CPU[MHz] 
#define TIMER_STEP  256/8

volatile uint8_t  overflow;
volatile uint32_t period;
uint16_t          rpm;

//--------------------------------------------------
ISR(TIMER0_OVF_vect)
{
   overflow++;
}

//--------------------------------------------------
ISR(INT0_vect)
{
static uint8_t odd;

   if(odd == 1)
   {
      overflow = 0;      //clear overflow counter
      TCNT0 = 0;         //clear timer
      TCCR0 = (1<<CS02); //start timer0
      odd = 0;
   }

   else
   {
      TCCR0 = 0;         //stop timer0   
      period = (overflow * 256UL + TCNT0) * TIMER_STEP ; //[microsec]
      odd = 1;
   }
}


int main(void)
{
   MCUCR |= (1<<ISC01)|(1<<ISC00);//rising edge
   GICR  |= (1<<INT0);  //enable INT0 interrupt

   TCCR0 |= (1<<CS02);  //prescaler 256
   TIMSK |= (1<<TOIE0); //enable tmr0 ovf interrupt 

   while(1)
   {
      cli(); //atomic section
      rpm = 1000000UL * 60 / period;
      sei(); //atomic section end
      _delay_ms(20); 

      //send rpm to the hyperterminal
   }
}

Not tested in real.

Edit:
TCCR0 = (1<<CS01); //start timer0
changed to
TCCR0 = (1<<CS02); //start timer0
Sorry.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, thanks for the code.I tried it and it worked. However, when you said rpm = 1000000*60/period i get a wrong rpm. it should be *30 instead of 60
Also, you used 256UL. is that a prescaler? or just the max in TCNT0?

Thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
However, when you said rpm = 1000000*60/period i get a wrong rpm. it should be *30 instead of 60
It suggests that you have two pulses for one revolution.
Quote:
Also, you used 256UL. is that a prescaler? or just the max in TCNT0?
We count pulses with timer0, register TCNT0.
After 256 pulses the timer overflows and we increment the variable "overflow".
So number in "overflow" means groups of 256 pulses.
Then we find number of all pulses with
pulses = overflow*256 + TCNT0

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for the explanation. It really helped.
I was wondering, does the pole pair affect the calculation of the rpm? The motor has 2 pole pairs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, of course . The more poles the more hall sensor changes per revolution. You should see that in your block commutation routine. A typical motor with 3 sensors has 6 states which will be repeated for each pole pass. I'm working with a 36 pole motor and this generates 36 complete sequences = 72 pole changes on each hall sensor per rotation.