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.

TM4C1231H6PGE: HOW TO CONFIGURE A PARTICULAR GPIO TO PWM

Part Number: TM4C1231H6PGE
Other Parts Discussed in Thread: TM4C123GH6PM, EK-TM4C123GXL,

Hi ,

I have a requirement of generating a pulse of on time 1ms and off time 100ms .Can it be possible to use PWM for the same?

If so can you please help me out in configuring the GPIO to PWM as per the requirements mentioned above.

Thanks and Regards,

Rohith.

  • Hello Rohith,

    Yes it is possible to do this, though are you sure you want 101 ms total period? 100 ms would be easier and more consistent.

    Also the MCU you have listed in your post does not have a PWM peripheral (though you could do it with a Timer too). You probably want to use the TM4C123GH6PM.

    You can look at our PWM examples at [Install Path]\TivaWare_C_Series-2.1.4.178\examples\peripherals\pwm

    You probably will find invert.c the simplest to follow as you just need to not use the PWMOutputInvert API's and the rest of the configuration is laid out for you.

    For you period, you will need the PWM Clock to run off a division of the System Clock. This is because your period configuration setting is 16 bits, so for 16 MHz, you would get only 244 Hz width at most. But if you divide a 16 MHz System clock by 16 so the PWM clock is 1 MHz, then you can get a 100 ms period by loading the period with 10000 (or try for 101 ms with 9901 but it won't always be 101 ms 100% of the time).

    The PWMClockSet is used to set the division ratio of the System Clock to PWM Clock. Your options are 1, 2, 4, 8, 16, 32, and 64. Even at 80 MHz (max system clock speed) you can support this period with even just a /32 division. Note the variable to include for PWMClockSet beyond the PWM Base would be PWM_SYSCLK_DIV_x where x is one of the options.

  • Hi Ralph ,

    Thanks for the response it was grateful.

    Below is the function that was used for the pwm generation . Apart from this is there any changes required in any of the files as in pin map or am i missing something .

    There was continuous reboot after loading this particular image in which the function is added .


    int
    pwc_pin_103(void)
    {


        //
        // Set the clocking to run directly from the external crystal/oscillator.
        // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
        // crystal on your board.
        //


        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_25MHZ);


        //
        // Set the PWM clock to the system clock.
        //
        SysCtlPWMClockSet(SYSCTL_PWMDIV_16);

       



        //
        // The PWM peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);

        //
        // For this example PWM1 is used with PortL Pin5.  The actual port and
        // pins used may be different on your part, consult the data sheet for
        // more information.
        // GPIO port L needs to be enabled so these pins can be used.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

        //
        // Configure the GPIO pin muxing to select PWM1 functions for these pins.
        // This step selects which alternate function is available for these pins.
        // This is necessary if your part supports GPIO pin function muxing.
        // Consult the data sheet to see which functions are allocated per pin.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinConfigure(GPIO_PL5_T2CCP1);

        //
        // Configure the PWM function for this pin.
        // Consult the data sheet to see which functions are allocated per pin.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypePWM(GPIO_PORTL_BASE, GPIO_PIN_5);

        //
        // Configure the PWM1 to count up/down without synchronization.
        //
        PWMGenConfigure(PWM1_BASE, PWM_GEN_0, 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) * SysClk.  Where N is the
        // function parameter, f is the desired frequency, and SysClk is the
        // system clock frequency.
        // In this case you get: (1 / 250Hz) * 16MHz = 64000 cycles.  Note that
        // the maximum period you can set is 2^16.
        // TODO: modify this calculation to use the clock frequency that you are
        // using.
        //
        
        PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0,64000);

        //
        // Set PWM0 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 16000 clock ticks (64000 / 4).
        //
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM1_BASE, PWM_GEN_0) / 1);

        //
        // Enable the PWM1 Bit0 (PD0) output signal.
        //
        PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, true);

        //
        // Enable the PWM generator block.
        //
        PWMGenEnable(PWM1_BASE, PWM_GEN_0);

        //
        // Loop forever while the PWM signals are generated.
        //
       
    }

    note : please ignore the frequency and duty cycle used and also the comments written just wanted to check whether i could see the pulse.

    Thanks,

    Rohith.

  • Hello Rohith,

    As I mentioned on my original post, the device you have selected does not have a PWM peripheral. Can you test and evaluate with the EK-TM4C123GXL LaunchPad?

    If not, then you need to look into doing a timer-based PWM such as the example found in: [Install Path]\TivaWare_C_Series-2.1.4.178\examples\peripherals\timer\pwm.c

  • Hi Ralph ,

    Appreciate your quick response .

    There is no launch pad available and TM4C1231H6PGE is the only possible option for PWM generation.

    Can we move forward implementing the function with reference to the example mentioned the post :[Install Path]\TivaWare_C_Series-2.1.4.178\examples\peripherals\timer\pwm.c?

    Thanks and Regards,

    Rohith.

  • Hello Rohith,

    Yes, that would be your only option for PWM with that device... but if PWM is one of your primary goals I still think you should select a TM4C device with an actual PWM peripheral. Just my two cents.

    Let me know if you have challenges with implementing that example successfully.

  • Hi Ralph,

    For generating the pulse of 100ms with 99.5mSec ON duration and 0.5msec OFF Duration , what would be the values is the system clock is of 25MhZ .

    =======================================================================================================

    can you please review the code and let me know if it is proper or am i missing out something.

    =======================================================================================================


    #include <stdbool.h>
    #include <stdint.h>
    #include "stellaris/inc/hw_gpio.h"
    #include "stellaris/inc/hw_ints.h"
    #include "stellaris/inc/hw_memmap.h"
    #include "stellaris/inc/hw_timer.h"
    #include "stellaris/inc/hw_types.h"
    #include "stellaris/driverlib/gpio.h"
    #include "stellaris/driverlib/interrupt.h"
    #include "stellaris/driverlib/pin_map.h"
    #include "stellaris/driverlib/sysctl.h"
    #include "stellaris/driverlib/timer.h"
    #include "stellaris/driverlib/uart.h"
    #include "stellaris/utils/uartstdio.h"

    //*****************************************************************************
    //
    //! \addtogroup timer_examples_list
    //! <h1>PWM using Timer (pwm)</h1>
    //!
    //! This example shows how to configure Timer1B to generate a PWM signal on the
    //! timer's CCP pin.
    //!
    //! This example uses the following peripherals and I/O signals.  You must
    //! review these and change as needed for your own board:
    //! - TIMER1 peripheral
    //! - GPIO Port L peripheral (for T2CCP1 pin)
    //! - T2CCP1 - PL5
    //!
    //
    //*****************************************************************************

    //*****************************************************************************
    //
    // The g_ui32SysClock contains the system clock frequency
    //
    //*****************************************************************************
    #if defined(TARGET_IS_TM4C129_RA0) ||                                         \
        defined(TARGET_IS_TM4C129_RA1) ||                                         \
        defined(TARGET_IS_TM4C129_RA2)
        uint32_t g_ui32SysClock;
    #endif


    //*****************************************************************************
    //
    // Configure Timer0B as a 16-bit PWM with a duty cycle of 99%.
    //
    //*****************************************************************************
    int pwm_pin_107(void)
    {
        //
        // Set the clocking to run directly from the external crystal/oscillator.
        // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
        // crystal on your board.
        //


        SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                       SYSCTL_XTAL_25MHZ);

     //
        // Set the PWM clock to the system clock.
        //
      
        //
        // The Timer0 peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);

        //
        // For this example T0CCP1 is used with port L pin 1.
        // The actual port and pins used may be different on your part, consult
        // the data sheet for more information.
        // GPIO port L needs to be enabled so these pins can be used.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

        //
        // Configure the GPIO pin muxing for the Timer/CCP function.
        // This is only necessary if your part supports GPIO pin function muxing.
        // Study the data sheet to see which functions are allocated per pin.
        // TODO: change this to select the port/pin you are using
        //
        GPIOPinConfigure(GPIO_PL5_T2CCP1);



        //
        // Configure the ccp settings for CCP pin.  This function also gives
        // control of these pins to the SSI hardware.  Consult the data sheet to
        // see which functions are allocated per pin.
        // TODO: change this to select the port/pin you are using.
        //
        GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_5);


        //
        // Configure Timer2B as a 16-bit periodic timer.
        //
        TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);

     
        //
        TimerLoadSet(TIMER2_BASE, TIMER_B, 10000);

        //
        // Set the Timer2B match value to load value / 2.
        //
        TimerMatchSet(TIMER2_BASE, TIMER_B,
                      TimerLoadGet(TIMER2_BASE, TIMER_B) / 2);

        //
        // Enable Timer2B.
        //
        TimerEnable(TIMER2_BASE, TIMER_B);

    }


    Thanks and Regards,

    Rohith.

  • Hello Rohith,

    We don't just do blind code reviews - you will need to run it and explain what isn't working.

    As far as the question about how get the duration set, you'll need to set the TimerLoadSet and TimerMatchSet based on the duration you want. You will want to use a wide timer as well, as otherwise you won't have enough bits to get that long period. I can see what examples we have for that during the work week if needed. But you can try searching on E2E for more about the topic in the meantime. You can definitely find wide timer examples on E2E and there should be a few posts on timer PWM too. So see what you can dig up and report back on Monday if you are having challenges with what you have put together so far and I can look at it and see what else might be missing then. You'll want to get an o-scope at some point too so you can see what outputs you are getting - that will be important information to have.

  • Hi Ralph,

    Regarding the output of the implementation i could see the pulse generated on the scope.Thanks for that.

    TimerLoadSet(TIMER2_BASE, TIMER_B, 64000);

    TimerMatchSet(TIMER2_BASE, TIMER_B,
                      TimerLoadGet(TIMER2_BASE, TIMER_B) / 5);

    For the above combination for setting the duration i could see the pulse generated with the frequency of 390Hz and duty cycle (90%) (OFF DURATION IS 259us).

    what can the optimised values to meet (99.5ms ON duration and 0.5ms OFF duration).

    Some of the challenges i could see:

    1) That if i configure two pins for PWM which use Timer2A and Timer2B , independently i could get the  pulse but if i wanted to use them together then only Timer2A could provide me the PULSE but not 2B ,Why is it So?

    2) Can it be possible to generate the Pulse on both pins operated at the same ,one of which is WideTimer1B and the other is Timer1A for the same ON and OFF Duration, (for example pin 109 and pin 120 on TM4C1231H6PGE).

    Thanks and Regards,

    Rohith.

  • Hi Ralph,
    Based on our requirement as mentioned with ON duration 99.5msec and OFF duration 0.5msec looks like there is some limitation in achieving it by using 109 and 120 pins of MCU  .
    Since we have no provision to use other pins the only option for us to fulfill our requirement is by using these two pins.
    Both the pins should the generate the pulse which is connected to drive the external component in our project.
    1) Using the pin 120.
    Below is the code implementation:
    // the below LoadSet and Match Set function sets the frequency of the Pulse to 380Hz from the crystal frequency of 25MHz .
    //(2^16=65536 is the maximum factor since the 120 pin can be used as a 16 bit timer).

    TimerLoadSet(TIMER1_BASE, TIMER_A, 65536);

    // to achieve aprroximately 20% duty cycle the set the match value to load value /5

    TimerMatchSet(TIMER1_BASE, TIMER_A,
                         TimerLoadGet(TIMER1_BASE, TIMER_A) / 5);
                        
    With this we could achieve the OFF duration of 0.5msec but the ON duration would be approximately 2.1msec .
     is there any possibility that we could still meet our requirement by using the Same timer pin 120.
    2) The Another pin that is used for the same purpose is pin 109 which is a wide timer(32-bit timer) , could you please suggest whether the below implementation will be good enough to fulfill our requirement:
        

    TimerLoadSet(WTIMER1_BASE, TIMER_B, 2500000);

    TimerMatchSet(WTIMER1_BASE, TIMER_B,
                     TimerLoadGet(WTIMER1_BASE, TIMER_B) / 200);
    Thanks and Regards,

    Rohith.

  • Hello Rohith,

    With a 25MHz system clock to have a period of 100ms you would need to use a Wide Timer, so Pin 109 would be what would work. You wouldn't be able to use the 16 bit + 8 bit prescale to achieve that with Pin 120.

    From some of your comments I am a bit unclear about one aspect now, are you trying to drive multiple PWM signals with that requirement? If so, how many? And if multiple, are you concerned about being synchronized?

  • Greetings Ralph,

    Well diagnosed - poster's plot thickens.

    He (may) be seeking "Complementary PWM Signals" - easy for your "PWM equipped MCUs" - not so much for his less capable device!    (He may 'hack' a complementary PWM signal via use of an "ultra fast inverter" (minimal propagation delays) yet w/out "Deadband" - any driven power stage may be at (high) risk!)

    Should he (really) be seeking "Two identical PWM Outputs" - simply drive a common logic gate from the MCU's Timer Output - such that "Two (or even more) (near) identical PWM Signals" appear upon the logic gate's outputs!    Via this "external gate method" (i.e. forcing the MCU's  PWM signal to drive "Two Gates") any such delays imposed by the logic gate are equalized (thus effectively cancelled) and (near) exact synchronization is achieved.

    For those "Resistant to the use of an external logic gate" - realize that the gate provides numerous advantages:

    • is likely to provide greater output drive than the MCU's output (and w/gate I/O "paralleled") - even higher level outputs
    • more flexible output signals (i.e. the output may be further gated (on-off) or via a regularly occurring, timed "pattern or sequence"
    • serves as a protective (even sacrificial) "buffer" for the MCU.   (Far better to "Lose a gate" - rather than the MCU!)

    Forcing the MCU to produce such "duplicate PWM signals" by itself - is a (very) poor use of the MCU resource...    (especially so now that this "alternative method" has arrived.)

    Again - vendor Ralph's (repeated) direction to employ an MCU which "includes the formal PWM Modules" is extremely sound - really should be followed!

    We await the "next twist" in this (very) winding post road...

  • Hello Ralph ,

    Appreciate your effort. According to our requirement we need two PWM signals one each from pn 109 and 120, we are not concerned about they being synchronised.

    Regards,

    Rohith.

  • Hello Rohith,

    You will need to use a System Clock of 16 MHz or less to get a PWM of 100ms period on Pin 120.