Brushless DC (BLDC) motor with Arduino – Part 2. Circuit and Software - Electronics Blog

Brushless DC (BLDC) motor with Arduino – Part 2. Circuit and Software


{adinserter Internal_left}In this post I will describe the hardware and the software part of a project involving the use of BLDC (Brushless DC) motor salvaged from a broken XBox 360. This is a second installment in the series of posts related to Arduino and brushless DC motors. Please see the first part for a bit of info on the theory behind the commutation sequence. Once you understand the commutation sequence for the particular design of the BLDC motor, the circuit design for the BLDC driver becomes pretty clear. It is not much different from a bipolar stepper driver in that we need the be able to both source and sink current at all ends of the windings, except of course in this case there are only three ends whereas the bipolar stepper has four.

The circuit diagram below is a concept that should work with any microprocessor (or a specialized driver IC) that is able to produce the correct commutation sequence:

Connecting a BLDC motor to SN754410NE driver IC and a microprocessor

Connecting a BLDC motor to SN754410NE driver IC and a microcontroller

Please note that this is a simplified circuit that only makes use of three MCU outputs. With three driver inputs it is possible to create only two levels at the ends of the windings: LOW and HIGH. Using three different levels – LOW, HIGH and OPEN could have enabled us to disable one of the windings on each of the steps, which results in more torque and also enables rotational speed feedback via measuring voltage induced on the disabled winding by the permanent magnet of the rotor. However, this circuit was designed for a rather simple application where speed feedback is not required – the load is so light that the motor is guaranteed to complete the steps given to it and the rate that the controller sets up. If your application requires accurate speed control and your motor does not have Hall-effect sensors (many BLDC motors do), then this simplified circuit is not suitable for your application. The flip side of the three-level BLDC driver circuit is that it requires six MCU outputs.

Another similarity of this circuit with bipolar stepper drivers is that it’s based on the same quad half-H bridge IC – SN754410 by Texas Instruments (SN754410 datasheet: SN754410 Quadruple Half-H Driver IC).

Here is the Arduino Sketch for driving the BLDC with discrete steps: Arduino sketch for BLDC motors – discrete steps

If you watched through the first part of the video above, you can see that the CD is constantly slipping on the spindle – if the motor is driven in such a way that the driver IC is given each of the 36 steps that comprise one complete 360° revolution, it responds to each step very quickly and half the time just sits there at the step while the CD disk ontop is having a hard time catching up. The friction between the spindle and the CD is just not enough to firmly hold the CD to the spindle and rotate synchronously. In the actual CD/DVD drive there is a small disk spring with several concentric petals that pushes on the CD toward the spindle and helps to prevent the slips. In our case we don’t have such a spring and so we have to devise other ways of gently rotate the spindle so the CD on top of it does not slip.

All these problems with jerkiness (Wikipedia says: Jerkiness, sometimes called strobing – somewhat ironic given that this will be a stroboscope when we’re done) of the spindle are caused by driving it from the binary output (either HIGH or LOW) of the MCU. Three phase motors like these are ideally driven with alternating currents and voltages creating a sinusoidal waveform, 120° apart on each of the three ends of the windings. This requires a lot of effort in a digital world – a DAC chip (Digital-to-Analog Convertor) and plenty of computations. But there is an easier way to “emulate” the effect of alternating current in the binary world of microcontrollers: pulse width modulation or PWM.

PWM is a technique of producing bursts of current at a preset voltage in a rapid succession of cycles of equal length called PWM period which is the inverse of the PWM frequency. The duration of the burst in each cycle, called PWM duty cycle, is defined by the PWM value from 0 to 255 (as implemented in Arduino) where 0 means no burst at all, at 127 the burst continues for 50% of the time of the PWM period and 255 means that the output is on HIGH during the entire length of the PWM period.

The PWM is still a digital output – it has only two states – 0 and 1 AKA LOW and HIGH. However, if we apply this output to a load that has inertia of any kind, such as persistence-of-vision if we control LEDs or moment of rotational inertia if we control electrical motors, the end result of PWM control resembles the effect of controlling the voltage across the load – dimming the LEDs and controlling the RPMs of the motor.

Driving a three-phase motor using Arduino PWM outputs - Timing Diagram

Driving a three-phase motor using Arduino PWM outputs - Timing Diagram


Most Arduino boards have 6 PWM-enabled outputs and Arduino Mega has 14. In our case 3 is enough. The PWM values (PWM duty cycle) are taken from the diagram above. Please disregard the LED flashes for now – they are specific to the project this digram was prepared for. Also, note that this is NOT a sine voltage waveform digram even though it would have been appropriate describing a three phase motor. It would be difficult to create it with Arduino and therefore what you see is a PWM timing digram – PWM duty cycle as a function of rotational angle.

Since our motor is a 9-cog, 12 magnetic poles BLDC, each of the PWM cycles (a change from 0 to 255 and back) on the diagram represent 1/6th of one full 360 ° rotation ( please see the first part for a better illustration of why). The number of steps in which we divide the full PWM cycle is rather arbitrary but after some experimentation I settled on 48. I started off with 12 but it did not make the rotation smooth enough. 24 PWM steps were already workable and 48 PWM steps were the most smooth. We could divide it even more but it would be too much of a hassle because I wanted to treat these values as a constant array so as to avoid making the Arduino go through some serious (for an MCU) math calculations to create it. I just calculated the 48 values I needed in the OpenOffice.org Spreadsheet (here is the spreadsheed for the sine function : Sine function spreadsheet in OpenOffice.org Spreadsheet format )

Please see the PWM duty cycle array definition on the highlighted lines in the Arduino sketch below. The rest of the sketch should be pretty much self-explanatory. The windings are marked as A,B and C and they are connected to Arduino’s digital PWM outputs numbers 9,10 and 11 respectively. The Arduino looks up the PWM parameter from the pwmSin array always keeping windings 1/3 of the cycle apart. Once the cycle duration variable, set by the motorDelay constant and additionally corrected by a potentiometer value potState, expires, the program moves one step forward by incrementing all of the winding’s positions and resetting the one that reached 48 back to 0.

/* 
Driving a DVD drive spindle three-phase motor 

This code was used for the stroboscope project
 
This example code is in the public domain. Based on several Arduino code samples
 
http://elabz.com/
 
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 8;// the number of the direction pushbutton pin
const int ledPin =  7;  // the number of the status LED pin (not the flash LED)
const int potPin = 0;  // pot controls the RPM speed
const int potPinFlash = 1;  // pot controls the flash speed
const int motorPin1 =9;
const int motorPin2 =10;
const int motorPin3 =11;
const int flashPin =12;
const int motorDelay=5; // together with pot controls the RPM
const int flashDelay=2; // controls duration of flash
const int frames=12; // has to be divisible by 3 in this version
const int serialDelay = 2000; //debug only
long serialLast =0; //debug only
// Variables will change:
boolean ledState = false; // the current state of the status LED output pin
int buttonState;    // the current reading from the direction input pin
int potState;       // the current reading from the RPM speed potentiometer
int potStateFlash; // the current reading from the flash rate potentiometer
int lastButtonState = LOW; 
int debounceDelay = 50;    // the debounce time; increase if the output flickers
boolean direct = true; // direction true=forward, false=backward

/*
int pwmSin[] = {127,110,94,78,64,50,37,26,17,10,4,1,0,1,4,10,17,26,37,50,64,78,94,110,127,144,160,176,191,204,217,228,237,244,250,253,254,253,250,244,237,228,217,204,191,176,160,144,127
}; // array of PWM duty values for 8-bit timer - sine function
*/

int pwmSin[]={511,444,379,315,256,200,150,106,68,39,17,4,0,4,17,39,68,106,150,200,256,315,379,444,511,578,643,707,767,822,872,916,954,983,1005,1018,1022,1018,1005,983,954,916,872,822,767,707,643,578,511
}; // array of PWM duty values for 10-bit timer - sine function

int increment;
int flashIncrement = 0;
int currentFlash=0;
int currentStepA=0;
int currentStepB=16;
int currentStepC=32;
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long motorDelayActual = 0;  // the actual delay, based on pot value and motor delay set above
long flashDelayActual = 0;
long flashDelayPerCycle = 0;
long lastMotorDelayTime = 0;
long flashTime = 0; // how long has flash been ON 
long flashTimeOFF = 0; // how long has flash been OFF 

void setup() {

  TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
//  ICR1 = 255 ; // 8 bit resolution
  ICR1 = 1023 ; // 10 bit resolution


  pinMode(buttonPin, INPUT);
  pinMode(potPin, INPUT);
  pinMode(potPinFlash, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(flashPin, OUTPUT);
  digitalWrite(flashPin, LOW);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = reading;
    direct = !direct;
    ledState = !ledState;
    lastButtonState = reading;
  }
  
  // set the LED using the state of the button:
  digitalWrite(ledPin, ledState);

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:

 potStateFlash = analogRead(potPinFlash);
 potState = analogRead(potPin);
motorDelayActual =   potState * motorDelay / 100; 
// flashDelayActual =   flashDelay+potStateFlash/200; // if we were controlling it with a POT
flashDelayActual =   flashDelay;
move();

  
}



void move()
{
if((millis() - flashTime) >  flashDelayActual)
{
  digitalWrite(flashPin, HIGH);
  
}
  
  
if((millis() - lastMotorDelayTime) >  motorDelayActual)
{ // delay time passed, move one step 


if (direct==true)
{
  increment = 1;
} else {
  increment = -1;  
} 
  currentStepA = currentStepA + increment;
  if(currentStepA > 47) currentStepA = 0;
  if(currentStepA<0) currentStepA =47;
  
  currentStepB = currentStepB + increment;
  if(currentStepB > 47) currentStepB = 0;
  if(currentStepB<0) currentStepB =47;
  
    currentStepC = currentStepC + increment;
  if(currentStepC > 47) currentStepC = 0;
  if(currentStepC<0) currentStepC =47;

lastMotorDelayTime = millis();
//flashDelayPerCycle = flashDelayPerCycle + flashDelayPerCycle;
currentFlash = currentFlash + 1;
if(currentFlash>24)
  { 

    digitalWrite(flashPin, LOW);
    currentFlash=0;
    flashTime = millis();
    flashDelayActual = millis();

  
  }


}
  
analogWrite(motorPin1, pwmSin[currentStepA]);
analogWrite(motorPin2, pwmSin[currentStepB]);
analogWrite(motorPin3, pwmSin[currentStepC]);
  
}

Here is the zip file with the Arduino sketch that you can download: Arduino Sketch for controlling 3-phase brushless DC (BLDC) motor

This is becoming a rather long post, so I’ll save practical issues with implementation of the stroboscope project for another post. If you have any question about controlling brushless DC motors in general, please post your question by starting a thread in our Motor Control Forum.

56 Responses to “Brushless DC (BLDC) motor with Arduino – Part 2. Circuit and Software”

  • […] have seen some Stroboscopes in operation before, for this  DIY Stroboscope that uses a Three Phase DC Motor which eLabs put together I think the actual stroboscope is the simpler part of the build. Since the […]

  • Candelo:

    Hi, How increase the speed, I try increase the frequency but doesn’t work.

    please help me.

    thank you.

    • It sort of depends on what RPMs you are looking for. Normally, you would adjust this line in the code

      const int motorDelay=5;

      – the lower the delay the quicker the wave of changing PWM values goes around the circle and the quicker the motors turns.

      However, these motors cannot go from 0 to full speed in no time. You have to speed them up gradually – it can be relatively quick but it cannot be instant – because the rotor is relatively large compared to the torque of the motor and if you try to rev it up too quick, the inertia of the rotor will just make it skip the steps and it will mess everything up – it’ll just stop if the speed with which the windings are commutated is too fast.

      if you lower the motorDelay constant and then start slow and gradually speed it up with the RPM potentiometer (talking about the complete circuit here) , you should be able to make it spin really fast.

      You can also adjust the Arduino sketch to insert a speeding-up sequence at the beginning. It will require some tweaking though, you’ll have to find the rate of acceleration that works with your particular motor.

      Thank you for stopping by!

  • Minseok Jeon:

    it is only dip type, not a smd type. i wish i could control bldc motor with smd type motor driver.

    • They do make SMD (14 pin MFP – 1mm pitch) half-H bridges equivalent to SN754410. Check out Sanyo LB1836M – “Low-saturation, Bidirectional Motor Driver for Low voltage applications”. It goes up to 10.5V supply and dissipates up to 800mW (when soldered to a board), current 1A per output max.

  • IF – and this is a big if – the desire is to simply drive a brushless motor as an experiment, the code is much simpler.

    Note the following:
    * I used a Seeed motor controller shield, with a single h-bridge chip, that I found at Radio Shack.
    * I used a Genuine Arduino Uno to drive it.
    * I used a motor salvaged from an old hard drive.
    * I did not use PWM, since (IMHO) the digital cycle time of the Arduino is sufficiently fast.
    * Using this code, the motor develops a reasonable amount of torque – you could easily drive a reduction gear assembly to drive something worthwhile. However, driving anything more than a few ounces directly will likely not work.
    * I implemented a start-up sequence.

    Also Note:
    For whatever reason, be it inefficiency in the code, the series resistance of the coils in a H/D motor, or whatever – both the driver chip and the motor get quite hot rather quickly so in this case, I do not let the motor spin for much longer than a couple of minutes.

    I have not tried driving any other kind of DC brushless motor, so I do not know if the heating effect is due to my choice of motor or not.

    BTW, the AC currents noted above do *NOT* apply to a *DC* brushless motor – that’s why it’s called a *Direct Current* brushless motor – as opposed to an *AC* brushless motor. It is true that you are supposed to alternate the direction of the current in the coils in a specific way – but not as a sine wave.

    The Microchip AN857 application note, “Brushless DC Motor Control Made Easy” (http://ww1.microchip.com/downloads/en/AppNotes/00857a.pdf) describes the basic layout of a Wye DC brushless motor, and the six states required for the three coils.

    I am going to list – inline – the Arduino code I used to run my particular experiment.

    ==================== begin inserted text ====================

    /*
      DC_Brushless_Wye_1 uses the Seeed motor driver board
      (which is designed to be used with either two brushed DC motors
       or one two-pole stepper), to drive a DC Brushless motor configured
       in a "Wye" (three coils, all connected together at one end with
       the other ends floating)
       
       My original design, DC_Brushless_Wye, did this by pulsing
       three of the four input lines in succession
       (i.e. 1-2-3 - 1-2-3 - etc.), with the common wire connected to
       the motor-power ground pin.
       
       This was extreamly inefficient, and caused a great deal of heating
       in both the motor and the driver chip.
       
       The Microchip AN857 application note, "Brushless DC Motor Control
       Made Easy" (http://ww1.microchip.com/downloads/en/AppNotes/00857a.pdf)
       describes the basic layout of a Wye DC brushless motor, and the six states
       required for the three coils.
       
       In summary:
       Given three coils, "X", "Y", and "Z", the three electrical connections
       to those coils, "x", "y", and "z", and the shared common center point, "c"
       "x", "y", the six states are like this:
    
    (Listed binary state)  (Coil I energized)  (What the current should be doing)
       1.  1-0-0                 x                   Current from x to y
       2.  1-1-0                 x-y                 Current from z to y
       3.  0-1-0                 y                   Current from z to x
       4.  0-1-1                 y-z                 Current from y to x
       5.  0-0-1                 z                   Current from y to z
       6.  1-0-1                 z-x                 Current from x to z
       
       Note that the common terminal "c" is not used, but can be used in some way,
       for monitoring the state of the motor.
       
       Note that the sequence that the coils are energized in the code below is
       actually backward from what is shown above - instead of 1-2-3, I cycle
       the coils as 3-2-1 in order to make the motor spin clockwise - the normal
       rotation for a hard-drive motor.  Of course, I could just wire them the
       other way. . . ( :grin: )
       
       Energizing the motor coils in this way - a, a-b, b, b-c, c, c-a - is actually
       more efficient and it develops greater torque.
    
    ====================================================*/
    
    /* Define the three coil output pins for the motor:
       These output pins drive the four input pins for the
       motor controller */
    int coil_1 = 8;
    int coil_2 = 11;
    int coil_3 = 12;
    int coil_4 = 13;
    
    /* Define the two enable pins.
       The two enable pins enable pairs 1 - 2 and 3 - 4 respectively
       enable_a enables the 1&amp;2 pair
       enable_b enables the 3&amp;4 pair */
    int enable_a = 9;
    int enable_b = 10;
    
    
    /*  Here we define the variables that control the motor's speed.
    
    Stepdelay is the number of milli-seconds to wait before switching
    to the next coil in rotation.
    
    Spinupdelay is just like stepdelay, except that it is used during initial motor
    turn-on.  It is preset to a fairly large value, and then decremented until the
    motor is spinning at the desired speed
    
    Decreaseby is just that.  It is the number of milli-seconds we subtract from spinupdelay
    prior to each successive series of motor pulses to allow the motor to gradually come up
    to speed
    
    It should be noted that there is some relationship between the value of
    stepdelay and the speed of the motor, as other values of stepdelay,
    either larger or smaller, cause the motor to either not run at all,
    oscillate, or run, but develop almost no torque.
    
    The value of stepdelay chosen below was the value optimal for the hard drive
    motor I was using.  Your Milage May Vary.
    */
    
    int stepdelay = 3;
    int spinupdelay = 15;
    int decreaseby = 1;
    
    /* Since the setup routine only runs once when you press reset, I use this section to do
    the initial initializations - and to perform the spin-up sequence.
    */
    
    void setup() {                
    
    // initialize the four coil pins as outputs.
      pinMode(coil_1, OUTPUT);     
      pinMode(coil_2, OUTPUT);     
      pinMode(coil_3, OUTPUT);     
      pinMode(coil_4, OUTPUT);
    
    // initialize the two enable pins as outputs too
      pinMode(enable_a, OUTPUT);
      pinMode(enable_b, OUTPUT);
    
    // set all coil pins low - no current being drawn by anyone yet.
      digitalWrite(coil_1, LOW);
      digitalWrite(coil_2, LOW);
      digitalWrite(coil_3, LOW);
      digitalWrite(coil_4, LOW);
    
    // set both enable pins high, so that both coil-pairs, (1-2 and 3-4) are active
      digitalWrite(enable_a, HIGH);
      digitalWrite(enable_b, HIGH);
      
    /*We start at a relatively slow step delay to account for the mass of the motor
    and platters.
    */
    do
    {
      digitalWrite(coil_3, LOW);   // Make sure coil 3 is off before turning on coil 2
      digitalWrite(coil_2, HIGH);  // State 1: Turn on coil 2
      delay(spinupdelay);          // Pause for "spinupdelay" milliseconds to give the motor time to get moving
      digitalWrite(coil_1, HIGH);  // State 2: Now turn on coil 1 so that both coil 2 and 1 are high
      delay(spinupdelay);
      digitalWrite(coil_2, LOW);   // State 3:  Turn off coil 2 so that coil 1 is on by itself
      delay(spinupdelay);
      digitalWrite(coil_3, HIGH);  // State 4: Turn on coil 3 so that coil 1 and 3 are high
      delay(spinupdelay);
      digitalWrite(coil_1, LOW);   // State 5: Turn off coil 1 so that coil 3 is on by itself
      delay(spinupdelay);
      digitalWrite(coil_2, HIGH);  // State 6: coil 2 and 3 both on
      delay(spinupdelay);
      spinupdelay = spinupdelay - decreaseby; // slowly increase the speed, (decrease the delay)
    } while (spinupdelay &gt;= stepdelay);  // we keep decreasing the spinup delay until we get to full speed.
    
    }  //  End "setup" block
    
    /*
    This is where the program does the "heavy lifting", so to speak.
    
    The "loop" structure works identically to a forever loop;
    for(ever), if(1), while(1), etc., as it repeats the block of code
    until reset - or Hell freezes!
    
    This section works just like the spinup section, except that the delay, (stepdelay),
    is a constant, and the block of code runs until turned off.
    */
    
    void loop() {
      digitalWrite(coil_3, LOW);   // Make sure coil 3 is off before turning on coil 2
      digitalWrite(coil_2, HIGH);  // State 1: Turn on coil 2
      delay(stepdelay);            // Pause for "stepdelay" milliseconds to give the motor time to get moving
      digitalWrite(coil_1, HIGH);  // State 2: Now turn on coil 1 so that both coil 2 and 1 are high
      delay(stepdelay);
      digitalWrite(coil_2, LOW);   // State 3:  Turn off coil 2 so that coil 1 is on by itself
      delay(stepdelay);
      digitalWrite(coil_3, HIGH);  // State 4: Turn on coil 3 so that coil 1 and 3 are high
      delay(stepdelay);
      digitalWrite(coil_1, LOW);   // State 5: Turn off coil 1 so that coil 3 is on by itself
      delay(stepdelay);
      digitalWrite(coil_2, HIGH);  // State 6: coil 2 and 3 both on
      delay(stepdelay);
    }                              // . . . and so on.
    
    /*  This ends the "forever"loop.  At this point coil three is still active, but
    since we jump right back to the top of the loop after stepdelay, coil 3 gets
    turned off at the appropriate time.
    */
    
    • Thank you for your detailed input, Jim! Yes, I agree, there are multiple ways to skin a cat (figure of speech 🙂 ).

      In my case I needed to have smooth transitions between the phases at a very low speed for this particular application: http://elabz.com/brushless-dc-bldc-motor-with-arduino-part-3-the-stroboscope-project/ Because of the strobe timing involved and the way the spindle is designed (the disk simply lays ontop, not attached) I could have absolutely no slippage of the rather slippery polycarbonate CD disk and therefore PWM played a huge part in this project.

      If the idea is to spin the BLDC motor up to a considerable speed, your approach with spinup delay routine is great and the code is simple. My project could benefit from speedup too, although it would have further complicated the code. I decided to forgo it since the top speed was not great anyhow and it already reaches it in a second or less.

      As far as heating of the driver IC, the actual “proper” setup would have you (and me, having the same heating issues) suspend one of the three ends of the windings in each phase by disconnecting it from both ground and the supply rail. In other words, instead of just two states – binary 0 and 1 we actually need that third Hi-Z state but it’s impossible to get with the Half-H driver ICs (unless you double their amount and utilize the Enable inputs). So, there’s a lot of current passing through this circuit that does absolutely nothing useful – just drains from 1 and 0 and generates heat. There’s also back-EMF which either adds or subtracts from that current, depending on the phase. So, yes, I agree, there’s a number of inefficiencies in this setup. They are all on the electronics side, by the way – the motor itself is incredibly efficient when hooked up properly.

      So, once again, thanks for your input! I’ll be delighted if you keep me posted through this blog if you continue your BLDC experiments. I am also planning to go back to playing with BLDCs at some point in the future.

  • abugroza:

    ummm… i’m new about arduino so i have some question
    1. what is it required while compiling/ downloading program to arduino
    2. if the spindle have 4 pin cable is it mean it 4 phase or just 3? and what line i should change
    3. and i have 3 cable brushless motor for rc can i use for it?

    thanks in advance

  • Anelia:

    Can you explaine what math calculations you used to create constant array.
    I’ll really appreciate it.

  • Hew:

    I am hoping to use a STM L6234 or L6235 bridge driven by Arduino 328 to control a BLDC motor.
    Has anyone attempted this route?
    Would value any comments and I’m prepared to collaborate in the project with anyone interested.

    • These STMicroelectronics chips are not just bridges, they are fully featured BLDC controllers – with phase commutation, PWM, rotational feedback, over-current protection, the whole 9 yards. In fact, I often see these and similar chips (ROHM’s BA6858,BH5510 and the rest of ROHM’s family of motor control chips, NEC uPD16882, Phillips SA56202 and many more) in DVD-RW drives that I open up to harvest the laser diode. I’ve yet to play with one of those but I am saving them all precisely because they seem to be so capable ICs and I have an almost endless supply of them from the broken DVD-RW drives.

      I assume you would have absolutely no trouble using ST L6235 chip with an Arduino or even a much smaller MCU chip because the controller does do much work by itself and only needs periodic input from the MCU. Which application you are going to be using it for? From the functional diagram it looks like L6235 would need an input from 3 Hall-effect sensors else it would “think” the motor had stalled. Most DVD spindle drives (though not all – XBox 360 is a notable exception) have those sensors. If you motor doesn’t, perhaps you can turn feedback OFF but I am not sure. Only have a cursory knowledge of these chips. Other than that, it seems pretty straightforward.

      I am very interested in what you find out! Please be sure to post here again with results. Perhaps it’s better to use the Forums, motor control section because you’ll be able to post pictures and links for videos: http://elabz.com/forums/motor-control/

      Thanks for stopping by!

  • sandip das:

    NO ITS JUST VIBRATING AND NOTHING HAPPENS IT IS MOTOR THAT NORMALLY USES FOR HELICOPTERS IM TRYING TO RUN IT WITHOUT ESC THAT’S WHY I AM TRYING TO MAKE IT.

  • sandip das:

    i have emailed you the pic details of the motor i hope that will help you to help me.and thank you very very much to help me sir.

  • […] to keep the same motor configuration so no software changes would be required. The change in the Arduino sketch for the brushless DC motor would be trivial but I just wanted the connect the upgraded motor right back to the stroboscope […]

  • sandip das:

    what change in the program is required if i want to drive a 12 cog motor not 9?

  • If the windings are wound in 4 groups of 3 (12 cogs) instead of 3 groups of 3 (9 cogs), no specific change would be needed – you just have to adjust the frequency of winding commutation to allow for 12 extra commutation steps (if we’re still talking about 12 poles rotor) during one complete 360 degree rotation. So, basically just run the commutation part of the software 25% faster and it will work the same.

  • sandip das:

    how i run the commutation part of the software faster ?

  • sandip das:

    and the motor has 12 coils and 14 magnets.

    • 14 is no divisible by 3 – I’ve never seen this combination before, not sure how it will work. Are you sure you’ve counted the poles properly? If it’s anything divisible by 3, you should be able to run the same software, only change the frequency of the winding commutation changes (more poles and/or cogs = faster commutations to keep the same RPM). To increase the frequency of commutations, change this line:

      const int motorDelay=5; // together with pot controls the RPM

      to something like

      const int motorDelay=2; // together with pot controls the RPM

      The smaller the number, the faster it will turn

  • sandip das:

    for this combination is the prog remain same?
    thank u in advance.

  • sandip das:

    Ok thank you.. I will check that.

  • Edwin John:

    Hi.
    I am doing a project based on the speed control of a bldc motor by pulse width modulation using an Arduino board. However, my motor does not have a hall sensor to provide the feedback on speed to the arduino. My set up involves using an esc (electronic speed controller) to link the bldc with the arduino. Can you suggest some method to achieve the required results with my components.
    Great page by the way. Cheers!

    • Thanks for stopping by, Edwin.

      Can you mount a reflective strip or cut a slot for a photo-interrupter type sensor to the actual spinning part? Problem with using a motor is that all three of its connections are taken by the ESC and it looks like it should be something of a sensor that’s external to the motor.

      You can also try to position an external Hall-effect sensor close to the magnet (if the motor design allows) – it’s usually in a small plastic TO-92 package, could slide it under the shroud of some of the outrunner BLDCs.

      Would you like to post more info about your project and perhaps some pictures that will be helpful for making a suggestion that makes sense, here: http://elabz.com/forums/post-your-projects/

  • I think that we still need a control loop to be able to lock the speed to the quartz clock of the MCU. One way of doing this is to use a capture & compare module + pulse feedback from the spindle (from a sensor – optic, magnetic, etc).

    • Thanks, Angel. Having control loop would be nice, but it is going to significantly increase the complexity of the project. Besides, there’s no way to get reliable electromagnetic feedback from the spindle at that speed – it’s way too slow to generate any significant amplitude. And the motor I used has no Hall-effect sensors inside. These are DVD spindle motors from early Xbox360s. Come to think of it, Microsoft probably saved 20 cents on not using motors with Hall-effect feedback in Xbox’es . And you were wondering why it’s reading the game disks so poorly … 🙂

  • Ethan:

    Hello,
    I want to use Arduino to control a 3-phases BLDC motor with absolute encoder and I saw your BLDC control project which is no sensor. My question is could I use your circuit for powering and control my motor and use Arduino board to read the encoder directly?
    Btw my motor is https://fmcc.faulhaber.com/details/overview/PGR_4436_13822/PGR_13822_13814/en/
    the encoder is https://fmcc.faulhaber.com/details/overview/PGR_19103_19701/PGR_19701_13802/en/

    Thanks

  • Duke:

    I don’t really understand “Using three different levels – LOW, HIGH and OPEN”. Could you post the digital timing diagram that apply to 3 motor inputs. I’m not able to translate from AC signals (winding A,B,C) to Digital inputs. Please, please.

    I have a spindle motor with 3wires. I used Ohm-meter to measure the resistance between each pins (A,B,C) and the values:
    A-B = 2 ohms, A-C = 4 ohms, B-C = 2 ohms.

    Base on the above measurement then it is not a Wye or Delta configuration.

    It seem like there are a 2 winding with center tab is B.

    What were I missed?

    Thank you

    • OPEN simply means that it’s connected to neither low nor high DC rail and no current is flowing through this end of the winding. It has no direct correlation to an AC motor hookup because you don’t have a device that disconnects windings, such as BLDC controller.
      But as far as the resistance between windings – there are myriad of AC motor winding configurations out there. Perhaps some of the ends are not exposed? I am not all that familiar with AC motors to be able to offer a good guess. If I were searching for a proper hookup of a motor, I would start by running its nameplate ID by Google to see if the manufacturer’s diagram comes up. More often than not, it does.

  • Ali Selcuk Birol:

    Hi,
    Is there any specific reason you choose pwm freq. as 31250 Hz in the program? And what is the effect of pwm freq. on driving bldc motor, if there is any.

    Thank you for your study and share.
    Regards …

    • Basically, the higher the frequency – the better. The windings need to be switched very quickly for any kind of serious RPM because you need to switch them 36 times during one revolution, plus you need to go through at least 24-48 PWM duty cycle changes to achieve the desired effect – the smooth rotation (see the video in this post with CD blank simply laying ontop of the spindle).

      Thanks for stopping by my blog!

  • jay oza:

    i want to know how to rotate and control the speed of BLDC with help of ESC by using arduino

  • Dani:

    Your code worked well on my salvaged spindle motor, thanks for sharing!!
    By the way, I found other spindle motors having 4 wires instead of 3.
    The fourth wire is labelled as C and I guessed it was the common wire.
    I just ignored it and the motor worked alright, but I wonder if it
    should be connected to the 4Y pin in the SN754410 chip.

  • […] quite a few sources for this project. We will be referencing material and using photos from this project, which served as our foundation for brushless motor control. Our code is heavily based on […]

  • Thanks for sharing information! I made my version of this project targeted for very slow speeds(gimbal motors)
    http://www.berryjam.eu/2015/04/driving-bldc-gimbals-at-super-slow-speeds-with-arduino/

  • Eduardo:

    Hi, quick question, by using the PWM, would that also mean that If I dont change the pwm value of the outputs the motor will stay at that angle right? Is this the way BLDC gimbals work?

    Thanks!

  • Albert:

    Hi, because you switched with 120 ° phase shift, if the electric phase shift between phases of the animation is 30º?

  • Andrei:

    Hi there,
    Great article. Really helps to explain the BLDC control.
    I was thinking of a way to control a BLDC by using 3 oscillator circuits with a phase shift of 120 degrees between them, instead of the three PWM signals. So I am curious to know if the input signal from your PWM resembles really a sine wave on an oscilloscope or is it more square?
    The idea is that I am trying to minimize my MCU computation for going through the entire array of PWM values as you mentioned.
    Thanks.

  • The signal is most definitely a square wave of varying width. Its resulting torque might look like a sine wave (if you could plot it) but the oscilloscope will only see square waves. Thanks for stopping by the blog!

  • John:

    I’m trying to use this code to rotate a 14-pole, 12-slot BLDC motor. However, I’m getting some very abrupt movements: https://youtu.be/GPtGkvvA9P8. I’ve tried both the 8-bit and 10-bit timers, but I still get very much the same result.

    Does anyone know why this might be happening or know of a solution?

    Thanks

  • YamZYang:

    Hello, I learned alot from here. I have a question about the H-bridge motor driver, are there any special need for the h-bridge IC to satisfy? For I tried a series of DC motor driver IC likes tb6612 l298n etc but turned out only l298 match the case, others run like miss a phase or something in my BLDC, but the l298n breakout boards are too large for me

  • Robert:

    Hello, can you explain why the 24 coil 22 pole motor I’m using (model BGM4108-130) does not rotate using your code? A slight vibration can be heard but there is no discernible movement in either direction.

    When I add an additional power source (9V battery) the same result is observed, except the vibration is louder.

    • Thank you for stopping by, Robert. To be honest, it’s been a couple of years since I looked at the code. But I imagine the issue is that the pole/coil ratio of your motor is different than that in the motor I used in that example. You will need to make adjustments to the code to allow for the different number of steps that would comprise a full 360 degree turn. In your case it is much more than in the simpler motor I used – 11*12 = 132 vs 36 in that example of mine. Perhaps some of the intermediate steps can be skipped – it depends on your application. The rotation will be less smooth than what it would have been, but the code implementation will be easier.

      The additional power source will unlikely solve the problem – first you need to make sure the energy goes around the circle in the right order of coils. Also, there’s very little energy stored in a 9V battery. For anything motor-related you definitely want something more powerful.

      • Robert:

        Thanks for you reply. I’m following a tutorial (https://www.instructables.com/id/DIY-Brushless-Gimbal-with-Arduino/?ALLSTEPS) to build a 3-axis gimbal using Arduino. In ‘Step 6’, the author describes how to rotate a Brushless Motor using a simple version of your code:

        // Driving 3-phase Brushless DC Motor with Square-wave
        // This sketch is based on the code for the stroboscope project by eLABZ.
        // (http://elabz.com/bldc-motor-with-arduino-circuit-and-software/)
        // Copyright (C) 2015 ArduinoDeXXX All Rights Reserved.
        const int motorDelayActual = 150;
        const int motorPin1 =9;
        const int motorPin2 =10;
        const int motorPin3 =11;
        const int motorPinState[]={1,1,1,0,0,0};
        int currentStepA=0;
        int currentStepB=2;
        int currentStepC=4;
        long lastMotorDelayTime = 0;
        void setup () {
        pinMode(motorPin1, OUTPUT);
        pinMode(motorPin2, OUTPUT);
        pinMode(motorPin3, OUTPUT);
        }
        void loop () {
        if((millis() – lastMotorDelayTime) > motorDelayActual){
        currentStepA = currentStepA ++;
        if(currentStepA > 5) currentStepA = 0;
        if(currentStepA 5) currentStepB = 0;
        if(currentStepB 5) currentStepC = 0;
        if(currentStepC < 0) currentStepC = 5;
        lastMotorDelayTime = millis();
        analogWrite(motorPin1, 254 * motorPinState[currentStepA]);
        analogWrite(motorPin2, 254 * motorPinState[currentStepB]);
        analogWrite(motorPin3, 254 * motorPinState[currentStepC]);
        }
        }
        // Copyright (C) 2015 ArduinoDeXXX All Rights Reserved.

        The purpose of the code is to drive the motor. In the tutorial, a 12 coil 14 pole motor is used. I may be mistaken but my understanding is that the code above should work with any 3-phase motor. I'm not sure why the pole/coil ratio would matter?

  • Filippo:

    Hi, thank you for this post.. Very instructive.
    Actually I’d have some question.. I want to use a BLDC motor to control an “arm” of a scientific ellipsometer. It’s an instrument that requires a very high precision, so I bought a motor with 360000 angular position. During calibration, I need to check every single position (each of the 360000 singularly). Do you have any advice for a possible implementation of your sketch so that it stops after a turn of 1/360000 and than it loops this process after 100 micro sec(acquisition time)?
    Thank you very much and… Forgive my English ahah

Leave a Reply

Or use the Forums ! If your comment is a question, please consider posting it to a matching section of our Electronics Forums. The forums allow for a more natural conversation flow, especially if multiple replies are required. Additionally, you'll be able to style your writing (bold font, italics etc.) and post images which can help with a good answer.