Help me sync a 1-sec generator (PIC) to a GPS

Discussion in 'The Projects Forum' started by bwack, Nov 9, 2013.

  1. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    Hello. It's been a while ;) Interests in this hobby comes and goes, but now it's the PIC12F629 and mikroE C compiler I'm currently interested in.

    I'm writing code for a 1-sec generator and clock. I'm using Bresenham Zero accumulative-error algorithm from Roman Black. That's where I got the inspiration from to do this project :) http://www.romanblack.com/one_sec.htm

    I'm also going to make the inexpensive xtal oven later http://www.romanblack.com/xoven.htm

    Now what I'd like to do is to sync this clock with gps unit that I have (FastraxUP300). It has a 1-sec pulse, and a serial data output (NMEA coded) , but for now I don't have a uart and I'd like to try to lock the phase and speed of the 1-sec generator with the GPS 1-sec pulse. I was thinking about allocating a pin on the PIC to listen for pulses and start the syncronizing prosess if the gps unit is connected to it. How is this possible ? I'm thinking it must be possible to use the TIMER1 (TMR0 is allready running the clock) as a start-stop watch with the gps 1-sec pulse and calculate a new and better Bresenham value for the Bresenham algorithm.. but how should I approach this.
    Any other suggestions ? What kind of clock precission can I expect from this method? Will I get better results if I recalculate the Bresenham value by comparing number of seconds error after say one week since last syncronisation?
     
    Last edited: Nov 9, 2013
  2. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Hi Bwack and thanks for saying you were inspired by my web page. :)

    Hmm, any reason you want to stay with the tiny 8-pin PIC 12F629? You said it's for a "clock" but does not have a lot of pins to run a display, as it only has 5 output pins.

    Or maybe the 12F629 just needs to generate a 1 second pulse itself? Please state what type of xtal and xtal freq etc.

    Anyway, it's worth reading my other page on GPS 1-second timing here;
    http://www.romanblack.com/onesec/High_Acc_Timing.htm

    If you look down the page at the heading "PLL mains-synchronised 1 second clock" a simple system is outlined. That will work to lock to the 1 second GPS pulse instead of locking to the AC mains pulses.

    An important point is to sync first to the GPS pulse, so the internal 1 second / edge occurs at the same time as the GPS pulse / edge.

    Then, every second if the GPS pulse happens first you subtract one count from the Bresenham value, reducing it by a tiny amount like a millionth or ten-millionth. If the GPS pulse / edge happens after the internal / edge, then increase the Bresenham value.

    That will lock both the phase and frequency mathematically. Also, since GPS units can drop out and stop making pulses you should add detection code so if the GPS pulse is missing, then no adjustment will be done.

    And as well as synchronising the two pulses at the start you will also need to start with a Bresenham value that is very close to a perfect second. That's pretty easy, just change the starting Bresenham value in code, and compile+program, then see how well the flashing LEDs sync by eye. Obviously you need to have a LED on the GPS pulse(most do) and it's easy to put a LED on the PIC.
     
  3. MikeML

    AAC Fanatic!

    Oct 2, 2009
    5,450
    1,066
    The Nov/Dec 2013 Issue of QEX has an article about Using GPS to fine-tune a Rubidium Freq Standard that is relevent...
     
  4. alexfreed

    Member

    Oct 8, 2012
    72
    10
    If you want a 1 sec clock and GPS already provides that I'm not sure I understand the need to sync to it unless the UPS signal is not always present.

    I did a somewhat similar thing with an AVR uC rather than PIC but it makes little difference. The crystal frequency (10 MHz) can be "pulled" within a few hundreds of Hz with a varactor which gets the control voltage from the uC's PWM output via simple RC filter. The idea and the code are extremely simple: every time the timer overflows, a counter is incremented. When a 1 sec pulse is detected, the timer's value is captured and compared to 10,000,000. The timer runs at the 10 MHz clock. In fact only the 16 bits from the timer are compared and only if the number of overflows is right. If the value differs from the perfect one, the PWM is adjusted to get the crystal frequency right. The number of clocks between 1 sec pulses from the GPS stays within +/- 1 from the perfect 10,000,000 after it locks.
     
  5. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    Wow, thanks for the replies! I've been feeling under the weather recently and here is what I've got so far.
    I was thinking about having a precise 1-sec module for future clock-projects, but when I come to think about it, it would be nice to have a display for debugging. I have a PIC16F628 and a PIC16F887, a mikroE EasyPIC5 dev.system + a 16x2 LCD display. I can port the code from the large pic to the small pic eventually.

    The crystal is a 8MHz quartz crystal that came with the EasyPIC 5 dev.board. Do you have a suggestion for a good one ?

    I was wrong with what GPS module I have. No name is written on it and I had an old datasheet on my computer, but it is identical to this one: https://www.sparkfun.com/products/465 .. There is a flashing LED on it, and if I connect the 1PPS signal to the EasyPIC board, an IO indicator led on that board will flash too. I will try your suggestions :) I have the code working to get the 1-sec pulse. That was easy..

    preliminary mikroE C code:

    Code ( (Unknown Language)):
    1. //PIC12F629 at 8MHz
    2. long counter=0;
    3. short ONESECflag=0;
    4.  
    5. void tick_event() {
    6.  //
    7. }
    8.  
    9. void interrupt() {
    10.   if(T0IF_bit) {
    11.     T0IF_bit=0;
    12.     counter-=256;       // 256 ticks every TIMER0
    13.     if (counter<0) {
    14.       counter+=1000000; // 1000000 ticks every second
    15.       tick_event();
    16.       ONEsecflag=1;
    17.     }
    18.   }
    19. }
    20.  
    21. void main() {
    22.   CMCON=0x07; // Set GP<2:0> to digital I/O.
    23.   TRISIO=0xF0;
    24.   GPIO=0;
    25.   OPTION_REG = 0b10000000;     //Assign prescaler to TMR0
    26.   TMR0 = 1;                    //init TMR0
    27.   INTCON = 0b10100000;         //GIE=1 enable interrupt & TOIE=1 on timer overflow
    28.  
    29.   do {
    30.     //delay_ms(20);
    31.     if (ONEsecflag) {
    32.       ONEsecflag=0;
    33.       GP0_bit = 1;
    34.       delay_ms(100);
    35.       GP0_bit = 0;
    36.     }
    37.   } while(1);
    38. }
    39.  
    40.  
    Regarding the GPS, it is expensive and I'd like to keep that for other projects, and the GPS needs a good location to get a signal. I live in a flat with concrete walls. Signal is lost unless you put the GPS antenna near the window. Also i'd like to see how precise one can get this 1-sec pulse :) Now I'll make the assembly to connect the gps to the easypic board.
     
  6. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    Hi again. I have a question. Here in the method of finding who comes with the first pulse, do you assume we use a capture pin? The timeroverflow happens every 256 ticks (1tick~1us), I can only imagine that I will never really reduce the period error down to 1us with this method without using a capture pin to latch the timer at the exact microsecond it happens... ?

    I have another problem. My gps module doesn't have the 1PPS afterall. I'm feeding the UART TX pin through an open collector (for shifting the voltage level from 3->5V). Now I have silence for 90% of the time on the TX, and every second there will come data. I ignore the data and continuously poll and shift into a 8bit variable in sofware.. When there is no longer activity on the TX pin, the 8bit variable will then soon become 0b0000000. This takes time and I ignore this state because I don't know how many 1's are in it, but as soon as TX starts pumping bits again the variable will be != 0, and I use that as the edge. It works, but polling is not very accurate.. Do you think a 555 monostable circuit can help with the filtering and help get a quicker fix on the edge? Should I have used interrupt-on-change rather than polling? I'm not satisfied with this and will move onto the 16F628 that has a capture pin..
    .. What about the accuracy of finding the 1sec pulse edge on the TX pin? There must be some data processing delay internally in the gps module, but is the delay the same every time.. ? ..

    In the mean time I have played with the PIC12F629. I first tried the method of locking the phase to the 1pps (TX in my case).. It worked and the pic kept syncing to the gps. However, I felt that I never got it to mathematically narrow the bresham values error to 1us, possible because I'm not having the advantage of a capture pin and the bresham value will swing around the ideal bresham by >256 ticks...

    For fun I have made another attemt at reducing the error by syncing once and counting seconds until the pulses are 1/4 sec apart, then correcting bresham value after finding out how many ticks are lost every second. The new value is stored on EEPROM. This is a slow process compared to the calibration down to 1us after 1s when having the opertunity to use a capture pin.

    Code ( (Unknown Language)):
    1. long counter=0, i;
    2. //long bresenham=999989;
    3. long bresenham=999000;
    4. unsigned long secs, answer;
    5. unsigned short ONESECflag=0, onesecold, uartsignal, filteredold, filtered, edge, gpsactivity;
    6.  
    7. void tick_event() {
    8. }
    9.  
    10. unsigned long divide(unsigned long a, unsigned long b) {
    11.   unsigned int answer=0;
    12.   while(a>b) {
    13.     a-=b;
    14.     answer++;
    15.   }
    16.   return answer--;
    17. }
    18.  
    19. void resync() {
    20.   INTCON=0x00; T0IF_bit=0; delay_ms(300); counter=0;
    21.   //while(1) {
    22.    for(i=0; i<200000; i++) {
    23.     uartsignal = (uartsignal<<1) + GPIO.B1;
    24.     if(uartsignal==0 ) { filtered=0; } else {filtered=1; delay_ms(5); }
    25.     if (filtered!=0 && filteredold==0 ) { // detect transition
    26.       counter++;
    27.       filteredold=1;    GP2_bit=1;
    28.       if(counter>2) {
    29.         TMR0=1; counter=bresenham; secs=0;
    30.         INTCON=0b10100000;
    31.         GP2_bit=0; return;
    32.       }
    33.     }
    34.     if (filtered==0 && filteredold!=0) { // detect trans
    35.       filteredold=0;      GP2_bit=0;
    36.     }
    37.     if (ONEsecflag && counter<500000) {
    38.       ONEsecflag=0;
    39.       GP0_bit=0;
    40.     }
    41.   }
    42.   GP2_bit=0;
    43.   return;
    44. }
    45.  
    46. void interrupt() {
    47.   if(T0IF_bit) {
    48.     T0IF_bit=0;
    49.     counter-=256;       // 256 ticks every TIMER0
    50.     if (counter<0) {
    51.       GP0_bit=1;
    52.       counter+=bresenham; // ~1000000 ticks every second
    53.       tick_event();
    54.       secs++;
    55.       ONEsecflag=1;
    56.     }
    57.   }
    58. }
    59.  
    60. void main() {
    61.   secs=0;
    62.   edge=0;
    63.   CMCON=0x07; // Set GP<2:0> to digital I/O.
    64.   TRISIO=0b11111010;
    65.   GPIO=0;
    66.   OPTION_REG = 0b10000000;     //Assign prescaler to TMR0
    67.   bresenham=0;
    68.   for(i=0;i<4;i++) {
    69.     bresenham = bresenham<<8;
    70.     bresenham += EEPROM_read(i);
    71.   }
    72.   if (bresenham<980000 || bresenham>1100000) { bresenham=980000; }
    73.   resync();
    74.   GP2_bit=0;
    75.  
    76.   while(1) {
    77.     uartsignal = (uartsignal<<1) + GPIO.B1;
    78.     if(uartsignal==0 ) { filtered=0; } else {filtered=1; delay_ms(1); }
    79.     if (filtered!=0 && filteredold==0 ) { // detect transition
    80.       edge=1; gpsactivity=1;
    81.       filteredold=1;
    82.     }
    83.     if (filtered==0 && filteredold==1) { // detect trans
    84.       filteredold=0;
    85.     }
    86.  
    87.  
    88.     if (edge==1 && secs>10) {
    89.       edge=0;
    90.       if ((counter>250000 && counter<270000) || (counter<750000 && counter>730000)) {
    91.         INTCON = 0b00000000;
    92.         //secs = (1+secs)<<2 - 1; (basically ((1+secs)-1/4 )*4)
    93.         if(counter>250000 && counter<270000) {
    94.           GP2_bit=1;
    95.           answer=divide(bresenham, (1+secs)<<2 - 1); // find how much lost ticks pr tmrof
    96.           bresenham-=answer;
    97.         } else {
    98.           answer=divide(bresenham,secs<<2 +1);
    99.           bresenham+=answer;
    100.         }
    101.         secs =0;
    102.         GP2_bit=0;
    103.         EEPROM_Write(0x00,0xFF&(bresenham>>24));
    104.         EEPROM_Write(0x01,0xFF&(bresenham>>16));
    105.         EEPROM_Write(0x02,0xFF&(bresenham>>8));
    106.         EEPROM_Write(0x03,0xFF&(bresenham));
    107.         //INTCON = 0b10100000;
    108.         resync();
    109.       }
    110.     }
    111.     else {
    112.       edge=0;
    113.     }
    114.  
    115.     if (ONEsecflag && counter<500000) {
    116.       ONEsecflag=0;
    117.       GP0_bit=0;
    118.     }
    119.   }
    120. }
     
  7. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Here's a cut and paste directly from my web page;
    "Procedure;
    1. capture every period / edge with the 16bit CCP hardware capture
    2. analyse every 2 captures to mathematically determine the xtal frequency"

    The PIC hardware capture CCP1 etc records the value of the 16bit TMR1 at the exact instant a / edge occurs on the CCP1 input pin. The precision will be the TMR1 count period, so if you use the PIC16F887 with 20MHz xtal TMR1 will run at 5MHz. That's 0.2uS per count resolution.

    Hmm, ok if you don;t have a 1PPS pulse, you have to gate on the serial data packet, which is sent once per second.

    The easiest way is to detect the blank period between data packets, then trigger the "event" on the very first change of the serial data pin (start of next packet).

    That's a bit hard to do with the CCP capture module, but you can do it manually (by polling the pin) at the cost of a little bit of precision per capture. You can still average multiple readings over multiple seconds, to give pretty good accuracy.

    Of, if you add a 555 monostable to the serial data pin, you can create a single HI pulse that starts at the start of serial data, and ends (say) 0.5 seconds later. Because that only has one / edge per second, you can then input that to the CCP1 capture input, and get full timing resolution.

    It's actually very good, at least on UBlox GPS modules. The GPS processor runs at a very high speed and the serial data is output at a very regular 1 second period AND timing. It's probably not as good as the 1PPS output, but it's plenty good enough to discipline a clock if you average the seconds.

    For now, I think you need to decide EXACTLY what you want this device to do, and I can suggest the best way to do it (in my opinion). :)
     
  8. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    Thanks for the reply :)

    I want to make a clock on a 4x 7seg display that alternates it's display to show outside temperature and time. I have code from a previous project to use a 1-wire DS1820 temperature IC.

    I/O requirements on a PIC:
    - 4x 7seg -> 10 (8 segments and 4 digits)
    - DS1820 1-wire -> 1
    - GPS -> 2 (TX, RX)
    - 1 PPS -> 1
    - Crystal -> 2
    16 total.

    I'm thinking PIC16F628. It has 16 I/Os and has CCP and UART.
     
  9. davebee

    Well-Known Member

    Oct 22, 2008
    539
    46
    If you're feeling adventurous, and are willing to risk damaging the GPS module, you may be able to get your 1 PPS signal if your module has the SIRFStar III chipset.

    I have a GPS module that had no user interface 1 PPS output, but it turned out that the internal chipset did provide it; the module designer had just chosen not to wire it out to the user interface.

    I peeled back a metal shield on the module, identified the 1 PPS pin on a surface mounted chip, soldered a wire to it, and it worked! 1 PPS pulses were available.

    I posted pictures of it here, with some discussion and links to chipset documentation:

    http://forums.parallax.com/showthread.php/129914-Parallax-GPS-sensor-PMB-688-1PPS?highlight=SIRF

    Also, FYI, my module works much better with the optional external powered antenna. With that antenna, it syncs to the satellites from almost anywhere inside the house, not just by the window.
     
  10. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    If you just want to show time from the GPS, the time is sent as ASCII data text string in three different NEMA strings.

    From memory, the #GGA string is very common and should be transmitted in the serial data every second.

    To make it a "4 digit clock" all you need to do is read the 4 HH:MM characters from the text string, and display it. That will display ZULU time (GMT). If you want your local time just add or subtract X hours from the HH pair, to convert ZULU to your local timezone.

    Since you are only wishing to display HH:MM (no seconds) there is little need to sync to high precision to the GPS time standard. Just directly display the HH:MM data which is very easy! :)
     
  11. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    I want to attach the gps to the clock, let it set and sync, then disconnect the gps and let the clock run.
     
  12. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    OK, that sounds reasonable. Do you have a flowchart or other proposed method of operation?

    Something like this;
    1. clock uses 1 second bresenham routine for timing
    2. GPS serial data is connected, sync HH:MM
    3. when GPS string changes from one minute to the next, reset PIC internal timer seconds to zero
    4. GPS can then be disconnected
     
  13. bwack

    Thread Starter Active Member

    Nov 15, 2011
    107
    10
    That sounds like what I had in mind. I have sketched a flowchart. It has been many years since i attempted that. It's not that long ago since I made a state chart diagram though. Tell me if this diagram is too detailed.

    [​IMG]

    Thanks for the info. I removed the shields from the back of the GPS module.

    First an initial pic. Impossible to see inscriptions (1st pic), so I held a flashlight diagonally onto the device and made a new shot (2nd pic).

    Before I removed the stickers and tape insulation on the cap
    [​IMG]

    Large chip on top is Flash Memory, and the other is the SirfStar III IC...
    It's the darn ballgrid type. I don't know where to figure out if the 1PPS
    is routed out of the chip or not :-\ .. This is the EM-411 module without 1PPS
    on the connector, however the pcb does say EM-406.. hmm, may there be some
    footprint with 1PPS. I don't know..
    [​IMG]
     
  14. THE_RB

    AAC Fanatic!

    Feb 11, 2008
    5,435
    1,305
    Nice flow chart, and well thought out.

    So when the GPS is connected, it will constantly reset the soft time to GPS time and display the GPS time as HH:MM? So it is simple a GPS display clock, for the time that the GPS is connected.

    Then the goal with the disciplining is to trim the internal timekeeping constant so the clock keeps accurate time after the GPS is disconnected? That is do-able too, but bear in mind you can set the timekeeping constant in a few seconds GPS monitoring to much less than 1 PPM time error.

    However after that point the clock xtal will drift in PPM error as temperature changes, so all the best disciplining in the world will still leave you with a clock that gains or loses time as the temperature rises or falls (once GPS is no longer connected).

    Since the GPS looks like one of those cheap old-style $10 modules why not leave it connected? That simplifies the clock a lot as you can just make a GPS time display, and it only needs to run from the internal timer during GPS outages.
     
Loading...