Stellaris Launchpad PWM Tutorial

After receiving my Stellaris Launchpad, I decided to browse the little amount of tutorials there was available on the subject. I was really impressed by the Getting Started hands-on workshop offered in TI’s wiki. After watching the first few tutorials, I had a somewhat firmer grasp on how this little puppy was supposed to be programmed, and the capabilities of the Code Composer Studio IDE.

I got as far as Chapter 4: Interrupts until I hit the first snag: After the Lab4 assignment, the friendly instructor told that as a home assignment, one could try out the PWM (pulse-width modulation) capabilities of the Launchpad before proceeding further. Little did I know how many hours I would spend on that topic! After a solid 8 hours of banging my head against the documentation, Launchpad and CCS (which is prone to hanging at least on my PC), I finally got it working, and decided this would be a great place for a tutorial.

Rule 1 of PWM on Launchpad: There are no PWM units

The initial four hours of my PWM efforts were spent on the StellarisWare Driverlib documentation concerning PWM. In case you haven’t yet watched the tutorials, the Driverlib is essentially a bundle of code that takes away the burden of writing into dozens of control registers, and instead presents the programmer with a couple of hundred API calls to enable a higher-level approach.

It wasn’t until the third hour of googling around that I discovered, that while the timer functionality of the Launchpad includes a PWM mode, there are no actual PWM units on board! So if you’re looking at the PWM functions in Chapter 21 of Stellaris Peripheral Driver Library User’s Guide – stop it and get back to the Chapter 27: Timer functions.

Step 1: Setting up the timer0 PWM mode

So the only PWM functionality the Launchpad supports is the “PWM mode” of the six hardware timers. Thankfully, that’s already quite nice (if I ever find out how to use interrupts with PWM, even better). So unless you already know how the timer system works, now’s a good time to watch the Chapter 4 video which explains it quite nicely. Based on that tutorial, we learn that the following piece of code should initialize the timer for us:

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

ulPeriod = (SysCtlClockGet() / 10) / 2;
TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod - 1);

TimerEnable(TIMER0_BASE, TIMER_A);


I removed the interrupt enabling part of code as we don’t need that. Also, the TIMER_CFG_32_BIT_PER constant was deprecated, so TIMER_CFG_PERIODIC is used instead.

In order to use the PWM mode, we only need to change the TIMER_CFG_PERIODIC to PWM (also requires setting the timer to split mode so there’s two 16-bit timers instead of one 32-bit one), and specify a match value which defines the duty cycle of our PWM:

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);

ulPeriod = 1000; // with a 16-bit timer, maximum is 65535
dutyCycle = 250; // 75 % duty cycle (0.25 * ulPeriod)

TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod - 1);
TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle);
TimerEnable(TIMER0_BASE, TIMER_A);

In normal operation, counter counts down from “load value” and PWM signal stays high until the counter reaches “match value”, at which point PWM signal goes down and stays there until timer reaches zero, at which point the counter is reset to “load value”, PWM signal goes back up, and downcount continues. In the above example, timer counts down from 1000 and PWM goes low when it reaches 250 (i.e. after 750 cycles), and then stays low for 250 cycles, after which counter resets to 1000 and PWM goes up again.

Step 0: Enabling Timer 0 Capture Compare PWM pins (CCP)

Now comes the tricky part. After enabling PWM mode and checking with scope, it’s easily verified that no pin on the Stellaris Launchpad is toggling at any rate, against any possible assumptions that might suggest otherwise. The reason for this is that the ARM core has the capability to use its pins for multiple purposes, and we need to specifically request that the Timer 0 CCP functionality is enabled.

From the LM4F120H5QR datasheet, page 658, chapter 11-1, Table 11-1 we discover that Timer 0 subtimer A is connected to CCP pin called “T0CCP0″. From the next page and Table 11-2 we discover that this pin can be assigned to PB6 or PF0. Several registers need to be set for this to happen, but thankfully the Driverlib also has a nice function for this – it only requires about three hours of googling around to find the magic incantations. What you need to do is:

  1. Define the constant PART_LM4F120H5QR
  2. include driverlib/pin_map.h
  3. (now we have GPIO_PB6_T0CCP0 defined)

  4. Use SysCtlPeripheralEnable() to enable Port B
  5. Call GPIOPinConfigure(GPIO_PB6_T0CCP0); to mux T0CCP0 to PB6
  6. Call GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6); to set up the pin

Pretty easy, wasn’t it? No, it wasn’t. And I can tell you that there is very scarce information yet available on this matter. And TI’s documentation on timer PWM modes with Driverlib is totally nonexistent, so it took me full three hours of trying to get all the details done. Thanks to Bakr Younis at TI forums for the final tips.

Oh, and to define the constant, you may want to go to project properties (I assume everyone is capable of creating an empty project already in CCS), and select Build / Advanced Options / Predefined Symbols / Add Pre-define NAME and type “PART_LM4F120H5QR” into the dialog. An example of how it should look like is given on the right.

Wrapping it all together

All right! We have everything more or less in place. The full source code becomes:

#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"

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

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

    ulPeriod = 1000;
    dutyCycle = 250;

    // Turn off LEDs
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);

    // 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_PWM);
    TimerLoadSet(TIMER0_BASE, TIMER_A, ulPeriod -1);
    TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle); // PWM
    TimerEnable(TIMER0_BASE, TIMER_A);

    while(1) { // The following code varies the duty cycle over time
        TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle++);

        if(dutyCycle >= ulPeriod - 1)
            dutyCycle = 0;

        SysCtlDelay(50000);
    }
}

After wiring the Launchpad to my trusty old (you can see the dust in the post title image if you click it full size :) Picoscope, it’s easy to verify the code actually works:

That’s it! Based on this tutorial, it should be quite easy to set up more PWM signals, or once you realize that the Launchpad LEDs are located in PF1-3 that in turn can be controlled by T0CCP1, T1CCP0, and T1CCP1, you can also set up all kinds of cool color displays like in the Stellaris Launchpad demo program.

Oh, and if someone is able to figure out how in the hell am I supposed to set up timer-based PWM interrupts so I can get interrupted on both timer reset and match and figure out which one, please let me know. Based on some “quick” (one hour down the drain) tests, the PWM functionality stops working once timer interrupts get set up. You’d think it would be rather straightforward using Driverlib, but in that case you’d think wrong.

Published by

Joonas Pihlajamaa

Coding since 1990 in Basic, C/C++, Perl, Java, PHP, Ruby and Python, to name a few. Also interested in math, movies, anime, and the occasional slashdot now and then. Oh, and I also have a real life, but lets not talk about it!

48 thoughts on “Stellaris Launchpad PWM Tutorial”

  1. //This code will PWM the leds

    #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”

    int main(void) {
    unsigned long ulPeriod_led_f1, dutyCycle_led_f1, ulPeriod_led_f2, dutyCycle_led_f2, ulPeriod_led_f3, dutyCycle_led_f3;

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

    ulPeriod_led_f1 = 1000;
    dutyCycle_led_f1 = 1;
    ulPeriod_led_f2 = 1000;
    dutyCycle_led_f2 = 1;
    ulPeriod_led_f3 = 1000;
    dutyCycle_led_f3 = 1;

    // Turn off LEDs
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0);

    // Configure LEDs PortF as Timer outputs -> see pg 659 of datasheet
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinConfigure(GPIO_PF1_T0CCP1|GPIO_PF2_T1CCP0|GPIO_PF3_T1CCP1);
    GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);

    // Configure timer 0 – this timer outputs to pf1 (led)
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM);
    TimerLoadSet(TIMER0_BASE, TIMER_B, ulPeriod_led_f1 -1);
    TimerMatchSet(TIMER0_BASE, TIMER_B, dutyCycle_led_f1); // PWM
    TimerEnable(TIMER0_BASE, TIMER_B);

    //Configure timer 1 – timer is split in half; A and B timers (16 bit)
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM);

    //Values and settings for Timer1(A) – this timer outputs to pf2
    TimerLoadSet(TIMER1_BASE, TIMER_A, ulPeriod_led_f2 -1);
    TimerMatchSet(TIMER1_BASE, TIMER_A, dutyCycle_led_f2); // PWM
    TimerEnable(TIMER1_BASE, TIMER_A);

    //Values and settings for Timer1(B) – this timer outputs to pf3
    TimerLoadSet(TIMER1_BASE, TIMER_B, ulPeriod_led_f3 -1);
    TimerMatchSet(TIMER1_BASE, TIMER_B, dutyCycle_led_f3); // PWM
    TimerEnable(TIMER1_BASE, TIMER_B);

    while(1) { // The following code varies the duty cycle over time, it cycles duty cycles at different rates
    TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle_led_f1++);
    TimerMatchSet(TIMER1_BASE, TIMER_A, dutyCycle_led_f2=dutyCycle_led_f2+2);
    TimerMatchSet(TIMER1_BASE, TIMER_B, dutyCycle_led_f3=dutyCycle_led_f3+4);

    if(dutyCycle_led_f1 >= ulPeriod_led_f1 – 1)
    dutyCycle_led_f1 = 0;

    if(dutyCycle_led_f2 >= ulPeriod_led_f2 – 1)
    dutyCycle_led_f2 = 0;

    if(dutyCycle_led_f3 >= ulPeriod_led_f3 – 1)
    dutyCycle_led_f3 = 0;

    SysCtlDelay(200000);
    }
    }

      1. What compiler are you using?It looks like you are using etheir CCS or IAR, this code is not compatible with etheir oneyou may have to enable the interrupt another way (gie bit), and you will have to change how the interrupt is called (#pragma)please let me know how you get it to work and i will update my post to add your changes

        1. The wrong is

          while(1) { // The following code varies the duty cycle over time, it cycles duty cycles at different rates
          TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle_led_f1++);

          It should be

          while(1) { // The following code varies the duty cycle over time, it cycles duty cycles at different rates
          TimerMatchSet(TIMER0_BASE, TIMER_B, dutyCycle_led_f1++);

    1. Hello,

      The wrong line is;
      GPIOPinConfigure(GPIO_PF1_T0CCP1|GPIO_PF2_T1CCP0|GPIO_PF3_T1CCP1);

      It should be as follows;
      ROM_GPIOPinConfigure(GPIO_PF3_T1CCP1);
      ROM_GPIOPinConfigure(GPIO_PF2_T1CCP0);
      ROM_GPIOPinConfigure(GPIO_PF1_T0CCP1);

      And good point to add invert outputs;
      // invert PWM outputs
      TIMER0_CTL_R |= 0x4000;
      TIMER1_CTL_R |= 0x4000;
      TIMER1_CTL_R |= 0x40;

      1. I had the same problem, changed the mentioned line to:


        GPIOPinConfigure(GPIO_PF1_T0CCP1);
        GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_1);
        GPIOPinConfigure(GPIO_PF2_T1CCP0);
        GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_2);
        GPIOPinConfigure(GPIO_PF3_T1CCP1);
        GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3);

        that seems to work. See also page 159 of the Stellaris Peripheral Driver Library

        1. both GPIOPinConfigure(GPIO_PF1_T0CCP1|GPIO_PF2_T1CCP0|GPIO_PF3_T1CCP1); and ROM_GPIOPinConfigure(GPIO_PF3_T1CCP1);
          ROM_GPIOPinConfigure(GPIO_PF2_T1CCP0);
          ROM_GPIOPinConfigure(GPIO_PF1_T0CCP1); is same mistake; #20 identifier “GPIO_PF3_T1CCP1″ is undefined

          what would be problem. I’m stuck here. ı m using CCS 5.3

  2. A solution to fire both interrupts on capture and on timer reset would be to use 2 syncronized timers one as PWM and the other just as a periodic one as suggested .

    1. Thanks for your input! Sorry that your comments took some time to appear, for some reason Akismet thought they were spam, which they definitely were not. :)

  3. You might want to check out the Stellaris PinMux utility on the TI website. It helps in setting up the alternate pin functions. I have found the learning curve for Stellaris steep, owing largely to a dearth of (clear) documentation. Your example also cleared up an issue I just ran into while using the UARTs-some constants used by the pin mapping were indefined even though the compiler was finding the include file. One would assume that specifying the chip when the project was created would have resulted in PART_LM4F120H5QR being defined. Apparently not so. I cannot see any reason for this not being an automatic feature.

  4. Here is how I managed to use interrupts with timer0 in PWM mode. Hope it helps.

    in main(void) :

    /*#include all necessary headers from previous examples */
    #include “inc/hw_timer.h” /* to gain access to TIMER_O_TAMR, etc. timer registers */

    /* As in the previous examples – setup clock, enable used peripherals, setup GPIOs here */

    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM);

    /* Make corresponding CCP pin go HIGH (going LOW is the default legacy operation) in the beginning of the PWM period (TAPLO = 1)
    * (not really needed if we only care for interrupts);
    * Make the changes to match registers take effect on the start of the next PWM period, not immediately (TAMRSU = 1);
    * Make the changes to reload (period) registers take effect on the start of the next PWM period, not immediately (TAILD = 1);
    *
    * NOTE: the PWM with interrupts should work even without this line, but the datasheet says it’s better to set the MR this way */
    HWREG(TIMER0_BASE + TIMER_O_TAMR) |= (TIMER_TAMR_TAMRSU | TIMER_TAMR_TAPLO | TIMER_TAMR_TAILD);

    /* Make the timer generate events on both rising and falling PWM edges */
    TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_BOTH_EDGES);

    /* Setup interrupts */
    TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);
    IntEnable(INT_TIMER0A);
    IntMasterEnable();
    TimerEnable(TIMER0_BASE, TIMER_A);
    while(1)
    {
    /* main loop here */
    }

  5. Wrong again :( :(
    Last attempt, if this does not work, please erase all the mess and mail me to (address removed) – I will send you the project.

    void Timer0IntHandler(void)
    {
    uint32_t tmr_val;
    uint32_t tmr_match;
    uint32_t InterruptStatus = TimerIntStatus(TIMER0_BASE, true);

    if(InterruptStatus & TIMER_CAPA_EVENT)
    {
    TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
    /*get the 24-bit current value of the timer's counter*/
    tmr_val = TimerValueGet(TIMER0_BASE, TIMER_A);
    /* compose the 24-bit match value */
    tmr_match = TimerPrescaleMatchGet(TIMER0_BASE, TIMER_A)*65536UL
    + TimerMatchGet(TIMER0_BASE, TIMER_A);
    if(tmr_val > tmr_match)
    {
    /* the interrupt is caused by a reload (start of a new PWM period) */
    /* Turn the red LED on */
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_PIN_1);
    }
    else
    {
    /* the interrupt is caused by a match (end of a PWM pulse) */
    /* Turn the red LED off */
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1, 0x00);
    }
    }
    }

        1. Hi,
          I will gladly send you the project, I just need to get home – its on the PC there. However…. I would need your e-mail, and I am afraid this site won’t let you publish it. Try mailing me at babatowatyahoodotcom (hope this does not get filtered).
          Looking forward to hearing from you,
          Ivan.

  6. Thank you very much I was able to get this working but may I ask for future reference…What is the point of defining the symbol “PART_LM4F120H5QR” ? Is it so that the compiler knows which device to look under in the pin_map? That’s just my wild guess since I was finding that CSS kept telling me GPIO_PF1_T0CCP1 was an unrecognized symbol up until I pre-defined the PART_LM4F120H5QR symbol in the project options.

    1. It’s so that the proper pin mappings from pin_map.h are pulled into the project. Believe me, took a little bit for me to figure that out the first time until I looked in the file, saw all the defines and went “aww hell!”

      1. Yes, one would assume the correct part constant is defined by other include files based on build target platform (one needs to set it when creating project, anyways), but no, you actually have to define that yourself. Very counterintuitive and there’s no mention of that in the documentation..

  7. There is an error in the tutorial code

    under Step 1: Setting up the timer0 PWM mode

    In the second code box dutyCycle is never used.

    I believe the line that reads
    TimerMatchSet(TIMER0_BASE, TIMER_A, ulPeriod / 2);
    should read
    TimerMatchSet(TIMER0_BASE, TIMER_A, dutyCycle);
    as it does in the final code box.

  8. Hey all!. This one has helped me a lot. i want to do a down counter. So i need to use TimerB of the timer0 and use the same way as above?

  9. To configure interrupts for PWM:

    TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);
    TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE);
    TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0AIntHandler);

    void Timer0AIntHandler(void) {
    TimerIntClear(TIMER0_BASE, TIMER_EVENT_POS_EDGE);
    ...
    }

  10. Hey I love this tutorial!!! Great work. I do have two questions though.

    1. Can you change the frequency of the PWM wave? Currently mines is at 40 kHz which is great but it would be nice to change the frequency for applications like servo driving.

    2. Can you achieve a 0% duty cycle? when I enter in 0% (1000) the PWM wave goes to 100% (3.3V)

    Thanks for your help

  11. Just wanted to say thank you so much for such a detailed and throughout write-up.
    Side note: We did include the PWM in the next revision of the board :-), but this helps give all of the Stellaris ones in the ecosystem a way to do it!

    Thank you again!

Leave a Reply

Your email address will not be published. Required fields are marked *


one − = 0

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>