Synchronizer

NameIn/OutWidthDescription
CLKIn1メインクロック
SETTINGSIn-
├─ UPDATEIn1同期フラグ
└─ ECAT_SYNC_TIMEIn64同期EtherCAT時刻
ECAT_SYNCIn1EtherCAT Sync0信号
SYS_TIMEOut57システム時刻
SKIP_ONE_ASSERTOut11飛ばしアサート

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ファームウェアと協調して, 以下の手順で行われる.

  1. CPU: 次のSync0信号が発火するシステム時刻ECAT_SYNC_TIMEを読み出し, FPGA内のBRAMに書き込む.
    • ただしこの時, 現在時刻がECAT_SYNC_TIMEに近すぎる場合は, いったん待機する. これにより, 次のUPDATEフラグの書き込み/読み出しがECAT_SYNC_TIMEより前に行われることを保証する.
  2. CPU: UPDATEフラグをFPGA内のBRAMに書き込む.
  3. FPGA: 以下の計算により, 時刻単位を変換しておく.
  4. FPGA: UPDATEフラグがアサートされている, かつ, ECAT_SYNCがアサートされたタイミングで, 単位変換済みのECAT_SYNC_TIMESYS_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信号が発火した後すぐ集中的に行うと, の周期的な操作に由来するノイズが生じる. 特によく使われるあたりの周波数はヒトの聴覚が比較的敏感な周波数でもあるので, このノイズは避けたいところではある. 古いバージョンでは補正タイミングを疑似乱数を用いてバラすことでこれを回避していた. しかし実際にはこのノイズはほぼ聞こえないので, 現在はこのような処理は行っていない.

1

ソフトウェアから指定すればいいだけの話だが, TwinCATを使用する場合, このを (クライアント側から) 取得する方法がなかった.

2

これが正しいかは確かめてはいない. また, MMCMの精度やジッター等は無視しているが, 後に明らかになるように, かなり余裕があるので問題ないだろう.