Synchronizer
| Name | In/Out | Width | Description |
|---|---|---|---|
| CLK | In | 1 | メインクロック |
| SYNC_SETTINGS | In | - | |
| ├─ UPDATE | In | 1 | 同期フラグ |
| └─ SYNC_TIME | In | 64 | 同期するデバイス時刻 (SYS_TIME 単位) |
| SYNC_IN | In | 1 | 同期パルス |
| SYS_TIME | Out | 57 | システム時刻 |
| SYNC | Out | 1 | 同期パルス検出フラグ |
| SKIP_ONE_ASSERT | Out | 1 | 1 飛ばしアサート |
| SYNC_TIME_DIFF | Out | 14 | 補正残量 (符号あり) |
| SYNC_RESYNC_COUNT | Out | 8 | 位相を取り直した回数 (255 で飽和) |
| PS_ENABLE | In | 1 | 細調整の有効フラグ |
| PS_FINE | Out | 1 | 細調整中フラグ |
| PS_EDGE | Out | 1 | 細調整のループを更新する同期パルスの検出 |
| PS_EDGE_DIFF | Out | 14 | その同期パルスでの位相カウンタのずれ (符号あり) |
Synchronizer は CPU のデバイス時刻に同期した時刻 SYS_TIME を生成するモジュールである.
超音波出力, Modulation, Emission 等はすべてこの SYS_TIME を時刻の基準にしている.
デバイス時刻がデバイス間で同期していれば, それらも必然的にすべてのデバイスで同期する.
このモジュールの動作を理解するためには, 以下の事柄を理解しておく必要がある.
- デバイス時刻 (CPU ボードの ETHSW タイマの時刻) は
単位の データである. - なお, 時刻基準は
Clientを開いた時点である.単位の なので約 600 年しか使えないが, 事実上問題ない.
- なお, 時刻基準は
- FPGA からは CPU ボードのデバイス時刻に直接アクセスできない.
- CPU ボードは一定の周期で同期パルス (
SYNC_IN) をアサートする. このパルスの立ち上がりはデバイス時刻を参照している. - 同期パルスの周期は
固定である. FPGA はこれを SYS_TIMEの単位に直した値 () を定数 params::SyncCycleTicksとして持つ
なお, SYS_TIME はデバイス時刻に同期しているが, その単位は
SYS_TIME の初回の時刻同期は CPU ファームウェアと協調して, 以下の手順で行われる.
- CPU: 次に同期パルスが立ち上がるデバイス時刻を求め, 以下の計算により
SYS_TIMEの単位に変換する. - CPU: 変換した値を
SYNC_TIMEとして FPGA 内の BRAM に書き込む.- ただしこの時, 現在時刻が立ち上がりの 1 周期以上前であれば, いったん待機する. これにより, 次の
UPDATEフラグが 1 つ手前の立ち上がりより後に届くことを保証する.
- ただしこの時, 現在時刻が立ち上がりの 1 周期以上前であれば, いったん待機する. これにより, 次の
- CPU: 同期の更新要求 (
SYNC_SET) を FPGA 内の BRAM に書き込む. Controller がこれを読んでSYNC_TIMEを取り込み,UPDATEフラグをアサートする. - FPGA:
UPDATEフラグを受けた後, 最初にSYNC_INが立ち上がったタイミングで,SYNC_TIMEをSYS_TIMEにセットする. - CPU: デバイス時刻を読み直し,
UPDATEフラグが書き込んだ立ち上がりより前に届いたことを確かめる. 間に合っていなければエラー (ERR_SYNC_MISSED) を返す (やり直すには Synchronize を送り直す).
以上により, FPGA 内部の SYS_TIME の時刻がデバイス時刻に同期する.
あとは, SYS_TIME をメインクロックでカウントアップすればいい.
しかし, 実際には FPGA のクロックを生成する水晶振動子には個体差があるため, SYS_TIME は徐々にずれていってしまう.
定期的に上記と同様のことを行って補正してもいいが, それは大変なので, 同期パルスが周期的に立ち上がるという性質を用いた別の補正方法を採用している.
同期パルスが立ち上がった際, SYS_TIME は前回の立ち上がりのときの値に, 同期パルスの周期 (SyncCycleTicks) を足した値になっているはずである.
そこで, メインクロックでインクリメントされ, SyncCycleTicks で 0 に戻る位相カウンタを持つ.
このカウンタは, ずれが無ければ立ち上がりのときに 0 に戻っているはずである.
ずれがあると, 同期パルスの立ち上がりの時点のカウンタの値 SYS_TIME が遅れていること, 負の値は進んでいることを表す.
SYS_TIME の補正は, SYS_TIME が基準より進んでいる場合 (即ち, 水晶振動子の周波数が基準より高い場合) は SYS_TIME のインクリメントを止め, SYS_TIME が遅れている場合 (即ち, 水晶振動子の周波数が基準より低い場合) は SYS_TIME を SYS_TIME は逆戻りすることはないが, 一つ飛ばしでカウントアップされる可能性がある.
一つ飛ばしが発生した際は SKIP_ONE_ASSERT をアサートする.
補正の残量は SYNC_TIME_DIFF として出力され, デバッグ用に GPIO Output から観測できる.
位相カウンタのリセット
Section titled “位相カウンタのリセット”立ち上がりの時点のずれが
初回同期の後に位相カウンタをリセットした回数は SYNC_RESYNC_COUNT として出力される.
補正タイミングの分散
Section titled “補正タイミングの分散”補正を同期パルスの立ち上がり直後に集中して行うと, 同期パルスの周期に由来する周期的なノイズが生じる.
同期パルスの周期は SYS_TIME の 1 単位ずつ行う.
(とはいえ実際にはこのノイズはほとんど聞こえない)
細調整 (位相ロック)
Section titled “細調整 (位相ロック)”上記の補正は SYS_TIME を 1 単位 (
細調整は, メインクロックを生成する MMCM の dynamic fine phase shift でクロックの位相そのものを動かし, 同期パルスの立ち上がりにクロックの立ち上がりを合わせる (位相ロック).
既定で有効で, SetFpgaConfig の sync_phase_lock で無効にできる.
4 台の実測で, デバイス間の出力のずれは標準偏差約
MMCM は入力
位相検出とループ
Section titled “位相検出とループ”細調整中は上記の SYS_TIME の補正を止め, 同期パルスの立ち上がりで見た位相カウンタのずれ
同期パルスごと (
- 細調整中:
, - 細調整外で
: , - それ以外: 更新しない
sync_kp, sync_ki, sync_kf で設定する (既定値は 64, 1024, 4096).
細調整に入ってから安定するまでは約