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.

RTOS/TM4C123GH6PM: Time measurement of PWM input signal

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: STRIKE

Tool/software: TI-RTOS

Hi

I am working just to capture the time difference between rising edge and falling edge of a input PWM signal(1KHz frequency).

I am using Timer 0 with CCP mode to capture external clock event. My Handler is getting called for both rising and falling edge of external clock but when I read the timer value on the handler using TimerValueGet(WTIMER0_BASE, TIMER_A) I am getting inappropriate value.

Timer a Value 4294967295

Timer a Value 4294978345

............................................

How to capture the time difference of two edges.Is there issue with timer configuration.

Please find my below config sequence.

SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_4);
GPIOPinConfigure(GPIO_PC4_WT0CCP0);
GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);


TimerConfigure(WTIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME);
TimerControlEvent(WTIMER0_BASE, TIMER_A, TIMER_EVENT_BOTH_EDGES);
TimerIntEnable(WTIMER0_BASE, TIMER_CAPA_EVENT);

System_printf("clock %u\n",SysCtlClockGet());


TimerLoadSet(WTIMER0_BASE, TIMER_A, SysCtlClockGet()); 

TimerIntRegister(WTIMER0_BASE, TIMER_A, Wtimer0IntHandler);

TimerEnable(WTIMER0_BASE, TIMER_A);

         My handler was

void
Wtimer0IntHandler(void)
{
// unsigned int data = GPIOPinRead(GPIO_PORTC_BASE, GPIO_PIN_4);
// System_printf("data %d\n",data);

//
// Clear the timer interrupt.
//
unsigned long timera = TimerValueGet(WTIMER0_BASE, TIMER_A);


System_printf("Timer a Value %u\n",timera);
// System_flush();

TimerIntClear(WTIMER0_BASE, TIMER_CAPA_EVENT);

//
// Update the interrupt status on the display.
//
IntMasterDisable();

// GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_4, 0);
// data = !!GPIOPinRead(GPIO_PORTC_BASE, GPIO_PIN_4);
// System_printf("data %d\n",data);

/* if(data != 0)
{
GPIO_write(Board_LED0, Board_LED_ON);
}
else
{
GPIO_write(Board_LED0, Board_LED_OFF);
}
*/

IntMasterEnable();
}

  • As has been written here (many) times - would not TWO Timers - one configured to, "Capture only Rising Edge" - the second to, "Capture only Falling Edge" immensely, "speed, ease, & enhance" your programming effort?       And such dual timer usage is fully KISS compliant - attempting to achieve this result w/in a single Timer adds greatly to the required time/effort - and such "NEED" (for the more difficult to implement Single Timer) is (of course) never/ever explained nor justified!

    And - how "effective" will your "Single Timer" prove when attempting to measure a, "Very brief/narrow PWM pulse?"       That's a "deal-breaker" - is it not?       TWO Timer solution completely solves such challenge - is (remains) the CLEAR WINNER!   

    I can find your code line which reads "one" of the Timer edges - yet sends that result out over UART - never again to "Seek the (remaining/other)" signal edge! 

    The TWO TIMER Method - operated under KISS - clearly is your "best/safest and ONLY" bet!

  • Hi Gowtham,
    GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD) is unnecessary in the below lines.

    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_4);
    GPIOPinConfigure(GPIO_PC4_WT0CCP0);
    GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

    Does the code you posted have the System_flush() commented or un-commented. Please note that if you have the System_flush() line uncommented it will then print on the CCS console which will impact realtime operation. If you don't have the System-flush then the characters stay in an internal buffer that can be viewed via Tools->ROV.

    Cb1 offers you a very robust solution using two TIMER modules. As the input signal frequency increases to the point where the high phase of the input is less than the interrupt latency time plus the time to execute TimerValueGet then the one TIMER solution will fail because before the CPU is able to read the captured time value inside the ISR, the current time register is already overwritten by the next edge.
  • Thanks for the recognition/agreement Charles - appreciated.       And again - never/ever is poster's "need" for added complexity - presented w/their request!

    May it be noted that it is not (just) signal's frequency which "breaks" the single Timer attempt - in reality it is the "Diminished Duty Cycle" - and even a relatively "low frequency" PWM signal input - if at minimal duty cycle - will cause the unwanted "over-write" you so nicely describe & detail...

    Posters should be advised to, "Accomplish the Mission" - first and only!      Later - should anyone (really) care - one can optimize - spin their development wheels.    (yet that is AFTER we've delivered - and been PAID!)

  • Hi All, Finally i got output but i can't able get overflow interrupt(timeout) from wtimer 0, and also i am not able to disable a interrupt in handler. Is it timer 0 is used in TI RTOS ? I am keeping code snippet down below.



    void
    Wtimer0IntHandler(void)
    {
    IntFlag = TRUE;
    IntMasterDisable();

    Tvalue[(count++ % SIZE)] = TimerValueGet(WTIMER0_BASE, TIMER_A);
    HWREG((unsigned int)WTIMER0_BASE + 0x50) = 0;
    TimerIntClear(WTIMER0_BASE, TIMER_CAPA_EVENT);
    IntMasterEnable();

    }

    int OverFlowTask()
    {
    System_printf("Hello world\n");
    return 0;
    }


    void initWtimerCcp(void)
    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    GPIOPinTypeTimer(GPIO_PORTC_BASE, GPIO_PIN_4);
    GPIOPinConfigure(GPIO_PC4_WT0CCP0);
    GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

    // Configure WTimer0
    TimerConfigure(WTIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP);
    TimerControlEvent(WTIMER0_BASE, TIMER_A, TIMER_EVENT_BOTH_EDGES);
    TimerIntEnable(WTIMER0_BASE, TIMER_CAPA_EVENT);

    TimerLoadSet(WTIMER0_BASE, TIMER_A, -1);
    TimerPrescaleSet(WTIMER0_BASE, TIMER_A, 0);


    TimerIntRegister(WTIMER0_BASE, TIMER_A, Wtimer0IntHandler);

    TimerEnable(WTIMER0_BASE, TIMER_A);



    }


    /*
    * ======== main ========
    */
    int main(void)
    {
    //GPIO_write(Board_LED0, Board_LED_OFF);
    //GPIO_write(Board_LED1, Board_LED_OFF);
    //GPIO_write(Board_LED2, Board_LED_OFF);


    /* Call board init functions */
    Board_initGeneral();
    Board_initGPIO();

    SysCtlClockSet( SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);

    initWtimerCcp();

    BIOS_start();

    return (0);
    }
  • While you've "Awarded, "This Resolved my issue" status to posts by vendor's Charles - and myself - you continue, "Locked Onto" the (proven discredited) "One and ONLY One Timermethod of problem attack.

    Still - there is no explanation as to, "Why you've "locked onto" this vastly more difficult - and performance limiting - approach!       Just because something, "May be done - does not suggest that such, "Should be done!"     (when resources ARE plentiful - and when the alternate "way" adds, "great & unnecessary time & effort..."

    The "TWO TIMER APPROACH" (AGAIN) proves far easier to implement - is impervious to the challenge of, "Very small Duty Cycles" (which exceed the capability of your "One Timer approach") - and saves (endless) "wear & tear" upon (both) yourself and your "hapless forum helper crüe!"      (is that Charles - carrying an, "On Strike" sign?)

  • Based on the TI-RTOS cfg file the build will will pick the first timer ( normally TIMER0) that is available for the OS tick generation. However, if user specifically used TIMER0 by using timer_create or timer_construct API then the build process will look for the next available timer modules such as TIMER1. Here we are using the timers managed and understood by the kernel.

    In your case you are calling out TIMER0 using TivaWare. You are having a mixed used of TI-RTOS and TivaWare. This can lead to problem as the kernel does not know the TIMER0 is being used directly by the user application. All timing operations will be messed up.If you try to plug in an interrupt and use driverlib’s interrupt.c instead of Hwi_create (or construct), the vector table will get whacked. This will probably lead to an exception.

    With all that said, change your timer to TIMER1 in TivaWare or use the TI-RTOS's API to create the timers you want. I will suggest you to also try create your TIMER0 program in a non-TI-RTOS environment if you want to use the TivaWare to get a fell of how timer module works.
  • May the record show that "this reporter" is setting a, "Non RTOS" - Non MCU - TIMER - to record "DAYS LOST" by the continuing pursuit of an overly complex and "Proven Duty-Cycle Limited" (thus much inferior/doomed) approach.