Recently i finished making a homemade BLDC motor driver and it works quite well.
But when adding features i noticed that there's something not right with it.
The project was based on this project here:
https://simple-circuit.com/arduino-sensorless-bldc-motor-controller-esc/Except that i've changed most of the code because i'm using an Attiny88 instead of a Atmega328.
The Attiny only has two HW PWM outputs and in my project i've only used one of them.
To multiplex the single PWM output i connected the PWM pin though 2k resistors to other three GPIO pins, which operate as open collector outputs to control the PWM. But that's not the problem.
The problem comes with the BEMF sensing. At first i noticed that my button polling wasn't working and quickly realized that it's because my analog comparator interrupt is taking too long.
The A-Comp interrupt routine was taken straight from the project mentioned above and the cause of the interrupt taking too long is the "debouncing" part:
// Analog comparator ISR
ISR (ANALOG_COMP_vect) {
// BEMF debounce
for(i = 0; i < 10; i++) {
if(bldc_step & 1){
if(!(ACSR & 0x20)) i -= 1;
}
else {
if((ACSR & 0x20)) i -= 1;
}
}
bldc_move();
bldc_step++;
bldc_step %= 6;
}
The way that the debouncing in the ISR works is that a
for() loop cycles a certain number of times and if the output of the analog comparator is not as expected the loop is stalled. But, for me, the loop is almost permanently stalled and i want to fix this my way, because the borrowed code isn't working for me.
So in summary what i'm doing
in my code right now:
1. Comparator is set to trigger on any edge*.
2. When it triggers the ISR is called.
3. The A-Comp interrupt is immediately disabled.
4. The "debouncing" bit takes place.
5. Outputs get commutated.
6. A-Comp inputs get changed.
7. A-Comp interrupt is enabled again.
*The reason why i trigger my interrupt on any comparator edge is that if noise appears then both falling and rising edges are close together, so it makes no difference in the end.
For my controller to work i need to find a way to reject noise. There are two main sources of noise.
First is the switching noise that appears at the beginning of the BEMF sensing period, and second is random noise in the form of voltage spikes.
In a Ti application note
[1] their switching noise was addressed by simply ignoring it for a set period. But this is problematic because the period needs to be shorter for higher speeds. And if i make the period proportional to speed then it's a positive feedback loop for more noise where: noise artificially increases speed measurement -> noise rejection period is decreased as result -> the probability of noise passing through is higher.
In the same application note the random noise was addressed by simply adding a capacitor in the volatge divider to make an RC filter.
This RC filter approach seems to be common among many other application notes, including Microchip, NXP etc.
I'm thinking for starters, if the output of the A-comp is not as expected then to just exit the ISR ASAP. But if all unexpected outputs are bad then all expected outputs are good? Nope. I think there also needs to be
some delay after exit. Since for a given voltage spike there will be an opposing edge right after the first trigger. But this would only work for voltage spikes going the "wrong" way.
Ok let's take a step back. In the same Ti application note it is made clear that the BEMF zero crossing occurs 30
o before the switching event needs to happen. This means that i have 30
o of time to determine if my BEMF crossing was correct or not. I think that i could trigger two SW timers for this.
First timer would count the 30
o that i need to delay my switching by. And the second timer would count the length of the comparator pulse received.
If the comparator pulse is impossibly short, then the degree timer would be reset and maybe halted completely. This would reject both positive and negative spikes, making the above mentioned "
some delay" unnecessary.
The thing is that, ultimately, the number of these false triggers will be highest near the zero crossing. Which is why i'm not sure i would halt the 30
o timer. And in the end i would be doing the same as the debouncing loop in the original code, except in a more roundabout way.
I'm thinking that, regardless of what the noise detection does, the 30
o timer should save the value of the A-comp for each degree. At the end of the 30
o period, if the result of the counted A-comp values is overwhelmingly as-expected (let's say above 90-95%) then it would be assumed that the zero crossing is valid and switching is permitted.
But then i'm not sure what to do if it's not. Maybe delay by 1
o for not more than 10
o until the result passes?
And if the result still doesn't pass, then assume that the motor is out of sync and disable all outputs?
Also the whole counting degrees thing relies on speed measurement, which relies on accurately detecting the zero crossing so it's like a catch-22.
What do you guys think? Do you have any tips or maybe some links to any resources?
[1]
https://www.ti.com/lit/an/spra498/spra498.pdf?ts=1659362622694&ref_url=https%253A%252F%252Fwww.google.com%252F