Last active
May 12, 2022 14:52
-
-
Save ollewelin/db5d5bd359064a95a4e11b7a44c79a16 to your computer and use it in GitHub Desktop.
3-phase motor PWM drive open loop motor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//This is a code made to run 3-phase PWM drive stage with 6-transistors, in other words 3 half bridge transistors with an Arduino UNO | |
//This setup is made with User settings of DEAD TIME. So here the the dead time can be adjusted by user. const int dead_time = 10;//10 = 0.625 us | |
//The PWM work here with fix frequancy of 31.25kHz (Other settings may not work proper when use all 3 TIMERS, if you want more flexibilty use Arduino MEGA 2560 or some other plattform) | |
//Olle Welin [email protected] | |
// TL Transistor Low side of half bridge pair | |
// TH Transistor High side of half bridge pair | |
// PWM assignement at Arduino UNO is by following: | |
//~6 TL, PH0, TMR0, pwm_ph0 data value | |
//~5 TH, PH0, TMR0, pwm_ph0 data value | |
//~9 TL, PH1, TMR1, pwm_ph1 data value | |
//~10 TH, PH1, TMR1, pwm_ph1 data value | |
//~11 TL, PH2, TMR2, pwm_ph2 data value | |
//~3 TH, PH2, TMR2, pwm_ph2 data value | |
#include <math.h> | |
void setup() | |
{ | |
pinMode(3, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
pinMode(5, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
pinMode(6, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
pinMode(9, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
pinMode(10, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
pinMode(11, INPUT); //PWM is set to input before PWM initialized to prevent start up short circuit | |
// start serial port at 9600 bps: | |
Serial.begin(9600); | |
while (!Serial) { | |
; // wait for serial port to connect. Needed for Leonardo only | |
} | |
} | |
const int dead_time = 10;//10 = 0.625 us | |
const int half_dead_time = dead_time / 2;// | |
int pwm_ph0=0; | |
int pwm_ph1=0; | |
int pwm_ph2=0; | |
void update_pwm(void) | |
{ | |
//Limit the pwm_phx so it take the dead time into account so it not will swap over when reach end limit of workable PWM range | |
if(pwm_ph0 > (255 - half_dead_time)) | |
{ | |
pwm_ph0 = (255 - half_dead_time); | |
} | |
if(pwm_ph1 > (255 - half_dead_time)) | |
{ | |
pwm_ph1 = (255 - half_dead_time); | |
} | |
if(pwm_ph2 > (255 - half_dead_time)) | |
{ | |
pwm_ph2 = (255 - half_dead_time); | |
} | |
if(pwm_ph0 < half_dead_time) | |
{ | |
pwm_ph0 = half_dead_time; | |
} | |
if(pwm_ph1 < half_dead_time) | |
{ | |
pwm_ph1 = half_dead_time; | |
} | |
if(pwm_ph2 < half_dead_time) | |
{ | |
pwm_ph2 = half_dead_time; | |
} | |
//All The PWM will run from 0xFF to 0x00 and up again to TOP 0xFF | |
//The OCRnx will automatic update when TCNTn is on TOP 0xFF by hardware | |
//Therefor it is sutible to change both OCRnx pair on a place where TCNT not update to ensure that the hardware automatic update NOT occur exact when only one of the two OCRnx have changed by this code | |
while(TCNT0 > 0x7F) | |
{ | |
} | |
//Now it's safe to update OCR0x pair (connect to same transistor pair) | |
OCR0A = (pwm_ph0 + half_dead_time);//~6 TL PH0 TMR0 | |
OCR0B = (pwm_ph0 - half_dead_time);//~5 TH PH0 TMR0 | |
while(TCNT1 > 0x7F) | |
{ | |
} | |
//Now it's safe to update OCR1x pair (connect to same transistor pair) | |
OCR1A = (pwm_ph1 + half_dead_time);//~9 TL PH1 TMR1 | |
OCR1B = (pwm_ph1 - half_dead_time);//~10 TH PH1 TMR1 | |
while(TCNT2 > 0x7F) | |
{ | |
} | |
//Now it's safe to update OCR2x pair (connect to same transistor pair) | |
OCR2A = (pwm_ph2 + half_dead_time);//~3 TH PH2 TMR2 | |
OCR2B = (pwm_ph2 - half_dead_time);//~11 TL PH2 TMR2 | |
} | |
void sync_pwm_timers(void) | |
{ | |
GTCCR = (GTCCR & 0xFF) | 0x81;// Set bit Bit 7 – TSM: Timer/Counter Synchronization Mode | |
//Writing the TSM bit to one activates the Timer/Counter Synchronization mode. In this mode, the value that is written | |
//to the PSRASY and PSRSYNC bits is kept, hence keeping the corresponding prescaler reset signals asserted. | |
//This ensures that the corresponding Timer/Counters are halted and can be configured to the same value without | |
//the risk of one of them advancing during configuration. When the TSM bit is written to zero, the PSRASY and | |
//PSRSYNC bits are cleared by hardware, and the Timer/Counters start counting simultaneously. | |
TCNT0 = 00;//Syncronize PWM timers | |
TCNT1 = 0x0000;//Syncronize PWM timers | |
TCNT2 = 0x00;//Syncronize PWM timers | |
GTCCR = (GTCCR & 0x7E);// Rest bit Bit 7 – TSM: Timer/Counter Synchronization Mode | |
} | |
void wait_TCN(void) | |
{ | |
//************************************************************************************** | |
///This two while wait will create a poll to create a Fix loop frequense of 31.25kHz | |
while(TCNT0 < 0xEF) | |
{ | |
} | |
while(TCNT0 > 0xEF) | |
{ | |
} | |
/// End of poll of Fix loop frequense 31.25kHz | |
//************************************************************************************** | |
} | |
void loop() | |
{ | |
TCCR1A = 0xE1;//PWM, Phase Correct 8-bit TOP at 0xFF | |
TCCR0A = 0xE1;//PWM, Phase Correct 8-bit TOP at 0xFF | |
TCCR2A = 0xE1;//PWM, Phase Correct 8-bit TOP at 0xFF | |
TCCR2B = 0x01;//clkI/O/1 (No prescaling) 31.25kHz PWM frequency | |
TCCR1B = 0x01;//clkI/O/1 (No prescaling) 31.25kHz PWM frequency | |
TCCR0B = 0x01;//clkI/O/1 (No prescaling) 31.25kHz PWM frequency | |
sync_pwm_timers(); | |
pwm_ph0=128;//128 = center. User PWM Range is value between (0 + half_dead_time) to (255 - half_dead_time) | |
pwm_ph1=128; | |
pwm_ph2=128; | |
update_pwm(); | |
pinMode(3, OUTPUT); //PWM output | |
pinMode(5, OUTPUT); //PWM output | |
pinMode(6, OUTPUT); //PWM output | |
pinMode(9, OUTPUT); //PWM output | |
pinMode(10, OUTPUT); //PWM output | |
pinMode(11, OUTPUT); //PWM output | |
pinMode(2, OUTPUT); //Frequance Indicator | |
const float rps = 0.555555555556f;/// 100 turn / 180 sec | |
const int table_size = 300; | |
float rot_step = 0.128f;/// (12 poles / 2) * rps * table_size / (31250Hz / 4) | |
float frequence = 7812.5; | |
rot_step = 6 * rps * table_size / frequence; | |
Serial.print("rot_step = "); | |
Serial.println(rot_step, 8); | |
const float two_pi = 6.28318530718; | |
float rot_counter=0; | |
float sinus=0; | |
float pwm_max = 100; | |
const float deg_120 = 2.09439510239f; | |
const float deg_240 = 4.18879020479f; | |
const int table_one_third = table_size / 3; | |
int table[table_size]; | |
//Make sinus integer table | |
for(int i = 0;i<table_size;i++) | |
{ | |
sinus = sin(two_pi * i/table_size);/// | |
sinus = sinus * pwm_max; | |
sinus = sinus + 128.0f; | |
table[i] = sinus; | |
/* | |
Serial.print("table["); | |
Serial.print(i); | |
Serial.print("] = "); | |
Serial.println(table[i]); | |
*/ | |
} | |
int table_index1=0; | |
int table_index2=0; | |
int table_index3=0; | |
const long ramp_sec = 60; | |
const float rot_step_ramp_inc = rot_step / (((float) frequence) * ((float)ramp_sec)); | |
Serial.print("rot_step_ramp_inc = "); | |
Serial.println(rot_step_ramp_inc, 8); | |
float rot_step_ramp = 0; | |
long ramp_counter = 0; | |
ramp_counter = (long) frequence; | |
Serial.print("ramp_counter = "); | |
Serial.println(ramp_counter); | |
ramp_counter = ramp_counter * ramp_sec; | |
Serial.print("ramp_counter = "); | |
Serial.println(ramp_counter); | |
for(long k = 0; k < ramp_counter; k++) | |
{ | |
digitalWrite(2, LOW); | |
wait_TCN(); | |
digitalWrite(2, HIGH); | |
if(rot_counter < table_size-1) | |
{ | |
rot_counter = rot_counter + rot_step_ramp; | |
} | |
else | |
{ | |
rot_counter = 0; | |
} | |
table_index1 = (int) rot_counter; | |
table_index2 = table_index1 + table_one_third; | |
wait_TCN(); | |
table_index3 = table_index1 + table_one_third + table_one_third; | |
if(table_index2 > table_size-1) | |
{ | |
table_index2 = table_index2 - table_size; | |
} | |
if(table_index3 > table_size-1) | |
{ | |
table_index3 = table_index3 - table_size; | |
} | |
pwm_ph2 = table[table_index1]; | |
pwm_ph1 = table[table_index2]; | |
pwm_ph0 = table[table_index3]; | |
/* | |
Serial.print("pwm_ph0 ="); | |
Serial.print(pwm_ph0); | |
Serial.print(" pwm_ph1 ="); | |
Serial.print(pwm_ph1); | |
Serial.print(" pwm_ph2 ="); | |
Serial.println(pwm_ph2); | |
*/ | |
wait_TCN(); | |
rot_step_ramp = rot_step_ramp + rot_step_ramp_inc; | |
wait_TCN(); | |
update_pwm(); | |
} | |
while(1) | |
{ | |
digitalWrite(2, LOW); | |
wait_TCN(); | |
digitalWrite(2, HIGH); | |
if(rot_counter < table_size-1) | |
{ | |
rot_counter = rot_counter + rot_step; | |
} | |
else | |
{ | |
rot_counter = 0; | |
} | |
table_index1 = (int) rot_counter; | |
table_index2 = table_index1 + table_one_third; | |
wait_TCN(); | |
table_index3 = table_index1 + table_one_third + table_one_third; | |
if(table_index2 > table_size-1) | |
{ | |
table_index2 = table_index2 - table_size; | |
} | |
if(table_index3 > table_size-1) | |
{ | |
table_index3 = table_index3 - table_size; | |
} | |
pwm_ph2 = table[table_index1]; | |
pwm_ph1 = table[table_index2]; | |
pwm_ph0 = table[table_index3]; | |
/* | |
Serial.print("pwm_ph0 ="); | |
Serial.print(pwm_ph0); | |
Serial.print(" pwm_ph1 ="); | |
Serial.print(pwm_ph1); | |
Serial.print(" pwm_ph2 ="); | |
Serial.println(pwm_ph2); | |
*/ | |
wait_TCN(); | |
wait_TCN(); | |
update_pwm(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment