This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Problem with PWM : using LM4F120H5QR

I am facing the problem while generating PWM using timer0 on my LM4F120H5QR controller at pin PB6.

if we calculate the clock ticks then to generate the frequency of 50Hz I should put 8,00,000 in LoadSet Value. (AM I WRONG?)

And as I want 5% duty cycle (1ms on time + 19ms off time = 20ms) I've used 760000 as my MatchSet value.(AM I WRONG?)

In short I am using following line of codes to do this : (I've got this from Lab4 of Launchpad workshop of TI) (at 40 MHz)

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
    ulPeriod = ((SysCtlClockGet() / 50 /2);
    TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod -1);

 I am getting 50Hz with 50% duty Cycle on Digital Oscilloscope, But not able to set the dutycycle...(I've tried various matchset value but- no result)

Then I've tried by enabling T0CCP0 which I've got from one of the blogs related to this:

// 40 MHz system clock
    SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

// Configure PB6 as T0CCP0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB6_T0CCP0);
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);

// Configure timer
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PERIODIC);
    TimerLoadSet(TIMER0_BASE,  TIMER_A, ulPeriod -1);
    TimerMatchSet(TIMER0_BASE,  TIMER_A, dutyCycle); // PWM
    TimerEnable(TIMER0_BASE, TIMER_A);


Here the value of ulPeriod can last for max. 131070 (65535 x2) - may be because I am splitting the timer. (I've checked on oscilloscope that for 131070; I am getting 610 Hz.)

but I need to set 800000 as a ulPeriod (I think it is right!! for 50 Hz? am I wrong?) And for that I should not split the timer.

But I haven't get any guidance/example/idea to use 32/64 bit timer to generate PWM pulse. I've gone through documents of API functions..

And also have applied some of them to start 32/64 bit timers but :( I am unable to do that.

Can someone please indicate where I am missing what ??

  • Note: fast forward to bottom for suggested answer - much "monkey motion" earlier...

    Quickly (have meeting) iirc the Timers - when operated in PWM Mode - limit you to 16 bits.  Thus - the values you're supplying are too large.   (this from memory - give a read of MCU datasheet to confirm)

    A fast, reasonable check of my assertion could be made by limiting such values to 65,535 - and seeing if Timer's PWM output then complies...

    Update: fast/reasonable - my 16 bit limit was wrong!   Here (a true copy) from our LX4F (not yours) datasheet:

    10.3.2.5 PWM Mode
    The GPTM supports a simple PWM generation mode. In PWM mode, the timer is configured as a
    24-bit or 48-bit down-counter with a start value (and thus period) defined by the GPTMTnILR and
    GPTMTnPR registers.

    Now - to realize 24 bits you must employ the pre-scaler - suspect you're better off to employ one of the "wide" timers - which yield 32 bits w/no such prescale complication nor requirement.   Someone - (or me) will check your code later today - but if you've not chosen "wide" timer - that would be a reasonable exercise...

    Update 2: appears that you've updated your original post - now bringing "wide" timers into the fold.  Clearly - I did not note those @ first read!

    Now my 64 pin LX4F sports 12 "wide" timers - available across a wide variety of pins.  And - ideally for you - 32 bits extends your count range to 4,294,967,296.

    You are not configuring the Timer properly for PWM operation!   "TIMER_CFG_A_PWM" per SW-DRL-UG is the correct parameter. 

    As best I can tell - selecting the wide timer (0 here) is achieved via: "WTIMER0_BASE"  (that is one of many)

    Thus:  TimerConfigure(WTIMER0_BASE, TIMER_CFG_A_PWM);  should "better approach" what you seek.  (I've not time to test...)  

    And - of course - you must SysCtlPeripheralEnable() this new WTIMER0_BASE - and any/all other required set-ups...

  • Thanks for your response sir.

    According to your suggestions, I've update my code.

    I am not able to verify it now.. but will check it tomorrow in my college.

    But still It would be better for me if you could verify it theoretically. I mean, am I still missing something or the code should work now.

    #define PART_LM4F120H5QR true

    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "driverlib/timer.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/cpu.h"
    #include "driverlib/rom.h"

    int main(void)
    {
        unsigned long ulPeriod, dutyCycle;

        // 40 MHz system clock
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

        ulPeriod = 800000;
        dutyCycle = 760000;

        // Turn off LEDs
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
        ROM_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);

        // Configure PB6 as T0CCP0
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        ROM_GPIOPinConfigure(GPIO_PB6_T0CCP0);
        ROM_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);

        // Configure timer
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
        ROM_TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC|TIMER_CFG_A_PWM);
        ROM_TimerLoadSet(WTIMER0_BASE, TIMER_A, ulPeriod -1);
        ROM_TimerMatchSet(WTIMER0_BASE, TIMER_A, dutyCycle); // PWM
        ROM_TimerEnable(WTIMER0_BASE, TIMER_A);

        while(1) {}

    // Thanks to cb1_mobile

  • Don't have your board schematic handy - but do note that, "PB6 as T0CCP0" (continued from your past) is not the correct definition for my suggested "wide" timer!  PB6 is your same, failed, standard timer - which we've replaced.  Replace all references to PB6/T0CCP0 - unless you will use it for other (undefined here) purposes.

    Quick read of your MCU's datasheet reveals: PC4, PC6, PD0, PD2, PD4 & PD6 each as "wide" timer appropriate.  (but only one of these is WTIMER0)  I list all 6 as not all will likely "make it" to your board's edge connector - you must choose one which is so routed.  (and then possibly alter to WTIMERX)  And you must then SysCtlPeriphalEnable() that chosen port and both GPIOPinConfigure() & GPIOPinType() the newly chosen, WTIMER pin. 

    Note you've altered my suggested TimerConfigure() - adding, "TIMER_CFG_PERIODIC."  Don't believe that is necessary - may in fact be harmful.

    With a TimerLoadSet value of 800,000 - any subtraction of 1 seems meaningless. 

  • And here - guaranteed, "Good for Gov't Work!"  Standard - "redistributive" 30 day/30 feet warranty applies.  (tested/verified on LX4F - not your device)

    void
    wide_timer_set_up(void)
    {
     
      SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER4);
      SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
      GPIOPinConfigure(GPIO_PD4_WT4CCP0);
      GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_4);
      TimerConfigure(WTIMER4_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
      TimerLoadSet(WTIMER4_BASE, TIMER_A, 800000);     // 3rd parameter -> PWM frequency - larger val reduces
      TimerMatchSet(WTIMER4_BASE, TIMER_A, 750000);   // 3rd parameter -> PWM duty cycle - larger val reduces
      TimerEnable(WTIMER4_BASE, TIMER_A);
     
    }

    I chose PD4 as it was routed to my custom board's edge connector - easing scope connection.  My System Clock was/is set to 50MHz - thus I'm bit over your desired 50Hz - but code is proven - compiles/runs w/out complaint.  (and my system clock is pre-coded w/in SPI Data Flash - along w/multiple fonts, graphic images/icons - thus not quick/easy (nor desired) to alter)

    For completeness (really curiosity) loaded/ran the ROM version of each/every function, above.  Results unchanged.  (proves that wide timer made it into ROM...)

    For those "follow on" readers: "GPIO_PD4_WT4CCP0" is found w/in file "pin_map.h" - and your IDE likely will require some "hoop-jumping" (i.e. must properly specify your MCU) for the "giant" pin_map.h file to search & locate.  (pin_map.h contains definitions for many, many Stellaris MCUs)

    Code listing produces continuous PWM output (requires no loop) and may be easily halted via: TimerDisable() - restarted w/ TimerEnable().

     

  • Hi

    Thanks for sharing your code.

    I am trying to generate 2 PWM outputs with frequency 5Hz on LM4F232H5QD Eval board on Pins PD0(WT2CCP0) and PD1(WT2CCP1). The code based on your examples produces only 1 output on PD1. Any hints, why and how to make both outputs work?

    void InitTimerPWM(void)

    // from here http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/249597.aspx

    {

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER2);

    //MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); // already done

    MAP_GPIOPinConfigure(GPIO_PD0_WT2CCP0);

    MAP_GPIOPinConfigure(GPIO_PD1_WT2CCP1);

    MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_0);

    MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_1);

    MAP_TimerConfigure(WTIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);

    MAP_TimerConfigure(WTIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);

    MAP_TimerLoadSet(WTIMER2_BASE, TIMER_A, 8000000);

    MAP_TimerMatchSet(WTIMER2_BASE, TIMER_A, 7500000);

    MAP_TimerLoadSet(WTIMER2_BASE, TIMER_B, 8000000);

    MAP_TimerMatchSet(WTIMER2_BASE, TIMER_B, 7500000);

    MAP_TimerEnable(WTIMER2_BASE, TIMER_A);

    MAP_TimerEnable(WTIMER2_BASE, TIMER_B);

    }

    Jan

     

  • Fixed, works great. Thanks again for your code.

    void InitTimerPWM(void)
    // from here http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/249597.aspx
    // another example here http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/236151.aspx
    {
          MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER2);
          //MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);    // already done
          MAP_GPIOPinConfigure(GPIO_PD0_WT2CCP0);
          MAP_GPIOPinConfigure(GPIO_PD1_WT2CCP1);
          MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_0);
          MAP_GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_1);
          MAP_TimerConfigure(WTIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);
          //MAP_TimerConfigure(WTIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);
          MAP_TimerLoadSet(WTIMER2_BASE, TIMER_A, 40000);    // 40MHz / 40000 -> 1kHz
          MAP_TimerMatchSet(WTIMER2_BASE, TIMER_A, 20000);
          MAP_TimerLoadSet(WTIMER2_BASE, TIMER_B, 8000000);    // 40MHz / 8000000 -> 5Hz
          MAP_TimerMatchSet(WTIMER2_BASE, TIMER_B, 4000000);
          MAP_TimerEnable(WTIMER2_BASE, TIMER_A | TIMER_B);
          //MAP_TimerEnable(WTIMER2_BASE, TIMER_B);
    }