Shujima Blog

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

【Mac/Watch】Apple製品をぜんぶ充電するには?USB-C充電器オススメ21選

f:id:masa_flyu:20220122143336p:plain

Apple製品の充電、皆様はどうしていますか?

私は、出先でちょっとした作業をすることも多く、iPhoneやApple Watchはもちろんのこと、MacBook ProやiPad Proも持ち歩いています。

そんなApple製品等ですが、日帰りならともかく、ちょっと外泊でもすると、途端に充電の問題がつきまといます。

そして、全てを充電するためには

  • MacBook Pro用のUSB-C充電器 USB-Cケ## Aブル
  • iPad Pro用のUSB-C充電器 USB-Cケーブル
  • iPhone用のUSB充電器・Lightningケーブル
  • AirPods Pro用のUSB充電器・Lightningケーブル
  • Apple Watch用のUSB充電器・専用ケーブル

合計5個の充電器、3種類5本の充電ケーブルを持ち運ぶはめになります。

これはあまりにしんどい...

そこで、いくつかのユースケースで最適な充電器、ケーブルの構成を考え、ベストバイな充電器・ケーブルを考えてみました。

と一言で言うのは簡単ですが、実際には膨大な数のACアダプタ、ケーブル、バッテリー、充電端子の組み合わせが存在しています。

それらの中からスマートで多くの場合に対応できる組み合わせを探してみました。

Apple製品をたくさん充電しているみなさんのご参考になれば幸いです。

  • 充電器
  • パターン1:4ポートACアダプタで全部充電する
    • パターン1のメリット・デメリット
    • パターン1の充電性能
    • パターン1に必要なもの
      • 63W 4ポート
      • Apple デュアル充電パッド
      • USB-C to USB-Cケーブル
      • USB-C to Lightningケーブル
      • USB-C to USB-Aケーブル
      • USB-A to Lightningケーブル
  • パターン2 : 充電器を2つ以上に増やす
    • パターン2の充電性能
    • パターン2に必要なもの
      • 40W 2ポート充電器(iPhone / iPad等に最適)
      • 65W 2ポート充電器(MacBook等に最適)
      • Apple デュアル充電パッド
      • USB-C to USB-Cケーブル 2本
      • USB-C to Lightningケーブル 2本
  • パターン3: Macをハブがわりに使う
    • パターン3の充電性能
    • パターン3に必要なもの
      • 65W 2ポート充電器(MacBook等に最適)
      • Apple デュアル充電パッド
      • USB-C to USB-Cケーブル 2本
      • USB-C to Lightningケーブル 2本
  • パターン4: 充電器2つ+Mac利用
    • パターン4の充電性能
    • パターン4で必要なもの
      • Apple デュアル充電パッド
      • USB-C to USB-Cケーブル 2本
      • USB-C to Lightningケーブル 2本
  • デュアル充電パッドの代わりになりそうなもの
続きを読む

【USB-C、MagSafe...】増えすぎたAppleデバイスの充電規格まとめ

f:id:masa_flyu:20220121232433p:plain

自分でまとめてて混乱してきました。

皆様、Apple製品を正しく充電していますか?

Apple製品をたくさん買っていたり、定期的に買い替えている人の中で、自分の持っているApple製品の充電性能を正しく把握している人はどのくらいいるのでしょうか?

案外、忘れていたり、気づかないでいるかもしれません。

せっかく搭載されている機能なんですから勿体無い。

そこで改めて、今発売されている / 過去数年に発売されたApple製品の充電方法をまとめてみました。

本当は自分で充電器を買おうと思って、情報を整理していたのですが、あまりに量が多くて、とうとう1つの記事を書く羽目になりました。

  • iPhone
  • AirPods / AirPods Pro
    • AirPods第1世代、第2世代 with Charging Case
    • AirPods Pro
  • Apple Watch
  • iPad
  • Mac
  • 以上のまとめ
続きを読む

STM32 NUCLEO-F746ZG Zephyr PWM出してみた(自分用メモ2)

自分用memo

やってること

STM32 Nucleo-F746ZGボードでPWM出力可能な全ピン32ヶ所からPWMを出す。

ただし、

www.shujima.work

こちらの記事とは違って、ボードファイルから作るパターンを試してみた。 実行結果は変わらない。

作成

構成は以下の通り

  • prj_f746
    • boards
      • arm
        • prj_f746
          • prj_f746_defconfig
          • prj_f746.dts
          • prj_f746.yaml
          • Kconfig.board
          • Kconfig.defconfig
          • board.cmake
          • support/
            • openocd.cfg
    • src
      • main.c
    • CMakeLists.txt
    • prj.conf

ただし

  • src
    • main.c
  • CMakeLists.txt
  • prj.conf

は前と変わらないため省略。

前回作成していたapp.overlayは、今回ボードのdtsファイルを自由に記述できることから、内容をその中に組み込むこととした。

boards/arm/prj_f746/prj_f746.defconfig

ボード固有のコンフィグを設定。 プロジェクト内で必要がある場合は、prj.confに記載することによって追記できる。

zephyr/nucleo_f746zg_defconfig at main · zephyrproject-rtos/zephyr · GitHub

boards/arm/prj_f746/prj_f746.dts

ボード内のデバイスツリーを記入。

大半はf746の公式デバイスツリーをそのまま使っている。

zephyr/nucleo_f746zg.dts at main · zephyrproject-rtos/zephyr · GitHub

ただし、前回app.overlayに追記した内容を今回はあらかじめ組み込んでいる。

/dts-v1/;
#include <st/f7/stm32f746Xg.dtsi>
#include <st/f7/stm32f746zgtx-pinctrl.dtsi>

/ {
    model = "STMicroelectronics STM32F746ZG-NUCLEO board";
    compatible = "st,stm32f746zg-nucleo";

    chosen {
        zephyr,console = &usart3;
        zephyr,shell-uart = &usart3;
        zephyr,sram = &sram0;
        zephyr,flash = &flash0;
        zephyr,dtcm = &dtcm;
        zephyr,canbus = &can1;
    };

    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";
        };
    };

    gpio_keys {
        compatible = "gpio-keys";
        user_button: button_0 {
            label = "User";
            gpios = <&gpioc 13 GPIO_ACTIVE_HIGH>;
        };
    };

    aliases {
        led0 = &green_led;
        led1 = &blue_led;
        led2 = &red_led;
        sw0 = &user_button;
    };
};

&clk_hse {
    hse-bypass;
    clock-frequency = <DT_FREQ_M(8)>; /* STLink 8MHz clock */
    status = "okay";
};

&pll {
    div-m = <4>;
    mul-n = <72>;
    div-p = <2>;
    div-q = <3>;
    clocks = <&clk_hse>;
    status = "okay";
};

&rcc {
    clocks = <&pll>;
    clock-frequency = <DT_FREQ_M(72)>;
    ahb-prescaler = <1>;
    apb1-prescaler = <2>;
    apb2-prescaler = <1>;
};

&usart2 {
    pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6
             &usart2_rts_pd4 &usart2_cts_pd3>;
    pinctrl-names = "default";
    current-speed = <115200>;
};

&usart3 {
    pinctrl-0 = <&usart3_tx_pd8 &usart3_rx_pd9>;
    pinctrl-names = "default";
    current-speed = <115200>;
    status = "okay";
};

&usart6 {
    pinctrl-0 = <&usart6_tx_pg14 &usart6_rx_pg9>;
    pinctrl-names = "default";
    current-speed = <115200>;
    status = "okay";
};

zephyr_udc0: &usbotg_fs {
    pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>;
    pinctrl-names = "default";
    status = "okay";
};

&i2c1 {
    pinctrl-0 = <&i2c1_scl_pb8 &i2c1_sda_pb9>;
    pinctrl-names = "default";
    status = "okay";
    clock-frequency = <I2C_BITRATE_FAST>;
};

&timers1 {
    st,prescaler = <0>;
    status = "okay";

    pwm1: pwm {
        status = "okay";
        pinctrl-0 = <&tim1_ch1_pe9 &tim1_ch2_pe11 &tim1_ch3_pe13 &tim1_ch4_pe14>;
        pinctrl-names = "default";
    };
};


&timers2 {
    st,prescaler = <0>;
    status = "okay";

    pwm2: pwm {
        status = "okay";
        pinctrl-0 = <&tim2_ch1_pa15 &tim2_ch2_pb3 &tim2_ch3_pb10 &tim2_ch4_pb11>;
        pinctrl-names = "default";
    };
};

&timers3 {
    st,prescaler = <0>;
    status = "okay";

    pwm3: pwm {
        status = "okay";
        pinctrl-0 = <&tim3_ch1_pb4 &tim3_ch2_pb5 &tim3_ch3_pb0 &tim3_ch4_pb1>;
        pinctrl-names = "default";
    };
};

&timers4 {
    st,prescaler = <0>;
    status = "okay";

    pwm4: pwm {
        status = "okay";
        pinctrl-0 = <&tim4_ch1_pb6 &tim4_ch2_pd13 &tim4_ch3_pb8 &tim4_ch4_pb9>;
        pinctrl-names = "default";
    };
};

&timers5 {
    st,prescaler = <0>;
    status = "okay";

    pwm5: pwm {
        status = "okay";
        pinctrl-0 = <&tim5_ch1_pa0 &tim5_ch2_pa1 &tim5_ch3_pa2 &tim5_ch4_pa3>;
        pinctrl-names = "default";
    };
};

&timers8 {
    st,prescaler = <0>;
    status = "okay";

    pwm8: pwm {
        status = "okay";
        pinctrl-0 = <&tim8_ch1_pc6 &tim8_ch2_pc7 &tim8_ch3_pc8 &tim8_ch4_pc9>;
        pinctrl-names = "default";
    };
};

&timers9 {
    st,prescaler = <0>;
    status = "okay";

    pwm9: pwm {
        status = "okay";
        pinctrl-0 = <&tim9_ch1_pe5 &tim9_ch2_pe6>;
        pinctrl-names = "default";
    };
};

&timers10 {
    st,prescaler = <0>;
    status = "okay";

    pwm10: pwm {
        status = "okay";
        pinctrl-0 = <&tim10_ch1_pf6>;
        pinctrl-names = "default";
    };
};

&timers11 {
    st,prescaler = <0>;
    status = "okay";

    pwm11: pwm {
        status = "okay";
        pinctrl-0 = <&tim11_ch1_pf7>;
        pinctrl-names = "default";
    };
};

&timers12 {
    st,prescaler = <0>;
    status = "okay";

    pwm12: pwm {
        status = "okay";
        pinctrl-0 = <&tim12_ch1_pb14 &tim12_ch2_pb15>;
        pinctrl-names = "default";
    };
};

&timers13 {
    st,prescaler = <0>;
    status = "okay";

    pwm13: pwm {
        status = "okay";
        pinctrl-0 = <&tim13_ch1_pf8>;
        pinctrl-names = "default";
    };
};

&timers14 {
    st,prescaler = <0>;
    status = "okay";

    pwm14: pwm {
        status = "okay";
        pinctrl-0 = <&tim14_ch1_pf9>;
        pinctrl-names = "default";
    };
};




&spi1 {
    pinctrl-0 = <&spi1_sck_pa5 &spi1_miso_pa6 &spi1_mosi_pa7>;
    pinctrl-names = "default";
    cs-gpios = <&gpiod 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
    status = "okay";
};

&iwdg {
    status = "okay";
};

&rtc {
    status = "okay";
};

&can1 {
    pinctrl-0 = <&can1_rx_pd0 &can1_tx_pd1>;
    pinctrl-names = "default";
    bus-speed = <125000>;
    sjw = <1>;
    prop-seg = <0>;
    phase-seg1 = <6>;
    phase-seg2 = <5>;
    status = "okay";
};

&dma2 {
    status = "okay";
};

&adc1 {
    pinctrl-0 = <&adc1_in0_pa0>;
    pinctrl-names = "default";
    status = "okay";
};

&rng {
    status = "okay";
};

&mac {
    status = "okay";
    pinctrl-0 = <&eth_mdc_pc1
             &eth_rxd0_pc4
             &eth_rxd1_pc5
             &eth_ref_clk_pa1
             &eth_mdio_pa2
             &eth_crs_dv_pa7
             &eth_tx_en_pg11
             &eth_txd0_pg13
             &eth_txd1_pb13>;
    pinctrl-names = "default";
};

&backup_sram {
    status = "okay";
};

boards/arm/prj_f746/prj_f746.yaml

なくても動く?

zephyr/nucleo_f746zg.yaml at main · zephyrproject-rtos/zephyr · GitHub

boards/arm/prj_f746/Kconfig.board

Kconfig — Zephyr Project Documentation

zephyr/Kconfig.board at main · zephyrproject-rtos/zephyr · GitHub

boards/arm/prj_f746/Kconfig.defconfig

zephyr/Kconfig.defconfig at main · zephyrproject-rtos/zephyr · GitHub

boards/arm/prj_f746/board.cmake

west flashするのに必要

board_runner_args(jlink "--device=STM32F746ZG" "--speed=4000")

include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

boards/arm/prj_f746/support/openocd.cfg

openocdの設定ファイルwest flashするのに必要

source [find board/st_nucleo_f7.cfg]

$_TARGETNAME configure -event gdb-attach {
        echo "Debugger attaching: halting execution"
        reset halt
        gdb_breakpoint_override hard
}

$_TARGETNAME configure -event gdb-detach {
        echo "Debugger detaching: resuming execution"
        resume
}

ビルドコマンド

west build -b f746_Actuator -- -DBOARD_ROOT=(ディレクトリ)/prj_f746

実行コマンド

west flash

STM32 NUCLEO-F746ZG Zephyr PWM出してみた(自分用メモ1)

自分用memo

やってること

STM32 Nucleo-F746ZGボードでPWM出力可能な全ピン32ヶ所からPWMを出す。

Version

cd ~/zephyrproject/zephyr
cat VERSION
VERSION_MAJOR = 2
VERSION_MINOR = 7
PATCHLEVEL = 99
VERSION_TWEAK = 0
EXTRAVERSION =

なので、Zephyr 2.7.99

Zephyr 3系だと動かない可能性高し

west --version v0.12.0 python --version Python 3.7.6

プロジェクトの作成

appを作っていく。お好きなエディタでいくつかのファイルを作成・記述していく。

最小構成のディレクトリ

最小構成は以下の通り

参考: https://docs.zephyrproject.org/latest/application/index.html#overview

<home>/app
├── CMakeLists.txt
├── prj.conf
└── src
    └── main.c

今回はappの名前をprj_f746とした。

ボード定義はzephyrに最初から含まれているnucleo_f746zgのものを利用する。

ただし、今回作成するPWMのアプリケーションに必要なタイマーの記述が、元のボード定義に不足していたため、新たにapp.overlayファイルを追加する必要がある。

<home>/app
├── CMakeLists.txt
├── prj.conf
├── app.overlay
└── src
    └── main.c

CMakeLists.txt

prj_f746ディレクトリ直下にCMakeLists.txtを作成

引用: https://docs.zephyrproject.org/latest/application/index.html#creating-an-application

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr)
project(prj_f746)

target_sources(app PRIVATE src/main.c)

prj.conf

prj_f746ディレクトリ直下にprj.confを作成

標準だとGPIOしか有効になっていないので、PWMなどのおしゃれな機能を使おうとしても動かない。なお動かなくてもビルドエラーは出ない(n敗)。

以下を記述する。

CONFIG_PWM=y

src/main.c

PWMを全部出してみた。 ただし、nucleoに乗ってる青色LED(LD2, PB7)は動作チェック用に点滅(1Hz)動作にしてある。

この点滅動作含めコードのほとんどはblinkyのサンプルから流用している。

zephyr/samples/basic/blinky at main · zephyrproject-rtos/zephyr · GitHub

#include <zephyr.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <drivers/pwm.h>

#include <stdio.h>


//#include <dt-bindings/pwm/pwm.h>

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   1000

/* The devicetree node identifier for the "led2" alias. */

#define LED2_NODE DT_ALIAS(led2)

#if DT_NODE_HAS_STATUS(LED2_NODE, okay)
#define LED2   DT_GPIO_LABEL(LED2_NODE, gpios)
#define PIN    DT_GPIO_PIN(LED2_NODE, gpios)
#define FLAGS  DT_GPIO_FLAGS(LED2_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 LED2   ""
#define PIN    0
#define FLAGS  0
#endif

void main(void)
{
    
    const struct device *pwm[15];
    const struct device *gpio_b; //B_14
    
    bool led_on = true;
    int ret;
    char labelname[20];

    const char pwm_enbl[15][4] =
    {
        {0,0,0,0}, //0
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {1,1,1,1},
        {0,0,0,0},
        {0,0,0,0},
        {1,1,1,1},
        {1,1,0,0},
        {1,0,0,0},
        {1,0,0,0},
        {1,1,0,0},
        {1,0,0,0},
        {1,0,0,0}
    };


    gpio_b = device_get_binding("GPIOB");
    if (gpio_b == NULL) {
        return;
    }

    

    for(int8_t i = 1; i <= 14; i++ )
    {
        if(i >= 1 && i <= 5 || i >= 8 && i <= 14)
            sprintf(labelname, "PWM_%d", i);
            pwm[i] = device_get_binding(labelname);
    }

    for(int8_t i = 1; i <= 14; i++ )
    {
        for(int8_t j = 1; j <= 4; j++ )
        {
            if(pwm_enbl[i][j-1] == 1)
                pwm_pin_set_usec(pwm[i], j, 200, 100, PWM_POLARITY_NORMAL);   
        }
    }

    ret = gpio_pin_configure(gpio_b, 7, GPIO_OUTPUT_ACTIVE | FLAGS);

    while (1) {
        gpio_pin_set(gpio_b, 7, (int)led_on);
        led_on = !led_on;
        k_msleep(SLEEP_TIME_MS);
    }


}

app.overlay

dtsファイルの内容を補足する。

拡張子は.overlayだが、書式はdtsそのもの。

ファイル名は「app」まで含めて決められているため変えてはいけない(変える場合がCMakeListに記載する必要がある)

https://docs.zephyrproject.org/latest/guides/dts/howtos.html#set-devicetree-overlays https://docs.zephyrproject.org/latest/guides/dts/intro.html

元になったと思われるArm Linuxのoverlayファイル(.dtso)では、先頭に

/dts-v1/;
/plugin/;

を記述する必要があるっぽい(参考:デバイスツリー Overlay について調べてみた - Qiita)が、Zephyrではむしろあっちゃダメっぽかった。

&timers1 {
    st,prescaler = <0>;
    status = "okay";

    pwm1: pwm {
        status = "okay";
        pinctrl-0 = <&tim1_ch1_pe9 &tim1_ch2_pe11 &tim1_ch3_pe13 &tim1_ch4_pe14>;
        pinctrl-names = "default";
    };
};


&timers2 {
    st,prescaler = <0>;
    status = "okay";

    pwm2: pwm {
        status = "okay";
        pinctrl-0 = <&tim2_ch1_pa15 &tim2_ch2_pb3 &tim2_ch3_pb10 &tim2_ch4_pb11>;
        pinctrl-names = "default";
    };
};

&timers3 {
    st,prescaler = <0>;
    status = "okay";

    pwm3: pwm {
        status = "okay";
        pinctrl-0 = <&tim3_ch1_pb4 &tim3_ch2_pb5 &tim3_ch3_pb0 &tim3_ch4_pb1>;
        pinctrl-names = "default";
    };
};

&timers4 {
    st,prescaler = <0>;
    status = "okay";

    pwm4: pwm {
        status = "okay";
        pinctrl-0 = <&tim4_ch1_pb6 &tim4_ch2_pd13 &tim4_ch3_pb8 &tim4_ch4_pb9>;
        pinctrl-names = "default";
    };
};

&timers5 {
    st,prescaler = <0>;
    status = "okay";

    pwm5: pwm {
        status = "okay";
        pinctrl-0 = <&tim5_ch1_pa0 &tim5_ch2_pa1 &tim5_ch3_pa2 &tim5_ch4_pa3>;
        pinctrl-names = "default";
    };
};

&timers8 {
    st,prescaler = <0>;
    status = "okay";

    pwm8: pwm {
        status = "okay";
        pinctrl-0 = <&tim8_ch1_pc6 &tim8_ch2_pc7 &tim8_ch3_pc8 &tim8_ch4_pc9>;
        pinctrl-names = "default";
    };
};

&timers9 {
    st,prescaler = <0>;
    status = "okay";

    pwm9: pwm {
        status = "okay";
        pinctrl-0 = <&tim9_ch1_pe5 &tim9_ch2_pe6>;
        pinctrl-names = "default";
    };
};

&timers10 {
    st,prescaler = <0>;
    status = "okay";

    pwm10: pwm {
        status = "okay";
        pinctrl-0 = <&tim10_ch1_pf6>;
        pinctrl-names = "default";
    };
};

&timers11 {
    st,prescaler = <0>;
    status = "okay";

    pwm11: pwm {
        status = "okay";
        pinctrl-0 = <&tim11_ch1_pf7>;
        pinctrl-names = "default";
    };
};

&timers12 {
    st,prescaler = <0>;
    status = "okay";

    pwm12: pwm {
        status = "okay";
        pinctrl-0 = <&tim12_ch1_pb14 &tim12_ch2_pb15>;
        pinctrl-names = "default";
    };
};

&timers13 {
    st,prescaler = <0>;
    status = "okay";

    pwm13: pwm {
        status = "okay";
        pinctrl-0 = <&tim13_ch1_pf8>;
        pinctrl-names = "default";
    };
};

&timers14 {
    st,prescaler = <0>;
    status = "okay";

    pwm14: pwm {
        status = "okay";
        pinctrl-0 = <&tim14_ch1_pf9>;
        pinctrl-names = "default";
    };
};

ビルドコマンド

west build -b nucleo_f746zg

実行コマンド

Nucleoを接続して

west flash

で自動的に書き込み・実行される。

青色LEDが点滅しだし、PWMが出るポートからPWMが出始める。

続き?

www.shujima.work

その他調べてわかったことメモ

プロジェクトフォルダの構造

https://docs.zephyrproject.org/latest/application/index.html

Zephyrにアプリケーションを追加する - みつきんのメモ

my_custom_board_defconfig
my_custom_board.dts
my_custom_board.yaml
board.cmake
board.h
CMakeLists.txt
doc/
dts_fixup.h
Kconfig.board
Kconfig.defconfig
pinmux.c
support/

Kconfig

prj.conf or <boardname>_defconfigファイル

defconfig

  • zephyr/
    • boards/
      • arm/
        • nucleo_f746zg/
          • nucleo_f746zg_defconfig

https://docs.zephyrproject.org/latest/guides/build/kconfig/setting.html#setting-configuration-values

Device Tree

デバイスツリーについて調べてみた - Qiita

[Linux][kernel] Device Tree についてのまとめ - Qiita

デバイスツリーのディレクトリ構成

  • zephyr/
    • boards/
      • arm/
        • nucleo_f746zg
          • nucleo_f746zg.dts
            • nucleoボードのデバイスツリー。f7のdtsiをincludeしている。
    • dts/
      • arm/
        • st
          • f7
            • stm32f7.dtsi
            • stm32f746.dtsi
              • 745を呼び出しているだけ
            • stm32f745.dtsi
              • i2c4
              • spi6
              • can2
              • mac(ethernet)

用語

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

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