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.

EK-TM4C1294XL Launchpad PWM configuration

Prodigy 150 points

Replies: 27

Views: 7019

Hello!

I'm working with the EK-TM4C1294XL Launchpad and trying to figure out how to use the hardware PWM module.

Ideally I'd like to find a way to use it in energia, but my guess is that energia doesn't support chip specific features like that, sadly. So any help getting it set up in CCS 6 would be fantastic.

So far I've made a new project and tried to compile the tivaware pwm example "dead_band.c" with an added #define PART_TM4C1294NCPD


Code I've tried is copied here:

//*****************************************************************************
//
// dead_band.c - Example demonstrating the dead-band generator.
//
// Copyright (c) 2010-2014 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
//   Redistribution and use in source and binary forms, with or without
//   modification, are permitted provided that the following conditions
//   are met:
// 
//   Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// 
//   Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the  
//   distribution.
// 
//   Neither the name of Texas Instruments Incorporated nor the names of
//   its contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
//
//*****************************************************************************
#define PART_TM4C1294NCPD
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/pwm.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.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
//!
//! The following UART signals are configured only for displaying console
//! messages for this example.  These are not required for operation of the
//! PWM.
//! - UART0 peripheral
//! - GPIO Port A peripheral (for UART0 pins)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! This example uses the following interrupt handlers.  To use this example
//! in your own application you must add these interrupt handlers to your
//! vector table.
//! - None.
//
//*****************************************************************************

//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
    //
    // Enable GPIO port A which is used for UART0 pins.
    // TODO: change this to whichever GPIO port you are using.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Configure the pin muxing for UART0 functions on port A0 and A1.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);

    //
    // Enable UART0 so that we can configure the clock.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

    //
    // Use the internal 16MHz oscillator as the UART clock source.
    //
    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    //
    // Select the alternate (UART) function for these pins.
    // TODO: change this to select the port/pin you are using.
    //
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, 16000000);
}

//*****************************************************************************
//
// Prints out 5x "." with a second delay after each print.  This function will
// then backspace, clearing the previously printed dots, and then backspace
// again so you can continuously printout on the same line.  The purpose of
// this function is to indicate to the user that the program is running.
//
//*****************************************************************************
void
PrintRunningDots(void)
{
    UARTprintf(". ");
    SysCtlDelay(SysCtlClockGet() / 3);
    UARTprintf(". ");
    SysCtlDelay(SysCtlClockGet() / 3);
    UARTprintf(". ");
    SysCtlDelay(SysCtlClockGet() / 3);
    UARTprintf(". ");
    SysCtlDelay(SysCtlClockGet() / 3);
    UARTprintf(". ");
    SysCtlDelay(SysCtlClockGet() / 3);
    UARTprintf("\b\b\b\b\b\b\b\b\b\b");
    UARTprintf("          ");
    UARTprintf("\b\b\b\b\b\b\b\b\b\b");
    SysCtlDelay(SysCtlClockGet() / 3);
}

//*****************************************************************************
//
// 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);

    //
    // Set up the serial console to use for displaying messages.  This is just
    // for this example program and is not needed for PWM operation.
    //
    InitConsole();

    //
    // Display the setup on the console.
    //
    UARTprintf("PWM ->\n");
    UARTprintf("  Module: PWM0\n");
    UARTprintf("  Pin(s): PD0 and PD1\n");
    UARTprintf("  Features: Dead-band Generation\n");
    UARTprintf("  Duty Cycle: 25%% on PD0 and 75%% on PD1\n");
    UARTprintf("  Dead-band Length: 160 cycles on rising and falling edges\n\n");
    UARTprintf("Generating PWM on PWM0 (PD0) -> ");

    //
    // 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)
    {
        //
        // Print out indication on the console that the program is running.
        //
        PrintRunningDots();
    }
}

But that generates the error:

"../main.c", line 98: error #20: identifier "GPIO_PA0_U0RX" is undefined
"../main.c", line 99: error #20: identifier "GPIO_PA1_U0TX" is undefined
"../main.c", line 214: error #20: identifier "GPIO_PB6_M0PWM0" is undefined

"../main.c", line 215: error #20: identifier "GPIO_PB7_M0PWM1" is undefined

I am betting I have the define incorrect or something, since I assume the example is meant to be easy to use, but I'm stuck and would really appreciate some help here.

Thank you!

Garrett

27 Replies

  • Hello Garrett,

    The define is PART_TM4C1294NCPDT and has to be defined under settings

    Right Click the Project -> Show Build Settings -> Build -> ARM Compiler -> Advanced Settings -> Predefined Symbols

    In the upper box  of Pre-define NAME you have to add the following two defines.

    PART_TM4C1294NCPDT

    TARGET_IS_TM4C129_RA1

    Regards

    Amit

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Afternoon Amit-

    Thanks for the quick response, but I'm still getting these errors after defining those two parts as instructed.

    "../main.c", line 213: error #20: identifier "GPIO_PB6_M0PWM0" is undefined

    "../main.c", line 214: error #20: identifier "GPIO_PB7_M0PWM1" is undefined

    Any ideas?

    Garrett

  • In reply to Garrett Burgwardt:

    Hello Garrett,

    On TM4C1294NCPDT PB6 and PB7 are not PWM pins. It is PF0 and PF1 and the define is

    GPIO_PF0_M0PWM0
    GPIO_PF1_M0PWM1

    You would have to enable the clock to GPIO Port F instead of GPIO Port B

    Also do note that PF0 is a Locked Pin and the following post will help you unlock it

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/284566.aspx

    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/346603.aspx

    Regards

    Amit

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Alright, so I changed the defines to PF0 and PF1 - I really only need one PWM signal so is it alright to just comment out the PF0/PWM0 line? Or can I just leave it and it won't actually do anything since the pin is locked.

    Either way, this is a hard example to run!

    After changing those lines, I now get the following errors-

    <Linking>

     undefined              first referenced
      symbol                    in file     
     ---------              ----------------
     GPIOPinConfigure       ./main.obj      
     GPIOPinTypePWM         ./main.obj      
     GPIOPinTypeUART        ./main.obj      
     PWMDeadBandEnable      ./main.obj      
     PWMGenConfigure        ./main.obj      
     PWMGenEnable           ./main.obj      
     PWMGenPeriodGet        ./main.obj      
     PWMGenPeriodSet        ./main.obj      

     PWMOutputState         ./main.obj      
    >> Compilation failure
     PWMPulseWidthSet       ./main.obj      
     SysCtlClockGet         ./main.obj      
     SysCtlClockSet         ./main.obj      
     SysCtlDelay            ./main.obj      
     SysCtlPWMClockSet      ./main.obj      
     SysCtlPeripheralEnable ./main.obj      
     UARTClockSourceSet     ./main.obj      
     UARTStdioConfig        ./main.obj      
     UARTprintf             ./main.obj     

    So fairly clearly it looks like it's missing a header file or something that defines those, but honestly I am very new at programming anything more advanced than the msp430 I used in my embedded systems lab (and here I thought this would be similar enough to not cause problems! Hah)

    Thank you very much for your help Amit, you're a saint.

    Garrett

  • In reply to Garrett Burgwardt:

    Hello Garrett,

    There are a few more things to be taken care

    1. Add the the file uartstdio.c and .h from utils directory of TIVAWare to your project

    2. On TM4C129 devices the SysCtlClockSet is replaced by the SysCtlClockFreqSet API

    3. The return value of SysCtlClockFreqSet is the System Clock Frequency which replaces SysCtlClockGet API call.

    As an example you can refer to

    C:\ti\TivaWare_C_Series-2.1.0.12573\examples\boards\ek-tm4c1294xl\hello\hello.c for usage of the SysCtlClockFreqSet

    For point of other functions giving an error during Linker the reason is missing driverlib.lib

    Attached is the screenshot of the missing driverlib.lib

    Regards

    Amit

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    Thank you for being so patient and helpful again Amit.

    I made the changes you suggested, and now I only have one error -

    "../driverlib/onewire.c", line 52: fatal error #1965: cannot open source file "inc/hw_onewire.h"

    I've googled around and it seems like this is a file that's just not included in tivaware - is that true? Is there any workaround for this?

    Additionally, I'm confused by what exactly I have to change for the switch to SysCtlClockFreqSet from SysCtlClockSet, but I'll keep studying the example you suggested and hopefully can figure that out on my own. For the record, all I did so far was change SysCtlClockSet to SysCtlClockFreqSet, but that seems to just throw more errors.

     

    Garrett

  • In reply to Garrett Burgwardt:

    Hello Garrett

    Yes. hw_onewire.h is not available as of now. We plan for it to be a part of the next TIVAWare release.

    As for the function replacement the example should be sufficient in my opinion but do post the project you have in case it still does not work out.

    Regards

    Amit

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    You are my favorite person right now Amit, I'm gonna buy a palette of TM4C1294NCPDT chips when I get this sorted out and include a note telling them to give you a raise :)

    So there doesn't seem to be a way to make this code run, if it won't compile without hw_onewire.h, or am I missing something?

    Maybe it would help to change my approach to this problem.

    I'm working at a startup and we want to use TI chips because of the fantastic community and low price, not to mention all the features.

    We don't need a huge amount of speed, but I need to generate a configurable PWM signal (approx 15 kHz and varying duty cycles), among other things that are already taken care of.

    So, could you point me to a compilable/uploadable PWM example that I could potentially modify to use? So far I haven't been able to get a PWM signal from PWM hardware, though I can just bitbang some (noisy) signals to get us by for now.

    Thanks Amit

    Garrett

  • In reply to Garrett Burgwardt:

    Hello Garrett,

    Zip your existing project (I do not have a ready PWM project on TM4C129) and attach to your post,

    I could see what exactly is required and trim the code down for PWM operation only.

    Regards

    Amit

    Regards,

    Amit Ashara

  • In reply to Amit Ashara:

    i actualy tried before using PWM module with TivaWare using Energia compiler. it was a bit harder than with timers but it eventualy worked, but i think it was just in the TM4C123, the TM4C1294 i never got it to work

    let me see if i find my code and check if it's working tomorrow (let's hope the osciloscope is free for me to use)


    Luís Afonso

    For more reply options press "Use rich formatting" on the bottom right.

    I have a blog that i am making to help some colleagues with learning Tiva:  https://sites.google.com/site/luiselectronicprojects/home
    I have here now example codes for the Tiva more organized: https://github.com/LuisAfonso95

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.