Society of Robots - Robot Forum

Software => Software => Topic started by: mbateman on October 20, 2008, 08:50:30 AM

Title: PWM on Axon
Post by: mbateman on October 20, 2008, 08:50:30 AM
I have found that using the "servo" command in my main loop works OK for some servos, but others require much tighter control of the base frequency. If you have too much to do in your main loop, they can be starved of signal and do strange things. This is especially true of the Sabertooth R/C. To get around this, I really needed to use the PWM timer/interupt functions of the atMega. I see that Admin is working on unlocking some of those functions in the new beta software, but in the mean time, I have put together a quick and dirty version that unlocks E3-5 and H3-5 for PWM mode. To simplifiy it, I have made some assumptions based on the Axon (16Mhz) and typical servos (20mS base frequency).

I know that this is not great programming style and is not flexible for other uses, but it may help some Axon users until the real thing is ready for primetime.

To use it, put the code at the bottom of this post into a file called "pwm.c" in you working directory. Then to use it on E3 and E4, you would do something like:

#include "pwm.c"

pwmInitE345();
pwmOnE3();
pwmOnE4();
pwmSetE3(1500);  // Center servo
pwmSetE4(1500);  // Center servo

while (1) {
  // Your code goes here. You can use pwmSetE3 and  pwmSetE4 to change the servo positions.
  // Otherwise they will continue to get the correct pulse and timing to keep them at the last set position.
}




Contents of pwm.c:

void pwmInitE345(void) {
   /***************************************************/
   /* Initialize timer for PWM use on pins E3, E4, E5 */
   /***************************************************/
   // 00   A off, toggle on compare
   // 00   B on, toggle on compare
   // 00   C on, toggle on compare
   // 00   Low part of WGM: PWM, phase & freq, ICRn
   TCCR3A=0x00;
   // 0   No input noise cancelling
   // 0   Input edge select does not matter
   // 0   Not used
   // 10   High part of WGM: PWM, phase & freq, ICRn
   // 010   Prescale 8
   TCCR3B=0x12;
   // Clear TCNT
   TCNT3H=0x00;
   TCNT3L=0x00;

   ICR3 = 20000;   // 20mS PWM cycle time
}

void pwmOffE345(void) {
   /**********************************************************/
   /* Return timer and pins to normal use on pins E3, E4, E5 */
   /**********************************************************/
   // 00   A off, toggle on compare
   // 00   B on, toggle on compare
   // 00   C on, toggle on compare
   // 00   Low part of WGM: Normal
   TCCR3A=0x00;
   // 0   No input noise cancelling
   // 0   Input edge select does not matter
   // 0   Not used
   // 00   High part of WGM: Normal
   // 000   Prescale None
   TCCR3B=0x00;
   // Clear TCNT
   TCNT3H=0x00;
   TCNT3L=0x00;

   ICR3 = 0;   // Clear ICR4
}
void pwmInitH345(void) {
   /***************************************************/
   /* Initialize timer for PWM use on pins H3, H4, H5 */
   /***************************************************/
   // 00   A off, toggle on compare
   // 00   B on, toggle on compare
   // 00   C on, toggle on compare
   // 00   Low part of WGM: PWM, phase & freq, ICRn
   TCCR4A=0x00;
   // 0   No input noise cancelling
   // 0   Input edge select does not matter
   // 0   Not used
   // 10   High part of WGM: PWM, phase & freq, ICRn
   // 010   Prescale 8
   TCCR4B=0x12;
   // Clear TCNT
   TCNT4H=0x00;
   TCNT4L=0x00;

   ICR4 = 20000;   // 20mS PWM cycle time
}

void pwmOffH345(void) {
   /**********************************************************/
   /* Return timer and pins to normal use on pins H3, H4, H5 */
   /**********************************************************/
   // 00   A off
   // 00   B off
   // 00   C off
   // 00   Low part of WGM: Normal
   TCCR4A=0x00;
   // 0   No input noise cancelling
   // 0   Input edge select does not matter
   // 0   Not used
   // 00   High part of WGM: Normal
   // 000   Prescale None
   TCCR4B=0x00;
   // Clear TCNT
   TCNT4H=0x00;
   TCNT4L=0x00;

   ICR4 = 0;   // Clear ICR4
}


void pwmOnE3(void) {
   /****************************/
   /* Put pin E3 into PWM mode */
   /****************************/
   // 10   A on, toggle on compare
   sbi(TCCR3A,7);
   cbi(TCCR3A,6);
}
void pwmOffE3(void) {
   /********************************/
   /* Return pin E3 to normal mode */
   /********************************/
   // 00   A off
   cbi(TCCR3A,7);
   cbi(TCCR3A,6);
}
void pwmOnE4(void) {
   /****************************/
   /* Put pin E4 into PWM mode */
   /****************************/
   // 10   B on, toggle on compare
   sbi(TCCR3A,5);
   cbi(TCCR3A,4);
}
void pwmOffE4(void) {
   /********************************/
   /* Return pin E4 to normal mode */
   /********************************/
   // 00   B off
   cbi(TCCR3A,5);
   cbi(TCCR3A,4);
}
void pwmOnE5(void) {
   /****************************/
   /* Put pin E5 into PWM mode */
   /****************************/
   // 10   C on, toggle on compare
   sbi(TCCR3A,3);
   cbi(TCCR3A,2);
}
void pwmOffE5(void) {
   /********************************/
   /* Return pin E5 to normal mode */
   /********************************/
   // 00   C off
   cbi(TCCR3A,3);
   cbi(TCCR3A,2);
}
void pwmOnH3(void) {
   /****************************/
   /* Put pin H3 into PWM mode */
   /****************************/
   // 10   A on, toggle on compare
   sbi(TCCR4A,7);
   cbi(TCCR4A,6);
}
void pwmOffH3(void) {
   /********************************/
   /* Return pin H3 to normal mode */
   /********************************/
   // 00   A off
   cbi(TCCR4A,7);
   cbi(TCCR4A,6);
}
void pwmOnH4(void) {
   /****************************/
   /* Put pin H4 into PWM mode */
   /****************************/
   // 10   B on, toggle on compare
   sbi(TCCR4A,5);
   cbi(TCCR4A,4);
}
void pwmOffH4(void) {
   /********************************/
   /* Return pin H4 to normal mode */
   /********************************/
   // 00   B off
   cbi(TCCR4A,5);
   cbi(TCCR4A,4);
}
void pwmOnH5(void) {
   /****************************/
   /* Put pin H5 into PWM mode */
   /****************************/
   // 10   C on, toggle on compare
   sbi(TCCR4A,3);
   cbi(TCCR4A,2);
}
void pwmOffH5(void) {
   /********************************/
   /* Return pin H5 to normal mode */
   /********************************/
   // 00   C off
   cbi(TCCR4A,3);
   cbi(TCCR4A,2);
}

/******************************/
/* Set pin pulse times in uS. */
/* Typical servo would use    */
/*     1500 for center        */
/*     1000 for full left     */
/*     2000 for full right    */
/******************************/
#define pwmSetE3(val)   OCR3A=val      // Set E3 pulse time in uS
#define pwmSetE4(val)   OCR3B=val      // Set E4 pulse time in uS
#define pwmSetE5(val)   OCR3C=val      // Set E5 pulse time in uS
#define pwmSetH3(val)   OCR4A=val      // Set H3 pulse time in uS
#define pwmSetH4(val)   OCR4B=val      // Set H4 pulse time in uS
#define pwmSetH5(val)   OCR4C=val      // Set H5 pulse time in uS



Title: Re: PWM on Axon
Post by: mbateman on October 20, 2008, 09:02:48 AM
I forgot to mention the obvious. If you use this, then you cannot use the associated timers for other things. E3-5 use timer3. H3-5 use timer4. Unfortunately, the 3 pins that use timer5 are not connected on the Axon board, so they are not available for PWM. The upside is that timer5 is availble for other use without interference.
Title: Re: PWM on Axon
Post by: airman00 on November 27, 2008, 06:26:21 PM
You wrote here
Code: [Select]
// 00   A off, toggle on compare
   // 00   B on, toggle on compare
   // 00   C on, toggle on compare

and then lower down you wrote
Code: [Select]
// 10   B on, toggle on compareso which is it for B on . 10 or 00 ?

btw I am trying to convert your code for the Axon to the ATmega168. There are some minor differences in register bit names and also on the ATmega168 the timers only are A & B , no C. There are three timers - so thats 6 PWM. Its pretty easy modifications to get it to work with the ATmega168

Also, go to page 104 of the ATmega168 Datasheet - www.atmel.com/dyn/resources/prod_documents/doc2545.pdf
there is no option for "Phase and Frequency Correct" - however there are two different options for "Phase Correct"
Title: Re: PWM on Axon
Post by: mbateman on November 27, 2008, 09:17:10 PM
Oops, too much cut and paste.  :( All the comments in the Init and Off sections should be 00 which is Off.

If you plan to use this for servos, the PWM on the 168 may not work well for you. Two of its three timers are 8 bit. Servos take such a small range of the base period that you just can't get much granularity with the 8 bit timer. You can still use it on Timer1 which is 16 bit. Also, Timer1 does have the Phase and Freq correct mode. See section 15.9.5.
Title: Re: PWM on Axon
Post by: airman00 on November 27, 2008, 10:03:02 PM
Oops, too much cut and paste.  :( All the comments in the Init and Off sections should be 00 which is Off.
you should probably edit that in your main post for future reference
Also small typo here: " ICR3 = 0;   // Clear ICR4 "

Also I'm using the hardware PWM for LEDs. I don't even really need 255 steps , 156 is fine ( thats the number of steps you mentioned an 8 bit timer would give you)

Btw mbateman thank you a lot for this code. It is helping me a ton!

Also, go to page 104 of the ATmega168 Datasheet - www.atmel.com/dyn/resources/prod_documents/doc2545.pdf
there is no option for "Phase and Frequency Correct" - however there are two different options for "Phase Correct"
Title: Re: PWM on Axon
Post by: airman00 on November 29, 2008, 07:41:39 PM
EDIT:
Solved the problems

Going to make a post detailing how I solved it soon.
Title: Re: PWM on Axon
Post by: Admin on December 02, 2008, 02:03:00 AM
Just a note to others who read this post . . . I greatly expanded the PWM features in the latest Axon code release.

Also, PWM code to make the green LED do a neat pulsing effect.

mbateman, your code helped me figure out a bug I was stuck on!
Title: Re: PWM on Axon
Post by: mbateman on January 21, 2009, 01:19:04 PM
Glad I could help. I have further docs and the code download available on my web site as well...

http://www.laughingsky.com/hobbies/robotics/pages/axon_modules/pwm/index.html (http://www.laughingsky.com/hobbies/robotics/pages/axon_modules/pwm/index.html)
Title: Re: PWM on Axon
Post by: OperationIvy on February 03, 2009, 01:41:49 PM
Question about this code.. after initializing PWM on pins E3, E4, and E5, can the pins be used for normal digital I/O? Basically I want to control the enable pin on a motor controller using PWM on E5, while using E3 and E4 for digital I/O to the controller. Can the code be modified to do this? I had a look at the Atmega640 datasheet but I'm a little scared to modify the sixteen bit registers because I've heard some bad things can happen if you don't do it right.
Title: Re: PWM on Axon
Post by: mbateman on February 03, 2009, 03:49:34 PM
Yes, the init is just setting up the appropriate timer which is shared by all three pins. But you can use PWM on any or all of the pins. For your use, you would use:

pwmInitE345();
pwmOnE5();

Then you could use E3 and E4 for other things.
Title: Re: PWM on Axon
Post by: Hanoush on March 23, 2009, 05:07:14 PM
I wanted to ask,what is the minimum and maximum inputs that I can give to this function ?
Is the minimum 1000 and the maximum 2000 ?