前回の記事では、Seeeduino XIAOのUARTポートからHello, world!を出力してみました。
まあ、Zephyr OS付属のサンプルそのままですが…😅
今回は、Seeeduino XIAOのUSB-CポートをUSBシリアルコンソール(USB CDC ACM)として使い、ここにHello, world!を出力してみます。 前は外部にUSB-UART変換モジュールを用意してパソコンと繋ぎましたが、今回はSeeeduino XIAOだけでパソコンと通信できます。
Seeeduino XIAOは600円くらいと安い開発ボードなのに、USBまで使えてとても便利ですよね!🥰
早速やってみましょう。
プロジェクトフォルダの作成
前回は~/myprojects/hello-world
にプロジェクトを作成しましたが、今回は~/myprojects/hello-world-usb
にしましょう。
$ mkdir -p ~/myprojects/hello-world-usb $ cd ~/myprojects/hello-world-usb
プロジェクトの作成
Zephyr OSのプロジェクトには最低限、CMakeLists.txt、prj.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_usb) target_sources(app PRIVATE src/main.c)
find_pachage(Zephyr)
でZephyr OSのビルドシステムを取り込み、app
というターゲットにアプリのソースファイルを指定します。
project()
はプロジェクト名の指定です。
これはプロジェクト名以外、前回のUART版Hello, world!と同じです。
prj.conf
続いてZephyr OSのどの機能を使うかを指定するprj.confですが、USB機能を有効にしたり、USBシリアル機能関連の設定をする必要があります。
Zephyr OSにはいろんなサンプルが付属していて、それを真似するだけでOKになっているのでわかりやすいです☺️
USBシリアルのサンプルは、zephyrproject/zephyr/samples/subsys/usb
にあります。このサンプルをそのまま使って、中身を次のようにします。
CONFIG_USB=y CONFIG_USB_DEVICE_STACK=y CONFIG_USB_DEVICE_PRODUCT="Zephyr USB console sample" CONFIG_USB_UART_CONSOLE=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_UART_LINE_CTRL=y CONFIG_UART_CONSOLE_ON_DEV_NAME="CDC_ACM_0"
CONFIG_USB=y
でUSBドライバを有効にします。CONFIG_USB_DEVICE_STACK=y
はUSBのデバイスモードを有効にします。もっとも、Zephyr OSは現時点ではUSBホストモードは対応しておらず、デバイスモードのみです。そして、CONFIG_USB_UART_CONSOLE=y
で、USBシリアルコンソールを有効にします。
その他、いくつかUSBやUARTのオプションを有効化したり設定したりしています。
ちなみに、このオプションだけではUSBシリアルコンソールへの出力はできますが、入力は受け付けません。USBシリアルコンソールの入出力を両方使う場合のサンプルは、zephyrproject/zephyr/samples/subsys/cdc_acm
を参照してください。
また、現時点ではZephyr OSは複数のUSBデバイスクラスを同時に使うことは対応していません。例えば、USBシリアルコンソールとUSBマスストレージを同時に有効にすることはできません🙅♀️
CONFIG_UART_CONSOLE_ON_DEV_NAME="CDC_ACM_0"
、Zephyr OSのコンソールの出力先を"CDC_ACM_0"にします。
この"CDC_ACM_0"というのがUSBシリアルになります。
src/main.c
いよいよソースコードを用意しましょう。とはいえ、これもサンプルほぼそのままです。
#include <zephyr.h> #include <sys/printk.h> #include <sys/util.h> #include <string.h> #include <usb/usb_device.h> #include <drivers/uart.h> void main(void) { const struct device *dev = device_get_binding( CONFIG_UART_CONSOLE_ON_DEV_NAME); uint32_t dtr = 0; if (usb_enable(NULL)) { return; } /* Poll if the DTR flag was set, optional */ while (!dtr) { uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); } printk("Hello World!\n"); }
USB機能を有効にするには、usb_enable()
を呼び出します。
Zephyr OSのドライバによっては、main()に入る前に自動で初期化・有効化してくれるものも多いのですが、USBは明示的に呼び出す必要があるようです。
使用するUSBデバイスクラスによって、usb_enable()
の前にアプリ側の設定などを行う必要があるからかと思われます。
続いて、
while (!dtr) { uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr); }
で、DTR(Data Treminal Ready)フラグが立つのを待っています。 これで、パソコン側とUSBシリアルコンソールの接続が確立し、通信できるようになるのを待つことができます。
この3行を外すと、パソコン側との接続の有無にかかわらず、先へ進みます。
そして最後に、printk()
でHello world!を出力します。
簡単ですね😉
動かしてみよう
プロジェクトの準備ができたら、早速ビルドしてみましょう。
$ west build -b seeeduino_xiao
ファームウェアのバイナリは、build/zephyr/zephyr.bin
にできます。
これをSeeeduino XIAOに書き込んであげて、Seeeduino XIAOのUSB-Cポートをパソコンにつないでみましょう。
Windowsパソコンでも大丈夫です。自動的にドライバがインストールされ、COMポートとして認識されます。
Tera Termなどのソフトウェアを使って、認識されたCOMポートに接続してみましょう。
このように、USBシリアルでHello World!が出力されました✨
前回と違いSeeeduino XIAO単体でパソコンにコンソール出力できるので、とても便利ですね☺️
今回はSeeeduino XIAOからパソコンへの出力だけでしたが、別のサンプルを参考にすれば、パソコンでの入力をSeeeduino XIAOで受けることもできます。
高機能なZephyr OSをぜひいろいろ試してみてください!
次回は、以前Rapberry PiにつないだBME280という温湿度気圧センサーをつないでみようと思います!