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.

LM4F120XL capture mode

//Tools: ccs5.4 Stellaris LM4F120 LaunchPad evaluation board(LM4F120H5QR)
//Description: There is no errors or warnings when the compile complete.I have
// already configured the start_ccs.c file. write the Timer2B interupt
function into the start_ccs.c file.


//Question: The pwm function is working properly.But something wrong with
the capture mode.Through watch the value of variable 'i' and set
the breakpoint in the interupt function, I found that it could not
get into the interupt function. where is the wrong?

// Sorry for my poor English and expressions Here is the codes.
//If possible, you can share some codes about the capture mode with me.
//Thanks a lot.

#ifndef PART_LM4F120H5QR
#define PART_LM4F120H5QR
#endif

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "utils/uartstdio.h"
#include "driverlib/pin_map.h"

//*****************************************************************************
//
// Configure Timer1B as a 16-bit PWM with a duty cycle of 50%.
//Configure TIMER1A as capture mode
//*****************************************************************************

int i=0;
void Timer1AIntHandler(void);

int main(void)
{
//
// Set the clocking to run directly from the external crystal/oscillator.
//
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);

//
// The Timer1 peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
//SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
//
// For this example CCP1 is used with port B pin 5.
// 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.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

//
// Configure the GPIO pin muxing for the Timer/CCP function.
// This is only necessary if your part supports GPIO pin function muxing.
// Study the data sheet to see which functions are allocated per pin.
//
GPIOPinConfigure(GPIO_PB5_T1CCP1); //pwm
GPIOPinConfigure(GPIO_PB4_T1CCP0); //capture
//
// Set up the serial console to use for displaying messages. This is
// just for this example program and is not needed for Timer/PWM operation.
//
GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_5); //pwm
GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_4); //capture

//GPIODirModeSet(GPIO_PORTB_BASE,GPIO_PIN_4,GPIO_DIR_MODE_IN);
//GPIOPadConfigSet(GPIO_PORTB_BASE,GPIO_PIN_4,GPIO_STRENGTH_4MA,GPIO_PIN_TYPE_STD_WPU);
// Configure Timer1B as a 16-bit periodic timer.
//
TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
TIMER_CFG_B_PWM); //pwm
TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
TIMER_CFG_A_CAP_COUNT); //capture
//
// Set the Timer1B load value to 50000. For this example a 66% duty
// cycle PWM signal will be generated. From the load value (i.e. 50000)
// down to match value (set below) the signal will be high. From the
// match value to 0 the timer will be low.
//
TimerLoadSet(TIMER1_BASE, TIMER_B, 40000); //pwm

TimerControlEvent(TIMER1_BASE,TIMER_A,TIMER_EVENT_NEG_EDGE);
TimerControlStall(TIMER1_BASE,TIMER_A,true); //capture
TimerLoadSet(TIMER1_BASE, TIMER_A, 6003);
// Set the Timer1B match value to load value / 3.
//
TimerMatchSet(TIMER1_BASE, TIMER_B, TimerLoadGet(TIMER1_BASE, TIMER_B) / 2);
TimerMatchSet(TIMER1_BASE, TIMER_A, 1);
//
// Enable Timer1B.
//
TimerIntRegister(TIMER1_BASE, TIMER_A,Timer1AIntHandler);
TimerEnable(TIMER1_BASE, TIMER_B);

TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT);
IntEnable(INT_TIMER1A);
TimerEnable(TIMER1_BASE, TIMER_A);

IntPrioritySet(INT_TIMER1A,0x20);
//
// Loop forever while the Timer1B PWM runs.
//

IntMasterEnable();
 while(1)
 {
   ;
 }
}

void Timer1AIntHandler(void)
{
 TimerIntClear(TIMER1_BASE, TIMER_A);
 i++;
 if(i==10000)
 {
   i=0;
 }

}

  • You don't say exactly what you want the code to do but I assume, given that you set the timer match register to 1, that you want an interrupt every time a negative edge is detected on pin CCP0? If that is true, there are a couple of changes you have to make to the code:

    1. Replace 

    TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
    TIMER_CFG_B_PWM); //pwm
    TimerConfigure(TIMER1_BASE, TIMER_CFG_16_BIT_PAIR |
    TIMER_CFG_A_CAP_COUNT); //capture

    with

    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR |
                   TIMER_CFG_B_PWM | TIMER_CFG_A_CAP_COUNT_UP);

    Your original code will corrupt the configuration for timer B when you make the second call to TimerConfigure(). Configure both sub-timers using one call to prevent this from happening. Note that I've updated this to match the new definitions in TivaWare - TIMER_CFG_16_BIT_PAIR is deprecated and has been replaced by TIMER_CFG_SPLIT_PAIR.

    By default, the timer will count down so I've changed the configuration so that it counts up which I expect is more helpful for you. In this mode, the timer starts at 0 and increments on each negative edge. When it reaches the match value, programmed to 1, the interrupt will fire.

    2. You enable the TIMER_CAPA_EVENT interrupt but this is only used for edge time mode. For edge count (capture) mode, use the TIMER_CAPA_MATCH interrupt instead.

    3. This isn't vital but you should remove the call to TimerIntRegister if you have included Timer1AIntHandler() in the startup file's vector table. All TimerIntRegister will do is waste about 2KB of SRAM to create a copy of the vector table there. This is not needed unless you really want to change interrupt vectors during the time an application is running.

    With these changes in the code, I have run your application and it now correctly calls the interrupt handler.

  • Thanks a lot for your reply.

    (Sorry for my poor expressions, I hope those words can make you clear about the purpose of the codes )

    My real purpose is calculate the frequency of the pwm which creates by the timerB. With your help, I modified my codes. But at the same time, I have a new question.

    Now I have changed the configures, replace the TIMER_CFG_A_CAP_COUNT_UP with the  TIMER_CFG_A_CAP_TIME_UP, and use the TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT).  Then with a botton, the codes can run into the interrupt function when a negative edge  occurs. 

    Here is the question. As we all know, we have to figure out how many times  the timers run overcount between the neighbour negative edges.

    Such as:(16-bit-timer)

    the first negative edge       the second negative edge      numbers of overcount

    50000                                             100                                                      1

    (current timer value)              (current timer value)

    so between the two negative edges, there are (65535*1-50000+100)=15635 clock steps.

    whether I can do the both things with the timer1A  ?(capture the negative edges and count numbers of overcount)

    I have tried by myself but it does not work. Only when a negative edge occurs, can the codes run into the interrupt. It means that when the timer runs overcount, it cann't

    get into the interrupt function even I have enable the TIMEROUT interrupt.

    I'm looking forward to hearing from you soon!  

                                                                                                                                                              wilson

    PS:here is my new codes.

    #ifndef PART_LM4F120H5QR
    #define PART_LM4F120H5QR
    #endif

    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_timer.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/timer.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/gpio.h"
    #include "utils/uartstdio.h"
    #include "driverlib/pin_map.h"
    #include "math.h"

    //*****************************************************************************
    //
    // Configure Timer1B as a 16-bit PWM with a duty cycle of 50%.
    //Configure TIMER1A as capture mode
    //*****************************************************************************

    int i=0;
    int overcount=0;
    void Timer1AIntHandler(void);

    int main(void)
    {
    //
    // Set the clocking to run directly from the external crystal/oscillator.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);

    //
    // The Timer1 peripheral must be enabled for use.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

    //
    // For this example CCP1 is used with port B pin 5.
    // GPIO port B needs to be enabled so these pins can be used.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    //
    // Configure the GPIO pin muxing for the Timer/CCP function.
    //
    //
    GPIOPinConfigure(GPIO_PB5_T1CCP1);             //pwm
    GPIOPinConfigure(GPIO_PB4_T1CCP0);        //capture
    //
    // Set up the serial console to use for displaying messages. This is
    //
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_5);         //pwm
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_4);        //capture

    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

    // Configure Timer1B as a 16-bit periodic timer.
    //
    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR |
    TIMER_CFG_B_PWM|TIMER_CFG_A_CAP_TIME_UP);         //B:pwm A:capture event mode

    //
    // Set the Timer1B load value to 40000. For this example a 50% duty
    // cycle PWM signal will be generated. From the load value (i.e. 50000)
    // down to match value (set below) the signal will be high. From the
    // match value to 0 the timer will be low.
    //
    TimerLoadSet(TIMER1_BASE, TIMER_B, 40000);                    //pwm

    TimerControlEvent(TIMER1_BASE,TIMER_A,TIMER_EVENT_NEG_EDGE);
    TimerControlStall(TIMER1_BASE,TIMER_A,true);              //capture
    TimerLoadSet(TIMER1_BASE, TIMER_A,10000);
    // Set the Timer1B match value to load value / 3.
    //
    TimerMatchSet(TIMER1_BASE, TIMER_B, TimerLoadGet(TIMER1_BASE, TIMER_B) / 2);
    //TimerMatchSet(TIMER1_BASE, TIMER_A, 5000);
    //
    // Enable Timer1B.
    //
    TimerEnable(TIMER1_BASE, TIMER_B);


    TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT|TIMER_TIMA_TIMEOUT); // enable the timeout interrupt at the same time
    IntEnable(INT_TIMER1A);
    TimerEnable(TIMER1_BASE, TIMER_A);

    //IntPrioritySet(INT_TIMER1A,0x20);
    //
    // Loop forever while the Timer1B PWM runs.
    //
    IntMasterEnable();

     while(1)
      {
         ;
       }
    }

    void Timer1AIntHandler(void)                                 // now the interrupt function is just for test. when the timer1A 
    {                                                                                       // is overcount, it can not get into the interrupt
         if(TimerIntStatus(TIMER1_BASE,TIMER_TIMA_TIMEOUT)==TIMER_TIMA_TIMEOUT)
          {
                   overcount++;                                             //cann't get here!!!!
            }
         else
         {
               i++;
              if(i==10000)
                  {
                           i=0;
                  }
         }
    TimerIntClear(TIMER1_BASE,TimerIntStatus(TIMER1_BASE, TIMER_CAPA_EVENT | TIMER_CAPB_EVENT));
    TimerIntClear(TIMER1_BASE,TIMER_TIMA_TIMEOUT);
    }

  • I re-read this section of the datasheet and I think you will have to use 2 timers to do this. If the edges you are measuring can ever be further apart than 2**16 clock cycles, a second timer should be used to let you catch rollover cases. The datasheet also says that you can extend the edge timer to 24 bits (from 16 bits) if you enable the prescaler so that may help resolve the problem because you would them be able to measure intervals 256 times longer without needing to use the second timer.

  • Believe Dave's able posts to solve - and fully detail.

    Might the goal of "all requirements" - solved by just one timer - add needless complexity/effort?

    ARM MCUs provide timers far in excess of many/most applications - successful engineers/programmers usually better (i.e. more fully) employ these resources...

    KISS rules - proceed by refinement follows.  (as/if needed...)  And KISS sure to aid/model/roadmap any such, "refinement."

  • I want to measure the frequency of pwm continuously. So with your advise, I choose to use another timer to complete it.

    Thanks a lot .