cancel
Showing results for 
Search instead for 
Did you mean: 

3 Phase sine wave generation

sanju
Senior

Hi all,

i am trying to generate a 3 phase sine wave with 120 degree phase shift by using stm32f030r8t6 nucleo board.

i can see the generated 3 phase sine wave on oscilloscope but the freq is not stable of the sine wave. it varies continuously from 40hz to 110 hz. please have a look on it and suggest me what can i do.

please find the attachment for code.

this is code of main.c file

#include "stm32f0xx.h"

#include "stm32f030x8.h"

#include "math.h"

void GPIO_Init(void);

void EXTI_Init(void);

void TIM1_Init(void);

void TIM1I_Init(void);

void UpdatePulse(void);

unsigned int i,i1=0,i2=0,i3=0,count,Ch1_DutyCycle=0,Ch2_DutyCycle=0,Ch3_DutyCycle=0,Ch1_Dir=0,Ch2_Dir=0,Ch3_Dir=0,Max_Duty=0,Start_Duty=0,Duty_Diff=0,Period=0;

unsigned int SinTable[100],SineFreq=0;

double x=0;

int main()

{

/****start PLL setting for system clock at 48Mhz using 8Mhz HSI****/

RCC->CFGR |= ((1<<19)|(1<<21)); // PLL Multification factor = 12

RCC->CFGR |= (1<<1); // PLL selected as system clock

RCC->CR |= (1<<24); // Enable / ON PLL

while((RCC->CR & (1<<25)) == 0); // Wait until PLL gets Ready

/****PLL settigs end here****/

Period = 1199; // 40khz i.e. 20 khz in center aligned mode

Max_Duty = 1080; // 90%

Start_Duty = 600; // 50%

Duty_Diff = (Max_Duty-Start_Duty);

// Generating sine table , here x is angle

x=0;

for(i=0;i<=24;i++)

{

x=x+0.062832;

SinTable[i] = Start_Duty+(Duty_Diff*(sin(x)));

}

for(i=25;i<=49;i++)

{

x=x+0.062832;

SinTable[i] = Start_Duty+(Duty_Diff*(sin(x)));

}

for(i=50;i<=74;i++)

{

x=x+0.062832;

SinTable[i] = Start_Duty+(Duty_Diff*(sin(x)));

}

for(i=75;i<=99;i++)

{

x=x+0.062832;

SinTable[i] = Start_Duty+(Duty_Diff*(sin(x)));

}

// maintaining 120 deg phase shift between 3 sine waves.

i1 = 33; // 120 degree W

i2 = 66; // 240 degree V

i3 = 99; // 0/360 degree U

GPIO_Init(); // gpio initialization

TIM1_Init(); // timer1 initialization

TIM1I_Init(); // timer 1 interrupt initialization

while(1) // infinite loop

{

}

}

void GPIO_Init()

{

RCC->AHBENR |= (1<<17); // Enable clock for GPIOA

RCC->AHBENR |= (1<<18); // Enable clock for GPIOB

GPIOA->MODER |= (1<<17); // PA8 in alternate function mode TIM1_CH1

GPIOA->OTYPER &= ~(1<<8); // PA8 as output push pull

GPIOA->OSPEEDR |= ((1<<16)|(1<<17)); // PA8 at high speed

GPIOA->PUPDR &= ~((1<<16)|(1<<17)); // PA8 no pull-up, no pull-down

GPIOA->AFR[1] |= (1<<1); // PA8 as TIM1_CH1 alternate function

GPIOA->MODER |= (1<<19); // PA9 in alternate function mode TIM1_CH2

GPIOA->OTYPER &= ~(1<<9); // PA9 as output push pull

GPIOA->OSPEEDR |= ((1<<18)|(1<<19)); // PA9 at high speed

GPIOA->PUPDR &= ~((1<<18)|(1<<19)); // PA9 no pull-up, no pull-down

GPIOA->AFR[1] |= (1<<5); // PA9 as TIM1_CH1 alternate function

GPIOA->MODER |= (1<<21); // PA10 in alternate function mode TIM1_CH3

GPIOA->OTYPER &= ~(1<<10); // PA10 as output push pull

GPIOA->OSPEEDR |= ((1<<20)|(1<<21)); // PA10 at high speed

GPIOA->PUPDR &= ~((1<<20)|(1<<21)); // PA10 no pull-up, no pull-down

GPIOA->AFR[1] |= (1<<9); // PA10 as TIM1_CH1 alternate function

GPIOA->MODER |= (1<<15); // PA7 in alternate function mode TIM1_CH1N

GPIOA->OTYPER &= ~(1<<7); // PA7 as output push pull

GPIOA->OSPEEDR |= ((1<<14)|(1<<15)); // PA7 at high speed

GPIOA->PUPDR &= ~((1<<14)|(1<<15)); // PA7 no pull-up, no pull-down

GPIOA->AFR[0] |= (1<<29); // PA7 as TIM1_CH1 alternate function

GPIOB->MODER |= (1<<1); // PB0 in alternate function mode TIM1_CH2N

GPIOB->OTYPER &= ~(1<<0); // PB0 as output push pull

GPIOB->OSPEEDR |= ((1<<0)|(1<<1)); // PB0 at high speed

GPIOB->PUPDR &= ~((1<<0)|(1<<1)); // PB0 no pull-up, no pull-down

GPIOB->AFR[0] |= (1<<1); // PB0 as TIM1_CH1 alternate function

GPIOB->MODER |= (1<<3); // PB1 in alternate function mode TIM1_CH3N

GPIOB->OTYPER &= ~(1<<1); // PB1 as output push pull

GPIOB->OSPEEDR |= ((1<<2)|(1<<3)); // PB1 at high speed

GPIOB->PUPDR &= ~((1<<2)|(1<<3)); // PB1 no pull-up, no pull-down

GPIOB->AFR[0] |= (1<<5); // PB1 as TIM1_CH1 alternate function

}

void TIM1_Init()

{

RCC->APB2ENR |= (1<<11); // Enable clock for TIM1

TIM1->PSC = 0;

TIM1->ARR = Period; // period

TIM1->CR1 |= ((1<<5)); // Center-aligned mode 1.

TIM1->CR1 |= ((1<<2)); // Only counter overflow/underflow generates an update interrupt

TIM1->DIER = 1; // Update interrupt enable

TIM1->RCR = 5; // update event after RCR+1 period

TIM1->CCMR1 |= ((1<<4)|(1<<5)|(1<<6)|(1<<3)); // TIM1_CH1 is set to pwm mode-2

TIM1->CCMR1 |= ((1<<12)|(1<<13)|(1<<14)|(1<<11)); // TIM1_CH2 is set to pwm mode-2

TIM1->CCMR2 |= ((1<<4)|(1<<5)|(1<<6)|(1<<3)); // TIM1_CH3 is set to pwm mode-2

Ch1_DutyCycle = SinTable[i1]; // 120 degree W @ start

Ch2_DutyCycle = SinTable[i2]; // 240 degree V @ start

Ch3_DutyCycle = SinTable[i3]; // 0/360 degree U @ start

TIM1->CCR1 = Ch1_DutyCycle; // Ch1 duty cycle

TIM1->CCR2 = Ch2_DutyCycle; // Ch2 duty cycle

TIM1->CCR3 = Ch3_DutyCycle; // Ch3 duty cycle

TIM1->CCER |= ((1<<0)|(1<<2)); // TIM1_CH1, TIM1_CH1N is Active, active high 

TIM1->CCER |= ((1<<4)|(1<<6)); // TIM1_CH2, TIM1_CH2N is Active, active high 

TIM1->CCER |= ((1<<8)|(1<<10)); // TIM1_CH3, TIM1_CH3N is Active, active high 

TIM1->BDTR |= (1<<15); // main output enable

TIM1->BDTR |= (1<<14); // automatic output enable

TIM1->BDTR |= ((1<<5)|(1<<4)|(1<<3)); // dead time

TIM1->EGR = 1; // Reinitialize the counter and generates an update of the registers

TIM1->CR1 |= 1; // TIM1 Counter enable

}

void TIM1I_Init()

{

 // interrupt enabling settings

__NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);

__NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);

}

void ISR()

{

UpdatePulse();

TIM1->SR = 0; // clear update interrupt flag

}

void UpdatePulse()

{

i1++;

if(i1>99)

{

i1=0;

}

Ch1_DutyCycle = SinTable[i1];

i2++;

if(i2>99)

{

i2=0;

}

Ch2_DutyCycle = SinTable[i2];

i3++;

if(i3>99)

{

i3=0;

}

Ch3_DutyCycle = SinTable[i3];

TIM1->CCR1 = Ch1_DutyCycle; // duty cycle

TIM1->CCR2 = Ch2_DutyCycle; // duty cycle

TIM1->CCR3 = Ch3_DutyCycle; // duty cycle

}

this is code of it.c file

void ISR(void);

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)

{

ISR();

}

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Hmm, I'm not sure. If ISR() is getting called at a constant rate I can't see any reason why the sine wave frequency would be changing.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

15 REPLIES 15
prain
Senior III

There is a better way for doing what you need. Check the reference​ manual; multiple timers can be synchronized to achieve exact phase difference. Or you can use a timer in conjunction with DMA to bit bang the GPIO BSRR register.

Thanks for your reply.

i am getting almost correct phase shift of 120 deg. my problem is that freq of sine wave is not constant and i am not updating freq in program.

In current program freq is varying continuously.

sanju
Senior

@TDK​ 

Dear TDK,

Can you help me here to sort out this problem.

TDK
Guru

@prain​ 

DMA doesn't have access to GPIO on the STM32F0 series.

@sanju​ 

You can't generate sine waves with a timer. You can generate square waves with 120 degree shift. Use the timer in PWM mode, set it to toggle when compare is met (OCxM=0b011). Then you just need to update the ARR and CCRx registers appropriately.

If you feel a post has answered your question, please click "Accept as Solution".

@TDK​ 

Yes, PWM can generate only square waves with desired duty cycle.

Here first i am calculating duty cycles values as per sine wave. and storing in array of size 100.

then initially i set timer1 ch1, ch2, ch3 at 120 phase shift duty cycle. and enabled the timer1 update interrupt.

my timer is set in center aligned mode. so i set rcr to odd value 5 so that every 6(5+1) pulses update interrupt generates. and in interrupt subroutine i updates the CCR!, CCR2, CCR3 values from array next index.

by this method (above programme) i can see generated 3 phase sine wave with 120 phase shift on oscilloscope .

but the issue which i am facing is that freq of generated sine wave is not stable it varies 50hz to 200hz. why it is happening even i am not changing the update interrupt rate (RCR) and ARR value. i have stuck at this point.

TDK
Guru

Okay, so duty cycle is varying between 0% and 100% over many timer updates to approximate a sine wave.

Can you measure the frequency your ISR is getting called? Is it varying between 50 Hz and 200Hz as well? It should be at a fixed rate.

Try in upcounting mode (as opposed to center aligned) to see if that's causing something odd.

If you feel a post has answered your question, please click "Accept as Solution".

@TDK 

Okay, so duty cycle is varying between 0% and 100% over many timer updates to approximate a sine wave.

Yes​(10% to 90% it is my range forming a sine wave and generated sine wave is fine with 120 phase shift only problem is it is not maintaining stable freq.)

Can you measure the frequency your ISR is getting called? Is it varying between 50 Hz and 200Hz as well? It should be at a fixed rate

ISR freq is different from sine wave because for each cycle of sine wave I have 100 times timer1 update interrupt (for first 25 interrupt duty cycle goes to 50% to 90% then next 25 duty cycle goes from 90% to 50% then next 25 (50% to 10%) and then next 25 ( 10% to 50%)) to form (positive cycle then negative cycle) and and it repeats

for debugging purpose I have used a pin PA5 as it toggles whenever ISR is called

i will measure by tomorrow that at what freq it toggles, Yes it should be stable.

Try in upcounting mode (as opposed to center aligned) to see if that's causing something odd.

T​hanks for this suggestions I was also thinking about it to try.

I will try it by tomorrow.​

Thank you once again for your helping nature.​

0693W000003PA6uQAG.jpg0693W000003PA6pQAG.jpg0693W000003PA6kQAG.jpg0693W000003PA6aQAG.jpg0693W000003PA62QAG.jpg0693W000003PA6QQAW.jpg@TDK​ 

Here i have attached some pictures of CRO which is showing that ISR calling freq is stable but generated sine wave freq is varying.

i have tested program first with RCR=15 i.e. at every 16(15+1) update interrupt isr will be called

second with RCR=5 i.e. at every 6(5+1) update interrupt isr will be called

both case shows that sine wave freq is not stable but isr routine freq is stable.

i have took picture of just one sine wave out of 3 phase.

i have tried timer in up counting mode instead of center aligned mode but situation remains same.

TDK
Guru

Hmm, I'm not sure. If ISR() is getting called at a constant rate I can't see any reason why the sine wave frequency would be changing.

If you feel a post has answered your question, please click "Accept as Solution".