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.

TM4C123GH6PM, no PWM output

Other Parts Discussed in Thread: TM4C123GH6PM, SYSBIOS

Hi,

I am using a TM4C123GH6PM to control a Q-Brain 4 in 1 ESC (Electronic Speed Controller). This ESC should receive a PWM signal (1ms - 2ms). I have made some code by combining the "Lab 15: PWM" from "Getting Started with the Tiva™ TM4C123G LaunchPad Workshop" and TI RTOS "gpionterrupt example".

Here is the code. It builds with no errors and warning. LED's are working fine and the ui8Adjust variable varies along with pushing Button0 and Button1:

Problem is that my ESC doesn't seem to get any PWM signal. Can anybody help?

/*
* ======== gpiointerrupt.c ========
*/

/* XDCtools Header files */
#include <xdc/std.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>

/* BIOS Header files */
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>

/* TI-RTOS Header files */
#include <ti/drivers/GPIO.h>
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/debug.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"
#include "inc/hw_gpio.h"
#include "driverlib/rom.h"

/* Example/Board Header files */
#include "Board.h"


// PWM variables
volatile uint32_t PWM_FREQUENCY;
volatile uint32_t ui32Load;
volatile uint32_t ui32PWMClock;
volatile uint8_t ui8Adjust;

/*
* ======== gpioButtonFxn0 ========
* Callback function for the GPIO interrupt on Board_BUTTON0.
*/
Void gpioButtonFxn0(Void)
{
/* Clear the GPIO interrupt*/
GPIO_clearInt(Board_BUTTON0);
ui8Adjust = 56; // PWM output to 1ms (0%)
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Load / 1000);
GPIO_write(Board_LED0, Board_LED_OFF);
GPIO_write(Board_LED1, Board_LED_OFF);
GPIO_write(Board_LED2, Board_LED_ON);

}

/*
* ======== gpioButtonFxn1 ========
* Callback function for the GPIO interrupt on Board_BUTTON1.
* This may not be used for all boards.
*/
Void gpioButtonFxn1(Void)
{
/* Clear the GPIO interrupt*/
GPIO_clearInt(Board_BUTTON1);
ui8Adjust = 111; // PWM output to 2ms (100%)
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Load / 1000);
GPIO_write(Board_LED0, Board_LED_OFF);
GPIO_write(Board_LED2, Board_LED_OFF);
GPIO_write(Board_LED1, Board_LED_ON);

}

Void pwmInit(Void)
{
// PWM settings
PWM_FREQUENCY = 55;
ui8Adjust = 83;

SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
SysCtlPWMClockSet(SYSCTL_PWMDIV_64);

SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0);
GPIOPinConfigure(GPIO_PD0_M1PWM0);

HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |= 0x01;
HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_4|GPIO_PIN_0, GPIO_DIR_MODE_IN);
GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4|GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

ui32PWMClock = SysCtlClockGet() / 64;
ui32Load = (ui32PWMClock / PWM_FREQUENCY) - 1;
PWMGenConfigure(PWM1_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN);
PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, ui32Load);

PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Load / 1000);
PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT, true);
PWMGenEnable(PWM1_BASE, PWM_GEN_0);

// Set PWM output = 50%
PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Load / 1000);
}
/*
* ======== main ========
*/
Int main(Void)
{
/* Call board init functions */
Board_initGeneral();
Board_initGPIO();
Board_initUART();

// PWM startup
pwmInit();

/* Turn on user LED */
GPIO_write(Board_LED0, Board_LED_ON);

System_printf("Starting the GPIO Interrupt example\nSystem provider is set"
" to SysMin. Halt the target and use ROV to view output.\n");
/* SysMin will only print to the console when you call flush or exit */
System_flush();

/* Initialize interrupts for all ports that need them */
GPIO_setupCallbacks(&Board_gpioCallbacks0);

/* Enable interrupts */
GPIO_enableInt(Board_BUTTON0, GPIO_INT_RISING);
GPIO_enableInt(Board_BUTTON1, GPIO_INT_RISING);

/*
* If more than one input pin is available for your device, interrupts
* will be enabled on Board_BUTTON1.
*/
//if (Board_BUTTON0 != Board_BUTTON1) {

/* Need to call setup if the button is on a different port */
//if (&Board_gpioCallbacks0 != &Board_gpioCallbacks1) {
// GPIO_setupCallbacks(&Board_gpioCallbacks1);
// }

// GPIO_enableInt(Board_BUTTON1, GPIO_INT_FALLING);
// }

/* Start BIOS */
BIOS_start();

return (0);
}

I have also attached a jpeg file with the wiring. 

  • Hi Alexander,

    Can you try changing the line

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, ui8Adjust * ui32Load / 1000);

    with

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0, (ui8Adjust * ui32Load) / 1000);

    Regards

    Amit

  • Hi Amit,

    The changes are made without any different results.

    My ESC returns a "beep" signal every 2 seconds telling me that the "throttle signal is abnormal". In my case meaning the PWM output.

  • Hi Alexander,

    The PWM configuration is fine. Just to double check, please send the value of the registers for PWM0LOAD, PWM0GEBA and PWM0CMPA.

    The only other bottle neck would be at the GPIO PORT-D if the configuration is not complete. Can you send a register dump of the above said GPIO from offset 0x400 to 0x43C and 0x500 to 0x53C

    Regards

    Amit

  • Alexander Waldejer said:
    My ESC returns a "beep" signal every 2 seconds telling me that the "throttle signal is abnormal". In my case meaning the PWM output.

     Hi Alex, I don't know this ESC, so answer can be useless: Input need a simple PWM like servo mode or this combined ESC need a frame like the one from RC receiver/transmitter? IF so missing framing signals cannot sync ESC from extracting channel information.

     May be also some programming must be done on ESC to establish communication mode.

  • I did some research (google :-) ), and found a similar problem one guy had when combining the Q-brain with a Arduino Mega (http://forum.arduino.cc/index.php?topic=214701.0)

    quote:
    " I was told from HobbyKing to lower the PWM frequency to below 400 with a wave length of 900us for 0%. I lowered the frequency, but I have no idea what the wave length is suppose to mean and how to set it."

    My setup should fit these requirements. The problem above was solved by connecting common ground between the card and the ESC. I don't actually use the BEC output (5V3A) from my ESC to power up the board, though connecting the ESC / BEC ground over to J3 pin 2 mite help. 

    I'll try this and get back to you guys on further development. Thanks for the help so far :-)

  • Alexander Waldejer said:

    " I was told from HobbyKing to lower the PWM frequency to below 400 with a wave length of 900us for 0%. I lowered the frequency, but I have no idea what the wave length is suppose to mean and how to set it."

     As I supposed specific programming is necessary to do these part working as they need.

     400Hz has a period of 2.5mS 2500uS and neutral point at middle 1250uS, neutral point is often acquired from steady state at power up, manufacturer suggest use neutral point of 900uS so not PWM Duty cycle of 50% but 100*900/2500 =36%

     This is not enough, you must ask again about resolution (time step) and min/max time or Duty cycle too. Otherwise you can do some experimental drive with a pulse generator than using a board.

     To drive a digital servo I seat down on front of my Agilent 8116 function/pulse generator extrapolating optimal parameter from experimental data, I suppose this ESC is more documented but nowtime cheap product come to market with chinese manual or just nothing more than plastic case.

  • Alexander Waldejer said:

    My setup should fit these requirements. The problem above was solved by connecting common ground between the card and the ESC. I don't actually use the BEC output (5V3A) from my ESC to power up the board, though connecting the ESC / BEC ground over to J3 pin 2 mite help. 

     FIRST:

    GROUND MUST BE CONNECTED TO ALL APPLIANCES!!!!!

     please connect a scope, Ground  to an LP ground pin and measure what is on PWM pin with probe tip then tell us waht is there.

     I got an eye to your code, you cannot set PWM to 2mS on an 1Khz period, you can set from few uS to a max of 999uS, 0 is ground 1000 and greater is steady vcc intermediate are 1000 step of PWM Duty cycle from 0 to 100*999/1000 or pulse width in uS from 0 to 999uS

  • Im new to all microcontrollers, including setting up PWM signals.

    From the "Getting Started With the Tiva C Series TM4C123G LaunchPad" - PWM section, the frequency is as following:

    When Hobbyking say that the ESC requires a frequency of 400, I guess my programmed 625 is to high...
    My CPU clock must be to high, as the PWM module divider has a range from 2 to 64.

    How could I go further here?

    Roberto Romano said:

    please connect a scope, Ground  to an LP ground pin and measure what is on PWM pin with probe tip then tell us waht is there.

     I got an eye to your code, you cannot set PWM to 2mS on an 1Khz period, you can set from few uS to a max of 999uS, 0 is ground 1000 and greater is steady vcc intermediate are 1000 step of PWM Duty cycle from 0 to 100*999/1000 or pulse width in uS from 0 to 999uS

    I will have my setup connected to a scope on monday.

  • Hi Alexander,

    If you could send the registers values as asked earlier along with the scope data, it would be useful information to know if the PWM signal is coming on the IO's.

    Regards

    Amit

  • Hi Alexander,

    I ran your code on my TM4C123 part and I see a 55Hz signal with a duty cycle of 8.5%. So basically the PWM is working fine.

    Regards

    Amit Ashara

  • Okey. So now I have tested the PWM output trough a oscilloscope. The results are as following:

    PWM frequency = 55Hz, peak voltage = 3.28V
    ui8Adjust = 56 (1ms), ui8Adjust = 111 (2ms)

    PWM frequency = 200Hz, peak voltage = 3.28V
    ui8Adjust = 200 (1ms), ui8Adjust = 400 (2ms)

    PWM frequency = 400Hz, peak voltage = 3.28V
    ui8Adjust = 400 (1ms), ui8Adjust = 800 (2ms)

    When testing the PWM against the ESC, I tried to run a frequency = 400Hz, with a max/min of ui8Adjust = 440/760.
    The ESC was able to calibrate. After a reboot of the system everything was working!

    So, a conclusion? 

    Roberto Romano said:

     I got an eye to your code, you cannot set PWM to 2mS on an 1Khz period, you can set from few uS to a max of 999uS, 0 is ground 1000 and greater is steady vcc intermediate are 1000 step of PWM Duty cycle from 0 to 100*999/1000 or pulse width in uS from 0 to 999uS

    By not setting the PWM max/min = 1ms/2ms, but as  said above a little few uS under and over, must have solved the case.

    In general ESC's accept a frequency from 50-400Hz and a peak voltage of 5V (though accepting 3.3V as in my case).

    Thanks for all the help guys!

    Regards Alexander Waldejer 

  • Hi Gurus,

    I am also trying to get my TIVA 1294 Connected launcpad to control an ESC (RCTIMER45A) .

    I took the PWM example from tirtos and changed the period to 20ms =50Hz and duty to vary between 1ms to 2 ms. The xample varies the intensity of an onboard LED and that's visually working.

    But I do not get my motors turning.

    The code :

    *

    * ======== pwmled.c ========

    */

    /* XDCtools Header files */

    #include <xdc/std.h>

    #include <xdc/cfg/global.h>

    #include <xdc/runtime/System.h>

    /* BIOS Header files */

    #include <ti/sysbios/BIOS.h>

    /* TI-RTOS Header files */

    #include <ti/drivers/PWM.h>

    /* Example/Board Header files */

    #include "Board.h"

    /*

    * ======== pwmLEDFxn ========

    * Task periodically increments the PWM duty for the on board LED.

    */

    Void pwmLEDFxn(UArg arg0, UArg arg1)

    {

    PWM_Handle pwm1;

    PWM_Handle pwm2 = NULL;

    PWM_Params params;

    uint16_t pwmPeriod = 20000; // Period and duty in microseconds

    uint16_t duty = 0;

    uint16_t dutymin = 1000;

    uint16_t dutymax=2000;

    uint16_t dutyInc = 100;

    PWM_Params_init(&params);

    params.period = pwmPeriod;

    pwm1 = PWM_open(Board_PWM0, &params);

    if (pwm1 == NULL) {

    System_abort("PWM0 did not open");

    }

    if (Board_PWM1 != Board_PWM0) {

    params.polarity = PWM_POL_ACTIVE_LOW;

    pwm2 = PWM_open(Board_PWM1, &params);

    }

     

    /* Loop forever incrementing the PWM duty */

    duty=dutymin;

    while (1) {

    PWM_setDuty(pwm1, duty);

    if (pwm2) {

    PWM_setDuty(pwm2, duty);

    }

    duty = (duty + dutyInc);

    if (duty == dutymax || (!duty)) {

    dutyInc = - dutyInc;

    }

    if (duty == dutymin || (!duty)) {

    dutyInc = - dutyInc;

    }

     

    Task_sleep((UInt) arg0);

    }

    }

    /*

    * ======== main ========

    */

    int main(void)

    {

    /* Call board init functions. */

    Board_initGeneral();

    Board_initGPIO();

    Board_initPWM();

    /* Turn on user LED */

    GPIO_write(Board_LED0, Board_LED_ON);

    System_printf("Starting the example\nSystem provider is set to SysMin. "

    "Halt the target to view any SysMin contents in ROV.\n");

    /* SysMin will only print to the console when you call flush or exit */

    System_flush();

    /* Start BIOS */

    BIOS_start();

    return (0);

    }

    I would like the signal to be available on port PF0 which is the pin for PWM0.

    Could you please help me on this.

    Regards, Vikram.

  • Vikram JHURRY said:

    I would like the signal to be available on port PF0 which is the pin for PWM0.  

    Interestingly I can find no mention of your (use PF0) anywhere w/in your code dump!

    Frequent poster here "Markel" advises that, "One should recall that pin PF0 must, "first be unlocked" prior to use beyond its (normal/default) NMI mode.    Appears that you've some way/how "missed" his "signature block" warning!    (strange that)

    That same well meaning (yet flawed due to obscurity) guidance appears w/in your MCU manual. (indeed nowhere in "proper highlight")      Sometimes worthwhile to read/review the "fine" manual...   

    You are not the "first" to be impaled by this (always helpful) default NMI behavior - surely will not be the last - and in fact some here have (long) protested such unwanted, "default as NMI" behavior.    Vendor appears "blind" to the need to fix/alter - despite pain/suffering caused their valued user-clients...

    Brief search this forum will reveal the hundreds here who suffered similarly - and provide "corrective action."     Or - far simpler - you can switch to a different pin!     (yet one more "awaits" to apply its same NMI curse - Russian Roulette anyone?)

  • Hi,
    Actually PIN PF0 is directly connected to the LED4 on the Launchpad - and since the LED was actually dimming well - means the PWM signal was coming right to the Pin.
    I finally found the problem - the ESC needs a 1ms duration signal for many seconds to arm.
    Once I did this - that is output a 1ms signal at 50 Hz for about 5 seconds then I got into the routine of incrementing/decrementing the duty cycle, now the motor turned.
    I got the hint form the comment
    "ESC is controlled just like a servo. It needs a single positive pulse from 1 to 2 mS wide that is repeated approximately every 20mS. The speed is controlled by the width of the pulse. You usually need to start it out at 1mS (ie motor off) for several seconds to arm the ESC."
    from forum:
    www.rcgroups.com/.../showthread.php

    I post the corrected code:

    Void pwmLEDFxn(UArg arg0, UArg arg1)
    {
    PWM_Handle pwm1;
    PWM_Handle pwm2=NULL;
    PWM_Params params;
    uint16_t pwmPeriod = 20000; // Period and duty in microseconds
    uint16_t duty = 0;
    uint16_t dutymin = 1000;
    uint16_t dutymax=10000;
    uint16_t dutyInc = 100;

    PWM_Params_init(&params);
    params.period = pwmPeriod;
    pwm1 = PWM_open(Board_PWM0, &params);
    if (pwm1 == NULL) {
    System_abort("PWM0 did not open");
    }

    if (Board_PWM1 != Board_PWM0) {
    params.polarity = PWM_POL_ACTIVE_LOW;
    pwm2 = PWM_open(Board_PWM1, &params);
    }

    PWM_setDuty(pwm1, dutymin);
    uint16_t armingtime;
    armingtime=arg0 * 300;


    Task_sleep((UInt) armingtime);



    /* Loop forever incrementing the PWM duty */
    duty=dutymin;
    while (1) {
    PWM_setDuty(pwm1, duty);

    if (pwm2) {
    PWM_setDuty(pwm2, duty);
    }

    duty = (duty + dutyInc);
    if (duty == dutymax || (!duty)) {
    dutyInc = - dutyInc;
    }
    if (duty == dutymin || (!duty)) {
    dutyInc = - dutyInc;
    }


    Task_sleep((UInt) arg0);
    }
    }


    notice the armingtime.
  • Glad that you report success - yet I (remain) blind to your "unlocking & reconfig." of PF0 - which usually is required.   

    Suspect that such is handled by one of your RTOS drivers - which may not be present for many here - and which (appears) to have desensitized you to this pin sensitivity issue.     While you're "safe for now" - torment may await - bit downstream.     (should/when you develop minus that RTOS)

  • He's using the Cadillac version (129) - PF0 has been cured there, only PD7 remains locked to NMI.

  • Thank you, Sir.   I wondered how even the heralded RTOS was smart enough to "divine" poster's (unexplained/unknown) intent re: PF0!    

    We note that this thread is titled - and still tagged: TM4C123...

    Outside this thread - yet notable - even "Cadillacs" suffer recall (I mean massive errata) do they not?