Kyoto Maker

Software & Hardware Laboratory Found In Kyoto, 2015.

Helioボード: プッシュボタンの内部バス幅を2→3ビットに拡張する

はじめに

Helioボードのリファレンスデザインには、FPGA側のプッシュボタンが押されたらコンソールにそれを通知するサンプルが同梱されています。しかし、実は、Helioボードに実装されている3つのプッシュボタンのうち1つが、このサンプルでは反応してくれません。今回は、その原因を究明し、解決してみます。

今回のハイライト: Quartus IIのRTL ViewerでFPAG内部の結線状況を確認している様子です。これから赤線の一部のバス幅を2ビットから3ビットに拡張します。

f:id:fixme:20150124151540p:plain

プッシュボタンの割り込み検出サンプル

HelioボードのLinuxを起動して、rootユーザーでログインすると、ホームディレクトリにREADMEというファイルがあります。 このREADMEにリファレンスデザインで提供されている各種サンプルの動かし方が説明されています。

root@socfpga:~# cat README
Table of Contents
=================
1. Soft IP Driver Example
2. Application Examples


1. Soft IP Driver Example
=========================
GPIO driver for soft PIO in the FPGA domain serves as a reference for
writing a simple driver in Linux. The source code of this driver is located in
...

今回は試すサンプルは、「Application to register interrupt and write simple interrupt service routine」のセクションに書かれているものです。

READMEに従い、GPIOを確認してみると、以下が認識されています。

root@socfpga:~# ls -l /sys/class/gpio/
--w-------    1 root     root          4096 Jan 17 22:10 export
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip149 -> ../../devices/virtual/gpio/gpiochip149
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip152 -> ../../devices/virtual/gpio/gpiochip152
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip156 -> ../../devices/virtual/gpio/gpiochip156
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip160 -> ../../devices/virtual/gpio/gpiochip160
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip192 -> ../../devices/virtual/gpio/gpiochip192
lrwxrwxrwx    1 root     root             0 Jan 17 22:10 gpiochip224 -> ../../devices/virtual/gpio/gpiochip224
--w-------    1 root     root          4096 Jan 17 22:10 unexport

試しにgpiochip149のlabelを確認してみます。「gpio@0x1000100C0」は、button_pioモジュールのBaseアドレス(Qsysで確認できます)に一致しています。つまり、このgpiochip149がFPGA側のプッシュボタンに対応しています。

root@socfpga:~/altera# cat /sys/class/gpio/gpiochip149/label
/sopc@0/bridge@0xc0000000/gpio@0x1000100C0

READMEの説明に従い、gpio_interruptモジュールをカーネルにロードします。先ほどGPIOの149番がプッシュボタンに対応しているとわかったので、gpio_numberには149を指定します。

root@socfpga:~# modprobe gpio_interrupt gpio_number=149

プッシュボタン(SW-11)を押してみます。すると、ターミナルに「Interrupt happened at gpio:149」と表示されました。

同様に、2つ目のプッシュボタン(SW-12)でも試してみます。READMEの説明にあるように、gpio_interruptをアンロードしてから、再度モジュールをロードします。ここではgpio_numberに149+1=150を指定します。これも動作しました。

root@socfpga:~# rmmod gpio_interrupt
root@socfpga:~# modprobe gpio_interrupt gpio_number=150

この調子で、3つ目のプッシュボタン(SW-13)を試してみると、残念ながら、何も応答がありません。

原因の究明

Qsysでbutton_pioの設定を確認してみます。すると、パラレルI/OのWidthが2ビットになっていることに気づきます。プッシュボタンは3つあるのに、Widthが2ビットということは、3つあるプッシュボタンのどれかの1つの信号がHPS(ARMプロセッサ)に到達していないということになります。

f:id:fixme:20150124154134p:plain

ピン割付を確認してみます。信号線fpga_button_pioは3ビットのバスになっています。また、念のため、HelioボードのReference Manualの「4.7.1 User-Defined push button」を確認してみても、正しく接続されていることがわかります。ということは、ピン割付には問題はなく、すべてのプッシュボタンの信号はFPGAに接続されているということになります。

f:id:fixme:20150124153218p:plain

先ほどピン割付で表示されていた信号線fpga_button_pioからHPS(ARMプロセッサ)までの結線を確認していきます。Quartus IIのTools -> Netlist Viewers -> RTL Viewerを選択します。

f:id:fixme:20150124151540p:plain

結線を良く見ると、fpga_button_pio[2..0]がdebounce_instのdata_in[1..0]に接続されています。fpga_button_pioが3ビットなのに対し、data_inは2ビットのバスです。つまり、ここでプッシュボタンの信号がロストしていたわけです。

ちなみに、このdebounce_instモジュールは、スイッチをON/OFF時に発生するチャタリング対策のためのものです。(チャタリング対策は、ソフトウェア側でもできますが、リファレンスデザインではFPGA側でやっているということになります。)

また、以降に結線されている、data_out[1..0]とbutton_pio_external_connection[1..0]のいずれも2ビットのバスです。これらも3つのプッシュボタンの信号を伝達するには3ビットのバスが必要です。

button_pio_external_connectionはbutton_pioのパラレルI/Oポートですので、以上でプッシュボタンからbutton_pioまでの結線状況の確認は完了です。

まとめると、button_pioとdebouceフィルタの入出力のバス幅が2ビットになっているため、3つのプッシュボタンを動作させるには、これらのバス幅を3ビットに拡張が必要ということになります。

解決

button_pioのパラレルI/OのWidthを2ビットから3ビットに拡張します。

HDLを生成します。(Qsysのメニュー Generate -> Generate HDL)

button_pio_external_coneection_exportのバス幅が3ビットになったことを確認します。

helio_ghrd_top.vを開き、関連する箇所のバス幅を変更します。変更点は2点です。

1つ目は、debounceフィルター後の信号線fpga_debounced_buttonsです。バス幅を3ビットに拡張します。

  // wire [1:0] fpga_debounced_buttons; // 変更前
  wire [2:0] fpga_debounced_buttons;    // 変更後

2つ目は、debounceフィルターです。debounceモジュール内部のパラメータWIDTHを3ビットに拡張します。

// Debounce logic to clean out glitches within 1ms
debounce debounce_inst (
  .clk                                  (fpga_clk_50),
  .reset_n                              (hps_fpga_reset_n),  
  .data_in                              (fpga_button_pio),
  .data_out                             (fpga_debounced_buttons)
);
  // defparam debounce_inst.WIDTH = 2; // 変更前
  defparam debounce_inst.WIDTH = 3;    // 変更後

コンパイルします。

コンパイルが終わったら、RTL Viewerを開きます。バス幅が3ビットに拡張されているのを確認できます。

f:id:fixme:20150124151609p:plain

もうほぼ終わりです。後は、FPGAに書き込み、Linuxを起動後、以下のコマンドで3つ目のプッシュボタン(SW-13)に対応するGPIOを指定すると、無事3つ目のプッシュボタンも反応するようになります。

root@socfpga:~# modprobe gpio_interrupt gpio_number=151

サンプルのソースコードとモジュールのデプロイ先

問題は解決しました。しかし、gpio_interruptのソースコードのありかとmodprobeした時にどこからロードされているのか気になったので調べました。

まず、ソースコードですが、前回Linuxカーネルを自前でビルドするのに使ったビルドマシン(Ubuntu)にありました。具体的には、~/yocto/meta-altera/recipes-gsrd/pio-interrupt-altera/ です。Makefileを見ると、yoctoでgpio_interruptをビルドする時に、カーネルモジュールとしてデプロイされるように記述されています。

次に、gpio_interruptモジュールのデプロイ先ですが、gpio_interruptをmodprobeした時のシステムコールをstraceで解析してみると、gpio_interruptの実体が見つかりました。modprobe gpio_interruptすると、裏ではこのgpio_interrupt.koがロードされている、ということになります。

root@socfpga:~# ls -l /lib/modules/3.9.0/extra/
-rw-r--r--    1 root     root          4472 Jan 17 16:04 gpio_interrupt.ko

おわりに

原因を特定して解決できた時は、ハードウェアでもソフトウェアと同じで、とても楽しいです。 今回はじめてGPIOに入門したので、今後、もう少し踏み込んでみたいです。