Go Down

Topic: What are the possible PWM frequencies? And how to set them. (Read 8726 times) previous topic - next topic

iyahdub

10 LET Loop=Infinite
20 GO TO 10

Punthoofd07

As promised here is a sketch using timers for PWM, with different frequencies. You can have 4 different frequencies, because there are 4 timer channels used. Each timer channel can have two outputs, A and B, each with their own duty cycles.

There are a total of 9 timer channels, so in theory you could have 9 different frequencies, but not all the output pins may be mapped in convenient locations, or at all. You would also need to do all the setup code yourself, as they are not handled by analogWrite, or possibly edit variant.cpp.

Code: [Select]
// --------------------------------------------
//
// PWM with timers demo
//
// Bob Cousins, August 2014
// --------------------------------------------

typedef struct {
    Tc *pTC;        // TC0, TC1, or TC2
    byte channel;   // 0-2
    byte output;    // 0 = A, 1 = B
}  tTimerInfo;

tTimerInfo timerLookup [] =
{
  {NULL,0,0}, // 0
  {NULL,0,0},
  {TC0,0,0},  // pin 2 = TIOA0
  {TC2,1,0},  // pin 3 = TIOA7
  {TC2,0,1},  // pin 4 = TIOB6
  {TC2,0,0},  // pin 5 = TIOA6
  {NULL,0,0},
  {NULL,0,0},
  {NULL,0,0},
  {NULL,0,0},
  {TC2,1,1},  // pin 10 = TIOB7
  {TC2,2,0},  // pin 11 = TIOA8
  {TC2,2,1},  // pin 12 = TIOB8
  {TC0,0,1}   // pin 13 = TIOB0
};

/**
 * \brief set a pin for PWM using a timer channel
 * \param pin       pin to use (0-13 only!)
 * \param frequency the frequency
 * \param dutyCyle  duty cycle 0-255
 * \return          this function returns a count, which is the effective PWM resolution. Returns 0 if pin is not valid
 */

uint32_t setupTimerPwm (byte pin, uint32_t frequency, unsigned dutyCycle)
{
  uint32_t count = VARIANT_MCK/2/frequency;
  tTimerInfo *pTimer = &timerLookup[pin];
 
  if (pTimer != NULL)
  {
    TC_SetRC (pTimer->pTC, pTimer->channel, count);
    if (pTimer->output == 0)
       TC_SetRA (pTimer->pTC, pTimer->channel, count * dutyCycle / 256);
    else
       TC_SetRB (pTimer->pTC, pTimer->channel, count * dutyCycle / 256);
 
    return count;
  }
  else
    return 0;
}

void setup() {
  // put your setup code here, to run once:

  // use the Arduino lib to do initial setup
  analogWrite (2, 128);
  analogWrite (13, 128);
 
  analogWrite (5, 128);
  analogWrite (4, 128);

  analogWrite (3, 128);
  analogWrite (10, 128);

  analogWrite (11, 128);
  analogWrite (12, 128);
 
  // pins 2 and 3 share the same timer so must have same frequency
  setupTimerPwm (2, 2000, 128);
  setupTimerPwm (13, 2000, 64);
 
  // pins 5 and 4 share the same timer
  setupTimerPwm (5, 3000, 128);
  setupTimerPwm (4, 3000, 64);

  // pins 3 and 10 share the same timer
  setupTimerPwm (3, 4000, 128);
  setupTimerPwm (10, 4000, 64);

  // pins 11 and 12 share the same timer
  setupTimerPwm (11, 5000, 128);
  setupTimerPwm (12, 5000, 64);

}

void loop() {
  // put your main code here, to run repeatedly:

}


Scope traces, showing pins 2, 5, 3 and 11 respectively (these are the 'A' outputs) :

demo2 by donotdespisethesnake, on Flickr

If you find the advice "read the source code" offensive, I'm sorry, but please don't send me PMs to complain. It really is Good Advice Learn to Read the Source, Luke!. If you don't want to read source code, consider a different hobby/profession!

And if you are using Arduino, you already have it's source code on your computer, so don't say you don't have it. It is really worth studying if you want to learn how it works.

Especially made an account to thank you! :-)

Go Up