Working on developing efficient code for driving a BLDC 3-phase motor with BEMF feedback using Atmega328pb,
The code is based (as a starting point) on this tutorial: Tutorial Link
The basic understanding is to increase the speed we need to increase the duty of the PWM's
However, the code I currently have works fine BUT is not efficient, (the motor uses much more current than other off the shelf controllers for the same speed)
Note: For this specific project, the main goal is to get a high speed (as the motor is used for an air pump or blower)
The code is simple,
See the link Controlling Sensorless, BLDC Motors via Back EMF that explains how it works, and for this project, we use this configuration below:
Important text from the Digikey tutorial from the link above:
Note that there is a phase difference between an individual Hall sensor changing output in a conventional BLDC motor, and the back EMF zero crossing point for an individual coil in a sensorless unit of 30 degrees. Consequently, in a sensorless motor control circuit, after the zero-crossing point is detected, a 30-degree phase lag is built into the firmware before the next action in the energizing sequence is activated
The question is:
How can we know exactly when to move to the next step, (maybe we can use timers, but the timers are used for controlling the PWM's)
In the tutorial code, it implements some form of delay in the ISR code that works somehow, but is very not efficient,
See code below:
Basically, the code waits for some amount of clock cycles before moving further
The ACSR register bit 0x20 (32) just shows the state of the comparator, but I don't understand what it is trying to do, and how to make it more efficient?
I am trying to do something like this:
Thank You.
The code is based (as a starting point) on this tutorial: Tutorial Link
The basic understanding is to increase the speed we need to increase the duty of the PWM's
However, the code I currently have works fine BUT is not efficient, (the motor uses much more current than other off the shelf controllers for the same speed)
Note: For this specific project, the main goal is to get a high speed (as the motor is used for an air pump or blower)
The code is simple,
- It uses a 6-step commutation to rotate the motor,
- It triggers a comparator interrupt to go from one step to the next step, (for every step the interrupt is different, see the code in the above link)
See the link Controlling Sensorless, BLDC Motors via Back EMF that explains how it works, and for this project, we use this configuration below:
Important text from the Digikey tutorial from the link above:
Note that there is a phase difference between an individual Hall sensor changing output in a conventional BLDC motor, and the back EMF zero crossing point for an individual coil in a sensorless unit of 30 degrees. Consequently, in a sensorless motor control circuit, after the zero-crossing point is detected, a 30-degree phase lag is built into the firmware before the next action in the energizing sequence is activated
The question is:
How can we know exactly when to move to the next step, (maybe we can use timers, but the timers are used for controlling the PWM's)
In the tutorial code, it implements some form of delay in the ISR code that works somehow, but is very not efficient,
See code below:
Code:
// Analog comparator ISR
ISR (ANALOG_COMP_vect) {
// BEMF debounce
for(i = 0; i < 10; i++) {
if(bldc_step & 1){
if(!(ACSR & 0x20)) i -= 1; //for falling interrupts
}
else {
if((ACSR & 0x20)) i -= 1; //for rising interrupts
}
}
bldc_move(); //start the next step
bldc_step++;
bldc_step %= 6;
}
The ACSR register bit 0x20 (32) just shows the state of the comparator, but I don't understand what it is trying to do, and how to make it more efficient?
I am trying to do something like this:
Code:
// Analog comparator ISR - at cross '0'
ISR (ANALOG_COMP_vect) {
//check time in Timer0 TCNT0 register
OCR0A = TCNT0; // + ((float)TCNT0 * 0.1);
TCCR0A = 0;// set entire TCCR2A register to 0
TCCR0B = 0;// same for TCCR2B
//initialize counter value to 0
TCNT0 = 0;
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS01 and CS00 bits for 64 prescaler
TCCR0B |= (1 << CS02);// | (1 << CS00);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
}
ISR(TIMER0_COMPA_vect) {
// disable timer compare interrupt
TIMSK0 &= ~(0 << OCIE0A);
bldc_move();
// set Timer0 to normal mode (just count)
TCCR0A &= ~(0 << WGM01);
// Set CS01 and CS00 bits for 64 prescaler
TCCR0B |= (1 << CS02);// | (1 << CS00);
//reset counter value to 0
TCNT0 = 0; //reset Timer0
}
Last edited: