PWM settings for multiple channels with shared scalars

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

PWM settings for multiple channels with shared scalars

2,000 Views
Matt_OES
Contributor I
Hello,
 
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
[CODE]
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)
  {
    Period0>>1;
    Period4>>1;
    PreClock++;
  }
  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
}
 
[/CODE]
 
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,
Matt
 
 
Labels (1)
0 Kudos
6 Replies

536 Views
RichTestardi
Senior Contributor II
Hi,
 
If I understand your goal correctly, you are trying to generate independent frequencies across the dtin pins, all with 50% duty cycles?  If so, then I believe the PWM peripheral might not be your best bet...  Instead, you can use the DMA Timers, which have independent 32 bit counters for each pin.
 
I have software that runs on the MCF52221/52233 (which I believe have identical peripherals to the 5213) as well as the MCF51JM128 (much harder, and the timers *are* coupled) which allows you to generate any PWM percentage (at a fixed frequency) *or* any frequency (at a fixed 50% duty cycle) on any pin.  On the MCF52221/52233, it is unrestricted.  (On the MCF51JM128 you can only have two pins on different "channels" configured for frequency generation, but that should not concern you.)
 
The file is attached -- it will soon all be public (on the download page of www.cpustick.com) as I am in the final phases of testing.  The file switches the pins between PWM and DMA Timer peripherals, as needed, but I believe you only want to follow the DMA Timer code path (pin_type == pin_type_frequency_output).
 
-- Rich
 
 
 
0 Kudos

536 Views
RichTestardi
Senior Contributor II
PS look at the pin_declare() function for setting up a dtin pin for frequency_output, and then pin_set() to set the actual frequency.
0 Kudos

536 Views
Matt_OES
Contributor I
Thanks a lot... I had no idea I could use the DMA timers for this. I'll just have to ensure that my RTOS is using PIT's instead of DMAT's. I'll download this code and have a look right now. This sounds very easy.
0 Kudos

536 Views
RichTestardi
Senior Contributor II
Great.  I think you'll find PITs are way easier to use for periodic timer generation than DMA Timers, as well.
 
Here's some sample code to do that, too, attached. :smileyhappy:
 
(And if you need the headers or any other files that go with these, you can find them at skeleton.zip at http://www.cpustick.com/downloads.htm -- remember, I haven't quite finished all my testing yet! :smileyhappy:
0 Kudos

536 Views
Matt_OES
Contributor I
Thanks for that one, but I'm using FreeRTOS - not a roll-your-own. I'm fairly new to the industry but it seemed every project i did in the first 16 months relied heavily on PIT's :smileyhappy:
0 Kudos

536 Views
RichTestardi
Senior Contributor II
Oh, and be sure to call pin_initialize(), once, before any pin_declare()'s.
0 Kudos