はじめに
前回の記事で実装したBitstreamを使い、GPIOを使ったキー入力のサンプルコードを実行します。
キー入力処理ではGPIOから直接読み取る方法とInput Subsystemを使う方法を利用します。
前提条件
開発環境は前回の記事と一緒です。本記事ではDevicetree更新までの手順が実行済みである事を前提としています。
前準備
本記事で利用する共通の環境変数の定義と、westコマンドを利用可能にする為の準備を行います。
# parameters
PROJ_NAME=basys3-mbv32
XSA_FILE=$HOME/ws/vivado/$PROJ_NAME/$PROJ_NAME.xsa
SDT_DIR=$HOME/${PROJ_NAME}_sdt
# vivado
source /tools/Xilinx/2025.1/Vivado/settings64.sh
# zephyr development environment
source $HOME/zephyrproject/.venv/bin/activate
GPIOから直接読み取る方法
ビルド手順
ここではzephyrの開発環境下にあるsamples/basic/buttonプロジェクトを使います。BASYS3で利用可能にする為、boards配下にmbv32.overlayを追加します。
#include "dt-bindings/gpio/gpio.h"
/ {
aliases {
sw0 = &button0;
led0 = &myled0;
};
buttons {
compatible = "gpio-keys";
button0: button_0 {
gpios = <&axi_gpio_inputs 0 GPIO_ACTIVE_HIGH>;
};
slide_sw0: slide_sw_0 {
gpios = <&axi_gpio_inputs_1 0 GPIO_ACTIVE_HIGH>;
};
};
leds {
compatible = "gpio-leds";
myled0: led_0 {
gpios = <&axi_gpio_led_16bits 0 GPIO_ACTIVE_HIGH>;
};
};
};
mbv32.overlayを用意したら、westコマンドでビルドを行います。
cd $HOME/zephyrproject/zephyr/samples/basic/button/
west build -p -b mbv32
実行手順
プログラムの実行はビルドを行ったフォルダ配下で下記コマンドを実行して下さい。
cd $HOME/zephyrproject/zephyr/samples/basic/button/
west flash --runner xsdb --elf-file ./build/zephyr/zephyr.elf --bitstream $SDT_DIR/$PROJ_NAME.bit
このプログラムはDevicetreeのaliasesで定義したsw0からスイッチ状態を読み取り、スイッチがONの場合はコンソールにメッセージを出力します。
ailiasesにled0が定義されている場合は、スイッチの状態をled0の点灯・消灯で表します。
mbv32.overlayではsw0 = &button0と定義しています。button0はボード上に十字状で配列されているpush buttonの「上」に該当します。このボタンを押すとコンソール上に以下の様に出力されます。またコンソールの出力と同時にled0で指定したLEDが点灯します。
*** Booting Zephyr OS build xilinx_v2024.2-111-g986cf11c05ea ***
Set up button at gpio@40010000 pin 0
Set up LED at gpio@40020000 pin 0
Press the button
Button pressed at 568007816
Button pressed at 655335193
Button pressed at 724337261
...
チャタリングの影響
スイッチの状態はGPIO driverのI/Fを使って直接読み込んでおり、debounce処理は行われていません。連続でボタンを押すと、コンソールの出力と押した回数が一致しない現象がたまに発生します。これがチャタリングによる誤認識の影響です。
mbv32.overlayのaliasesを以下の様に変更すると、sw0にslide_sw0が割り当てられます。これはボード上にある右端のslide switchに該当します。
aliases {
sw0 = &slide_sw0;
led0 = &myled0;
};
変更後に再度ビルドと実行を行うと、今度は右端のslide switchの状態に応じて、コンソール出力とLEDの点滅が実行されます。
プログラムの実行中にスイッチを中途半端な状態にしてみて下さい。私の環境では連続してON状態への遷移を認識します。スイッチをOFFにしても、しらばらくON状態を読み取る場合もあります。この様な現象はスイッチの経年劣化等による物理状態も影響しますので、必ずしも同じ形になるとは限りません。それでもチャタリングによる誤認識の影響は確認できるかと思います。
Input Subsystemを使った入力方法
概要
次はsamples/subsys/input/input_dumpでInputを使った入力を試します。
このsubsystemを使う事で、アプリケーションが各種デバイスからの入力を統一された方法で処理可能となります。入力デバイスとしてGPIOを使った場合でも、入力信号毎にkey codeを割り当ててアプリケーションに渡す事が可能となります。
またInputはdebounce処理に対応しています。これによりGPIOから直接読み出した時との違いを確認できます。
ビルド手順
samples/subsys/input/input_dump/boards配下にボード固有の.overlayファイルを作成します。
#include "dt-bindings/gpio/gpio.h"
#include "dt-bindings/input/input-event-codes.h"
/ {
buttons {
compatible = "gpio-keys";
debounce-interval-ms = <50>;
button_0 {
gpios = <&axi_gpio_inputs 0 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_UP>;
};
button_1 {
gpios = <&axi_gpio_inputs 1 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_RIGHT>;
};
button_2 {
gpios = <&axi_gpio_inputs 2 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_DOWN>;
};
button_3 {
gpios = <&axi_gpio_inputs 3 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_LEFT>;
};
slide_sw_0 {
gpios = <&axi_gpio_inputs_1 0 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_0>;
};
slide_sw_1 {
gpios = <&axi_gpio_inputs_1 1 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_1>;
};
slide_sw_2 {
gpios = <&axi_gpio_inputs_1 2 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_2>;
};
slide_sw_3 {
gpios = <&axi_gpio_inputs_1 3 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_3>;
};
};
};
mbv32.overlayを用意したらビルドを行います。
cd $HOME/zephyrproject/zephyr/samples/subsys/input/input_dump/
west build -p -b mbv32
src/main.cには起動時のメッセージ出力処理しか実装されていません。このプログラムはInput Subsystemが持つ機能を使ってイベント情報を出力しており、prj.confのCONFIG_INPUT_EVENT_DUMPの定義で有効化されています。
CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y
CONFIG_INPUT=y
CONFIG_INPUT_EVENT_DUMP=y
実行手順
プログラムの実行はビルドを行ったフォルダ配下で下記コマンドを実行して下さい。
cd $HOME/zephyrproject/zephyr/samples/subsys/input/input_dump/
west flash --runner xsdb --elf-file ./build/zephyr/zephyr.elf --bitstream $SDT_DIR/$PROJ_NAME.bit
プログラムが起動するとPush ButtonやSlide SwitchのON/OFFに応じてイベント情報がコンソールへ出力されます。
*** Booting Zephyr OS build xilinx_v2024.2-111-g986cf11c05ea ***
Input sample started
I: input event: dev=buttons SYN type= 1 code=103 value=1
I: input event: dev=buttons SYN type= 1 code=103 value=0
I: input event: dev=buttons SYN type= 1 code= 11 value=1
I: input event: dev=buttons SYN type= 1 code= 2 value=1
I: input event: dev=buttons SYN type= 1 code= 11 value=0
I: input event: dev=buttons SYN type= 1 code= 2 value=0
I: input event: dev=buttons SYN type= 1 code= 3 value=1
I: input event: dev=buttons SYN type= 1 code= 3 value=0
...
debounce処理が入っているので、Push Buttonを連続で押したりSlide Switchを中途半端な状態で止めても、イベント情報が変な形で表示される事はありません。
それでも私の環境では一部のSlide Switchに反応が異様に遅い現象が見られました。この様な場合はスイッチに物理的問題があると思われます。
Devicetree定義内容
今回追加したmbv32.overlayの基本構成は変わりませんがzephyr,codeとdebounce-interval-msが追加されています。入力デバイスとして4つのPush Buttonと右端4つ分のSlide Switchに対して定義してあります。
十字状に配置されたPush Buttonの中央は押さないで下さい。これはBlockDesignのreset信号に割り当てられています。アサインしなければ良いだけの話なのですが、ボードのデフォルト設定ではこの様な割り当てになっています。
一般的なdebounce処理では、ボタンの押下等で入力状態の変化を捉えると一定時間待った後に再度状態を確かめるという処理でチャタリングの影響を回避します。この時の待ち時間をdebounce-interval-msによりms単位で指定します。この値はデフォルトで30msとなっています。
kephyr,codeはInputにより通知されるkey codeになります。この割り当ては任意に変更可能です。BASYS3のPush Buttonは十字状に配置されていますので、今回はUP, RIGHT, DOWN, LEFTの値を割り当ててみました。これらは$HOME/zephyrproject/zephyr/include/zephyr/dt-bindings/input/input-event-codes.hで定義されています。
Slide Switchに関しては右端の4つ分しか定義していません。他のSwitchの定義を追加すればInputで認識可能となります。Slide Switchはgpiosの2番の値で物理スイッチを指定します。例えば、slide_sw_3の定義では3が物理スイッチの番号に相当します。この値は0-15の範囲で指定可能です。
slide_sw_3 {
gpios = <&axi_gpio_inputs_1 3 GPIO_ACTIVE_HIGH>;
zephyr,code = <INPUT_KEY_3>;
};
おわりに
debounce処理は自前で簡単に実装できる機能ですが、システムで用意されているのはありがたいです。
次は7-segment displayの制御を実装してみる予定です。