Goto page 1, 2, 3, 4 Next
Atlantis
Guest
Wed Nov 12, 2014 1:35 am
Eksperymentowałem ostatnio z synchronizacją czasu w układzie z Atmegą i
ENC28J60. Użyłem gotowych funkcji zaimplementowanych w stosie
tuxgraphics.org, z niewielkimi modyfikacjami (głównie przeliczanie
odebranej wartości na Unix epoch.
Generalnie rozwiązanie jest bardzo proste. Programowy licznik odlicza w
dół liczbę sekund pomiędzy kolejnymi synchronizacjami (w tej chwili
3600). Gdy dojdzie do zera wysyłany jest pakiet z requestem.
Jednocześnie w momencie przyjścia pakietu UDP funkcja sprawdza, czy mamy
do czynienia z odpowiedzią - jeśli tak, to do zmiennej volatile int32_t
rtc ładowany jest odebrany czas.
Obliczanie wartości wygląda następująco:
*time = ( ( ((uint32_t)buf[0x52]<<24) | ((uint32_t)buf[0x53]<<16) |
((uint32_t)buf[0x54]<<

| ((uint32_t)buf[0x55]) ) - 2208988800UL )
Pomiędzy synchronizacjami zegar jest inkrementowany w przerwaniu timera.
Przerwanie jest wywoływane co 1ms - normalnie zwiększana jest zmienna
pomocnicza, jednak w przypadku przekroczenia przez nią wartości 1000
uruchamia się obsługa zegara i kilku programowych liczników.
Program zdaje się działać prawidłowo, jednak byłem ciekaw na ile jest
dokładny. Napisałem prosty skrypt na Raspberry Pi, który odczytuje czas
z omawianego urządzenia i odejmuje go od czasu systemowego w RasPi.
Wyniki są dziwne. Nieraz mam kilka sekund różnicy, czasem jednak pojawia
się wynik w granicach 60 sekund. Niekiedy większą różnicę obserwuję tuż
po synchronizacji.
Nie wydaje mi się, żeby mogło to wynikać z niedokładności timera Atmegi
- niewielki dryf ie objawiłby się tak szybko. No chyba, że jeszcze zegar
w RasPi ma tak tragiczną stabilność.
Gdzie mogę szukać przyczyn takiego zachowania?
Marek
Guest
Wed Nov 12, 2014 9:12 am
On Wed, 12 Nov 2014 01:35:22 +0100, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Nie wydaje mi się, żeby mogło to wynikać z niedokładności timera
Atmegi
- niewielki dryf ie objawiłby się tak szybko. No chyba, że jeszcze
zegar
w RasPi ma tak tragiczną stabilność.
Czy raspi ma synchroniziwany zegar? Bo nie rozumiem co mierzysz
teraz. Dokładność zegara w tym Twoim urządzeniu czy niedokładnośc
raspi?
--
Marek
Andrzej W.
Guest
Wed Nov 12, 2014 9:45 am
W dniu 2014-11-12 o 01:35, Atlantis pisze:
Quote:
Eksperymentowałem ostatnio z synchronizacją czasu w układzie z Atmegą i
ENC28J60.
A obsługujesz poprawnie zapis i odczyt wartości większych niż 8 bitów?
Wyłączenie/włączenie przerwań na czas zapisu i odczytu?
Tu bym zaczął, sprawdził bym też czy na pewno w obliczeniach używasz
zmiennych o odpowiedniej wielkości, czy są ze znakiem itd.
--
AWa.
Atlantis
Guest
Wed Nov 12, 2014 9:45 am
W dniu 2014-11-12 09:12, Marek pisze:
Quote:
Czy raspi ma synchroniziwany zegar? Bo nie rozumiem co mierzysz teraz.
Dokładność zegara w tym Twoim urządzeniu czy niedokładnośc raspi?
Musi mieć. RasPi w fabrycznej konfiguracji nie ma nawet RTC - czas brany
jest z NTP przy starcie systemu.
Marek
Guest
Wed Nov 12, 2014 10:36 am
On Wed, 12 Nov 2014 09:45:37 +0100, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Musi mieć. RasPi w fabrycznej konfiguracji nie ma nawet RTC - czas
brany
jest z NTP przy starcie systemu.
Ale co ile ta synch. później po starcie jest? Bo to normalne, że jak
będzie rzadko to się szybko rozjedzie (czas jest liczony bo zwykłym
przerwaniu timera), linux w raspi nie jest rt, przynajmniej w
najpupolarniejszych dtstrybucjach dla raspi. Badasz względem siebie
dwa niepewne urządzenia. Najpierw sprawdź to z encj wzgl. zaufanego
wzorca czasu, później raspi wzgl. tego wzorca, dopiero wtedy wyciągaj
wnioski.
--
Marek
Atlantis
Guest
Wed Nov 12, 2014 10:54 am
W dniu 2014-11-12 10:36, Marek pisze:
Quote:
Ale co ile ta synch. później po starcie jest? Bo to normalne, że jak
będzie rzadko to się szybko rozjedzie (czas jest liczony bo zwykłym
przerwaniu timera), linux w raspi nie jest rt, przynajmniej w
najpupolarniejszych dtstrybucjach dla raspi.
Zdaje sobie z tego sprawę. Jednak minuta dryfu na godzinę!?
Atlantis
Guest
Wed Nov 12, 2014 11:18 am
W dniu 2014-11-12 09:45, Andrzej W. pisze:
Quote:
A obsługujesz poprawnie zapis i odczyt wartości większych niż 8 bitów?
Jak mam to rozumieć?
Quote:
Wyłączenie/włączenie przerwań na czas zapisu i odczytu?
Dodałem cli() i sei() w każdej partii kodu, gdzie pojawia się odwołanie
do zmiennej rtc. Nie wydaje mi się, żeby pomogło.
Quote:
Tu bym zaczął, sprawdził bym też czy na pewno w obliczeniach używasz
zmiennych o odpowiedniej wielkości, czy są ze znakiem itd.
Zmienna rtc to volatile uint32_t.
Obliczanie jej wartości na podstawie informacji z pakietu (jak już
wspominałem) wygląda następująco:
*time = ( ( ((uint32_t)buf[0x52]<<24) | ((uint32_t)buf[0x53]<<16) |
((uint32_t)buf[0x54]<<

| ((uint32_t)buf[0x55]) ) - 2208988800UL );
"time" to po prostu wskaźnik przekazujący wynik obliczeń wykonywanych
wewnątrz funkcji.
Atlantis
Guest
Wed Nov 12, 2014 12:10 pm
Hmm.... Wygląda na to, że Raspberry Pi pokazuje dokładnie ten sam czas,
który widać np. na epochconverter.com albo currenttimestamp.com.
To na układzie z Atmegą pojawia się jakaś dziwna różnica, wynosząca od
kilku do kilkudziesięciu sekund. Mam wrażenie, że nie narasta ona w
wyniku dryfu wprowadzanego przez timer - zwykle jest ona widoczna już po
aktualizacji czasu, którą mogę też inicjować ręcznie.
Kod funkcji analizującej pakiet NTP w tej chwili wygląda następująco:
uint8_t client_ntp_process_answer(uint8_t *buf, volatile uint32_t
*time,uint8_t dstport_l){
uint32_t tm_temp=0;
if (dstport_l){
if (buf[UDP_DST_PORT_L_P]!=dstport_l){
return(0);
}
}
if (buf[UDP_LEN_H_P]!=0 || buf[UDP_LEN_L_P]!=56 ||
buf[UDP_SRC_PORT_L_P]!=0x7b){
// not ntp
return(0);
}
// copy time from the transmit time stamp field:
tm_temp = ( ((uint32_t)buf[0x52]<<24) | ((uint32_t)buf[0x53]<<16) |
((uint32_t)buf[0x54]<<

| ((uint32_t)buf[0x55]) );
tm_temp -= 2208988800UL;
cli();
*time = tm_temp;
//*time = ( ( ((uint32_t)buf[0x52]<<24) |
((uint32_t)buf[0x53]<<16) | ((uint32_t)buf[0x54]<<

|
((uint32_t)buf[0x55]) ) - 2208988800UL ); //0x83AA7E80
sei();
return(1);
}
J.F.
Guest
Wed Nov 12, 2014 12:17 pm
Użytkownik "Atlantis" napisał w wiadomości
W dniu 2014-11-12 10:36, Marek pisze:
Quote:
Ale co ile ta synch. później po starcie jest? Bo to normalne, że
jak
będzie rzadko to się szybko rozjedzie (czas jest liczony bo zwykłym
przerwaniu timera), linux w raspi nie jest rt, przynajmniej w
najpupolarniejszych dtstrybucjach dla raspi.
Zdaje sobie z tego sprawę. Jednak minuta dryfu na godzinę!?
Rozumiem ze czas tam jest mierzony przerwaniem programowym na
podstawie czestotliwosci zegarowej uP.
Jest jakis mechanizm ze to przerwanie jest rowno generowane, i nie
wplywa np na niego opoznienie jego obsluzenia ?
Czestotliwosc zegarowa - jesli kwarcem, to powinna byc w miare
dokladna. Tak powiedzmy do 100ppm, jesli dales byle jakie elementy.
Czyli sekunda na trzy godziny.
Ale jesli to nie kwarc, tylko jakis gorszy oscylator, to kto wie czy
nie 1% dokladnosci. Ale to powinienes widziec ze dryfuje a nie skacze.
Porownujesz z jakims innym urzadzeniem ... ale jakim ?
Moze tam jest numer ze np odczytujesz koncowke 59 sekund, a minuty juz
po zmianie ...
J.
Andrzej W.
Guest
Wed Nov 12, 2014 12:36 pm
W dniu 2014-11-12 o 12:10, Atlantis pisze:
Quote:
Hmm.... Wygląda na to, że Raspberry Pi pokazuje dokładnie ten sam czas,
który widać np. na epochconverter.com albo currenttimestamp.com.
To na układzie z Atmegą pojawia się jakaś dziwna różnica, wynosząca od
kilku do kilkudziesięciu sekund. Mam wrażenie, że nie narasta ona w
wyniku dryfu wprowadzanego przez timer - zwykle jest ona widoczna już po
aktualizacji czasu, którą mogę też inicjować ręcznie.
Kod funkcji analizującej pakiet NTP w tej chwili wygląda następująco:
uint8_t client_ntp_process_answer(uint8_t *buf, volatile uint32_t
*time,uint8_t dstport_l){
uint32_t tm_temp=0;
if (dstport_l){
if (buf[UDP_DST_PORT_L_P]!=dstport_l){
return(0);
}
}
if (buf[UDP_LEN_H_P]!=0 || buf[UDP_LEN_L_P]!=56 ||
buf[UDP_SRC_PORT_L_P]!=0x7b){
// not ntp
return(0);
}
// copy time from the transmit time stamp field:
tm_temp = ( ((uint32_t)buf[0x52]<<24) | ((uint32_t)buf[0x53]<<16) |
((uint32_t)buf[0x54]<<

| ((uint32_t)buf[0x55]) );
tm_temp -= 2208988800UL;
cli();
*time = tm_temp;
//*time = ( ( ((uint32_t)buf[0x52]<<24) |
((uint32_t)buf[0x53]<<16) | ((uint32_t)buf[0x54]<<

|
((uint32_t)buf[0x55]) ) - 2208988800UL ); //0x83AA7E80
sei();
return(1);
}
Ten kod to interpretuje każdy pakiet UDP co ma 56 bajtów, tak?
Żeby czytać właściwy pakiet warto sprawdzić czy odpowiedź zawiera
znacznik czasu wysłany przez Ciebie w zapytaniu. (RFC4330 Originate
Timestamp).
Ja u siebie czytam czas z pozycji [40:43], widzę, że Ty czytasz [82:85].
Ten bufor to "czyste" dane z pakietu UDP, czy jest tam też jakiś
nagłówek? Bo czytasz znacznie dalej niż długość pakietu UDP.
--
AWa.
Atlantis
Guest
Wed Nov 12, 2014 12:43 pm
W dniu 2014-11-12 12:17, J.F. pisze:
Quote:
Rozumiem ze czas tam jest mierzony przerwaniem programowym na podstawie
czestotliwosci zegarowej uP.
Tak. Przerwanie TIMER0_COMPA_vect jest wywoływane co 10ms. W procedurze
jego obsługi inkrementowana jest zmienna. Jeśli jej wartość przekroczy
100, wykonywana jest instrukcja warunkowa wewnątrz której zwiększana
jest wartość zegara (a także obsługiwane jest kilka dodatkowych
programowych timerów).
Quote:
Czestotliwosc zegarowa - jesli kwarcem, to powinna byc w miare dokladna.
Tak powiedzmy do 100ppm, jesli dales byle jakie elementy.
Czyli sekunda na trzy godziny.
MCU jest taktowany sygnałem 12,5MHz, pochodzącym z układu ENC28J60 który
z kolei jest taktowany kwarcem 25 MHz. Niedokładność wedle mkAVR
Calculatora wynosi 0,06%.
Zresztą zachowanie układu wcale nie wygląda na dryf spowodowany
niedokładnością wzorca. Opóźnienie wynoszące od kilku do kilkudziesięciu
sekund często mam tuż po synchronizacji.
Quote:
Porownujesz z jakims innym urzadzeniem ... ale jakim ?
Porównałem z webowymi wzorcami (np. currenttimestamp.com). Pokazują
dokładnie to samo, co Raspberry Pi. Czas na Atmedze prawie zawsze różni
się o pewną liczbę sekund...
Quote:
Moze tam jest numer ze np odczytujesz koncowke 59 sekund, a minuty juz
po zmianie ...
Nie dokonuję konwersji na "human readable time". Zależy mi tylko na
timestampie, najlepiej w formacie Unix epoch.
Atlantis
Guest
Wed Nov 12, 2014 12:49 pm
W dniu 2014-11-12 12:36, Andrzej W. pisze:
Quote:
Ten kod to interpretuje każdy pakiet UDP co ma 56 bajtów, tak?
Sprawdza też jeszcze, czy zgadza się port.
Quote:
Ja u siebie czytam czas z pozycji [40:43], widzę, że Ty czytasz [82:85].
Ten bufor to "czyste" dane z pakietu UDP, czy jest tam też jakiś
nagłówek? Bo czytasz znacznie dalej niż długość pakietu UDP.
Z tego co pamiętam, to w buforze znajduje się kompletna ramka
Ethernet/MAC, pobrana bufora ENC28J60. Tuxgraphics to mocno uproszczony
stos, który operuje właśnie na pojedynczych ramkach i nie jest w stanie
obsługiwać dłuższych komunikatów.
W każdym razie nie sądzę, żeby tutaj leżała przyczyna. Gdyby do układu
"zabłąkał się" przypadkowy pakiet UDP o oczekiwanej długośc, wysłany na
oczekiwany port, to otrzymywałbym po prostu bezsensowne dane. Ja
tymczasem otrzymuję wartość zbliżoną do obecnego czasu, różniącą się o
tych kilka do kilkudziesięciu sekund.
Marek
Guest
Wed Nov 12, 2014 12:59 pm
On Wed, 12 Nov 2014 12:49:31 +0100, Atlantis <marekw1986NOSPAM@wp.pl>
wrote:
Quote:
Ja tymczasem otrzymuję wartość zbliżoną do obecnego czasu, różniącą
się o
tych kilka do kilkudziesięciu sekund.
Jesteś pewien, że prawidłowo interpretujesz otrzymane dane? Czy czas
z serwera ntp już jest przesunięty czy przesunięcie następuje podczas
lokalnego odczytu tuż po odbiorze (ta funkcja licząca *time)?
--
Marek
Atlantis
Guest
Wed Nov 12, 2014 1:49 pm
W dniu 2014-11-12 12:59, Marek pisze:
Quote:
Jesteś pewien, że prawidłowo interpretujesz otrzymane dane? Czy czas z
serwera ntp już jest przesunięty czy przesunięcie następuje podczas
lokalnego odczytu tuż po odbiorze (ta funkcja licząca *time)?
Tego właśnie nie wiem. W każdym razie patrzę na kod i nie widzę co
mogłoby być nie tak. Zastosowałem trochę inny, jaśniejszy sposób
przeliczania danych z bufora na timestamp:
uint32_t sec_since_1900 = 0;
(...)
sec_since_1900 = (uint32_t)buf[0x52] << 24;
sec_since_1900 |= (uint32_t)buf[0x53] << 16;
sec_since_1900 |= (uint32_t)buf[0x54] << 8;
sec_since_1900 |= (uint32_t)buf[0x55];
cli();
*time = (sec_since_1900 - 2208988800UL);
sei();
Efekt jest dokładnie taki sam.
Gdybym czytał dane z nieprawidłowych komórek bufora, to w efekcie
otrzymywałbym kompletnie bezsensowną wartość, a nie wynik różniący się
od obecnego czasu o kilka-kilkadziesiąt sekund.
Raspberry Pi jest synchronizowane z tego samego serwera czasu.
Andrzej W.
Guest
Wed Nov 12, 2014 2:01 pm
W dniu 2014-11-12 o 13:49, Atlantis pisze:
Quote:
Gdybym czytał dane z nieprawidłowych komórek bufora, to w efekcie
otrzymywałbym kompletnie bezsensowną wartość, a nie wynik różniący się
od obecnego czasu o kilka-kilkadziesiąt sekund.
W pakiecie SNTP masz chyba cztery różne znaczniki czasu, jakaś szansa na
to by odczytać coś sensownego z innej lokalizacji istnieje, jednak nie
spodziewał bym się tam różnicy 60 sekund a raczej jednej dwóch.
Chyba, że robisz wielokrotne uaktualnienie czasu i za każdym razem
wczytujesz czas nadania swojego zapytania (Originate Timestamp).
--
AWa.
Goto page 1, 2, 3, 4 Next