2024/02/24

nRF Connect SDKでZephyr RTOSに入門

zephyrclangrtosnrf-connect-sdk

概要

2023年の夏あたりから、組込開発をかじることになりました。

今後のために「本格的にハードウェア関係のプロダクトを開発できるように」という趣旨で
組込開発が絡むものを趣味として始めることにしました。

題材をいろいろ検討しましたが・・

候補に上がったのが以下でした

  1. SONY製のSPRESENSEでスマート家電的なものをつくる
  2. RISC-Vが動くチップセットがのった開発ボードでFreeRTOSを使って簡単なセンサーを開発する
  3. Zephyr RTOSベースでスマート家電的なものをつくる

検討の結果 No.3 の「Zephyr RTOS + VS Codeで開発できる NRF Connect SDKを使って何か開発する」ことに決めました。

採用の決め手は以下

  • RTOSのライセンスがフリーである
  • VS Codeで開発できる
  • UbuntuでもMacでもWindowsでも開発できる
  • 今おつきあいのあるクライアント様と異なるテックスタックでありNDAまわりに気を使わなくてすむ
  • 入門サイトや公開されているサンプルが豊富で手がつけやすい

本記事では、Zephyr RTOSの入門サイトとして最適な「nRF Connect SDK Fundamentals
に+αの要素(主に環境周りの整備)をしたものを備忘録として残します。

私は最初intel chipsetのMacOSXで上記の入門コースをコンプリートしましたが・・
備忘録自体はUbuntuベースで記載します。
※ 極力VSCode Extensionに頼らないで開発ができないか試したかったというのが理由で、Ubuntuで環境構築し直しています。

ハードウェアの準備

  1. 開発ボードであるnRF53440 DKを購入しました。
  2. 充電だけではなく、データも転送できるMicro USBケーブルを購入しました。
  3. (別途開発機としてMac/Windows/UbuntuのいずれかのOSのマシンが必要です。)

注意事項

Micro USBケーブルは必ずデータも転送できるものを購入する必要があります。(まれに給電のみのケーブルというのが存在し、その場合うまく通信できません。)
わたしは、手持ちのMicro USBケーブルで接続をしたときに、LEDが光ったので安心したのですが・・
いざシリアル通信をしようとするとデバイスが認識されず・・
所有していた各種OS(Mac/Windows/Ubuntu)が搭載されたマシンで接続し、USBポートも変えてためしたがうまくいかず・・
数時間を無駄にしてしまいました。。

ソフトウェアの準備

  1. こちらのリンクからOS(以下)にあうものを選んで nRF command line toolsをダウンロードしてインストール
  2. こちらのリンクから nFR Utilをダウンロードして、パスが通っているフォルダに移動します。(/usr/local/bin などに)
  3. UbuntuかMacの場合は、こちらのリンク からJ-Link Software and Documentation packをダウンロードしてインストールする必要があります。(Windowsの場合はCommand Line Toolsのインストーラーに同梱されています。)
  4. こちらのリンクからnRF Connect SDKをインストールします。
  5. VS Codeをインストール(任意です。どんなIDEでも動作します。)
  6. nRF Connect Extension Pack というVS Code Extensionをインストールします。(任意です。下記の記事の手順では不要です。)
  7. Astyleをインストール(sudo apt-get install -y astyle)(任意ですが、Cのファイルをフォーマットするのに便利です。)
  8. Astyle VS Code Extensionをインストールします。(C言語のフォーマット用)(任意ですが、Cのファイルをフォーマットするのに便利です。)

nRF Connect SDKのUbuntu20.04へのインストール用の下準備メモ

# Kitware APT Repositoryを追加します。
$ sudo apt-get update
$ sudo apt-get install ca-certificates gpg wget
$ wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
$ echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | sudo tee /etc/apt/sources.list.d/kitware.list >/dev/null
$ sudo apt-get update
$ test -f /usr/share/doc/kitware-archive-keyring/copyright || sudo rm /usr/share/keyrings/kitware-archive-keyring.gpg
$ sudo apt-get install kitware-archive-keyring

# 各種必要なツール群・依存関係のインストール
$ sudo apt install --no-install-recommends git cmake ninja-build gperf \
  ccache dfu-util device-tree-compiler wget \
  python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
  make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1
# バージョンの確認
$ cmake --version
cmake version 3.28.3
CMake suite maintained and supported by Kitware (kitware.com/cmake).
$ python3 --version
Python 3.8.10
$ dtc --version
Version: DTC 1.5.0

接続確認

Ubuntuの場合シリアルポートにログインユーザーがアクセスできるように権限等設定しておかないといけません。

# 自分自身を dialout グループに追加
$ sudo usermod -a -G dialout `whoami`
# dialoutのメンバ確認
$ getent group dialout

# Modem Managerサービスを停止します
$ systemctl stop ModemManager.service
$ systemctl disable ModemManager.service
# 再起動します。
$ reboot
# 接続先を確認します。
# ここで大事なのが、USBを変なポートに接続すると、dialoutグループの所有にならなかったりしたので注意が必要です。
# マザーボードに付属のUSB type-Aのポートに接続するとうまく動作しました。
$ ls -la /dev/ttyACM*
crw-rw-rw- 1 root dialout 166, 0  2月 20 07:08 /dev/ttyACM0
crw-rw-rw- 1 root dialout 166, 1  2月 20 07:08 /dev/ttyACM1

$ minicom -D /dev/ttyACM1 -b 115200
# 終了するときは Ctrl+A のあと q

macの場合は以下のような感じで接続できます。

# 事前に minicomをインストールしておく必要があります。
% brew install minicom
% minicom -D /dev/tty.usbmodem0010500880393 -b 115200
# 終了するときは Esc+Z のあと q

実装

接続確認までできたらサンプル実装を行います。

実装の準備

# 作業用フォルダを作成します。
$ mkdir ~/workspace
$ cd ~/workspace

# プロジェクトルートフォルダを作成します。
$ mkdir nrf-connect-sdk-tutorial
$ cd nrf-connect-sdk-tutorial

# .gitignoreを作成します。
$ cat <<'EOF' > .gitignore
# editors
*.swp
*~

# pyenv
.python-version
__pycache__

# Zephyr workspace
/.west
/bootloader
/modules
/nrf
/nrfxlib
/test
/tools
/zephyr

# build
build*/

# OSX
.DS_Store
EOF

# .vscode/settings.jsonを作成します。(C言語のファイルのフォーマッターの設定)
$ mkdir .vscode
$ cat <<'EOF' > .vscode/settings.json
{
    "editor.formatOnType": true,
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "chiehyu.vscode-astyle",
    "astyle.astylerc": "${workspaceRoot}/app/tools/astyle.cfg"
}
EOF

# git導入
$ git init

# python venvを作成&westインストール
$ pyenv install 3.12.2
$ pyenv virtualenv 3.12.2 nrf_connect_sdk_tutorial
$ pyenv local nrf_connect_sdk_tutorial
$ pip install --upgrade pip
$ pip install west

# zephyr-sdkのインストール
# HOMEの直下にインストールしましたが・・より良い管理方法がありそうな気がする。
# おとなしく toolchain-manager を利用してもいいかもしれない・・
$ cd ~
$ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.5-1/zephyr-sdk-0.16.5-1_linux-x86_64.tar.xz
$ wget -O - https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.16.5-1/sha256.sum | shasum --check --ignore-missing
$ tar xvf zephyr-sdk-0.16.5-1_linux-x86_64.tar.xz
$ rm zephyr-sdk-0.16.5-1_linux-x86_64.tar.xz
$ cd ~/zephyr-sdk-0.16.5-1
# setup.shを正常に実行するためにpythonのバージョンを揃えておく
$ pyenv local nrf_connect_sdk_tutorial
$ ./setup.sh
Install host tools [y/n]? y
Register Zephyr SDK CMake package [y/n]? y
# Install udev rules, which allow you to flash most Zephyr boards as a regular user:
$ sudo cp ~/zephyr-sdk-0.16.5-1/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d
$ sudo udevadm control --reload

# see https://docs.zephyrproject.org/latest/develop/west/workspaces.html
# see also https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.3.0/zephyr/develop/west/workspaces.html#west-workspaces
$ cd ~/workspace/nrf-connect-sdk-tutorial
$ mkdir app
$ cat <<'EOF' > app/west.yml
manifest:
  remotes:
    - name: sdk
      url-base: https://github.com/nrfconnect
  projects:
    - name: sdk-nrf
      remote: sdk
      revision: v2.5.2
      path: nrf
      import: true
      clone-depth: 1
  self:
    path: app
EOF

$ cd app
$ west init -l .
# 以下実行すると、nrf connect sdkやzephyrのgit cloneが走るためかなり時間がかかります。
$ west update
$ west zephyr-export

$ cd ..
$ pip install -r zephyr/scripts/requirements.txt
$ pip install -r nrf/scripts/requirements.txt
$ pip install -r bootloader/mcuboot/scripts/requirements.txt

# astyleの設定ファイル作成
$ mkdir -p app/tools
$ cat <<'EOF' > app/tools/astyle.cfg
# Configuration file for AStyle
--style=kr
--pad-oper
--pad-header
--align-pointer=name
--align-reference=name
--max-continuation-indent=100
--min-conditional-indent=0
--add-braces
--indent-switches
--convert-tabs
--max-code-length=120
--break-after-logical
--ignore-exclude-errors
--suffix=none
--verbose
--errors-to-stdout
--exclude=src/images
--exclude=src/ext_drivers
--exclude=drivers/input
--exclude=drivers/sensor
--exclude=src/applications/2048/2048_lib
--exclude=src/applications/iaq/ui_export
EOF

実装

LEDをチカチカさせるものを実装します。

# main.cを実装
$ mkdir -p app/src
$ cat <<'EOF' > app/src/main.c
#include <zephyr/kernel.h>
#include <zephyr/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)

/*
 * A build error on this line means your board is unsupported.
 * See the sample documentation for information on how to fix this.
 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int main(void)
{
    int ret;

    if (!gpio_is_ready_dt(&led)) {
        return 0;
    }

    ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    if (ret < 0) {
        return 0;
    }

    while (1) {
        ret = gpio_pin_toggle_dt(&led);
        if (ret < 0) {
            return 0;
        }
        k_msleep(SLEEP_TIME_MS);
    }
    return 0;
}

EOF

# プロジェクト設定ファイル(prj.conf)を作成します。
# 一旦はLTEを使うためのGPIOを有効にする設定だけONにしておきます。
$ cat <<'EOF' > app/prj.conf
CONFIG_GPIO=y
EOF

# 最後にCMakeLists.txtを作成します。
$ cat <<'EOF' > app/CMakeLists.txt
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(nrf_connect_sdk_tutorial)
target_sources(app PRIVATE src/main.c)
EOF

ビルド

$ cd app
# 今回はnRF5340 DKのボード向けにコンパイルする必要がありますので、--boardオプションに指定します。
$ west build --board nrf5340dk_nrf5340_cpuapp_ns

デプロイ(flash)

# west flashコマンドを実行すると、ボードに書き込まれてLEDが点滅すればOK
$ west flash
-- west flash: rebuilding
[0/16] Performing build step for 'tfm'
ninja: no work to do.
[2/3] Performing install step for 'tfm'
-- Install configuration: "MinSizeRel"
[3/3] Completed 'tfm'
-- west flash: using runner nrfjprog
Using board 1050088039
-- runners.nrfjprog: Flashing file: /home/hiroki/workspace/nrf-connect-sdk-tutorial/app/build/zephyr/merged.hex
[ #################### ]   1.911s | Erase file - Done erasing                                                          
[ #################### ]   0.406s | Program file - Done programming                                                    
[ #################### ]   0.303s | Verify file - Done verifying                                                       
Applying pin reset.
-- runners.nrfjprog: Board with serial number 1050088039 flashed successfully.

その他

本記事で作成したソースコードはgithub.com/kumanote/nrf-connect-sdk-tutorialに公開しています。

参考リンク