Shop OBEX P1 Docs P2 Docs Learn Events
Keeping time comments and solutions ? — Parallax Forums

Keeping time comments and solutions ?

Zap-oZap-o Posts: 452
edited 2009-08-26 18:26 in Propeller 1
I want to keep time and try to keep it for as long as possible. I am using the code below and quite frankly became surprised when it started to drift after about 90 minutes. My prop is hooked up and running at 80Mhz with a precision x-tal that is rated at 50ppm. Nevertheless, shouldn't I get better out of it? I am updating another cog every second that sends it to my PC.
{
 Clock object used for keeping track of time in seconds 
}

VAR
        Long cog
    Long Second    
    Long Stack[noparse][[/noparse] 25 ]
       
          
Pub Start  : okay  
  stop
  okay := cog := cognew(main, @stack) + 1


PUB stop
'' Stop driver - frees a cog

  IF cog
    cogstop(cog~ - 1)
  
PUB Main 
  Second~
  'seconds in a year 31,556,926    2^32 = 4294967296 / 2 = 2,147,483,648
  Repeat
    Waitcnt(clkfreq / 1 + Cnt) 'wait for .1 seconds 
    Second ++
                                                          
Pub Seconds 




Your comments are greatly wanted. tongue.gif
«1

Comments

  • CounterRotatingPropsCounterRotatingProps Posts: 1,132
    edited 2009-08-12 20:53
    Hi Zap-o

    you've got to account for the lost cycles in the repeat, save the clkfreq and count outside the repeat first.

    - H

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-12 20:55
    The overhead of the "Second ++" and the "Repeat" will accumulate. It's much better to do something like:
    result := cnt
    repeat
       waitcnt( result += clkfreq )
       Second++
    
  • Zap-oZap-o Posts: 452
    edited 2009-08-12 21:14
    Man the more I ask question the more frighting it becomes. Its clear that many of you have programming skills I never imagined.

    CounterRotatingProps - I am confused by what you are saying here "save the clkfreq and count outside the repeat first." I mean why will it matter? Sorry if it seems a dumb question

    Mike - I could simply copy and paste this and run it, but I have to ask. Why is this better and shouldn't i remove the Second++ if you are using "Result"?
  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-12 21:24
    1) I'm just using "result" as a temporary counter. You could use any long variable.

    2) "Second" is something you're using to keep track of elapsed seconds. I was using "result" to keep track of clock ticks for the next second interval. It wraps around roughly every 50 seconds, so isn't very useful beyond that.

    3) The reason this is better is that the execution time of the "Second++" statement and the "repeat" statement overlaps the one second interval rather than extending it as it did in your code. It's not a big difference, but it does accumulate over time. There is a little discussion on this in the Spin part of the Propeller Manual in the section on the WAITCNT statement.
  • Zap-oZap-o Posts: 452
    edited 2009-08-13 14:56
    Thanks for the explanation. I think I understand. As a side note it ran better with your suggestion. It was improved but still not good enough. Is this something Ill have to deal with or is there a better approach?

    Is there a better way to keep time?
  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-13 15:19
    50ppm error is pretty standard for ordinary crystals. It's not a precision crystal at all. There are several sources of error, all of which can be compensated for. There's the accuracy of the crystal ... the difference between what's stamped on the top and what frequency it actually oscillates at. That's fixed and you can measure that by comparing the crystal frequency over a period of time to some frequency standard (like an atomic clock). Once you know that, you can adjust the _CLKFREQ or _XINFREQ value to match the actual crystal frequency (or its fixed multiple).

    There's the thermal variation. The crystal expands and contracts with changes in temperature and that changes its frequency. You can plot the frequency against the ambient temperature over time and get an adjustment factor that you can apply to the value you use for a 1 second pause.

    Lastly, there's aging. Crystals go through a long period of aging after manufacture where their frequency drifts slowly as they operate. This is predictable and can be adjusted for. The crystal datasheet will generally have that information as well as information on thermal drift.

    If you want accurate timekeeping over a long period of time, you need some kind of thermally compensated real time clock that's calibrated (adjusted for crystal accuracy). You can use the Propeller, calibrate its crystal against an atomic clock or frequency standard, and include a digital thermometer so it can compensate for the ambient temperature or you can buy a real time clock.

    Dallas makes a temperature compensated 32KHz oscillator (www.maxim-ic.com/quick_view2.cfm/qv_pk/2940/t/al) that you could either use to feed a real time clock or directly input to a Propeller I/O pin for a time standard.
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 01:36
    I am under the impression that the propeller can not keep time in seconds for more than 3 hours. I am basing this on the simplest code I could write while running in its own cog [noparse][[/noparse]posted above.] I find this disturbing and unfortunate seeing how other micros can keep time for days.

    You may say that it is my xtal, but running a 20PPM xtal it should last a few days in my calculations. You may say that its the temperature causing the xtal to sway, but I contained the propeller with xtal in a temperature static room that is PID controlled.

    Has anyone done better or find this unfortunate as well? I am open for suggestions and wish to brighten my understanding of the propeller.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 01:53
    Zap-o said...
    I am under the impression that the propeller can not keep time in seconds for more than 3 hours.
    It would be wrong to blame the Propeller for this. It is no less capable than any other micro of keeping accurate time under identical conditions. You will need to cast a much wider net that encircles physics and, perhaps, a still-errant program. Can you post your entire current Spin program, please, and let us take another look?

    -Phil
  • HollyMinkowskiHollyMinkowski Posts: 1,398
    edited 2009-08-25 02:10
    If your project uses an ac source for power supply couldn't you just read the
    ac cycles using something like an opto coupler? They take great care to keep
    that ac frequency stable enough to keep time. Or, you could do the timing just
    as you are and every hour or whatever check a counter that you have ticking by
    from reading the ac freq and then correct the xtal timers reading.... sort of like
    those atomic wall clocks do. Doing it this way would let you keep time through
    a power failure if your device had battery backup...although you might miss an
    update and correction if the power was off for long.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - Some mornings I wake up cranky.....but usually I just let him sleep in -
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 02:49
    The reason i blame the propeller is because the multipule cogs running and timing the shared memory. Also I blame the propeller because of the loose ends. As in using stack space when running a cog. Its like guessing! ^^

    My code is as follows:

    VAR
     
        Long Second, cog    
        Long Stack[noparse][[/noparse] 25 ]
              
    Pub Start  : okay
     
      stop
      okay := cog := cognew(main, @stack) + 1
    
    PUB stop
      IF cog
        cogstop(cog~ - 1)
      
    PUB Main 
    
      Second~
      
      result := cnt
      
      repeat
         waitcnt( result += clkfreq )
         Second++
                                                              
    Pub T_Seconds
    
      return Second
    
    



    Now after some thought I think that writing the code in assembly might help this problem. Of course I have not wrote code in this form yet so excuse the question:

    Maybe you can help, but each line in assembly can be counted as 1 clock cycle or more depending on the operand? I may be able to calculate each line of code and thus this may translate to time the code?

    @ HollyMinkowski
    Nice idea but the electronics is running off a DC supply.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 03:11
    Zap-o,

    Your object looks okay. However, none of the objections you have to the Propeller, including to Spin itself, are valid. The code you've posted should not accumulate any errors. Even being coded in Spin, there is plenty of time between "ticks". 'No timing issues there.

    So let's take a closer look at your hardware. You say you're using a precision crystal, but what kind of crystal (series resonant? parallel resonant? ) and how have you hooked it up? PCB? Solderless breadboard? What drive level are you using? (That will be in your main program, which you should also post.)

    Even if it's an irreconcilable hardware issue, there are ways to work around inaccurate oscillation. For one, you can fudge the _clkfreq value to correspond more closely with the actual oscillation frequency. But let's not go there just yet, unless we're sure it's necessary.

    -Phil

    Post Edited (Phil Pilgrim (PhiPi)) : 8/25/2009 3:17:37 AM GMT
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 03:49
    Phil some questions you ask are over my head. What is series / parallel resonate? Ill Google it after a bit. The xtal is soldered to a PCB board I designed and very close to the propeller. The type of xtal is not something I can answer tonight [noparse][[/noparse]data sheet is at work]. Tomorrow I will have more information. My main program is very very long but the just of it is as follows:

    
    Pub Main 
    
     Current_Time := 3
     TimeKeeper [noparse][[/noparse] 0 ] ~
    
      REPEAT          
            IF (Timer.Seconds == (TimeKeeper [noparse][[/noparse] 0 ] + Current_Time))
                                    TimeKeeper [noparse][[/noparse] 0 ] := Timer.Seconds   
    
    



    Where Timer.Seconds is in the other cog. I posted up above --^

    This code sends the "Tick Tock" every 3 seconds. I have a PC program that records the time and compares it from the propeller. If the propeller is off the PC program shows it and shows how much over time.

    By the way; thanks for taking time to help and to teach.
    smile.gif
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 04:03
    Zap-o,

    What are your _clkmode and _clkfreq constants? What is the nominal frequency of your crystal? Are any other components connected to your crystal, other than the Prop pins?

    Regarding the crystal type, a part number and datasheet when you get to work tomorrow will be very helpful.

    -Phil
  • Mike GreenMike Green Posts: 23,101
    edited 2009-08-25 04:03
    I assume your Timer.Seconds is the same as T_Seconds in what you posted earlier.

    You have a potential problem with what you posted above. In particular, your Timer Main routine is running in another cog while the above Main program is running. You have two calls to Timer.Seconds and they can return different answers if your Timer Main routine updates Seconds in between these two calls. Better to have a temporary variable and do:
        IF ((temp := Timer.Seconds) == (TimeKeeper[noparse][[/noparse] 0 ] + Current_Time))
           TimeKeeper[noparse][[/noparse] 0 ] := temp
    
  • Bob Lawrence (VE1RLL)Bob Lawrence (VE1RLL) Posts: 1,720
    edited 2009-08-25 05:03
    Clock
    Author: Jeff Martin (Parallax)

    Provides clock timing functions to:
    * Set clock mode/frequency at run-time using the same clock setting constants as with _CLKMODE,
    * Pause execution in units of microseconds, milliseconds, or seconds,
    * Synchronize code to the start of time-windows in units of microseconds, milliseconds, or seconds.

    obex.parallax.com/objects/139/
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 13:14
    Okay fellas. Wow... yeah.gif

    Mr.Green
    ...Yes your assumption was correct on T_Seconds. My mistake. For consistency purposes I re-posted the code roll.gif
    Pub Main 
    
     Current_Time := 3
     TimeKeeper [noparse][[/noparse] 0 ] ~
    
      REPEAT          
            IF (Timer.T_Seconds == (TimeKeeper [noparse][[/noparse] 0 ] + Current_Time))
                                    TimeKeeper [noparse][[/noparse] 0 ] := Timer.T_Seconds 
    
    



    VAR
     
        Long Second, cog    
        Long Stack[noparse][[/noparse] 25 ]
              
    Pub Start  : okay
     
      stop
      okay := cog := cognew(main, @stack) + 1
    
    PUB stop
      IF cog
        cogstop(cog~ - 1)
      
    PUB Main 
    
      Second~
      
      result := cnt
      
      repeat
         waitcnt( result += clkfreq )
         Second++
                                                              
    Pub T_Seconds
    
      return Second
    
    



    You mention:
    [noparse][[/noparse]quote]You have two calls to Timer.Seconds and they can return different answers if your Timer Main routine updates Seconds in between these two calls. Better to have a temporary variable and do:


    Is this refering to this line of code as the second call?
    [b]TimeKeeper [noparse][[/noparse] 0 ] := Timer.T_Seconds[/b]
    



    Bob Lawrence
    ...Thanks for the link and I have searched the object exchange. I just simply want to learn more about this problem I am having so forgive me for not needing this informatiom tongue.gif


    Phil Pilgrim
    ...The x-tal is a 30ppm (I may have mentioned a 20ppm but still good enough imo) the link search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name=X1091-ND
    My Clock Constants
    _clkmode = xtal1 + pll16x                         
      _xinfreq = 5_000_000  
    
    



    I ran the xtal on the oscilloscope and its running at: 4.99-5.010Mhz, 2.10Volts Pk-Pk


    To all
    ...Thanks for all the help this has got to be the friendliest place to get help and learn.
  • Agent420Agent420 Posts: 439
    edited 2009-08-25 13:32
    Almost every time based project I have seen incorporates a 32.768 Khz watch crystal as the time reference.· The high speed crystals used for system clocks are simply not capable of the accuracy needed for long term clock timing functions.· Some other controllers such as the avr have dedicated inputs for a 32.768 crystal specifcally for that purpose in additon to the main system clock inputs.

    As Mike mentioned earlier, I think the best solution would be some kind of watch crystal based time source, whether that be a 32.768 oscillator or an inexpensive rtc like the DS1307 (which can output several frequencies of timing pulses from 1 Hz to 32Khz in additon to providing full clock, calender and alarm functions).


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 16:33
    Well I did get it to run overnight without being off a second. This was done however without any other code running. Its promising.
  • Agent420Agent420 Posts: 439
    edited 2009-08-25 16:38
    I think you'll find you won't get too far using the system clock.· Of course, much of that depends on how accurate your needs are.

    For < $7, you might consider something like this

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
  • David BDavid B Posts: 592
    edited 2009-08-25 16:46
    I did an experiment once where I connected a GPS 1PPS signal to my propeller and used it to calculate the clocks-per-second count from the local propeller clock.

    The one seconds count was initially very stable. But warming up the crystal by just resting my finger on the crystal case caused an immediate drift in the crystal rate, as compared to the GPS clock. Then I touched an ice cube to the crystal case and swung the rate the other way.

    This was just hacking around; I wasn't trying to make my propeller into a clock, so I didn't calculate what the drift was, but it was a great demo of crystal temperature sensitivity.
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 16:46
    Agent
    Sure that's a nice setup but, I am trying to learn more about the fine details programming a propeller and my board space is very limited. Not to mention I/O pins are limited. In the long run if this wont work as I have predicted I will have to go for some IC that keeps time.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 17:18
    Zap-o,

    The Propeller specs call for a parallel-resonant crystal rated for about an 18pF load capacitance. The crystal you're using is series-resonant. This discrepancy matters and will contribute to any timing inaccuracies you observe. A better choice would be a DigiKey part number X410-ND (not RoHS) or 300-8475-ND (RoHS-compliant).

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 17:30
    Phil Pilgrim

    This is an interesting find you have presented to me. I looked on wiki and could not find any information about parallel-resonant / series-resonant crystal. If you have time could you tell me what this is about and effects it has on the timing?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 17:39
    Zap-o,

    Here's a link that explains the difference: www.maxim-ic.com/appnotes.cfm/an_pk/726/.

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 17:47
    Also Phil and please note I am not trying to be an *** but, I cant find on the data sheet where it states the type of crystal needed to run a propeller. Is it somewhere else?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 18:01
    Zap-o,

    Yeah, it's pretty subtle, that's for sure. Whenever you see a load capacitance mentioned, parallel resonance is implied. Crystals spec'd for series resonance don't include a load capacitance in their specifications. Parallax really should just include an explicit reference to "parallel resonance" in the datasheet, though, as this is not the first time this issue has come up in the forum. Here's a link to a thread where Chip warns against using series-resonant crystals: http://forums.parallax.com/showthread.php?p=585872.

    -Phil
  • Zap-oZap-o Posts: 452
    edited 2009-08-25 18:02
    Thank you [noparse]:)[/noparse]
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-08-25 18:16
    One other thing worth noting: In the datasheet, the pin capacitance for operation of crystals in the 5MHz range is listed as "36pF". The recommended load capacitance rating for a crystal in this range is half that, though, or 18pF. Here's a thread that discusses this apparent discrepancy: http://forums.parallax.com/showthread.php?p=816550.

    -Phil
  • Jim FouchJim Fouch Posts: 395
    edited 2009-08-26 15:52
    Attached is a High Speed clock I wrote in PASM to keep a higher resolution clock count. A DS1307 can only report the current time to the second. I need a way to keep track of time at the millisecond level for my data recording project. So I will read the last know time from the DS1307 and then use a cog to keep a more acurate time stamp.

    The parent object just needs to define the global vars so they can be updatad from the ClockCounter object.

    VAR               'Variables to be located here
    
      Long MilliSecond,Second,Minute,Hour,Day,Month,Year
     
    OBJ               'Object declaration to be located here
    '***************************************
      CLKCTR : "ClockCounter"
    
    

    Then when you start the object simply insert the current time/date as shown here...

      Second:=0
      Hour := 1
      Minute :=28
      Day := 26
      Month:=8
      Year:=2009
      clkctr.start(@MilliSecond)
    
    


    From this point on, the object will advance the clock for you keeping track down to the millisecond. yeah.gif Simply read from the Vars in your parent Cog and the lower one will change them as the clock advances.

    I still need to add for Leap Years that are divisable by 400 but not 100. But it's good till the end of this century anyway...lol

    I was up till 1:30am last night working on this and left it running till 7am and compared to my Asus laptop clock, there was no drift to the second level.

    Use at your own risk.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jim Fouch

    FOUCH SOFTWARE
  • Agent420Agent420 Posts: 439
    edited 2009-08-26 16:04
    ^ Just as a point of thought, the DS1307 has a pulse output that can be configured for 1Hz, 4Khz, 8Khz or 32Khz, so another possibility is to read the DS107 pulse on an io pin (or use a counter) and use that as the time source to obtain higher resolution which is still based on the more accurate crystal.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Sign In or Register to comment.