# BLDC Motor Controller Using Arduino

**URL:** <https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372>\
**Category:** Motors, Mechanics, Power and CNC\
**Created:** [November 4, 2014, 6:45am UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372 "2014-11-04T06:45:40Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [November 4, 2014, 6:45am UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/1 "2014-11-04T06:45:40Z")

</div>

I wrote the below Arduino uno code to control a sensored bldc motor using the attached schematic diagram circuit.  
The controller can run the motor in the tow rotation directions(cw & ccw) and the speed can be controlled using a potentiometer connected to A0. In the code there are tow functions fwd() and bwd() each function is for the rotation direction selected by switches on pins 10 & 11, the switch on pin 12 is to stop the motor.  
Project Blog: [http://elecnote.blogspot.com](http://elecnote.blogspot.com)

```plaintext
#include <PWM.h>
int32_t frequency = 20000; //pwm frequency in Hz
unsigned int n = 0, timer2_initial_value, s = 0;
void setup(){
  InitTimersSafe();
  bool success = SetPinFrequencySafe(9, frequency);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(0, INPUT);
  pinMode(1, INPUT);
  pinMode(2, INPUT);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);
  // initialize timer2 interrupt for adc reading 
  noInterrupts();           // disable all interrupts
  TCCR2A = 0;
  TCCR2B = 0;
  timer2_initial_value = 0;  
  TCNT2 = timer2_initial_value;   // preload timer
  TCCR2B |= (1 << CS22) |(1 << CS21) | (1 << CS20); // 1024 prescaler 
  TIMSK2 |= (1 << TOIE2);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}
 ISR(TIMER2_OVF_vect)        // interrupt service routine 
 {
  TCNT2 = timer2_initial_value;   // preload timer
  n++;
  if (n>20){
    n = 0;
   if (s != analogRead(A0)){
   s = analogRead(A0); 
  pwmWrite(9,s/4);}}
 }
int fwd(){
   while(1){
if (digitalRead(2)==1){
    if (digitalRead(1)==0){
      if (digitalRead(0)==1){
        digitalWrite(8,0);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,1);digitalWrite(4,1);digitalWrite(3,0);}
      else {
        digitalWrite(8,1);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,1);digitalWrite(4,0);digitalWrite(3,0);}}
        
     if (digitalRead(1)==1){
      if (digitalRead(0)==0){
        digitalWrite(8,1);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,1);}}}
        
   
 if (digitalRead(2)==0){
    if (digitalRead(1)==1){
      if (digitalRead(0)==0){
        digitalWrite(8,0);digitalWrite(7,0);digitalWrite(6,1);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,1);}
      else {
        digitalWrite(8,0);digitalWrite(7,1);digitalWrite(6,1);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,0);}}
        
     if (digitalRead(1)==0){
      if (digitalRead(0)==1){
        digitalWrite(8,0);digitalWrite(7,1);digitalWrite(6,0);
        digitalWrite(5,0);digitalWrite(4,1);digitalWrite(3,0);}}}
   if (digitalRead(12)==0) break;}
}
 int bwd(){
   while(1){
if (digitalRead(2)==1){
    if (digitalRead(1)==0){
      if (digitalRead(0)==1){
        digitalWrite(8,0);digitalWrite(7,0);digitalWrite(6,1);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,1);}
      else {
        digitalWrite(8,0);digitalWrite(7,1);digitalWrite(6,1);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,0);}}
        
     if (digitalRead(1)==1){
      if (digitalRead(0)==0){
        digitalWrite(8,0);digitalWrite(7,1);digitalWrite(6,0);
        digitalWrite(5,0);digitalWrite(4,1);digitalWrite(3,0);}}}
        
   
 if (digitalRead(2)==0){
    if (digitalRead(1)==1){
      if (digitalRead(0)==0){
        digitalWrite(8,0);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,1);digitalWrite(4,1);digitalWrite(3,0);}
      else {
        digitalWrite(8,1);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,1);digitalWrite(4,0);digitalWrite(3,0);}}
        
     if (digitalRead(1)==0){
      if (digitalRead(0)==1){
        digitalWrite(8,1);digitalWrite(7,0);digitalWrite(6,0);
        digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,1);}}}
   if (digitalRead(12)==0) break;}
}
     
void loop(){
  digitalWrite(13, LOW);
  pwmWrite(9,s);
  digitalWrite(8,0);digitalWrite(7,0);digitalWrite(6,0);
  digitalWrite(5,0);digitalWrite(4,0);digitalWrite(3,0);
  if (digitalRead(10)==0) {digitalWrite(13, HIGH);bwd();}
  if (digitalRead(11)==0) {digitalWrite(13, HIGH);fwd();}
}

```

This video shows the working:

[![]( " - YouTube") ](https://www.youtube.com/watch?v=O6e36vgL40k)

 ![ARDUINO BLDC MOTOR CIRCUIT.png](https://europe1.discourse-cdn.com/arduino/original/4X/1/2/f/12f1d7a67ba4af7f18d2ae3390027fab7b994db5.png)

---

<div class="post-metadata">

**Author:** ![johnwasser](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/johnwasser/32/214270_2.png) [@johnwasser](https://forum.arduino.cc/u/johnwasser)\
**Post date:** [November 4, 2014, 1:21pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/2 "2014-11-04T13:21:48Z")

</div>

Since D0 and D1 are the Serial pins on an Arduino UNO it is best to leave them unused if possible. I would move the buttons to A1-A3 (which can be used as digital pins) and slide the other connections up two pins. This will allow Serial.print() to be used for debugging.

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [November 4, 2014, 7:54pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/3 "2014-11-04T19:54:04Z")

</div>

Yes it is better to let pins 0 & 1 unused and since pin9 is for pwm signal I can change the pins 0,1,2 to A1,A2,A3 that pins are feedback and comes from hall sensors.  
Thanks  
johnwasser

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [November 4, 2014, 8:29pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/4 "2014-11-04T20:29:33Z")

</div>

Those unwieldy fwd() bwd() functions need some attention... Table look-up is the  
way to perform this sort of thing - combine the Hall inputs into a 3-bit number,  
use that to index an array to return a 6-bit output, which is then split out to the  
outputs.

Most 3-phase bridges don't have a separate PWM input, this is best done by  
encoding the PWM into the lookup-table and using a pin-change interrupt to drive the outputs, so 4 bits to the table-lookup (3 hall bits and PWM state). Thus a pin-change interrupt  
on pin 9 would be needed. To keep timings tight direct-port manipulation is  
usually required (write all 6 outputs in one instruction, rather than 25us for  
6 calls to digitalWrite).

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [November 5, 2014, 5:58pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/5 "2014-11-05T17:58:48Z")

</div>

> MarkT:  
> Those unwieldy fwd() bwd() functions need some attention... Table look-up is the  
> way to perform this sort of thing - combine the Hall inputs into a 3-bit number,  
> use that to index an array to return a 6-bit output, which is then split out to the  
> outputs.
> 
> Most 3-phase bridges don't have a separate PWM input, this is best done by  
> encoding the PWM into the lookup-table and using a pin-change interrupt to drive the outputs, so 4 bits to the table-lookup (3 hall bits and PWM state). Thus a pin-change interrupt  
> on pin 9 would be needed. To keep timings tight direct-port manipulation is  
> usually required (write all 6 outputs in one instruction, rather than 25us for  
> 6 calls to digitalWrite).

Thanks mr MarkT  
For the pwm inside the bridge is as shown in the attached picture.  
How can I write all the 6 outputs in just one instruction?

![pwm.png](https://europe1.discourse-cdn.com/arduino/original/4X/e/2/c/e2cf91f216a194b84473f083deaa8513f7f1f94a.png)

---

<div class="post-metadata">

**Author:** ![system](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/system/32/1140315_2.png) [@system](https://forum.arduino.cc/u/system)\
**Post date:** [January 5, 2015, 6:07am UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/6 "2015-01-05T06:07:05Z")

</div>

> spokba:  
> Thanks mr MarkT  
> For the pwm inside the bridge is as shown in the attached picture.  
> How can I write all the 6 outputs in just one instruction?

i interested to your logic construction. Its nice to use only 1 PWM pin, And execuse me Sir, i want to ask, so the 6 output from the AND logic straight go to N channel mosfet?

---

<div class="post-metadata">

**Author:** ![MorganS](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/morgans/32/218718_2.png) [@MorganS](https://forum.arduino.cc/u/MorganS)\
**Post date:** [January 5, 2015, 10:45pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/7 "2015-01-05T22:45:28Z")

</div>

To write pins simultaneously, make sure they are all on the same "port" from the AVR chip.

[Arduino Pin Map](http://arduino.cc/en/Hacking/PinMapping168)

See the pin names next to the chip? "PD2" "PD3"? That says those pins are in port D. You can write a byte directly to the port to change all 8 pins at exactly the same instant. With a bit of care, you can do this for 6 pins in a way that doesn't disturb the other pins on the port, such as the serial pins on PD0 and PD1.

digitalWrite() is kind of slow but it is portable between different Arduinos. Hacking the ports directly is not portable, although equivalents exist on all Arduinos, so just make sure you write the code with pin and port definitions at the top so you only need to change it in one place in your code.

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [February 2, 2015, 1:16pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/8 "2015-02-02T13:16:21Z")

</div>

The bridge circuit is shown on the schematic below:  
More details about this project are on:

[http://elecnote.blogspot.com](http://elecnote.blogspot.com)

 ![Three phase bldc motor bridge.png](https://europe1.discourse-cdn.com/arduino/original/4X/b/0/0/b00885964e8ab7bdfe3450a73d351cd34c84d150.png)

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [February 2, 2015, 6:09pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/9 "2015-02-02T18:09:49Z")

</div>

> spokba:  
> Thanks mr MarkT  
> For the pwm inside the bridge is as shown in the attached picture.  
> How can I write all the 6 outputs in just one instruction?

That circuit with 6 and gates is clearly flawed - you don't PWM every pin in the same  
direction simultaneously!!!

I said use the PWM pin to generate a pin change interrupt, and do the work  
in the pin-change interrupt routine.

[ BTW If you know you'll only be PWMing the high side devices, say, then you  
could use a 3-and-gate version of that circuit ]

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [February 2, 2015, 8:06pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/10 "2015-02-02T20:06:17Z")

</div>

> MarkT:  
> That circuit with 6 and gates is clearly flawed - you don't PWM every pin in the same  
> direction simultaneously!!!
> 
> I said use the PWM pin to generate a pin change interrupt, and do the work  
> in the pin-change interrupt routine.
> 
> [ BTW If you know you'll only be PWMing the high side devices, say, then you  
> could use a 3-and-gate version of that circuit ]

It is better to have six pwm outputs, and ATmega328 can do that if we use all the 3 timers, we may need at least 1 timer which means we can not generate 6 pwm signals. So we have to generate just one pwm signal and route this signal to the active switches with the help of the AND gates, each gate controls one switch.

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [February 3, 2015, 5:51pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/11 "2015-02-03T17:51:54Z")

</div>

Note that you can only use independent (unsynchronized) PWM outputs if only PWMing  
one device at a time, which pretty much forces trapezoidal drive and PWMing only 3  
devices in total (all the highs or all the lows).

It is possible to synchronise all 3 timers with care (set them all in an equivalent mode,  
disable interrupts and write the count registers with experimentally derived values, re-enble  
interrupts). Then you can have 6 synchronised PWM signals (allowing sinusoidal drive  
for instance, or fast-decay mode for trapezoidal).

---

<div class="post-metadata">

**Author:** ![rmetzner49](https://avatars.discourse-cdn.com/v4/letter/r/bb73d2/32.png) [@rmetzner49](https://forum.arduino.cc/u/rmetzner49)\
**Post date:** [February 4, 2015, 6:56am UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/12 "2015-02-04T06:56:26Z")

</div>

If it's not already too late, may I offer an Arduino with the 32U4 on it (leonardo, etc.) might be better suited to what you want to accomplish.

I think you'll find the timers are designed to do 3-phase control and I remember there being an app note on the Atmel site for doing this. As long as (as MarkT suggested) you will be doing direct register access, do it on a CPU with a couple more bells and whistles.

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [February 4, 2015, 12:55pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/13 "2015-02-04T12:55:03Z")

</div>

The leonardo seems to have 3 PWM driven by timer1 and 3 PWM driven by timer4, which  
might be a bit more logical for 3phase, but the pin out is pretty random and the two sets  
clash...

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [February 5, 2015, 1:21pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/14 "2015-02-05T13:21:17Z")

</div>

For this project it is easier to work with microchip PIC18FXX31 series it has 6 pwm outputs and with MikroC compiler you just write pwmx\_start(); where x defines the output number and goes from 1 to 6.

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [February 5, 2015, 1:58pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/15 "2015-02-05T13:58:18Z")

</div>

I've generated trapezoidal signals before with one PWM pin and no external hardware -  
I just use the PWM pin to trigger a pin-change interrupt and then drive the bridge from  
the ISR - works fine!

With synchronized AVR timers I've generated sinusoidal 3-phase PWM - use one of the timer's  
overflow ISRs to update the 3 OCR registers by copying from global variables - again  
does the job, drives induction motor nicely 🙂

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [February 6, 2015, 7:25am UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/16 "2015-02-06T07:25:35Z")

</div>

If it is a pure sinusoidal and has 120° between phases I think it will run it very well. Mr MarkT do you have any idea about controlling sensorless bldc motor and zero detection technique?

---

<div class="post-metadata">

**Author:** ![spokba](https://avatars.discourse-cdn.com/v4/letter/s/9d8465/32.png) [@spokba](https://forum.arduino.cc/u/spokba)\
**Post date:** [February 11, 2015, 9:50pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/17 "2015-02-11T21:50:02Z")

</div>

I built the same controller but with microchip PIC16F877A.

[![]( " - YouTube") ](https://www.youtube.com/watch?v=Wa6hp512Fmk)

---

<div class="post-metadata">

**Author:** ![gurgel](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gurgel/32/1174388_2.png) [@gurgel](https://forum.arduino.cc/u/gurgel)\
**Post date:** [March 12, 2016, 9:10pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/18 "2016-03-12T21:10:04Z")

</div>

good morning ! we need to make a motor control 3 phase, AC, 10HP, batery bank is 96VDC, a connected potentiometer at Arduino, send signal to the 6 (six) outputs, the pulses have to be phased to excite the drivers, and then the signs go to the 6 IGBT, and then to the motor 3 phase AC motor, in the shaft is installed a "bicycle brake disc" with the holes measured by a TCST2103, this signal TCST goes to the arduino to make better the funcional set, I need help to function, it is to be used in large electric car, ok

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [March 14, 2016, 12:23pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/19 "2016-03-14T12:23:03Z")

</div>

So you need 3-phase bridge, current sensors on two of the phases (the third would be redundant of  
course), encoder to measure shaft angle (preferably absolute), and a lot of experience with this  
sort of motor control.

I think what you call TCST is an optical encoder?

This is a big project and with those power levels safety and probably legal compliance are your prime  
concerns from the beginning.

Start small.

---

<div class="post-metadata">

**Author:** ![MarkT](https://avatars.discourse-cdn.com/v4/letter/m/c89c15/32.png) [@MarkT](https://forum.arduino.cc/u/MarkT)\
**Post date:** [March 14, 2016, 12:24pm UTC](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372/20 "2016-03-14T12:24:44Z")

</div>

BTW you have an AC servo motor there, if using sinusoidal drive, a BLDC is basically the same  
hardware with trapezoidal drive rather than sinusoidal, and hall-sensors for commutation.

I note you've started a new thread on this (this thread wasn't the right place for a whole  
new project), here:  
[https://forum.arduino.cc/index.php?topic=385999.0](https://forum.arduino.cc/index.php?topic=385999.0)

[Next page](https://forum.arduino.cc/t/bldc-motor-controller-using-arduino/267372.md?page=2)
