From a high level, I wanted an interface to a BLDC motor that behaved much like a H-bridge does for a brushed DC motor. The result is a board that handles the heavy work of commutating of a BLDC motor using hall effect feedback. After hooking up power, motor wires and hall sensors, the minimal inputs required to the board are direction (high/low) and PWM. Everything else is taken care of to properly spin the motor. Pretty nifty.
The smart part of this board is that it can act as a SPI slave, keeping track of position of the motor via the hall effect sensors (using a 3-phase adaptation of this quadrature decoding method), or optionally a quadrature encoder (breakout pins included). The SPI master can set a sample-and-hold pin high to tell the Smart BLDC Commutator to sample the current position and get it ready for communication over SPI. Then the master can initiate the SPI transfer at its leisure to read the position at the time the sample-and-hold pin was set. This is particularly useful for closed loop control on multiple motors so that each iteration through the control loop you can read the positions of the various motors at the same instant in time.
Many people will probably ask why I don't offload the control loop itself to the Smart BLDC Commutator, transferring the desired position over SPI and letting the board do the rest. While I have build the board with that possibility in mind, there is a problem when trying to sync multiple motors. That problem is variations in clock speed between multiple Smart BLDC Commutator boards. In college I attempted to build a differential drive robot with a separate uC controlling each wheel and a master uC relaying position commands to them. Because one uC will inherently run ever so slightly faster than the other that means one wheel will spin ever so slightly faster. Therefore, instead of driving in a straight line the robot would drive along an arc. To fix the robot I had to disable on of the uC's and add a lot of magnet wire to get one uC controlling both wheels.
Enough overview. Let's dig into the hardware.
At the heart of the Smart BLDC Commutator is an atmega328p uC, identical to the one found on the Arduino Uno. For easy compatibility with the Arduino IDE, I have a 16MHz external clock on board. A reset button is included because I've learned my lesson about not including them while repeatedly disconnecting and reconnecting power over and over again with reset buttonless designs. An LED lives on board for good measure, connected to an I/O pin to be fully configurable.
Each of the three motor wires, lovingly called A, B, and C, are driven by discrete power MOSFETs: a high-side (P-channel) and low-side (N-channel). At any given time during active commutation there is exactly one high-side MOSFET and on low-side MOSFET conducting, but never both on the same motor wire (which would be a short to ground). Driving the gates of these MOSFETs are a collection of small N-channel MOSFETs and voltage dividers which are used to take the low voltage uC signals (3.3-5V) up to higher voltages required for the power MOSFETs (4-18V).
Because the high-side MOSFETs are P-channel the gate voltage is referenced relative to the source (connected to VM). When the source-to-gate voltage is 0 (i.e. the gate voltage is at VM) then the MOSFET is non-conducting. when the source-to-gate voltage is enough negative (i.e. the gate voltage is less than VM) then the MOSFET is conducting. It is driven as follows: when the AH signal (C7) is low the MOSFET Q1 acts as an open switch. This effectively removes R4 from the picture and what's left is a 10k pull-up resistor R3. When the AH signal is high then Q1 acts as a closed switch to ground, introducing R4 back into the picture and creating a voltage divider to drive the gate of the A high-side MOSFET thus turning it on.
The low-side MOSFETs are N-channel and behave more intuitively. The relevant voltage for N-channels is the gate-to-drain voltage and since the drain is connected to ground here then the gate-to-drain voltage is the same as the gate-to-ground voltage. To make the following description less awkward assume that the PWM value is a steady high signal (100% duty cycle), therefore the voltage at the gate of the small MOSFET Q6 (location C6) is the OPPOSITE of the AL signal (due to the NOT portion of the NAND gate). Now the low-side MOSFETs are driven as follows: when the signal on AL is low then Q6 is conducting, connecting the gate of the A low-side MOSFET to ground making it non-conducting. When AL is high then Q6 is like an open switch, so the A low-side gate gets pulled through R9 to the VGL voltage (set by the voltage divider made by R1 and R2) which makes the A low-side MOSFET conducting.
Now a little about that NAND gate, the 4011B. One of my goals was to have a single PWM input to the Smart BLDC Commutator for power control to the motor. The PWM needs to be routed to each of the three motor wires. Instead of having the onboard uC attempt read PWM from the master and then commutate the motor with the same PWM, I routed the masters PWM to all three motor wires. I then ANDed the PWM with the commutated control signals. However, MOSFET driving circuit meant that a low on AL/BL/CL would result in the A/B/C low-side MOSFET conducting, and a high on AL/BL/CL would be non-conducting. This feels backward and is opposite the high-side MOSFETs and made it hard to keep track of what the code was doing. But changing the AND gate to a NAND gate reversed everything and made it all make sense.
As for how all this gets power to the motor, suppose that the A high-side and B low-side MOSFETs are conducting--current will flow from VM (location D8), through the A high-side MOSFET (D7), out motor wire A and through the motor windings back through motor wire B, and then to ground through the B low-side MOSFET (G6) to complete its journey. As the motor turns and is detected by the hall sensors the uC updates which hi-side and which low-side MOSFETs get turned on, keeping the motor perpetually spinning.
|Click on image for animated version.|
To set all the motor control signals (AH, AL, BH, etc.) I wanted to take advantage of port manipulation on the uC in order to quickly change all pins at once. To allow this I made sure that all the signals were connected to the same port on the uC, in this case port C (PC0-PC5). Now to set the signals all I have to do is write a 6-bit binary number to PORTC. For example
PORTC = 0b001010;
sets AH and BL signals high and all the others low.
For the sample-and-hold and direction inputs from the master into the Smart BLDC Commutator, as well as the hall effect sensors, I wanted to use pin change interrupts for maximum speed and code efficiency, so likewise I ensured that all these signals were connected to a common port, in this case port D. In software I set up an interrupt handler to trigger when any one of the above pins changes, which updates the commutation phase and motor position.
The design files are hosted on GitHub and are licensed under CERN OHL v.1.2.
The firmware is also hosted on GitHub but under the BSD 3 clause license. The firmware will be discussed in detail in a coming post.
Smart BLDC Commutator PCBs will soon be available in the makeatronics store for $15.