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.

SW-EK-TM4C123GXL: PWM - Frequency & Duty Cycle Setting

Part Number: SW-EK-TM4C123GXL

Hii all,

I was digging out the PWM capabilities of TM4C123G,and found very confusing to configure the PWM resoultion  or maybe i am going wrong somewhere,

Well let me take a simple code example  which can control the Speed of a Toy DC motor.i wrote the code as follows.

I am configuring PF1 as PWM pin and PE3 as ADC for POT.

------------------------------------------------------------------------CODE STARTS HERE----------------------------------------------------------------------------------------------------------------------------------------------------------------

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

int main(void)
{

uint32_t result[0];
SysCtlClockSet(SYSCTL_SYSDIV_5| SYSCTL_USE_OSC |SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
SysCtlPWMClockSet(SYSCTL_PWMDIV_1);//Divide the sys clock for PWM module
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

// ADCHardwareOversampleConfigure(ADC0_BASE, 64);
SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_3);
ADCSequenceDisable(ADC0_BASE, 3);
ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0|ADC_CTL_IE|ADC_CTL_END);
ADCSequenceEnable(ADC0_BASE, 3);

SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); //The Tiva Launchpad has two modules (0 and 1). Module 1 covers the LED pins
GPIOPinConfigure(GPIO_PF1_M1PWM5);
GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1);//set PF1 as PWM
PWMGenConfigure(PWM1_BASE, PWM_GEN_2,PWM_GEN_MODE_DOWN|PWM_GEN_MODE_DBG_RUN);
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_2, 4095);
PWMGenEnable(PWM1_BASE, PWM_GEN_2);
PWMOutputState(PWM1_BASE, PWM_OUT_5_BIT , true);

while(1)
{
ADCIntClear(ADC0_BASE,3);

ADCProcessorTrigger(ADC0_BASE,3);

while(!ADCIntStatus(ADC0_BASE,3,false))

{
}

ADCSequenceDataGet(ADC0_BASE,3,result);

PWMPulseWidthSet(PWM1_BASE, PWM_OUT_5,result[0]);


}

-------------------------------------------------------------------------------------------------------------END HERE-----------------------------------------------------------------------------------------------------------------------------------------------------------------

I have connected an oscilloscope and a multi-meter on the PF1 pin to see the out put result..10k POT is connected between 0V and 3.3v.Also added the ''result' value to watch window which varies perfectly from 0-4095 as expected.Now when i go for 4095 value through my pot the Scope shows 100% duty cycle and voltage also around 3.1v,and when i slowly slowly decrease the pot value towards 0,same i see in scope as the duty cycle reducing and led also glows accordingly. 

when my pot is at level 6 or 7,below that  led starts blinking ,which i think is the property of pwm  and voltage also stops reducing ,it goes from some 0.7v to 1.17v(up and down) continuosly.

If i now connect the same PWM with a DC motor,i am able to control the speed when its above that pot level(6 or 7), till 4095.

below that motor  rotates with the blink of LED.

Do i need to set the PWM resolution,and 

If i want my Pwm to be controlled from the very begining level 0,what is the PWM resolution i need to set up and how to calculate it?

Thank You

 

  • Sajad Rather4 said:
    ...when my pot is at level 6 or 7,below that  led starts blinking ,which i think is the property of pwm  and voltage also stops reducing ,it goes from some 0.7v to 1.17v(up and down) continuosly.

    What you report (Led starts blinking) likely indicates that your PWM Frequency is too low.     With sufficient (i.e. high enough) PWM frequency - the Led's brightness should vary smoothly (based upon the duty cycle of that PWM signal) from, "Fully ON to (nearly) Fully OFF."    (it often requires "special code or hw "handling" to achieve the "extremes" of PWM duty cycle (i.e. 0 & 100%)   Suggest that (both) be avoided - for now.

    PWM frequency of (even) a few hundred Hertz should avoid such "blinking."   To control your motor - I suggest 5KHz PWM frequency as a reasonable beginning.

    Your code: "SysCtlClockSet(SYSCTL_SYSDIV_5| SYSCTL_USE_OSC |SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);" appears to target a 40MHz System Clock - yet it LACKS enabling of the PLL!    Was that your intent?   I've  listed code (below) which our group past used - which yields 40MHz System clock.

    // Configure the processor to run at 40 MHz.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);   //  do note our enabling of the PLL!

    Believe it best for you to set your PWM Duty Cycle to 50% - then read - and report the PWM frequency obtained.   (I believe that your "PWMPeriodSet()" parameter (4095) will yield a, "Far too high" frequency - but due to the mis-setting of your System Clock - the actual MCU Clock Frequency is "disturbed.")    

  • I think the problem is that when you get down to a small duty cycle, you are updating the width with a value that the counter has already passed. This results in a long pulse as the counter must reload and decrement again to reach a match. I suggest you add local synchronization to the configuration.

     

      PWMGenConfigure(PWM1_BASE, PWM_GEN_2,PWM_GEN_MODE_DOWN|PWM_GEN_MODE_SYNC|PWM_GEN_MODE_GEN_SYNC_LOCAL|PWM_GEN_MODE_DBG_RUN);

  • Bob - our posts just crossed - I believe poster's "miss" of the PLL has yielded an "uncertain" System Clock. (I've detailed, above)
  • Well Bob & CB1_mobile

    Bob,

    I tried your idea,but it just gives a constant PWM with 100% duty cycle irrespective of the POT level above that 6 & 7.

    & CB1_mobile

    I changed the system clock to 40MHZ by using PLL.It also puts no effect ,i think changing the clock to 40MHZ will increase the total ticks in my period.

    Previously i have tried to vary the brightness of LED ,with no involvement of ADC_POT,it works fine with any frequency.I have done that with 5khz too.

    I cannot change my period here,as its ADC output of POT,which goes as high upto 4095,so in order to control the dc motor the PWM duty cycle should be varied from 0(0%) to 4095(100%).

    All i can sum up is that when pot is at 0,the motor or led duty cycle should be also 0(no blinking),when pot value increases motor should start rotating slowly or led brightness should start increase and similarly when pot is at 2048,duty cycle should be at 50%. and so on,last value of pot will be 4095 should give duty cycle of 100%

    Well from the above code i am able to get 100%,50%,75%, then why not 0%....even increased my clock frequency to 40 and tried to divide the same also with no effect.





    well i go with CB1s point that system frequency goes too low below 6 or 7th level.


    regards

    sajad
  • I cannot find your "report" of PWM frequency @ 50% Duty Cycle.   I calculate "4095" as yielding an F_PWM just over 10KHz - this can work - but is likely too high for your beginning usage.

    We have - for many years - employed a pot input to DIRECTLY & PRECISELY vary PWM Duty Cycle - just as you seek!    (but - excluding the "extremes," outlined my post, above)

    The API function you MUST ADD is, "PWMPulseWidthSet()."    (this explains why you could not properly vary the duty cycle!)

    from our past StellarisWare:

    Sets the pulse width for the specified PWM output.
    Prototype:
    void
    PWMPulseWidthSet(unsigned long ulBase,
    unsigned long ulPWMOut,
    unsigned long ulWidth)

    I'd like you to adjust PWM Frequency to 1KHz.    This done by placing a calculated value - to reside w/in your "PWMGenPeriodSet()" function.   THIS is how you CONTROL the PWM Frequency.

    And - via my "back of envelope - cell assisted calculation" "40,000" should order a 1KHz PWM frequency - when entombed w/in PWMGenPeriodSet().   (check:  40MHz yields 25nS period - 40K multiplier yields .001S = 1mS - thus 1KHz!)

    If you then (after the above) load a value (into (new for you) PWMPulseWidthSet()) which equals that period's value - 100% PWM will result.   Likewise - 50% of that value will yield 50% duty cycle - just as you desired.  

    *** The "final piece of this puzzle" sees you "SCALING" your ADC reading (reflective of the pot setting) to range between (slightly above zero) & that value, (40,000) "Set w/in the PWMGenPeriodSet() function!"    And - best of all - that scaling will successfully cover the FULL RANGE of your pot - automating the process!

    Your scaling is 40,000/4095 - which is SO CLOSE to TEN (10) - that I'd use that.   (you must "intercept those calls to PWMPulseWidthSet() which attempt to enter a value higher than say 39,900!   (due to problematic 100% duty)     You must also block setting duty cycle to 0 -  as I consider - likely easier for you to test for - then prevent your ADC from passing values HIGHER than 3990 (will be scaled by 10) and lower than (say) 5.   (again will be scaled up by 10)

    This is guaranteed - and there is NO NEED - at all - to "sync."    (there is an "obligation" for you to "click  "Verify"  to reward effort here, though...)

    BTW - you're a smart guy - yet your subject/title provides NO/ZERO subject guidance nor value!    May I suggest that you edit it to, PWM - Frequency & Duty Cycle Setting.  (others will find that of much more interest/value)

  • well that solves the problem,


    Thank you so much for such an explained post.

    Regards Sajad