3 Phase Variable Frequency Drive VFD with F103

What are you developing?
bogdanaioane
Posts: 23
Joined: Thu Oct 04, 2018 3:46 am

3 Phase Variable Frequency Drive VFD with F103

Post by bogdanaioane » Wed Jan 16, 2019 5:04 pm

Hi All,
I have been "playing" with building a VFD for my CNC machine. I would image one would ask... why for the love of god would you want to build one of these things when they sell for peanuts online nowadays. and the answer is.. I got my hands on a very fancy spindle that requires frequencies of up to 1000Hz and the cheap drives i can see online seem to stop at about 3-400Hz. Also i kind of like to use this to learn and share.
the main part that i am currently concerned with is the 3 phase sine wave generator. Here is what i have done so far:

Image

I have in principal made it work by using simple logic and "naive" code.
here is the code:

Code: Select all

PROGMEM const uint16_t Half_Sine[] = {
  0,  4,  8, 13, 17, 22, 26, 31, 35, 40, 44, 48, 53, 57, 61, 66, 70, 74, 79, 83, 87, 91, 95,100,104,108,112,116,120,124,
128,131,135,139,143,146,150,154,157,161,164,167,171,174,177,181,184,187,190,193,196,198,201,204,207,209,212,214,217,219,
221,223,226,228,230,232,233,235,237,238,240,242,243,244,246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255,
256,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247,246,244,243,242,240,238,237,235,233,232,230,228,226,223,
221,219,217,214,212,209,207,204,201,198,196,193,190,187,184,181,177,174,171,167,164,161,157,154,150,146,143,139,135,131,
128,124,120,116,112,108,104,100, 95, 91, 87, 83, 79, 74, 70, 66, 61, 57, 53, 48, 44, 40, 35, 31, 26, 22, 17, 13,  8,  4 
};
int PhaseA_OUT = PA8;     //  TIM1_CH1 pwm output for phase A sine wave
int PhaseA_High_EN = PB10;
int PhaseA_Low_EN = PB11;
int PhaseA_EN_State = 0;
int PhaseB_OUT = PA9;     //  TIM1_CH2 pwm output for phase B sine wave
int PhaseB_High_EN = PB8;
int PhaseB_Low_EN = PB9;
int PhaseB_EN_State = 0;
int PhaseC_OUT = PA10;    //  TIM1_CH3 pwm output for phase C sine wave
int PhaseC_High_EN = PB5;
int PhaseC_Low_EN = PB6;
int PhaseC_EN_State = 0;
int Amplitude_OUT = PA6;  //  TIM3_CH1 pwm channel for controlling the amplitude of the sinewave by using the sine wave channels as carriers for higher frequency pwm
int Amplitude_CTRL = 100;   //  variable that controls the duty cycle of Amplitude_OUT pin 
int Frequency_CTRL = 100;   //  variable that controls the frequency of the sine wave 
int Array_Limit = 179;
int a = 0;
int b = 0;
int c = 0;
int i = 0; // Array Increment
int Dead_Band_Delay = 10;
HardwareTimer CarrierTimer(1);
HardwareTimer AmplitudeTimer(3);
void setup() {                
  CarrierTimer.setPrescaleFactor(1);
  CarrierTimer.setOverflow(256);
  AmplitudeTimer.setPrescaleFactor(8);
  AmplitudeTimer.setOverflow(500);
  pinMode(PhaseA_OUT, PWM);
  pinMode(PhaseA_High_EN, OUTPUT);
  pinMode(PhaseA_Low_EN, OUTPUT);
  pinMode(PhaseB_OUT, PWM);
  pinMode(PhaseB_High_EN, OUTPUT);
  pinMode(PhaseB_Low_EN, OUTPUT);
  pinMode(PhaseC_OUT, PWM);
  pinMode(PhaseC_High_EN, OUTPUT);
  pinMode(PhaseC_Low_EN, OUTPUT);
  pinMode(Amplitude_OUT, PWM);
  digitalWrite(PhaseA_High_EN, HIGH);
  digitalWrite(PhaseA_Low_EN, LOW);
}
void loop() {
  pwmWrite(Amplitude_OUT, Amplitude_CTRL);
  if (a < 60) {
    b = a + 120;
  } else {
    b = a - 60;
  }
  if (a < 120) {
    c = a + 60;
  } else {
    c = a - 120;
  }
  a++;
  if (a > Array_Limit) {
    a = 0;
    digitalWrite(PhaseA_High_EN, (PhaseA_EN_State) ? HIGH : LOW);
    digitalWrite(PhaseA_Low_EN, (PhaseA_EN_State) ? LOW : HIGH);
    PhaseA_EN_State = ! PhaseA_EN_State;
  } 
  if (b == 0) {
    digitalWrite(PhaseB_High_EN, (PhaseB_EN_State) ? HIGH : LOW);
    digitalWrite(PhaseB_Low_EN, (PhaseB_EN_State) ? LOW : HIGH);
    PhaseB_EN_State = ! PhaseB_EN_State;
  }
  if (c == 0) {
    digitalWrite(PhaseC_High_EN, (PhaseC_EN_State) ? HIGH : LOW);
    digitalWrite(PhaseC_Low_EN, (PhaseC_EN_State) ? LOW : HIGH);
    PhaseC_EN_State = ! PhaseC_EN_State;
  }
  pwmWrite(PhaseC_OUT, Half_Sine[c]);
  pwmWrite(PhaseA_OUT, Half_Sine[a]);
  pwmWrite(PhaseB_OUT, Half_Sine[b]);
  delay_us(Frequency_CTRL);
}
The issue is that it is not fast enough. I saw a much more elegant approach using interrupts with arduino uno but unfortunately for me, i am "not yet there" in terms of understanding interrupts.

here is the code for that implementation:

Code: Select all

// 3 phase PWM sine
// (c) 2016 C. Masenas
// Modified from original DDS from: 
// KHM 2009 /  Martin Nawrath
// table of 256 sine values / one sine period / stored in flash memory
PROGMEM const unsigned char sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
};
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
int testPin = 7;
int enablePin = 6 ;
volatile  float freq=1;
const float refclk=122.549  ;     //  16 MHz/510/256
// variables used inside interrupt service declared as voilatile
volatile unsigned long sigma;   // phase accumulator
volatile unsigned long delta;  // phase increment
byte phase0, phase1, phase2 ;
void setup()
{
  Serial.begin(9600);        // connect to the serial port
  Serial.println("DDS Test");
  pinMode(enablePin, OUTPUT);      // sets the digital pin as output
  pinMode(testPin, OUTPUT);      // sets the digital pin as output
  pinMode(9, OUTPUT);     // pin9= PWM  output / frequency output
  pinMode(10, OUTPUT);     // pin10= PWM  output / frequency output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output
  Setup_timer2();
  Setup_timer1();
  digitalWrite(enablePin, HIGH);
// the waveform index is the highest 8 bits of sigma
// choose refclk as freq to increment the lsb of the 8 highest bits
//    for every call to the ISR of timer2 overflow
// the lsb of the 8 highest bits is 1<<24 (1LL<<24 for long integer literal)
  delta = (1LL<<24)*freq/refclk ;  
}
void loop(){
  changeFreq(20);
  delay(10000);
  changeFreq(25);
  delay(10000);
 }
void changeFreq(float _freq){
  cbi (TIMSK2,TOIE2);              // disable timer2 overflow detect
  freq = _freq;
  delta=(1LL<<24)*freq/refclk;  // update phase increment
  sbi (TIMSK2,TOIE2);              // enable timer2 overflow detect
} 
//******************************************************************
// timer2 setup
// set prscaler to 1,  fast PWM
void Setup_timer2() {
// Timer2 Clock Prescaler to : 1
  sbi (TCCR2B, CS20);  // set
  cbi (TCCR2B, CS21);  // clear
  cbi (TCCR2B, CS22);
  // Timer2 PWM Mode 
  cbi (TCCR2A, COM2A0);  // clear OC2A on Compare Match, PWM pin 11
  sbi (TCCR2A, COM2A1);
  // set to fast PWM
  sbi (TCCR2A, WGM20);  // Mode 1, phase correct PWM
  cbi (TCCR2A, WGM21);
  cbi (TCCR2B, WGM22);
  sbi (TIMSK2,TOIE2);              // enable overflow detect
}
// timer1 setup  (sets pins 9 and 10)
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer1() {
// Timer1 Clock Prescaler to : 1
  sbi (TCCR1B, CS10);
  cbi (TCCR1B, CS11);
  cbi (TCCR1B, CS12);
  // Timer1 PWM Mode set to Phase Correct PWM
  cbi (TCCR1A, COM1A0);  // clear OC1A on Compare Match, PWM pin 9
  sbi (TCCR1A, COM1A1);
  cbi (TCCR1A, COM1B0);  // clear OC1B on Compare Match, PWM pin 10
  sbi (TCCR1A, COM1B1);
  sbi (TCCR1A, WGM10);  // Mode 1  / phase correct PWM
  cbi (TCCR1A, WGM11);
  cbi (TCCR1B, WGM12);
  cbi (TCCR1B, WGM13);
}
//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// runtime : 8 microseconds ( inclusive push and pop)
// OC2A - pin 11
// OC1B - pin 10
// OC1A - pin 9
// https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
ISR(TIMER2_OVF_vect) {
  sbi(PORTD,testPin);          
  sigma=sigma+delta; // soft DDS, phase accu with 32 bits
  phase0=sigma >> 24;     // use upper 8 bits for phase accu as frequency information
                         // read value fron ROM sine table and send to PWM DAC
  phase1 = phase0 +85 ;
  phase2 = phase0 +170 ;
  OCR2A=pgm_read_byte_near(sine256 + phase0);  // pwm pin 11
  OCR1B=pgm_read_byte_near(sine256 + phase1);  // pwm pin 10
  OCR1A=pgm_read_byte_near(sine256 + phase2);  // pwm pin 9
  cbi(PORTD,testPin);            
}
Do you guys think i could get some help in implementing a similar solution for the F103? The way i imagine this is that the STM32 board would do nothing other than the PWM sine generation with a frequency determined by some kind of external signal or communicated via serial by another MCU.
Last edited by Rick Kimball on Wed Jan 16, 2019 7:29 pm, edited 1 time in total.
Reason: used the suggested embed code from ibb.co

User avatar
mrburnette
Posts: 3001
Joined: Mon Apr 27, 2015 12:50 pm
Location: Greater Atlanta
Contact:

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by mrburnette » Wed Jan 16, 2019 5:26 pm

bogdanaioane wrote:
Wed Jan 16, 2019 5:04 pm
... I got my hands on a very fancy spindle that requires frequencies of up to 1000Hz and the cheap drives i can see online seem to stop at about 3-400Hz. Also i kind of like to use this to learn and share....
Do you guys think i could get some help in implementing a similar solution for the F103? The way i imagine this is that the STM32 board would do nothing other than the PWM sine generation with a frequency determined by some kind of external signal or communicated via serial by another MCU.
http://stm32duinoforum.com/forum/viewtopic.php?t=2351
"ted" built a single phase sine wave generator that goes up to 15KHz with external filtering, but multi-phase is much more complex and may require an approach such as Magic Sine Waves. https://www.tinaja.com/glib/msinprop.pdf

Other approaches in general can be found on Google: https://www.google.com/search?q=uC+code ... sine+waves

Ray

bogdanaioane
Posts: 23
Joined: Thu Oct 04, 2018 3:46 am

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by bogdanaioane » Wed Jan 16, 2019 7:24 pm

Thanks Ray, Ill have a read through these.
I am trying to put pictures of the progress I'm making but I get an "image too large" error. surely an image under 100kb is not a large image these days. Am I doing something wrong?

User avatar
Rick Kimball
Posts: 1400
Joined: Tue Apr 28, 2015 1:26 am
Location: Eastern NC, US
Contact:

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by Rick Kimball » Wed Jan 16, 2019 7:25 pm

bogdanaioane wrote:
Wed Jan 16, 2019 7:24 pm
Thanks Ray, Ill have a read through these.
I am trying to put pictures of the progress I'm making but I get an "image too large" error. surely an image under 100kb is not a large image these days. Am I doing something wrong?
Use some picture posting site. I use imgur.com.

[edit] I see you were using a picture site, Make sure you use their suggested embed code. See what I did in your first post to fix the image.[/edit[
-rick

ted
Posts: 312
Joined: Sun Jul 16, 2017 9:57 pm

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by ted » Thu Jan 17, 2019 6:31 pm

Last edited by ted on Thu Jan 17, 2019 7:38 pm, edited 3 times in total.

ted
Posts: 312
Joined: Sun Jul 16, 2017 9:57 pm

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by ted » Thu Jan 17, 2019 6:46 pm

for square;
add 1 more timer
12.5kHZ, 90deg

Code: Select all

HardwareTimer pwmtimer3(3);
HardwareTimer pwmtimer2(2);
void setup() {
  pinMode(PA7, PWM);
  pwmtimer3.pause();
  pwmtimer3.setPrescaleFactor(1);       
  pwmtimer3.setOverflow(5760 - 1);         
  pwmtimer3.setCompare(TIMER_CH2, 2880);  
  pwmtimer3.refresh();
  pwmtimer3.resume();
  delay(50); // phase shift adjustment
  pinMode(PA3, PWM);
  pwmtimer2.pause();
  pwmtimer2.setPrescaleFactor(1);       
  pwmtimer2.setOverflow(5760- 1);          
  pwmtimer2.setCompare(TIMER_CH4, 2880);  
  pwmtimer2.refresh();
  pwmtimer2.resume();
}
void loop() {
}

ted
Posts: 312
Joined: Sun Jul 16, 2017 9:57 pm

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by ted » Thu Jan 17, 2019 7:09 pm

I see you were using a picture site, Make sure you use their suggested embed code. See what I did in your first post to fix the image.[/edit[

reduce it below 50 kb
Last edited by ted on Thu Jan 17, 2019 7:37 pm, edited 4 times in total.

ted
Posts: 312
Joined: Sun Jul 16, 2017 9:57 pm

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by ted » Thu Jan 17, 2019 7:14 pm

I think you need this, I am using them with no problems.
MTD6501C-HC1 3-Phase Brushless DC Sinusoidal Sensorless Fan Motor Driver

bogdanaioane
Posts: 23
Joined: Thu Oct 04, 2018 3:46 am

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by bogdanaioane » Fri Jan 18, 2019 9:30 am

ted wrote:
Thu Jan 17, 2019 7:14 pm
I think you need this, I am using them with no problems.
MTD6501C-HC1 3-Phase Brushless DC Sinusoidal Sensorless Fan Motor Driver
Thank you Ted, this looks very interesting.
Looking through the datasheet of the chip i can't find a reference to the output frequency of the 3 phase signal. Or is it that what it does is it takes your input signal and phase shifts it into 3 separate signals 180deg apart which would mean that whatever freq you feed into the input, it would be the output freq as well.

bogdanaioane
Posts: 23
Joined: Thu Oct 04, 2018 3:46 am

Re: 3 Phase Variable Frequency Drive VFD with F103

Post by bogdanaioane » Fri Jan 18, 2019 9:34 am

I will read through this and try to make sense of it
thank you

Post Reply