Arm LinuxもRTOSも知らない人が理解しようと奮闘した残渣
※ 内容に自信がないので、当記事を論拠とする引用はお控えください。
※ やってみた的な引用、こう言ってる人もいる的な引用などはOK。
zephyr 2.7.99
#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#define SLEEP_TIME_MS 1000
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
#else
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED0 ""
#define PIN 0
#define FLAGS 0
#endif
void main(void)
{
const struct device *dev;
bool led_is_on = true;
int ret;
dev = device_get_binding(LED0);
if (dev == NULL) {
return;
}
ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
if (ret < 0) {
return;
}
while (1) {
gpio_pin_set(dev, PIN, (int)led_is_on);
led_is_on = !led_is_on;
k_msleep(SLEEP_TIME_MS);
}
}
include プリプロセッサ
#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
6. #include <zephyr.h>
7. #include <device.h>
8. #include <devicetree.h>
9. #include <drivers/gpio.h>
define プリプロセッサ
#define SLEEP_TIME_MS 1000
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
#else
#error "Unsupported board: led0 devicetree alias is not defined"
#define LED0 ""
#define PIN 0
#define FLAGS 0
#endif
11. #define SLEEP_TIME_MS 1000
よくあるスリープ秒数を決めるやつ。
デフォルトで1000[ms]
13. #define LED0_NODE DT_ALIAS(led0)
Zephyr API Documentation: Existence checks
led0というエイリアスがボードのdtsに存在するか調べて、そのノードidを返す。
Devicetree API — Zephyr Project Documentation
DT_ALIAS()マクロはzephyr/include/devicetree.h
内で定義されている。
aaaaaを抽象化するのに役立つ。
エイリアスとは
led0などのほかによく使われるエイリアス名はあるの?
おそらく無い。ボードのdtsも自分達で作る想定だから。
ledだけ例外?
他のチュートリアルファイルを見るとわかるかも。
ボードのdtsとは
今回の場合nucleo-f746のdtsファイル。
dtsはデバイスツリーを記述している。
以下今回の参照先のdtsファイルから一部抜粋
zephyr/nucleo_f746zg.dts at main · zephyrproject-rtos/zephyr · GitHub
leds {
compatible = "gpio-leds";
green_led: led_0 {
gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>;
label = "User LD1";
};
blue_led: led_1 {
gpios = <&gpiob 7 GPIO_ACTIVE_HIGH>;
label = "User LD2";
};
red_led: led_2 {
gpios = <&gpiob 14 GPIO_ACTIVE_HIGH>;
label = "User LD3";
};
};
aliases {
led0 = &green_led;
led1 = &blue_led;
led2 = &red_led;
sw0 = &user_button;
};
デバイスツリーとは
デバイス固有の情報(プロパティ)を抽象化するために、Arm Linuxで設けられた仕組み。
デバイス固有のピン番号などの情報を他から隠蔽している。
今回の場合、上記ボードのdtsファイル、そしてSTM32のチップ自体のdtsiファイルがある。
dtsiファイル
zephyr/stm32f7.dtsi at main · zephyrproject-rtos/zephyr · GitHub
gpiob: gpio@40020400 {
compatible = "st,stm32-gpio";
gpio-controller;
#gpio-cells = <2>;
reg = <0x40020400 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_AHB1 0x00000002>;
label = "GPIOB";
};
STMGPIOのbindingファイル
#
zephyr/st,stm32-gpio.yaml at main · zephyrproject-rtos/zephyr · GitHub
抜粋
description: STM32 GPIO node
compatible: "st,stm32-gpio"
include: [gpio-controller.yaml, base.yaml]
properties:
reg:
required: true
label:
required: true
clocks:
required: true
"#gpio-cells":
const: 2
gpio-cells:
- pin
- flags
LEDのbindingファイル
zephyr/dts/bindings/gpio/gpio-leds.yaml
zephyr/gpio-leds.yaml at main · zephyrproject-rtos/zephyr · GitHub
抜粋
description: GPIO LEDs parent node
compatible: "gpio-leds"
include:
- name: base.yaml
property-allowlist: [label]
properties:
label:
description: |
Human readable string describing the device and used to set the device
name. It can be passed as argument to device_get_binding() to retrieve
the device. If this property is omitted, then the device name is set
from the node full name.
child-binding:
description: GPIO LED child node
properties:
gpios:
type: phandle-array
required: true
label:
required: false
type: string
description: |
Human readable string describing the LED. It can be used by an
application to identify this LED or to retrieve its number/index
(i.e. child node number) on the parent device.
ノードIDとは
各ノードに自動的に振られるID。
ノードとは
green_led
、blue_led
など。
14. #if DT_NODE_HAS_STATUS(LED0_NODE, okay)
DT_NODE_HAS_STATUS()
でボードが特定のノードを持っているか調べられる
Nucleoは"led0"を最初から持っているのでこの#if内に分岐する
15. #define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
Devicetree API — Zephyr Project Documentation
ノードID, phandleからラベルを取得する。
phandleとは
おそらくparent handle
Arm Linux デバイスツリーからの輸入。
とあるエンジニアの備忘log: Device Tree 入門
(今回ならLED0)にとっての親要素のハンドル(適当な整数値)。
今回はボードのdtsファイル内でgpiobを指定している。
するとdtsiファイル内のgpiobと紐づく。
phandleの書式
Introduction to devicetree — Zephyr Project Documentation
a-phandle = <&mynode>;
some-phandles = <&mynode0 &mynode1 &mynode2>;
a-phandle-array = <&mynode0 1 2 &mynode1 3 4>;
ラベルとは
"User LD1"
、"User LD2"
など
dtsファイル内に記載。
ノードの検索ワードみたいなもの?
何のために存在しているのか不明。
そもそもなぜ引数にphandleが必要なんだろう。
ノードIDがあれば特定できるものではないのかな?
ノードIDは親ごとに振られるのかな?
DT_GPIO_LABEL()マクロはzephyr/include/devicetree/gpio.h
内で定義されている。ただし、当該ヘッダファイルはdevicetree.h
からインクルードされているため、includeする必要はない。
16. #define PIN DT_GPIO_PIN(LED0_NODE, gpios)
Devicetree API — Zephyr Project Documentation
DT_GPIO_PIN_BY_IDX()の特別な場合。
こちらでは引数が1つ多く。
`
DT_GPIO_PIN_BY_IDX(node_id, gpio_pha, idx)となる。
ピンという名前のセルを持つ
DT_GPIO_PIN()マクロはzephyr/include/devicetree/gpio.h
内で定義されている。ただし、当該ヘッダファイルはdevicetree.h
からインクルードされているため、includeする必要はない。
セルとは
Devicetree bindings — Zephyr Project Documentation
phandleに記述する付加情報。引数。
例えばボードのdtsにある
gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>;
だったら、
0
GPIO_ACTIVE_HIGH
がセル。
dtsiファイルの中に
dt-cells = <2>;
とあり、これはセルを2つ持つという意味
またSTMGPIOのbindingファイルの中に
"#gpio-cells":
const: 2
gpio-cells:
- pin
- flags
とあり、これはセルを記述している。
なので、
gpios(gpioのphandle array) は gpiobである
pin = 0
flags = GPIO_ACTIVE_HIGH
という意味になる。
17. #define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
Devicetree API — Zephyr Project Documentation
DT_GPIO_FLAGS()マクロはzephyr/include/devicetree/gpio.h
内で定義されている。ただし、当該ヘッダファイルはdevicetree.h
からインクルードされているため、includeする必要はない。
#define FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
18-24 #else - #endif
単なるエラー処理。"led0"がなかった時の挙動を決めてる。
27 const struct device *dev;
30. dev = device_get_binding(LED0);
device_get_binding(LED0)
↓#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
↓↓ #define LED0_NODE DT_ALIAS(led0)
↓#define LED0 DT_GPIO_LABEL( <"led0"のnode id>, gpios)
device_get_binding("User LD1")
defineマクロなのでgpiosに""はいらないッテコト!?
34. ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
ret = gpio_pin_configure(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS);
↓#define PIN DT_GPIO_PIN(LED0_NODE, gpios)
boardの.dtsにgpios = <&gpiob 0 GPIO_ACTIVE_HIGH>;
0とあるので
ret = gpio_pin_configure(dev, 0 , GPIO_OUTPUT_ACTIVE | FLAGS);
ret = gpio_pin_configure(dev, 0 , GPIO_OUTPUT_ACTIVE | FLAGS);
39. gpio_pin_set(dev, PIN, (int)led_is_on);
41. k_msleep(SLEEP_TIME_MS);
GPIO
GPIO — Zephyr Project Documentation
LED API
LED — Zephyr Project Documentation
Device Tree
とあるエンジニアの備忘log: Device Tree 入門
Device Tree Binding
Devicetree bindings — Zephyr Project Documentation
バスを考慮する
Devicetree bindings — Zephyr Project Documentation
zephyr/dts/bindings/gpio/gpio-leds.yaml
LEDのbinding
zephyr/gpio-leds.yaml at main · zephyrproject-rtos/zephyr · GitHub