Shop OBEX P1 Docs P2 Docs Learn Events
MSF Time Decoder — Parallax Forums

MSF Time Decoder

g3cwig3cwi Posts: 262
edited 2012-07-08 18:37 in Propeller 1
Hi

Does anyone have the code written to decode the MSF time signals. If so would you are to share it?

http://www.npl.co.uk/upload/pdf/MSF_Time_Date_Code.pdf

If not it looks like a nice little exercise!

http://www.pvelectronics.co.uk/index.php?main_page=index&cPath=9&zenid=ea39d143e3ff1a9d7da5af3aacdb93cf

Cheers

Richard

Comments

  • g3cwig3cwi Posts: 262
    edited 2012-07-05 12:27
    The following code uses a counter to detect the positive lengths.
    PUB Measure (MSF_In,pulsesOut)
    {{Continuously acquire pulse width at address MSF_In,
         and store as milliseconds at the address pulsesOut }}
      ctra[30..26] := 010       ' Set mode to "APIN=1"
      frqa         := 1            ' Increment phsa by 1 for each clock tick
      phsa         := 0            ' Reset counter
      ctra[5..0]   := LONG[MSF_In] ' Set APIN
      
      repeat    
                                
          waitpeq(|< LONG[MSF_In], |< LONG[MSF_In], 0)   ' Wait for pulse to start
          waitpne(|< LONG[MSF_In], |< LONG[MSF_In], 0)   ' Wait for pulse to stop             
          LONG[pulsesOut] := phsa /(clkfreq/1_000)-17    ' Calculate Width, in milliseconds
          phsa := 0     
    

    Unfortunately the data I have is inverted so I need to measure the spaces. I have tried a few things including reversing the order of waitpeq and waitpne without success. What might be the best way to invert the incoming data stream or to measure the 0 periods?

    Thanks.

    Richard

    PS I am also surprised that I have to insert a correction of 17mS to get the pulses reasonably accurate but they still have a lot of jitter. This is strange as they come from a standard time source.
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2012-07-05 13:26
    Now that we have got to mess about with all that Higgs-Bosson stuff, Mother nature is getting her own back by varying one of the constants :-)

    Alan
  • AribaAriba Posts: 2,690
    edited 2012-07-05 21:08
    g3cwi wrote: »
    PS I am also surprised that I have to insert a correction of 17mS to get the pulses reasonably accurate but they still have a lot of jitter. This is strange as they come from a standard time source.

    I'm surprised that you get anything usefull out of this code :smile:

    ctra[30..26] := 010
    sets the counter mode to POSEDGE if I count the modes right (010=decimal 10 = binary %01010).
    To measure a pulse length you need POSDETECT or NEGDETECT, for low pulses NEGDETECT is the right mode:
    ctra[30..26] := %01100

    Then
    ctra[5..0] := LONG[MSF_In]
    This sets the pin number to the value of the hubmemory long at the location MSF_In, which I don't think was your intention.
    Just set it to the pin number with:
    ctra[5..0] := MSF_In

    If you now swap the WAITPNE and WAITPEQ lines, you should measure the low pulse length.

    But if you need only a milliseconds resolution then the following code without a counter should also work:
    waitpne(|< LONG[MSF_In], |< LONG[MSF_In], 0)   ' Wait for pin Low             
          starttime := cnt
          waitpeq(|< LONG[MSF_In], |< LONG[MSF_In], 0)   ' Wait for pin High
          LONG[pulsesOut] := (cnt-starttime) / (clkfreq/1_000)
    

    Andy
  • kuronekokuroneko Posts: 3,623
    edited 2012-07-05 21:27
    Ariba wrote: »
    I'm surprised that you get anything usefull out of this code :smile:

    ctra[30..26] := 010
    Judging by the misaligned comment it looks like the infamous % consumption struck again (I'm guessing %11010, LOGIC.A). Anyway, this doesn't explain the need for adjustment unless the pin issue you suspect is real.
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-07-05 21:42
    g3cwi: Interesting modules.
    I suspect some of the decoding RF work done by Phil may work without requiring the pcb at all ??? (i.e. decode fully in propeller software with simple R/C/L circuitry)
  • AribaAriba Posts: 2,690
    edited 2012-07-05 22:10
    kuroneko wrote: »
    Judging by the misaligned comment it looks like the infamous % consumption struck again (I'm guessing %11010, LOGIC.A). Anyway, this doesn't explain the need for adjustment unless the pin issue you suspect is real.

    Yes, "LOGIC A" makes sense. If the pin was also the correct one by accident, then it's not so surprising anymore...
    So to get the Low pulse time he can also set the mode to "LOGIC !A". Looks like these counter modes are exactly the same as POS and NEG detect.

    Andy
  • g3cwig3cwi Posts: 262
    edited 2012-07-06 00:21
    Ariba wrote: »
    I'm surprised that you get anything usefull out of this code :smile:


    ...such are the joys of the OBEX! It is a lift out of an object there.

    Cheers

    Richard
  • g3cwig3cwi Posts: 262
    edited 2012-07-06 08:48
    The counters have lots of different modes but no-where in the Prop Manual can I see a detailed explanation for each one (with possible application examples). Perhaps they are "obvious" to experts but they are not to me. Even the App Note leaves me guessing about a lot of things...

    I will plod on regardless!

    Cheers

    Richard
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-07-06 15:45
    g3cwi wrote: »
    The counters have lots of different modes but no-where in the Prop Manual can I see a detailed explanation for each one (with possible application examples). Perhaps they are "obvious" to experts but they are not to me. Even the App Note leaves me guessing about a lot of things...

    I will plod on regardless!

    Cheers

    Richard
    You are not alone. A number of us would like to see the logic diagram. I am certain there are other uses for these counters that still haven't been thought of.
  • Christoph_HChristoph_H Posts: 31
    edited 2012-07-07 02:14
    AN001(link) has some code examples and illustrates how each mode functions.
  • g3cwig3cwi Posts: 262
    edited 2012-07-07 10:22
    Dear all

    Amazingly I have written a decoder that works! The Parity checking is crude. Are there clever ways of doing it?
    {MSF Off-Air Clock Data Decoder
    Richard G3CWI June 2012
    
    Use with http://www.pvelectronics.co.uk/index.php?main_page=product_info&products_id=2}
    
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
            ThisYear = 2012
    
    VAR
      long  NegPulse
      Long  A[59], B[59]
      Long  Year, Month, Date, Day, Hour, Mn
      Long  MonthTxt, DayTxt, error
       
    OBJ
      DB      : "Debug_LCD03"
      
    PUB Main | Start, Stop, Period, i, T1, T2
    
    DB.Start(15,9600,4)
    DB.Backlight(true)
    DB.cls
    DB.cursor(0)
    DB.str(string("Waiting for start..."))
    
      Repeat
      
              Repeat until NegPulse > 450 'Detect 500ms negative start pulse
                waitpeq(|< 14, |<14, 0)
                Start := cnt
                waitpne(|< 14, |<14, 0)
                Stop := cnt
                NegPulse := (Stop-Start) / (clkfreq/1_000)            
    
              If Date == 0 'only first time after start
                DB.cls
                DB.Str(string("Start detected."))
                DB.NL
                DB.Str(string("Gathering data.")) 
                
              NegPulse := 0 'reset start pulse detector
              
              wait(610) 'Wait until start of first databit + 10mS
           
              Repeat i from 1 to 59
    
                T1:=INA[14] 'test twice
                wait(10)    '10ms delay
                T2:=INA[14]
                IF T1==T2
                  A[i] := T1
                Else
                  A[i] := 999
                  
                Wait(100)  'wait for next data bit
                
                T1:=INA[14] 'test twice
                wait(10)    '10ms delay
                T2:=INA[14]
                IF T1==T2
                  B[i] := T1
                Else
                    B[i] := 999
                                    
                If i <> 59 'stops loop missing start pulse at end of minute
                  wait (880)  '880+10+10 = 1000ms
    
            ErrorCheck
               
            If Error == 0
            
              CalcYear
              CalcMonth
              CalcDate
              CalcDay
              CalcHour
              CalcMin
                       
            Else
              Mn := Mn + 1
           
            DB.cls
            DB.Str(MonthTxt)
            DB.Str(string(" "))
            DB.Dec(Date)
            DB.Str(string(" "))
            DB.Dec(Year)
            DB.Str(string(" "))
            DB.Dec(Error)
            DB.Nl
            
            DB.Str(DayTxt)
            DB.Str(string(" "))
            DB.Dec(Hour)
            DB.Str(string(":"))
            
            IF Mn < 10 'add leading zero
              DB.Str(String("0"))
              DB.Dec(Mn)
            Else
              DB.Dec(Mn)
               
            If Error == 1
                DB.Str(string("*"))
    
    PRI Wait(ms)
    
    Waitcnt((clkfreq/1000)*ms + cnt)
    
    Pri ErrorCheck | Parity
    
     Error := 0
    
     Parity := B[54] + A[17] + A[18] + A[19] + A[20] + A[21] + A[22] + A[23] + A[24]
     Parity := Parity & %1
     If Parity <> %1 
       Error:= 1
       Return
     
     Parity := B[55] + A[25] + A[26] + A[27] + A[28] + A[29] + A[30] + A[31] + A[32] + A[33] + A[34] + A[35] 
     Parity := Parity & %1
     If Parity <> %1 
       Error:= 1
       Return
     
     Parity := B[56] + A[36] + A[37] + A[38]
     Parity := Parity & %1
     If Parity <> %1 
       Error:= 1
       Return
    
     Parity := B[57] + A[39] + A[40] + A[41] + A[42] + A[43] + A[44] + A[45] + A[46] + A[47] + A[48] + A[49] + A[50] + A[51] 
     Parity := Parity & %1
     If Parity <> %1 
       Error:= 1
       Return
      
    Pri CalcYear
      
      Year := A[17]*80 + A[18]*40 + A[19]*20 + A[20]*10 + A[21]*8 + A[22]*4 + A[23]*2 + A[24] + 2000 
       
    Pri CalcMonth
    
      Month := A[25]*10 + A[26]*8 + A[27]*4 + A[28]*2 + A[29]
    
      Case Month
       1 :   MonthTxt:= string("January")
       2 :   MonthTxt:= string("February")
       3 :   MonthTxt:= string("March")
       4 :   MonthTxt:= string("April")
       5 :   MonthTxt:= string("May")
       6 :   MonthTxt:= string("June")
       7 :   MonthTxt:= string("July")
       8 :   MonthTxt:= string("August")
       9 :   MonthTxt:= string("September")
       10:   MonthTxt:= string("October")
       11:   MonthTxt:= string("November")
       12:   MonthTxt:= string("December")
       Other:MonthTxt:= string("Error") 
       
    Pri CalcDate
      
      Date := A[30]*20 + A[31]*10 + A[32]*8 + A[33]*4 + A[34]*2 + A[35]
       
    Pri CalcDay
      
      Day := A[36]*4 + A[35]*2 +A[38]
     
      Case Day
       1     :DayTxt:= string("Monday")
       2     :DayTxt:= string("Tuesday")
       3     :DayTxt:= string("Wednesday")
       4     :DayTxt:= string("Thursday")
       5     :DayTxt:= string("Friday")
       6     :DayTxt:= string("Saturday")
       7     :DayTxt:= string("Sunday")
       Other :DayTxt:= string("Error")
       
    Pri CalcHour
      
      Hour := A[39]*20 + A[40]*10 + A[41]*8 + A[42]*4 + A[43]*2 + A[44]
    
       
    Pri CalcMin
      
      Mn := A[45]*40 + A[46]*20 + A[47]*10 + A[48]*8 + A[49]*4 + A[50]*2 + A[35]
      
    
    

    Cheers

    Richard

    PS Year displays as Zero if there is a Parity Error which looks like it's impossible... Driving me crazy!!!
  • rosco_pcrosco_pc Posts: 468
    edited 2012-07-07 16:59
    g3cwi wrote: »
    The Parity checking is crude. Are there clever ways of doing it?

    Look here for an explanation on parity bits: http://en.wikipedia.org/wiki/Parity_bit

    So you parity check will become:
     Parity := B[54] ^ A[17] ^ A[18] ^ A[19] ^ A[20] ^ A[21] ^ A[22] ^ A[23] ^ A[24]
     If !Parity
       Error:= 1
       Return
    

    However you write 999 to the bit value when you detect different levels within 10mS. Chnage that part of the code to something like this (avering the bit vaue over 3 tries):
                b1 := INA[14] 	'get average reading of 3 tries
                wait(10)    	'10ms delay
                b2 := INA[14]
                wait(10)    	'10ms delay
                b3 := INA[14]
    	    A[i] = (b1&b2)|(b2&b3)
    

    What's more although your code works for the normal case it will not work for lead seconds where the system send 58 or 60 seonds!!
    Yiou might be better off with the edge detection as described earlier
  • g3cwig3cwi Posts: 262
    edited 2012-07-08 03:43
    Thanks for the clues Rosco_pc.

    I revised your snippets as follows:
    Parity := B[54] ^ A[17] ^ A[18] ^ A[19] ^ A[20] ^ A[21] ^ A[22] ^ A[23] ^ A[24] 
      If Parity == 0   'Your suggestion for !Parity seemed to fail
        Error:= 1   
        Return
    
    

    Your averaging idea did not seem to work so I multiplied the samples together. My "999" idea was a bad one!

    The code is now in the OBEX.

    http://obex.parallax.com/objects/875/

    Cheers

    Richard
  • g3cwig3cwi Posts: 262
    edited 2012-07-08 05:21
    Cluso99 wrote: »
    g3cwi: Interesting modules.
    I suspect some of the decoding RF work done by Phil may work without requiring the pcb at all ??? (i.e. decode fully in propeller software with simple R/C/L circuitry)

    Ahh yes. thanks Cluso. I recall that - but I cant actually find it again :( Nothing obvious in the OBEX.

    Cheers

    Richard
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-07-08 05:31
    I have the thread saved on my pc, so wiill post the links in the morning.
  • g3cwig3cwi Posts: 262
    edited 2012-07-08 05:51
    Got it. I recalled reading it before and remembered that Phil mentioned a Tayloe mixer - that came up in the search. Thanks.

    Richard
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-07-08 07:41
    g3cwi wrote: »
    The counters have lots of different modes but no-where in the Prop Manual can I see a detailed explanation for each one (with possible application examples).

    The PEK text (available from Prop Tool Help menu) has a some stuff on using counters. I think they have some code examples. I don't think (IIRC) they go into much depth on the subject though.
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-07-08 18:37
    There are some details in AN-001 and there is some good info for the Sigma Delta mode in another App Note. Also some good code examples in that come with the Prop Tool download.

    But, what we would really like is the logic diagram of the counters including the VGA too. A number of us are convinced we could find some other great uses if we had this info. You never can get to this sort of level with other micros because they are just too complex and too many varieties - and of course the chip vendors are very secretive, not at all like Chip & Parallax.

    For reference, here are some links to other threads...
    http://forums.parallax.com/showthread.php?136886-A-link-for-PhiPi-on-a-SDR-maybe-you-ve-already-seen-it.&highlight=software+defined+radio
    http://forums.parallax.com/showthread.php?135233-quot-Density-Domain-quot-Signal-Processing&highlight=software+defined+radio
    http://forums.parallax.com/showthread.php?133173-FIR2PASM-Automatic-FIR-Filter-Code-Generator&highlight=software+defined+radio
    http://forums.parallax.com/showthread.php?123791-Propeller-mediated-Sine-Wave-Frequency-Synthesizer
    http://forums.parallax.com/showthread.php?117044-Online-Ham-Radio-Receiver&highlight=software+defined+radio
    http://forums.parallax.com/showthread.php?132977-Hilbert-Transform-Prop-DSP&highlight=software+defined+radio
    http://forums.parallax.com/showthread.php?105674-Hook-an-antenna-to-your-Propeller-and-listen-to-the-radio!-(New-shortwave-prog&highlight=software+defined+radio
    and you shuold also look here for SRD info..
    http://www.wb5rvz.com/sdr/softrock_40_r/
    http://www.wb5rvz.com/sdr/ensemble_rx_ii/
Sign In or Register to comment.