aimdevel’s blog

勉強したことを書きます

Raspberry Pi PicoとZephyr OSを使用したI2C LCD1602の実験

概要

前回から引き続き、ラズパイ入門キット「SunFounder Da Vinci Kit for Raspberry Pi」に入っている機器をRaspberr Pi Pico + Zephyr OSで動かしてみた。
今回は、I2C LCD1602を試した。

環境

I2C LCD1602を使用する。 Raspberr Pi Picoとを以下のように接続する。接続方法はSunFounderのチュートリアルを参考にした。

使用方法

以前と同様に作成したソースコードを以下に格納したので、これを使用する。

GitHub - aimdevel/my-zephyr-applications

Zephyrの開発環境構築については公式ドキュメントを参照。

Getting Started Guide — Zephyr Project Documentation

環境をセットアップ

前の記事と同様。

 west init -m https://github.com/aimdevel/my-zephyr-applications.git --mr main my-workspace
cd my-workspace/
west update

この手順はこのリポジトリを利用するときに1回だけ実施すればよい。

ビルド

west build -b rpi_pico apps/apps/i2c_lcd1602/

別のアプリのビルド結果が残っている場合、buildディレクトリを削除してから上記のコマンドを実行すること。

基板に焼いて動作確認

ディスプレイに以下の2つが交互に表示される。

Zephyr OS
I2C LCD1602
Smaple code
is running!

ソースコード説明

作成したdevicetree

作成したdevicetreeは以下。

my-zephyr-applications/apps/i2c_lcd1602/boards/rpi_pico.overlay at main · aimdevel/my-zephyr-applications · GitHub

全体は以下のようになっている。単純なi2cデバイスとして定義してある。compatibleは適当なものを指定しただけで、ほかのものでもよいはず。

&i2c0 {
    status = "okay";
    i2c_lcd1602: i2c_lcd1602@27 {
        compatible = "zephyr,i2c-target-eeprom";
        reg = <0x27>;
    };
};

このdevicetreeで重要なのは、i2c_lcd1602: i2c_lcd1602@27 {@27と、reg = <0x27>;の部分で、i2c lcd1602のスレーブアドレスを表している。
他の部分は適当で問題ないと思われる。

ソースコード

使用したコードは以下。

my-zephyr-applications/apps/i2c_lcd1602/src/main.c at main · aimdevel/my-zephyr-applications · GitHub

このソースコードは、sunfounderのサンプルコードを改変して作成した。
もとにしたコードは以下。

davinci-kit-for-raspberry-pi/c/1.1.7/1.1.7_Lcd1602.c at master · sunfounder/davinci-kit-for-raspberry-pi · GitHub

おおきな変更個所は、i2cを使用する関数をwiringPiI2Cからzephyr OSのものに置き換えたところだけで、ほかの部分はほぼそのまま使用できた。

i2cに関連する箇所は以下。

static const struct i2c_dt_spec lcd1602 = 
                I2C_DT_SPEC_GET(DT_NODELABEL(i2c_lcd1602));

devicetreeから情報を取得する。

i2c_write_dt(&lcd1602, &temp, 1);

tempの内容を1バイト書き込む。

まとめ

Zephyr OSでi2cを使用してlcd1602を動かした。

参考

GitHub - zephyrproject-rtos/zephyr: Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

Zephyr Project Documentation — Zephyr Project Documentation

1.1.7 I2C LCD1602 — SunFounder davinci-kit-for-raspberry-pi ドキュメント

Raspberry Pi – I2C~LCD1602 – TauStation

https://www.handsontec.com/dataspecs/module/I2C_1602_LCD.pdf

https://www.handsontec.com/dataspecs/module/I2C_1602_LCD.pdf

Zephyr OSでRaspberry Pi Picoを使用して74HC595と7セグメントディスプレイを接続する方法

概要

前回から引き続き、ラズパイ入門キット「SunFounder Da Vinci Kit for Raspberry Pi」に入っている機器をRaspberr Pi Pico + Zephyr OSで動かしてみた。
今回は、Segment Displayを試した。

環境

74HC595と7セグメントディスプレイを使用する。 Raspberr Pi Picoとを以下のように接続する。接続方法はSunFounderのチュートリアルを参考にした。

74HC595を使用する方法については以下のサイトを参考にした。

Arduinoからシフトレジスタ 74HC595へ SPIでデータを送る | meyon's STUDY

使用方法

前回と同様に作成したソースコードを以下に格納したので、これを使用する。

GitHub - aimdevel/my-zephyr-applications

Zephyrの開発環境構築については公式ドキュメントを参照。

Getting Started Guide — Zephyr Project Documentation

環境をセットアップ

前の記事と同様。

 west init -m https://github.com/aimdevel/my-zephyr-applications.git --mr main my-workspace
cd my-workspace/
west update

この手順はこのリポジトリを利用するときに1回だけ実施すればよい。

ビルド

west build -b rpi_pico apps/apps/segment_display/

別のアプリのビルド結果が残っている場合、buildディレクトリを削除してから上記のコマンドを実行すること。

基板に焼いて動作確認

時間経過でディスプレイの表示が変化することを確認する。

ソースコード説明

作成したdevicetree

作成したdevicetreeは以下。

https://github.com/aimdevel/my-zephyr-applications/blob/main/apps/segment_display/boards/rpi_pico.overlay

全体は以下のようになっている。

&spi0 {
    status="okay";
    cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;
    gpio_expander_0: gpio_expander0@0 {
        reg = <0>;
        compatible = "ti,sn74hc595";
        reset-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
        ngpios = <0x8>;
        spi-max-frequency = <2000000>;
        #gpio-cells = <0x2>;
        gpio-controller;
    };
};

ドキュメントがあるのでそれに従って記述した。

ti,sn74hc595 (on spi bus) — Zephyr Project Documentation

cs-gpios

spiのチップセレクトの指定。

cs-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>;

ここで設定したGPIOが通信の際にACTIVE(=LOW)になる指定。

reset-gpios

リセットに使用するピンの指定。

ngpios

74HC595で制御できるGPIOの数。8で固定。

spi-max-frequency

周波数。適当な値でOKなはず。

このdevicetreeを記述していて気が付いたのだが、Zephyrではdevicetreeの定義を「dts/bindings/~~」にyamlファイルとして格納しておくと、その定義に合わない設定がされたときはコンパイルエラーになるようだ。
例えば、必須の設定がされていない場合や、statusに指定する値がokayやdisabled以外になっている場合などは、コンパイルに失敗する。
Linux のdevicetreeのコンパイル時には、最低限の文法に従っていればエラーが出ず、typoに気づきづらかった記憶があるので、これはありがたい。

devicetreeの関連個所

自分で作成したわけではないが、devicetreeで関係のある個所を説明する。
関係するのは以下のファイルの、spi0_default。

https://github.com/zephyrproject-rtos/zephyr/blob/main/boards/arm/rpi_pico/rpi_pico-pinctrl.dtsi

spi_defaultは以下のように設定されている。

 spi0_default: spi0_default {
        group1 {
            pinmux = <SPI0_CSN_P17>, <SPI0_SCK_P18>, <SPI0_TX_P19>;
        };
        group2 {
            pinmux = <SPI0_RX_P16>;
            input-enable;
        };
    };

GPIOの17~19をそれぞれSPI0で使用する設定になっている。

Raspberry Pi PicoのPinoutを見ると、確かにGPIO17~19はSPI0で使用できるようになっている。 また、0~3、4~7でもSPI0を使用できそうだ。

ソースコード

使用したコードは以下。

https://github.com/aimdevel/my-zephyr-applications/blob/main/apps/segment_display/src/main.c

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>

#define MAX_GPIOS 1<<7 - 1

static const struct device *const gpio_ex =
                DEVICE_DT_GET(DT_NODELABEL(gpio_expander_0));

int main(void)
{
    printk("start!\n");
    if (!device_is_ready(gpio_ex)) {
        return 0;
    }
    printk("device is ready!\n");

    for (int i=0;i<8;i++) {
        printk("gpio configure loop\n");
        int ret = gpio_pin_configure(gpio_ex, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW);
    }

    k_msleep(10000);

    int gpio_n = 0;
    while (1) {
        printk("loop gpio_n=%d!\n",gpio_n);
        gpio_port_set_masked_raw(gpio_ex, 0x7f, gpio_n);
        //gpio_port_set_bits_raw(gpio_ex, gpio_n);
        k_msleep(1000);
        gpio_n++;
        if (gpio_n > MAX_GPIOS) {
            gpio_port_clear_bits_raw(gpio_ex, 0x7f);
            gpio_n = 0;
        }
    }
    return 0;
}

デバイスドライバの仕様に従ってgpio APIを使用した。

  • 初めにdevicetreeから情報を取得
static const struct device *const gpio_ex =
                DEVICE_DT_GET(DT_NODELABEL(gpio_expander_0));
  • ピンの設定
    ドライバの実装的にこの設定は意味がないかも。
for (int i=0;i<8;i++) {
        printk("gpio configure loop\n");
        int ret = gpio_pin_configure(gpio_ex, i, GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW);
    }
  • 出力の制御 74HC595の出力を制御する。gpio_port_set_masked_rawを使用する。
gpio_port_set_masked_raw(gpio_ex, 0x7f, gpio_n);

使用方法は、

  • 第一引数に、deviceの構造体を渡す。
  • 第二引数に、使用できるピンを表すmaskを渡す。 8bit分の各ビットがそれぞれのピンに対応する。今回は7セグメントディスプレイのため、01111111を指定している。
  • 第三引数に、highにするピンの情報を渡す。 第二引数と同様に8bit分のデータを渡す。ここを変化させることでディスプレイの表示を変更できる。

device driver

使用したデバイスドライバは以下。
gpio APIを使用できるデバイスとして74HC595を制御できるようになっている。

zephyr/drivers/gpio/gpio_sn74hc595.c at main · zephyrproject-rtos/zephyr · GitHub

まとめ

Raspberry Pi Pico + Zephyr OSで、74HC595を使ってセグメントディスプレイを制御した。
74HC595にはドライバが用意されており、devicetreeを書けば簡単に使用できることが分かった。
devicetreeを触っていると、Linuxで使用しているdevicetreeとの差異が見えてきて面白い。Zephyrの方にはコンパイル時のdevicetreeチェックなどがあり、これは便利だと感じたのでLinuxの方にも実装してほしい。

記事の本題とは関係ないが、Hatena Blogの機能で、AIアシスタントが記事のタイトルを考えてくれるようになったので、使ってみた。
それっぽいタイトルをつけてくれるので、これは活用していきたい。

参考

GitHub - zephyrproject-rtos/zephyr: Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

Arduinoからシフトレジスタ 74HC595へ SPIでデータを送る | meyon's STUDY

1.1.4 7セグメントディスプレイ — SunFounder davinci-kit-for-raspberry-pi ドキュメント

Zephyr Project Documentation — Zephyr Project Documentation

Raspberry Pi PicoのRGB LED実験 with Zephyr OS

概要

ラズパイ入門キット「SunFounder Da Vinci Kit for Raspberry Pi」に入っている機器をRaspberr Pi Pico + Zephyr OSで動かしてみた。
今回は、RGB LEDを試した。

環境

Raspberr Pi PicoとLEDを以下のように接続する。接続方法はSunFounderのチュートリアルを参考にした。

rgb_led

使用したソフトはZephyr OSの以下のサンプルコードで、デバイスツリーのみ上記の回路に合わせて変更した。

https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/basic/rgb_led/src/main.c

使用方法

作成したソースコードを以下に格納したので、これを使用する。

GitHub - aimdevel/my-zephyr-applications

Zephyrの開発環境構築については公式ドキュメントを参照。

Getting Started Guide — Zephyr Project Documentation

環境をセットアップ

 west init -m https://github.com/aimdevel/my-zephyr-applications.git --mr main my-workspace
cd my-workspace/
west update

この手順はこのリポジトリを利用するときに1回だけ実施すればよい。

ビルド

 west build -b rpi_pico apps/apps/rgb_led/

基板に焼いて動作確認

時間経過でLEDの色が変化する様子を確認できる。

ソースコード説明

devicetree

devicetreeは以下。

https://github.com/aimdevel/my-zephyr-applications/blob/main/apps/rgb_led/boards/rpi_pico.overlay

全体は以下のようになっている。

/{
    aliases {
        red-pwm-led = &red_pwm_led;
        green-pwm-led = &green_pwm_led;
        blue-pwm-led = &blue_pwm_led;
    };
    pwmleds {
        compatible = "pwm-leds";

        red_pwm_led: red_pwm_led {
            pwms = <&pwm 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        };
        green_pwm_led: green_pwm_led {
            pwms = <&pwm 3 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        };
        blue_pwm_led: blue_pwm_led {
            pwms = <&pwm 4 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        };
    };
};

&pwm {
    status = "okay";
    divider-frac-1 = <15>;
    divider-int-1 = <255>;
    divider-frac-2 = <15>;
    divider-int-2 = <255>;
};

&pwm_ch4b_default {
    group2 {
        pinmux = <PWM_1A_P2>, <PWM_1B_P3>, <PWM_2A_P4>;
    };
};

aliases

各ノードに別名をつける設定。
アプリのコードからデバイスツリーにアクセスする際に使用できる。
ここでは、各色に対応するノードに設定を行っている。

aliases {
        red-pwm-led = &red_pwm_led;
        green-pwm-led = &green_pwm_led;
        blue-pwm-led = &blue_pwm_led;
    };

pwmleds

それぞれの色にPWMを割り当てている。
1つだけ取り出して見る。

     red_pwm_led: red_pwm_led {
            pwms = <&pwm 2 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        };

これは赤色をpwmの2番(GPIO2のピン)で制御することを表している。ほかの色も同様である。
細かい設定は公式ドキュメントを参照。

Pulse Width Modulation (PWM) — Zephyr Project Documentation

pwm

pwmの設定。

&pwm {
    status = "okay";
    divider-frac-1 = <15>;
    divider-int-1 = <255>;
    divider-frac-2 = <15>;
    divider-int-2 = <255>;
};

status = "okay"; でpwmを有効にしている。
そのほかは分周の設定で、Zephyr OS公式を参考に設定した。

pwm_ch4b_default

ピンの設定。
名前はch4bだが、それ以外のチャネルもここで設定できる。

&pwm_ch4b_default {
    group2 {
        pinmux = <PWM_1A_P2>, <PWM_1B_P3>, <PWM_2A_P4>;
    };
};

この1Aなどの値がPWMのチャネルなのだが、この値とGPIOの関係はデータシートによると以下のようになっている。

pico_pwm

今回はGPIO2, 3, 4をPWMとして使用するので、対応するpwmのチャネルは1A, 1B, 2Aとなっており、上記のピン設定となる。

サンプルコード

公式のサンプルコードから全く手を加えていない。
pwmを制御する際に行っているのは以下の部分。

  • バイスツリーから情報を取得。
static const struct pwm_dt_spec red_pwm_led =
    PWM_DT_SPEC_GET(DT_ALIAS(red_pwm_led));
static const struct pwm_dt_spec green_pwm_led =
    PWM_DT_SPEC_GET(DT_ALIAS(green_pwm_led));
static const struct pwm_dt_spec blue_pwm_led =
    PWM_DT_SPEC_GET(DT_ALIAS(blue_pwm_led));

DT_ALIASでaliasesで設定した名前を使用できるはずだが、ここではアンダースコア表記。

  • pwmの値を設定
ret = pwm_set_pulse_dt(&red_pwm_led, pulse_red);

pwm_set_pulse_dt関数にデバイスの構造体とパルスの値を渡して制御する。

まとめ

バイスツリーの対応だけでサンプルコードを動かせることを確認した。
pwmの制御だけなので、前回のサーボモータを動かすサンプルとほぼ同じ内容だった。
ラズパイ入門キットには、ほかにも多くのデバイスが含まれているのでそれらの動作にも挑戦していく。

参考

GitHub - zephyrproject-rtos/zephyr: Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.

1.1.2 RGB LED — SunFounder davinci-kit-for-raspberry-pi ドキュメント

Zephyr Project Documentation — Zephyr Project Documentation

Raspberry Pi Pico + Zephyr OSでサーボモータを回す

概要

Zephyr OSのPWM APIサーボモータを動かすサンプルをRaspberry Pi Picoで動かしたメモ。

概要

使用するサーボモータは「RDS3115」。 以下のように配線して動かす。

サーボモータの赤色の線は電源の+に、黒は電源のーに、黄色はpicoのGPIO0につないでいる。 ソースコードは以下のサンプルを使用する。

zephyr/samples/basic/servo_motor/src/main.c at main · zephyrproject-rtos/zephyr · GitHub

作業手順

バイスツリーを追加する。

サーボモータを動かすには、上記の配線に合わせてデバイスツリーを書く必要がある。
ファイルはzephyrのソースコードに「samples/basic/servo_motor/boards/rpi_pico.overlay」として格納する。

今回はサンプルコードをベースに以下のように作成した。

/* SPDX-License-Identifier: Apache-2.0 */

/ {
    servo: servo {
        compatible = "pwm-servo";
        pwms = <&pwm 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        min-pulse = <PWM_USEC(500)>;
                max-pulse = <PWM_USEC(2500)>;
    };
};

&pwm_ch4b_default {
    group2 {
        pinmux = <PWM_0A_P0>;
    };
};

&pwm {
    status = "okay";
    divider-frac-4 = <15>;
    divider-int-4 = <255>;
};

上記の内容を説明する。

ビルドする

通常通りビルドする。

west build -p always -b rpi_pico samples/basic/servo_motor

基板に転送して動作を確認する。

このプログラムをpicoで実行すると、サーボモータが1秒おきに角度を変えるように動く。

ソースコード確認

今回の変更箇所はデバイスツリーのみで、サンプルコード本体には手を加えていない。
バイスツリーのそれぞれのノードを見ていく。

バイスツリー

servo

/ {
    servo: servo {
        compatible = "pwm-servo";
        pwms = <&pwm 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
        min-pulse = <PWM_USEC(500)>;
                max-pulse = <PWM_USEC(2500)>;
    };
};

ここで設定する項目は以下。
- pwms
今回はpwmのチャネル0を使用するという指定になっている。チャネル0とはpicoのGPIO0番ピンを使用する指定のようだ。
- min-pulse
最小パルスを指定する。使用するサーボモータごとに異なるので調べる。今回は500とした。
- max-pulse
最大パルスを指定する。同上。

pwm_ch4b_default

 &pwm_ch4b_default {
    group2 {
        pinmux = <PWM_0A_P0>;
    };
};

使用するピンの設定を記述している。元から定義されているピン設定ノードに追加する形で作ったが、新たにノードを追加することもできると思う。
group1は初期設定されているので、ひとまずgroup2を使用した。多分何でもよい。
<PWM_0A_P0>が今回使用するピンの設定であり、0番ピン(GPIO0)をPWMの0Aチャネルで使用するという指定のようだ。

pwm

&pwm {
    status = "okay";
    divider-frac-4 = <15>;
    divider-int-4 = <255>;
};

status = "okey" でpwmを有効に設定する。
残りの二つの設定は、ほかのデバイスツリーの流用なのでよくわかっていない。また調べることにする。

12/3 追記
divider-frac-4とdivider-int-4は分周機構の設定値のようだ。
末尾についている数値がpwmのどのスライスの設定かを指している。
あれ?だとすると、上記の記述だとスライス0に設定できていないことになるな。なんで動いてるんだ。。。?
ちなみに、GPIO7などのピンでpwmを使おうとすると、スライス3用に上記の設定を書き換えないと動作しなかった。

サンプルコード

以下の流れでモータを制御している。サンプルコードでは3と4をループしている。
1. デバイスツリーから情報を取得
2. pwm構造体をバリデート
3. pwmのパルス幅を設定
4. 次のパルス幅を計算

1. デバイスツリーから情報を取得

static const struct pwm_dt_spec servo = PWM_DT_SPEC_GET(DT_NODELABEL(servo));
static const uint32_t min_pulse = DT_PROP(DT_NODELABEL(servo), min_pulse);
static const uint32_t max_pulse = DT_PROP(DT_NODELABEL(servo), max_pulse);

2. pwm構造体をバリデート

 if (!pwm_is_ready_dt(&servo)) {
        printk("Error: PWM device %s is not ready\n", servo.dev->name);
        return 0;
    }

3. pwmのパルス幅を設定

ret = pwm_set_pulse_dt(&servo, pulse_width);

4. 次のパルス幅を計算

ソースコードは割愛。最大パルスと最小パルスの間を行ったり来たりするように制御している。

まとめ

Raspberry Pi Pico + Zephyr OSでサーボモータを回すサンプルコードをうごかした。
サンプルコードや基板固有のコードではなく、デバイスツリーの変更のみで動作可能だったので、基板間のコードの移植性が良いのではないかと感じた。
まあ、他のリアルタイムOSをあまり知らないので当たり前のことなのかもしれませんが。。。

Raspberry Pi PicoでZephyr OSを動かしてみた

概要

Raspberry Pi Pico上でZephyr OSを動かせるようなので試してみた。

環境

作業手順

開発環境構築

公式ドキュメントに従って環境構築する。
以下のドキュメントの「Install the Zephyr SDK」まで手順通りに進める。

Getting Started Guide — Zephyr Project Documentation

アプリをビルド

raspberrypi picoに載っているLEDを光らせるアプリをビルドする。

west build -p always -b rpi_pico samples/basic/blinky

ビルド結果は、「~/zephyrproject/zephyr/build/zephyr/zephyr.uf2」に出力される。

実行

ビルドした「zephyr.uf2」を基板に焼く。
Raspberry Pi PicoのBOOTSELを押しながらUSBケーブルをつなぐと、書き込みモードで接続される。
picoがストレージデバイスとして認識されるので、「zephyr.uf2」をpicoに格納する。
書き込みが終わるとアプリが実行され、LEDが点滅することを確認できる。

ソースコード確認

動かしたソースコードを確認する。今回動かしたコードは以下。

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

このコードの中には具体的にどのピンでLEDを制御するなどの記述はない。
それは、HW構成の記述をデバイスツリーで行えるようになっているためである。
例えば、picoのLEDは以下のように記述されている。

 leds {
        compatible = "gpio-leds";
        led0: led_0 {
            gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
            label = "LED";
        };
    };

zephyr/boards/arm/rpi_pico/rpi_pico.dts at main · zephyrproject-rtos/zephyr · GitHub

これを見ると、led_0はGPIO25で制御するとなっている。
picoのデータシートの「2.1. Raspberry Pi Pico pinout」に「GPIO25 OP Connected to user LED」という記述があり、デバイスツリーの内容とあっていることを確認できる。

https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf

バイスの設定箇所がわかったところで、アプリのソースコードを見ていこうと思う。
全体の流れは以下のようだ。

aliasでデバイスツリーのノード識別名を取得

#define LED0_NODE DT_ALIAS(led0)

gpioノードの構造体を取得

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

gpioの構造体をvalidate

gpio_is_ready_dt(&led)

gpioピンを設定

gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);

gpioのon/offを切り替え

ret = gpio_pin_toggle_dt(&led);

この処理を1秒おきに実行することでLEDを点滅させている様子。

まとめ

Raspberry Pi Pico上でZephyr OSを動作させ、そのソースコードを理解した。
バイスツリーはlinuxでも採用されているが、zephyrではその情報にアプリからアクセスできるようで、linuxのものとは似ているだけで実態は結構違うのかもしれないと感じた。
せっかくzephyrを使えることが分かったので、もう少し遊んでみようと思う。

yoctoのレシピでkernel configを変更する方法

概要

yoctoでlinux kernelをビルドする際にconfigを変更する方法は複数あり、
どの方法を使えばよいのか迷うことがある。
そこでいくつかの方法を実際に使用してみて、どれが使いやすいか考えた。

実験環境

  • 対象ハード : raspberrypi4-64 (meta-raspberrypi + poky)
  • yoctoバージョン : kirkstone

  • 今回試した方法

    • KERNEL_FEATURESを設定する方法
    • 独自のcfgファイルを使用する方法
    • defconfigをレシピから渡す方法

使用結果

1. KERNEL_FEATURESを設定する方法

linux-yoctoの標準で用意されている設定を、機能ごとに指定して反映できる。
指定できる設定は以下のリポジトリなどに格納されており、
この中のcssファイルをyocto設定のKERNEL_FEATURES変数に指定できる。

yocto-kernel-cache - Patches and configuration for the linux-yocto kernel tree

設定例:

KERNEL_FEATURES += "features/uprobe/uprobe.scc"

上記の設定を行うとビルド時に.configに以下設定が追加される。

CONFIG_UPROBES=y
CONFIG_UPROBE_EVENTS=y

KERNEL_FEATURESに既存の設定を指定するだけなので簡単に使いたい機能を有効にできる。
ただし、細かい設定はできないように見える。

上記のような特徴から、単純に目的の機能が有効になればよい場合に使用するのが良いと思われる。
ユーザが細かい設定を行えないので、kernelの機能を制限したい場合などでは使いにくそうだと感じた。

また、sccファイルではconfigの変更以外も可能なようだが、今回は詳細を確認しない。 sccについては以下の公式ドキュメントを参照。

3 Working with Advanced Metadata (yocto-kernel-cache) — The Yocto Project ® 4.0.13 documentation

2. 独自のcfgファイルを使用する方法

SRC_URIに自作した.cfgファイルを指定すると、ベースになるconfigを変更できる。
.cfgの記述はkernelのconfigと同様に以下のような形式。

CONFIG_WILC1000_SPI=m

これを.bb/bbappendのSRC_URI変数に追加すると、ここに書かれた設定が追加される。
kernelのconfigを直接指定できるので、ピンポイントで必要な設定を行えるが、kernelのconfigを知っている必要があり、知識がないと作成するのが難しい。

上記の特徴のように、kernelのconfigを直接に記述できるので、目的の設定を確実に行うことができる。
ただし、基本的には機能追加で使用するので、これも最小のkernelをビルドしたい場合には、ベースにしたconfigを確認して不要な機能が有効化されていないか見る必要がある。

3. defconfigをレシピから渡す方法

独自に作成したdefconfigファイルをrecipeで渡す方法。
レシピの記述例は以下。レシピから渡したdefconfigを使用するようにbbappendファイルを作成する。

KBUILD_DEFCONFIG:raspberrypi4-64 = ""
SRC_URI += " file://defconfig "

1行目で既存のdefconfigの設定を削除し、2行目でdefconfigを指定している。  

この方法では、kernelのconfigをほとんどコントロールすることができるので、ユーザが必要な機能だけを有効にしやすい。
ただし、defconfig全体を作成するので、cfgファイルの作成以上にkernelの知識が必要である。
また、yoctoの設定によっては、自動的にkernelのconfigを有効にするものがあるので、ビルド後に.configを確認して不要なconfigがされていないか確認するのが良いと思う。

比較

簡単さで言うと、
「KERNEL_FEATURESを設定 > 独自のcfgファイルを使用 > defconfigをレシピから渡す」
となる。 ラズパイなどを自分用にカスタマイズして遊ぶ分には方法1と2で十分だが、製品向けにビルドするとなると、方法3を行ったうえで、yoctoのほかの設定から有効になってしまう機能を調べるなどの対応が必要そうだ。

使用した資材は以下に格納した。

GitHub - aimdevel/meta-my-raspberrypi: Yocto layer of my raspberrypi

まとめ

yoctoでkernelのconfigを変更する方法を3つ試して比較した。
個人で楽しむ分には方法1と2で十分だと感じた。
それ以上にkernelの細かい設定を行いたいとなると、方法3を使うか、もしくはkernelをforkして個人用のリポジトリを作って、yoctoでもそこを参照するなどの方法をとる方がよい気がする。

参考情報

https://docs.yoctoproject.org/4.0.13/kernel-dev/advanced.html#

GitHubのDependabot alertに対処する

前に書いたRustのコードをGitHubにおいていたら、脆弱性情報が通知されていたので、それに対応した。
別のところで同じ対応をするときに困らないように、行った作業をまとめておこうと思う。
対応したリポジトリは以下。

GitHub - aimdevel/part-mount: tool to mount a partition of device file.

 

Security通知の確認

放置していたリポジトリを久しぶりに見に行くと、securityタブに1と表示されていた。

内容を見ると以下のように書かれている。

どうやら問題のあるバージョンのrustixが依存に存在するので、バージョンを上げろという事のようだ。
そこで使用できる機能として、Dependabot security updateというものがあり、自動で依存をアップデートしてくれるらしい。
しかし、今回はその機能はエラーになっていたので手動でパッケージを更新した。

一応Dependabot security updateのリンクを貼っておく。
docs.github.com

作業手順

パッケージをアップデートする

ソースコードをクローンしてきて以下のコマンドを実行するだけで更新できる。

$ cargo update -p rustix --precise 0.38.19

ただし、--preciseを指定しないと少し古いバージョンがインストールされてしまうので注意が必要そうだ。

GitHubにプッシュする。

プッシュ後にGitHubを確認する。

アラートが消えていることを確認できる。

まとめ

GitHubのDependabot alertに対応した。
パッケージ管理を行っている言語はパッケージの脆弱性
ある程度はGitHubに任せておくことが出来そうに見える。

また、今回は使用できなかったが、Dependabot security updateを使用すると、
botがバージョンを上げてくれるらしいので、特別バージョンの固定が必要ないソフトに関しては、
この機能を使用すると楽ができると思う。