FieldLinker-Display は、1200 個の NeoPixel(6ch × 200)で構成された円形ディスプレイを、Raspberry Pi と Tang Primer 25K (Gowin GW5A) で駆動するためのリファレンス実装です。
Raspberry Pi 側で物理シミュレーションベースのアニメーションを生成し、SPI 経由で FPGA に送出、FPGA 内の並列 NeoPixel ドライバが電気的タイミングを保証します。
| パス | 内容 |
|---|---|
raspberrypi/ |
フレーム生成アプリ (spi-led.c)、物理シミュレーション (ball_physics.*)、1200 点の座標データ (neopixel_cordinates.h) |
neopixel-engine/ |
Tang Primer 25K 向け SPI→NeoPixel エンジン(SystemVerilog / Gowin プロジェクト / シミュレーション環境) |
neopixel-engine/sim/ |
Icarus Verilog 用テストベンチと GTKWave 設定 |
neopixel-engine/gowin_neopixel-engine/ |
Gowin EDA でそのまま開けるプロジェクト、制約ファイル (.cst, .sdc) |
- Raspberry Pi
/dev/spidev4.0を SPI Mode 3 / 10 MHz で使用。ball_physics.cの HSV ベース粒子シミュレーションで 1200px の RGB フレームを用意。- フレーム毎に Start バイト
0x55 0x5B→1200×3バイトの RGB → Stop バイト0xAAを送信。
- Tang Primer 25K
- SPI Slave がフレームを 3,600 バイトのダブルバッファに格納。
- 6ch NeoPixel ドライバが同期スタートし、各 200px を 50 MHz から生成した WS2812 タイミングで出力。
- FieldLinker LED アレイ
neopixel_cordinates.hに保存された 0.01 mm 単位の XY 座標をもとに、ボールの陰影を計算。
- Raspberry Pi(SPI4 を引き出せるモデル。例: CM4 + Carrier、Pi 5 等) + 64bit Raspberry Pi OS
- Tang Primer 25K(GW5A-LV25)と 50 MHz 外部クロック
- 6 系統に分岐した NeoPixel(WS2812/WS2812C)× 1200
- SPI 配線(Pi → FPGA):
SCLK,MOSI,CS,GND - ソフトウェア:
gcc,make,iverilog,gtkwave, Gowin EDA (V1.9.9 以降推奨)
cd raspberrypi
gcc -O2 -Wall -Wextra -lm spi-led.c ball_physics.c -o spi-led
# または ./tmp.sh (最低限の gcc 呼び出し)sudo raspi-config→ Interface Options → SPI を有効化(SPI4 を使う場合は dtoverlay 設定も忘れずに)。/boot/firmware/config.txt例:dtoverlay=spi4-1cs,cs0_pin=8,mosi_pin=10,sclk_pin=9/dev/spidev4.0のアクセス権があることを確認。
sudo ./spi-led- 3 ms 間隔で新しいフレームを送り続けます(およそ 333 fps)。
BallConfigHSV配列(spi-led.c内)を編集すると、位置・速度・半径・HSV 変化を個別に調整できます。- 座標は
COORD_TO_FLOAT()マクロで mm に変換し、draw_ball()が加算合成モード(mode=2)で描画します。
cd neopixel-engine
make sim # 1200px フルトップレベル動作検証 (tmp/wave.vcd)
make wave # GTKWAVE が入っていれば自動で VCD を開く
make neopixel # 単体 NeoPixel ドライバテスト (tmp/neopixel.vcd)sim/tb_top.vは SPI プロトコルを模倣し、初期 3px と 30px のテストパターンを送信します。
- Gowin EDA で
neopixel-engine/gowin_neopixel-engine/gowin_spi-led.gprjを開く。 impl/gwsynthesis→Run、impl/pnr→Runで bitstream を生成。impl/pnr/gowin_spi-led.fsを JTAG または内蔵 Program Tool で書き込み。
top.sv- 6 チャネル × 200 LED、各チャネル専用の
double_buffer+neopixel_driver。 - SPI 受信はスタート
0x55 0x5B/ストップ0xAAを状態機械で認識し、フレーム単位でダブルバッファをスワップ。
- 6 チャネル × 200 LED、各チャネル専用の
double_buffer.sv- 書き込み側と読み出し側を完全分離し、フレーム境界で
i_swapによるトグルを実施。
- 書き込み側と読み出し側を完全分離し、フレーム境界で
neopixel.sv- 50 MHz クロックから WS2812 用
T0H/T0L/T1H/T1L/RSTを定数化。 o_rd_addrは(LEDS*3 - r_byte_cnt - 1)となるため、BRAM 側はリトルエンディアン配置に注意。
- 50 MHz クロックから WS2812 用
| 項目 | 値 |
|---|---|
| モード | SPI Mode 3 (CPOL=1, CPHA=1) |
| クロック | 10 MHz(spi-led.c の speed で変更可) |
| フレーム | 0x55 0x5B → LEDS_TOTAL * 3 バイト(R, G, B の順) → 0xAA |
| LED 割り当て | チャネル 0〜5 に 200px ずつ。INDEX = channel * 200 + local_index |
raspberrypi/neopixel_cordinates.hに 1200 点すべての ID / X / Y / 極座標 を 0.01 mm 精度で格納。- 変換マクロ:
COORD_TO_FLOAT(x)→ 実測 mmtheta_deg / ROTATION_SCALE→ deg
- 自動生成ファイルのため、再配置したい場合は CAD/Excel などから同形式で再エクスポートしてください。
/dev/spidev4.0が存在しない:dtoverlay設定と再起動、もしくはspi-led.cのdevを既存デバイスに合わせて変更。- LED が点滅/明るさが暴れる: 5 V/GND のリファレンス共通化、FPGA 側
o_neopixel_outにシリーズ抵抗 (33 Ω) を追加。 - SPI CRC エラー的な挙動:
send_led_data()は単純なフレーミングのみなので、ノイズが多い場合は CS の配線長を見直すか速度を落としてください。 - シミュレーション波形が空:
tmp/ディレクトリが生成済みか確認し、make clean→make simを実行。
- Raspberry Pi 側で他のエフェクト(FFT ビジュアライザ等)を実装し、
ball_physics.cと入れ替える。 - SPI プロトコルを DMA 対応にし、フレーム同期割り込みを付けてソフト側で映像同期を取る。
- FPGA 側でガンマ補正やダブルバッファを 3 枚に拡張し、ギガビット Ethernet 等からの入力にも対応する。
ライセンスは未定です。利用ポリシーを決める場合はプロジェクトルートに LICENSE を追加してください。