KV260上で動作するリアルタイムOS「Zephyr」から、PMODインターフェースのGPIOを制御するテストを実施しました。
Vivadoでのハードウェア作成から、デバイスツリーのコンパイル、そしてxmutilを使用したアプリケーションのロードまでの手順をまとめます。
ZephyrのR5コアからFPGA(PL)のメモリ・GPIO制御してみた
KV260上で動作するリアルタイムOS「Zephyr」から、PMODインターフェースのGPIOを制御するテストを実施しました。


Vivadoでのハードウェア作成から、デバイスツリーのコンパイル、そしてxmutilを使用したアプリケーションのロードまでの手順をまとめます。
デモ動画は下記となっています。
詳細は下記hackster.ioの記事でも書いています。
KV260でZephyrのHelloWorld
下記でKV260でのZephyr(RTOS)を使ったHello Worldの手法を紹介しています。
この準備が前提の記事となっています。
KV260のR5コアにZephyr(RTOS)を実装してみる

テスト環境
今回のテスト環境は以下の通りです。
-
開発PC: Vivado 2025.2 / Vitis 2025.2 /Petalinux 2025.1
-
ターゲットボード: Kria KV260 Vision AI Starter Kit
-
OS: Zephyr RTOS v4.4.0(Cortex-R5F) / PetaLinux (Cortex-A53)
Vivadoでのハードウェア作成
まずは、KV260のPMODに接続されたGPIOを含むデザインをVivadoで作成します。
こちらのHackster.ioの記事を参考に、KV260用のGPIOデザインを構築します。
今回のデザインにおける XDC制約(ピンアサイン) は以下の通りです。PMODインターフェースに合わせて設定しています。
|
1 2 3 4 5 6 7 8 9 |
set_property PACKAGE_PIN H12 [get_ports gpio_rtl_0_tri_o[0]] set_property PACKAGE_PIN E10 [get_ports gpio_rtl_0_tri_o[1]] set_property PACKAGE_PIN D10 [get_ports gpio_rtl_0_tri_o[2]] set_property PACKAGE_PIN C11 [get_ports gpio_rtl_1_tri_i[0]] set_property IOSTANDARD LVCMOS33 [get_ports gpio_rtl_0_tri_o[0]] set_property IOSTANDARD LVCMOS33 [get_ports gpio_rtl_0_tri_o[1]] set_property IOSTANDARD LVCMOS33 [get_ports gpio_rtl_0_tri_o[2]] set_property IOSTANDARD LVCMOS33 [get_ports gpio_rtl_1_tri_i[0]] |
論理合成・インプリメンテーションを実行し、 .xsa ファイルをエクスポートします。
デバイスツリー(pl.dtbo)の作成
FPGA部分をロードするために、デバイスツリー・オーバーレイ(DTBO)を作成します。
Vitisの xsct を使用して、エクスポートした .xsa から生成およびコンパイルを行います。
|
1 2 3 4 5 |
xsct createdts -hw design_1_wrapper.xsa -zocl -platform-name mydevice -git-branch xlnx_rel_v2025.2 -overlay -compile -out mydevice dtc -@ -O dtb -o mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtbo mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtsi mkdir dtg_output cp mydevice/mydevice/mydevice/psu_cortexa53_0/device_tree_domain/bsp/pl.dtbo dtg_output/ |
作成した pl.dtbo は、後ほどKV260の /lib/firmware/xilinx/ 配下で使用します。
ビットストリーム(.bin)の生成
Vivadoで生成された.bitファイルを、Kriaのユーティリティで扱える.bin形式に変換します。
|
1 2 3 |
cd [Vivado project]/[Vivado project].runs/impl_1 echo 'all:{design_1_wrapper.bit}' > bootgen.bif bootgen -w -arch zynqmp -process_bitstream bin -image bootgen.bif |
shell.jsonの作成
xmutilでアプリケーションをロードする際に必要なshell.jsonを作成します。
これは、アクセラレータのタイプ(今回はXRT_FLAT)を定義するファイルです。
ZephyrのMPU設定
ZephyrからPL(FPGA)領域のレジスタやメモリにアクセスするためには、MPU(Memory Protection Unit)の設定を変更して、該当するアドレス空間へのアクセスを許可する必要があります。
MPU設定の修正(PL AXI領域の解放)
Zephyrソースコード内の以下のファイルを編集し、PL領域(0x80000000〜)へのアクセス許可を追加します。
対象ファイル: zephyr/soc/xlnx/zynqmp/arm_mpu_regions.c
追記内容:
|
1 2 3 4 5 6 7 8 |
/* Allow access to the PL (FPGA) region */ MPU_REGION_ENTRY( "PL_AXI", 0x80000000, REGION_1G, {.rasr = P_RW_U_NA_Msk | DEVICE_SHAREABLE | NOT_EXEC}), |
Zephyrのデバイスツリー・オーバーレイ設定
Zephyr側でFPGA上のGPIO(AXI GPIO)を認識させるため、プロジェクト内に .overlay ファイルを作成し、以下の内容を記述します。

-
エイリアスの設定:
led0〜led2やsw0を定義することで、Zephyrのアプリケーション(C言語)側からDT_ALIAS(led0)のような形でデバイスを簡単に参照できるようにしています。 -
アドレスの解釈(&{/soc}): ZynqMPのような64bit対応SoCでは、デバイスツリーのルート直下だとアドレスセルの解釈が複雑になることがありますが、
&{/soc}ノードを明示的に指定することで、PL領域の32bitレジスタアドレスを確実にマッピングさせています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/* SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/dt-bindings/gpio/gpio.h> / { aliases { led0 = &led_0; led1 = &led_1; led2 = &led_2; sw0 = &sw_0; }; leds { compatible = "gpio-leds"; led_0: led_0 { gpios = <&axi_gpio_0 0 GPIO_ACTIVE_HIGH>; }; led_1: led_1 { gpios = <&axi_gpio_0 1 GPIO_ACTIVE_HIGH>; }; led_2: led_2 { gpios = <&axi_gpio_0 2 GPIO_ACTIVE_HIGH>; }; }; buttons { compatible = "gpio-keys"; sw_0: button_0 { gpios = <&axi_gpio_1 0 GPIO_ACTIVE_HIGH>; }; }; }; /* * Key point of the fix: * By describing it inside the &{/soc} node instead of the root, * the 32-bit address will be interpreted correctly. */ &{/soc} { axi_gpio_0: gpio@b0000000 { compatible = "xlnx,xps-gpio-1.00.a"; /* Address 0xb0000000, size 0x10000 described with 1 cell each */ reg = <0xb0000000 0x10000>; status = "okay"; gpio-controller; #gpio-cells = <2>; }; axi_gpio_1: gpio@b0010000 { compatible = "xlnx,xps-gpio-1.00.a"; reg = <0xb0010000 0x10000>; status = "okay"; gpio-controller; #gpio-cells = <2>; }; }; |
KV260へのデプロイと実行
作成した3つのファイル(pl.dtbo, design_1_wrapper.bit.bin, shell.json)をKV260に転送し、xmutilでロードします。
フォルダの作成とファイル配置
Zephyrのビルドディレクトリ(build/zephyr/zephyr.elf)にあるバイナリを、KV260の /lib/firmware ディレクトリにコピーします。
|
1 2 3 4 5 6 |
# Create the firmware directory sudo mkdir -p /lib/firmware/xilinx/zephyr_kv260_gpio # Copy the files sudo cp pl.dtbo shell.json design_1_wrapper.bit.bin /lib/firmware/xilinx/zephyr_kv260_gpio/ sudo cp zephyr.elf /lib/firmware/zephyr_gpio.elf |
アプリケーションのロード
現在のアプリをアンロードし、新しく作成したGPIO用のアプリをロードします。
|
1 2 3 |
sudo xmutil listapps sudo xmutil unloadapp sudo xmutil loadapp zephyr_kv260_gpio |
正常にロードされると、ZephyrからPMODのGPIOを叩く準備が整います。
実際にロードすると下記形となります。
|
1 2 3 4 5 6 7 8 9 |
xilinx-kv260-starterkit-20251:~/zephyr_kv260_gpio$ sudo xmutil listapps # Accel_type user_load_type user_load_region Base Pid Base_type #slots(RPU+PL+AIE) slot->handle Accelerator -- ----------- -------------- ---------------- ----------- ----- --------- ------------------ ------------ --------- 1 XRT_FLAT - - k26-star... id_ok XRT_FLAT (0+0+0) 0->0, k26-starter-kits 2 XRT_FLAT - - zephyr_k... id_ok XRT_FLAT (0+0+0) -1 zephyr_kv260_gpio xilinx-kv260-starterkit-20251:~/zephyr_kv260_gpio$ sudo xmutil unloadapp remove from slot 0 returns: 0 (Ok) xilinx-kv260-starterkit-20251:~/zephyr_kv260_gpio$ sudo xmutil loadapp zephyr_kv260_gpio zephyr_kv260_gpio: Loaded with slot_handle 0 |
Zephyrバイナリ(.elf)のデプロイと実行
PL(FPGA)のロードが完了したら、次にZephyrの実行本体である .elf ファイルをR5コアへデプロイして実行します。これにはLinuxの remoteproc フレームワークを使用します。
remoteprocによるロードと起動
Linux側からR5プロセッサ(remoteproc0)に対して、ファームウェアの指定と実行指示を出します。この操作にはroot権限が必要なため、sudo -i で切り替えて実行します。
|
1 2 3 |
sudo -i echo zephyr_gpio.elf > /sys/class/remoteproc/remoteproc0/firmware echo start > /sys/class/remoteproc/remoteproc0/state |
実行状態の確認
正常に起動すれば、KV260に接続したシリアルコンソール等からZephyrのログが確認でき、PMOD経由でのGPIO制御が可能になります。


Zephyrを起動すると、シリアルコンソールに以下のログが表示されます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
*** Booting Zephyr OS build v4.4.0-1293-g81e1e71d3f90 *** Hello World! kv260_r5/zynqmp_rpu LED 0 is ON SW0 state: 0 [Debug] Data Reg (0xb0000000): 0x00000001 [Debug] Dir Reg (0xb0000004): 0xffffffff LED 1 is ON SW0 state: 0 [Debug] Data Reg (0xb0000000): 0x00000002 [Debug] Dir Reg (0xb0000004): 0xffffffff LED 2 is ON SW0 state: 0 [Debug] Data Reg (0xb0000000): 0x00000004 [Debug] Dir Reg (0xb0000004): 0xffffffff |
ログを確認すると、以下のことが分かります。
-
バージョンの確認: Zephyr OS v4.4.0 が正常に起動しています。
-
GPIOの制御: LEDの状態に合わせて、FPGA上のAXI GPIOレジスタ(
0xb0000000)の値が0x1,0x2,0x4と変化しており、ZephyrからPL(FPGA)側のLEDを正しく制御できています。 -
スイッチの監視:
SW0 stateの表示により、PL側の入力ピンの状態もリアルタイムに監視できています。
これにより、Cortex-R5上のZephyrから、ZynqMPのPL領域(AXIインターフェース)へ正常にアクセスできていることが確認できました!
冒頭でも紹介しましたが、下記がデモ動画となっています。
まとめ
KV260上で動作するリアルタイムOS「Zephyr」から、PMODインターフェースのGPIOを制御するテストを実施しました。
Vivadoでのハードウェア作成から、デバイスツリーのコンパイル、そしてxmutilを使用したアプリケーションのロードまでの手順をまとめました。


コメント