概要
前回から引き続き、ラズパイ入門キット「SunFounder Da Vinci Kit for Raspberry Pi」に入っている機器をRaspberr Pi Pico + Zephyr OSで動かしてみた。
今回は、Segment Displayを試した。
環境
74HC595と7セグメントディスプレイを使用する。 Raspberr Pi Picoとを以下のように接続する。接続方法はSunFounderのチュートリアルを参考にした。
74HC595を使用する方法については以下のサイトを参考にした。
Arduinoからシフトレジスタ 74HC595へ SPIでデータを送る | meyon's STUDY
使用方法
前回と同様に作成したソースコードを以下に格納したので、これを使用する。
GitHub - aimdevel/my-zephyr-applications
Zephyrの開発環境構築については公式ドキュメントを参照。
Getting Started Guide — Zephyr Project Documentation
環境をセットアップ
前の記事と同様。
west init -m https://github.com/aimdevel/my-zephyr-applications.git --mr main my-workspace cd my-workspace/ west update
この手順はこのリポジトリを利用するときに1回だけ実施すればよい。
ビルド
west build -b rpi_pico apps/apps/segment_display/
別のアプリのビルド結果が残っている場合、buildディレクトリを削除してから上記のコマンドを実行すること。
基板に焼いて動作確認
時間経過でディスプレイの表示が変化することを確認する。
ソースコード説明
作成したdevicetree
作成したdevicetreeは以下。
全体は以下のようになっている。
&spi0 { status="okay"; cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; gpio_expander_0: gpio_expander0@0 { reg = <0>; compatible = "ti,sn74hc595"; reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>; ngpios = <0x8>; spi-max-frequency = <2000000>; #gpio-cells = <0x2>; gpio-controller; }; };
ドキュメントがあるのでそれに従って記述した。
ti,sn74hc595 (on spi bus) — Zephyr Project Documentation
cs-gpios
spiのチップセレクトの指定。
cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
ここで設定したGPIOが通信の際にACTIVE(=LOW)になる指定。
reset-gpios
リセットに使用するピンの指定。
ngpios
74HC595で制御できるGPIOの数。8で固定。
spi-max-frequency
周波数。適当な値でOKなはず。
このdevicetreeを記述していて気が付いたのだが、Zephyrではdevicetreeの定義を「dts/bindings/~~」にyamlファイルとして格納しておくと、その定義に合わない設定がされたときはコンパイルエラーになるようだ。
例えば、必須の設定がされていない場合や、statusに指定する値がokayやdisabled以外になっている場合などは、コンパイルに失敗する。
Linux のdevicetreeのコンパイル時には、最低限の文法に従っていればエラーが出ず、typoに気づきづらかった記憶があるので、これはありがたい。
devicetreeの関連個所
自分で作成したわけではないが、devicetreeで関係のある個所を説明する。
関係するのは以下のファイルの、spi0_default。
https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi
spi_defaultは以下のように設定されている。
spi0_default: spi0_default { group1 { pinmux = <SPI0_CSN_P17>, <SPI0_SCK_P18>, <SPI0_TX_P19>; }; group2 { pinmux = <SPI0_RX_P16>; input-enable; }; };
GPIOの17~19をそれぞれSPI0で使用する設定になっている。
Raspberry Pi PicoのPinoutを見ると、確かにGPIO17~19はSPI0で使用できるようになっている。 また、0~3、4~7でもSPI0を使用できそうだ。
ソースコード
使用したコードは以下。
https://github.com/aimdevel/my-zephyr-applications/blob/main/apps/segment_display/src/main.c
#include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/device.h> #include <zephyr/drivers/gpio.h> #include <zephyr/drivers/spi.h> #define MAX_GPIOS 1<<7 - 1 static const struct device *const gpio_ex = DEVICE_DT_GET(DT_NODELABEL(gpio_expander_0)); int main(void) { printk("start!\n"); if (!device_is_ready(gpio_ex)) { return 0; } printk("device is ready!\n"); for (int i=0;i<8;i++) { printk("gpio configure loop\n"); int ret = gpio_pin_configure(gpio_ex, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW); } k_msleep(10000); int gpio_n = 0; while (1) { printk("loop gpio_n=%d!\n",gpio_n); gpio_port_set_masked_raw(gpio_ex, 0x7f, gpio_n); //gpio_port_set_bits_raw(gpio_ex, gpio_n); k_msleep(1000); gpio_n++; if (gpio_n > MAX_GPIOS) { gpio_port_clear_bits_raw(gpio_ex, 0x7f); gpio_n = 0; } } return 0; }
- 初めにdevicetreeから情報を取得
static const struct device *const gpio_ex = DEVICE_DT_GET(DT_NODELABEL(gpio_expander_0));
- ピンの設定
ドライバの実装的にこの設定は意味がないかも。
for (int i=0;i<8;i++) { printk("gpio configure loop\n"); int ret = gpio_pin_configure(gpio_ex, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW); }
- 出力の制御 74HC595の出力を制御する。gpio_port_set_masked_rawを使用する。
gpio_port_set_masked_raw(gpio_ex, 0x7f, gpio_n);
使用方法は、
- 第一引数に、deviceの構造体を渡す。
- 第二引数に、使用できるピンを表すmaskを渡す。
8bit分の各ビットがそれぞれのピンに対応する。今回は7セグメントディスプレイのため、
01111111
を指定している。 - 第三引数に、highにするピンの情報を渡す。 第二引数と同様に8bit分のデータを渡す。ここを変化させることでディスプレイの表示を変更できる。
device driver
使用したデバイスドライバは以下。
gpio APIを使用できるデバイスとして74HC595を制御できるようになっている。
zephyr/drivers/gpio/gpio_sn74hc595.c at main · zephyrproject-rtos/zephyr · GitHub
まとめ
Raspberry Pi Pico + Zephyr OSで、74HC595を使ってセグメントディスプレイを制御した。
74HC595にはドライバが用意されており、devicetreeを書けば簡単に使用できることが分かった。
devicetreeを触っていると、Linuxで使用しているdevicetreeとの差異が見えてきて面白い。Zephyrの方にはコンパイル時のdevicetreeチェックなどがあり、これは便利だと感じたのでLinuxの方にも実装してほしい。
記事の本題とは関係ないが、Hatena Blogの機能で、AIアシスタントが記事のタイトルを考えてくれるようになったので、使ってみた。
それっぽいタイトルをつけてくれるので、これは活用していきたい。
参考
Arduinoからシフトレジスタ 74HC595へ SPIでデータを送る | meyon's STUDY
1.1.4 7セグメントディスプレイ — SunFounder davinci-kit-for-raspberry-pi ドキュメント