TMR1 interrupt seems to trigger too early

Author
wolfi_b
New Member
  • Total Posts : 2
  • Reward points : 0
  • Joined: 2018/02/11 11:49:05
  • Location: 0
  • Status: offline
2018/02/13 00:29:45 (permalink)
0

TMR1 interrupt seems to trigger too early

Hi,
 
I’m trying to implement speed measurement with the compare-module of a PIC 18F24K22. To extend the measurement range I’m taking into account the overflows of Timer1 and add them to the measurement result (see calcualtion of period variable):
 
    
//Initialization:
    //Timer1 config - CCP2 capture
    TMR1CS1 = 0; //Internal clock (Fosc/4)
    TMR1CS0 = 0;
    T1CKPS1 = 1; //11 = 1:8 Prescale value
    T1CKPS0 = 1;
    TMR1GE = 0; //Timer1 counts regardless of Timer1 gate function
    TMR1ON = 1; //Enable Timer1
 
    //CCP2 config - engine speed measurement
    CCP2M3 = 0; //0100 = Capture mode: every falling edge
    CCP2M2 = 1;
    CCP2M1 = 0;
    CCP2M0 = 0;
    C2TSEL1 = 0; //00 = CCP1 - Capture modes use Timer1
    C2TSEL0 = 0;
 
    //interrupts
    IPEN = 0; //Disable priority levels on interrupts
    TMR1IE = 1; //Enables the TMR1 overflow interrupt
    CCP2IE = 1; //Enable CCP2 interrupt
    PEIE = 1; //Enables all unmasked peripheral interrupts
    GIE = 1; //Enables all unmasked interrupts
 
//ISR:
void interrupt myisr(void) {
    static unsigned int t1_overflow_count = 0;

    if (TMR1IE && TMR1IF) { //TMR1 overflow interrupt
        t1_overflow_count ++;       
        TMR1IF = 0; //reset interrupt
    }
    if (CCP2IE && CCP2IF) { //CCP2 interrupt - rev counter
        unsigned int ccpr2 = 0;
        static unsigned int ccpr2_last = 0;
        unsigned long period = 0;

#ifdef DEBUG
        debug_t1_overflow_count = t1_overflow_count;
#endif
        
        ccpr2 = ((unsigned int) CCPR2H << 8) | CCPR2L;      //read capture value
        if(ccpr2 < ccpr2_last)    //if new value is smaller then old value
            t1_overflow_count--;                            //ignore (first) overflow
        
        period = (unsigned long)t1_overflow_count * 0xFFFF + (unsigned int)(ccpr2 - ccpr2_last);

#ifdef DEBUG
        debug_period = period;
        debug_ccpr2h = CCPR2H;
        debug_ccpr2l = CCPR2L;
        debug_ccpr2 = ccpr2;
        debug_ccpr2_last = ccpr2_last;
#endif
        ccpr2_last = ccpr2;
        
        calculate_and_set_x(period); //calculate engine speed and update process variable
            
        t1_overflow_count = 0;
        
        CCP2IF = 0; //reset interrupt
    }

 
This approach works good most of the time, but every few minutes it happens that ccpr2 is bigger than ccpr2_last (Timer1 overflow can not have happened) but Timer1 interrupt has triggered (t1_overflow_count is 1). At the next measurment the Timer1 interrupt is missing. It looks like the Timer1 interrupt is triggerd too early.
Below I have attached some debug output examples:
 

ccpr2_last  ccpr2   overlow_count  period
30716        56360  0                    25644         --> correct example
---------------------------------------------------------------------------------------------------------------
32359        65383  1                    98559         --> Timer1 overflow too early
65383        30716  0                    4294867094 --> missing Timer1 overflow
---------------------------------------------------------------------------------------------------------------
32296        65533  1                    98772         --> Timer1 overflow too early
65533        30078  0                    4294866306 --> missing Timer1 overflow
---------------------------------------------------------------------------------------------------------------
33159        65535  1                    97911         --> Timer1 overflow too early
65535        30165  0                    4294866391 --> missing Timer1 overflow

 
What could be the reason?
 
Kind regards, Wolfgang
#1

3 Replies Related Threads

    mbrowning
    Just a Member
    • Total Posts : 790
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: online
    Re: TMR1 interrupt seems to trigger too early 2018/02/13 10:35:49 (permalink)
    0
    Interrupt Latency.
    If capture occurs when T1 is close to 0xffff and about to rollover, the rollover happens after the capture but before the ISR checks TMR1IF. So your ISR counts a rollover when capture happened before rollover.
     
    Why bother checking for rollovers anyway? Just do 16bit arithmetic and the 16bit result will be correct regardless of rollovers.
     
    edit -
    Plus your math is wrong anyway.
    period = t1_overflow_count * 0xFFFF + (ccpr2 - ccpr2_last);
    0xffff should be 0x10000.
    post edited by mbrowning - 2018/02/13 10:42:28

    Can't remember. I've slept since then - Mark
    #2
    wolfi_b
    New Member
    • Total Posts : 2
    • Reward points : 0
    • Joined: 2018/02/11 11:49:05
    • Location: 0
    • Status: offline
    Re: TMR1 interrupt seems to trigger too early 2018/02/13 12:26:26 (permalink)
    0
    mbrowning
    Interrupt Latency.
    If capture occurs when T1 is close to 0xffff and about to rollover, the rollover happens after the capture but before the ISR checks TMR1IF. So your ISR counts a rollover when capture happened before rollover.

    The smallest value of ccpr2_last I have seen when the problem has occured was 65275.
    2^16-65275=261 T1 counts left until rollover
    T1 prescaler = 8
    261 * 8 = 2088 instruction cycles
    2088 instruction cycles interrupt latency? Can that be true?
     
    mbrowning 
    Why bother checking for rollovers anyway? Just do 16bit arithmetic and the 16bit result will be correct regardless of rollovers.

    So I can measure durations which are longer than 2^16 counts
     
    mbrowning 
    edit -
    Plus your math is wrong anyway.
    period = t1_overflow_count * 0xFFFF + (ccpr2 - ccpr2_last);
    0xffff should be 0x10000.

    I'm afraid that you are rightLoL: LoL
    #3
    mbrowning
    Just a Member
    • Total Posts : 790
    • Reward points : 0
    • Joined: 2005/03/16 14:32:56
    • Location: Melbourne, FL
    • Status: online
    Re: TMR1 interrupt seems to trigger too early 2018/02/14 11:14:09 (permalink)
    0
    Your ISR compiled with XC8 in free mode has close to 50 cycles latency due to all the context saving, but that is a far cry from 2000. But even a small latency will eventually cause the problem you are seeing, so you need to have some mechanism to handle it.
     
    If the code you haven't shown is disabling interrupts for a time, that could exacerbate this. Or writing/erasing Flash (as peripherals continue while code execution freezes) .
     
     

    Can't remember. I've slept since then - Mark
    #4
    Jump to:
    © 2018 APG vNext Commercial Version 4.5