MSF Time Decoder
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
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
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 := 0Unfortunately 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.
Alan
I'm surprised that you get anything usefull out of this code
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
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)
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
...such are the joys of the OBEX! It is a lift out of an object there.
Cheers
Richard
I will plod on regardless!
Cheers
Richard
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!!!
Look here for an explanation on parity bits: http://en.wikipedia.org/wiki/Parity_bit
So you parity check will become:
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
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 ReturnYour 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
Ahh yes. thanks Cluso. I recall that - but I cant actually find it again
Cheers
Richard
Richard
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.
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/