I went ahead and implemented the PWM functionality using the Register class from C# as a couple of you had suggested and it totally addresses the PWM glitch issue! It did take quite a while to get all of the register calls set up just right (8-9 hours) but in the end it’s not too bad. In addition to the user manual, I found that the sample code bundle from NXP ([url]http://ics.nxp.com/support/documents/microcontrollers/zip/code.bundle.lpc23xx.lpc24xx.uvision.zip[/url]) was really useful.
Here is my test code so far. If I have time after getting it cleaned up and generalized I’ll post that as well.
using System;
using System.Threading;
using GHIElectronics.NETMF.Hardware.LowLevel;
// This class demonstrates using direct access to the registers to implement PWM on the Fez Panda. The code
// ramps PWM2 from 0% duty cycle up to 100% duty cycle and then back down to 0% over the course of about 2 seconds.
public class RegisterPWMDemo
{
public static void Main()
{
// Create register objects for the registers we need to manipulate to implement the PWM.
Register PCONP = new Register(0xE01FC0C4); // Power Control for Peripherals is needed to make sure power is supplied to the PWM module.
Register PCLKSEL0 = new Register(0xE01FC1A8); // Peripheral Clock Selection register 0 is needed to specify the input clock rate to the PWM module.
Register PINSEL3 = new Register(0xE002C00C); // Pin function select register 3 is needed to connect the PWM2 to arduino pin 9.
Register PWM1TCR = new Register(0xE0018004); // Timer Control Register is needed to reset the timers and enable the timers and PWM mode.
Register PWM1PR = new Register(0xE001800C); // Pre-Scale Register could be used to slow down the PWM clock though we leave it at zero here.
Register PWM1MCR = new Register(0xE0018014); // Match Control Register is used to specify that the PWM repeats instead of being a one-shot.
Register PWM1MR0 = new Register(0xE0018018); // Match Register 0 is used to specify the total waveform duration.
Register PWM1MR2 = new Register(0xE0018020); // Match Register 2 is used to specify the duration of the PWM high output.
Register PWM1PCR = new Register(0xE001804C); // PWM Control Register enables each of the PWM lines and sets them to be single edge PWMs.
Register PWM1LER = new Register(0xE0018050); // Latch Enable Register bits must be enabled every time after the match values are updated.
Register PWM1CTCR = new Register(0xE0018070); // Count Control Register is used to select timer mode (instead of triggering off some other input).
PCONP.SetBits(1 << 6); // Turn on power to the PWM module.
PCLKSEL0.SetBits(1 << 12); // Set the PWM module to use the clock at its original frequency.
PINSEL3.ClearBits(1 << 8); // Set output pin 20 to act as a PWM (Pin 9 on the arduino shield is P1.20 on the arm processor (i.e. pin 20 on port one))
PINSEL3.SetBits(1 << 9);
const uint WAVEFORM_DURATION = 1000000; // Duration in clock counts of the waveform duration (high plus low). All PWM's will use this value.
PWM1TCR.Write(0x00000002); // Reset the counters.
PWM1PR.Write(0x00000000); // Set the counter pre-scale to zero so that the PWM runs at the full clock frequency.
PWM1MCR.Write(0x00000002); // Specify that the counter should reset when it equals MR0 (instead of stopping or triggering an interrupt).
PWM1MR0.Write(WAVEFORM_DURATION); // Set the waveform duration. This MUST be done before enabling PWM mode in the TCR.
PWM1MR2.Write(0); // Initialize the duration of the high output to zero so the output is 100% low until it is set differently later on.
PWM1LER.Write(0x00000005); // Enable the PWM latches for MR0 and MR2 so the total and high duration values get copied into the match registers.
PWM1PCR.Write(0x00000400); // Set all of the PWM channels to be single edge mode and only enable the output for PWM 2.
PWM1TCR.Write(0x00000009); // Enable the counter and the PWM feature.
// Loop continuously, ramping the PWM2 up and down between 0% and 100% duty cycle
while (true)
{
for (uint i = 0; i < 100; ++i) // Ramp up the PWM by changing i (the percent high duty cycle).
{
PWM1MR2.Write(i * (WAVEFORM_DURATION/100)); // Set the MR2 to be a value between zero and the totally waveform duration.
PWM1LER.SetBits(1 << 2); // Make sure to set the latch enable register so the new data will be copied into the match registers when the cycle completes.
Thread.Sleep(10); // Sleep for 100th of a second.
}
for (uint i = 100; i > 0; --i) // Now ramp the PWM back down to zero.
{
PWM1MR2.Write(i * (WAVEFORM_DURATION/100));
PWM1LER.SetBits(1 << 2);
Thread.Sleep(10);
}
}
}
}
Thanks for everyone’s help,
David