I've been trying to make a good ESC for years. My first prototype 3 years ago was working "good". It was very big and the BEMF was not that good. It could reach decent speeds and you ahve that tutorial here on this page. Now, with my final version I have all taht I wanted. High speed, good BEMF detection and that means good torque, PWM control of the speed and small size. The board is programed in Arduino.
So what is an ESC? Well, electronic speed controllers are used to control brushless motors, in thisc ase the motor has a triple phase input. To control this input, the ESC must apply a special sequence of LOWs and HIGHs signals in a predefined order. It has to conmutate very fast and by taht rotate the rotor of the motor. In this tutorial we will see how to control the rotation, the speed, detect the BEMF and by that know when to make the switch to the next step of the sequence. So this is a sensorless brushless motor speed controller since it uses no sensor to detect the rotor position. We will learn:
- - The schematic and why we need each part
- - Triple phase MOSFET bridge control
- - BEMF detection and 0 cross
- - Interrumprions and internal comparator of ATMEGA328
- - PWM control
Now the schematic might look complicated but is not. First things first, we have a power block. This is a buck converter circuit that will give 5V for all the digital parts. The main input could be from 11 to 18V but this block will aloways give 5V. The next block is the triple phase bridge. These are 6 MOSFETs in a bridge configurations that are used to energise the coils of the motor. Each of these MOSFETs has a driver control with the IR2101 which is a dual driver so it could control both the high and low sides of the bridge.
- 1 x PCB: GERBERS here
- 1 x ATmega328: LINK eBay
- 1 x MP2307DN-LF-Z: LINK eBay
- 1 x CH340C: LINK eBay
- 3 x IR2101STRPBF: LINK eBay
- 6 x IRLR7843TRPBF: LINK eBay
- 3 x 1N4148WS: LINK eBay
- 1 x CON-USB-F-MICRO-B: LINK eBay
- 1 x 16MHz crystal 3213: LINK eBay
- 1 x BUZZER 5020: LINK eBay
- 0603 Resistors (100R, 1K, 6.8K, 10K, 33K, 44.2K, 100K, 1M): LINK eBay
- 2 x 0603 LEDs: LINK eBay
- 0603 Capacitors (1 x 3.9n, 1 x 10n, 4 x 100n, 3 x 2.2u): LINK eBay
- 1206 Capacitors (4 x 10u, 6 x 22u,): LINK eBay
- 1 x 7.4X6.6 coil 100uH: LINK eBay
- wire, solder, soldering-iron, etc
We have the BEMF voltage dividers block. The voltage from the motor will be higher than the maximum voltage that the ATmega328 could tahe as input, in this case 5V. So for that, using some resistors of 10K and 33K we lower the voltage so the analog input of the ATmega328 could read that. This inputs will be used to detect the position of the rotor and know when to switch to next step of the rotating sequence. We also have the ATmega328 microcontroller, the CH340 programmer so we could upload codes with the USB connector and a few more extra components such as buzzer, LEDs and pads.

The PCB I've designed is 60 by 35 mm. In the photo below you can see the first version of the PCB in red but also the final version with black soldermask. The V1.0 had some errors such as some bad GND connections, wrong pin for the Buzzer and also the power tracks were covered by the soldermask. For version V2.0 now all the problems are fixed and the big tracks are exposed so I could fill those with solder for more current. You can download the gerber files from below. When you will download the GERBERS file above you will have a .zip file. Go to JLCPCB or any other professional PCB manufacturer, uplaod the .zip file and order your boards. In my case 10 PCBs cost me just 2 dollars plus shipping which for spain was 6 more dollars. I 7 days, I receive the next boards with a great look. You have silklayer for all the components so soldering the components should be easy. The PCB thickness is 1.6mm, signal tracks are 0.2mm and power tracks are 2mm. This red board has no exposed power tracks but the GERBER file you can download from above, is with the final version so don't worry.

The first part we solder is the power block. This will be a buck converter circuit that will lower the voltage from 12V to 5V for the microcontroller and other digital parts. Why we do this part first? Well, if we first solder the digital part and then the power block and by mistake the output of the buck converter is not 5V but 12V, well, taht will burn all the digital part.

Second step is to solder the microcontroller basic configuration. That is the ATmega328p-AU chip, the 16MHz crystal, the R23 resistor of 1M ohm, the R1 resistor of 10K ohm, the C6 capacitor of 100nF. These components are mandatory for the microcontroller to work. Once you've soldered all these parts, we can test if we can upload something to the chip.
Once you have soldered all the parts for the basic configuration connect the FTDI external programmer to the RX DTR and TX pads but also Vcc and GND. Now open Arduino IDE and uplaod the next test code that will increas the "x" value each second and print that on the serial monitor. If you can see the number increasing, that means the IC was well soldered and it is working with no problem.
int x = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
x = x + 1;
Serial.println(x);
delay(1000);
}

Once the voltage is 5V and the ATmega chip is working, we can keep soldering parts. Next part is the CH340 FTDI programmer. This chip will make the connection between and USB connector from a PC and our ATmega chip. So solder the CH340C, the C7 capacitor and the R18 aND R19 resitors of 1k. Also solder the USB connector. Make sure the FTDI chip is the CH340C not the CH340G, because that will also need a crystal. Once you solder the chip and the connector, try to upload the same code as before but this time with the USB connector on the board. If it works we are good to go.

Now that everything works, we can solder the BEMF resistors, the MOSFET drivers with the diode and capacitors and the MOSFETs on the back for the triple phase bridge. Also solder the LEDs and the buzzer. Finally, we solder 3 wires with female connectors to the GND, Vcc and PWM pads. These will be the input signal from the radio receiver, just as any other commercial ESC.

Now the code is a bit long and difficult to understand. That's why each line has a comment. So download the code from the link below. Then read each line in order to understand why I do each part. The code will have the main.ino but also s secondary code for the EEPROM write/read. The code starts by defining the variables to use in the code. In the Setup loop we first check if the first position of the EEPROM memory is 1. If not that means it is the first time we run the code so we save the min and max values of the PWM input signal and also write a "1" on the first EEPROM adress.
Then, still in the Setup loop we configure all the registers. We set the pins as outputs/inputs, we set the PWM registers and alos set digital pin D8 to be able to create pin state change interrumptions. This pin is used to read the input PWM width in microseconds.
After the register configuration there are some loops that will detect if the ESC should enter configuration mode or not. If the input PWM signal is above a certain value when the ESC is powered on, then it should enter config mode where you could set the max and min range of the PWM input. If not, it will jump to the motor rotation loop.
Then we have a bunch of functions and ISRs to detect the PWM input value, to change the pins for the MOSFET drivers to high or low or to PWM or not PWM and also to change the comparator input on pin D6. With this input we read the BEMF and on each step of the sequence we need to change that input from BEMF_A, to BEMF_B or BEMF_C. The Armega328 has this comparator on pin D6. The negative input if this comparator will be the COM line, which is the summ of all back electromotive foces of A, B and C. Then the positive input of the comparator will then be selected in the code with the line:
DDRD |= B00011100; // Configure pins 2, 3 and 4 as outputs
PORTD = B00000000; //pins 0 to 7 set to LOW
DDRB |= B00001110; // Configure pins 9, 10 and 11 as outputs
PORTB &= B00110001; //B00110001 D9, D10 and D11 to LOW
// Timer1
TCCR1A = 0;
TCCR1B = 0x01;
// Timer2
TCCR2A = 0;
TCCR2B = 0x01;
// Comparator on pin D6
ACSR = 0x10; // Clear flag comparator interrupt
//Set D8 (PWM in) to trigger interrupt (we use this to read PWM input)
PCICR |= (1 << PCIE0); //enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); //Set pin D8 trigger an interrupt on state change.
Once you uploaded the code and connected power, the motor and the PWN input we can test this. Make sure the PWM joystick is low and then connect power. When you increase the PWM signal the motor should spin. If you want to set a new range of PWM and calibrate the ESC, just put the joystick in the middle position before powering the ESC. Power the ESC and you will hear the config beeps. After the beeps put the joystick to the maximum value and then to the minimum value and it will get stored to the EEPROM. That's it.
Once you uploaded the code and connected power, the motor and the PWN input we can test this. Make sure the PWM joystick is low and then connect power. When you increase the PWM signal the motor should spin. If you want to set a new range of PWM and calibrate the ESC, just put the joystick in the middle position before powering the ESC. Power the ESC and you will hear the config beeps. After the beeps put the joystick to the maximum value and then to the minimum value and it will get stored to the EEPROM. That's it.
2 Comments
-
Ricardo Salazar 1983
about 4 years ago
Hola amigo he probado tu primer sieno con los ir2301 y los mosfet irf3205 pero no me jala he puesto el codigo el arduino y no logro sacar nada por los transitores lo he simulado en proteus y no me fuciona
David Morreres Viladegut
Hola amigo, Recienteme he visto la versión española de este proyecto y me asalta una duda que seguro me podrás aclarar. Como se hace en easyEda para que no te serigrafie por encima de las pistas que soportan más corriente para poder reforzarlas con estaño. Seguro que es muy fácil pero no encuentro la manera de hacerlo. Gracias de antemano.