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.

PWM signal using Capture/Compare Timer



I am having trouble getting an audio signal using PWM with PD0 on the LM3S9B92 eval board.  I had it working based on the example pwmgen.c using the motion control module, but was unable to get it working using the Capture/Compare/PWM0 functionality of the pin.  Using the example pwm.c in the stellarisware, I wrote the following code.  I am trying to get a 2kHz pulse.

unsigned long ulPeriod;   // PWM period

// The clock is set elsewhere in the code before this point

SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

ulPeriod = MAP_SysCtlClockGet() / 2000; // Compute the PWM period based on the system clock and

MAP_GPIOPinConfigure(GPIO_PD0_CCP6); // Set PWM pin. It is used to output the audio signal.

GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_0);

TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_B_PWM);

TimerLoadSet(TIMER1_BASE, TIMER_B, ulPeriod);

TimerMatchSet(TIMER1_BASE, TIMER_B, ulPeriod/2);  // This will be set to have different duty cycles later on depending on what I want to do, does the Timer have to be disabled when this is called?

//I then call 

TimerEnable(TIMER1_BASE, TIMER_B);

//or

TimerDisable(TIMER1_BASE, TIMER_B);

//every 10ms depending on whether the audio should be on/off

Please note that I am using Timer 1B for the audio, while I am using Timer 1A for a frequency input, and Timer 0A for a output.  I'm not sure if these would conflict in any way.  Any and all help is appreciated.

I also had the motion control PWM working on a LM4F232H5QD board, but in both cases I am having problems with the CCP method.  The Pin I am trying to use on the LM4F board is PC6 which has no motion control module.

Thank you

  • Have you put a scope on the output pin?  Are you getting any output?

    I don't see your code for configuring timer 1A.  Are you sure your 1A code is not clobbering your 1B configuration?

    --
    Miles 

  • There is no change on the output when using a scope to view it.

    Here is how I am enabling Timere 1A.  Do you see a problem with it, I do not think Timer 1A would affect Timer 0B with how we have it configured?

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); /* enable Timer1 for use */
    MAP_TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER|TIMER_CFG_A_PERIODIC); /* Configure Timer1A as a 32-bit*/
    /* periodic timer. */
    MAP_TimerEnable(TIMER1_BASE, TIMER_A); /* Enable Timer1A */

    Thank you for your help

  • I'm a little concerned with this:

    MAP_TimerConfigure(TIMER1_BASE, TIMER_CFG_32_BIT_PER|TIMER_CFG_A_PERIODIC); /* Configure Timer1A as a 32-bit*/
    vs.
    TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_B_PWM);

    Those configurations would be mutually exclusive on TIMER1.  If you made both of those calls then only the most recent would be effective.

    --
    Miles 

  • Well, which one should I be using? PER or PAIR?  A is setup first.  Even if I disable setting up A, B still doesn't give me the output that I am looking for.  When using the LM4F232 chip, I have used 32 bit rather than 16 bit for Timer 0B with same results.

    The way I am trying to setup B is otherwise correct?

  • By default a timer is 32 bits wide.  You can split a single timer into two 16-bit wide timers, ex. TIMER1A and TIMER1B.

    TIMER1 has one configuration register so you must configure the "A-side" and "B-side" at the same time (ie. you must OR the flags together).

    Also note that that your timer load and match values must fit within 16 bits (assuming you split the timer).  This code successfully generates a 50% PWM on an LM4F232 using the general purpose timers:

     unsigned long ulPeriod; // PWM period // // Set the clocking to run directly from the crystal. // SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); // Compute the PWM period based on the system clock ulPeriod = SysCtlClockGet() / 2000; // Is ulPeriod > 16 bits? // // Enable the peripherals used by this example. // SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); GPIOPinConfigure(GPIO_PF3_T1CCP1); GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3); // // Configure the two 32-bit periodic timers. // TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM | TIMER_CFG_A_PERIODIC); TimerLoadSet(TIMER1_BASE, TIMER_A, 0xffff); TimerLoadSet(TIMER1_BASE, TIMER_B, 0x8000); TimerMatchSet(TIMER1_BASE, TIMER_B, 0x4000); // // Enable the timers. // TimerEnable(TIMER1_BASE, TIMER_A); TimerEnable(TIMER1_BASE, TIMER_B);
    
  • Wow.  That was awesome.  Let's try again, this time without the Obfuscated Code Contest styling:

     unsigned long ulPeriod; // PWM period
     //
    // Set the clocking to run directly from the crystal.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
     // Compute the PWM period based on the system clock
    ulPeriod = SysCtlClockGet() / 2000;
     // Is ulPeriod > 16 bits?
     //
    // Enable the peripherals used by this example.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
     GPIOPinConfigure(GPIO_PF3_T1CCP1);
     GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3);
     //
    // Configure the 32-bit timer, split into two 16 bit halves
    //
    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR |
    TIMER_CFG_B_PWM |
    TIMER_CFG_A_PERIODIC);
     TimerLoadSet(TIMER1_BASE, TIMER_A, 0xffff);
    TimerLoadSet(TIMER1_BASE, TIMER_B, 0x8000);
    TimerMatchSet(TIMER1_BASE, TIMER_B, 0x4000);
     //
    // Enable the timers.
    //
    TimerEnable(TIMER1_BASE, TIMER_A);
    TimerEnable(TIMER1_BASE, TIMER_B);
  • thank you, haven't gotten it working yet, but this helps

    ulPeriod = 25000 so it should be good

  • Obfuscated Code Contest styling indeed - friend Miles!  (neat that you checked - and improved - thanks.)

    We noted similar - best forum work-around was to copy code from IDE into Notepad - then copy from Notepad and "paste" to Forum.   Like this...

              // Set the clocking to run directly at 50 MHz.
             //
              ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_25MHZ |
                           SYSCTL_OSC_MAIN);
          //
         //  Enable the GPIO port that is used for the on-board LED.
        //
       //    SYSCTL_RCGC2_R = (SYSCTL_RCGC2_GPIOF | SYSCTL_RCGC2_GPIOC |
      //                     SYSCTL_RCGC2_GPIOD | SYSCTL_RCGC2_GPIOB | SYSCTL_RCGC2_GPIOG);

             HWREG(SYSCTL_RCGC2) = 0x7F;   //   speaking of obfuscation...

    I changed the code's color via "Select Text Color" icon (just right of font size box, above.)  Believe legibility, "good for gov't work" - this method.

  • cb1 - the annoying thing was that I didn't paste that code.  Before I noticed the "preformatted" option from the styling dropdown I hit the "edit HTML source" button and wrapped it all in my own <pre>...</pre> tags.  

    I guess the forum doesn't really support any arbitrary HTML.  *sigh*  You'll always get punished when you deviate from K.I.S.S.

    As an aside, if you're on a Mac, you can hit cmd-shift-v to "paste and match style" which saves you from having to paste to an intermediate editor to ditch the RTF.  

    --Miles

  • @Miles -

     on a Mac, you can hit cmd-shift-v to "paste and match style" - Now that's a great tip!  (when we cut/paste directly from paid IAR - forum output borders on unreadable)

  • Hi Ben,

    The following PWM code runs on the EVM.  It uses the 16/32 vs 32/64 wide timers.  The code differences are highlighted in YELLOW.  I’m contacting apps to see if StellarisWare supports PWM using the wide timer using.

    Regards,
    Mark

        // PWM test code start
        // Enable the peripherals used by this example.
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

        // Configure GPIO pin as PWM output
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
        ROM_GPIOPinConfigure(GPIO_PL0_T0CCP0);
        ROM_GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_0);
        // Configure the timer.
        ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_PWM);
        ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 20000);
        ROM_TimerMatchSet(TIMER0_BASE, TIMER_A, 10000);
        // Enable the timer.
        ROM_TimerEnable(TIMER0_BASE, TIMER_A);
        // Loop forever and blink the led while the timers run.
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTG_BASE, GPIO_PIN_2);
        while(1)
          {
            ROM_GPIOPinWrite(GPIO_PORTG_BASE, GPIO_PIN_2, GPIO_PIN_2);
            ROM_SysCtlDelay(300000);
            ROM_GPIOPinWrite(GPIO_PORTG_BASE, GPIO_PIN_2, 0);
            ROM_SysCtlDelay(300000);
            }
        // PWM test code end

     

  • The following code fixed the problem.  We needed to reference WTIMER1_BASE, not TIMER1_BASE.  I’ve got it running on the EVM.

        // Alliance code start
        // Compute the PWM period based on the system clock
        ulPeriod = SysCtlClockGet() / 2000;
        //
        // Enable the peripherals used by this example.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER1);
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
        ROM_GPIOPinConfigure(GPIO_PC6_WT1CCP0);
        ROM_GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_6);

        //
        // Configure the two 32-bit periodic timers.
        //
        ROM_TimerConfigure(WTIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
        ROM_TimerLoadSet(WTIMER1_BASE, TIMER_A, ulPeriod);
        ROM_TimerMatchSet(WTIMER1_BASE, TIMER_A, ulPeriod / 2);
        //
        // Enable the timers.
        //
        ROM_TimerEnable(WTIMER1_BASE, TIMER_A);
                for(;;)
        // Alliance code end

    Regards,
    Mark