3 Phase Variable Frequency Drive VFD with F103

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:

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);

}


mrburnette
Wed Jan 16, 2019 5:26 pm
[bogdanaioane – 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://stm32duino.com/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
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?

Rick Kimball
Wed Jan 16, 2019 7:25 pm
[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?

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[


ted
Thu Jan 17, 2019 6:31 pm
For sine
https://www.stm32duino.com/viewtopic.ph … 0&start=30

ted
Thu Jan 17, 2019 6:46 pm
for square;
add 1 more timer
12.5kHZ, 90deg
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
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


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
Fri Jan 18, 2019 9:30 am
[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

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
Fri Jan 18, 2019 9:34 am
[ted – Thu Jan 17, 2019 6:31 pm] –
For sine
https://www.stm32duino.com/viewtopic.ph … 0&start=30

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


bogdanaioane
Fri Jan 18, 2019 9:37 am
[Rick Kimball – Wed Jan 16, 2019 7:25 pm] –

[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?

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[

That helps,
I will upload some pics of the work in progress. Is it useful/allowed to show circuit schematics or should i stick to the stm32 bit only?


ted
Fri Jan 18, 2019 5:02 pm
ImageMTD6501C-HC1

You don’t need a generator it is inside the chip, so you connect the motor directly to it. The only one think you need to consider – how big is your motor = the current of the motor.


bogdanaioane
Fri Jan 18, 2019 7:24 pm
From what i can see in the datasheet, this chip generates a set of 3 square wave signals 180ged out of phase with each other based on the frequency of the input square wave. If this is the case it is not much use to me as i need a modulated sin wave to be able to smoothly run my motor. the motor im working with is a 3.8Kw AC motor but that is another issue for which i believe i have a solution in terms of IGBTs and drivers.
I will read the topic you linked in one of your previous replies as i think one of those is very close to what I am trying to accomplish

ted
Fri Jan 18, 2019 10:38 pm
So for this power you need 3 phase sine inverter, the speed of the motor you can regulate by frequency or by PWM, in first case you can use my sine generator , frequency is changing by number here <#define SAMPLES 100>, in second case you can use MTD6501C-HC1 connected to small 3 phase motor and take the 3 sine signals from pins 4,5,7 for inverter , the speed is controlled by PWM on pin 10, without small motor there is no signals on pins 4,5,7.

MTD6501C-HC1
produce 3 sine waves shifted 120 deg that what I sow on scope, 180 deg I think it is something else, you can’t have 3 phase shifted by 180 deg because the third one will be the same as the first.

https://www.amazon.ca/Variable-Frequenc … 2793&psc=1


bogdanaioane
Sat Jan 19, 2019 10:00 am
I did think that the 180deg was a bit strange in the datasheet but as you say, maybe it refers to something else.
Thanks for the link for the inverter. This is pretty much what I’m trying to build but at a higher frequency. It would be great if i could find something like that that goes up to 1Khz.
I will be playing with your sine generator this weekend. I have already tried it as is and get a full sinewave at about 7KHz but the 3 signals are not quite 120 deg out of phase but that I’m sure is fixable. The first thing i would like to do is see if instead of a full sinewave i can produce only half
Something like this
Image
and after filtering..
Image
Then… i will have to toggle another pin at each “zero crossing” of the sine wave.
Something like this.
Image
I will start working on it today and hopefully i can make some progress although I must admit I am a bit intimidated by the look of the code of your sine generator. (as i said at the beginning.. I’m not quite there yet) so any advice will be greatly appreciated.

ted
Sat Jan 19, 2019 12:52 pm
don’t forget mentioned square wave generator it is simple and easier to adopt for your needs, using MAX 7410 filter you get nice sine, the example how to change the with of it is here so you nee to apply this metode for overflow line, …….
viewtopic.php?t=3752
you need to create an algorithm for delay because it is depends to frequency.

ted
Sat Jan 19, 2019 12:56 pm
[bogdanaioane – Sat Jan 19, 2019 10:00 am] –

Something like this.

actually with MAX 7410 you ok with any shape of the signals, just shifted 120 deg


bogdanaioane
Sat Jan 19, 2019 1:20 pm
A simple square wave generator will not work. It must be a modulated sine. I’m only showing a filtered output for ease of explanation and to check the quality of the sine, but in fact having an analog sine wave like the filtered one is not useful as I have to pass that through a galvanic isolation barrier and recondition it to drive a set of IGBTs. I have made all of this work in my concept stage but I’m now thinking that using a dma implementation like yours I might get the max frequency of 1KHz i need.

This is ultimately what I’m after:
Image

The two signals are essentially the positive and the negative halves of a sine wave. I obtained these by toggling an additional pin at teh beginning of every pass through the “half sine” array and passing that with the signal from one of the channels through some logic gates like i showed in my original post.

I am trying to understand the code in your sine application and have lots to read before I can make anything happen but it would be helpful if you could explain the config in your code below

timer_dma_set_base_addr(dev1, TIMER_DMA_BASE_CCR2);
timer_dma_set_burst_len(dev1, 1);
timer_dma_enable_req(dev1, PIN_MAP[out1].timer_channel);
timer_set_reload(dev1, 102);
timer_set_prescaler(dev1, 0);


ted
Sat Jan 19, 2019 1:46 pm
You overlooked function of MAX = very good filter,…………………………
The code was assembled using existing programs and I didn’t go through details.
In my program lower frequency = higher quality of sine. For 7200 Hz you have 100 samples for 720 Hz 1000 samples for 360 Hz 2000 samples rate. For galvanic isolation use optocoupler, because it is hard to find a linear one, use the filter after isolation.

RogerClark
Sat Jan 19, 2019 8:44 pm
If your primary goal is to build a 3 phase variable frequency generator, IMHO you would be better off using a SI5351 clock generator to actually generate the 3 sine waves

The SI5351 is a clock generator IC with 3 outputs, but it generates square waves.

However some simple analog filtering would produce a reasonably accurate since wave.

You would still need a microcontroller to setup and control the SI5351, but the major workload would be removed from the microcontroller

Ps SI5351 modules are available for less than $10 from places like AliExpress and even Adafruit sell them ( but not so cheaply )

If you don’t want to have to filter square waves from the SI5351 you could use 3 AD9850 modules, but they are much more expensive, and you would have to work out how to feel the master clock from one of the modules into the other 2 so that they are all in phase


bogdanaioane
Sat Jan 19, 2019 9:22 pm
Thanks Roger,
The issue with any sort of generator that eventually gives me an analog sinewave is that this signal essentially cannot be used for the purpose of driving IGBTs for high power motor applications, The signal needs to be a series of pulses the width of which is modulated into a sine wave that can be passed through an isolation barrier and into a driver for IGBTs or maybe MOSFETs such that, on the high voltage/power side, if we install a high voltage low pass filter we get a close to true sine wave. At these sort of voltages it is very important that the sine wave is as close to true as possible, otherwise there will be huge losses and motor issues. I have looked into some standalone chips like the ones you are suggesting but the problem remains that there is not much I can do with the signal they generate as i don’t know how (or even if its possible) to decompose the signal back into a PWM and Enable signals that i can use for the drivers of the FETS or IGBTs.

I have been working all day on this and managed to make some progress.

here is the code so far:
#include <Arduino.h>

PROGMEM const uint16_t Half_Sine_A[] = {
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
};

PROGMEM const uint16_t Half_Sine_B[] = {
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
};

PROGMEM const uint16_t Half_Sine_C[] = {
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
886 , 873, 858, 843, 828, 812, 795, 778, 760, 742, 724, 704, 685, 665, 644, 623, 601, 579, 557, 535,
512 , 488, 464, 440, 416, 391, 366, 341, 316, 290, 265, 239, 212, 186, 160, 133, 107, 80, 53, 26,
0 , 26, 53, 80, 107, 133, 160, 186, 212, 239, 265, 290, 316, 341, 366, 391, 416, 440, 464, 488,
512 , 535, 557, 579, 601, 623, 644, 665, 685, 704, 724, 742, 760, 778, 795, 812, 828, 843, 858, 873,
886 , 899, 912, 924, 935, 946, 955, 965, 973, 981, 989, 995, 1001, 1006, 1011, 1015, 1018, 1020, 1022, 1023,
1024, 1023, 1022, 1020, 1018, 1015, 1011, 1006, 1001, 995, 989, 981, 973, 965, 955, 946, 935, 924, 912, 899,
};

int PhaseA_OUT = PA8; // TIM1_CH1 pwm output for phase A sine wave
int PhaseB_OUT = PA9; // TIM1_CH2 pwm output for phase B sine wave
int PhaseC_OUT = PA10; // TIM1_CH3 pwm output for phase C sine wave

HardwareTimer CarrierTimer(1);

void setup() {
CarrierTimer.setPrescaleFactor(1);
CarrierTimer.setOverflow(1024);

pinMode(PhaseA_OUT, PWM);
pinMode(PB3, OUTPUT);
pinMode(PB4, OUTPUT);

pinMode(PhaseB_OUT, PWM);
pinMode(PB5, OUTPUT);
pinMode(PB6, OUTPUT);

pinMode(PhaseC_OUT, PWM);
pinMode(PB7, OUTPUT);
pinMode(PB8, OUTPUT);

}

void loop() {
for(int i=0; i<240; i++){
pwmWrite(PhaseA_OUT, Half_Sine_A[i]);
pwmWrite(PhaseB_OUT, Half_Sine_B[i]);
pwmWrite(PhaseC_OUT, Half_Sine_C[i]);
if(i>=0 & i<120){
GPIOB->regs->ODR |= (1<<3); //Set pin PB3 High
GPIOB->regs->ODR &= ~(1<<4); //Set pin PB4 Low
}else{
GPIOB->regs->ODR &= ~(1<<3); //Set pin PB3 Low
GPIOB->regs->ODR |= (1<<4); //Set pin PB4 High
}

if(i>=40 & i<160){
GPIOB->regs->ODR |= (1<<5); //Set pin PB5 High
GPIOB->regs->ODR &= ~(1<<6); //Set pin PB6 Low
}else{
GPIOB->regs->ODR &= ~(1<<5); //Set pin PB5 Low
GPIOB->regs->ODR |= (1<<6); //Set pin PB6 High
}

if(i>=80 & i<200){
GPIOB->regs->ODR |= (1<<7); //Set pin PB7 High
GPIOB->regs->ODR &= ~(1<<8); //Set pin PB8 Low
}else{
GPIOB->regs->ODR &= ~(1<<7); //Set pin PB7 Low
GPIOB->regs->ODR |= (1<<8); //Set pin PB8 High
}

delay_us(100);
}

}


RogerClark
Sat Jan 19, 2019 11:30 pm
OK

I thought you needed a pure sine wave, but if you effectively have class C or class D power amplifier, I can see that you need PWM of the sine wave and not a sine wave its self.

Re: Changing the frequency

Its not my area of expertise, but I thought there were standard methods of varying the frequency of the sine wave produced from a wave table.

From memory, one of the ways is to have a very detailed table, and depending on the frequency that is required, you skip one or more samples in the table.
But I think this requires that the “skip” value be calculated for each sample, because it has to be dithered to produce enough granularity in the frequencies that can be produce.

I’m sure someone wrote a library (which they posed a link to here), which did some clever processing to do something like that, but only a single channel.

I’m sure someone could tell you about that library, (they may have already posted a link)


ted
Sat Jan 19, 2019 11:46 pm
Unusual approach and unusual results, in my square generator the frequency can be changed by those two lines
pwmtimer3.setPrescaleFactor(1); // Timer input clock Prescaler = 1 (= 72MHz input ?)
pwmtimer3.setOverflow(100-1);

ted
Sat Jan 19, 2019 11:59 pm
I have somewhere russian version for Arduino Uno , which do exactly what you need. I will look for it.

bogdanaioane
Sun Jan 20, 2019 12:33 am
There might be some confusion here… so just to clarify
There are 2 separate frequencies here. One is the frequency of the PWM itself that is set by these two lines
CarrierTimer.setPrescaleFactor(1);
CarrierTimer.setOverflow(1024);

bogdanaioane
Sun Jan 20, 2019 12:33 am
[ted – Sat Jan 19, 2019 11:59 pm] –
I have somewhere russian version for Arduino Uno , which do exactly what you need. I will look for it.

That would be great
Thanks


ted
Sun Jan 20, 2019 2:01 am
I checked with oscilloscope, regardless the numbers in mentioned lines the frequency is the same all the time, sine 80Hz, square 40Hz. For nanosec delay google = nanoseconds delay arduino , stm32 nanoseconds delay and similar.

ted
Sun Jan 20, 2019 2:08 am
Russian version, use google translate, if you have problem with that I can help.
3 signals with adjustable phase shift, adjustable frequency, adjustable duty ratio.

void setup() {
// подпрограмма инициализации
// Serial.begin(9600); //для наладки
pinMode(2,OUTPUT); //ножка порта фазы A
pinMode(3,OUTPUT); //ножка порта фазы B
pinMode(4,OUTPUT); //ножка порта фазы C

digitalWrite(2,LOW); //снять сигнал с порта
digitalWrite(3,LOW);
digitalWrite(4,LOW);

//Serial.println("Start");
}

void loop() {
// подпрограмма основного цикла
long PhA = 0; //счетчик-таймер фазы A
long PhB = 0; //счетчик-таймер фазы B
long PhC = 0; //счетчик-таймер фазы C
long TAU = 180*3; //полупериод меандра (уменьшать для увеличения частоты)
char GoA = 1; //флаг разрешение работы фазы A
char GoB = 0; //флаг разрешение работы фазы B
char GoC = 0; //флаг разрешение работы фазы C

//long TestTime = 0; //для наладки

while(1){
//TestTime += 1;
//delay(100); //задержка для последовательного порта и ограничения кол-ва данных в маткад
//Serial.print(digitalRead(2));Serial.print(",");
//Serial.print(digitalRead(3));Serial.print(",");
//Serial.print(digitalRead(4));Serial.print(",");
//Serial.println(TestTime); //строка в мониторе имеет вид A,B,C,time, где А, B, C - состояние ножки порта

if(GoA) PhA += 1; //начать отсчет по фазе
if(GoB) PhB += 1;
if(GoC) PhC += 1;

if(PhA == 1) {digitalWrite(2,HIGH);} //установить импульс в фазе A
if(PhB == 1) {digitalWrite(3,HIGH);} //установить импульс в фазе B
if(PhC == 1) {digitalWrite(4,HIGH);} //установить импульс в фазе C

if(PhA == TAU) {digitalWrite(2,LOW);} //снять импульс в фазе A (вот здесь изменять длину импульса - число вместо TAU)
if(PhB == TAU) {digitalWrite(3,LOW);} //снять импульс в фазе B
if(PhC == TAU) {digitalWrite(4,LOW);} //снять импульс в фазе C

if(PhA == 2*TAU) PhA = 0; //период фазы = начало нового цикла (360 градусов)
if(PhB == 2*TAU) PhB = 0;
if(PhC == 2*TAU) PhC = 0;

if((PhA > 0.667 * TAU) && (GoB == 0)) GoB = 1; //фазовый сдвиг задавать множителем (например 0.167 ~= 30 градусов)
if((PhB > 0.667 * TAU) && (GoC == 0)) GoC = 1;

}

}


RogerClark
Sun Jan 20, 2019 2:15 am
Assuming the code works at all…

Looking at the “while” loop code in the loop() function, I was surprised that it didn’t have any code which appears to measure how long the while loop instruction took to execute.

You may find that it doesn’t work the same on the STM32 as its a ARM processor, and the compiler and the ARM branch instruction (for the if’s ) may cause strange timing problem.

Of course digitalWrite() isn’t that fast, and you would probably be better off directly accessing the GPIO output register or the BSSR register.


ted
Sun Jan 20, 2019 2:24 am
This code should work up to 1.5kHz as far I remember author claims on uno, STM32 is much faster.

bogdanaioane
Sun Jan 20, 2019 9:34 am
Thanks
Ill give it a go today.
I looked for nanoseconds delay for arduino and STM32 but came up short. I tried the asm volatile (“nop”) but got a compilation error. if you have any suggestions it would be great.

ted
Sun Jan 20, 2019 12:10 pm
Frequency problem
Try to use 3 different timers = separate for each channel

bogdanaioane
Sun Jan 20, 2019 6:42 pm
I’m at the end of my rope with this.
It is especially frustrating due to the fact that i am so close to what i need and still not quite there.
The way I see it if i could update 2 variables in the main loop without impacting the processing speed i would have it.
It looks like UART with DMA is the solution but i don’t know how to implement it.
Can you guys point me in the direction of an example of receiving an int via serial using DMA?
All the best

ted
Sun Jan 20, 2019 8:04 pm
Adjustment of the phase in my program = this line
val2[i] = 50 + amp * sin( stp * i + shift * 6.2831 / 360);

mrburnette
Sun Jan 20, 2019 9:43 pm
[ted – Sun Jan 20, 2019 8:04 pm] –
Adjustment of the phase in my program = this line
val2[i] = 50 + amp * sin( stp * i + shift * 6.2831 / 360);

ted
Sun Jan 20, 2019 9:50 pm
Yes boss, LOL
I just pasted one line of the code

bogdanaioane
Mon Jan 21, 2019 12:03 am
Ted,
The sine wave generator you shared would not be suitable for my application. Its not just a 3 sinewaves I am after. If it were i would just use a specialized chip. what is needed for this type of design is 9 signals in total, all synchronized in terms of phase. 3 of these signals are the 3 phases of the sine itself (and since the final signal should be symmetrical across GND half a sinewave is more useful than a full wave)
like this..
Image

what would be the negative side of the sine has been flipped. this way the center of the sine is still referenced to ground and any amplitude control works very well and also it makes it much easier to split this flipped sine type signal into positive half sine and negative half sine using the rest of 6 signals that are needed 2 for each phase.

the result after splitting the positive and negative half sines.
Image
Note CH1 is flipped to better show the sine form.

also i cannot see a way to program the enable signals for the IGBT drivers that would be in perfect sync with the 3 output sines ( I guess i could do it analogically with some schmitt triggers and comparators but that would defeat the purpose of using a mcu altogether)

I have been playing with my code and design to see the symmetry and stability of the outputs but with only a 2 channel scope and 6 signals to measure i had to overlay multiple pictures in photoshop to show the output I’m getting.
which is this..
Image

everything works nice except the fact that the max frequency i can get while doing two analog reads (one for amplitude and one for freq) is 415Hz. If i do not do any ADC the max frequency i get is 1.19KHz which is where i hope and pray that i can somehow use DMA for UART to send the variables for freq and ampl to the STM32.
i found this article but it is above my level of understanding
http://stm32f4-discovery.net/2017/07/st … using-dma/
Can someone please help me with this?
Thanks


ted
Mon Jan 21, 2019 1:05 am
I see no reason why my program cannot be symmetrical, and why this is important. So you are using those 6 additional signal to create full sine, the question is why not to use full sine from beginning , the problem with symmetry ?
The brushless motor Nidec 22H67 has 380 Hz @ 2400 rpm may by your 415Hz it is enough, unless you meed much higher RPM.

I am not familiar with linked stuff.
May be go to next step = IGBTs and make tests with the motor ?

Comparing Nidec(square wave ) and motor running on MTD6501C-HC1 (sine wave) the second one is running much smoother but this are small motors, to make Nidec working better I added to it a flywheel. In my case the smooth was main factor (Less than 0.1deg vibration), I dont think you need such precision.


bogdanaioane
Mon Jan 21, 2019 10:24 am
So you are using those 6 additional signal to create full sine
No I’m not. The 6 signals in combination with the 3 sine wave signals, are needed to control the 6 gates in the 3 phase H-Bridge.
Image
It could also work with 3 signals by using a different type of driver i guess.
But the question remains,
How can i accomplish this with your code for the sine generator?
do you have a schematic of how you drive your motor from your code?

the question is why not to use full sine from beginning , the problem with symmetry ?
because a full sine wave is not useful to drive the gates/drivers directly. I still need to break it into separate signals for the high side and the low side of the H bridge and to do that i need at least another signal that is in sync with the sine (I could accomplish this analogically but that, like I said, would negate the use of a MCU entirely and would be more complicated I think) In addition the need for symmetry and synchronization is much greater in a VFD of this type than say in a low voltage BLDC. (if there are problems you get unwanted losses and lower rpms in a BLDC but in a 240V AC motor you trip the breaker at best or start a fire at worst.)
The brushless motor Nidec 22H67 has 380 Hz @ 2400 rpm may by your 415Hz it is enough, unless you meed much higher RPM.
My motor is a 3.8Kw mains powered AC motor with a top speed of 40,000RPM

May be go to next step = IGBTs and make tests with the motor ?
I agree.

I do hope that someone here knows how to receive data via UART using DMA or maybe ADC using DMA??


stevestrong
Mon Jan 21, 2019 10:53 am
Maybe is this post interesting for you: viewtopic.php?f=18&t=2743

bogdanaioane
Mon Jan 21, 2019 11:07 am
[stevestrong – Mon Jan 21, 2019 10:53 am] –
Maybe is this post interesting for you: viewtopic.php?f=18&t=2743

Thanks That looks very clever.
And reinforces my belief that DMA is the way to go for me.
I found this post viewtopic.php?f=48&t=4399&p=51439&hilit=adc+dma#p51439 but it goes a bit over my head.


stevestrong
Mon Jan 21, 2019 12:10 pm
There are some ADC + DMA examples in my repo for F4, you could maybe port them to F1.

But be warned, several DMAs running simultaneously could eventually disturb each other.


ted
Mon Jan 21, 2019 12:15 pm
Image

ted
Mon Jan 21, 2019 12:31 pm
Don’t bother about quality of the sine, on oscilloscope;
Nidec has distortion on both edges of square wave, MTD6501C-HC1 is like trapeze not a pure sine.

Comparing the noise, Nidec is noisily (acoustic noise) , MTD6501C-HC 1 is very quiet = you can hear almost nothing even if you put ear to the body of the motor.

You can to this;
PWM to optocoupler > to gate of IGBT > to motor.
You don’t need high voltage filters, inductance of the motor will do that.


ted
Mon Jan 21, 2019 12:36 pm
Don’t forget a big diode between emitter / collector

bogdanaioane
Mon Jan 21, 2019 12:51 pm
[stevestrong – Mon Jan 21, 2019 12:10 pm] –
There are some ADC + DMA examples in my repo for F4, you could maybe port them to F1.

That is very helpful thank you.
I have never ported code before but will get reading. Is it a complex procedure? I assume it is mostly about editing the STM32F4ADC.h?? Do you have any advice? or is it too much for a beginner like me to do?

But be warned, several DMAs running simultaneously could eventually disturb each other.
Ideally i would like to read two ADC channels but if it comes to it one would also be enough.


stevestrong
Mon Jan 21, 2019 1:05 pm
F4 DMA porting to/from F1 is not quite a trivial process, since the HW structures behind are different.
You have to dig deep, with the help of both reference manuals.

OTOH, DMA examples can be found in SPI library for F1.
For soft PWM output it has to be triggered by timer, and the destination address must be adapted as well.
If you have that, using DMA for ADC should not be that difficult, rather a good exercise.

But all these you have to do by yourself, I cannot do that due to lack of time.


bogdanaioane
Mon Jan 21, 2019 2:33 pm
I understand.
I had a “look” through the library. It, unfortunately for me, is more than i can understand so I doubt i could port the code myself. I will keep looking for examples of ADC or UART with DMA for the F1.
Another option i guess would be to use an F4 board instead. Is there a bluepill type board with an F4 chip?

stevestrong
Mon Jan 21, 2019 2:43 pm
small F4 boards: https://stm32duino.com/viewtopic.php?f=39&t=1977

FCam1
Tue Mar 05, 2019 2:21 pm
I don’t know if you are always looking for a DMA UART TX example but I did that few month ago for a F103ZET6 : https://www.stm32duino.com/viewtopic.ph … art#p47489

bogdanaioane
Tue Mar 05, 2019 2:38 pm
[FCam1 – Tue Mar 05, 2019 2:21 pm] –
I don’t know if you are always looking for a DMA UART TX example but I did that few month ago for a F103ZET6 : https://www.stm32duino.com/viewtopic.ph … art#p47489

Thank you
I will have a read.
Have you encountered a RX example anywhere. In my case i would need to only receive but I’m hoping that i can work it out using your example.


FCam1
Tue Mar 05, 2019 4:51 pm
Have you encountered a RX example anywhere
Some examples using DMA with ADC : https://github.com/rogerclarkmelbourne/ … C/examples

dannyf
Sat Mar 16, 2019 12:51 pm
i’m late to the discussion but it seems to be a fairly simple issue:

assuming that you need digital sine output (=pwm), not analog sine output.

here is what I would do.

1) have a sine duty table. 256 points for example. use a phase accumulator to index it.
2) set up 3 pwm output channels, ch1–3.
3) set up a timer interrupt and is invoked periodically.
4) in the timer isr, set ch1’s duty cycle based on the duty table, indexed at accumulator; ch2’s duty cycle indexed to accumulator + 256/3, and ch3’s duty cycle indexed to accumulator + 256*2/3.

with this approach, your main() loop is empty.

if you really need analog output, put a lpf on each of the digital output channels.


dannyf
Sat Mar 16, 2019 12:52 pm
BTW, it is possible to use one of the pwm channels for timing as well.

ted
Sat Mar 16, 2019 1:50 pm
[dannyf – Sat Mar 16, 2019 12:51 pm] –

1) have a sine duty table. 256 points for example. use a phase accumulator to index it ?

You mean use 3 tables, two of them shifted ± 120 deg ?
I saw something like that somewhere.


dannyf
Sat Mar 16, 2019 2:00 pm
why use 3 tables when 1 can do?

ted
Sat Mar 16, 2019 2:36 pm
Because with one table I see the guys have a problem

dannyf
Sat Mar 16, 2019 3:03 pm
if you cannot make 1 table work, use 3 tables then.

ted
Sat Mar 16, 2019 3:24 pm
If one table can not do 3 tasks, use 3 table, 1 task for each.
The idea is simple, use 360 point table, each point is 1 deg.
Example for 10 deg. shift; remove 10 first points from table and put them on the end in reverse order.

fredbox
Sat Mar 16, 2019 3:42 pm
[dannyf – Sat Mar 16, 2019 2:00 pm] –
why use 3 tables when 1 can do?

Many years ago (probably around 1990) I remember that the programmers only used the first 90 degrees of one sinewave in a table to create three phases.


Leave a Reply

Your email address will not be published. Required fields are marked *