pondělí 10. srpna 2026

blog se přestěhoval...

Začátkem srpna 2026 se blog přestěhoval na novou adresu.
Mělo by automaticky dojít k přeměrování na novou adresu, pokud se to nestalo, musíte kliknout ručně.

 tyfoza.github.io

Všechny nové články od začátku srpna 2026 už budou přibývat pouze na nové adrese. 



úterý 4. srpna 2026

Kalibrace DS3231

Úprava přesnosti hodin nastavením registru 0x10 (Aging Offset) pro kompenzaci stárnutí krystalu.
    Tester[1] mně pomohl jednoduše roztřídil moduly na ty, co nemají kompenzaci nebo mají příliš ujetou frekvenci Zůstaly moduly s funkční teplotní kompenzací a stabilní frekvencí, žel jsou frekvenčně posunuté o ±2 až ±3 ppm, což by mělo jít vyřešit. DS3231 má registr 0x10 (Aging Offset) pro kompenzaci stárnutí krystalu. 

    Tohle laboratorní cvičení se neobejde bez přesného čítače frekvence. Měření [mikrokontrolerem] je dobré na relativní měření; měří přesně a opakovaně; ale na absolutní čísla to není. Je to jako měření plastovým pravítkem, které někdo nahřál a roztáhl. Měří pořád stejně přesně, ale oproti realitě je měření posunuté.

Zde nastupuje 40 let starý PM6654, má rozlišení 2ns a poslední kalibrací prošel v lednu 2026. Vstup 1MΩ; Pin 32K připojen osciloskopickou sondou (nastaveno na 10:1)

Komunikace po I²C

    Raspberry Pi Pico (nebo jakýkoli jiný MCU) má na I²C připojený měřený modul a dělá komunikační rozhraní pro Python. Komunikuje pomocí jednoduchých textových příkazů posílaných po sériové lince. Dá se používat pohodlně ze sériového monitoru z Arduino IDE:
Mám tu [CP2112],  který jsem potřeboval pro  komunikaci s baterií notebooku, ale rozdělit komunikaci na python ↔ měřák | python ↔ pico | pico ↔ modul se bude lépe ladit.

pico_DS3231_I2C_Full_Manager.ino [ke stažení]
obsahuje komunikaci po sériovém rozhraní, komunikuje se textovými příkazy

příkaz HELP vypíše možnosti

Kalibrátor v Pythonu

AR488-PM6654-DS3231-calibrator.py [ke stažení]
– Načte hodnotu kompenzačního offsetu z registru.
– Provede měření před kalibrací
    Po GBIP čte stav čítače (např. FA 32.76805515E+3). Délku měření volím 360 sekund. Čítač má nastavenou dobu „hradlování“ gate na 10s, tj. čas po který průměruje měření než ho odešle.
– Spočte kalibrační offset a po I²C uloží. Registr 0x10 je 8bitový; rozsah od -127 do +127, kde 1 krok je 0,1ppm; která se přičítá nebo odečítá
– Provede měření po kalibraci
– Počítá základní statistiky
– Kreslí graf


po třech iteracích lze dosáhnout pěkné přesnosti
(z chyby 10s za měsíc na chybu 10s za rok)

Ppm po kalibraci říká chybu 0.5s za rok!

Výpadek napájení smaže kalibraci

    Zápis do registru 0x10 není navždy, při odpojení baterie a ztrátě napájení se smázne a vynuluje. Většinu modulů, co se snažím zkalibrovat mám v šuplíku bez záložní baterie. Proto hledám řešení jiné, než moduly očíslovat a vést si tabulku kompenzací, kterou tam nastavím až budu modul potřebovat. Naštěstí má modul ZM-042 nebo HW-084[2] na sobě má EEPROM na I²C adrese 0x57. Komunikační rozhraní pico_DS3231_I2C_Full_Manager.ino zajistí, že při uložení kalibrace do DS3231 zároveň uloží do EEPROM stejnou informaci a když stejným komunikačním rozhraním ověřím příkazem PING, jestli DS3231 komunikuje, tak si načte infromaci o kalibraci, pokud je tam uložená. 
    Je to krok stranou pro to, abych mohl kalibrovat bez nutnosti záložní baterie. Až budu modul potřebovat, dám baterii, načtu uloženou kalibraci z EEPROM a dál už to bude jen na záložní baterii.

Další čtení

    Jak se kalibrují čítače [PDF] [zdroj]

Trocha deskriptivní statistiky

Z měření, které program čte po GPIB se počítají zajímavé popisné statistiky

– Ochylka v ppm[1] je relativní odchylka průměrné frekvence od ideální hodnota 32768.0 Hz
–  Směrodatná odchylka[2] ukáže rozptyl hodnot kolem průměru. V našem případě vidíme, jestli jsme ve stabilním prostředí.

– Jitter[3] je maximální rozkmit. Ukazuje rozdíl mezi nejvyšší a nejnižší naměřenou frekvencí. Ukazuje hned nejhorší měření, je to přesně opak průměrování.

– Časový drift jenom přepočítává relativní chybu ppm na reálný čas. Třeba pro den (86400s) se spočte 86400 × (PPM / 1E6)

Jaký je šum zdroje signálu

Kalibrace nám nepomůže se šumem samotného krystalu. Ale informace o něm považuji za zajímavé. V kalibračním programu počítame i Allan Dev

– Allanova odchylka je informace o stabilitě oscilátoru. Udává se v ppb.
    Pro moje měření v 10s balíčcích
< 10 ppb ... čip je v optimálním a klidném prostředí
10 až 50 ppb ... pokoj s prouděním vzduchu
50 až 100 ppb ... nadměrný šum, to už je něco špatně (krystal vedle ventilátoru = mechanické vibrace; nestabilní napájení; vadný čip)

Jak to číst, když měření vyjde třeba 8ppb
    Kolísání frekvence mezi dvěmi sousedními 10s měřemi bylo 8 miliardtin. Pro frekvenci 32768Hz

    Allanova odchylka měří stabilitu (šum), jak moc krystal náhodně plave v krátkodobém časovém horizontu; proto kalibrace na toto měření nebude mít vliv. Běžná směrodatná odchylka předpokládá, že celkový průměr se nemění. Allanova odchylka vyhodnocuje rozdíly mezi sousedícími vzorky. Tím odfiltruje pomalý drift a ukáže čistý krátkodobý šum krystalu. Výsledek se násobí 1E9 a uvádí se v ppb. 

Napsat definici, tak to zabiju hned na začátku: Allanova odchylka je druhá odmocnina z Allanova rozptylu[4]. Vzah je stejný jako mezi směrodatnou odchylkou a rozptylem. 

Takto se běžně zapíše vzorec, který mně není na první pohled jasný

tohle si musím přepsat, abych to viděl jasněji; jsem hrubě podprůměrný matematik

a teď si vzorec přečtu:
– odchylka σ pro časové okno měření τ 
– N počet naměřených vzorků
– i je index vzorku, suma v cyklu běží od i=1 do N–1
– yᵢ říká jak moc se naměřený vzorek fᵢ liší od ideální hodnoty fₙₒₘ (32768Hz). Čitatel (fᵢ –fₙₒₘ) dává chybu v Hz a jmenovatel /fₙₒₘ vykrátíme jednotky, aby vzniklo pouze bezrozměrné číslo (poměr). Říkáme tomu zlomková frekvence.
– sčítáme rozdíly sousedních vzorků; to mocnění je tady proto, aby nám kladné a záporné rozdíly neodčítaly. Prostě sčítáme plochy jednotlivých výkyvů frekvence.
– průměr ze všech výkyvů frekvence meti vzorky, tedy dělíme N–1, tj. vypočteme průměrný čtverec rozdílu mezi dvěma měřeními; počítáme z dvojic měření (100 vzorků udělá 99 rozdílů)
– 1/2 Proč z toho průměru bereme jen polovinu? Tohle je jediná neintuitivní věc z celého vzorce. Když odečteme dva šumy od sebe, tak se energie šumu sečte; statistik by řekl, že odečtením dvou náhodných veličin se rozpyty (zde energie šumu) nevyruší, ale sečtou. Nejistota (šum) nemůže být záporná. Protože počítáme rozdíl dvou proměnných, jejichž šum je nezávislý, rozptyl (šum) tohoto rozdílu se uměle zdvojnásobí; průměr z těchto měření vyjde taky dvojnásobný, proto musíme vzít jen polovinu, abychom dostali skutečnou fyzikální úroveň šumu

– celé to odmocníme abychom se vrátili z energie šumu do amplitudy šumu; při sčítání se to mocnilo proto, aby všechny rozdíly byly kladné; tím jsme ale změnili jednotku na ppb², která je k ničemu. Odmocněním to vrátíme zpátky.

Pro úplnost shrnutí, že ADEV = sqrt(AVAR)
Allanův rozptyl[5] (AVAR)

Allanova odchylka (ADEV)

Podrobnější výklad viz str. 5 [Vigner/2017] kapitola 2.2 o měření časové a frekvenční stability.


Co DS3231 ukáže ve spektrální oblasti
32768Hz je frekvence a přesně 1024Hz od ní vidím fázový šum.
Toto rušení je produkt vnitřní děličky v čipu.

    Zúžení rozlišovacího filtru zjemní náhled. Vidíme stabilní frekvenci uprostřed a nežádoucí signály (spurs) po stranách.

    Lze si prohlédnout pouze polovinu grafu od špičky směrem doprava. Šumový graf.

    Sukýnka kolem nosné frekvence je symetrická. Vezmu jen pravou polovinu toho grafu a rozbalím si ji do logaritmické stupnice. Vrchol meřeného signálu (32768) je teď v 0Hz a směrem doprava se posunujeme po grafu. Výhoda je, že rozsah 10Hz – 100Hz má na šumovém grafu stejný prosto jako 1Khz –  100kHz.
    Jednotka dBc/Hz jsou dB „realative to Carrier“, což chápu jako „decibely pod špičkou“.
„Hloubka v dBc/Hz pod špičkou“ udává, o kolik decibelů je šum v okně 1Hz slabší než celkový výkon užitečného signálu.Čím hlouběji pod špičkou = čím je číslo zápornější, tím čistsí a kvalitnějí je sledovaný signál.



pondělí 3. srpna 2026

Tester DS3231

    Zadání: Budeme přesně měřit předpokládanou frekvenci krystalu 32768,0Hz modulu [DS3231]. Pak čip zahřejeme – stačí přiložit prst – dojde k teplotnímu dritfu (třeba jen 0.025Hz) tuto malinkou změnu frekvence detekujeme. Vyvoláme nucenou teplotní kompenzaci a ověříme, jestli proběhla.
    pico_DS3231_tester.ino [k náhledu] [ke stažení] 

    Dílčí úkol: Přesné měření frekvence mikrokontrolerem. Procesor RP2040 s PIO stavovými automaty jako reciproční frekvenční čítač. Řešení jsem našel, ale úplně snadná cesta to nebyla viz článek [reciproční frekvenční čítač].

Jak oddělit zrno od plev

    Chceme ověřit, že křemíkové srdce DS3231 tepe na správné frekvenci a změřit, že čip má funkční teplotní kompenzaci. Potřeboval jsem přesný čas do pár drobných projektů, vylovil jsem ze šuplíku pár kusů modulů a pak jsem zjistil, že některé vůbec nejsou tak přesné jak by měly být. Ne každý čip je originál a ne každý klon je funkčním klonem.

    DS3231 má vyvedený pin 32K, kde se po zapnutí napájení objeví aktuální takt krystalu. V ideálním světě by byl přesně 32768.0 Hz

Ideální hodinový takt byl-li by, byl by takto krásný.

    Tedy připojím k čítači, zahřeju s vidím, jestli se frekvence srovná... Ale to je zdlouhavé a není to plně prokazatelné a opakovatelné měření. Navíc, kdo má na stole čítač frekvence?
Postavme tester DS3231. Čip má automatickou teplotní kompenzaci každý 64 sekund nebo ji lze vyvolat příkazem.
reálná frekvence na které tepe krystal uvnitř čipu

Tester DS3231 na Raspberry Pi Pico (RP2040)

    Modul testujeme bez baterie. Po připojení RP2040 k USB dostane napájení. Tím bude zajištěno, že první automatická teplotní kompenzace přijde za 64 sekund. Za tu dobu stihneme měření. Tester komunikuje textově do sériového terminálu.

Připojení modulu ZS-042 nebo HW-084 k Raspberry Pi Pico
  32K ... GP17    (pin číslo 22)
  SWQ ... nepřipojujeme
  SCL ... GP5     (pin číslo 7)
  SDA ... GP4     (pin číslo 6)
  GND ... GND     (pin číslo 38)
  VCC ... 3V3 Out (pin číslo 36)

Další info k logice programu a měření obsahují podrobné komentáře viz [pico_DS3231_tester]. Je nezbytné mít vyřešený reciproční frekvenční čítač viz [blog].

Mezi asi dvaceti hodinovými moduly jsem našel šest vadných, co měly už při startu ujetou frekvenci a pak jeden, který nereagoval na teplotní kompenzaci a jak se zahřál, tak už měl frekvenci mimo už od začátku.


úspěšný test



selhání s frekvencí mimo toleranci

frekvence plave už od začátku


sobota 1. srpna 2026

Frekvenční čítač přímý nebo reciproční?

Frekvenční čítač má změřit frekvenci vstupního signálu. Na Raspberry Pi Pico (RP2040) postavíme frekvenční čítač, který měří do 70MHz. Umí být přesný i pro frekvence menší než 100kHz.

pico_citac_autorange.ino [ke stažení] 

    Komunikuje přes sériový monitor.  Při spuštění vyžaduje zadat hledanou frekvenci, kterou měříme, aby mohl dopočítat chybu ppm. Pokud zadáme 0, tak se spustí automatické měření, které zobrazí pouze frekvenci, kdy změří frekvenci vstupního signálu pomocí PWM periferie a pokud vychází menší než 100kHz zvolí přesnější metodu recipročního měření frekvence.

hledáme 70MHz


Přímé měření frekvence 

    Obvykle si čítač frekvence představím tak, že po stanovenou dobu počítame náběžné hrany signálu a pak spočteme frekvenci. Obecně N pulzů za t sekund f = N/t. Když budeme počítat pulzy po dobu jedné sekundy, tak počet hran je roven frekvenci v Hz. 

Přímý frekvenční čítač pomocí Raspberry Pi Pico (RP2040)

    Použijeme periferii PWM, procesor má 8 nezávislých bloků, každý blok má 2 kanály (A,B).  Každý blok je 16bitový čítač (0 – 65535). Čítač bloku B nemusí tikat podle systémových hodin, ale dá se přepnout do režimu, kdy se inkrementuje pouze, když přijde náběžná hrana pulzu z vnějšího zdroje.
    Drobné hardwarové omezení je, že počítání hran funguje výhradně na kanálu B, což jsou liché piny GPIO. Aby nám fungovalo počítání frekvence musíme vyřešit přetečení. PWM registr má jen 16bitů, takže když napočítá do 65535, musí vyvolat přerušení a inkrementovat 32bitovou proměnnou.
    Finální počet pulzů získáme jako počet přetečení × 65536 + zbytek, který zůstal v hardwarovém čítači.
Více v komentářích přímo v programu viz [pico_primy_citac].

Problém pomalých signálů

    Možný problém u měření pomalých signálů je kvantizační šum. Vstupní signál měříme procesorem. Hodinový takt procesoru není nijak synchronizován či jinak propojen s generátorem vstupního signálu. Na okrajích měřícího okna se může dít to, že pokud se hrana signálu objeví před zavřením počítacího okna, napočítáme N pulzů, ale pokud hrana uteče třeba jen o nanosekundu až po zavření okna, už napočítáme N–1 pulsů. Chybě říkáme ±1 count error.   


f vstupního signálu v Hz
t čas měření v sekundách

pro signál 10Hz měřený v okně 1s
1/10=0,1=10% 
ppm je 0,1 × 1E6 =  ±100000ppm

Reciproční měření frekvence

    Otočíme logiku měření. Nečekáme až se pomalé pulzy naskládají do časového okna, ale pomalý signál je časové okno do kterého natlačíme takty interních hodin procesoru. Kvantizanční chyba bude záviset pouze na frekvenci procesoru a délce měření.
f cpu v Hz
t čas měření v sekundách

pro signál 10Hz a takt procesoru 200MHz, délka meření 1s
10Hz za sekundu má 10 period
takt procesoru trvá 5ns, za sekundu napočítá 20 000 000 taktů
±1 pulz bude nejistota 1/20000000= 0,00000005 
ppm je 0,00000005 × 1E6 = ±0,05ppm 
Srovnejme s předchozí chybou ±100000ppm. Ano, je to opravdu o tolik lepší!

Příklad praktický, měření hodinového krystalu

signál 32768Hz měřený v okně 16 sekund

Přímé měření
počet napočítaných pulsů 32768 × 16 = 524 288
chyba ±1 pulz ≈ 1/524288 = 1,9073486E-6 
ppm 1,9073486E-6 × 1E6 = ±1,91ppm
1,9073486E-6 × 32768= ±0,0625Hz (to je minimální krok s jakým umí přímý čítač měřit; tedy menší odchylka např 0,01Hz se ztratí v kvantizačním šumu)

Reciproční měření
kvantizační chyba ±1 takt procesoru ±1/(200E6 × 16)= 3,125E-10 
ppm je 3,125E-10 × 1E6 = ±0,0003125ppm
odchylka Hz 3,125E-10 × 32768 = ±0, 00001024Hz

Charakteristiky čítačů viz [kapitola 3].
Pro přesné měření nízkých frekvencí (cca do 100kHz) je výhodnější použít reciproční frekvenční čítač, který dosahuje výrazně vyšší přesnosti.

Reciproční frekvenční čítač pomocí Raspberry Pico (RP2040)

RP2040 má programovatelné stavové automaty PIO, které běží deterministicky. Jsou zcela nezávislé na procesoru. Takt PIO je takt procesoru, při 200MHz je to 5ns. 

Přesnému změření délky jedné celé periody vstupního signálu (tedy doby, po kterou je signál ve stavu HIGH + doby ve stavu LOW) pomocí počítání hodinových taktů mikrokontroléru. Program funguje tak, že si nastaví počítadlo (registr X) na maximum a neustále od něj odečítá jedničku, dokud se nedokončí celá jedna perioda signálu.


 0: wait 0 pin 0 
 1: wait 1 pin 0 
 2: set x, 0       
 3: mov x, ~x      
 4: jmp pin 6      
 5: jmp 8          
 6: nop            
 7: jmp x-- 4      
 8: jmp pin 11     
 9: jmp 10         
10: jmp x-- 8      
11: mov isr, x     
12: push           

Jak to přesně funguje?
0: wait 0 pin 0
Synchronizace
PIO automat čeká, dokud měřený pin (index 0) neklesne do logické nuly (LOW). Pokud už na nule je, okamžitě pokračuje dál. Zajišťuje to, že měření nezačne uprostřed již probíhajícího pulzu.
1: wait 1 pin 0
Detekce startu měření
Automat vyčkává na náběžnou hranu – okamžik, kdy se pin překlopí z logické 0 na logickou 1 (HIGH). Přesně v tento moment začíná nová perioda a odstartuje se počítání.
2: set x, 0
Inicializace počítadla
Nastaví hodnotu v interním 32bitovém pracovním registru X na nulu (0x00000000).
3: mov x, ~x
Příprava maxima
Provede bitovou inverzi registru X. Ze samých nul se rázem stane maximální 32bitová hodnota, tedy 0xFFFFFFFF (desítkově 4 294 967 295). Registr se používá jako odpočítávadlo (od maxima směrem dolů).
4: jmp pin 6
Smyčka pro úroveň HIGH
Zkontroluje aktuální stav pinu, který byl nastaven jako skokový (jmp_pin v C kódu). Pokud je na pinu stále logická 1, program skočí na instrukci 6. Pokud je na pinu už logická 0 (začala druhá půlka periody), instrukce neprovede skok a program pokračuje na řádek 5.
5: jmp 8
Opuštění HIGH smyčky
Tento řádek se vykoná pouze ve chvíli, kdy měřený signál spadl z HIGH do LOW. Jedná se o nepodmíněný skok na instrukci 8, čímž se opustí první měřící smyčka a plynule se přejde do druhé měřící smyčky.
6: nop
Vyrovnání taktu (Smyčka HIGH)
Prázdná operace (No Operation), která nedělá nic, ale spotřebuje přesně 1 hodinový takt procesoru. Slouží k tomu, aby jeden oběh HIGH smyčky trval přesně stejný počet taktů bez ohledu na to, kudy kód prochází (udržuje precizní a konstantní časování celého čítače).
7: jmp x-- 4
Odkrojení taktu (Smyčka HIGH)
Sníží hodnotu v registru X o 1 (dekrementuje). Následně skočí zpět na instrukci 4, čímž uzavírá smyčku, která počítá takty, dokud je signál v úrovni HIGH.
8: jmp pin 11
Smyčka pro úroveň LOW
Jsme v měření úseku, kdy je signál dole (LOW). Tato instrukce se ptá: "Naskočil už signál znovu na logickou 1?" Pokud ano (detekována další náběžná hrana = celá perioda je u konce!), skočí se na instrukci 11 a měření se ukončí. Dokud je signál stále v nule, pokračuje se dál na řádek 9.
9: jmp 10
Vyrovnání taktu (Smyčka LOW)
Znovu trik pro udržení stejného počtu taktů. Skočením rovnou na následující řádek 10 se úmyslně spotřebují (spálí) hodinové takty procesoru, aby byla délka LOW smyčky naprosto symetrická (trvala stejný čas) jako HIGH smyčka výše.
10: jmp x-- 8
Odkrojení taktu (Smyčka LOW)
Sníží hodnotu v registru X o 1 a skočí zpět na instrukci 8. Toto uzavírá smyčku, která běží po celou dobu, kdy je signál na logické nule.
11: mov isr, x
Uložení výsledku
Jakmile perioda skončila (na pinu se objevila jednička), program se dostal sem. Hodnota z registru X (od čísla 0xFFFFFFFF se mezitím v obou smyčkách odečetl počet uplynulých taktů procesoru) se překopíruje do vstupního posuvného registru (ISR).
12: push
Odeslání výsledku
Hodnota z ISR se protlačí do RX FIFO paměťové fronty. Z této paměti si už výsledek přečte hlavní C kód (pio_sm_get). Po provedení push se program – díky wrap v hlavním programu – automaticky a bez jakéhokoliv zdržení zacyklí zpět na začátek měření pro další periodu.

Další informace jsou v komentářích viz program [pico_reciprocni_citac] pro Arduino IDE.

blog se přestěhoval...

Začátkem srpna 2026 se blog přestěhoval na novou adresu. Mělo by automaticky dojít k přeměrování na novou adresu, pokud se to nestalo, musít...