Zybo Z7でＬチカ

# 概要

Zybo Z7 の petalinux で gpio-leds の使い方を調べたメモです。

# 作業環境

<dl>
  <dt>Bord</dt>
  <dd>Zybo Z7-20</dd>
  <dt>Tool</dt>
  <dd>Vivado ML Edition 2023.2.1 (Windows11)</dd>
  <dd>Petalinux 2023.2.1 (Ubuntu 22.04.4)</dd>
</dl>

# Vivado 作業手順

PS - AXI GPIO - LED の構成でプロジェクトを作成します。

最初に下図のBlock Desgin を作成します。

![design_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332407/909c7b97-64a7-200a-050e-2e717ea4eecc.png)

作業手順は Tcl スクリプトで記述しています。以降ではスクリプトを vivado 起動後の Tcl console で実行する事を前提に記述します。

最初にボード情報の更新と Zybo Z7-20 のインストールを実行します。少し時間が掛かりますが、既にインストール済みであれば実行する必要はありません。

```tcl
# update and install the board information for Zybo z7-20
xhub::refresh_catalog [xhub::get_xstores xilinx_board_store]
set_param board.repoPaths "$env(APPDATA)/Xilinx/Vivado/[version -short]/xhub/board_store/xilinx_board_store"
xhub::install [xhub::get_xitems digilentinc.com:xilinx_board_store:zybo-z7-20:1.1]
```

c:\vivado\zybo-gpio-led\ フォルダ配下にプロジェクトを作成します。

```tcl
# create zybo-led project
set_param board.repoPaths "$env(APPDATA)/Xilinx/Vivado/[version -short]/xhub/board_store/xilinx_board_store"
file mkdir c:/vivado
create_project zybo-gpio-led C:/vivado/zybo-gpio-led -part xc7z020clg400-1
set_property board_part digilentinc.com:zybo-z7-20:part0:1.1 [current_project]
```

成功すると vivado でプロジェクトが開かれた状態になります。
次に Block Design を作成します。

```tcl
# create block design
create_bd_design "design_1"
update_compile_order -fileset sources_1
startgroup
create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 processing_system7_0
endgroup
startgroup
create_bd_cell -type ip -vlnv xilinx.com:ip:axi_gpio:2.0 axi_gpio_0
apply_board_connection -board_interface "leds_4bits" -ip_intf "axi_gpio_0/GPIO" -diagram "design_1" 
endgroup
apply_board_connection -board_interface "rgb_led" -ip_intf "/axi_gpio_0/GPIO2" -diagram "design_1" 
apply_bd_automation -rule xilinx.com:bd_rule:processing_system7 -config {make_external "FIXED_IO, DDR" apply_board_preset "1" Master "Disable" Slave "Disable" }  [get_bd_cells processing_system7_0]
apply_bd_automation -rule xilinx.com:bd_rule:axi4 -config { Clk_master {Auto} Clk_slave {Auto} Clk_xbar {Auto} Master {/processing_system7_0/M_AXI_GP0} Slave {/axi_gpio_0/S_AXI} ddr_seg {Auto} intc_ip {New AXI Interconnect} master_apm {0}}  [get_bd_intf_pins axi_gpio_0/S_AXI]
regenerate_bd_layout
```

成功すると[最初の図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332407/909c7b97-64a7-200a-050e-2e717ea4eecc.png)と同様の Block Design が作成されます。
次に Block Design の Wrapper File を作成します。

```tcl
# create wrapper file
cd [get_property DIRECTORY [current_project]]
make_wrapper -files [get_files ./[current_project].srcs/sources_1/bd/design_1/design_1.bd] -top
add_files -norecurse ./[current_project].gen/sources_1/bd/design_1/hdl/design_1_wrapper.v
```

これでプロジェクトが合成可能な状態になりました。最後に Bitsream と XSA ファイルを生成します。**-jobs** の値は利用している PC に合わせて変更して下さい。

```tcl
# generate bitstream file
launch_runs impl_1 -to_step write_bitstream -jobs 4
wait_on_run impl_1
# export hardware platform
write_hw_platform -fixed -include_bit -force -file [get_property DIRECTORY [current_project]]/[current_project].xsa
```

成功するとプロジェクトフォルダ配下に zybo-gpio-led.xsa が作成されます。

# petalinux 作業手順

## 前提条件

作業手順では下記条件での実行を前提としています。

- petalinux の各種ツールが利用可能
- ホームディレクトリ配下に zybo-gpio-led.xsa がコピー済み

## ビルド

最初に環境変数を設定します。ここでは ~/petalinux/ 配下にプロジェクトを作成する様に設定しています。

```bash
WORK_DIR=~/petalinux
PROJ_NAME=zybo-gpio-led
PROJ_DIR=$WORK_DIR/$PROJ_NAME
PROJ_XSA=~/$PROJ_NAME.xsa
```
次にプロジェクトを作成し、作成した XSA ファイルを取り込みます。petalinux-config の実行でメニュー画面が表示されたら **\<Save\>** を実行してから終了して下さい。

```bash
mkdir -p $WORK_DIR
cd $WORK_DIR
# create project
petalinux-create --type project --template zynq --name $PROJ_NAME
cd $PROJ_DIR
# configure H/W
petalinux-config --get-hw-description $PROJ_XSA
```

![peta-op1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3332407/92c0528f-a866-34d2-8709-5175711b9e8d.png)

次は gpio-leds を利用する為に Device Tree の修正を行います。`$PROJ_DIR/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi` を下記内容に置き換えます。

```:system-user.dtsi
#include "dt-bindings/gpio/gpio.h"
/include/ "system-conf.dtsi"

/ {
        leds {
                compatible = "gpio-leds";
                ld0 {
                        gpios = <&axi_gpio_0 0 GPIO_ACTIVE_HIGH>;
                };
                ld1 {
                        gpios = <&axi_gpio_0 1 GPIO_ACTIVE_HIGH>;
                };
                ld2 {
                        gpios = <&axi_gpio_0 2 GPIO_ACTIVE_HIGH>;
                };
                ld3 {
                        gpios = <&axi_gpio_0 3 GPIO_ACTIVE_HIGH>;
                };
                ld5b {
                        gpios = <&axi_gpio_0 4 GPIO_ACTIVE_HIGH>;
                };
                ld5g {
                        gpios = <&axi_gpio_0 5 GPIO_ACTIVE_HIGH>;
                };
                ld5r {
                        gpios = <&axi_gpio_0 6 GPIO_ACTIVE_HIGH>;
                };
                ld6b {
                        gpios = <&axi_gpio_0 7 GPIO_ACTIVE_HIGH>;
                };
                ld6g {
                        gpios = <&axi_gpio_0 8 GPIO_ACTIVE_HIGH>;
                };
                ld6r {
                        gpios = <&axi_gpio_0 9 GPIO_ACTIVE_HIGH>;
                };
        };
};
```

最後に petalinux のビルドと BOOT.BIN の作成を実行します。

```bash
# build images
petalinux-build
# create BOOT.BIN
petalinux-package --boot --fsbl images/linux/zynq_fsbl.elf --fpga images/linux/system.bit --u-boot --force
```

## 起動

`$PROJ_DIR/images/linux/` 配下に作成された下記ファイルを microSD カードの FAT パーティションに書き込んで起動します。

- BOOT.BIN
- boot.scr
- image.ub

## Ｌチカの実行

### sysfs による制御

正常にビルドできていれば `/sys/class/leds/` 配下に下記の様な ld から始まるフォルダが作成されます。

```
zybo-gpio-led:~$ ls /sys/class/leds/
ld0     ld2     ld5b    ld5r    ld6g    mmc0::
ld1     ld3     ld5g    ld6b    ld6r
```

フォルダ名称はボード上のシルクプリントに合わせています。ld0-3 はスライドスイッチの上部に実装されている各 LED です。ld5* と ld6* は２つの RGB LED に対応しています。

LED の点灯／消灯は root 権限で各フォルダ配下の brightness に 0 または 1 を書き込んで下さい。

```bash:sysfs による制御
# 点灯
echo 1 > /sys/class/leds/ld0/brightness
# 消灯
echo 0 > /sys/class/leds/ld0/brightness
```

sysfs の場合 trigger に設定したタイミングで点灯させる事が可能です。trigger に設定可能なパラメータは cat で確認できます。

```
zybo-gpio-led:~# cat /sys/class/leds/ld0/trigger
[none] kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 timer oneshot heartbeat backlight gpio cpu cpu0 cpu1 default-on transient flash torch
```

下記は CPU0/CPU1 の実行状態に応じて ld0/ld1 を点滅させます。

```
echo cpu0 > /sys/class/leds/ld0/trigger
echo cpu1 > /sys/class/leds/ld1/trigger
```

点滅を停止させる場合は trigger に none を書き込みます。

```
echo none > /sys/class/leds/ld0/trigger
echo none > /sys/class/leds/ld1/trigger
```

# おまけ
## devmem による制御

devmem コマンドを利用すると AXI GPIO のレジスタを直接アクセスして LED を制御できます。

/proc/iomem で AXI GPIO のレジスタアドレスを確認します。

```
zybo-gpio-led:~# cat /proc/iomem
00000000-3fffffff : System RAM
  00008000-00afffff : Kernel code
  00c00000-00c5c7b7 : Kernel data
41200000-4120ffff : 41200000.gpio gpio@41200000
e0001000-e0001fff : xuartps
e000a000-e000afff : e000a000.gpio gpio@e000a000
e000b000-e000bfff : e000b000.ethernet ethernet@e000b000
e000d000-e000dfff : e000d000.spi spi@e000d000
e0100000-e0100fff : e0100000.mmc mmc@e0100000
f8003000-f8003fff : dma-controller@f8003000
  f8003000-f8003fff : f8003000.dma-controller dma-controller@f8003000
f8005000-f8005fff : f8005000.watchdog watchdog@f8005000
f8007000-f80070ff : f8007000.devcfg devcfg@f8007000
f8007100-f800711f : f8007100.adc adc@f8007100
f8801000-f8801fff : etb@f8801000
f8803000-f8803fff : tpiu@f8803000
f8804000-f8804fff : funnel@f8804000
f889c000-f889cfff : ptm@f889c000
f889d000-f889dfff : ptm@f889d000
fffc0000-fffcffff : fffc0000.sram sram@fffc0000
```

上記ではレジスタアドレスは 0x41200000 となります。今回のデザインでは GPIO_DATA の下位４ビットに ld3-ld0、GPIO_DATA2 の下位６ビットに ld6/ld5 を接続しています。下記はレジスタのアクセス例です。

```
# LD0 と LD3 を点灯
devmem 0x41200000 32 9
# LD5 の Blue を点灯
devmem 0x41200008 32 1
# LD6 の Red を点灯
devmem 0x41200008 32 32
# LD5 の Red/Blue を点灯
devmem 0x41200008 32 5
```