Hello.
Im creating a motor controller for a 3 phase AC motor.
I'm having a lot of difficulty with generating the correct pwm signals. I need to generate a signal with 10kHz frequency, the period must be center aligned, and I need to update the duty cycle every 10kHz.
I tried this using analogWrite, but the pwm signales where shifted, and only left aligned. So I went on the great internet in search for some help and found some code of interest. The problem I have with this code is that when I try to update the duty cycle the pwm signal ends up as a giant noisy blur. It seems like it doesnt reset properly and write the new duty cycle. Any help would be much appreciated!
//Encoder library
#include <Encoder.h>
// Black magic, function for setting up timers
void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)irq);
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
TC_SetRC(tc, channel, rc);
TC_Start(tc, channel);
tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
NVIC_EnableIRQ(irq);
}
//assigning pins to variables
int aPin=59;
int bPin=58;
int cPin=57;
int vfcPin=55;
int ibuckPin=62;
int ipmsmPin=60;
int iscPin=61;
int pwmbuckPin=4;
int pwmtisPin=0;
int pwmaPin=6;
int pwmbPin=8;
int pwmcPin=9;
int pwmostPin=0;
int pwmpikPin=0;
//int enablebuckPin=3;//not assigned on the physical board yet
int encA=30;//30 on new board.
int encB=28;//28
int encZ=26;//26
//int pwmfcPin=2;
int lemref=66;
//declaring variables used for calculations and I/O
volatile int a=0;
volatile int b=0;
volatile int c=0;
volatile int oldPos= -999;
volatile int newPos= 0;
volatile int enablebuck=0;
volatile int da=0;
volatile int db=0;
volatile int dc=0;
volatile int dbuck=0;
volatile int ibuck=0;
volatile int iboost=0;
volatile int iq=0;
volatile int id=0;
volatile int ia,ib,ic;
volatile int vqc=0;
volatile int vdc=0;
volatile int pos=0;
int idref=0;
volatile int iqref = 0.5*10000;
volatile int k=0;
int i=0;
int kpdq=2;
int kidq=1000;//1250
int kpspeed=0;
int kispeed=0;
int Ts=1;//0,00004 s (1/25 kHz) scaled
volatile int vd,vq;
volatile int prevvd,prevvq,preverrd,preverrq,va,vb,vc,ysat,prevysat,ysatd,ysatq,prevysatd,prevysatq,vdaw,vqaw,errord,errorq,vdint,vqint,errordold,errorqold,errordaw,errorqaw,errordawold,errorqawold=0;
int kaw=200;
//Look up table for cosine/sine function
int table[]={10000,9998,9994,9986,9976,9962,9945,9925,9903,9877,9848,9816,9781,9744,9703,9659,9613,9563,9511,9455,9397,9336,9272,9205,9135,9063,8988,8910,8829,8746,8660,8572,8480,8387,8290,8192,8090,7986,7880,7771,7660,7547,7431,7314,7194,7071,6947,6820,6691,6561,6428,6293,6157,6018,5878,5736,5592,5446,5299,5150,5000,4848,4695,4540,4384,4226,4067,3907,3746,3584,3420,3256,3090,2924,2756,2588,2419,2250,2079,1908,1736,1564,1392,1219,1045,872,698,523,349,175,0};
//setup:
//*Assigning pins as either input or output
//*starting timers
void setup(){
//asssigning pinmodes
pinMode(aPin,INPUT);
pinMode(bPin,INPUT);
pinMode(cPin,INPUT);
pinMode(vfcPin,INPUT);
pinMode(pwmaPin,OUTPUT);
pinMode(pwmbPin,OUTPUT);
pinMode(pwmcPin,OUTPUT);
pinMode(pwmbuckPin,OUTPUT);
pinMode(ipmsmPin,INPUT);
pinMode(ibuckPin,INPUT);
pinMode(encZ,INPUT);
attachInterrupt(encZ,reset,RISING);
analogWrite(lemref,127);
//More timer fun!
ADC->ADC_WPMR=0x00; //disable write protection on MR
ADC->ADC_MR |= 0x200080; //set ADC in free running mode and settling time is 9 times ADC clock
ADC->ADC_CR=2; //enable ADC clock
ADC->ADC_CHER=0x1FF; //enable A0->A7+A8
startTimer(TC1, 0, TC3_IRQn, 10000);//timer for pwm write inverter and sync buck
startTimer(TC1, 1, TC4_IRQn, 10000); //timer for reading analog inputs and calculating duty cycles
}
Encoder myEnc(encA,encB);
void loop(){
newPos = myEnc.read();
if (newPos != oldPos){
oldPos=newPos;
pos=0.0439*2*newPos; //(360/2000) From pulses to degrees
}
}
void TC4_Handler()
{
TC_GetStatus(TC1,1);
while((ADC->ADC_ISR & 0x1FF)!=0x1FF);//waiting for data on A0-A8
a=ADC->ADC_CDR[2]; //read data on A5 pin
b=ADC->ADC_CDR[3]; //read data on A4 pin
c=ADC->ADC_CDR[4]; //read data on A3 pin
//scale measerued signals
ia=(129*a-270000)/100;
ib=(129*b-270000)/100;
ic=(129*c-267000)/100;
//Park transformation, from adc to dq0 ref system
//id and iq are scaled with 10000
id=(67*(cosinus(pos)*ia+cosinus(pos-120)*ib+cosinus(pos+120)*ic))/10000;
iq=(67*(-cosinus(90-pos)*ia-cosinus(90-pos-120)*ib-cosinus(90-pos+120)*ic))/10000;
//scale down id and iq to be 10000 times actual value (instead of 10^8 timesactual value)
//PI controller with anti windup
errord=0-id;
vdint=vdint+(kidq/100)*(errord)+100*kpdq*(errord-errordold)+(kaw/200)*(errordaw+errordawold);
vd=vdint;
errordawold=errordaw;
errordold=errord;
if(vd>28000000){
errordaw=28000000-vd;
vd=28000000;
}
else if(vd<-28000000){
errordaw=-28000000-vd;
vd= -28000000;
}
else{
errordaw=0;
}
errorq=iqref-iq;
vqint=vqint+(kidq/100)*(errorq)+(kaw/200)*(errorqaw+errorqawold)+100*kpdq*(errorq-errorqold);
vq=vqint;
errorqawold=errorqaw;
errorqold=errorq;
if(vq>28000000){
errorqaw=28000000-vq;
vq=28000000;
}
else if(vq<-28000000){
errorqaw=-28000000-vq;
vq= -28000000;
}
else{
errorqaw=0;
}
//scaling vd and vq down to 100 times actual value
vdc=vd/10000;
vqc=vq/10000;
//dq0 to abc (inverse park transformation)
//va,vb,vc is calculated 10^6 times bigger than actual value
va=cosinus(pos)*vdc-cosinus(90-pos)*vqc;
vb=cosinus(pos-120)*vdc-cosinus(90-pos-120)*vqc;
vc=cosinus(pos+120)*vdc-cosinus(90-pos+120)*vqc;
//convert voltage references to duty cycles
da=((va/2800)+10000)/79;
if(da>255){
da=255;
}
if(da<0){
da=0;
}
db=((vb/2800)+10000)/79;
if(db>255){
db=255;
}
if(db<0){
db=0;
}
dc=((vc/2800)+10000)/79;
if(dc>255){
dc=255;
}
if(dc<0){
dc=0;
}
}