2020-07-27 02:44 AM
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();
}
Solved! Go to Solution.
2020-08-12 06:20 AM
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.
2020-07-27 03:09 AM
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.
2020-07-27 09:50 PM
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.
2020-08-09 09:28 PM
@TDK
Dear TDK,
Can you help me here to sort out this problem.
2020-08-10 06:03 AM
@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.
2020-08-10 09:41 PM
@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.
2020-08-11 05:53 AM
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.
2020-08-11 10:14 AM
@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.
Thanks 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.
2020-08-12 04:37 AM
@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.
2020-08-12 06:20 AM
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.