Synchronizer
Name | In/Out | Width | Description |
---|---|---|---|
CLK | In | 1 | メインクロック |
SETTINGS | In | - | |
├─ UPDATE | In | 1 | 同期フラグ |
└─ ECAT_SYNC_TIME | In | 64 | 同期EtherCAT時刻 |
ECAT_SYNC | In | 1 | EtherCAT Sync0信号 |
SYS_TIME | Out | 57 | システム時刻 |
SKIP_ONE_ASSERT | Out | 1 | 1飛ばしアサート |
Synchronizerはすべてのデバイスで同期した時刻SYS_TIME
を生成するモジュールである.
超音波出力, Modulation, STM等はすべてこのSYS_TIME
を時刻の基準にしている.
したがって, それらも必然的にすべてのデバイスで同期する.
このモジュールの動作を理解するためには, 以下の事柄を理解しておく必要がある.
- EtherCATのシステム時刻は単位のデータであり, これはすべてのEtherCATスレーブで同期している.
- なお, 時刻基準は2000年1月1日である. 単位のなので約600年しか使えないが, 事実上問題ない.
- FPGAからはEtherCATスレーブ (CPUボード) のレジスタに書き込まれているシステム時刻に直接アクセスできない.
- EtherCATスレーブは一定の周期でSync0信号 (
ECAT_SYNC
) をアサートできる. この信号の発火はシステム時刻を参照しているので, すべてのデバイスで同期している. - Sync0信号が発火する周期はの整数倍である.
なお, SYS_TIME
はEtherCATのシステム時刻に同期しているが, その単位はで, となっている.
NOTE:
SYS_TIME
をにしたのは可能な限り使用リソースを少なくするためである. これにより, オーバーフローまでの期限がEtherCATそのものより短く, 約223年となるが, これも事実上問題ないだろう.
まず, SYS_TIME
の初回の時刻同期はCPUファームウェアと協調して, 以下の手順で行われる.
- CPU: 次のSync0信号が発火するシステム時刻
ECAT_SYNC_TIME
を読み出し, FPGA内のBRAMに書き込む.- ただしこの時, 現在時刻が
ECAT_SYNC_TIME
に近すぎる場合は, いったん待機する. これにより, 次のUPDATE
フラグの書き込み/読み出しがECAT_SYNC_TIME
より前に行われることを保証する.
- ただしこの時, 現在時刻が
- CPU:
UPDATE
フラグをFPGA内のBRAMに書き込む. - FPGA: 以下の計算により, 時刻単位を変換しておく.
- FPGA:
UPDATE
フラグがアサートされている, かつ,ECAT_SYNC
がアサートされたタイミングで, 単位変換済みのECAT_SYNC_TIME
をSYS_TIME
にセットする.
以上により, FPGA内部のSYS_TIME
の時刻がEtherCATのシステム時刻に同期する.
NOTE: ただ単にデバイス間を同期することが目的なのであれば, FPGA内部の時刻をEtherCATのシステム時刻に同期する必要はない. そのため,
UPDATE
フラグがアサートされている, かつ,ECAT_SYNC
がアサートされたタイミングでSYS_TIME
をに初期化すれば良い気もするが, これは正しくない. というのも, EtherCATスレーブのシステム時刻とSync0信号は同期しているが, それ以外の動作が同期している保証はないためである. つまり,UPDATE
フラグがアサートされるタイミングはすべてのデバイスで異なる可能性がある.
あとは, SYS_TIME
をメインクロックでカウントアップすればいい.
しかし, 実際にはFPGAのクロックを生成する水晶振動子には個体差があるため, SYS_TIME
は徐々にずれていってしまう.
定期的に上記と同様のことを行って補正してもいいが, それは大変なので, Sync0信号が周期的かつ同期的に発火するという性質を用いた別の補正方法を採用した.
まずは, Sync0信号がの間隔で発火する場合を考えよう.
この場合, Sync0信号が発火した際, SYS_TIME
は前回Sync0信号が発火したときの値にを足した値になっているはずである.
したがって, Sync0信号が発火した際に, この本来あるべき値と実際の値を比較して補正できる.
Sync0信号がの間隔で発火する場合は, を推定する必要がある1. これは, Sync0信号の発火タイミングから推定できる. Sync0信号の発火タイミングで, カウンタをで初期化した後, これをメインクロックでカウントアップする. そして, 次にSync0信号の発火タイミングでを で推定する. この推定が正しくなる条件を求めてみる. FPGAの実際のクロック周波数がであるとすると, となる. これが正しくになるためには, から, を満たせば良い (十分条件. なお, の場合は常に満たされる.). AUTD3デバイスで使用している水晶振動子 (SG-8002CE-25.6M-PCB-L2, EPSON) の周波数は, トレランスはである. これから生成されるクロックを, FPGA内蔵のMixed-Mode Clock Manager (MMCM) で変換したものをメインクロックとして使用している. トレランスは不変と仮定すると2, の最大値は となる. このときの条件は, である. 実際には, 10台ほどのデバイスを接続したとしてもで動作するので, この条件は常に満たされると考えて問題ない.
さて, SYS_TIME
の補正は, SYS_TIME
が基準より進んでいる場合 (即ち, 水晶振動子の周波数が基準より高い場合) はSYS_TIME
のインクリメントを止め, SYS_TIME
が遅れている場合 (即ち, 水晶振動子の周波数が基準より低い場合) はSYS_TIME
をすることにより実行する.
そのため, SYS_TIME
は逆戻りすることはないが, 一つ飛ばしでカウントアップされる可能性がある.
一つ飛ばしが発生した際はSKIP_ONE_ASSERT
をアサートする.
NOTE:
SYS_TIME
をの補正をSync0信号が発火した後すぐ集中的に行うと, の周期的な操作に由来するノイズが生じる. 特によく使われる–あたりの周波数はヒトの聴覚が比較的敏感な周波数でもあるので, このノイズは避けたいところではある. 古いバージョンでは補正タイミングを疑似乱数を用いてバラすことでこれを回避していた. しかし実際にはこのノイズはほぼ聞こえないので, 現在はこのような処理は行っていない.
ソフトウェアから指定すればいいだけの話だが, TwinCATを使用する場合, このを (クライアント側から) 取得する方法がなかった.
これが正しいかは確かめてはいない. また, MMCMの精度やジッター等は無視しているが, 後に明らかになるように, かなり余裕があるので問題ないだろう.