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.

TM4C1231H6PZ: Capture and Compare Timer Calculating Zero On Time

Part Number: TM4C1231H6PZ

Hello,

I am calculating period and on time for an input signal using capture and compare timers. I have two inputs that happen to be connected to WT4CCP0 and WT4CCP1. I have both channels monitoring input signals at the same time. WT4CCP0 calculates the signal parameters without error. WT4CCP1 does well for the most part, but periodically will calculate a 0 on time. I have the on time calculated in the timer ISR. I have attached this code. Can anyone see any issues with the code that may produce this error? 

void Wide_Timer_4_subtimer_B_ISR(void) {

    ROM_TimerIntClear(WTIMER4_BASE, TIMER_CAPB_EVENT);

    IPC_Properties[6].IPC_Edge = ROM_GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_5) >> 5;

    if(IPC_Properties[6].IPC_Edge == 1) {
        IPC_Properties[6].IPC_TimerPrev = IPC_Properties[6].IPC_Timer;
        IPC_Properties[6].IPC_Timer = ROM_TimerValueGet(WTIMER4_BASE, TIMER_B);
    }
    else {
    	IPC_Properties[6].IPC_TimerFalling = ROM_TimerValueGet(WTIMER4_BASE, TIMER_B);
    	IPC_Properties[6].IPC_OnTime = IPC_Properties[6].IPC_TimerFalling - IPC_Properties[6].IPC_Timer;
    }

    TMR_StartExpirationTimerMS(&IPC_Properties[6].IPC_Shutoff, 1000);

    ROM_TimerEnable(WTIMER4_BASE, IPC_Properties[6].IPC_TimerConfig);
}

void Wide_Timer_4_subtimer_A_ISR(void) {

    ROM_TimerIntClear(WTIMER4_BASE, TIMER_CAPA_EVENT);

    IPC_Properties[8].IPC_Edge = ROM_GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4) >> 4;

    if(IPC_Properties[8].IPC_Edge == 1) {
    	IPC_Properties[8].IPC_TimerPrev = IPC_Properties[8].IPC_Timer;
        IPC_Properties[8].IPC_Timer = ROM_TimerValueGet(WTIMER4_BASE, TIMER_A);
    }
    else {
    	IPC_Properties[8].IPC_TimerFalling = ROM_TimerValueGet(WTIMER4_BASE, TIMER_A);
    	IPC_Properties[8].IPC_OnTime = IPC_Properties[8].IPC_TimerFalling - IPC_Properties[8].IPC_Timer;
    }

    TMR_StartExpirationTimerMS(&IPC_Properties[8].IPC_Shutoff, 1000);


    ROM_TimerEnable(WTIMER4_BASE, IPC_Properties[5].IPC_TimerConfig);
}

  • Your code is properly paralleled between sub-timers A & B.     As you report "proper performance" most of the time - this appears (other) than a coding issue.

    As a simple test - does the "issue" move should you "reverse" input signals?     That proves somewhat instructive - does it not?

    Untold is the frequency - and potential overlap - of these signals.     is it possible that such signal "overlap" - combined w/individual interrupt priorities and/or response times - proves responsible?

    You may "cross-connect" one signal source - such that both of your Timer inputs are "commonly driven" - and observe results.

    Perhaps my "best" diagnostic thought - route the channel w/issue to a 2nd (independent) Timer (drive 2 timers via the same input signal) - such that an additional interrupt triggers - and note if the issue flows to that added timer...

  • First Kilometer,

    Let me make a few observations to your code and strategy, maybe they will be of help:

    - Avoid clearing specific interrupt triggers, like TimerIntClear(WTIMER4_BASE, TIMER_CAPA_EVENT); - as your code grow or when you import that into other projects, you will eventually enable other triggers, and your code will loop forever into this timer ISR. Adopt as a habit to read all the interrupt flags into a variable, and then erase them all.

    - You are reading GPIOPin inside the interrupt. What happens if your pin flips during the interval in which your measured transition happened, and when you make this reading? Something will go ballistic. Mind the fact that other interrupts could have been serviced when the transition happened, and your code will not reach that point until several cycles later.

    - Did you ensure that the load of your timer is enough to measure your event's cycle? If you are simply using the "normal" 16 bits, that's quite fast...

    - Your ISR is short, but if you could make it even shorter, that's better (so not to impact other ISR's): simply capture the values into variables, and set a flag to evaluate such values somewhere inside your main loop. The less you do inside an ISR, the better.

    A much more complicated but accurate way of doing this measurement is by using DMA. You configure your DMA to transfer a timer count into a known memory array every time your signal flips. And after so many transitions, you run a routine to do this sort of difference evaluation that you are doing. If you don't have too many channels taken, you can actually configure TWO DMA transfers for one transition: one transfers the timer counter, the other transfers the pin level, so that in the end you have a table sort like this:

    14200 1
    14300 0
    17150 1
    17250 0

    Regards,

    Bruno