Arm LinuxもRTOSも知らない人が理解しようと奮闘した残渣
※ 内容に自信がないので、当記事を論拠とする引用はお控えください。 ※ やってみた的な引用、こう言ってる人もいる的な引用などはOK。
zephyr 2.7.99
/* * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr.h> #include <device.h> #include <devicetree.h> #include <drivers/gpio.h> /* 1000 msec = 1 sec */ #define SLEEP_TIME_MS 1000 /* The devicetree node identifier for the "led0" alias. */ #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 /* A build error here means your board isn't set up to blink an LED. */ #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 プリプロセッサ
/* 1000 msec = 1 sec */ #define SLEEP_TIME_MS 1000 /* The devicetree node identifier for the "led0" alias. */ #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 /* A build error here means your board isn't set up to blink an LED. */ #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"; //←device Tree Binding(yamlファイル)の名前 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