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.

EK-TM4C129EXL: PWM not working

Part Number: EK-TM4C129EXL

Hello Team,

I'm posting on behalf of my customer. Please see below my customer's inquiry:

Hello TI,

 I have been trying for a while to create a PWM code that will flash LED's.  I have tried several examples online and even tried mixing and matching from the examples and following the documentation for the board.  I cannot seem to get any PWM signal out.  The signal is always high and does not seem to oscillate.  I do not have an oscilloscope to verify, but based on the LED's I have hooked up, the lights are always on, no matter how low I set the oscillations.  I am attaching the code that I have right now.  I do not know if my boards' onboard oscillators are not working, or if the code is wrong.

#include <stdint.h>
#include <stdbool.h>
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "inc/hw_ints.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"

void main (void){

    SysCtlClockSet(SYSCTL_XTAL_25MHZ|SYSCTL_OSC_MAIN|SYSCTL_USE_PLL|SYSCTL_CFG_VCO_480);

    SysCtlPWMClockSet(SYSCTL_PWMDIV_1);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);           //Enables GPIO Port F
    // Enable PMW0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);

    GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_0);

    GPIOPinConfigure(GPIO_PF0_M0PWM0);

    PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);

    PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 400);

    // Set to 75% duty cycle
    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0, 300);

    PWMGenEnable(PWM0_BASE, PWM_GEN_0);

    PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT, true);

    while(1){

    }
}

Regards,

Renan

  • Hello Renan,

    Two issues here. One is the clock configuration is not done properly. The wrong API is being used.

        //
        // Run from the PLL at 120 MHz.
        // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
        // later to better reflect the actual VCO speed due to SYSCTL#22.
        //
        g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                                 SYSCTL_OSC_MAIN |
                                                 SYSCTL_USE_PLL |
                                                 SYSCTL_CFG_VCO_240), 120000000);

    The other issue isn't with the PWM configuration. It is that the period set is so small that the human eye won't be able to perceive any blinking of an LED. That is why they think it is always high and not oscillating.

    Assuming a 16MHz clock due to clock configuration issue, the PWM is running at 40 kHz. Way too fast for the human eye to see.

    This is the setup for how to get 250 Hz at 25% Duty Cycle using the above 120MHz System Clock:

        //
        // Set the PWM clock to be SysClk / 8.
        //
        MAP_PWMClockSet(PWM0_BASE, PWM_SYSCLK_DIV_8);
        //
        // Use a local variable to store the PWM clock rate which will be
        // 120 MHz / 8 = 15 MHz. This variable will be used to set the
        // PWM generator period.
        //
        ui32PWMClockRate = g_ui32SysClock / 8;
    
        //
        // Configure PWM2 to count up/down without synchronization.
        //
        MAP_PWMGenConfigure(PWM0_BASE, PWM_GEN_1,
                            PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    
        //
        // Set the PWM period to 250Hz.  To calculate the appropriate parameter
        // use the following equation: N = (1 / f) * PWMClk.  Where N is the
        // function parameter, f is the desired frequency, and PWMClk is the
        // PWM clock frequency based on the system clock.
        //
        MAP_PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, (ui32PWMClockRate / 250));
    
        //
        // Set PWM2 to a duty cycle of 25%.  You set the duty cycle as a function
        // of the period.  Since the period was set above, you can use the
        // PWMGenPeriodGet() function.  For this example the PWM will be high for
        // 25% of the time or (PWM Period / 4).
        //
        MAP_PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2,
                             MAP_PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1) / 4);
    

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

         Thank you for your answer.  I do have one question though, what types are the functions that you have provided?

    Thank you,

    Drew (The one who asked the question initially)

  • Also, what library are these functions in?

  • Hi Drew,

    Ah sorry that I didn't notice the mismatch in that I used mapped functions versus the Flash driver functions.

    You can remove the MAP_ prefix from all of them to use the direct Flash driver functions like in your code.

    Or if you want to use the mapped functions, add:

    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    

    That will then use our mapped functions that call either the ROM version or Flash version of a given function. The ROM version is used if it exists in ROM and is not subject to any updates made to TivaWare since the initial library creation. If any changes were made, then the Flash version is used instead.

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

         Alright, that answers the library question, but I still need to know the data types of the constants.  I also see that I need to update my TivaWare as SYSCTL_CFG_VCO_240 is undefined.

    Thank you for your help,

    Drew

  • Hello Drew,

    They are uint32_t.

    Our TivaWare code uses naming conventions where we list the data type as part of the variable name. So for ui32PWMClockRate - the ui32 indicates unsigned integer 32 bits. Hopefully that helps in general as you work with our SDK.

    And yes you should download TivaWare 2.2.0! It has dedicated PWM examples for both LaunchPads now Slight smile One of the many improvements (we added quite a few new examples!). You can get it from https://www.ti.com/tool/SW-TM4C

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

         Thank you.  I did not realize that about the naming convention.  I downloaded the latest version of TivaWare, but I already had it installed and it still does not know what SYSCTL_CFG_VCO_240 is.  Is that in a different library from the ones I have included?

    Thank you,

    Drew

  • Hello Ralph,

        I figured out what that problem was.  I had the software in the wrong folder.  Silly me, however, the program is still not working.  The light never turns on.  Here is the code that I have:

    #include <stdint.h>
    #include <stdbool.h>
    #include "driverlib/pwm.h"
    #include "driverlib/pin_map.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/gpio.h"
    #include "driverlib/sysctl.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_types.h"
    #include "driverlib/debug.h"
    
    
    void main (void){
    
        //
        // Run from the PLL at 120 MHz.
        // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
        // later to better reflect the actual VCO speed due to SYSCTL#22.
        //
        uint32_t g_ui32SysClock;
        uint32_t ui32PWMClockRate;
    
        g_ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_240), 120000000);
    
        SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);           //Enables GPIO Port F
        // Enable PMW0
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
    
        GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_0);
    
        GPIOPinConfigure(GPIO_PF0_M0PWM0);
    
        //
        // Set the PWM clock to be SysClk / 8.
        //
        PWMClockSet(PWM0_BASE, PWM_SYSCLK_DIV_8);
        //
        // Use a local variable to store the PWM clock rate which will be
        // 120 MHz / 8 = 15 MHz. This variable will be used to set the
        // PWM generator period.
        //
        ui32PWMClockRate = g_ui32SysClock / 8;
    
        //
        // Configure PWM2 to count up/down without synchronization.
        //
        PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    
        //
        // Set the PWM period to 250Hz.  To calculate the appropriate parameter
        // use the following equation: N = (1 / f) * PWMClk.  Where N is the
        // function parameter, f is the desired frequency, and PWMClk is the
        // PWM clock frequency based on the system clock.
        //
        PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, (ui32PWMClockRate / 250));
        //
        // Set PWM2 to a duty cycle of 25%.  You set the duty cycle as a function
        // of the period.  Since the period was set above, you can use the
        // PWMGenPeriodGet() function.  For this example the PWM will be high for
        // 25% of the time or (PWM Period / 4).
        //
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1) / 4);
    
        PWMGenEnable(PWM0_BASE, PWM_GEN_1);
    
        PWMOutputState(PWM0_BASE, PWM_OUT_0_BIT, true);
    
        while(1){
    
        }
    }
    

    I am using pin F0 which has a built in LED and uses M0PWM0.  What needs to change?  If I make all the PWM_X_# into PWM_X_0, the light just stays on.  Is it flashing too fast still?

    Thank you,

    Drew

  • Hello Drew,

    M0PWM0 would be on Generator 0. Your code is still configuring PWM2 which is on Generator 1.

    Update your functions to use PWM_GEN_0 and PWM_OUT_0 and it should work.

    Best Regards,

    Ralph Jacobi

  • Oh, I didn't see the last line. Yes, if the light is always on then its flashing too fast still. If you think about speed, 250 Hz is about 4 milliseconds. So that is still too short of a blink to be perceived by our eyes. 250 Hz would be 250 blinks per second. Even 50 Hz would be 50 blinks in a second. That's more than we can really notice typically, but with the duty cycle tweaked it may be possible. I hadn't tested the exact frequencies needed to see an LED, I was trying to demonstrate how to get your PWM running much slower so you can work through what frequencies which are needed. That said I should have clearly stated you would need to go even slower.

  • Hello Ralph,

         Thank you for your help, I appreciate it.  I should be able to figure out the rest from here.

    Thank you,

    Drew

  • Well, I was wrong, I was horribly wrong.  All the changes I make just change the brightness of the LED.  I cannot slow it down enough to see blinking.  I am wondering if my oscillation is actually working on the hardware level.  I am not sure what to do now, but I will keep at it.  Thank you for your help.

  • Hi Drew,

    You'd honestly be better off using a hardware timer to toggle a GPIO than use the PWM. The PWM is really meant more for motor drive type applications and is pretty ill-equipped to handle blinking LEDs.

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

         Fair enough.  Was hoping to avoid using hardware timers and solely relying on a random number generator to control brightness and timing of a PWM through an LED, but if I should just use hardware timers, then I will do that.

    Thank you,

    Drew

  • Hi Drew,

    The hardware timers also have a PWM feature so you might be able to find a middle ground using them in that manner as well. Maybe that could give you the granularity level needed over the PWM peripheral that is more geared towards higher frequencies for motor control.

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

       Are you referring to SysCtlDelay()?  Or is there another one?

    Thank you,

    Drew

  • Hi Drew,

    Not sure what you mean by that?

    I was referring to the pwm.c example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\peripherals\timer

    Best Regards,

    Ralph Jacobi

  • Hello Ralph,

         Oh, I see.  I will look more into that as that looks like it might work out for me.  I meant before the simple delay function SysCtlDelay() function that halts execution for x number of milliseconds.

    Thank you,

    Drew

  • Hi Ralph,

         While the timer might work, the LED does not seem to turn on.  I tried putting in a GPIOPinWrite command, but the LED still does not seem to turn on.  I think it is a clock PWM, not a signal PWM.  I need something that will oscillate the LED and can control the voltage being delivered (brightness).  Hence why I wanted PWM.  No pins though on the board that I have seen have a timer and PWM, or something of the sort.  I am not sure if my project will succeed if there are no examples of this.  Oh well.

    Thank you for your help,

    Drew