Skip to content

Instantly share code, notes, and snippets.

@ollewelin
Last active September 29, 2023 13:00
Show Gist options
  • Save ollewelin/4afcf202a6ff267aa70e5b289724abc2 to your computer and use it in GitHub Desktop.
Save ollewelin/4afcf202a6ff267aa70e5b289724abc2 to your computer and use it in GitHub Desktop.
3-phase PWM with deadtime 31.25kHz Arduino UNO. 6 transistors PWM
//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
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 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
Serial.println("This is a code made to run 3-phase PWM drive stage with 6-transistor");
Serial.println("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");
while(1)
{
pwm_ph0=128;// Center
pwm_ph1=128;
pwm_ph2=128;
update_pwm();
delay(100000);//delay timer scale is screwd up by the new PWM TMR settings
pwm_ph0=10;// Test some other values
pwm_ph1=249;//Above value or below value 6 the update_pwm() function will automatic limit so the PWM not wrap over because of the dead_time
pwm_ph2=30;//
update_pwm();
delay(100000);
}
}
@ResoCole2017
Copy link

Wao, Iove this contribution. The code was expressly used

@ibrahimerez
Copy link

Hello, thank you for sharing this work. how can i set frequency for pwm in this code. frequency can be 300hz or 400hz.

@cinqlair
Copy link

I don't understand the first operation : (GTCCR & 0xFF) at this line :

GTCCR = (GTCCR & 0xFF) | 0x81;

Since GTCCR is a 8 bits registers, GTCCR & 0xFF is the same as GTCCR, am I wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment