Skip to content

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 を返す.