Hey everyone this is my first time reaching out to the community for help, and I am really stuck. Basically I am trying to make my own ESC for a BLDC before anyone says the commercial solution is cheaper and easier, I'm doing it to try learn more and make a customisable version that's all my own work so lets get into the issue.
The problem is although I'm using a 20khz Pwm signal at a variable duty on the high side input generated by direct timer control on the nano, to try "chop"/control the current and keeping the lowside fully grounded, the MOSFETs I'm using (N-channel irf1405s that are 55V and 160A rated) are getting really really hot and so is the motor like over 150 degrees Celsius hot even after only running for 30 seconds. The actually motor spins just fine however I can even change the speed using a timed step change (although I do have the hardware and did have the software for BEMF step changing too I disabled it to try simplify things since the heating issue is my main priority).
I've attached my code and schematic as well as a picture of my circuit if anyone can see something on this that I can't it would be much appreciated because I'm at my wits end here ive tried adding lots of different changes to the hard and software with no luck as at the end of it all I still can't seem to stop the MOSFETs and motor from getting really hot because of what I assume is excessive current draw (possibly building up in the coils and trying to ground through the FETS body diode? maybe?) , if I increase the duty to 70%+ the MOSFETs also just straight up explode even with dead time coded in using delay functions.
I'm using a 12V 6.5Ah lead acid battery for testing as its close to the power supply I would use the ESC with normally.
if anyone with experience in power electronics or any ideas on how to fix my heating issue is reading this please help. Thank you, Harry.
my schematic:

my Code done it Arduino IDE:
int StepCounter = 1; //step counter
int RawDutyCycle = 0; //raw pot input storage variable
int Duty = 0; //duty cycle
//setup lowside pins for standalone direct port manipulation
int LowSideA = PD2; //pin D2
int LowSideB = PD5; //pin D5
int LowSideC = PD7; //pin D7
//setup highside pins to be PWM outputs at port level
int HighSideA = PD3; //OC2B D3
int HighSideB = PB1; //OC1A D9
int HighSideC = PB2; //OC1B D10
//defins all the PWM pin States neatly
#define HighSideASetON (1<<COM2A0) + (1<<COM2B1) + (1<<WGM20)
#define HighSideASetOFF (0<<COM2A0) + (0<<COM2B1) + (1<<WGM20)
#define HighSideBSetON (1<<COM1A1) + (0<<COM1B1)
#define HighSideCSetON (0<<COM1A1) + (1<<COM1B1)
#define HighSideBandCSetOFF (0<<COM1A1) + (0<<COM1B1)
void setup() {
//Sets data direction of all pins
DDRD = (1<<LowSideA) | (1<<LowSideB) | (1<<LowSideC) | (1<<HighSideA);
DDRB = (1<<HighSideB) | (1<<HighSideC);
pinMode(A0, INPUT);
//timer1 PWM pins D9 and D10 setup
TCCR1A = 0;
TCCR1B = 0;
TCCR1A = (1<<COM1A1) + (1<<COM1B1) + (1<<WGM11); //phase correct pwm
TCCR1B = (1<<WGM13) + (1<<CS11);
ICR1 = 100; //set kHz
OCR1A = 10; //set duty
OCR1B = 10; //set duty
//timer2 PWM pin D3 setup
TCCR2A = 0;
TCCR2B = 0;
TCCR2A = (1<<COM2A0) + (1<<COM2B1) + (1<<WGM20); //phase correct pwm
TCCR2B = (1<<CS21) + (1<<WGM22);
OCR2A = 100; //set kHz
OCR2B = 10; //set duty
//Sets all 3 H-bridges to float
TCCR1A = (0<<COM1A1) + (0<<COM1B1);
TCCR2A = (0<<COM2A1) + (0<<COM2B1);
PORTD = (1<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
}
void loop() {
RawDutyCycle = analogRead(A0); //read the pot
int WaitTime = map(RawDutyCycle, 0, 1023, 10000, 500);
Duty = 50;
OCR1A = Duty; //set duty
OCR1B = Duty;
OCR2B = Duty;
delayMicroseconds(WaitTime);
switch(StepCounter){
case 1: //step1
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (0<<LowSideB) + (1<<LowSideC);
TCCR2A = HighSideASetON;
StepCounter = 2;
break;
case 2: //step2
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (1<<LowSideB) + (0<<LowSideC);
TCCR2A = HighSideASetON;
StepCounter = 3;
break;
case 3: //step3
TCCR2A = HighSideASetOFF;
PORTD = (1<<LowSideA) + (1<<LowSideB) + (0<<LowSideC);
TCCR1A = HighSideBSetON;
StepCounter = 4;
break;
case 4: //step4
TCCR1A = HighSideBandCSetOFF;
PORTD = (0<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideBSetON;
StepCounter = 5;
break;
case 5: //step5
TCCR1A = HighSideBandCSetOFF;
PORTD = (0<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideCSetON;
StepCounter = 6;
break;
case 6: //step6
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (0<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideCSetON;
StepCounter = 1;
break;
}
}
The problem is although I'm using a 20khz Pwm signal at a variable duty on the high side input generated by direct timer control on the nano, to try "chop"/control the current and keeping the lowside fully grounded, the MOSFETs I'm using (N-channel irf1405s that are 55V and 160A rated) are getting really really hot and so is the motor like over 150 degrees Celsius hot even after only running for 30 seconds. The actually motor spins just fine however I can even change the speed using a timed step change (although I do have the hardware and did have the software for BEMF step changing too I disabled it to try simplify things since the heating issue is my main priority).
I've attached my code and schematic as well as a picture of my circuit if anyone can see something on this that I can't it would be much appreciated because I'm at my wits end here ive tried adding lots of different changes to the hard and software with no luck as at the end of it all I still can't seem to stop the MOSFETs and motor from getting really hot because of what I assume is excessive current draw (possibly building up in the coils and trying to ground through the FETS body diode? maybe?) , if I increase the duty to 70%+ the MOSFETs also just straight up explode even with dead time coded in using delay functions.
I'm using a 12V 6.5Ah lead acid battery for testing as its close to the power supply I would use the ESC with normally.
if anyone with experience in power electronics or any ideas on how to fix my heating issue is reading this please help. Thank you, Harry.
my schematic:

my Code done it Arduino IDE:
int StepCounter = 1; //step counter
int RawDutyCycle = 0; //raw pot input storage variable
int Duty = 0; //duty cycle
//setup lowside pins for standalone direct port manipulation
int LowSideA = PD2; //pin D2
int LowSideB = PD5; //pin D5
int LowSideC = PD7; //pin D7
//setup highside pins to be PWM outputs at port level
int HighSideA = PD3; //OC2B D3
int HighSideB = PB1; //OC1A D9
int HighSideC = PB2; //OC1B D10
//defins all the PWM pin States neatly
#define HighSideASetON (1<<COM2A0) + (1<<COM2B1) + (1<<WGM20)
#define HighSideASetOFF (0<<COM2A0) + (0<<COM2B1) + (1<<WGM20)
#define HighSideBSetON (1<<COM1A1) + (0<<COM1B1)
#define HighSideCSetON (0<<COM1A1) + (1<<COM1B1)
#define HighSideBandCSetOFF (0<<COM1A1) + (0<<COM1B1)
void setup() {
//Sets data direction of all pins
DDRD = (1<<LowSideA) | (1<<LowSideB) | (1<<LowSideC) | (1<<HighSideA);
DDRB = (1<<HighSideB) | (1<<HighSideC);
pinMode(A0, INPUT);
//timer1 PWM pins D9 and D10 setup
TCCR1A = 0;
TCCR1B = 0;
TCCR1A = (1<<COM1A1) + (1<<COM1B1) + (1<<WGM11); //phase correct pwm
TCCR1B = (1<<WGM13) + (1<<CS11);
ICR1 = 100; //set kHz
OCR1A = 10; //set duty
OCR1B = 10; //set duty
//timer2 PWM pin D3 setup
TCCR2A = 0;
TCCR2B = 0;
TCCR2A = (1<<COM2A0) + (1<<COM2B1) + (1<<WGM20); //phase correct pwm
TCCR2B = (1<<CS21) + (1<<WGM22);
OCR2A = 100; //set kHz
OCR2B = 10; //set duty
//Sets all 3 H-bridges to float
TCCR1A = (0<<COM1A1) + (0<<COM1B1);
TCCR2A = (0<<COM2A1) + (0<<COM2B1);
PORTD = (1<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
}
void loop() {
RawDutyCycle = analogRead(A0); //read the pot
int WaitTime = map(RawDutyCycle, 0, 1023, 10000, 500);
Duty = 50;
OCR1A = Duty; //set duty
OCR1B = Duty;
OCR2B = Duty;
delayMicroseconds(WaitTime);
switch(StepCounter){
case 1: //step1
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (0<<LowSideB) + (1<<LowSideC);
TCCR2A = HighSideASetON;
StepCounter = 2;
break;
case 2: //step2
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (1<<LowSideB) + (0<<LowSideC);
TCCR2A = HighSideASetON;
StepCounter = 3;
break;
case 3: //step3
TCCR2A = HighSideASetOFF;
PORTD = (1<<LowSideA) + (1<<LowSideB) + (0<<LowSideC);
TCCR1A = HighSideBSetON;
StepCounter = 4;
break;
case 4: //step4
TCCR1A = HighSideBandCSetOFF;
PORTD = (0<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideBSetON;
StepCounter = 5;
break;
case 5: //step5
TCCR1A = HighSideBandCSetOFF;
PORTD = (0<<LowSideA) + (1<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideCSetON;
StepCounter = 6;
break;
case 6: //step6
TCCR1A = HighSideBandCSetOFF;
PORTD = (1<<LowSideA) + (0<<LowSideB) + (1<<LowSideC);
TCCR1A = HighSideCSetON;
StepCounter = 1;
break;
}
}