Högtupplösande RTC - hur jag har gjort
Postat: 19 mars 2014, 16:31:14
Jag håller på att bygga upp mjukvarabasen på det styrkort som jag sitter med.
Det har en RTC (Real Time Clock, DS3232) sittande på en I²C-bus. Den RTC är ju ganska hyggligt exakt och den har en funktion jag gillar: pulser ut! Puls-utgången kan ge olika frekvenser varav en är 1Hz.
Att avläsa RTC'n via I²C-bussen tar sin lilla tid när µC'n kör med 50 MHz, det gillar jag inte så jag ritade schemat från början till att ha den pulsutgång till en IRQ-ingång på µC'n. Vid uppstart avläsas RTC'n, det synkroniseras med att pulsen skiftar från låg till hög, sedan utförs avläsningen, värden konverteras från BCD till binära värden i en variabelklump som innehåller år, månad, datum, timme, minut och sekund.
Men jag vill ha mer - för framtida behov - så jag har en systemklocka som kör med 1ms upplösning och då kom jag på att synkronisera dessa två med varandra. Jag har löst det vid att starta systemklockan med det teoretisk korrekta värdet för den frekvens µC'n kör men då jag använder den interna 50 MHz oscillator finns det ett frekvensberoende som inte är bra.
Jag vill ju ha en timestamp som som kan dela in varje sekund i 1000 delar och då är det ingen hjälp att den blir stampad med hhmmss,1005. Jag har därför gjort som följer:
* Själva IRQ'ns interrupt har fått en ganska hög prioritet, detta ska ge snabbt svar.
* Värdet av en ms-räknare kopieras in i en avläsningsvariabel och sedan nollställs det. Denna kopiering sker för att minska felet i tid.
* Sedan kollas avläsningsvariabeln och om värdet är > 1000 räknas dividern upp ett steg.
* Är den däremot < 999 minskas dividern ett steg.
Jag har testat att skriva ut värdet på dividern varje sekund och den står stabilt - fram till jag lekar med kylsprayen! Får µC'n en skvätt ser man hur värdet stegar iväg lite grann och när temperaturen kommer tillbaka till normal drift återgår den.
Detta sätt gör såklart att dividern måste ha ett ganska högt värde för att stegen ska vara så pass små att den verkligen kan fintrimmas, i detta fall är det uträknade värdet 1561 och den kan "skena iväg" till 1565 när µC'n frysar rumpan av sig.
Slutresultatet är att den exakta frekvens beror mest på noggrannheten av RTC'n och att den har en upplösning på 1ms. Helt OK.
Och för att spara tid läser den bara RTC'n via I²C-bussen vid uppstart för att ställa datum/tid rätt, sedan sker all uppräkning i mjukvaran. Detta kan ske i all evighet, jag har rutiner som kan kolla om ett datum är korrekt varför jag kan räkna datum upp och sedan kolla om datumet är legalt. Är det inte sätter jag datum till 1 och räknar upp månaden. Kollar sedan datumets legalitet igen och är även det fel ställs månaden till 1 och året räknas upp.
Detta sätt ger konstant tillgång till den riktiga tid utan att vänta på I²C-bussen.
Jag håller just på att sammanställa en beställningslista där en GPS-mottagare ingår, då ska tiden avläsas från den. Kombinerat med den RTC-krets jag har vald (± 2 minuter/år i avvikelse) kan jag nog tro att tiden kan visas ganska bra utan att behöva ställas jämt o ständigt.
Jag har såklart redan rutin för sommar/vintertid, veckodag, veckonummer osv. klar
Det har en RTC (Real Time Clock, DS3232) sittande på en I²C-bus. Den RTC är ju ganska hyggligt exakt och den har en funktion jag gillar: pulser ut! Puls-utgången kan ge olika frekvenser varav en är 1Hz.
Att avläsa RTC'n via I²C-bussen tar sin lilla tid när µC'n kör med 50 MHz, det gillar jag inte så jag ritade schemat från början till att ha den pulsutgång till en IRQ-ingång på µC'n. Vid uppstart avläsas RTC'n, det synkroniseras med att pulsen skiftar från låg till hög, sedan utförs avläsningen, värden konverteras från BCD till binära värden i en variabelklump som innehåller år, månad, datum, timme, minut och sekund.
Men jag vill ha mer - för framtida behov - så jag har en systemklocka som kör med 1ms upplösning och då kom jag på att synkronisera dessa två med varandra. Jag har löst det vid att starta systemklockan med det teoretisk korrekta värdet för den frekvens µC'n kör men då jag använder den interna 50 MHz oscillator finns det ett frekvensberoende som inte är bra.
Jag vill ju ha en timestamp som som kan dela in varje sekund i 1000 delar och då är det ingen hjälp att den blir stampad med hhmmss,1005. Jag har därför gjort som följer:
* Själva IRQ'ns interrupt har fått en ganska hög prioritet, detta ska ge snabbt svar.
* Värdet av en ms-räknare kopieras in i en avläsningsvariabel och sedan nollställs det. Denna kopiering sker för att minska felet i tid.
* Sedan kollas avläsningsvariabeln och om värdet är > 1000 räknas dividern upp ett steg.
* Är den däremot < 999 minskas dividern ett steg.
Jag har testat att skriva ut värdet på dividern varje sekund och den står stabilt - fram till jag lekar med kylsprayen! Får µC'n en skvätt ser man hur värdet stegar iväg lite grann och när temperaturen kommer tillbaka till normal drift återgår den.
Detta sätt gör såklart att dividern måste ha ett ganska högt värde för att stegen ska vara så pass små att den verkligen kan fintrimmas, i detta fall är det uträknade värdet 1561 och den kan "skena iväg" till 1565 när µC'n frysar rumpan av sig.
Slutresultatet är att den exakta frekvens beror mest på noggrannheten av RTC'n och att den har en upplösning på 1ms. Helt OK.
Och för att spara tid läser den bara RTC'n via I²C-bussen vid uppstart för att ställa datum/tid rätt, sedan sker all uppräkning i mjukvaran. Detta kan ske i all evighet, jag har rutiner som kan kolla om ett datum är korrekt varför jag kan räkna datum upp och sedan kolla om datumet är legalt. Är det inte sätter jag datum till 1 och räknar upp månaden. Kollar sedan datumets legalitet igen och är även det fel ställs månaden till 1 och året räknas upp.
Detta sätt ger konstant tillgång till den riktiga tid utan att vänta på I²C-bussen.
Jag håller just på att sammanställa en beställningslista där en GPS-mottagare ingår, då ska tiden avläsas från den. Kombinerat med den RTC-krets jag har vald (± 2 minuter/år i avvikelse) kan jag nog tro att tiden kan visas ganska bra utan att behöva ställas jämt o ständigt.
Jag har såklart redan rutin för sommar/vintertid, veckodag, veckonummer osv. klar