Shujima Blog

Apple製品,技術系の話をするブログ

zephyr memoのmemo

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_ledblue_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

当ブログをご利用いただく際には免責事項をお読みください。