Monday, September 30, 2013

A simple brushless sensorless motor driver for AVR Atmega

Brushless electric motor (BLDC motors) are synchronous motors that are powered by a DC electric source via an integrated inverter/switching power supply, which produces an AC electric signal to drive the motor.

For an introduction to BLDC motors, please look at my sensored motor driver post, here:

For this project, I've implemented a simple brushless sensoreless motor driver for AVR Atmega. The code i propose it's not perfect, and can be improved, but for the needs i had it works.

The motor can be controlled in speed and direction (clockwise and anti-clockwise).

This project use open loop startup and bemf zero crossing detection method with ADC.
Speed change can be done only when motor is not running, ADC is used during spinning phase in zc detection so it can not be used during the motor spinning, but digital speed changing can be implemented.
ZC threshold current should be defined by user depending on the motor type.

User has to setup the port used to read the the bemf current. Also the timer interrupt and prescaler should be setup for different running frequency.
The running step for the motor are defined as default, anyway user can change it to fit any motor.

A sample main routine is provided to help you understand how the library works.

The same test board of sensored library post is used, reported here the schamatics, for further info look at the sensored library post.

Setup parameters are contained in bldcsensorless.h

This library was developed on Eclipse, built with avr-gcc on Atmega8 @ 8MHz.

  • read risk disclaimer
  • excuse my bad english


  1. I was waiting for it. Great. But I don't understand smt:

    "User has to setup the port used to read the hall sensor, <...>"

    Isn't this sensorless?

    1. thank you for you feedback.
      yes, it is for sensorless motors, i made i mistake writing description here, now i've corrected this post :)

  2. Hallo! Nice job, i like your work on those bldc's with atmega8. In your two projects, witch one had the most torque on the motor: the sensored or the sensorless one? I'm interested in making a diy rc hovercraft from scraps and junked pc components for a charity purpose. Thank you!

    1. i've not measured torque force, for shure the sensored has more force on startup stage, cause input are driven by hall sensor.

  3. Hi again Davide, i'm sorry for putting noob questions but i'm a beginner in programming avr (i'm still learning the arduino), i tried to make a hex file from your Eclipse project but i couldn't find a way to do so. I also tried in Eclipse and Avr Studio but with no result. Can you please help me with that? What do i have to do to turn your project into a hex file for burning it to the atmega8? P.S.- the programmer is not an issue, i can build it in no time. Thnx

    1. No problem, just google for "Eclipse AVR tutorial" you will find some website that teach you how to build and hex file for ATmega with Eclipse. I suggest you, at first, to try building and loading a simple project, like a blinking led, then try with this one.

  4. Thanks for your effort.
    I saw the schematic and the source code for sensorless.
    When I check the source code and the schematic, I found some difference.
    For example
    To change the direction, you use the PC5 port. But the PC5 connect to on the PD0 schematic. So I'm confusing.
    I want to know what the truth is. And I want to get the schematic of the latest version. Can you send it to me?
    Have a nice day!
    Regards HYYoo

    1. Thank you for feedback, I've never noticed i've posted the wrong schematics version.
      The one you can find now in this post has correct wiring.

    2. Thank you Davide.
      Your source code is simple and excellent. So I can understand the concept for the BLDC. Also I can know how to implement it.
      As your code, for the change a speed and a direction, first stop a motor then start it. Is right? I think that the speed is changed while spin. So I just add some part as follow. is it possible?
      if(direction != directionold) { //direction changed
      potspeed = adc_read(POTSPEED_CHANNEL); //read filtered pot speed
      if(potspeed != potspeedold) {
      potspeedold = potspeed;
      uint16_t potspeedn = (long)(potspeed - 0) * (long)(100 - 0) / (long)(1024 - 0) + 0;

      Thank you!

      Regards HYYoo.

    3. thank you.
      The sensorless version of my code check the backemf by ADC continously (BLDCSENSORLESS_ADCREADSEL), ADC is always "busy". that's the reason why i prefer to read speed changes while not spinning.
      You could free the RX pin an control the speed by uart.
      You also could use other tecnique to read the backemf. Some time ago I was implementing a version that use cumulative current check, and make less use of ADC, but I've never continue on that project. I suggest you to give a try to the Takao code from, or the wii-esc project code.

  5. hi
    i m implementing ur code but i need some clarification about these points
    BLDCSENSORLESS_ZCERRORS : what does it refer to
    how in code i define zero cross threshold
    bldcsensorless_setspeed(100) :what is the unit for speed
    thanks for ur help

    1. Hello,
      BLDCSENSORLESS_ZCERRORS it is used to check how many zc incorrect position (errors), occours, if too many occours, then a startup loop is launched.
      Unit for speed, is 0 to 100.

  6. thanks for ur reply
    i m trying it now with cd rom motor of nidek
    the start up commutations start but the repeat without entering running phase
    what is the problem
    thanks again for feed back

    1. Check your hardware with another firmware, like wii-esc, so you will be shure that hardware is ok, and then you can debug the firmware.

  7. hi again
    how do i define zc threshold ? i mean if it is estimated tobe 4 volts >>how do i write 4 volts in ur code"i see value of 150 and i dont know what it refers to "volts - millivolts....???

    1. My threshold is a raw value, not a voltage converted value.

  8. //check zc depending on actual polarity
    if ((!bldcsensorless_zcpolarity && currentbemf>BLDCSENSORLESS_ZCTHRESHOLD) || (bldcsensorless_zcpolarity && currentbemf>>>>?????
    this part is vague to me

    1. That's where the zero crossings (zc) is checked.
      Keep in mind that i use adc to check this, a better approach should use the analog comparator. As soon as i will have time to implement that, i will release an analog comparator version of this project.

  9. hi
    which wii-esc is suitable for ur hardware scheme?

    1. Check the wii-esc circuit, i suppose you just have to change ports setup.

  10. hi
    here what i did till now
    1 i built ur hardware circuit
    2 i flashed the mcu with ur code"didnt change it coz i dont know what variables to change regarding zcthreshold and the port used to read bemf current "

    1. Again, check the harware whit another firmware, then you can debug the software.
      Mine is a farily basic driver, It does not implement duty cycle, and do not use analog comparator. So if you need performance, i suggest you to switch to another one. Takao Shimizu on is building a simple but very good driver, check the "BLDC controller" discussion on the To read more about bldcmotors, is the place you have to be.
      Also a good starting point will be the AVR444 Atmel Application Note.

  11. This comment has been removed by the author.

    1. hi
      I have hdd motor ı want to drive without any feedback when delay about 30ms it turn but when delay is too low it produces "squealing sound" but does not turn can you suggest me any solution
      thanks for your help

    2. It could be because you are trying to move it too fast. If you are using this driver keep in mind that this is not a PWM driver. Also it use ADC reading to read back EMF, there are faster approach that use ADC comparator, and faster ADC conversion means faster spin.

  12. To adjust the speed, I understand you can bypass the switches (in order to avoid the losses), and instead do it by adjusting the VBus going to the motor. The switches would only be used for commutation.

    But what if you want to control speed via the PWM duty cycle.. does it matter which switch you pulse (i.e. high side, low side, both (complimentary))?

    Also, there's unipolar vs bipolar (1-4 quadrants) that I'm not sure how what this means in practical terms. From what I've read, when doing unipolar, the rotation direction is determined by the commutation sequence, but in bipolar, the direction is based on if the duty cycle is less than or greater than 50%?! But how (or why) does this actually work?

    Also, can you recommend where to buy a driver board? I'm not too handy with a soldering iron, but would love to hook up a bldc motor (no sensors) to my atmega1280 kit. I'd like to try 6-step trapezoidal commutation and maybe someday sinusoidal/foc with a beefier processor!

    1. If you mean controlling the speed control of the driver by PWM, you need to implement a PWM reader using the interrupt input PIN as example. There are a few post on avrfreaks to discuss about this.
      For the "how to drive", and "how it works", The unipolar / bipolar commutation sequence it is a PWM techinique of controlling the motor. This (my driver), is not PWM.
      The cheapest compete boards that comes to me, are ESC 30A drivers commonly used for RC. You can buy any SimonK compatible ESC board, then open it, make just some solder to expose the ISP programming wiring, and use the internal ATmega8 micro. Or you can buy somthing like the hip4086 and use just some mosfet to build an external driver to use with your ATmega1280.
      Hope this helps.

    2. Awesome, thanks! I was thinking you were using pwm because the bldcsensorless.c source had a comment about fast pwm mode... but looks like that's just to setup the timer. So are you controlling the speed by adjusting the time (ICR1) between when a zero crossing occurs and when the next commutation is applied?

    3. Yep. The speed control it's "ICR1 = bldcsensorless_speed;". I'm working on a PWM driver, but In this period I'm full of work and I do not have time to finish that driver.

  13. Hi Davide . I made it but what is the UART (PD1) ? where i should connect it to ?
    What is the use of it ?
    Thank you

    1. Hello,
      the uart PD1 is just for debug purpose on serial port. If you need to debug something throght serial connection.

  14. so why it does'n work ? :-(
    I made both in real and also in Proteus .
    In real it rotates the motor for a while with different speeds and again and again.
    and it has nothing to do with the speed variable resistor and direction set .

    1. Check your timer setup. Check the zc bemf threshold. Scope around to see what's not working. It will probabily do the startup cycle, then maybe the zc threshold is not read or it is not propery setted. It changes by motors and even by power driver. You have to debug it.

  15. thank you for this.
    But I can't understand why PD6 don't have LPF?
    I had known neutral point need LPF. Its input is HF signal.
    can you tell that?

    1. Hello. The schematics you see above it's a standard implementation. The code in this library does not use the comparator on PD6. A better approach is to use that comparator. Indeed I've another driver in production which use that comparator. I will share that project soon.

  16. Hello, I have one more question.
    It can't start with itself. If I forced to start, it has run.
    I think starting power is lack, but I can't modify.
    How can I fix the source to do?

    //run commutations
    for(;;) {
    if(bldcsensorless_commutationstep == 0) {
    if (i < 2)
    i += 1;
    j += 1;i=0;
    //do startup delays
    uint16_t d = 0;
    for(d=0; d<startupdelays[j]; d++) {

    I modified i and delay_us(5), but that wasn't change.

    Linked address is video of my bldc driver.

    I'm sorry for this. T.T

    1. I modified zc threshold and zc error but it can't run too.
      How can I start a motor...

    2. Hello, at first i would try with another motor, one that's needs less current then the the one you are using, maybe a floppy or cd one. Just to see if is all working.
      But remember, this a simple brushless driver, i think you should go for a PWM one, which works slighty better on high speed.