Pulse Generator on a FEZ Panda 2 - 1Hz to 30Mhz?

Hi All, I am fairly new to FEZ but think it is awesome! Good job guys!.

I am wondering if I can ask some advice before I start a project. I have done a bit of Arduino stuff and expect some similaritys in the actual application of the same. I want to build a Pulse generator for a FEZ Panda II, capable of Low to High frequency, say from 0.1Hz to 30Mhz. I realise the Registers are limited to certian speeds and a fair bit of programming will be rquired to make this work. I have built a Pulse Gen from Arduino, it was on my old website @ E-Gadget.

I had trouble with the CPU on the Arduino. With the 32 Bit, 72Mhz, and extra memory I am guessing can do a better job.

Can anyone advise me to the do’s and dont’s before I start?

Any one have any suggestions before I get into it?

I am prepared to share all my code, it will have a windows form for contrrol.

Thanks in advance.

P.S. To the GHI Guys, how hard would it be, to ask for a variable frequency, say 10-15 amp full H Bridge Shield. I believe these things would sell like hot cakes, I have seen the Motor drivers out there but they are only good from around 1 - 20 Khz. I want a good to go from 0.1Hz to 30Mhz. These then can be used in not just the Motor Driver applications but for thousands of other applications also. EG: Home build Tesla Coils and so on…

[EDIT] The Codeshare URL for this project is : http://www.tinyclr.com/codeshare/entry/450

All the best Chris

Why do you need 30mhz?

Hi Gus,

Thx for your quick response! I just used 30Mhz as an axample. I would like to make this as flexable as possible. 30Mhz was just a figure I pulled out of the Air.

Some of the Tesla Coils run high Frequency, so I guess the higher the better.

I want to control over the UART Port and be able to save settings. Also I want to build in a Sweep function. My C# skills are ok but I am new to FEZ.

Really, I am just putting out my feelers to get a bit of a grasp of what limitations I will face.

What are your thoughts on the Card?

Thanks

ChrisO

PWM can go very high but not sure what is the max. If you need more, you can use a frequency generator chip.

Your request for high amperage bridge is taken, although this is the first find anyone asked for one!

Hi Gus,

Any suggestions on the Chip for High Freq?

If you guys are happy to do the board, I am happy to purchase then do demo Videos and tutorials on the uses of it.

Maybe we could chat about the design specs of it if you take this board on?

Thanks Gus!

Chris

P.S. Checking the Min and Max of PWM now. Will post the result in a day or two.

I have seen these chips but never used one.

Hi Gus,

Thanks for the sugestion. I found this: Breakout Board for AD9835 Signal Generator

Good from 1Hz to 25Mhz. This is a start if I need to go down that path.

Thanks

ChrisO

Hi Everyone,

I have some code working, actually it was a bit more of a task than first thought. I have used the Datasheet and to my understanding have the code right but I seem to be striking two seperate problems:

1: It takes about a minute after reboot to work. EG: I get no output on my Pins untill around a minute or so, then the PWM works fine.

2: The Pins i have selected in the Register (PINSEL3) are not the Pins that they should be?

3: There is at higher frequencys a little bit of distortion in the wave form. According to all I have read this is normal behavior.

Here is my Code:


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware.LowLevel;

namespace FEZ_Panda_II_HardWarePWM
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                              Please do not remove this header...                                               //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                     This Code is Copyrighted under the Apache 2.0 Licence.                                     //
    //                                         http://www.apache.org/licenses/LICENSE-2.0.txt                                         //
    //                                                                                                                                //
    //                                                 Written by Chris Sykes (ChrisO)                                                //
    //                                                                                                                                //
    //                                                For use by all FEZ Panda II Users..                                             //
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    public class HardWarePWM
    {
        /// <summary>
        /// Primary Frequency of the PWM - The Frequency is set by Match Register 0 (MR0) and can be Single Edge or Double Edge Control Mode set in the PWM Control Registers (PWM1PCR)...
        /// See Page 562 of LPC23XX User Manual : Chapter 24: LPC23XX Pulse width modulator Rev. 02 — 11 February 2009...
        /// </summary>
        private static uint _frequency;

        /// <summary>
        /// Match Register 1 (MR1) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR1;

        /// <summary>
        /// Match Register 2 (MR2) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR2;

        /// <summary>
        /// Match Register 3 (MR3) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR3;

        /// <summary>
        /// Match Register 4 (MR4) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR4;

        /// <summary>
        /// Match Register 5 (MR5) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR5;

        /// <summary>
        /// Match Register 6 (MR6) Duty Cycle in Percent...
        /// </summary>
        private static uint _dutyMR6;

        /// <summary>
        /// Set Latch Enable Register Bits for the corrosponding Match Register's...
        /// </summary>
        /// <param name="bit">
        /// A 7 Bit Array, value's 0 - 6 must be set 0 or 1 : 
        /// Bit 0 Enable PWM Match 0 Latch
        /// Bit 1 Enable PWM Match 1 Latch
        /// Bit 2 Enable PWM Match 2 Latch
        /// Bit 3 Enable PWM Match 3 Latch
        /// Bit 4 Enable PWM Match 4 Latch
        /// Bit 5 Enable PWM Match 5 Latch
        /// Bit 6 Enable PWM Match 6 Latch
        /// For example, if the PWM is configured for double edge operation and is currently running,
        /// a typical sequence of events for changing the timing would be:
        /// • Write a new value to the PWM Match1 register.
        /// • Write a new value to the PWM Match2 register.
        /// • Write to the PWMLER, setting bits 1 and 2 at the same time.
        /// • The altered values will become effective at the next reset of the timer (when a PWM Match 0 event occurs).
        /// </param>
        private static void SetLatchEnableRegister(byte[] bit)
        {
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PWM Latch Enable Register (PWM1LER - 0xE001 8050)
            // See Page: 575 - LPC23XX User Manual Rev. 02 — 11 February 2009...
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            Register PWM1LER = new Register(LPC23xx.PWM1LER);
            if (bit[0] == 1) PWM1LER.SetBits(1 << 0);
            if (bit[1] == 1) PWM1LER.SetBits(1 << 1);
            if (bit[2] == 1) PWM1LER.SetBits(1 << 2);
            if (bit[3] == 1) PWM1LER.SetBits(1 << 3);
            if (bit[4] == 1) PWM1LER.SetBits(1 << 4);
            if (bit[5] == 1) PWM1LER.SetBits(1 << 5);
            if (bit[6] == 1) PWM1LER.SetBits(1 << 6);
        }

        /// <summary>
        /// PWM Setup, Initialise a PWM Setup...
        /// This section is described in Chapter 24: LPC23XX Pulse width modulator...
        /// See Page: 562 - LPC23XX User manual Rev. 02 — 11 February 2009...
        /// _______________________________________________________________________________________________________
        /// Basic Setup :
        /// The PWM is configured using the following registers:
        /// 1. Power: In the PCONP register (Table 4–56), set bit PCPWM1.
        /// Remark: On reset, the PWM is enabled (PCPWM1 = 1).
        /// 2. Peripheral clock: In the PCLK_SEL0 register (Table 4–49), select PCLK_PWM.
        /// 3. Pins: Select PWM pins and pin modes in registers PINSELn and PINMODEn (see Section 9–5).
        /// 4. Interrupts: See register PWM1MCR (Table 24–487) and PWM1CCR (Table 24–488) for match and capture events. 
        /// Interrupts are enabled in the VIC using the VICIntEnable register (Table 6–76).
        /// _______________________________________________________________________________________________________
        /// This implementation supports up to N-1 single edge PWM outputs or (N-1)/2 double edge
        /// PWM outputs, where N is the number of match registers that are implemented. PWM
        /// types can be mixed if desired.
        /// </summary>
        public static void Setup()
        {
            #region Power: In the PCONP register (Table 4–56), set bit PCPWM1.

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Power Control for Peripherals Register (PCONP - 0xE01F C0C4)
            // See Page: 68 - LPC23XX User manual Rev. 02 — 11 February 2009...
            //_______________________________________________________________________________________________________
            // Bit     Symbol     Description                          Reset value
            // 6        PCPWM1     PWM1 power/clock control bit.        1
            //_______________________________________________________________________________________________________
            Register PCONP = new Register(LPC23xx.PCONP);
            PCONP.SetBits(1 << 6);

            #endregion

            #region Peripheral clock: In the PCLK_SEL0 register (Table 4–49), select PCLK_PWM.

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Peripheral Clock Selection registers 0 and 1 (PCLKSEL0 - 0xE01F C1A8 and PCLKSEL1 - 0xE01F C1AC) 
            // See Page: 62 - LPC23XX User manual Rev. 02 — 11 February 2009...
            // A pair of bits in a Peripheral Clock Selection register controls the rate of the clock signal
            // that will be supplied to the corresponding peripheral as specified in Table 4–49, Table 4–50 and Table 4–51.
            //______________________________________________________________________________________________________________________________
            // 13:12 PCLK_PWM1 Peripheral clock selection for PWM1.
            //______________________________________________________________________________________________________________________________
            // See Page: 63 - LPC23XX User manual Rev. 02 — 11 February 2009 : Table 51. Peripheral Clock Selection register bit values
            //______________________________________________________________________________________________________________________________
            // 00 PCLK_xyz = CCLK/4
            // 01 PCLK_xyz = CCLK[1]
            // 10 PCLK_xyz = CCLK/2
            // 11 Peripherals clock is selected to PCLK_xyz = CCLK/8 except for CAN1, CAN2, and CAN filtering when 11 selects PCLK_xyz = CCLK/6.
            //______________________________________________________________________________________________________________________________
            Register PCLKSEL0 = new Register(LPC23xx.PCLKSEL0);
            PCLKSEL0.ClearBits(3 << 12);
            PCLKSEL0.SetBits(1 << 12);

            #endregion

            // TODO WORK OUT Why my Pin Setup does not work as per Pin Out on FEZ Panda II Schematic...
            #region Pins: Select PWM pins and pin modes in registers PINSELn and PINMODEn (see Section 9–5).

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Pin function select register 3 (PINSEL3 - address 0xE002 C00C) bit description (LPC2361/62/64/65/66/67/68 and LPC2387)
            // See Page: 160 - LPC23XX User manual Rev. 02 — 11 February 2009...
            //______________________________________________________________________________________________________________________________
            // PINSEL3     Pin name     Function when 00     Function when 01     Function when 10     Function when 11     Reset value
            //  5:4         P1.18       GPIO Port 1.18         USB_UP_LED1[1]      PWM1.1               CAP1.0               00            -   IO35 on the FEZ Panda II...
            //  9:8         P1.20       GPIO Port 1.20         USB_TX_DP1[2]       PWM1.2               SCK0                 00            -   IO25 on the FEZ Panda II...
            //  11:10       P1.21       GPIO Port 1.21         USB_TX_DM1[2]       PWM1.3               SSEL0                00            -   IO23 on the FEZ Panda II...
            //  15:14       P1.23       GPIO Port 1.23         USB_RX_DP1[2]       PWM1.4               MISO0                00            -   IO62 on the FEZ Panda II...
            //  17:16       P1.24       GPIO Port 1.24         USB_RX_DM1[2]       PWM1.5               MOSI0                00            -   IO63 on the FEZ Panda II...
            //  21:20       P1.26       GPIO Port 1.26         USB_SSPND1[2]       PWM1.6               CAP0.0               00            -   IO65 on the FEZ Panda II...
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Pin function select register 4 (PINSEL4 - address 0xE002 C010) bit description (LPC2364/65/66/67/68 and LPC2387)
            // See Page: 161 - LPC23XX User manual Rev. 02 — 11 February 2009...
            //______________________________________________________________________________________________________________________________
            // PINSEL4     Pin name     Function when 00     Function when 01     Function when 10     Function when 11     Reset value
            // 1:0          P2.0         GPIO Port 2.0        PWM1.1               TXD1                  TRACECLK[1]         00            -   IO05 on the FEZ Panda II...
            // 3:2          P2.1         GPIO Port 2.1        PWM1.2               RXD1                  PIPESTAT0[1]        00            -   IO03 on the FEZ Panda II...
            // 5:4          P2.2         GPIO Port 2.2        PWM1.3               CTS1                  PIPESTAT1[1]        00            -   IO01 on the FEZ Panda II...
            // 7:6          P2.3         GPIO Port 2.3        PWM1.4               DCD1                  PIPESTAT2[1]        00            -   IO04 on the FEZ Panda II...
            // 9:8          P2.4         GPIO Port 2.4        PWM1.5               DSR1                  TRACESYNC[1]        00            -   IO02 on the FEZ Panda II...
            // 11:10        P2.5         GPIO Port 2.5        PWM1.6               DTR1                  TRACEPKT0[1]        00            -   IO07 on the FEZ Panda II...
            //______________________________________________________________________________________________________________________________
            Register PINSEL3 = new Register(LPC23xx.PINSEL3);
            PINSEL3.SetBits(2 << 4);
            PINSEL3.SetBits(2 << 8);
            PINSEL3.SetBits(2 << 10);
            PINSEL3.SetBits(2 << 14);
            PINSEL3.SetBits(2 << 16);
            PINSEL3.SetBits(2 << 20);
            // 0x0228A23 is the Hex Equivilent...

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Pin Mode select register 1 (PINMODE1 - 0xE002 C044)
            // See Page: 167 - LPC23XX User manual Rev. 02 — 11 February 2009...
            // 00 Pin has an on-chip pull-up resistor enabled.
            // 01 Reserved. This value should not be used.
            // 10 Pin has neither pull-up nor pull-down resistor enabled.
            // 11 Pin has an on-chip pull-down resistor enabled.
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PINMODE1       Symbol              Description                                                Reset value
            //   1:0           P1.16MODE           PORT1 pin 16 on-chip pull-up/down resistor control.        00
            //   31:30         P1.31MODE           PORT1 pin 31 on-chip pull-up/down resistor control.        00
            //______________________________________________________________________________________________________
            // PINMODE0 to PINMODE9 Values             Function                                              Value after Reset
            //     00                                    Pin has an on-chip pull-up resistor enabled.         00
            //     01                                    Reserved. This value should not be used.
            //     10                                    Pin has neither pull-up nor pull-down resistor enabled.
            //     11                                    Pin has an on-chip pull-down resistor enabled.
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            Register PINMODE3 = new Register(LPC23xx.PINMODE3);
            PINMODE3.SetBits(3 << 0);
            PINMODE3.SetBits(3 << 20);

            #endregion

            #region Interrupts: See register PWM1MCR (Table 24–487) and PWM1CCR (Table 24–488) for match and capture events. Interrupts are enabled in the VIC using the VICIntEnable register (Table 6–76).

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PWM Match Control Register (PWM1MCR - 0xE001 8014)
            // See Page: 570 - LPC23XX User manual Rev. 02 — 11 February 2009...
            // The PWM Match Control Registers are used to control what operations are performed
            // when one of the PWM Match Registers matches the PWM Timer Counter. The function of
            // each of the bits is shown in Table 24–487.
            Register PWM1MCR = new Register(LPC23xx.PWM1MCR);
            // Enable the Timer - Set Bit 2 to 1...
            PWM1MCR.SetBits(1 << 1);

            // Set the match Register 0 to a value of 0...
            Register PWM1MR0 = new Register(LPC23xx.PWM1MR0);
            PWM1MR0.Write(0);

            #endregion

            #region Configure the PWM Control Registers (PWM1PCR)...

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PWM Control Registers (PWM1PCR - 0xE001 804C)
            // See Page: 573 - LPC23XX User manual Rev. 02 — 11 February 2009...
            // The PWM Control Registers are used to enable and select the type of each PWM
            // channel. The function of each of the bits are shown in Table 24–489.
            // This implementation supports up to N-1 single edge PWM outputs or (N-1)/2 double edge
            // PWM outputs, where N is the number of match registers that are implemented. PWM
            // types can be mixed if desired.
            // _______________________________________________________________________________________________________________________________
            //   Bit        Symbol        Value        Description                                                                Reset Value
            //    1:0        Unused                     Unused, always zero. NA
            //    2          PWMSEL2       1            Selects double edge controlled mode for the PWM2 output.                    0
            //                            ____________________________________________________________________________________________________
            //                             0          Selects single edge controlled mode for PWM2.
            //                            ____________________________________________________________________________________________________
            //    3          PWMSEL3       1            Selects double edge controlled mode for the PWM3 output.                    0
            //                            ____________________________________________________________________________________________________
            //                             0          Selects single edge controlled mode for PWM3.
            //                            ____________________________________________________________________________________________________
            //    4          PWMSEL4       1            Selects double edge controlled mode for the PWM4 output.                    0
            //                            ____________________________________________________________________________________________________
            //                             0          Selects single edge controlled mode for PWM4.
            //                            ____________________________________________________________________________________________________
            //    5          PWMSEL5       1            Selects double edge controlled mode for the PWM5 output.                    0
            //                            ____________________________________________________________________________________________________
            //                             0          Selects single edge controlled mode for PWM5.
            //                            ____________________________________________________________________________________________________
            //    6          PWMSEL6       1            Selects double edge controlled mode for the PWM6 output.                    0
            //                            ____________________________________________________________________________________________________
            //                             0          Selects single edge controlled mode for PWM6.
            //                            ____________________________________________________________________________________________________
            //    8:7        -                          Reserved, user software should not write ones to reserved bits. 
            //                                          The value read from a reserved bit is not defined.
            //                            ____________________________________________________________________________________________________
            //    9          PWMENA1       1            The PWM1 output enabled.                                                    0
            //    10         PWMENA2       1            The PWM2 output enabled.                                                    0
            //    11         PWMENA3       1            The PWM3 output enabled.                                                    0
            //    12         PWMENA4       1            The PWM4 output enabled.                                                    0
            //    13         PWMENA5       1            The PWM5 output enabled.                                                    0
            //    14         PWMENA6       1            The PWM6 output enabled.                                                    0
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // It is generally not advantageous to use PWM channels 3 and 5 for double edge PWM outputs because it
            // would reduce the number of double edge PWM outputs that are possible. Using PWM 2, PWM4, and
            // PWM6 for double edge PWM outputs provides the most pairings.
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            Register PWM1PCR = new Register(LPC23xx.PWM1PCR);

            PWM1PCR.Write(0x00);

            // Reserved Bits Dont Change this: PWM1PCR.ClearBits(3 << 7);

            PWM1PCR.SetBits(1 << 9);
            PWM1PCR.SetBits(1 << 10);
            PWM1PCR.SetBits(1 << 11);
            PWM1PCR.SetBits(1 << 12);
            PWM1PCR.SetBits(1 << 13);
            PWM1PCR.SetBits(1 << 14);

            #endregion

            // Optional - Set PR, IR and CTCR Registers...
            ZeroValueRegisters();

            #region Set the Latch Enable Register Settings....

            // See the SetLatchEnableRegister method Description Above...
            byte[] bit = { 1, 0, 0, 0, 0, 0, 0 };
            SetLatchEnableRegister(bit);

            #endregion

            #region Enable the Timer Control Register (PWM1TCR) Enable the Timer and PWM Mode...

            // Enable the Timer Control Register (PWM1TCR) Enable the Timer and PWM Mode...
            Register PWM1TCR = new Register(LPC23xx.PWM1TCR);
            PWM1TCR.Write(0x09U);

            #endregion
        }

        /// <summary>
        /// Typically this section is not needed as the Values are already what we need... All 0...
        /// You can call this methods if you need to...
        /// </summary>
        private static void ZeroValueRegisters()
        {
            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Prescale Register (PWM1PR - 0xE001 800C)
            // See Page: 567 - LPC23XX User manual Rev. 02 — 11 February 2009...
            // The TC is incremented every PR+1 cycles of PCLK.
            //_______________________________________________________________________________________________________
            Register PWM1PR = new Register(LPC23xx.PWM1PR);
            PWM1PR.Write(0);

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PWM Interrupt Register (PWM1IR - 0xE001 8000)
            // See Page: 568 - LPC23XX User manual Rev. 02 — 11 February 2009...
            //_______________________________________________________________________________________________________
            Register PWM1IR = new Register(LPC23xx.PWM1IR);
            PWM1IR.Write(0);

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // PWM Count Control Register (PWM1CTCR - 0xE001 8070)
            // See Page: 569 - LPC23XX User manual Rev. 02 — 11 February 2009...
            //_______________________________________________________________________________________________________
            Register PWM1CTCR = new Register(LPC23xx.PWM1CTCR);
            PWM1CTCR.Write(0);

        }

        /// <summary>
        /// Set the Pin Number, the base Frequency and the Duty Cycle of the PWM...
        /// </summary>
        /// <param name="Pin">int - PWM Pins 1 - 6</param>
        /// <param name="Frequency">double - Frequency in Hz. Clock is 72Mhz.</param>
        /// <param name="DutyCycle">int - Values 0 - 100 are valid Duty Cycle values.</param>
        public static void SetPWM(int Pin, double Frequency, int DutyCycle)
        {
            // Check Input from User...
            if (Frequency >= 1 && Frequency <= 72000000)
            {
                // Set Frequency in Hz...
                _frequency = (uint)(72000000 / Frequency);
            }

            Register PWM1MR0 = new Register(LPC23xx.PWM1MR0);
            PWM1MR0.Write(_frequency);

            switch (Pin)
            {
                case 1:
                    SetPWM1Duty(DutyCycle);
                    break;
                case 2:
                    SetPWM2Duty(DutyCycle);
                    break;
                case 3:
                    SetPWM3Duty(DutyCycle);
                    break;
                case 4:
                    SetPWM4Duty(DutyCycle);
                    break;
                case 5:
                    SetPWM5Duty(DutyCycle);
                    break;
                case 6:
                    SetPWM6Duty(DutyCycle);
                    break;
                default:
                    Debug.Print("Invalid selection. Please select 1, 2, or 3.");
                    break;
            }
        }

        /// <summary>
        /// Calculate Duty Percentage - User Inputs say 50, which will be a percentage of the Frequency that has been selected...
        /// This sets the Duty Cycle of the Frequency to a value of 50%, so 50% on and 50% off in one cycle...
        /// </summary>
        /// <param name="percentage"></param>
        /// <returns></returns>
        private static uint CalculateDutyPercentage(double percentage)
        {
            // Calculate the Percentage Divider...
            double devider = (percentage / 100.0);

            // Calculate the Percentage of the Frequency...
            double dutyCycle = (((double)_frequency) * devider);

            // Return the calculated Duty Cycle...
            return (uint)dutyCycle;
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM1 - Di10 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM1Duty(int dutyCyclePercentage)
        {
            _dutyMR1 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 1 Register...
            Register PWM1MR1 = new Register(LPC23xx.PWM1MR1);
            PWM1MR1.Write(_dutyMR1);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 1, 0, 0, 0, 0, 0 };
            SetLatchEnableRegister(bit);
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM2 - Di9 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM2Duty(int dutyCyclePercentage)
        {
            _dutyMR2 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 2 Register...
            Register PWM1MR2 = new Register(LPC23xx.PWM1MR2);
            PWM1MR2.Write(_dutyMR2);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 0, 1, 0, 0, 0, 0 };
            SetLatchEnableRegister(bit);
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM3 - Di8 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM3Duty(int dutyCyclePercentage)
        {
            _dutyMR3 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 3 Register...
            Register PWM1MR3 = new Register(LPC23xx.PWM1MR3);
            PWM1MR3.Write(_dutyMR3);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 0, 0, 1, 0, 0, 0 };
            SetLatchEnableRegister(bit);
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM4 - Di10 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM4Duty(int dutyCyclePercentage)
        {
            _dutyMR4 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 4 Register...
            Register PWM1MR4 = new Register(LPC23xx.PWM1MR4);
            PWM1MR4.Write(_dutyMR4);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 0, 0, 0, 1, 0, 0 };
            SetLatchEnableRegister(bit);
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM5 - Di5 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM5Duty(int dutyCyclePercentage)
        {
            _dutyMR5 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 5 Register...
            Register PWM1MR5 = new Register(LPC23xx.PWM1MR5);
            PWM1MR5.Write(_dutyMR5);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 0, 0, 0, 0, 1, 0 };
            SetLatchEnableRegister(bit);
        }

        /// <summary>
        /// Set the PWM Duty Cycle on PWM6 - Di6 on the FEZ PandaII...
        /// </summary>
        /// <param name="dutyCyclePercentage">Duty Cycle Example (0 - 100)</param>
        private static void SetPWM6Duty(int dutyCyclePercentage)
        {
            _dutyMR6 = CalculateDutyPercentage(dutyCyclePercentage);

            // Set the Match 6 Register...
            Register PWM1MR6 = new Register(LPC23xx.PWM1MR6);
            PWM1MR6.Write(_dutyMR6);

            // Set the Latch Enable Register...
            byte[] bit = { 1, 0, 0, 0, 0, 0, 1 };
            SetLatchEnableRegister(bit);
        }


    } // END of Class...
} // END of Namespace...


To call my code and make it all work use this:


using System;
using System.Threading;

using Microsoft.SPOT;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Panda_II_HardWarePWM
{
    public class Program
    {
        public static void Main()
        {

            // Disable Garbage Collection...
            Debug.EnableGCMessages(false);

            // Set a Frequency Variable...
            double frequency = 1; 

            // Setup PWM Registers...
            HardWarePWM.Setup();

            while (true)
            {
                // Increment the Frequency...
                frequency++;

                // Set the Frequency and Duty...
                HardWarePWM.SetPWM(2, frequency, 50);

                // Sleep for 10 milliseconds...           
                Thread.Sleep(10);
            }
        }
    }
}


This code works perfectly except for the above problems. Theoretically we should be able to set Frequencys from 1Hz to 72MHz - It seems to be a bit slow at High Frequencys and I need to do more testing on this. It seems to me that the PWM Class in the in the GHI SDK is implimented in a slightly different way. I believe my Code has some advantages over the PWM Class. The Wave form is much cleaner at low frequencys and various other things. Maybe Gus can eloborate on the differences more?

Please let me know if you spot any problems in this code. It is excessively commented - alot of code in the CodeShare and this forum is not very well commented at all and thats good for the experienced but hopeless for the not so much experienced…

This code is in the early stages and may be changed soon due to a few small limitations in the PWM…

Thanks

ChrisO

ChrisO,

you better put this on CodeShare even if it is not 100% according to your needs. On CodeShare you can always upload new revisions.

Hi EriSan500,

Done

The Codeshare URL is : http://www.tinyclr.com/codeshare/entry/450

Thanks

ChrisO

@ ChrisO - Be kind to your silicon. A gpio pin is struggling even at min rise/fall times at 72MHz and at max rise/fall times wont make 72MHz. That would be at perfect loading and circuit layout.

Hi Davef,

To find the absolute limits in this project I will need to push the Silicon hard… There is only two PWM Channels, PWM0 and PWM1. I will be experimenting more on Multi Channel outputs now also which will push the “Silicon” even harder now.

72Mhz is as you say an un-realistic maximium Frequency though. More testing will give me a better idea on the limits that I can achieve. The GHI PWM Class seems to become a bit unresponsive at 90KHz, my Class still works and is responsive at 900Khz… This is at a 10ms Response time to changes…

As you can tell from my Code its a slow process to keep a sweep going and monitoring it all the way through the sweep.

I also expermented with this sweep last night:


using System;
using System.Threading;

using Microsoft.SPOT;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Panda_II_HardWarePWM
{
    public class Program
    {
        private static double frequency;

        public static void Main()
        {
            // Disable Garbage Collection...
            Debug.EnableGCMessages(false);

            // Set a Frequency Variable...
            frequency = 1;

            // Setup PWM Registers...
            HardWarePWM.Setup();

            // Sweep Frequency..
            Sweep();
        }

        private static void Sweep()
        {
            while (frequency < 20)
            {
                // Increment the Frequency...
                frequency++;

                // Set the Frequency and Duty...
                HardWarePWM.SetPWM(1, frequency, 50);

                // Sleep for 500 milliseconds...           
                Thread.Sleep(500);
            }

            while (frequency > 1)
            {
                // Increment the Frequency...
                frequency--;

                // Set the Frequency and Duty...
                HardWarePWM.SetPWM(1, frequency, 50);

                // Sleep for 500 milliseconds...           
                Thread.Sleep(500);
            }

            // Loop Here...
            Sweep();
        }
    }
}


This works real nice! Looks good on a LED!

My previous problems still remain however. If anyone has any suggestions on how to fix them please let me know as I think it would make this project so much more benificial for everyone!

All the Best…

ChrisO

ChrisO

I think the problem you are seeing is due to you working with too many abstaction layers. You have done most of the heavy work, why not transfer the driver to RLP?

Hi Davef,

I hear you, RLP is not something I have played around with and really have no experience in. I have done a small amount of C++ but C# is more my area.

I see where you are going though and tend to agree that its all just too many layers trying to do too much.

I will improve the code to the point I am happy with the end result then look at doing this in the next stage as transfering it now may be a waste of time if it is not as flexable as I need it to be.

Thanks for the advise!

ChrisO

Hi All,

Initial tests show good response at 12Mhz @ 100ms 100 Hz changes.

The wave form is a bit distorted however. Filtering will likely fix this.

My impedance is an LED.

all the best

ChrisO

ChrisO,
Whats the waveform like without the LED. RLP is very flexible.

Hey Davef,

still quite distorted but not to bad, its better as would be expected…

[EDIT] I have just added Pictures, srry they are not 100% clear but you can see whats going on…

Cheers

ChrisO

Just another small update,

I set a frequency of 25MHz and It also works but I have discovered another problem. The measured Frequency is 36MHz with no Impedance (LED), and 71.926Mhz with an Impedance (LED) Connected.

Seems we are seeing the max frequency response around 25Mhz for the PWM1 Channel.

The wave is very sine wave looking at this frequency!

All the Best

ChrisO

ChrisO,

The over and under shoot of the waveform, could be that you have not calibrated your probe? Try calibrating from the 1KHz cal point on the scope.

Hey Davef,

@ 1KHZ the Shoot is out by a Nats Coc*.

All the best

ChrisO