• AVR Freaks

Hot!incoherent Timer0 period

Author
Arnaud42
New Member
  • Total Posts : 24
  • Reward points : 0
  • Joined: 2017/01/09 01:31:04
  • Location: 0
  • Status: offline
2019/06/20 00:30:45 (permalink)
0

incoherent Timer0 period

Hi all,
 
Using a PIC16F785, i have trouble with the timer 0.
The pic runs with its internal oscilator at 8Mhz => instruction period is 2.00 Mhz (measured on output ClkOut). 
I try to configure the timer0 to generate a 100µs interrupt : 
void Init_Timer0 (void) {
    
    OPTION_REGbits.T0CS = 0; // Clock internal
    OPTION_REGbits.T0SE = 0; // without prescaler

    TMR0 = TMR0_PERIOD; // value is 0xFF - 200 cycles (timer period) - 2 blanc cycles => 53
    
    INTCONbits.GIE = 1; // general interrupt
    INTCONbits.PEIE = 1; // low prio interrupt
    INTCONbits.T0IF = 0; // RAZ flag
    INTCONbits.T0IE = 1; // allowed IT  
}
 
 
An interrupt is supposed to occurs each 100µs : 
 
void interrupt ISR (void) { 
    if (INTCONbits.T0IF == 1) {
       TMR0 = TMR0_PERIOD;
       
       if (Var == 0) {
           Var = 1;
           LED1 = LED_ON;
       } else {
           Var= 0;
           LED1 = LED_OFF;
       }
    INTCONbits.TMR0IF = 0; // clear interrupt flag
    }
}

 I check frequency on LED1 with oscilloscope : 113.2µs (100µs expected) => but why ? 
 
Thanks 
#1

9 Replies Related Threads

    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11425
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 01:06:42 (permalink)
    +1 (1)
    If you want a periodic interrupt, use TMR2.  That's what it's made for.
    #2
    Arnaud42
    New Member
    • Total Posts : 24
    • Reward points : 0
    • Joined: 2017/01/09 01:31:04
    • Location: 0
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 01:43:32 (permalink)
    0
    Perfect, it works fine with TMR2
     
    thanks  
    #3
    ric
    Super Member
    • Total Posts : 24593
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 02:08:50 (permalink)
    +1 (1)
    As jtemples suggested, TMR2 is a better choice.
    The main problem with your first attempt is that it does not allow for the code that is executed on entry to the interrupt service routine (which is quite a few instructions in these old "non-enhanced" PIC16F parts.)
    Fortunately there is an easy way to automatically allow for it, by changing
           TMR0 = TMR0_PERIOD; 

    to
           TMR0 += TMR0_PERIOD;

     
    It is a useful mental exercise to work out for yourself why this works.

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #4
    pcbbc
    Super Member
    • Total Posts : 1381
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: online
    Re: incoherent Timer0 period 2019/06/20 02:13:21 (permalink)
    +1 (1)
    Arnaud42 I check frequency on LED1 with oscilloscope: 113.2µs (100µs expected) => but why?

    To explicitly answer that question (so you and others know for next time):
    Because there is an overhead in calling your ISR before you get to the line of code which resets TMR0.  Approximately 26 instructions, given the code currently produced by the compiler, it would seem.
     
    You could manually adjust for that, but you cannot guarantee it will always be 26 instructions:
    a) There may be blocks of your mainline code that disable interrupts;
    b) If you have other interrupts enabled, those may be being serviced when TMR0 rolls over;
    c) You, or the compiler, may add additional code to your ISR before you check T0IF.
    Any of these will add further latency to servicing the T0 interrupt.
     
    Another option is to read and adjust the TMR0 value so you take into account the actual latency:
    TMR0 = TMR0 - TMR0_CYCLES;

     
    But as others have stated, by far the best/easiest solution is to use TMR2 for periodic interrupts as you can latch the restart value.
    #5
    acharnley
    Super Member
    • Total Posts : 403
    • Reward points : 0
    • Joined: 2016/05/01 06:51:28
    • Location: 0
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 02:50:51 (permalink)
    +1 (1)
    If you use a newer PIC there are loads of options available with zero code.

    You're after a 50% duty so:

    1. A timer or any clk source inc pin in, and a CLC in J/K flip-flop mode.
    2. NCO (FOSC 24 bit)
    3. Timer 2/4/6 + PWM/CCP (FOSC/4)
    4. CLKREF (31000/128)
    #6
    pcbbc
    Super Member
    • Total Posts : 1381
    • Reward points : 0
    • Joined: 2014/03/27 07:04:41
    • Location: 0
    • Status: online
    Re: incoherent Timer0 period 2019/06/20 03:55:59 (permalink)
    +1 (1)
    acharnleyIf you use a newer PIC there are loads of options available with zero code.

    You're assuming the OPs need for an interrupt is to generate a square wave output.
    In all likelihood the "LED flash" is just for test purposes so the OP can measure the frequency and confirm the interrupt rate.  (You're not going to see a 100us flash).
    PIC16F785 has PWM module available if needed.  Although I agree a more modern PIC would have more features and lower price.
    #7
    1and0
    Access is Denied
    • Total Posts : 9989
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 06:31:11 (permalink)
    +1 (1)
    Arnaud42
    Using a PIC16F785, i have trouble with the timer 0.
    The pic runs with its internal oscilator at 8Mhz => instruction period is 2.00 Mhz (measured on output ClkOut). 
    I try to configure the timer0 to generate a 100µs interrupt : 

        TMR0 = TMR0_PERIOD; // value is 0xFF - 200 cycles (timer period) - 2 blanc cycles => 53
     

    First, Timer0 overflows from 0xFF to 0x00 so the subtraction should be from 0x100, not 0xFF. Second, the "period" value should account for the two instruction cycle delay when TMR0 is written and one instruction cycle for the write itself; that is,
    #define TMR0_PERIOD (256 - 200 + 3)

    which is a value of 59, not 53.  Then in your ISR, adjust the TMR0 register as shown by Ric.
    #8
    acharnley
    Super Member
    • Total Posts : 403
    • Reward points : 0
    • Joined: 2016/05/01 06:51:28
    • Location: 0
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 14:26:54 (permalink)
    0
    pcbbc
    acharnleyIf you use a newer PIC there are loads of options available with zero code.

    You're assuming the OPs need for an interrupt is to generate a square wave output.
    In all likelihood the "LED flash" is just for test purposes so the OP can measure the frequency and confirm the interrupt rate.  (You're not going to see a 100us flash).
    PIC16F785 has PWM module available if needed.  Although I agree a more modern PIC would have more features and lower price.



    True, I just assumed since he couldn't see 100us the purpose was to dim it via PWM. 
    #9
    1and0
    Access is Denied
    • Total Posts : 9989
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: incoherent Timer0 period 2019/06/20 20:53:54 (permalink)
    0
    Arnaud42
    void interrupt ISR (void) { 
     
        if (INTCONbits.T0IF == 1) {
           TMR0 = TMR0_PERIOD;
           
           if (Var == 0) {
               Var = 1;
               LED1 = LED_ON;
           } else {
               Var= 0;
               LED1 = LED_OFF;
           }
        INTCONbits.TMR0IF = 0; // clear interrupt flag
        }
    }

     I check frequency on LED1 with oscilloscope : 113.2µs (100µs expected) => but why ? 

    Your ISR does not toggle LED1 evenly; i.e. it's not a 50/50 square wave. Use this instead
    #define TMR0_PERIOD (256 - 200 + 3)
    void interrupt ISR (void) { 
        INTCONbits.TMR0IF = 0; // clear interrupt flag
        TMR0 += TMR0_PERIOD; // adjust TMR0
        LED1 ^= 1; // toggle LED
    }

    #10
    Jump to:
    © 2019 APG vNext Commercial Version 4.5