みかんのゆるふわ技術ブログ

Raspberry PiやIoT関係のことを書き残していきます

Zephyr OSのプロジェクトを作ってみよう~Hello, world!出力

前回はZephyr OS付属のサンプルプログラムをビルドしてSeeeduino XIAOに書き込んでみました。

www.mikan-tech.net

www.mikan-tech.net

いよいよ、独自のプロジェクトを作ってマイアプリを作っていきましょう!✊ まずは、定番のHello world!を表示するファームウェアを作ってみます。

ちなみに、Hello, world!を表示するサンプルはZephyr OSにも含まれているので、ほぼそれと同じ内容になります。

プロジェクトフォルダの作成

上記記事ではでZephyr OSを~/zephyrproject/以下にインストールし、その中に含まれているサンプルプロジェクトをビルドしました。 独自のプロジェクトを作成するときは、この~/zephyrproject/以外の場所に、自分用のプロジェクトフォルダを作ってアプリを管理するのがよいでしょう。

ここでは、~/myprojects/以下にアプリを作成していきます。たくさんアプリを作ることを想定して、その中にhello-worldフォルダを作って、そこにhello-worldというプロジェクトを作ることにします。

$ mkdir -p ~/myprojects/hello-world
$ cd ~/myprojects/hello-world/

この中に必要なファイルを配置していきます。

プロジェクトファイルの作成

前回の記事で取り上げた通り、Zephyr OSのプロジェクトには最低限、CMakeLists.txtprj.conf、ファームウェアのソースファイルの3つが必要です。

├── CMakeLists.txt
├── prj.conf
└── src
    └── main.c

こんな感じになるようにファイルを作っていきましょう。

CMakeLists.txt

最低限の中身のCMakeLists.txtは次のようになります。

cmake_minimum_required(VERSION 3.13.1)

find_package(Zephyr)
project(hello_world)

target_sources(app PRIVATE src/main.c)

find_pachage(Zephyr)でZephyr OSのビルドシステムを取り込み、appというターゲットにアプリのソースファイルを指定します。 project()はプロジェクト名の指定です。

prj.conf

このファイルには、使用するZephyr OSの機能、追加で読み込むドライバ、設定値の変更などを指定します。

前回のLEDチカチカのサンプルプログラムには、GPIOドライバを読み込む設定が入っていましたね。

実はUARTでの文字出力はZephyr OSのデフォルトで有効になっているので、今回は何も書かなくても良いです。 ファイルが無くてもOKですが、一応コメントだけ書いておきます。

# Nothing needed

src/main.c

Hello, world!を表示するソースファイルがこちらです。

#include <zephyr.h>
#include <sys/printk.h>

void main(void)
{
        printk("Hello World!\n");
}

とても簡単ですね。printk()はZephyr OSのシステムコンソールに文字を出力する関数で、標準Cライブラリのprintf()と似た機能を持ちます。 引数も同じように使えます。ただし、浮動小数点のフォーマット%fをサポートしていないなど、軽量化のための制約もあります。

printk()を使うには、KconfigのCONFIG_PRINTKyに設定する必要がありますが、デフォルトでyになっています。 そのため、prj.confCONFIG_PRINTK=yと書く必要はありません。

以上でプロジェクトが完成しました。

システムコンソールとは?

ところで、printk()の文字はどこに出力されるのでしょうか?🤔

これはZephyr OSのシステムコンソールに出力されます。そのシステムコンソールはKconfigやボードのデバイスツリーで設定されています。

Zephyr OSのソースツリー中のSeeeduino XIAOのボード定義フォルダをのぞいてみると、デバイスツリーファイルに次のような記述があります(抜粋)。

chosen {
    zephyr,console = &sercom4;
    zephyr,shell-uart = &sercom4;
    zephyr,sram = &sram0;
    zephyr,flash = &flash0;
    zephyr,code-partition = &code_partition;
};

ここで、コンソールとしてsercom4が選択されていることがわかります。

sercom4というのはSeeeduino XIAOに搭載されているマイコンSAMD21のペリフェラルで、UART機能を持っています。

f:id:kimura_khs:20210424165558j:plain
画像出典: Seeeduino XIAO Wiki

Seeeduino XIAOでは、sercom4のピンがUART TX/RXピン(D6/D7ピン)に割り当てられています。

なのでデフォルトのままだと、このUART TX/RXピンがコンソールとして使われることになります。

アプリ側でオーバーライドして、他のポートをコンソールにしたり、USBシリアルをコンソールにしたりもできます。 最終的なデバイスツリーは、ビルド結果のbuild/zephyr/zephyr.dtsに出力されるので、ここで確認できます。

また、Kconfigで出力先を変えた場合は、build/zephyr/.configを見ると、CONFIG_UART_CONSOLE_ON_DEV_NAME="SERCOM1"などと出力先が設定されていることもあります。

ビルド&書き込み

いよいよこのプロジェクトをビルドしてみましょう。 プロジェクトフォルダに入り、

$ west build -b seeeduino_xiao

(略)
Memory region         Used Size  Region Size  %age Used
           FLASH:       10572 B       232 KB      4.45%
            SRAM:        3816 B        32 KB     11.65%
        IDT_LIST:          0 GB         2 KB      0.00%

とすれば、ビルドできます。最後にメモリ使用量を表示してくれます。FLASHが10KB、RAMが4KBくらい使われているようです。 まだまだ余裕ですね。

ビルド成果物はbuild/というフォルダができてそこに出てきます。 ファームウェアバイナリファイルはbuild/zephyr/zephyr.binで、これをSeeeduino XIAOに書き込めばOKです。

動かしてみよう

ファームウェアを書き込んだらいよいよ動かしてみましょう。

私は市販のUSBシリアル変換基板を用意して、Seeeduino XIAOのUARTポートにつないでみました。

Seeeduino XIAOピン USBシリアルピン 説明
3V3 3V3 電源(3.3V)
GND GND グランド (0V基準電圧)
TX RxD UART (XIAO→PC)
RX TxD UART (PC→XIAO)

今回はSeeeduino XIAOは出力だけで入力は無いので、PC→XIAOのピンはつながなくても大丈夫です。 実際に接続すると、次のようになりました。

f:id:kimura_khs:20210424172432j:plain

電源を入れると、パソコン上のTera Termに文字が出力されました!🥰

f:id:kimura_khs:20210424172212p:plain

最初の行はZephyr OSが自動的に出力しているみたいです。

とても単純なプログラムですが、これで自分のプロジェクトが作れるようになりましたね。 次回はSeeeduino XIAOのUSBポートからUSBシリアル出力してみたいと思います。