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

400 hz (2ms) hardware pwm on 50 mhz clock speed
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

400 hz (2ms) hardware pwm on 50 mhz clock speed
PostPosted: Thu Aug 01, 2013 3:03 pm     Reply with quote

hi friends.

I want to generate 400 hz (2ms) hardware pwm on pic18f87j11 with 50 mhz clock speed for input of esc, but there is one problem.

Hardware pwm is work with timer 2 and timer 2 in prescaler=16 overflow in 327 us.

My compiler v is 4.130

Can anyone help me?
oxo



Joined: 13 Nov 2012
Posts: 219
Location: France

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 3:13 pm     Reply with quote

400 Hz is 2.5 ms
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

PostPosted: Thu Aug 01, 2013 3:27 pm     Reply with quote

oxo wrote:
400 Hz is 2.5 ms


Right. you are right.


500 hz 2.5 ms

do you have any way to solve this problem?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 12:07 am     Reply with quote

Despite of the numerical confusion, 327 µs maximal PWM period for 50 MHz clock is right.
This means, software PWM is the only option for 400 Hz.
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 12:24 am     Reply with quote

The normal solution, is to use a 'half hardware' PWM. Use the CCP, with the modes to automatically set/clear it's output pin, and in it's interrupt change the time period wanted for the next half cycle. Because the CCP supports 16bit timing, rather than 8bit, the slower period is no problem, and given the slower period, the overhead of the interrupt calls is not normally a problem.

Best Wishes
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 1:54 am     Reply with quote

FvM wrote:
Despite of the numerical confusion, 327 µs maximal PWM period for 50 MHz clock is right.
This means, software PWM is the only option for 400 Hz.


Right, but software pwm is kill processor speed. Thanks.

Ttelmah wrote:
The normal solution, is to use a 'half hardware' PWM. Use the CCP, with the modes to automatically set/clear it's output pin, and in it's interrupt change the time period wanted for the next half cycle. Because the CCP supports 16bit timing, rather than 8bit, the slower period is no problem, and given the slower period, the overhead of the interrupt calls is not normally a problem.

Best Wishes


Thanks Ttelmah. Do you have any example code?
temtronic



Joined: 01 Jul 2010
Posts: 9241
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 5:29 am     Reply with quote

You might want to consider another PIC? In your original post you mention 'input to esc' as well as 400Hz( 2.5 ms).
That sounds like an RC servo system (e)lectronic (s)peed (c)ontrol unit.
If so I can think of several options.
1) slow down your current PIC.Depends on what else it's doing..
2) choose another PIC.Again, depends on other functions it needs to do.
3) add a 2nd smaller PIC.It'd only be the esc 'controller'.
4) use the hard/soft ccp pwm as suggested.
5) rethink/design of the esc software.

If it's really an RC based 'esc' then timing isn't super 'critical'.There's a fair amount of RC servo code here,have a look,see what's useful to you.

How you proceed is up to you, but you really don't need a 50MHz PIC to run RC servo systems.My first 'PC' ran at 2Mhz.

hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 8:14 am     Reply with quote

Many of the later PIC's also allow the timer2 output to be used to feed the PWM, giving wider frequency choices. However:
Code:

#define PERCENT 312
int16 on_time;
#define PERIOD 31250 //400Hz at 50Mhz
#define OP_PIN PIN_C2 //whatever you want

void set_duty(int8 in_percent)
{
   //This sets the duty cycle from 0 to 100 in percent (integer).
   //Locks output full off/on for 0 & 100%.
   int16 temp;
   temp=((int16)in_percent*PERCENT)+(in_percent/2);
   temp=0-temp; //This gives the correct positive unsigned value for timer
   if (in_percent<1)
   {
      disable_interrupts(INT_CCP1);
      output_low(OP_PIN);
      return;
   }
   if (in_percent>99)
   {
      disable_interrupts(INT_CCP1);
      output_high(OP_PIN);
      return;
   }
   disable_interrupts(INT_CCP1);
   on_time=temp;
   enable_interrupts(INT_CCP1);
}

#INT_TIMER3
void falling(void)
{
   //Here timer3 has triggered so need to set the output pin low
   output_low(OP_PIN);
   disable_interrupts(INT_TIMER3);
}

#INT_CCP1
void rising(void)
{
   output_high(OP_PIN);
   //just need to load the 'on' time, and enable the
   //timer interrupt
   set_timer3(on_time);
   clear_interrupt(INT_TIMER3);
   enable_interrupts(INT_TIMER3);
}

void main()
{
   setup_timer_1(T1_DIV_BY_1 | T1_INTERNAL);
   CCP_1=PERIOD; //Now gives 400Hz
   
   setup_timer_3(T3_DIV_BY_1 | T3_INTERNAL);

   setup_ccp1(CCP_COMPARE_RESET_TIMER);
   //Now CCP1, is going to interrupt at the end of the period
   //while timer3 is going to handle the 'off'.
   setup_comparator(NC_NC_NC_NC);
   set_duty(10); //10% duty
   
   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
       //do what you want.
   }

}


About the minimum 'overhead' to do this.

Best Wishes
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 11:16 am     Reply with quote

temtronic wrote:


How you proceed is up to you, but you really don't need a 50MHz PIC to run RC servo systems.My first 'PC' ran at 2Mhz.





50 mhz speed is low let alone 2 mhz.

my Quadcopter has 5000 line of codes and a sensor that has 3 axis accel and 3 axis gyro with i2c interface and a pid loop.that this element need to high clock speed.my sensor has 6 axis for reading.450*6=2.7 ms each cycle of read from i2c is 400us with 2 mhz clock speed.and i add the math library and use the atan() , sqrt() , pow() function.this function need high clock speed.when add the math lib with 2 mhz clock you have a 20 ms delay on CPU.
temtronic



Joined: 01 Jul 2010
Posts: 9241
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 11:45 am     Reply with quote

You'll find out that PICs are not great for 'math' especially transcendentals and floating point operations.
If you settle for integer math operations you can easily speed up by a factor of 10-30 times or more.
I've done several 3DOF helis with PID using 16F877s at 20MHz without any problems.

jay
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 12:15 pm     Reply with quote

I hope you are not using floating point math in a quadcopter! All that trig can be done with scaled ints so much faster.
_________________
The search for better is endless. Instead simply find very good and get the job done.
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

PostPosted: Fri Aug 02, 2013 2:26 pm     Reply with quote

temtronic wrote:
You'll find out that PICs are not great for 'math' especially transcendentals and floating point operations.
If you settle for integer math operations you can easily speed up by a factor of 10-30 times or more.
I've done several 3DOF helis with PID using 16F877s at 20MHz without any problems.

jay


float pointing is very accurate for Quadcopter.0.5 to 1 degree accurate.

thanks alot.My opinion use dspic33fj256mc710.40 MIPS clock speed.great for math and float pointing

Ttelmah wrote:
Many of the later PIC's also allow the timer2 output to be used to feed the PWM, giving wider frequency choices. However:
Code:

#define PERCENT 312
int16 on_time;
#define PERIOD 31250 //400Hz at 50Mhz
#define OP_PIN PIN_C2 //whatever you want

void set_duty(int8 in_percent)
{
   //This sets the duty cycle from 0 to 100 in percent (integer).
   //Locks output full off/on for 0 & 100%.
   int16 temp;
   temp=((int16)in_percent*PERCENT)+(in_percent/2);
   temp=0-temp; //This gives the correct positive unsigned value for timer
   if (in_percent<1)
   {
      disable_interrupts(INT_CCP1);
      output_low(OP_PIN);
      return;
   }
   if (in_percent>99)
   {
      disable_interrupts(INT_CCP1);
      output_high(OP_PIN);
      return;
   }
   disable_interrupts(INT_CCP1);
   on_time=temp;
   enable_interrupts(INT_CCP1);
}

#INT_TIMER3
void falling(void)
{
   //Here timer3 has triggered so need to set the output pin low
   output_low(OP_PIN);
   disable_interrupts(INT_TIMER3);
}

#INT_CCP1
void rising(void)
{
   output_high(OP_PIN);
   //just need to load the 'on' time, and enable the
   //timer interrupt
   set_timer3(on_time);
   clear_interrupt(INT_TIMER3);
   enable_interrupts(INT_TIMER3);
}

void main()
{
   setup_timer_1(T1_DIV_BY_1 | T1_INTERNAL);
   CCP_1=PERIOD; //Now gives 400Hz
   
   setup_timer_3(T3_DIV_BY_1 | T3_INTERNAL);

   setup_ccp1(CCP_COMPARE_RESET_TIMER);
   //Now CCP1, is going to interrupt at the end of the period
   //while timer3 is going to handle the 'off'.
   setup_comparator(NC_NC_NC_NC);
   set_duty(10); //10% duty
   
   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
       //do what you want.
   }

}


About the minimum 'overhead' to do this.

Best Wishes


thanks alot Ttelmah for your code.this work perfect.but can you give a source code to 4 channel pwm?

thanks alot
Ttelmah



Joined: 11 Mar 2010
Posts: 19537

View user's profile Send private message

PostPosted: Sat Aug 03, 2013 1:40 am     Reply with quote

I'm not going to write your code for your. However some comments:

Remember that the 'period' will be the same for all, so one timer can handle the start of all four pulses.
I must admit I'd probably just use a basic PIC12 to actually generate the servo pulse train, and leave the main processor handling the calculation work.

However don't get hooked on 400Hz.
If you try out one of the Quad controllers based on faster processors, you will find that even with ESC's flashed to support 400Hz, changing to this rate has little if any effect on the performance. Problem is that the actual update rate is dependant on the timing of the main algorithm loop, and even on a much faster processor, people tend to waste time in this loop, and so it updates it's output at several tens of mSec intervals - if you are lucky....
Don't use float. Use scaled integers, and some real thought. The servo algorithm should be written so that the PID terms can be handled in something like an int32, and divided by 256 for the fractional part. A single floating point division, even at 50MHz, takes 116uSec. Solve a few PID calculations, and you are into hundreds of uSec. Using scaled integers, with the scaling chosen so that divisions are binary values, and you should be able to get _dozens_ of times faster updates. This is the vital part, not the servo output rate. You need to be designing your algorithm _from scratch_ with a real understanding of what takes time in the processor, and what can be done quickly. Temtronic's comment is spot on here.
Even if you switch to much faster processors, this still applies. The Arducopter has run into significant problems recently with this. Lot's of new 'frilly bits' added, and in certain states, the update rate plummets (as does the copter....).

Best Wishes
Mahdi



Joined: 21 Aug 2012
Posts: 47

View user's profile Send private message

PostPosted: Sat Aug 03, 2013 12:14 pm     Reply with quote

Ttelmah wrote:
I'm not going to write your code for your. However some comments:

Remember that the 'period' will be the same for all, so one timer can handle the start of all four pulses.


Sorry but i just have problem with 4 channel software pwm.

I understand with your code style that any timer run a PWM channel. Now how can i run 4 channel PWM with same freq and different duty with One timer?


My quadcopter is flying but it fly with a little delay. Now i want to remove this delay with increase the clock speed. If i increase the clock speed i cant use hardware PWM, so i must use software pwm. Now I would ask you to help me to build a 4 channel software pwm

thanks alot buddies
John P



Joined: 17 Sep 2003
Posts: 331

View user's profile Send private message

PostPosted: Sat Aug 03, 2013 7:49 pm     Reply with quote

It may be easy to run 4 (or any number) of PWM's on one timer, or it may not. What makes the difference is how much resolution you need in the outgoing pulse, and I don't believe you've told us that.

The way to do this is to learn to use the timer so that you can make it generate successive time intervals that add together to make exactly 2.5msec. Assuming you do want 4 PWM outputs, you make up 4 bytes (or perhaps fewer, as I'll explain) to write to an output port when each PWM bit goes low. So at time t=0, you set all the PWM outputs high. Then after the right interval, the first one goes low, then after some other interval the next one goes low (and the first one stays low) and so forth until they've all gone low at the correct times. You might have some of the PWM's with the same duty cycle, and that's the situation where you don't need all 5 interrupts: in fact you might need as few as 2, one each to start and stop the waveforms.

Anyway, when all 4 outputs are low, the last time interval you use is something that makes the total end up at 2.5msec, and that's when you set them all high and start again.

But I said it "may be easy". I claim it's simple if you don't need a very high resolution in time intervals. If that's not the case, you're going to have problems if there are PWM duty cycles which are almost, but not exactly, the same. The limit is how long it takes to get out of, and then back into, an interrupt. I can imagine solving that by staying in the interrupt and somehow measuring off the right time between transitions, but that seems like a real mess, and I'd hate to have to do it.

Anyway, that's how to do it. Tell us how it comes out.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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