1. はじめに
Zephyr の深淵へようこそ。
本記事は、Zephyr の最大の鬼門と思われる Devicetree を覗き込む内容の、其の参の最終章となります。
まだ序章や其の壱、其の弐に触れていない方は、まずはそちらから読み進める事をお勧めします。
Zephyr 公式の Devicetree ドキュメントはこちら。序章と深淵はおよそこの内容をカバーしており、これらを理解できれば Devicetree の書き方に関してはおよそ掴めるはずです。
今回も以下の環境をベースに話を進めます。
| board | Zephyr 環境 | ビルド対象のアプリ |
|---|---|---|
| rpi_pico | ~/zephyrproject | zephyr/sample/basic/minimal |
2. 序章のおさらい
本記事は、序章で紹介した下記テーブルを深堀する内容となります。其の壱は *.dts, *.dtsi
| ファイル名 | 概要 | 取り扱い記事 |
|---|---|---|
| *.dts | Devicetree source. これにベースに下記ファイルが連結されていく | 其の壱 |
| *.dtsi | dts から include して定義を追加できるようにしたファイル | 其の壱 |
| *.overlay | dts の定義を上書きで変更を加えるためのファイル | 序章 |
| *.yaml | dts / overlay 内で利用する左辺値(プロパティ名)の定義 | 其の弐 |
| *.h | dts / overlay 内で利用する右辺値(プロパティ値)の定義 | 其の参 |
| zephyr.dts | ビルド時に上記ファイル群が結合され、最終的な dts として生成 | 序章 |
*.dtsi は、名前の通り dts や dtsi から include されるファイルで、dts に直接的に関与します。一方で *.yaml と *.h は 間接的に dts 関与するファイル群となります。
今回はこの *.h の役割や何が書かれているかについて触れていきます。
3. *.h に記載されている内容
一般的なヘッダーファイルと同様に、devicetree に於ける *.h も定義が主な役割となります。
たとえば、rpi_pico の i2c のスピードモードはデフォルトでは以下のように I2C_BITRATE_STANDARD が設定されています。
この文字列を設定するとそれに該当する値が反映されるわけですが、実際にこの文字列を見ただけでは何が設定されるかわかりません。
また、別のパラメータを設定しようとしたとき、他にどんなパラメータの選択肢があるかもわかりません。
そこで参照すべきファイルが、本記事のメインである *.h ファイルとなるわけです。
&i2c0 {
clock-frequency = <I2C_BITRATE_STANDARD>;
status = "okay";
pinctrl-0 = <&i2c0_default>;
pinctrl-names = "default";
};
と、それを確認する前に、このデフォルトの設定値は最終的にどんな値になっているかを確認してみます。
i2c0: pico_i2c0: i2c@40044000 {
:
clock-frequency = < 0x186a0 >;
status = "okay";
:
};
west build で生成された値は 0x186a0 になっており、これを 10 進数に変換すると 100,000 となります。
つまりこの I2C_BITRATE_STANDARD に関しては、最終的に 100000 の数値に置き換えられていることになります。
I2C の bitrate で汎用的な数値である 100kbps と合致しており、定義名から期待される値が定義されていることがわかります。
ちなみに、この定義名を数値に置き換えてもビルドは可能です。
実際にI2C_BITRATE_STANDARDを適当な数値に書き換えると、生成されるzephyr.dtsもその数値が反映されます(ただし実際にそのbpsで動くかは別問題)。
4. dts を構成するパラメータ群の確認
それでは、どこを参照してどんな風に変えていくのか順を追って確認していきます。
4.1. dts の右辺に使用する定義の配置場所
基本的に先述の I2C_BITRATE_STANDARD といった右辺で使う定義は以下のディレクトリで管理されています。
$ ls zephyr/include/zephyr/dt-bindings
acpi ethernet lvgl qspi
adc flash_controller memory-attr rdc
battery gnss memory-controller regulator
clock gpio mfd reserved-memory
comparator i2c mipi_dbi reset
dac input mipi_dsi sensor
dai inputmux misc spi
display interrupt-controller pcie timer
dma ipc_service pinctrl usb
dt-util.h led power usb-c
espi lora pwm video
4.2. 具体的な定義とその値の確認
では、I2C を例に確認していきましょう。
右辺に入る定義は以下のファイルにそれぞれ定義されています。
#define I2C_BITRATE_STANDARD 100000 /* 100 Kbit/s */
#define I2C_BITRATE_FAST 400000 /* 400 Kbit/s */
#define I2C_BITRATE_FAST_PLUS 1000000 /* 1 Mbit/s */
#define I2C_BITRATE_HIGH 3400000 /* 3.4 Mbit/s */
#define I2C_BITRATE_ULTRA 5000000 /* 5 Mbit/s */
試しに I2C_BITRATE_STANDARD を I2C_BITRATE_ULTRA に書き換えて生成してみます。
(定義元を直接編集するのは Zephyr では非推奨です。実運用で変更する場合は、序章で紹介している overlay の仕組みを利用しましょう)
&i2c0 {
clock-frequency = <I2C_BITRATE_ULTRA>; <---- 変更箇所
status = "okay";
pinctrl-0 = <&i2c0_default>;
pinctrl-names = "default";
};
改めて west build -b rpi_pico zephyr/samples/basic/minimal で dts を生成すると 5000000(10進数) → 0x4c4b40(16進数) に値が反映されていることが確認できます。
i2c0: pico_i2c0: i2c@40044000 {
:
clock-frequency = < 0x4c4b40 >; /* in zephyr/boards/raspberrypi/rpi_pico/rpi_pico-common.dtsi:104 */
:
他にも GPIO の設定として利用できる GPIO_ACTIVE_LOW なども同じ階層のヘッダーファイルに定義されています。
/** GPIO pin is active (has logical value '1') in low state. */
#define GPIO_ACTIVE_LOW (1 << 0)
/** GPIO pin is active (has logical value '1') in high state. */
#define GPIO_ACTIVE_HIGH (0 << 0)
ボードやチップメーカーによって、それぞれの設計思想がこの辺りに反映されていたりしていて、例えば GPIO のヘルパー関数を用意しているメーカーもあり、工夫(≒個性)が出てくる箇所でもあります。
#define XEC_GPIO_HELPER(gpio_bank, gpio_bitpos) gpio_bank gpio_bitpos
/* bank A */
#define MCHP_GPIO_DECODE_000 XEC_GPIO_HELPER(&gpio_000_036, 0)
#define MCHP_GPIO_DECODE_001 XEC_GPIO_HELPER(&gpio_000_036, 1)
#define MCHP_GPIO_DECODE_002 XEC_GPIO_HELPER(&gpio_000_036, 2)
#define MCHP_GPIO_DECODE_003 XEC_GPIO_HELPER(&gpio_000_036, 3)
:
leds {
compatible = "gpio-leds";
led4: led_0 {
/* GPIO241/CMP_VOUT0/PWM0_ALT on schematic,
* LED4 on silkscreen.
*/
gpios = <MCHP_GPIO_DECODE_241 GPIO_ACTIVE_HIGH>;
label = "LED 4";
};
5. まとめ
今回、Devicetree を記述する際に、参照すべきファイルや設定などを紹介しました。
序章から其の壱、其の弐、其の参それぞれ読み通していけば、最低限必要な設定が把握でき、overlay の編集や作成ができるようになると思います。
とはいえ、Arudino のようにレジスタなどを意識せず開発に着手できるような実装になっておらず、マイコンのデータシートや各ベンダーの個性を読み解いたうえで利用する必要があり、記述の仕方の理解だけで自由自在に扱えるかというと、そうでもないのが実情です。
逆にいうと Zephyr は H/W 性能を活かせるとも言え、また、Arduino は"基本的には"ソースコード開示の義務を負ってしまう LGPL なのに対し、Zephyr は販売などにも都合の良い Apache ライセンスでもあるため、個人・ホビー用途の Arduino に対して業務用/本格派の Zephyr という棲み分けができるかと思います。
6. 2024年アドベントカレンダーの締め
ここまで 2024 年アドベントカレンダーの終盤に参加を始めて約10か月、12記事を書いてきました。
これまでの記事に目を通せば「好みのマイコンを Zephyr で動かしてみたい!」ができるようになる内容に仕上がっているかと思います。
今後も公私ともども、いろんなプロダクトに導入して、Zephyr を盛り上げていくつもりです。
主催が Linux Kernel も開発している Linux Fundation でもあり、信頼性や拡張性、ひいては将来性も十分期待できる RTOS になっています。
利用者が少ない今だからこそ、参加する価値は高いと思いますので、ぜひトライしてみてはいかがでしょうか?