Sensorless BLDC motor control with Arduino – DIY ESC

DIY ESC with Arduino UNO

This topic shows how to build a sensorless brushless DC (BLDC) motor controller or simply an ESC (Electronic Speed Controller) with an Arduino UNO board.

There are two types of brushless DC motors: sensored and sensorless. Sensored BLDC motor has built-in 3 hall effect sensors, these sensors detect the rotor position of the BLDC motor. Controlling a sensored BLDC motor is easy since we know the rotor position like what was done in the project below:
Sensored brushless DC motor control with Arduino

The commutation of the sensored BLDC motor is done according to the hall effect sensors state.

Sensorless BLDC motor doesn’t have any sensor to detect its rotor position, its commutation is based on the BEMF (Back Electromotive Force) produced in the stator windings.

The main advantage of sensorless BLDC motor control is lower system cost and the main disadvantage is the motor must be moving at minimum rate to produce sufficient BEMF to be sensed.

How it works:
When the BLDC motor rotates, each winding (3 windings) generates BEMF opposes the main voltage. The 3 generated BEMF signals are 120° out of phase which is the same as the hall effect sensor signals. The figure below shows the relationship between the hall effect signals and the BEMF signals:

bldc hall sensor and bemf signals

As shown in the figure above, the BEMF signals are not synchronized with the hall effect sensor signals (phase shift of 30°). In every energizing sequence, two windings are energized (one connected to positive and the other to negative) and the third winding is left open (floating). The floating winding is used to detect the zero crossing, thus, the combination of all 3 zero cross over point are used to generate the energizing sequence. Totally we’ve 6 events:
Phase A zero crossing: from high to low and from low to high
Phase B zero crossing: from high to low and from low to high
Phase C zero crossing: from high to low and from low to high

How to detect the zero crossing event:
The easiest way to detect the zero crossing events is by using comparators. The comparator has 3 main terminals: 2 inputs (positive and negative) and an output. Comparator output is logic high if the positive voltage is greater than the negative voltage, and logic low if the positive voltage is lower than the negative voltage.
Basically 3 comparators are needed for this project, connections are done as shown in the figure below (example for phase B). Each phase requires a similar circuit.

bldc bemf signal detection

The virtual natural point is the same for all the 3 comparators, it is generated using 3 resistors. When the BEMF generated in the floating (open) winding crosses the zero point towards positive side, the comparator output makes a transition from low-to-high. When the BEMF generated in the floating winding crosses the zero point towards negative side, the comparator output makes a transition from high-to-low. By having three such comparator circuits, one on each of the phases gives three digital signals corresponding to the BEMF signal in the windings. The combination of these three signals is used to derive the commutation sequence.

Hardware Required:

  • Arduino UNO board
  • Brushless DC (BLDC) motor
  • 6 x 06N03LA N-type mosfet (or equivalent)  – datasheet
  • 3 x IR2104S (IR2104) gate driver IC  – datasheet
  • 6 x 33k ohm resistor
  • 3 x 10k ohm resistor
  • 6 x 100 ohm resistor
  • 3 x IN4148 diode
  • 3 x 10uF capacitor
  • 3 x 2.2uF capacitor
  • 2 x pushbutton
  • 12V source
  • Breadboard
  • Jumper wires

Sensorless BLDC motor control with Arduino circuit:
Project circuit schematic is shown below.

Arduino sensorless BLDC motor controller DIY ESC circuit


Note that all grounded terminals are connected together.

In the circuit there are 2 pushbuttons, one is used to increase BLDC motor speed and the 2nd one is used to decrease it.

The first three 33k (connected to motor phases) and the three 10k resistors are used as voltage dividers, because we can not supply the microcontroller with 12V, the other three 33k resistors generate the virtual natural point. The virtual natural point is connected to Arduino pin 6.

The Arduino UNO board is based on the ATmega328P microcontroller which has one analog comparator. The positive input of this comparator is on Arduino uno pin 6 (AIN0) and the negative input can be pin 7 (AIN1), A0 (ADC0), A1 (ADC1), A2 (ADC2), A3 (ADC3), A4 (ADC4) or A5 (ADC5). So I connected the virtual natural point to the positive pin of the analog comparator (pin 6), phase A BEMF to pin 7 (AIN1), phase B BEMF to pin A2 and phase C BEMF to pin A3. Each time the comparator compares the virtual point with the BEMF of one phase (this is done in the software). This minimizes the hardware needed and simplifies the circuit.

The IR2104S chips are used to control high side and low side mosfets of each phase. The switching between the high side and the low side is done according to the control lines IN and SD. The figure below shows input and output timing diagram:

ir2104s timing

The SD lines of the three IR2104S are connected to pins 11, 10 and 9 respectively for phase A, phase B and phase C. The Arduino UNO can generate PWM signals on that pins where only high side mosfets are PWMed.

Sensorless BLDC motor control with Arduino code:
The code below does not use any BLDC motor library.

As mentioned above, Arduino pins 9, 10 and 11 can generate PWM signals where pin 9 and pin 10 are related with Timer1 module (OC1A and OC1B) and pin 11 is related with Timer2 module (OC2A). Both Timer modules are configured to generate a PWM signal with a frequency of about 31KHz and a resolution of 8 bits. The duty cycles of the PWM signals are updated when a pushbutton is pressed (speed up or speed down) by writing to their registers (OCR1A, OCR1B and OCR2A).

The analog comparator compares the positive input AIN0 (Arduino pin 6) with the negative input which can be AIN1 (pin 7), ADC2 (pin A2) or ADC3 (pin A3). When the positive pin voltage is higher than the negative pin voltage, the output of the analog comparator ACO is set, and when the positive pin voltage is lower than the negative pin voltage, ACO is cleared.
In this project I used the analog comparator interrupt and I used its interrupt on rising (transition from low to high) and interrupt on falling (transition from high to low), this makes the zero crossing events interrupt the microcontroller.

To fully understand the code, please read the ATmega328 datasheet!

Sensorless BLDC motor control with Arduino video:
The video below shows how project is working.

Microchip AN970 document


      1. In the video there is only 5 capacitors, but the circuit shows 6 capacitors and the arduino uno default timer2 frequency is ~61 khz, but you explained and coded default prescale, can u please provide the full report with the virtual ground resistor design. Please help me i am on my major project..

        1. In my circuit it should be 7 capacitors (the 6 capacitors shown in the schematic diagram and one between (+) and (-) of the 12V source). The biggest capacitor in the video is for 12V source. It could be done just as shown in the schematic diagram.
          The frequency of Timer2 PWM signal is about 31KHz because when it is ON its register TCCR2A = 0x81 which means WGM20 bit = 1 (PWM phase correct mode) and therefore: freq = 16000000/(N*510) = 31372Hz where N is the prescaler = 1 (TCCR2A = 1), you can check it with a real oscilloscope or even by Proteus simulation. All data are provided in the Atmega328P datasheet.

  1. Thank you, and what you used as power source Lipo battery or power supply. And the design of virual ground and back emf

    1. I used 12V power supply for both the Arduino and the 3-phase bridge, a battery (Li-ion, Li-po ..) can be used for powering both of them.

      1. I also used 12v power supply, but when i see the voltage across power supply dropping to 5v or lower when turning on motor and motor vibrates and try to turn but not rotating. Also tested with lipo battery but motor condition is same and i am using STP105N3LL mosfet. Could you please verify the program and also the circuit diagram,

    1. It’s A2212 1000KV, it’s well used in quadcopters, even PC cd-rom (dvd-rom) sensorless BLDC motor (spindle motor) works fine.

    1. It’s the analog comparator interrupt service routine (ISR), the analog comparator is used to detect zero crossing events and at any event the analog comparator interrupts the microcontroller in order to update the commutation state.

      1. Thanks for the quick reply! I understand that this is an interrupt service routine and that is updating commutation state. I just do not understand why “i” is decremented by 1 in “for” loop when ACSR.ACO is “1” or “0” and why loop is counting to 10.

        I suppose that these “if” statements make decisions regarding the rising or falling period of BEMF, because ACSR.ACO is in these cases going from 1 to 0 (rising period of bemf) and from 0 to 1 (falling period of bemf), but can not figure out why “i” is decremented by 1 and why is counting to 10.

  2. Hi! I’m having issues understanding the commutation code:
    1 – ex:
    void BH_AL(){
    PORTB = 0x08; // 0000 1000 >> PB3 >> PIN 11 ON
    PORTD &= ~0x28; // 0010 1000 CLEAR >> PD5, PD3 >> PIN 5 OFF, PIN 3 OFF
    PORTD |= 0x10; // 0001 0000 SET >> PD4 ON >> PIN 4 ON
    TCCR2A = 0; // Turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
    TCCR1A = 0x21; // 0010 0001 >> CLEAR OC1B ON COMPARE, PWM PHASE CORRECT 8 BIT >> PB2 >> PIN 10

    Why did we set pin PB3 when we clear it ?

    I am trying to convert this code to run on my hardware, the gate drivers have separate input for High and Low side FETs, I think I shall be able to do that with inverted output PWMs, any comments here ?

    1. See the post below, it’s a little bit different, I used IR2101 instead of IR2104 gate driver. The IR2101 has separated gate control inputs for high side and low side mosfets.

    1. You can try it by your self but doing that may cause some problems to the analog comparator because it’s used for zero crossing detection and the analog comparator share the same multiplexer with the analog-to-digital converter (ADC).

  3. It can work your design with the following engine I have .. N5065 1820W 320KV Outrunner Brushless Motor For Electric Skate Board DIY Kit New

  4. Hello. Nice work thank you! Do you think, is it possible to check that engine is started after start procedure? If engine will not start correctly or its blocked. I tried to check bemf but when engine is fixed, the comparator goes crazy…

    1. As you say, when stationary, there’s no BEMF signal at all, and since there’s no (defined) hysteresis on the comparator it’ll just be triggering on noise. The traditional means of detecting operation is a stall counter – increment a variable every millisecond or so using a timer interrupt, and resetting every time a correctly sequential commutation is detected i.e. rotation rather than oscillation. If there’s no correct sequence in say half a second then disable – or start a restart routine.

  5. Hello, very good job.
    It’s works perfect, i try it in my project and need to make some changes( revers, startup by button, current restart(when its high, and higher speed by make the pwm is higher) and therer some problems…..
    For example- try to make the revers by button- wrote some lines of code to stup the motor and use bldc move in another way- but the motor after perfect work stops after i press the button-and start work crazy……
    Can you help me with code( can and want to simmelar pay for it)
    can you connect with me by e-mail(for example)
    Best regards, Igor

  6. Good job! But if i use a power supply higher than 12v, what resistor should i use for the virtual point and voltage divider? If i dont make any change, can i damage my microcontroller?

    1. Of course you may damage your Arduino microcontroller. Make sure that the input voltage doesn’t exceed 5V (for the ATmega328P)

      1. congratulations for your project, I have seen this same circuit all the same in another project, the only difference is the output uses the N-type mosfet IRF840 and fed with 400 volts, the voltage divider of the BFEM the resistances are of the same value as samples in the circuit, nomas that changes to 5 watts, my question is if there is higher bfem with 400 volts the divider has the same resistance values but at 5 watts, but the working voltage is 400 volts there is no risk of damaging the arduino .
        How to use this circuit that you propose with 400 volts with the IRF840, and resistance values that must be put in the divider, thanks for your contributions

        1. Increasing the voltage without changing voltage divider resistors may damage the Arduino. Project the circuit diagram is for 12V BLDC motor (just use voltage divider equation).
          The mosfets 06N03LA also doesn’t work with 400V, you may find that in its datasheet.

          1. thanks for your comments, if the 06N03LA is for 25v Vds, for the irf840 it is 8 A, 500 Volts would be to calculate the voltage of the divider and the value of the resistors, I need to know the CFEM, thanks again, if you have more data to be able to operate it with irf840 at 400 volts, I thank you in advance

  7. We have 3 capasitors (values are:10microFarad) and we finished the circut.But us second condenser(in the middle ) blowed up 2 times and we don’t know main problem.Us energy source is city network and 12VDC converter.Can you help us ? Thanks…i

    1. a copper strip which passes from the 12-volt Arduino area into
      the motor area and it is felt that there is the potential for a back-EMF voltage spike to be fed back along that copper track and damage the IR2104 chip or even the Arduino board itself. It is suggested that the introduction of a fast Schottky diode in those links would block that possibility.

  8. i am using this ESC circuit to run a compressor, its working fine but the flow rate is not up to the mark so i want to increase the speed of the compressor, to do so should i try a higher voltage supply or can the speed increased by the code itself? if so then please help me with the code to increase the speed of the compressor.

    1. The is no thing to with the code to increase the maximum speed of your motor, the code give the maximum speed when the PWM duty cycle = 255.
      Increasing the voltage may increase the speed (you should use your motor nominal voltage), but be careful, with this circuit diagram you shouldn’t exceed 20V, unless you change the back emf resistors.

  9. Circuit is working but speed is less how can I get a maximum speed is it possible to increase pwm max duty above the 255
    Instead of 06N03LA mosfet I am usingP55NFO6 mosfet is it responsible for low speed

    1. The duty cycle of the PWM signal may be vary from 0 to 100%, so the motor reaches its maximum speed when the duty cycle = 100% which is represented in the code by 255.
      The maximum speed depends on type of motor (max speed, voltage …).
      The P55NF06 should work without any problem.

          1. void AH_BL(){
            PORTB = 0x04;
            PORTD &= ~0x18;
            PORTD |= 0x20;
            TCCR1A = 0; // Turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
            TCCR2A = 0x81; //
            void AH_CL(){
            PORTB = 0x02;
            PORTD &= ~0x18;
            PORTD |= 0x20;
            TCCR1A = 0; // Turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
            TCCR2A = 0x81; //

            can you please explain the logic behind the above code.

  10. I have used
    1) IRF3205 n-channel MOSFET instead of 06N03LA N-type mosfet
    2) IR2102 gate driver IC instead of IR2104S (IR2104) gate driver IC
    I simluate the schematic in proteus using the above mentioned components.
    I don’t get any error message.
    At the same time I don’t get any outpput.BLDC motor refuse to rotate.
    Is there any problem of using differnet MOSFETs and ICs ?PLease help me to get my output.This is my final year project.
    Thanks in advance…

    1. 1) Although it may work, but the IRF3205 is not a good choice for this application (slow).
      2) You can’t use the IR2102 directly without doing some modifications to the application code (if you want to use it you’ve to make some modifications to the code, read the datasheet of the two devices!).
      I don’t know if you can simulate this application using Proteus, it’s better to do it in real hardware circuit.

      1. I have comopleted this project using the components
        Driver chip – IR2104S
        N-Channel MOSFET – P55NF06
        BLDC motor is as same as your’s

        The problem is the motor doesn’t start automaticaly.
        I switched on the power supply and rotate manually by fingers with full speed settings using speed up pish button.After only my motor rotates.
        There is no prblem with the speed control.But how can I start the motor automatically.What is the problem behind this?
        please help me to find a solution for this.
        Thanks in advance.

  11. would you please reply to my previous question…I am struggling with it for more than a week…
    Please help me to complete my project…..

    1. I think you’ve to make some modifications to motor starting code:

      while(i > 100) {


      just do some experiments!

  12. Sir, while uploading the program,it shows some undeclared identifiers, they are
    – bldc_move
    – AH_BL
    – AH_CL
    – BH_AL
    – BH_CL

    This is a part of my academic project……please help.
    Thanks in advance.

  13. Hello. Great work.
    Question, and request I Got a Samsung 3 phase 36 pol BLCD motor.
    Would like to set the speed to 3000RPM. And display it on 4 digit display( working onit), by counting the Zero crossing. Can U please help me by the Zero Counting with i can work and later display?
    Kindly Regards

    1. This is the project that you mention the samgsun 36 poles engine, the output IRF840 mosfet is used, powered by 400 volts, the whole scheme is the same as the one shown here, also the code is the same, the difference is only in the output of the mosfet that uses IRF840 alimenentado with 400 volts, and the divider of voltage of the CFME the resistance equal value nomas that are of 5 watts, and this is what it was consulting if it will have the problem of greater contrainduccion in the divider and damage the arduino , I’m going to have to perform tests with 12 volts, small motor, change the output mosfet with a higher voltage and larger motor, and change the value of the voltage divider, since the samsung 36 poles engine project is all same as the one that shows simple projects, as I have mentioned the only changes that are the mosfet, higher voltage, and higher watts in the CFME divider resistors, there is someone who wants to comment or suggest something, I do not know what damage the arduino, or the best one,
      Thanks to Simple Projects, for their orientations and illustrative videos

  14. Hello,
    We are trying the same circuit but we are using :
    1) IRF540 MOSFET’s
    Rest the entire circuit is same as yours. But the issue is, the motor runs only once and then, starts vibrating. Even when we press the switches, the sound of vibration is changing but motor doesn’t move. Any comments, what may be wrong?

  15. Its not enough. A shkotty diod need to beplaced in the Back FM way, otherwise it eill damage the Half wave drive, and the Arduido to. .. I working on another circuit feed with Sinus wave form generated by Arduino. The earlier mentiond code dos not hold the Mofet oppen, insted its gives out small peek’s.. +. The waweformis decrease as the Half wave is operats,and changing electric phase.

  16. Maandish Shing
    Its tray’s to rotat in the wrong direction. Because of the Fix linear wave generation Its just workingin one direction. There sould be a code, if no BEMF detekted in a among of time, contoler should stop eweryting, and restart “Start up” process.

  17. Alex.

    I readed the projekt. Ther are some fault in tha circuit. They have “repaired it”, because of the ~380v BEMF and This is the reason why the Capacitor is blowed up as in one of the post mentioned earlier. Still the Wave form is not efficient/sufficient for a High Voltage Unit. This code can’t hold the the Mosfet open. Insted its makes a PMW( many small peek’s) output.. witch is not efficient for this type of motor, es it is a induction motor.. elekto magnetik fiel is indicated.. and the magnet on the rotor is respondin of the EMF( pull push) .

    1. Wunsch Fee, thank you very much for the information, I will review the data, if you have something to help us in that project, some novelty, some circuit that makes the motor samsug of 36 poles to 400 volts work, I thank you for informing us, thanks for share

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.