Matt Geerts

PWM settings for multiple channels with shared scalars

Discussion created by Matt Geerts on Dec 4, 2008
Latest reply on Dec 4, 2008 by Matt Geerts
I am using an MCF5213 to generate 4 PWM signals.  I am currently trying to write a PWM software module that will accept as arguments 4 frequencies and spit out the settings required in the PWM module to generate those 4 frequencies. All outputs will be 50% duty cycle, so that's one factor less complicated.
I have, for a previous project, converted frequency(Hz) and duty(%) into the PreClock, Scalar, PER and DTY settings required. This time, however, the hurdle is not getting accurate duty%, it is getting channels with shared timing registers to run at different frequencies.
Unfortunately, this revision of the board leaves me using PWM0,2,4,6, which can NOT be concatenated into 16-bit PER. This severely increases the complexity.
As an example - PWM0 and PWM4 share the same PreClock and Scalar values (although it is selectable if each channel will actually use the Scalar value). If I would like to generate one clock at 1kHz and the other clock at 300kHz i can not do this as easily as my previous project because of the shared registers. In fact, because they are more than 256 times apart, the 300kHz will have to be generated without using the Scalar at all. So i need to programatically find a way to generate 300kHz using only the PreClock and PER, then be able to generate 1kHz using that same PreClock and adding Scalar and PER settings for that channel.
Now, i'd love it if someone could just drop a 4-channel PWM module in my lap, but barring that, maybe we can work out an algorithm to do this.
To kick things off, here's what I would do if both numbers were closer
PWM_Set_CH0_CH4(uint32 Period0, uint32 Period4)
  Scalar = 1;
  PreClock = 0;
  Period0 >> 2;
  Period4 >> 2; //Shift both by two because PWM module gets fsys/2 and scaled clock is /2
  if( PWM_Set(PreClock, Scalar, Period0, Period4) )
    return; // that was easy
  //okay, not so easy, we need to shrink the periods, first use the PreClock to shrink as much as possible
  while( Periods are both even numbers)
  if( PWM_Set(PreClock, Scalar, Period0, Period4) )
    return; // that wasn't too bad
  //Okay, this is getting bad
  //what number must the largest period be divided by to get it below 255 so it fits in the Period register?
  Scalar = (MAX(Period0, Period4) / 0xFF ) + 1;
  Period0 /= Scalar;
  Period4 /= Scalar;
  if( PWM_Set(PreClock, Scalar, Period0, Period4) )
    return; // okay, that was maybe not perfectly accurate, but best we can do
  return; //we're screwed.
PWM_Set( [preclock, scalar and period] )
  return TRUE if preclock, scalar and period are valid (8-bit, etc), false otherwise
So, that's not TOO bad, but what the heck do i do with the 1kHz and 300kHz signal that won't allow both sides to use the scalar... i still need some accuracy! The new board rev using PWM1,3,5,7 will be much better because the frequencies must be within a factor of 0xffff instead of 0xff.
Thanks, have fun,