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.

1 Hz period 50% duty cycle is not work, try Timer and PWM generator, pls help (TM4C123G)

#include <stdint.h>
#include <stdbool.h>
#include "driverlib/rom.h"

#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/pin_map.h"
#include "driverlib/pwm.h"

void timerVersion(){
uint32_t ulPeriod, dutyCycle1;

SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); // Enable port F
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); // Enable Timer 1
GPIOPinConfigure(GPIO_PF3_T1CCP1); // Configure pin PF3 as output of Timer 1_B
GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3); // Enable pin PF3 as output of timer addressed to it

ulPeriod = SysCtlClockGet();
dutyCycle1 = (unsigned long)(ulPeriod-1)*0.50;

TimerConfigure(TIMER1_BASE, (TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM)); // Configure Timer 1 as two 16 but timers with both functioning as PWM
TimerControlLevel(TIMER1_BASE, TIMER_BOTH, 0); // Timer 1 is trigger low
TimerLoadSet(TIMER1_BASE, TIMER_B, ulPeriod-1); // Timer 1 Load set
TimerMatchSet(TIMER1_BASE, TIMER_B, dutyCycle1); // Timer 1 Match set
TimerEnable(TIMER1_BASE, TIMER_BOTH);
}

void pwmVersion(){
uint32_t ulPeriod = 0;

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

// Enable the peripherals used by this program.
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); //The Tiva Launchpad has two modules (0 and 1). Module 1 covers the LED pins
ulPeriod = ROM_SysCtlClockGet(); //PWM frequency 1Hz

//Configure PF3 Pins as PWM
ROM_GPIOPinConfigure(GPIO_PF3_M1PWM7);
ROM_GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_3);

//Configure PWM Options
//PWM_GEN_2 Covers M1PWM4 and M1PWM5
//PWM_GEN_3 Covers M1PWM6 and M1PWM7 See page 207 4/11/13 DriverLib doc
ROM_PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);

//Set the Period (expressed in clock ticks)
ROM_PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, ulPeriod);

//Set PWM duty-50% (Period /2)
ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_7, ulPeriod/2);

// Enable the PWM generator
ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_3);

// Turn on the Output pins
ROM_PWMOutputState(PWM1_BASE, PWM_OUT_7_BIT, true);
}

int main(void)
{

//
// Set the clocking to run at 50 MHz from the PLL.
//
ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
SYSCTL_OSC_MAIN);

timerVersion(); //16, 50 MHz-> illuminating LED
//pwmVersion(); //50 MHz-> "black" LED

while(1)
{
}
}

  • Hi Molnar,

    Well with the general timers it's impossible. At least the one you used.

    If you make the math for 1Hz pwm output you need a load value of 80Mhz/1 = 80.000.000
    That's a lot. The timer1 in split mode (necessary for PWM) is a 16bit timer, maximum value: 65535!
    You either use a wide timer which in split mode has 32bits. 
    Normally when you need a lower frequency than it's possible for your timer at the system clock you are using you use a prescaler. But the timer1 prescaler is only 8bits, so 80Mhz/256 = 312500Hz - works like a divider but if you do 312500/1 it's still over 65535 so your only option is the wide timer.

    I actually don't know the limits of the PWM module, I will have to get back on you with that later.

    Other option: 1Hz is pretty low. You could have a timer in periodic mode interrupt every 1 second. In this mode you can use the full timer so you have 32bits. In the interrupt handler you toggle the pin state.


    You have a lot of resources on your MCU; i'll let you decide the best. You have so many timers and wide timers that it's not like you will miss using 1 wide timer for 1Hz PWM generation

  • Hello Luís Afonso,

    How can i write 1Hz, 50Hz, 1kHz pwm generator? (1 Hz to see the operation.)
    This is a sub-task. Other additions: 1x CAN, 2x ADC, 2x GPIO in, 1x GPIO out, 3x PWM (50 HZ 20-50%, 1 kHz 0-100%)

    Molnár Gergely
  • I already suggested how to get lower frequencies with the Timer.

    With the PWM module you have a 16bit counter per generator.

    The only way to get lower frequencies is to change the PWM clock. The PWM modules are fed not only from the system clock but also a separate PWM clock which is a division from the system clock. You can use SysCtlPWMClockSet() to set this division. Check Tivaware peripheral drivers library user guide in how to use that function.
    Note that the maximum division is 64. So if you have a 80Mhz clock, the lowest clock possible fed into the PWM generator is 80Mhz/64=1250000hz, way over the 65535 maximum value which you require for 1Hz.
    So for really low frequencies like 1Hz it's best to use the timers for PWM generation.

    Amit Ashara (310847) , there seems to be an error in: SW-TM4C-DRL-UG-2.1.0.12573

    In PWMClockSet it says on the notes:

    "This function should not be used with TM4C123 devices. For TM4C123 devices, the SysCtlPWMClockGet() function should be used."

    See how it redirects to SysCtlPWMClockGet() instead of SysCtlPWMClockSet()?

  • Thanks Master! You are best!

    Finally, my Code:
    void timerVersion(){
    uint32_t ulPeriod, dutyCycle1;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); // Enable port C
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0); // Enable Timer 0
    GPIOPinConfigure(GPIO_PC5_WT0CCP1); // Configure pin PF3 as output of Timer 0_B
    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_5); // Enable pin PC5 as output of timer addressed to it

    ulPeriod = SysCtlClockGet();
    dutyCycle1 = (unsigned long)(ulPeriod-1)*0.50;

    TimerConfigure(WTIMER0_BASE, (TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM)); // Configure Timer 0 as two 32 but timers with both functioning as PWM
    TimerControlLevel(WTIMER0_BASE, TIMER_B, 0); // Timer 0 is trigger low
    TimerLoadSet(WTIMER0_BASE, TIMER_B, ulPeriod-1); // Timer 0 Load set
    TimerMatchSet(WTIMER0_BASE, TIMER_B, dutyCycle1); // Timer 0 Match set
    TimerEnable(WTIMER0_BASE, TIMER_B);
    }
  • Glad it's working, good luck with the rest of your projects