Skip to content

Instantly share code, notes, and snippets.

@ollewelin
Last active May 12, 2022 14:52
Show Gist options
  • Save ollewelin/db5d5bd359064a95a4e11b7a44c79a16 to your computer and use it in GitHub Desktop.
Save ollewelin/db5d5bd359064a95a4e11b7a44c79a16 to your computer and use it in GitHub Desktop.
3-phase motor PWM drive open loop motor
//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