PIC18F452 clock not inaccurate

Discussion in 'Embedded Systems and Microcontrollers' started by ecka333, Oct 31, 2012.

  1. ecka333

    Thread Starter Active Member

    Oct 1, 2009
    76
    0
    Made project with pic18f452 microcontroller. Timer1 module used as a real time clock with 32768kHz crystal and 33pF caps connected to microcontroller's Timer1 oscillator pins. Problem is that clock is not accurate, it makes about 4sec/day delay. Changed crystal, but this didnt helped. Tried to reroute PCB, this also not helped. I suspect maybe my clock routine is wrong? Here it is:
    Code ( (Unknown Language)):
    1.  
    2. if(PIR1.TMR1IF==1)
    3.         {
    4.         TMR1H=252;
    5.         if(FourthHertz<3){FourthHertz++; Blinker=1;} //count to four, that is to 1 second and invert variable state for text blinking
    6.         else
    7.             {
    8.             FourthHertz=0; Blinker=0;
    9.                
    10.             if(Seconds<59){Seconds++;}
    11.             else
    12.                 {
    13.                 Seconds=0;
    14.                 if(Minutes<59){Minutes++;}
    15.                 else
    16.                     {
    17.                     Minutes=0;
    18.                     if(Hours<23){Hours++;}
    19.                     else{Hours=0; if(Day<6){Day++;} else {Day=0;}}
    20.                     }
    21.                 }  
    22.             }
    23.         PIR1.TMR1IF=0; //clear timer1 interrupt flag
    24.         }
    25.  
    Can clock inaccuracy occur due to permanent writing to TMR1h register? (TMR1L register is never changed.) Any ideas and suggestions?
     
    Last edited: Oct 31, 2012
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Well, the fact that you are using C will incur timing errors. Since the pic is a risc processor, each instruction is executed in a predetermined time... With the exception of branching statements. Unfortunately, a simple line of code in C will not necessarily correlate to a single risc instruction.

    I'd recommend anything requiring a very precise timing to be in assembly.

    Would it be so bad to simply compensate for the drift , our does it have to be as accurate as possible?
     
  3. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    ...also, writing to the timer registers causes it to skip a few clock cycles, though I don't think that could account for a 4 sec/day offset...
     
  4. JohnInTX

    Moderator

    Jun 26, 2012
    2,340
    1,022
    4 sec/day is a .0046% error. Is your XTAL / osc running at the exact speed? It doesn't have to be too far off to accumulate this amount of error over 24 hours.

    Are you sure that the compiler runs timer 1 in the 8 bit write mode and is not writing 16 bits? T1CON bit 7 controls that..

    Instead of writing to timer 1 each time, I would set it up using CCP1 using the special event trigger to reset TMR1 each time it matches the CCP count. (Instead of TMR1IF you'll use CCP1IF). That way you don't have any worries about problems writing to your time base and you get much more time to service the IRQ.

    Finally, be sure to check the PICs errata to see if it has any issues with TMR1. Lots do and the '452 is an old chip.

    TMR1 Errata for the '452
     
    Last edited: Oct 31, 2012
  5. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,866
    988
    Your subject line says PIC18F452 clock not inaccurate. :)

    Most RTCs have the ability to be adjusted. Check your datasheet.
     
  6. MrChips

    Moderator

    Oct 2, 2009
    12,420
    3,355
    4sec/day is about 40 parts per 1,000,000.
    You should be able to achieve about 1-5 parts per million with a crystal.
    Replace the capacitor at T1OSI with a 56pF variable trim capacitor.
     
  7. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Here is a the ISR I made for a clock once. The trick is to start timer 1 at 0x8000. Then using a clock crystal. That is done by writing 0x80 to TMR1H in the ISR. But you are writing 252 to the register. That I do not understand

    Code ( (Unknown Language)):
    1. static void interrupt
    2. isr(void)   // Here is interrupt function - the name is
    3.     // unimportant.
    4. {
    5.  if(TMR1IF)
    6.   {// Was this a timer overflow?
    7.       TMR1IF=0;//Clear interrupt flag, ready for next
    8.    TMR1H=0x80;
    9.         //If we set TMR1 to start at 0x8000 (32768), the TMR1 will overflow every 1 second
    10.      timer_tick=1;
    11.   }//we are done here
    12. }
     
  8. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    You should not need to write to TMR1. A 32768 Hz xtal means the timer overflows at 65536 ticks which is exactly 2 seconds.

    If you need a 1 second event, just check for when bit7 of TMR1H changes, that change (toggle) occurs exactly every second.

    If you write to TMR1 you incur a delay, so the time will not be accurate. You need to leave TMR1 free running and just read it.

    Is there any reason you must use TMR1 and a 32768 Hz xtal for the clock? Why not just derive the clock from the main PIC xtal?
     
  9. ecka333

    Thread Starter Active Member

    Oct 1, 2009
    76
    0
    My timer1 register is configured once: T1CON=0b0011111111; that means prescaler is 1:8; register Read/Write of Timer1 in two 8-bit operations. With these settings i get 4Hz frequency. It is used for time counting (seconds, minutes, hours) and numbers blinking in LCD, when they are edited.
    Yesterday changed Timer1 configuration: prescaler set to 1, deleted TMR1H register preload in ISR; T1CON=0b00001111. So now interrupt occurs at 0,5Hz, or every two seconds. But result remained the same: clock is slow. Today i will buy new crystal and will try it.
     
  10. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    In a typical clock application like this . You can write to the TMR1H register before TMR1L roll over with no loss of accuracy. But in general it is kind of a dodgy approach I shall admit that
     
  11. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    I don't believe that is right T06afre, on which PIC? From what I remember writing to TMR1 means it does not increment during that one instruction (because it is being written instead of incrementing when the instruction takes place).

    If TMR1 is prescaled at 1:1 than each instruction is 1 TMR1 count, so writing to TMR1 once every 65536 counts means it will take 65536+1 counts to roll, giving a time error of 1 part in 65536.

    If I remebered that right your code writes to the TMR1 every 32768 ticks so will produce a total period of 32768+1. That would make a real time clock error of about 2.6 seconds a day.
     
  12. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    I think I used the 16f690. And set it up to work in Asynchronous Counter Mode. The external clock input is not synchronized. The timer increments asynchronously to the internal phase clocks. The system used the internal oscillator set to 4MHz. So it was not driven by the watch crystal.
     
  13. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    I still call that one. :) I'll try to get some time tomorrow to do tests and get back to you.

    I have a strong memory that writing to TMR1H inhibits TMR1 for that clock cycle, even on internal synchronous clock.
     
  14. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Setting bit 15 (TMR1H.7) on a free running TMR1 module shortly after a TMR1 overflow, when using the Timer 1 oscillator and 32768 Hz crystal, is a time tested method for generating a one Hertz TMR1 overflow flag.

    I haven't tried this yet on an 18F device and so I'm guessing that you would need to clear the RD16 control bit in T1CON to allow updating TMR1H without touching TMR1L.

    Regards...
     
  15. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    I can not find any sign of that in section 12 in this document(Mid-Range MCU Family
    Reference Manual) http://ww1.microchip.com/downloads/en/devicedoc/33023a.pdf
    The method of changing TMR1H is also suggest as a solution in AN580. And for sure used in AN649. And the latter manual state
     
  16. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    A couple thoughts, if I may...

    (1) The 33 pf caps may be a bit high. I use 22 pf caps with good results.
    (2) Writing either timer register while using prescaler other than 1:1 is a "no no".

    Regards...
     
  17. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Thank you T06afre and MMcLaren for correcting me, it's appreciated (and saved me doing a silly test). ;) As a general rule I don't write to timers to generate periods.

    As T06afre said why set TMR1H to 252? That gives 4 rolls of TMR1L before the next int, which gives an int period of 1024 TMR1 ticks or 1024/32768 seconds, which is 0.03125 seconds per interrupt.

    That is 8 times faster than the OP's desired "quarter second" and would imply he is using a TMR1 prescaler of 8:1?

    I think MMcLaren hit it on the head, it's error caused by writing to TMR1 when the TMR1 prescaler is selected... (Another good reason not to be in the habit of writing to timers).
     
  18. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Well, it would be easy enough to poll TMR1H in a loop in order to extract "one time" bit changes for "one time" operations. For example, the following code uses a state latch and simple logic to refresh 'delta' with "one time" bit changes each loop;

    Code ( (Unknown Language)):
    1.  
    2.         delta = tmr1h ^ latch;     // changes, hi or lo
    3.         latch ^= delta;            // update state latch
    4.  
    Since 'delta' is refreshed each time through the loop, delta.7 will be a '1' only during one loop at one second intervals. Simply test delta.7 each loop and update your RTC variables when the bit is a '1'. Use delta.6 for 1/2 second (2 Hz) "one time" intervals, or delta.5 for 1/4 second (4 Hz) "one time" intervals. You could, for example, use delta.6 to toggle the colon LEDs on a display twice per second to flash the colon LEDs at a 1 Hz (one second) rate.

    Code ( (Unknown Language)):
    1.  
    2.         if(delta.6)                // if new 1/2 second interval
    3.           colon ^= 1;              // toggle colon LEDs
    4.  
    Of course the 'latch' variable reflects the actual "real time" state of TMR1H and so 'latch' bits could be used directly for "real time" operations instead of "one time" operations. For example, flashing the colon LEDs once per second, as in the previous example, could also be accomplished by simply copying the 1/2 second latch.6 bit to the colon LED pin during each loop;

    Code ( (Unknown Language)):
    1.  
    2.     /*
    3.      *  flash colon LEDs once per second
    4.      */
    5.         colon = latch.6;           // real-time 1/2 second bit
    6.  
    Anyway, as Roman suggested, there are plenty of ways to get the intervals you may need without writing timer registers, if writing timer registers is an issue.

    Cheerful regards, Mike
     
    Last edited: Nov 5, 2012
Loading...