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

}

15 REPLIES 15

In the ISR, check if TIMx_SR has the update flag set, and execute rest of ISR only if it has.

JW

@Community member​ 

Ok i will try it.

With your help in the past my problems was solved on stm32f0, Thanks for this reply.

@Community member​ 

I changed interrupt handler

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)

{

ISR();

}

to

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)

{

if((TIM1->SR & 0x0001) != 0)

{

ISR();

}

}

nothing changed in output sine wave and, sine wave freq still varying.

Msd.1
Associate II

Sanju, There's two point in your code:

First, define variables that used in interrupt routines as volatile.

Second, for a 50 Hz sine wave with 100 samples, your sampling rate is 5000 Hz. and in your pictures your ISR frequency is very low. And in reality you should have 15 to 20 PWM pulse for each sample to have a stable PWM , if you have 16 pulse for each sample you need 5000 x 16 = 80,000 PWM frequency. For test you reduce Period to 599 so PWM frequency is 80,000 Hz. Adjust samples value by divide them by 2, and test again. also send us PWM signal picture too if possible.

@Msd.1​ 

in my program whenever the ISR is called it toggles a pin PA5 (which is shown by green pulses in image) to debug the ISR calling freq.

So to be noted here that ISR toggles PA5 at each calling and update PWM duty cycle to form the sine wave.

to form a single pulse of sine wave there are 100 samples means ISR will be callled 100 times for one pulse of sine wave and PA5 will be toggled 100 times (100 times toggles makes 50 pulses).

so it means for every 50 pulses of PA5 (green color waveform) one pulse of sine wave will be generated.

if i notice from images there is two types of images (one for RCR=5 and Second one for RCR = 15)

CASE 1:

for RCR =5 freq is showing 3.32khz i.e. 3320hz.

so sine wave freq should be 3320/50 = 66.4hz

CASE 2:

for RCR =15 freq is showing 1.25khz i.e. 1250hz.

so sine wave freq should be 1250/50 = 25hz.

when this will be ok i will set program for different freq. my project is not to generate sine wave of 50hz it is to drive DC servo motor.

Note: PA5 is not in above program but it is in the conversation held already.

sanju
Senior

@Laurent Ca...​ 

Can you have a look at this.