CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

problem in changing spwm amplitude

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
notbad



Joined: 10 Jan 2013
Posts: 68

View user's profile Send private message

problem in changing spwm amplitude
PostPosted: Wed Apr 10, 2013 7:30 am     Reply with quote

i’m trying to generate a sinusoidal PWM from frequency 1hz to 100hz.
sinusoidal points are updated in int_ccp4 working with timer1
and its overflow rate is determined by pre-calculated ccp4vals selected by adc.
and for frequencies less than 50 hz, amplitude must be weakened wich function vf_calc does that correctly.
the problem is that if freq is less than 50 and vf_calf comes to work, the output frequency is corrupted.
why do you think?

Code:

#include <18F26K22.h> // ccs v4.130
#device adc=10
#FUSES NOWDT, WDT128, HSH, NOPLLEN, NOFCMEN, NOIESO, PUT, NOBROWNOUT, WDT_NOSLEEP, NOLVP, NOXINST
#use delay(clock=16000000)
//////////////////////////////////////////////////////////////
int8  index=0,duty;
int16 speed=0;

int8 CONST sine[256]={
0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c};

int16 CONST ccp4vals[100]={15625,7813,5208,3906,3125,2604,2232,1953,1736,1563,1420,
1302,1202,1116,1042,977,919,868,822,781,744,710,679,651,625,601,579,558,539,521,504,
488,473,460,446,434,422,411,401,391,381,372,363,355,347,340,332,326,319,313,306,300,
295,289,284,279,274,269,265,260,256,252,248,244,240,237,233,230,226,223,220,217,214,
211,208,206,203,200,198,195,193,191,188,186,184,182,180,178,176,174,172,170,168,166,
164,163,161,159,158,156};

int8 vf_calc(int8 sinea, int8 Ain)
{
 int16 sine_temp;
 int8 sine1;
 sine1=((sinea<128)?~sinea:sinea);
 sine_temp=sine1<<1;
 sine_temp-=255;
 sine_temp*=Ain;
 sine_temp>>=8;
 sine_temp+=255;
 sine_temp>>=1;
 sine_temp++;
 sine1=sine_temp;
 if (sinea<128) sine1=~sine1;
 return sine1;
}

#int_ccp4
void  ccp4_isr(){
++index;
if(speed>=49)        //freq >= 50 Hz
 duty=sine[index];
else
{
 int32 A=0;
 A=(((int32)255*(speed))/50);
 duty=vf_calc(sine[index],A);
}
set_pwm1_duty(duty);
}

void main()
{
 enable_interrupts(INT_CCP4);
 enable_interrupts(GLOBAL);
 setup_ccp1(CCP_PWM_PLUS_3|CCP_PWM_HALF_BRIDGE|CCP_USE_TIMER1_AND_TIMER2);
 setup_ccp4(CCP_COMPARE_RESET_TIMER|CCP_USE_TIMER1_AND_TIMER2);
 setup_timer_2(T2_DIV_BY_1,255,1);
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
 setup_adc_ports(sAN0);
 setup_adc(ADC_CLOCK_DIV_32);
 set_adc_channel(0);
 
 while(1)
 {
  delay_ms(10);
  speed=read_adc()/10;
  if (speed>99)speed=99;
  CCP_4=(ccp4vals[speed]);
 }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Wed Apr 10, 2013 7:41 am     Reply with quote

/50 is the killer. At 16MHz, this takes nearly 300uSec to execute. The * takes 132uSec. Both unacceptable times. Total over 400uSec....

Now, this is effectively multiplication by 5.1. Speed is always under 100. So if you stay with int16, instead of using int32, and multiply speed by 326, then >>6 (/64), you get effectively *5.09375, taking about 60uSec instead. May be low enough to let it work.

Best Wishes
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Wed Apr 10, 2013 10:02 am     Reply with quote

TTelmah is pointing you in the direction of much reduced #int time
and very small error
B U T
if you can stand a 2% error -
really cut to the chase and use :
Code:

  // A=(((int32)255*(speed))/50);
 A=speed*5;
 

and my gut says says vf_calc could perhaps use a further simplification/tweaking too,
as my head reels just looking at it.
Very Happy Very Happy Very Happy
notbad



Joined: 10 Jan 2013
Posts: 68

View user's profile Send private message

PostPosted: Thu Apr 11, 2013 1:32 am     Reply with quote

wow thanks
i didn't think those instructions will take that long to execute.
another question is what happens in the processor? we are in the isr routine and another interrupt occurs. does it get serviced? if yes, shouldn't it cause stack overflow and hence device reset?
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Thu Apr 11, 2013 1:34 am     Reply with quote

No.
You are only using one hardware interrupt level.
Second interrupt will be serviced when the first handler finishes.

The manual has a section 'How much time do maths operations take'.
Now there are extensions and caveats. For instance /64, can be done using simple rotations, so this only takes perhaps 5uSec at your clock rate. The compiler is actually 'smart enough', that if you ask for a fixed division by a binary value (2,4,8 etc.), it will substitute a rotation.
Then other things can be much slower than you think, vara=varb, takes just a couple of instructions for an int8 (depends on whether bank switching is involved). However vara=varc[varb];, will typically take nearly twenty instructions (has to do a table lookup. This is where playing with very small programs, and the stopwatch in MPLAB SIM, can be really informative.

Best Wishes
notbad



Joined: 10 Jan 2013
Posts: 68

View user's profile Send private message

PostPosted: Thu Apr 11, 2013 1:01 pm     Reply with quote

Ttelmah wrote:
No.
You are only using one hardware interrupt level.
Second interrupt will be serviced when the first handler finishes.

I'm not talking about a second interrupt. the same interrupt.
ccp4 interrupt occurs > we go to its ISR > ccp4 interrupt occurs again > do we go to the start of the ISR or wait until the current routine is finished and then we go to the start of the ISR?
or is it just missed?

Quote:

This is where playing with very small programs, and the stopwatch in MPLAB SIM, can be really informative.

After you pointed about execution times, I tested some statements as follows and it was very informative:

set timer to 0
do something
value=get timer
printf timer value
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Thu Apr 11, 2013 2:59 pm     Reply with quote

On the interrupt, neither.
If an interrupt triggers a second time inside itself, the second trigger is lost. For each interrupt, there is only one interrupt flag. This is cleared when the interrupt exits. It doesn't matter if it has triggered ten times, or one....
This is why interrupt handlers should always be as short as possible.

One other way of doing what you want, is to just have a second array. Have the code switch which array it uses based on the number. No maths at all.

Best Wishes
notbad



Joined: 10 Jan 2013
Posts: 68

View user's profile Send private message

PostPosted: Fri Apr 12, 2013 12:15 am     Reply with quote

thank you Ttelmah
and you asmboy.
it's good to have you guys here. Smile
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Apr 12, 2013 2:47 am     Reply with quote

Besides the good things that have been said about effective arithmetic: It seems completely useless to calculate the magnitude factor A in the ISR...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group