Skip to content
This is the development version of the documentation. It may change before the next release. See 0.6.x for the latest release.

CPU ファームウェア

This content is not available in your language yet.

CPU ボード (AP-RZT-01, Alpha Project) は Renesas RZ/T1 (Arm Cortex-R4F) を搭載しており, EtherCAT スレーブとして動作する. これの役割は, EtherCAT の PDO で受け取ったフレームを解釈し, FPGA 内の BRAM へ書き込むことである.

ソースは firmware/cpu/ 以下にあり, no_std Rust で記述されている. 2 つのクレートに分かれている.

  • fw/ (autd3-cpu-fw): プロトコル解釈・コマンド処理・FPGA 書き込みなどの可搬ロジック. ハードウェアには Port trait 越しにのみアクセスし, unsafe を含まない. ホストテストと autd3-rs-firmware-emulator からも同じコードが使われる.
  • board/ (autd3-cpu): 実機ターゲット (armv7r-none-eabi) の staticlib. レジスタ定義・BSP・Port trait の実機実装・C-ABI エクスポート・panic handler を持ち, unsafe はここに閉じ込める.

CPU ファームウェアに関する作業はすべて autd3-sdk/ ディレクトリ内で cargo xtask 経由で実行する.

cargo xtask cpu build # 実機用 .bin を生成
cargo xtask cpu flash # build 後, J-Link で実機へ書き込む
cargo xtask cpu test # ホスト上の単体テスト (cargo test -p autd3-cpu-fw)
cargo xtask cpu lint # clippy (fw + board)
cargo xtask cpu format # rustfmt --check (fw + board)
cargo xtask cpu format --fix # rustfmt 実書き換え
用途 ツール
実機ビルド Rust ツールチェイン + rustup target add armv7r-none-eabi, Arm GNU Toolchain (arm-none-eabi-gcc, arm-none-eabi-objcopy)
実機書き込み J-Link Commander (JLinkExe)
ホストテスト Rust ツールチェイン (cargo test)
lint / format clippy, rustfmt

arm-none-eabi- 以外のプレフィックスを使う場合は環境変数 CROSS_COMPILE で上書きできる. JLinkExe が PATH に無い場合は環境変数 JLINK でパスを指定できる.

cargo xtask cpu build は以下を行う.

  1. cargo xtask cpu gen-param で FPGA の params.svh から fw/src/params.rs を生成する.
  2. board/armv7r-none-eabi ターゲットの staticlib (libautd3_cpu.a) としてビルドする.
  3. arm-none-eabi-gccplatform/autd3-platform.o とリンカスクリプト platform/autd3-cpu.ld を用いてリンクする.
  4. objcopybuild/autd3-cpu.bin を生成する.

platform/autd3-platform.o は EtherCAT スレーブコントローラの初期化などを含む非公開コードのビルド済みオブジェクトである. 両者の C-ABI 境界 (init_app / recv_ethercat / app_process_pending / bsp_*) は board/src/lib.rs#[unsafe(no_mangle)] エクスポートが実装する.

cargo xtask cpu flash は J-Link を JTAG 接続し, autd3-cpu.bin0x30000000 へロードして実行する. デバイスは R7S910018_R4F として認識される.

fw/Port trait (fpga_write / fpga_read / memory_barrier / sleep_ms など) 以外のハードウェア依存を持たない. cargo xtask cpu test では fw/src/tests/mock.rsMockPort がこれを置き換え, FPGA への書き込みを記録する. fw/src/tests/ がプロトコル層 (Cpu::recv_ethercat / Cpu::process_one) の振る舞いを検証する.

EtherCAT の 1 サイクルにつき, マスタからスレーブへ 626 byte, スレーブからマスタへ 2 byte が転送される.

受信フレームは先頭が seq (1 byte), cmd (1 byte) で, 残り 624 byte がペイロードである. 送信フレームは ack (1 byte) と data (1 byte) からなる.

同じ seq かつ同じ cmd のフレームは再送とみなして無視する.

フレームの処理方式には 2 つのモードがあり, SetMode コマンド (CMD_SET_MODE) でセッション全体を切り替える.

フレーム処理モード
  • MODE_FIFO (既定): 受信フレームを深さ 8 のリングバッファに積むだけで割り込みを抜け, メインループの app_process_pending() が処理する. 割り込み時間が短く済むが, ack が返るまでの遅延が増える.
  • MODE_LOW_LATENCY: 受信割り込みの中で直接処理する. 遅延は小さいが, 処理時間の長いコマンドが EtherCAT サイクルを圧迫する.

FIFO が満杯の場合, フレームは捨てられる. ack が進まないため, クライアント側が再送する.

CMD_RESET だけはモードに関わらず割り込み内で即座に処理され, FIFO も破棄される.

handle_frame はコマンドを実行し, エラーがあればエラーコードをラッチする. ラッチされたコードは CMD_READ_ERROR_DETAIL で読み出せる.

コード 名前 意味
0x00 ERR_NONE エラーなし
0x01 ERR_UNKNOWN_CMD 未知のコマンド
0x02 ERR_INVALID_PAYLOAD ペイロードの長さ・オフセットが不正
0x03 ERR_INVALID_DATA データの値が不正
0x04 ERR_INVALID_SILENCER_SETTING Silencer の設定が厳格モードの条件を満たさない
0x05 ERR_INVALID_TRANSITION_MODE 遷移モードと繰り返し回数の組み合わせが不正
0x06 ERR_MISS_TRANSITION_TIME SysTime 遷移の指定時刻が近すぎる・過去である
0x07 ERR_FPGA_TIMEOUT FPGA が制御フラグを期限内にクリアしない
0x08 ERR_SYNC_NOT_READY EtherCAT の DC が未設定で Sync0 時刻が読めない
0x09 ERR_INVALID_SYNC0_CYCLE Sync0 周期が未設定, または の整数倍でない

FPGA は CS1 空間 (0x44000000) にマップされた 幅のメモリとして見える. Port trait の fpga_write / fpga_read (実機実装は board/src/port.rsHwPort) がこの領域への volatile アクセスを担う.

fpga::write(select, addr, value)select (BRAM 選択, 2 bit) と addr (14 bit) を連結してアドレスを作る. 詳細は Memory を参照されたい.

設定値の反映は制御フラグ経由のハンドシェイクで行う. set_and_wait_update(flag)ADDR_CTL_FLAG の該当ビットを立て, FPGA の Controller がそれをクリアするまでポーリングする.

CMD_SYNCHRONIZE は以下を行う.

  1. Sync0 の発火周期を読み出す

  2. 周期を検証する. ( DC が設定されてない ) や の整数倍でない場合は ERR_INVALID_SYNC0_CYCLE を返す

  3. 周期を FPGA内部のSYS_TIME の単位 () へ変換する

  4. 次に Sync0 が発火する EtherCAT システム時刻を読み出す. 現在時刻がそれに近すぎる ( 未満) 場合は次の発火まで待つ.

    • DC が未設定で時刻が読めない場合は ERR_SYNC_NOT_READY を返す
  5. その時刻を ADDR_ECAT_SYNC_TIME_* へ, 変換した周期を ADDR_ECAT_SYNC_CYCLE_* へ書き込む.

  6. SYNC_SET フラグを立て, FPGA の SynchronizerSYS_TIME をセットするのを待つ.

遷移モードと繰り返し回数の組み合わせには制約がある. 無限ループ (REP == 0xFFFF) では Immediate / Ext のみ, 有限ループでは SyncIdx / SysTime / Gpio のみが有効である. transition_mode_violates_loop() がこれを検証し, 違反すれば ERR_INVALID_TRANSITION_MODE を返す.

また SysTime 遷移では, 指定時刻が現在時刻から 以内 (または過去) の場合, FPGA が遷移を取りこぼす可能性がため, ERR_MISS_TRANSITION_TIME を返す.