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 with dead time not toggling pins

Other Parts Discussed in Thread: EK-TM4C123GXL

Working with the EK-TM4C123GXL launch pad with CCS Version: 6.1.0.00104, I attempted to adapt the dead_band.c example (from Tivaware_C_Series-2.1.0.12573)  to pins PF0/PF1. I see no output on the 'scope, so I am overlooking something, no doubt. Here is the code. Please advise.

#include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pin_map.h"
#include <stdint.h>
#include <stdbool.h>
#include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_gpio.h"
#include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_types.h"
#include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_memmap.h"
#include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\sysctl.h"
#include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\gpio.h"
#include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pwm.h"

int main(void)
{
    //Set the clock
   SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC |   SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

   //Configure PWM Clock to match system
   SysCtlPWMClockSet(SYSCTL_PWMDIV_1);

   // Enable the peripherals used by this program.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);  //The Tiva Launchpad has two modules (0 and 1).

    // Unlock the Pin PF0 and Set the Commit Bit
    // See datasheet table 10-1 for explanation of why this pin needs unlocking
    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    HWREG(GPIO_PORTF_BASE + GPIO_O_CR)   |= 0x01;

    //Configure PF0 and PF1 Pins as PWM
    //See table 20-1 for these assignments
    GPIOPinConfigure(GPIO_PF0_M1PWM4);
    GPIOPinConfigure(GPIO_PF1_M1PWM5);

    GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //Configure PWM Options:PWM_GEN_2 Covers M1PWM4 and M1PWM5
    PWMGenConfigure(PWM1_BASE, PWM_GEN_2, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);

    unsigned long period = 64000;

    //Set the Period (expressed in clock ticks)
    PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, period);

    //Set PWM duty
    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_4,
                         PWMGenPeriodGet(PWM1_BASE, PWM_OUT_4) / 4);


    PWMDeadBandEnable(PWM1_BASE, PWM_GEN_2, 160, 160);
    // Turn on the Output pins
    PWMOutputState(PWM1_BASE, PWM_OUT_4_BIT | PWM_OUT_5_BIT, true);

    // Enable the PWM generator
    PWMGenEnable(PWM1_BASE, PWM_GEN_2);



    while(1)
    {

    }

}
  • Otto Hunt said:
    PWMGenConfigure(PWM1_BASE, PWM_GEN_2, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);

    Might you require one more (following) parameters to fully enable the deadband?    From our (past) StellarisWare User Guide:

    PWM_GEN_MODE_DB_NO_SYNC,      PWM_GEN_MODE_DB_SYNC_LOCAL, or
    PWM_GEN_MODE_DB_SYNC_GLOBAL to specify the deadband  parameter synchronization mode 

    Our BLDC code uses "PWM_GEN_MODE_DB_SYNC_LOCAL" and our deadband performs as anticipated.   (as you do not use "Sync" you may have to use another)

    Your review of the PWMGenConfigure() function - w/in PWM.C - should detail if one of those 3 parameters is required to solve your ills...

    As big KISS advocates may I suggest your removal of the call to "PWMDeadBandEnable()" - just to learn if that restores the PWM Outputs?   If that works - it may be that you require one of the 3 "DBxxxSync" parameters (listed).    It is also possible that your DB values of 160 prove too large for your PWM frequency - always best to "start conservatively" - only expand utilization after test/verified...

  • Thanks for the suggestion. I edited out the UART stuff from dead_band.c and ran it on the same board. It works, Here is the code:

    //*****************************************************************************
    // dead_band.c - Example demonstrating the dead-band generator.
    // This is part of revision 2.1.1.71 of the Tiva Firmware Development Package.
    //*****************************************************************************
    
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_types.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_memmap.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\sysctl.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pwm.h"
    
    //*****************************************************************************
    //
    //! \addtogroup pwm_examples_list
    //! <h1>PWM dead-band (dead_band)</h1>
    //!
    //! This example shows how to setup the PWM0 block with a dead-band generation.
    //!
    //! This example uses the following peripherals and I/O signals.  You must
    //! review these and change as needed for your own board:
    //! - GPIO Port B peripheral (for PWM pins)
    //! - M0PWM0 - PB6
    //! - M0PWM1 - PB7
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Configure the PWM0 block with dead-band generation.  The example configures
    // the PWM0 block to generate a 25% duty cycle signal on PD0 with dead-band
    // generation.  This will produce a complement of PD0 on PD1 (75% duty cycle).
    // The dead-band generator is set to have a 10us or 160 cycle delay
    // (160cycles / 16Mhz = 10us) on the rising and falling edges of the PD0 PWM
    // signal.
    //
    //*****************************************************************************
    int
    main(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_16MHZ);
        // Set the PWM clock to the system clock.
        //
        SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    
        //
        // The PWM peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);
    
        //
        // For this example PWM0 is used with PortB Pins 6 and 7.  The actual port
        // and pins used may be different on your part, consult the data sheet for
        // more information.  GPIO port B needs to be enabled so these pins can be
        // used.
        // TODO: change this to whichever GPIO port you are using.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
        //
        // Configure the GPIO pin muxing to select PWM 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_PB6_M0PWM0);
        GPIOPinConfigure(GPIO_PB7_M0PWM1);
    
        //
        // Configure the GPIO pad for PWM function on pins PB6 and PB7.  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_PORTB_BASE, GPIO_PIN_6);
        GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_7);
    
        //
        // Configure the PWM0 to count up/down without synchronization.
        // Note: Enabling the dead-band generator automatically couples the 2
        // outputs from the PWM block so we don't use the PWM synchronization.
        //
        PWMGenConfigure(PWM0_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 - 1.
        // TODO: modify this calculation to use the clock frequency that you are
        // using.
        //
        PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 64000);
    
        //
        // Set PWM0 PD0 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 cycles (64000 / 4).
        //
        PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM0_BASE, PWM_OUT_0) / 4);
    
        //
        // Enable the dead-band generation on the PWM0 output signal.  PWM bit 0
        // (PD0), will have a duty cycle of 25% (set above) and PWM bit 1 will have
        // a duty cycle of 75%.  These signals will have a 10us gap between the
        // rising and falling edges.  This means that before PWM bit 1 goes high,
        // PWM bit 0 has been low for at LEAST 160 cycles (or 10us) and the same
        // before PWM bit 0 goes high.  The dead-band generator lets you specify
        // the width of the "dead-band" delay, in PWM clock cycles, before the PWM
        // signal goes high and after the PWM signal falls.  For this example we
        // will use 160 cycles (or 10us) on both the rising and falling edges of
        // PD0.  Reference the datasheet for more information on dead-band
        // generation.
        //
        PWMDeadBandEnable(PWM0_BASE, PWM_GEN_0, 160, 160);
    
        //
        // Enable the PWM0 Bit 0 (PD0) and Bit 1 (PD1) output signals.
        //
        PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true);
    
        //
        // Enables the counter for a PWM generator block.
        //
        PWMGenEnable(PWM0_BASE, PWM_GEN_0);
    
        //
        // Loop forever while the PWM signals are generated.
        //
        while(1)
        {
    
        }
    }
    

  • We note the following:

    a) Without explanation - you've changed from PF0/PF1 to PB6/PB7.

    b) You've added one of the 3 "DB_SYNC" parameters - as I suggested - to "PWMGenConfigure()."

    I believe my earlier writing - via that suggestion - has earned a, "Verified Answer" tick.

    It would be comforting to myself/others to learn if the removal of the Parameter, "PWM_GEN_MODE_NO_SYNC" causes this PWM Generator to, "go quiet" - as you earler reported.   Minus that report - it remains unclear "how" your PWM Generator has regained functionality...

  • Helpful and attentive as you are, I.m not letting you off that easy! I did indulge you in removing, temporarily, "PWM_GEN_MODE_NO_SYNC" from the PWMGenConfigure function: no change.

    Keep in mind, here, that my code and the (working) trimmed dead_band.c code, are both derived from the TI-provided example dead_band.c. My code was an attempt to move the PWM output to PF0 and PF1, changing as little as possible - but I still got in trouble.
  • //Configure PF0 and PF1 Pins as PWM
    GPIOPinConfigure(GPIO_PF0_M1PWM4);
    GPIOPinConfigure(GPIO_PF1_M1PWM5);

    Later quote: "It works"
    Did you check the schematic to see if PF0/1 are not being used to service some other onboard hardware?
    Perhaps you discovered someone made a mistake packing the DB example code with the wrong GPIO pins enabled.
  • Otto Hunt said:
    I did ... temporarily remove, "PWM_GEN_MODE_NO_SYNC" from the PWMGenConfigure function: no change

    May I note that even engineering & law school does not enable me to clearly parse that writing.   

    Is it "no change" from:

    a) failure to output PWM signals when that parameter is included

    or

    b) PWM output continues - with or without - that parameter

    My small firm has not used this vendor's MCUs for awhile - we did include that parameter family - and as reported - our BLDC Controllers "deadband" to specification.   We've never attempted to "remove" the DB_Sync parameter - its (absence) was the only deviation I could note between your code and our own.

  • The "no change" statement meant a continuation of "no output" upon temporarily removing, "PWM_GEN_MODE_NO_SYNC" from the PWMGenConfigure function.

    Again following your suggestion, I modified the file to output to PE4 and PE5. Still no output. Here is the (non-working) code:

    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_types.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_memmap.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\sysctl.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pwm.h"
    
    int main(void)
    {
        //Set the clock
       SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC |   SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
       //Configure PWM Clock to match system
       SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    
       // Enable the peripherals used by this program.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);  //The Tiva Launchpad has two modules (0 and 1).
    
        // Unlock the Pin PF0 and Set the Commit Bit
        // See datasheet table 10-1 for explanation of why this pin needs unlocking
    //    HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
    //    HWREG(GPIO_PORTF_BASE + GPIO_O_CR)   |= 0x01;
    
        //Configure PE4 and PE5 Pins as PWM
        //See table 20-1 for these assignments
        GPIOPinConfigure(GPIO_PE4_M1PWM2);
        GPIOPinConfigure(GPIO_PE5_M1PWM3);
    
        GPIOPinTypePWM(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    
        //Configure PWM Options: PWM_GEN_1 Covers M1PWM2 and M1PWM3
        PWMGenConfigure(PWM1_BASE, PWM_GEN_1, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    
        unsigned long period = 64000;
    
        //Set the Period (expressed in clock ticks)
        PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, period);
    
        //Set PWM duty
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2,
                             PWMGenPeriodGet(PWM1_BASE, PWM_OUT_2) / 4);
    
    
        PWMDeadBandEnable(PWM1_BASE, PWM_GEN_1, 160, 160);
        // Turn on the Output pins
        PWMOutputState(PWM1_BASE, PWM_OUT_4_BIT | PWM_OUT_5_BIT, true);
    
        // Enable the PWM generator
        PWMGenEnable(PWM1_BASE, PWM_GEN_1);
    
    
    
        while(1)
        {
    
        }
    
    }
    

  • PWMOutputState(PWM1_BASE, PWM_OUT_4_BIT | PWM_OUT_5_BIT, true);

    PWMGenEnable(PWM1_BASE, PWM_GEN_1);

    GPIOPinConfigure(GPIO_PE4_M1PWM2);
    GPIOPinConfigure(GPIO_PE5_M1PWM3);

    That cannot be correct - can it?   Earlier you appeared quite good in matching the PWM Generator to its PWM Output Bit pair.   Here - not so much...  (Would not PE4 - if M1PWM2 as your code suggests - be "PWM_OUT_2_BIT" - and not that which your code, (PWM_OUT_4_BIT) presents?  Ditto for forsaken, "3_BIT."

    We must note that this vendor (actually the one prior) would have been hard pressed to employ (more) names for the individual PWM bits.  It clearly is confusing!

    Your code is loitered w/"stale" comments - thus masks your (real) intent - and becomes unappealing/confounding for outsiders to read/review...

  • OK, I cleaned it up. I'll take my ADD meds next time.
  • Or - you could "roll out" yet another PWM pair - to further challenge we (hapless) helpers.
  • Here is another PWM pin pair that works, this time it is PD0 and PD1:

    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_types.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_memmap.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\sysctl.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pwm.h"
    
    //*****************************************************************************
    //
    // Configure the PWM0 block with dead-band generation.  The example configures
    // the PWM0 block to generate a 25% duty cycle signal on PD0 with dead-band
    // generation.  This will produce a complement of PD0 on PD1 (75% duty cycle).
    // The dead-band generator is set to have a 10us or 160 cycle delay
    // (160cycles / 16Mhz = 10us) on the rising and falling edges of the PD0 PWM
    // signal.
    //
    //*****************************************************************************
    int
    main(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_16MHZ);
        // Set the PWM clock to the system clock.
        //
        SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    
        //
        // The PWM peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
        // Enable port D
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
        GPIOPinConfigure(GPIO_PD0_M1PWM0);
        GPIOPinConfigure(GPIO_PD1_M1PWM1);
    
        //
        // Configure the GPIO pad for PWM function on pins PD0and PD1.  Consult
    
        GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
        GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_1);
    
        // Configure the PWM1 to count up/down without synchronization.
        // Note: Enabling the dead-band generator automatically couples the 2
        // outputs from the PWM block so we don't use the PWM 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 - 1.
        PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, 64000);
    
        // Set PWM1 PD0 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 cycles (64000 / 4).
     
        PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM1_BASE, PWM_OUT_0) / 4);
    
        // Enable the dead-band generation on the PWM0 output signal.  PWM bit 0
        // (PD0), will have a duty cycle of 25% (set above) and PWM bit 1 will have
        // a duty cycle of 75%.  These signals will have a 10us gap between the
        // rising and falling edges.
        PWMDeadBandEnable(PWM1_BASE, PWM_GEN_0, 160, 160);
    
    
        // Enable the PWM0 Bit 0 (PD0) and Bit 1 (PD1) output signals.
        PWMOutputState(PWM1_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true);
    
        // Enables the counter for a PWM generator block.
        PWMGenEnable(PWM1_BASE, PWM_GEN_0);
    
        // Loop forever while the PWM signals are generated.
        while(1)
        {
    
        }
    }
    

    And another pin pair that does not work, PB4/PB5:

    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pin_map.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_types.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\inc\hw_memmap.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\sysctl.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\gpio.h"
    #include "C:\ti\TivaWare_C_Series-2.1.1.71\driverlib\pwm.h"
    
    int main(void)
    {
        //Set the clock
       SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC |   SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    
       //Configure PWM Clock to match system
       SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    
       SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);  //The Tiva Launchpad has two modules (0 and 1).
       // Enable the peripherals used by this program.
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
        //Configure PB4 and PB5 Pins as PWM
        //See table 20-1 for these assignments
        GPIOPinConfigure(GPIO_PB4_M0PWM2);
            GPIOPinConfigure(GPIO_PB5_M0PWM3);
    
            // Configure the GPIO pad for PWM function on pins PB4 and PB5.
            GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_4);  //M0PWM2
            GPIOPinTypePWM(GPIO_PORTB_BASE, GPIO_PIN_5);  //M0PWM3
    
            // Configure the PWM0 to count up/down without synchronization.
            // Note: Enabling the dead-band generator automatically couples the 2
            // outputs from the PWM block so we don't use the PWM 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) * 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 - 1.
            PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, 64000);
    
            // Set PWM0 PD0 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 cycles (64000 / 4).
            PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2,
                             PWMGenPeriodGet(PWM0_BASE, PWM_OUT_2) / 4);
    
            //
            // Enable the dead-band generation on the PWM0 output signal.  PWM bit 0
            // (PD0), will have a duty cycle of 25% (set above) and PWM bit 1 will have
            // a duty cycle of 75%.  These signals will have a 10us gap between the
            // rising and falling edges.
            PWMDeadBandEnable(PWM0_BASE, PWM_GEN_1, 160, 160);
    
            // Enable the PWM0 Bit 0 (PB4) and Bit 1 (PB5) output signals.
            PWMOutputState(PWM0_BASE, PWM_OUT_2_BIT | PWM_OUT_3_BIT, true);
    
            // Enables the counter for a PWM generator block.
            PWMGenEnable(PWM0_BASE, PWM_GEN_1);
    
            // Loop forever while the PWM signals are generated.
            //
            while(1)
            {
    
            }
        }
    

    By now a pattern is clear: only when PWM0 and PWM1 (module 0 or module 1) is used will the outputs happen. I don't know why. I hope someone more knowledgeable than I will chime in here.

  • Hi Otto,
    TI used pwm0 Gen0-1 GPIO ports PF0/1 for EMAC LED's on EK-TM4c1294-xl launch pad. That being said the question of a much earlier post asked Otto; Yet to be answered does the schematic of the 123 launch pad show anything connected to PB4/5 other than booster pack header pins?

    We had to cut traces and reroute the EMAC LED's to free up the PWM0 GEN0/1 ports for PWM use on the TM4C1294 launch.

    Otherwise did you also consult the TI errata datasheet for your 123 processor silicon revision sometime during this lengthy post?
  • The booster pack connector chart shows no role for PB4 and PB5 on the board. Also I could find no relevant issues in the errata. Thanks for the suggestion, BP101.

  • Only thing that I can add is the (possibility) that - with all the PWM gyrations - you've missed/mixed the assignment of PWM Module 0 or 1.

    The fact that you appear to have at least two different PWM Generators "Up/Running" establishes that you have mastered the basic method.

    Perhaps your return here after some "passage of time" will better enable your issue resolution.   (and do you really need all of those PWM channels - if so - you'll surely find it...)

    Adios...

  • I have checked and rechecked - ad nauseum - the PWM module function arguments. Thanks, though.

    I only need one PWM pin pair to drive the coils for my benchtop shaker project. I originally chose PF0/PF1 which led to this thread. I have two PWM pin pairs working. I am moving forward, not banging my head against the wall anymore. I still want this issue resolved just because. You're an engineer, I am sure you know the feeling.

  • Otto Hunt said:
    You're an engineer, I am sure you know the feeling.

    Well - Engineer is "one hat" - but reality can be brutal - making payroll consistently - and keeping investors happy - and shipping (sometimes) ahead of schedule - dwarfs any time for "head-banging."  

    Look - this is one MCU - on one board.   We use almost 10 different ARM MCUs - clients would never let us get away w/single source.   Thus - if the opportunity warrants - it's likely that we could find/resolve - but (the reality) who really cares.   If it matters to you sufficiently - you'll succeed.

    Beware "single board anomaly" - they're destructive - eat your time, funds (and hair!)   (but never mine - we NEVER build less than 3 - usually 5 of anything!)

  • Hello Otto,

    I have been following this thread for some time. On the TM4C123 LP did you not get the PF0/PF1 to work? and that is why you had to change ports to PB6/PB7?

    Regards
    Amit
  • Actually, Amit, I am using PD0/PD1. The choice between that and PB6/PB7 was arbitrary - I got both pin sets to work. And I have made great progress: I now have the ADC driving the PWM frequency and dead time, using driverlib!

    My conclusion is that there is probably some default setting on this chip that works for PWM0/PWM1 on either module, and must be set differently to enable other pin pairs. I would still like to get to the bottom of this so, naturally, I appreciate your attention.

  • Hello Otto,

    I have used the other Generators (1 to 3) on both PWM0 and PWM1 and got them to work as well as GEN-0.

    I would check the code of "PB4/PB5" pair to see what the issue is.

    Regards
    Amit
  • Hello Otto,

    So I got some time on the issue and it turned to be a SW bug.

    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2,
    PWMGenPeriodGet(PWM0_BASE, PWM_OUT_2) / 4);

    Must be replaced by

    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2,
    PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1) / 4);

    The function PWMGenPeriodGet was using the wrong parameter.

    Regards
    Amit
  • Yes, PB4/PB5 is working now.

    PWM_GEN_0 and PWM_OUT_0 both evaluate to 0x00000040, which is why PWM0/PWM1 pins worked despite the bug.

     Thanks for your help, Amit.

  • Amit Ashara said:
    PWMGenPeriodGet(PWM0_BASE, PWM_GEN_1) / 4);  

    As this poster reported, "Two of his PWM generators succeeded" it appears that lack of total focus on this (bit exotic) function caused his pain.

    Surely poster is content now - yet is there not some danger & inefficiency in such a function?    For the past 5 years my firm's used LM3S & LX4F to drive exotic BLDC motors (in the 2KW class) - and somehow never found a compelling "need" (nor ANY need) to employ PWMGenPeriodGet()!   

    Does not the indirection of that function (requiring a call-back to PWMGen's period) both slow & potentially cause grave problems if it fails, proves imprecise, or does not complete?    It appears that such "integer dividers" may reduce PWM resolution - as well.

    We found that the direct entry of the period's numeric value - and then test/verify (w/out motor's presence) worked best (& fastest) when setting PWM period.  

    In this poster's case - the "convenience" of this function complicated & confounded.    And the variety of different parameters - with their unclear (yet similar) naming conventions - invites the difficulty the poster experienced...   (he's surely not the first down that trail - and guaranteed not the last...)   KISS rules...

  • I wish to report here that the origin of this bug is dead_band.c as supplied by TI in TivaWare_C_Series_2.1.0.12573.

  • Well - that's surely useful - yet the composing of, "Verified Answer" rendered the (real killer) source of the bug unclear.     I bet (most always) upon poster error!

    Yet - inquiring minds - how then did you "succeed" w/TWO PWM Generators?     Surely "dead_band.c" was employed there - and would have worked its evil - would it not?   And that critical observation has (thus far) escaped analysis!

    Might you "wrap" this long thread w/the completeness it deserves?     Thank you... (and note - our direct entry into "PWMPeriodSet()" (unconsciously) avoided any such pitfall!)

    Again - KISS rules - would have avoided this nightmare.   Adding complexity (i.e. special functions - of questionable value) when simplicity is at the doorstep - never good...

  • Hello cb1,

    Could it be the Generator-2 in both the PWM Modules were being used allowed it work?

    For the forum: Also the bug in the code is there from source project and hence it has found it way into 2.1.0 and 2.1.1 release.

    Regards
    Amit
  • Amit Ashara said:
    Could it be the Generator-2 in both the PWM Modules were being used allowed it work?   

    I don't believe that the intrusion of the "dead-band" would cause (some) PWM Generators to work - while others failed.

    To this day - to my mind - it remains unclear as to, "If and how" our poster succeeded w/deadband on one (perhaps two) PWM Generators - and then failed w/the two remaining PWM Generators.

    Poster clearly reported success - has proved clever enough to "parallel" working code to a 2nd (most similar) PWM instantiation - yet (still) unexplained is HOW that first attempt (w/deadband enabled) succeeded...

    Again - the method I outlined (not holding the PWM Period hostage by utilizing a function call) - especially when direct numeric entry proves faster/safer/easier - has long enabled my small firm to avoid all such issues...   KISS (continues) to rule...

  • Hello cb1,

    I understand. I think only Otto can confirm that as of now.

    Regards
    Amit
  • Shortly after posting my "it works now, thanks for your help" post (to Amit). I then edited that post to express my observation that the erroneous function argument to PWMGenPeriodGet, PWM_OUT_0, evaluates to 0x00000040, just like the correct argument PWM_GEN_0 does. Dead_band.c works by this accident:

    PWMPulseWidthSet(PWM0_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM0_BASE, PWM_OUT_0) / 4);

    But then extrapolating this as I tried here:

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2,
                             PWMGenPeriodGet(PWM1_BASE, PWM_OUT_2) / 4);

    Will not work.

    The correct function argument:

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0,
                         PWMGenPeriodGet(PWM1_BASE, PWM_GEN_0) / 2);

    (Taken from my presently working code) can be extrapolated safely with digging around in .h files for eligible arguments.

    In response to cb1: I make use of the PWMGenPeriodGet function argument to PWMPulseWidthSet to keep the pulse width at 50% while varying the frequency (using an ADC input).

  • Classically - when a 50% duty cycle is required - is not a simple, standard, single counter stage (divide by two) employed?   (has long worked for us)   The input frequency would be 2x that desired @ counter's output yet the output would be a true, 50% duty square-wave.

    I'd have to delve back into the API to see if changes to the PWM frequency - as you suggest - are quickly & reliably reflected into the numerous, other function calls.  (as the method you describe requires.)    Deadband has long been achieved via simple, standard logic - and may also serve as an effective PWM gate control.   (i.e. PWM Output OFF!)

    Thank you for persisting here - and closing the loop to this unique issue...   (I had written earlier - got interrupted - and "shop/watch dog ate my homework/posting.")

  • Hello Otto

    A sincere thanks from my side as well on bringing the final doubts to rest

    Regards
    Amit