1. Examples 一覧
Spresense SDKでは、NuttShell の Built-in コマンドとして各種 Example を用意しています。
SDK v2.0 以降から NuttX オリジナルのアプリケーションも Examples に追加されています。
(SDK v1.x 以前のバージョンのチュートリアルは こちら を参照してください)
初めてビルドする方は、はじめにスタートガイドを参照してください。 コンフィグレーションの方法や、ビルドしたプログラムを実行する手順についての詳しい説明があります。 |
1.1. SDK examples
カテゴリ | Example名 | 説明 |
---|---|---|
Peripheral |
||
GPS (GNSS) |
||
GNSS 評価用のサンプルです。 |
||
GNSS PVTログを出力するサンプルです。 |
||
AudioLite |
||
Audio |
||
オーディオのパススルー機能を用いて、マイク入力、スピーカ出力、I2S入出力を使用したサンプルです。 |
||
PCMデータをキャプチャするサンプルです。 |
||
オーディオビープ音を再生するサンプルです。 |
||
オーディオのデュアルデコード再生のサンプルです。 |
||
オブジェクトインターフェース層を用いたオーディオプレーヤーのサンプルです。 |
||
オブジェクトインターフェース層を用いたオーディオレコーダーのサンプルです。 |
||
オブジェクトインターフェース層を用いたPCMキャプチャのサンプルです。 |
||
低遅延で音声エフェクトを行うサンプルです。 |
||
ASMP |
ASMPフレームワークによるマルチコアを使用したサンプルです。 |
|
マルチコアを使用して素数計算を行うサンプルです。 |
||
マルチコアを使用してFFT演算を行うサンプルです。 |
||
Sensor |
加速度センサからセンサ情報を取得するサンプルです。 |
|
ジャイロセンサからセンサ情報を取得するサンプルです。 |
||
照度センサからセンサ情報を取得するサンプルです。 |
||
地磁気センサからセンサ情報を取得するサンプルです。 |
||
気圧センサからセンサ情報を取得するサンプルです。 |
||
近接センサからセンサ情報を取得するサンプルです。 |
||
カラーセンサからセンサ情報を取得するサンプルです。 |
||
加速度センサを使用して傾き検出を行うサンプルです。 |
||
SCUによるデシメータ機能を使って間引き処理を行うサンプルです。 |
||
加速度センサによる歩数計及び行動認識を行うサンプルです。 |
||
Camera |
||
JPEG |
||
DNN |
DNN Runtime機能を使用して、数字認識を行うサンプルです。 |
|
LTE |
||
DigitalFilter |
||
HostIF |
||
FW Update |
||
ELTRES |
||
FileSystem |
||
Others |
setjmp()/longjmp() 関数を使用したサンプルです。 |
2. Peripheral Driver チュートリアル
2.1. RTC alarm サンプルアプリケーション
RTC alarm サンプルアプリケーションの動作について説明します。
2.1.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/alarm
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/alarm make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
2.1.2. 動作確認
シリアルターミナルを開いて、alarm
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
alarm
コマンドを実行します。alarm
コマンドの使い方を以下に示します。nsh> alarm ERROR: Invalid number of arguments: 0 USAGE: alarm <seconds> Where: <seconds> The number of seconds until the alarm expires.
<seconds> には相対時間(秒)を指定します。例えば、
alarm 5
と入力すると、5 秒後にアラームが発火します。nsh> alarm 5 alarm_daemon started alarm_daemon: Running Opening /dev/rtc0 Alarm 0 set in 5 seconds nsh> alarm_demon: alarm 0 received
2.1.3. 省電力機能と組み合わせて使用する
alarm
コマンドと省電力機能を組み合わせて使用する例について紹介します。
Spresense には、Deep Sleep や Cold Sleep モードといった省電力機能が提供されています。
poweroff
コマンドを用いてこれらの Sleep 状態に入ることができます。
そして、RTC アラーム機能により、この Sleep 状態から起床することができます
Deep Sleep や Cold Sleep について、詳しくは スリープモード を参照してください。
2.1.4. その他の RTC に関するコマンド
date
コマンドにより、RTC に時刻を設定したり、RTC に設定された現在時刻を表示することができます。
nsh> help date date usage: date [-s "MMM DD HH:MM:SS YYYY"]
例)RTC に 2019年12月1日23時34分56秒を設定する場合、
nsh> date -s "Dec 1 23:34:56 2019"
date コマンドにより現在時刻を表示します。
nsh> date Dec 01 23:35:14 2019
RTC は、Deep/Cold Sleep といったスリープ中や reboot
コマンドにより再起動した場合でも時刻を保持し続けます。ただし、電源供給がオフされたり、リセットボタンが押された場合は、RTC に設定された時刻はリセットされます。
以下に reboot
コマンドによる再起動後も時刻が保持されている例を示します。
nsh> date Dec 01 23:41:08 2019 nsh> reboot NuttShell (NSH) NuttX-8.2 nsh> date Dec 01 23:41:12 2019 nsh>
2.2. Watchdog サンプルアプリケーション
Watchdog サンプルアプリケーションの動作について説明します。
2.2.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/watchdog
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/watchdog make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
2.2.2. 動作確認
シリアルターミナルを開いて、wdog
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
wdog
コマンドを実行します。wdog
コマンドの使い方を以下に示します。nsh> wdog -h Usage: wdog [-h] [-d <pingdelay>] [-p <pingtime>] [-t <timeout>] Initialize the watchdog to the <timeout>. Start the watchdog timer. Ping for the watchdog for <pingtime> seconds, then let it expire. Options include: [-d <pingdelay>] = Time delay between pings in milliseconds. Default: 500 [-p <pingtime>] = Selects the <pingtime> time in milliseconds. Default: 5000 [-t timeout] = Time in milliseconds that the example will ping the watchdog before letting the watchdog expire. Default: 2000 [-h] = Shows this message and exits
- -d
-
指定された周期 [msec] で ioctl(fd, WDIOC_KEEPALIVE, 0) を呼び出すことで watchdog タイマーをクリアします。
- -p
-
指定された期間中 [msec] は watchdog をクリアし続けます。
- -t
-
指定された値 [msec] で ioctl(fd, WDIOC_SETTIMEOUT, (unsigned long)wdog.timeout) を呼び出しwatchdog タイマーの周期を設定します。
本サンプルアプリケーションは、watchdog タイマーの発火に伴いシステムがリブートすることを確認できます。
wdog
コマンドを実行した例を以下に示します。
引数無しで動作させたときは、デフォルト値の 2 秒で watchdog タイマー周期を設定します。
5 秒間は 500 msec 周期で watchdog タイマーをクリアし続けます。
その後、watchdog タイマーをクリアしないままタイマーが満了してシステムがリブートします。
nsh> wdog ping elapsed=0 ping elapsed=500 ping elapsed=1000 ping elapsed=1500 ping elapsed=2000 ping elapsed=2500 ping elapsed=3000 ping elapsed=3500 ping elapsed=4000 ping elapsed=4500 NO ping elapsed=5000 NO ping elapsed=5500 NO ping elapsed=6000 up_assert: Assertion failed at file:irq/irq_unexpectedisr.c line: 65 task: Idle Task up_dumpstate: sp: 0d0279d4 up_dumpstate: IRQ stack: up_dumpstate: base: 0d027a00 up_dumpstate: size: 00000800 up_dumpstate: used: 00000120 up_stackdump: 0d0279c0: 00000000 0d003e3d 0d0291a8 0d02975c 00000000 00000002 466cc9d4 0d002f69 up_stackdump: 0d0279e0: 0d002f55 0d00703d 00000000 0d02975c 0d028a20 00000003 00000000 0d006fd5 up_dumpstate: sp: 0d029830 up_dumpstate: User stack: up_dumpstate: base: 0d029840 up_dumpstate: size: 00000400 up_dumpstate: used: 00000000 up_stackdump: 0d029820: 9b7feebc 1f86add5 00000000 0d002e75 0d029844 001567bc 2df7cabf 00000000 up_registerdump: R0: 00000000 0d026bcc 0d02df68 00000014 0d026b54 0d028a20 00000003 00000000 up_registerdump: R8: 0d026ca0 f0bbaf7f dc9161d8 466cc9d4 00000003 0d029830 0d002e79 0d008792 up_registerdump: xPSR: 21000000 BASEPRI: 00000000 CONTROL: 00000000 up_registerdump: EXC_RETURN: ffffffe9 up_taskdump: Idle Task: PID=0 Stack Used=0 of 0 up_taskdump: hpwork: PID=1 Stack Used=344 of 2028 up_taskdump: lpwork: PID=2 Stack Used=352 of 2028 up_taskdump: lpwork: PID=3 Stack Used=352 of 2028 up_taskdump: lpwork: PID=4 Stack Used=352 of 2028 up_taskdump: init: PID=5 Stack Used=1032 of 8172 up_taskdump: cxd56_pm_task: PID=6 Stack Used=320 of 996 up_taskdump: wdog: PID=8 Stack Used=528 of 2028 NuttShell (NSH) NuttX-8.2 nsh>
2.3. ADC サンプルアプリケーション
この章では、ADC サンプルアプリケーションの動作手順を示します。
2.3.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/adc_monitor
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/adc_monitor make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
2.3.2. 動作確認
シリアルターミナルを開いて、adc_monitor コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
adc_monitor
コマンドを実行します。adc_monitor コマンドの Usage を以下に示します。
nsh> adc_monitor -h Usage: adc_monitor [OPTIONS] Arguments are "sticky". For example, once the ADC device is specified, that device will be re-used until it is changed. "sticky" OPTIONS include: [-p devpath] selects the ADC device. /dev/lpadc0, 1, 2, 3, /dev/hpadc0, 1 Current: /dev/lpadc0 [-n count] set the number of reads. Current: 10 [-h] shows this message and exits
- -p
-
全部で 6 つの ADC 専用端子があります。-p オプションにより、-p /dev/lpadc[0-3] もしくは /dev/hpadc[0-1] を指定します。 Spresense ボード上のピン番号とデバイスファイルの関係は下記の通りです。
ピン番号
A0
A1
A2
A3
A4
A5
/devファイル
/dev/lpadc0
/dev/lpadc1
/dev/lpadc2
/dev/lpadc3
/dev/hpadc0
/dev/hpadc1
- -n
-
測定回数を指定します。
例えば、HPADC0 (A4) に対して、10 回分の ADC データ取得を行います。 HPADC0 に対して、ADC データをバッファリングし、その平均値、最小値、最大値を表示します。 ADC データは 16bit の符号付きデータで、範囲は -32767 ~ 32767 です。
nsh> adc_monitor -p /dev/hpadc0 -n 10 ADC example - Name:/dev/hpadc0 bufsize:16 Ave:-32767 Min:-32767 Max:-32767 Cnt:8 Ave:-32767 Min:-32767 Max:-32767 Cnt:8 Ave:-32767 Min:-32767 Max:-32767 Cnt:8 Ave:14673 Min:14668 Max:14676 Cnt:8 Ave:14681 Min:14677 Max:14684 Cnt:8 Ave:14690 Min:14687 Max:14694 Cnt:8 Ave:14684 Min:14680 Max:14690 Cnt:8 Ave:14677 Min:14672 Max:14682 Cnt:8 Ave:14677 Min:14675 Max:14682 Cnt:8 Ave:14672 Min:14667 Max:14677 Cnt:8 ADC example end
2.3.3. ADC サンプリング周波数について
ADC のサンプリング周波数は SCU clock mode により選択されたクロックに依存します。
2.3.3.1. HPADC (High Performance ADC)
HPADC は高速サンプリングが可能な ADC です。
HPADC の クロック系統図を以下に示します。
クロックソースを固定分周して HPADC クロックが決まります。 その ADC クロックを 2 のべき乗で分周してサンプリング周波数が決定されます。
n の値は、次の SDK コンフィグレーションにより変更することができます。
System Type -> CXD56xx Package Configuration -> Peripheral Support -> ADC -> HPADC0 -> Coefficient of sampling frequency (CONFIG_CXD56_HPADC0_FREQ) ADC -> HPADC1 -> Coefficient of sampling frequency (CONFIG_CXD56_HPADC1_FREQ)
n の取りうる範囲は、SCU clock mode によって変わります。
-
SCU clock mode = RTC の場合
n 9 10 11 Fs(Hz)
64
32
16
Available
〇
〇
〇
-
SCU clock mode = RCOSC/XOSC の場合
n 0 2 3 4 5 6 7(*1) Fs(Hz)
540-550K(*3)
512K
256K
128K
64K
32K
16K
Available
△(*4)
△(*2)
△(*2)
△(*2)
〇
〇
〇
(*1): デフォルトは SCU clock mode = RCOSC, n = 7 が選択されており、Fs = 16KHz です。
(*2): CONFIG_CXD56_HPADC0_HIGHSPEED=y のとき、最大512KHzまでのFsをサポートします。
(*3): CONFIG_CXD56_HPADC0_HIGHSPEED=y のとき、SCUシーケンサの実行性能に律速し、540〜550KHzで動作します。
(*4): n = 0 にしたとき、後段の平滑化CICフィルタが無効になり、10bit精度のADC生値を出力します。CONFIG_CXD56_HPADC0_HIGHSPEED を有効にした場合、
HPADC1、LPADC、I2C/SPI の SCUシーケンサを使用することはできなくなります。高速サンプリングレート(512KHz)を使用する際の推奨コンフィグレーションを以下に示します。
Configuration Value Description CONFIG_CXD56_ADC
y
ADC を有効にします。
CONFIG_CXD56_HPADC0
y
HPADC0 を有効にします。
CONFIG_CXD56_HPADC1
n
HPADC1 を無効にします。
CONFIG_CXD56_LPADC
n
LPADC を無効にします。
CONFIG_CXD56_HPADC0_FREQ
2
Fsを512KHzに設定します。
CONFIG_CXD56_HPADC0_HIGHSPEED
y
高速オプションを有効にします。
CONFIG_CXD56_HPADC0_INPUT_GAIN_M6DB
y
入力ゲイン設定として-6dBを選択します。
CONFIG_CXD56_I2C0_SCUSEQ
n
I2C0 SCUシーケンサを無効にします。
CONFIG_CXD56_I2C1_SCUSEQ
n
I2C1 SCUシーケンサを無効にします。
CONFIG_CXD56_SPI3_SCUSEQ
n
SPI3 SCUシーケンサを無効にします。
CONFIG_CXD56_SCU_XOSC
y
SCUクロック源としてXOSCを選択します。
2.3.3.2. LPADC (Low Power ADC)
LPADC は HPADC に比べてサンプリングレートは低速ですが省電力で動作する ADC です。 LPADC のクロック系統図を以下に示します。
LPADC を RTC クロックをベースに動作します。そのクロックを 2 のべき乗で分周してサンプリング周波数が決定されます。
n の値は、次の SDK コンフィグレーションにより変更することができます。
System Type -> CXD56xx Package Configuration -> Peripheral Support -> ADC -> LPADC0 -> Coefficient of sampling frequency (CONFIG_CXD56_LPADC0_FREQ) ADC -> LPADC1 -> Coefficient of sampling frequency (CONFIG_CXD56_LPADC1_FREQ) ADC -> LPADC2 -> Coefficient of sampling frequency (CONFIG_CXD56_LPADC2_FREQ) ADC -> LPADC3 -> Coefficient of sampling frequency (CONFIG_CXD56_LPADC3_FREQ)
n の取りうる範囲は、SCU clock mode によって変わります。 また、LPADC は全部で 4 チャンネルありますが、1 ch のみ使用する場合、2ch で使用する場合、4ch で使用する場合 でもサンプリング周波数の上限値が変わります。それぞれのケースで、n の取りうる値を以下に示します。
-
SCU clock mode = RTC の場合
-
LPADC channel 0 ~ 3 のいずれか一つのチャンネルを選択した場合
n 11 12 13 14 15 Fs(Hz)
16
8
4
2
1
Available
〇
〇
〇
〇
〇
-
LPADC channel 0 and 1 の二つのチャンネルを選択した場合
n 12 13 14 15 Fs(Hz)
4
2
1
0.5
Available
〇
〇
〇
〇
-
LPADC channel 0 ~ 3 の四つのチャンネルを選択した場合
n 11 12 13 14 15 Fs(Hz)
4
2
1
0.5
0.25
Available
〇
〇
〇
〇
〇
-
-
SCU clock mode = RCOSC の場合
-
LPADC channel 0 ~ 3 のいずれか一つのチャンネルを選択した場合
n 3 4 5 6 7 8 9 10 11 12 13 14 15 Fs(Hz)
4K
2K
1K
512
256
128
64
32
16
8
4
2
1
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
-
LPADC channel 0 and 1 の二つのチャンネルを選択した場合
n 6 7 8 9 10 11 12 13 14 15 Fs(Hz)
256
128
64
32
16
8
4
2
1
0.5
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
-
LPADC channel 0 ~ 3 の四つのチャンネルを選択した場合
n 7(*) 8 9 10 11 12 13 14 15 Fs(Hz)
64
32
16
8
4
2
1
0.5
0.25
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
(*): デフォルトは LPADC 全チャンネル有効で SCU clock mode = RCOSC, n = 7 が選択されています。
-
-
SCU clock mode = XOSC の場合
-
LPADC channel 0 ~ 3 のいずれか一つのチャンネルを選択した場合
n 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Fs(Hz)
8K
4K
2K
1K
512
256
128
64
32
16
8
4
2
1
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
-
LPADC channel 0 and 1 の二つのチャンネルを選択した場合
n 6 7 8 9 10 11 12 13 14 15 Fs(Hz)
256
128
64
32
16
8
4
2
1
0.5
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
〇
-
LPADC channel 0 ~ 3 の四つのチャンネルを選択した場合
n 7 8 9 10 11 12 13 14 15 Fs(Hz)
64
32
16
8
4
2
1
0.5
0.25
Available
〇
〇
〇
〇
〇
〇
〇
〇
〇
-
2.4. PWM サンプルアプリケーション
PWM サンプルアプリケーションの動作について説明します。
2.4.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/pwm
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/pwm make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
2.4.2. 動作確認
シリアルターミナルを開いて、pwm
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
pwm
コマンドを実行します。pwm
コマンドの使い方を以下に示します。nsh> pwm -h Usage: pwm [OPTIONS] Arguments are "sticky". For example, once the PWM frequency is specified, that frequency will be re-used until it is changed. "sticky" OPTIONS include: [-p devpath] selects the PWM device. Default: /dev/pwm0 Current: /dev/pwm0 [-f frequency] selects the pulse frequency. Default: 1000 Hz Current: 1000 Hz [-d duty] selects the pulse duty as a percentage. Default: 50 % Current: 50 % [-t duration] is the duration of the pulse train in seconds. Default: 5 Current: 5 [-h] shows this message and exits
例)PWM1 に対して、周期 2000 Hz、デューティー比 30 % の PWM 信号を 10 秒間出力します。
nsh> pwm -p /dev/pwm1 -f 2000 -d 30 -t 10
- -p
-
全部で 4 つの PWM 専用端子があります。-p オプションにより、-p /dev/pwm[0-3] を指定します。
- -f
-
PWM 周期 [Hz] を設定します。
- -d
-
デューティー比(周期に対する High 期間の割り合い) [%] は、1 ~ 99 までの数字を指定します。
- -t
-
指定された時間 [s] の PWM 信号を出力します。
2.4.3. PWM 周波数とデューティー比について
PWM は SCU clock mode により選択されたクロックで動作します。
SCU clock を以下に示します。
-
Same with SCU32K → RTC 32.768kHz
-
RCOSC → 約8.2MHz
-
XOSC → TCXO 26MHz を CONFIG_CXD56_SCU_XOSC_DIV(=2) で分周した 13MHz
PWM 信号の波形は、下図で表されるように SCU clock の PWM_CYCLE カウント数により周期が決まり、 PWM_THRESH カウント数により Low 出力の期間が決定されます。カウント数の上限は 0xffff です。
PWM で設定できる周波数の範囲は、
1 <= PWM frequency <= SCU clock / 2
となり、例えば、SCU clock が RCOSC を選択した場合は、1Hz ~ 約 4MHz までとなります。
デューティー比について、-d
で指定された数字から計算上の近似値で Low, High の区間を決定するため、
出力される波形は正確なデューティー比にならず丸め誤差を含むことがあります。
3. GPS チュートリアル
3.1. GNSS サンプルアプリケーション
GNSS サンプルアプリケーションの動作について説明します。
3.1.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/gnss
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/gnss make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
3.1.2. 動作確認
シリアルターミナルを開いて、gnss
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
gnss
コマンドを実行します。図 1. gnssコマンド起動時ログ
本アプリケーションを実行すると、はじめに /dev/gps
ドライバを open() します。
fd = open("/dev/gps", O_RDONLY);
openしたドライバに対して ioctl() を用いて、測定周期の設定や衛星システムの選択を行います。
ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_OPE_MODE, (uint32_t)&set_opemode);
ret = ioctl(fd, CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM, set_satellite);
ioctl() の CXD56_GNSS_IOCTL_START コマンドにより測位を開始します。
ret = ioctl(fd, CXD56_GNSS_IOCTL_START, CXD56_GNSS_STMOD_HOT);
測位結果は、read() を用いて読みだすことができます。
ret = read(fd, &posdat, sizeof(posdat));
本アプリケーションでは 1 秒周期で測位結果を表示します。
位置情報が取得できるまでの間は、"No Positioning Data"と表示されます。
Hour:0, minute:0, sec:3, usec:503 No Positioning Data
はじめに時刻情報を取得できたら、ターミナル上に UTC 時刻を表示します。
さらに位置情報を取得できたら次のように緯度、経度情報がターミナル上に表示されます。
Hour:9, minute:13, sec:20, usec:559 LAT 35.25.6303 LNG 139.22.1986
本アプリケーションは、位置情報を取得してから約200秒後に測位動作を終了します。
ioctl() の CXD56_GNSS_IOCTL_STOP コマンドにより測位を停止した後に、/dev/gps
ドライバを close() します。
ret = ioctl(fd, CXD56_GNSS_IOCTL_STOP, 0);
ret = close(fd);
上空がよく見える屋外など受信環境が良い場合は、約30秒~1分ぐらいで測位ができますが、 受信環境がよくない場合は測位するまでに数分かかる場合があります。
3.2. Geofence サンプルアプリケーション
Geofence サンプルアプリケーションの動作について説明します。
Geofence は、GNSS で取得される位置情報を使って、特定のリージョンに入る・抜ける・一定期間滞在している、 といったイベントを検出しアプリケーションに通知する機能を提供します。そのリージョンは、中心座標(緯度経度)とその半径によって 指定され、ユーザーが任意の位置を最大 20 地点まで登録することができます。
3.2.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/geofence
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/geofence make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
3.2.2. 動作確認
シリアルターミナルを開いて、geofence
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
geofence
コマンドを実行します。nsh> geofence
本アプリケーションでは、まず現在位置の情報を測位によって取得します。
その現在位置と、そこを起点として東西南北方向にそれぞれ 50 m ずつ離れた場所の計 5 つのリージョンを登録します。
現在位置の測位が完了しリージョンが設定された後に、デバイスを持ち歩いて移動することにより、 特定のリージョンに入った"ENTER"/抜けた"EXIT"/滞在している"DWELL"、といったステータスの情報がログ上に表示されます。
具体的な Geofence 機能の使い方については以下の通りです。
/dev/gps
ドライバを open() して測位を行う方法は、
前述した GNSS サンプルアプリケーション を参照してください。
Geofence 機能を使用するためには /dev/geofence
ドライバを open() します。
g_fdgeo = open("/dev/geofence", O_RDONLY);
openしたドライバに対して ioctl() を用いて、Dead zone [m] や滞在通知期間 [s] を設定します。
mode.deadzone = 5;
mode.dwell_detecttime = 10;
ret = ioctl(g_fdgeo, CXD56_GEOFENCE_IOCTL_SET_MODE, (unsigned long)&mode);
ioctl() の CXD56_GEOFENCE_IOCTL_ADD コマンドにより、リージョンを追加します。
region_xxx.id = 0;
region_xxx.latitude = own_latitude;
region_xxx.longitude = own_longitude;
region_xxx.radius = GEOFENE_REGION_RADIUS;
ret = ioctl(g_fdgeo, CXD56_GEOFENCE_IOCTL_ADD, (unsigned long)®ion_xxx);
ioctl() の CXD56_GEOFENCE_IOCTL_START コマンドにより、Geofence 動作を開始します。
ret = ioctl(g_fdgeo, CXD56_GEOFENCE_IOCTL_START, 0);
Geofence イベントを poll() によって待ち受け、read() により情報を取得します。
ret = read(g_fdgeo, &g_geofence_status, sizeof(struct cxd56_geofence_status_s));
本アプリケーションは、トータル 10 個のイベント通知がきたら Geofence 動作を終了します。
ioctl() の CXD56_GEOFENCE_IOCTL_STOP コマンドにより停止した後に、/dev/geofence
ドライバを close() します。
ret = ioctl(g_fdgeo, CXD56_GEOFENCE_IOCTL_STOP, 0);
ret = close(g_fdgeo);
3.3. GNSS ATCMD アプリケーション
gnss_atcmd
は Spresense SDK 上で動作する GNSS 機能評価用のサンプルアプリケーションです。
PC 等のホストからシリアルポートを介してコマンドを送信すると、そのシリアルポートに NMEA センテンスの結果が出力されます。具体的なコマンドの仕様とアプリケーションの使用例について示します。
3.3.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
本アプリケーションを実行するためには、以下の SDK Configuration を有効にしてください。
CONFIG_CXD56_GNSS=y CONFIG_GPSUTILS_CXD56NMEA_LIB=y CONFIG_EXAMPLES_GNSS_ATCMD=y
下記のコマンド実行することでこれらの Configuration を自動的に有効にすることができます。
./tools/config.py examples/gnss_atcmd
また、コマンド入出力に使用するポートを、コンフィグレーション GNSS Command IO によって切り替えることができます。
│ Prompt: GNSS Command IO │ Location: │ -> Examples │ -> GNSS CXD5603 @command emulator example (EXAMPLES_GNSS_ATCMD [=y])
-
Example uses USB CDC tty : 拡張ボード上の USB ポートを使用 (デフォルト)
-
Example uses STDINOUT for nsh debug UART : メイン基板上の USB ポート (UART1)
-
Example uses UART ttyS0 : メイン基板上の USB ポート (UART1)
-
Example uses UART ttyS1 : 非サポート
-
Example uses UART ttyS2 : メインボード及び拡張ボード上の UART ポート (UART2)
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
というバイナリファイルが生成されます。
-
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
3.3.2. @コマンド仕様
ホストから送信するコマンドの仕様について説明します。
PC 等のホストから送信されたコマンドを gnss_atcmd アプリケーションが受信し、処理結果をホストに返します。コマンド送信から結果が応答されるまでの期間は、NMEA は出力されません。gnss_atcmd アプリケーションからコマンド完了を示す応答メッセージ (Done または Err ) が返ってくる前に別のコマンドを発行しないようにして下さい。なお、コマンド送信からコマンド応答が返るまでの時間はコマンドの種別およびその時の状態により異なりますが、ワーストケースで約 5 秒かかることがあります。ホストコントローラにてタイムアウトを検出する際は 5 秒にてタイムアウトと判断して下さい。
3.3.2.1. コマンドフォーマット
コマンドの書式は以下の通りです。"@" (アットマーク)に続いてコマンド文字列や引数を送信し、最後に改行コードを送ります。
@Command [Argument0] [Argument1]...<CR><LF>
- Command
-
4 文字以内の文字列です。詳細は下表 コマンド一覧 を参照してください。
- Argument
-
10 進数で表される数値です。文字列の先頭が "0x" の場合は 16 進数を表します。 コマンドによっては複数の引数をとります。
- <CR><LF>
-
改行コードを表します。コマンド行の終わりには CR (Carriage Return) + LF (Line Feed) を付けてください。
3.3.2.2. 正常応答フォーマット
正常応答結果の書式は以下の通りです。[送信したコマンド文字列]に続いて、"Done"の文字列が返ります。
[Command] Done<CR><LF>
- Command
-
受信したコマンド文字列を表します。
- <CR><LF>
-
改行を表します。応答行の終わりには CR (Carriage Return) + LF (Line Feed) が付加されています。
3.3.2.3. エラー応答フォーマット
エラー応答結果の書式は以下の通りです。[送信したコマンド文字列]に続いて、"Err"の文字列とエラーコードが返ります。
[Command] Err ErrorCode<CR><LF>
- Command
-
受信したコマンド文字列を表します。
- ErrorCode
-
負値のエラーコードを表します。
- <CR><LF>
-
改行を表します。応答行の終わりには CR (Carriage Return) + LF (Line Feed) が付加されています。
3.3.2.4. コマンドシーケンス
@GCD のような測位開始のコマンドを発行すると、"Done" の応答を返した後に、定期的に NMEA センテンスが Host へ送られます。
@VER コマンドを発行すると、バージョン情報が送られた後に、"Done" の応答が返ります。
3.3.2.5. コマンド一覧
gnss_atcmd が処理可能なコマンド一覧を下記に示します。
Command | Argument | Description | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@AEXT |
- |
アプリケーションを終了します。本コマンドは測位停止中に実行してください。 |
||||||||||||||||||||||||||||||
@BSSL |
NMEAマスク |
NMEA 0183 (ver 4.00) 規格で定義されているNMEAセンテンスのうち、 出力するNMEAセンテンスをビットマスク値で引数に指定します。 初期状態ではNMEAマスクには0xefが設定されています。
xx は、以下を表します。
コマンド例:
|
||||||||||||||||||||||||||||||
@BUP |
- |
受信済みのエフェメリス及び各種パラメータを Flash へセーブします。セーブされたデータは次回起動時に自動的にリストアされます。
本コマンドは測位停止中に実行して下さい。 |
||||||||||||||||||||||||||||||
@GCD |
- |
Cold Start による測位を開始し、NMEAセンテンスを周期的に出力します。出力されるNMEAセンテンスはNMEAマスクに従います。 |
||||||||||||||||||||||||||||||
@GNS |
衛星マスク |
測位に使用する衛星を引数のビットマスク値で選択します。
NOTE
GLONASS, Galileo, BeiDou に関して同時に使用することはできません。 コマンド例:
|
||||||||||||||||||||||||||||||
@GPOE |
<緯度[度]> |
楕円体座標の受信機現在位置を設定します。 コマンド例:
|
||||||||||||||||||||||||||||||
@GSR |
- |
Hot Start による測位を開始し、NMEAセンテンスを周期的に出力します。 |
||||||||||||||||||||||||||||||
@GSTP |
- |
測位を停止します。 |
||||||||||||||||||||||||||||||
@GSW |
- |
Warm Start による測位を開始し、NMEAセンテンスを周期的に出力します。 |
||||||||||||||||||||||||||||||
@GTIM |
<年> |
UTC時刻を設定します。 コマンド例:
|
||||||||||||||||||||||||||||||
@VER |
- |
ALLゼロのバージョン番号を返します。 |
3.3.3. 動作確認
シリアルターミナルを開いて、gnss_atcmd コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
gnss_atcmd
コマンドを実行します。以下に示す例は、コマンド入出力のターミナルとして NuttShell と同じメイン基板上の USB ポートを使用しています。 前述した GNSS Command IO のコンフィグレーションは、"Example uses STDINOUT for nsh debug UART" を選択しています。
-
Example uses USB CDC tty
-
Example uses STDINOUT for nsh debug UART
-
Example uses UART ttyS0
-
Example uses UART ttyS1
-
Example uses UART ttyS2
-
3.3.3.1. 例: Cold Start による測位の開始と停止
GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 その後 NMEA センテンスが出力され、適当な期間の後、測位を停止して gnss_atcmd を終了します。
nsh> gnss_atcmd (アプリケーション開始)
@GNS 0x0b↵ (測位衛星の選択)
@GCD↵ (Cold Start測位開始)
----- <NMEA出力> ----
@GSTP↵ (測位停止)
@AEXT↵ (アプリケーション終了)
nsh>
3.3.3.2. 例: GNSS 終了後の Hot Start 測位
初めに GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 測位された後に、Spresense の電源は保ちつつ GNSS を終了し、再度 Hot Start で測位を開始します。 Hot Start では測位開始から数秒後に測位が FIX します。
nsh> gnss_atcmd (アプリケーション開始)
@GNS 0x0b↵ (測位衛星の選択)
@GCD↵ (Cold Start測位開始)
----- <NMEA出力> ----
@GSTP↵ (測位停止)
@AEXT↵ (アプリケーション終了)
nsh> gnss_atcmd (アプリケーション開始)
@GSR↵ (Hot Start測位開始)
----- <NMEA出力> ----
@GSTP↵ (測位停止)
@AEXT↵ (アプリケーション終了)
nsh>
3.3.3.3. 例: Spresense 電源 OFF 後の Hot Start 測位
初めに GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 その後、GNSS を終了した後に Spresense の電源を OFF します。
再度 Spresense の電源を入れた後、UTC 時刻と現在位置を入力して Hot Start で測位を開始します。 Hot Start では測位開始から数秒後に測位が FIX します。
nsh> gnss_atcmd (アプリケーション開始)
@GNS 0x0b↵ (測位衛星の選択)
@GCD↵ (Cold Start測位開始)
----- <NMEA出力> ----
@GSTP↵ (測位停止)
@BUP↵ (Flashへバックアップ)
@AEXT↵ (アプリケーション終了)
----- <Power OFF> -----
----- <Power ON> -----
nsh> gnss_atcmd (アプリケーション開始)
@GTIM 2018 11 09 02 45 05↵ (UTC 時刻設定)
@GPOE 35 39 31 139 44 05↵ (現在位置の設定)
@GSR↵ (Hot Start測位開始)
----- <NMEA出力> ----
@GSTP↵ (測位停止)
@AEXT↵ (アプリケーション終了)
nsh>
3.3.3.4. みちびきQZQSMセンテンスの出力
衛星マスクにQZSS L1/CAを選び、NMEAマスクでQZQSMセンテンスを有効にした後、測位を開始します。 受信条件が良ければ10秒弱で最初のQZQSMセンテンスが出力され、その後4秒毎に出力されます。
nsh> gnss_atcmd
@GNS 0x29↵
@BSSL 0x40ef↵
@GCD↵
$GPGGA,000001.00,,,,,0,00,,,,,,,*49
$GNGLL,,,,,000001.00,V,N*55
…
$GNZDA,000008.00,06,01,1980,,*77
$QZQSM,56,9AADF260540002C3F2587F8B101962082C41A588ACB1181623500011439023C*7B
$GPGGA,000009.00,,,,,0,00,,,,,,,*41
…
3.4. GNSS Add-on サンプルアプリケーション
GNSS Add-on サンプルアプリケーションの動作について説明します。
本サンプルアプリケーションは、GNSS Add-onボードを使って位置情報を取得するといった基本的な使い方に加えて、 GPSデータロガーとしてそのまま利用できるようないくつかの機能をオプションとして実装しています。 オリジナルアプリケーションを作成する場合の参考にしてください。
-
NMEA出力サポート
-
測位周期設定サポート
-
1PPS信号を使った時刻設定
-
ファイルロギング機能
-
省電力のための間欠測位
-
アプリケーションの自動実行
-
みちびき災危通報出力サポート
3.4.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/gnss_addon
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/gnss_addon make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
3.4.2. 動作確認
シリアルターミナルを開いて、gnss_addon
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
gnss_addon
コマンドを実行します。gnss_addon
コマンドの引数に-h
を指定するとUsage
が表示されます。nsh> gnss_addon -h Usage: gnss_addon [-n] [-q] [-p] [-c <cycle>] [-f <fixcnt>] [-s <sleep>] [-o <filepath>] Options: -n: Enable NMEA output -q: Enable NMEA DC Report output with "-n" option -p: Enable 1PPS signal -c <cycle>: Positioning cycle (100, 125, 200, 250, 500 or 1000 x N) [msec] (default:1000) -f <fixcnt>: Positioning fix count (default:300) -s <sleep>: Sleeping time [sec] (default:0) -o <filepath>: Full path to a log file
gnss_addon
コマンドを実行すると、はじめにファームウェアのバージョンを表示した後、指定した引数にしたがって測位を開始します。 測位がFIXして位置情報を取得できてから-f
で指定した数だけ連続して測位に成功すると測位動作を停止し、-s
で指定した秒数だけシステム全体がスリープ状態に入ります。アプリケーションの自動実行機能を利用することで、スリープ状態から起床したら再び測位を開始する、という間欠的な動作を繰り返し行うことができます。 -
アプリケーションの自動実行を設定する
アプリケーションの自動起動方法 に書かれている方法で、電源投入時に本アプリケーションが自動で実行されるように設定します。
例えば、100回測位した後に60秒スリープするという周期動作を行う場合は、次のように
init.rc
スクリプトを作成します。nsh> echo "gnss_addon -f 100 -s 60" > /mnt/spif/init.rc
reboot
コマンド、もしくは、リセットボタンを押して再起動すると、スクリプトの内容に従って自動実行を開始します。nsh> reboot Run /mnt/spif/init.rc. sh [13:100] NuttShell (NSH) NuttX-12.3.0 nsh> GNSS Add-on example application: NMEA: Disable (DC Report: Disable), 1PPS: Disable After positioning fix 100 times, sleep 60 sec. FW version: v00.144 2000/01/02 00:00:03.000 0.000000 0.000000 0.000 [N]
測位実行中でもNuttShellコマンドを入力することができます。自動起動を中止する場合は、
init.rc
スクリプトを削除してから再起動してください。nsh> rm /mnt/spif/init.rc nsh> reboot
3.4.3. プログラム解説
-
基本的な測位シーケンス
ここでは、GNSS Add-onボードを使用して位置情報を取得するための基本的な手順を解説します。 内蔵GNSSとインターフェース互換性を保っているので、基本的な使い方は、GNSS サンプルアプリケーション と同様です。
内蔵GNSSのデバイスファイル名は
/dev/gps
、GNSS Add-onドライバのデバイスファイル名は/dev/gps2
になります。GNSS デバイスファイル名 内蔵GNSS
/dev/gps
GNSS Add-on
/dev/gps2
まず初めに
/dev/gps2
のデバイスファイルをopen()
します。fd = open("/dev/gps2", O_RDONLY);
openしたドライバに対して
ioctl()
のCXD56_GNSS_IOCTL_START
コマンドにより測位を開始します。ret = ioctl(fd, CXD56_GNSS_IOCTL_START, CXD56_GNSS_STMOD_HOT); if (ret < 0) { printf("ERROR: start ret=%d, errno=%d\n", ret, errno); goto errout; }
周期的にあがってくる測位データを読み出す方法を以下に示します。
測位情報の通知を
poll()
によって待ち合わせてから、read()
を用いて測位データを読み出す、という動作を繰り返し行います。この通知の間隔は、後述する測位周期の設定に依存します。デフォルトでは、1秒に1回の間隔で通知がきます。 また、測位動作中であることを外部から監視できるように、toggle_led()
関数でメインボード上のLED3(GPIO_LED4)
を点滅させています。/* Wait for positioning data to be notified. */ ret = poll(fds, 1, -1); if (ret < 0) { printf("ERROR: poll ret=%d, errno=%d\n", ret, errno); break; } /* Read the positioning data. */ ret = read(fd, &posdat, sizeof(posdat)); if (ret != sizeof(posdat)) { printf("ERROR: read ret=%d, errno=%d\n", ret, errno); break; } toggle_led();
取得した測位データをシリアルターミナルへ出力するコードを以下に示します。
/* Print the positioning data. */ if (args.nmea) { print_nmea(&posdat); } else { print_posdat(&posdat, fp); }
NMEAフォーマットでの出力方法については後述します。 デフォルトでは、UTC時刻、緯度[度]、経度[度]、高度[m] 及び測位ステータス情報を表示しています。 測位ステータス表示の意味は次の通りです。
測位ステータス 状態 [N]
非測位状態
[A]
測位状態
[D]
測位状態かつDGPSによる補正が有効
指定した回数だけ測位が完了したら、
ioctl()
を用いて測位を停止 (CXD56_GNSS_IOCTL_STOP
) します。次回起動のためにバックアップデータを保存 (CXD56_GNSS_IOCTL_SAVE_BACKUP_DATA
) した後、GNSS Add-onボード上のデバイスをディープスリープモード (CXD56_GNSS_IOCTL_SLEEP
) に入れます。ディープスリープ状態にすることで、電源投入後のアイドル状態よりも消費電力を低減することができます。/* Stop GNSS, save the backup data and put it deep sleep mode * for power saving. */ ret = ioctl(fd, CXD56_GNSS_IOCTL_STOP, 0); if (ret < 0) { printf("ERROR: stop ret=%d, errno=%d\n", ret, errno); } ret = ioctl(fd, CXD56_GNSS_IOCTL_SAVE_BACKUP_DATA, 0); if (ret < 0) { printf("ERROR: save ret=%d, errno=%d\n", ret, errno); } ret = ioctl(fd, CXD56_GNSS_IOCTL_SLEEP, CXD56_GNSS_DEEPSLEEP); if (ret < 0) { printf("ERROR: sleep ret=%d, errno=%d\n", ret, errno); }
もし、ディープスリープモードからウェイクアップさせるときは、
ioctl()
のCXD56_GNSS_IOCTL_WAKEUP
コマンドを発行してください。本サンプルアプリケーションでopen()
直後にウェイクアップコマンドを発行していますが、これはgnss_addon
コマンドを繰り返し実行するときに、既にディープスリープモードにいるデバイスを起こすために行っています。このコマンドはデバイスが起床状態のときに発行しても特に問題ありません。/* Wakeup as GNSS may be in sleep mode. */ ret = ioctl(fd, CXD56_GNSS_IOCTL_WAKEUP, 0); if (ret < 0) { printf("ERROR: wakeup ret=%d, errno=%d\n", ret, errno); }
最後に、デバイスを
close()
します。/* Close a GNSS Add-on device driver. */ ret = close(fd); if (ret < 0) { printf("ERROR: close ret=%d, errno=%d\n", ret, errno); }
ここまでが測位を行うための基本シーケンスになります。これより先では、その他のオプション機能について説明します。
-
NMEA出力
NMEA形式で出力を行う場合は、
gnss_addon
コマンドの引数に-n
を追加してください。他の引数と組み合わせて使用することができます。nsh> gnss_addon -n [その他のオプション]
NMEAを出力するためのコードは
gnss_addon_nmea.c
に実装されています。 出力するNMEAセンテンスを限定したいときは、次のコードから不要なものを削除してください。/* Select NMEA sentence */ NMEA_SetMask2(NMEA_GGA_ON | NMEA_GLL_ON | NMEA_GSA_ON | NMEA_GSV_ON | NMEA_GNS_ON | NMEA_RMC_ON | NMEA_VTG_ON | NMEA_QZQSM_ON | NMEA_ZDA_ON);
-
みちびき災危通報出力
みちびき災危通報の出力を行う場合は、
gnss_addon
コマンドの引数に-n
と-q
を追加してください。他の引数と組み合わせて使用することができます。nsh> gnss_addon -n -q [その他のオプション]
みちびき災危通報を受信するとNMEA出力の中に
$QZQSM
センテンスが出力されます。みちびき災危通報を受信するためには、GNSS Add-on ボード上のファームウェアを v00.144 以降へ更新してください。
-
1PPS信号出力
1PPS信号を出力する場合は、
gnss_addon
コマンドの引数に-p
を指定してください。他の引数と組み合わせて使用することができます。nsh> gnss_addon -p [その他のオプション]
1PPS信号の出力を有効にするには、
ioctl()
のCXD56_GNSS_IOCTL_SET_1PPS_OUTPUT
コマンドを発行します。1PPS信号とは、UTC時刻に同期した1秒間隔のパルス信号になります。この信号は、GNSS Add-onボード上の
CL2
ランドから出力されます。その他に、ノーマウントの抵抗R16
をショートすることで GNSS Add-on ボード上のPIN_I2S0_DATA_OUT
ピンからも出力されます。詳しくは、ハードウェア設計資料 のGNSS Add-onボード回路図を参照してください。ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_1PPS_OUTPUT, 1); if (ret < 0) { printf("ERROR: 1pps ret=%d, errno=%d\n", ret, errno); }
1PPS信号を使った時刻同期方法も本サンプルコードに実装されています。本サンプルでは1PPS信号をGPIO割り込みとして受信しているので、そのまま利用するためには、1PPS信号と
PIN_I2S0_DATA_OUT
ピンを接続する必要があります。CL2
ランドとPIN_I2S0_DATA_OUT
ピンを外部で結線するか、もしくは、抵抗R16
をショートしてください。測位データの中に含まれている時刻情報は、デバイスが測位したタイミングとSpresenseが通知を受け取って読み出しを行うタイミングとのズレがあり、実時間から数100ミリ秒遅れた時刻になっています。より正確な時刻を知りたい場合は、1PPS信号を利用することができます。測位データに含まれる時刻情報から秒未満を切り捨てて +1秒した時刻ちょうどに、次の1PPS信号が通知されます。例えば、測位データ内の時刻が12時34分56秒だった場合、これは実時刻よりも遅れた時刻になっていますが、次にPPS信号から割り込みを受けたタイミングが実時刻の12時34分57秒ちょうどになります。
gnss_addon_pps.c
サンプルコードでは、測位データから+1秒した時刻を覚えておいて、1PPS信号を割り込みとして受けたタイミングでその時刻をRTCにセットしています。割り込みハンドラからスレッドへのディスパッチ時間、RTCへの書き込み時間、及び、RTCの時刻精度が32kHzなので、ある程度の誤差は含まれますが、測位データ内の時刻よりは正確な実時間をRTCへ設定することができます。また、デバッグ用途で1PPS信号を割り込みとして受信したタイミングでメインボードのLED2(GPIO_LED3)
を点滅させています。1PPS信号を割り込みとして正しく受け取れているかを確認することができます。 -
測位周期
gnss_addon
コマンドの引数に-c <周期msec>
を指定して測位周期を変更することができます。何も指定しなかった場合のデフォルト測位周期は1000msec(=1Hz)です。サポートしている周期は、100、125、200、250、500 もしくは 1000 の N 倍 (N≠0)です。サポート外の周期を設定した場合は、Invalid Parameter
のエラーになりコマンドの実行を終了します。例えば、500msec(=2Hz)に設定する場合は次のように実行します。
nsh> gnss_addon -c 500 [その他のオプション]
測位周期の設定は、
ioctl()
のCXD56_GNSS_IOCTL_SET_OPE_MODE
コマンドを使用します。struct cxd56_gnss_ope_mode_param_s opemode; opemode.mode = 1; opemode.cycle = args.cycle; ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_OPE_MODE, (uint32_t)&opemode); if (ret < 0) { printf("ERROR: cycle ret=%d, errno=%d\n", ret, errno); goto errout; }
-
ファイルロギング機能
gnss_addon
コマンドの引数に-o <ファイル名>
を指定することで、測位結果をシリアルに出力する代わりにファイルへ保存します。拡張ボードにSD カードを挿して、SDカード上のnmea.log
にログファイルを記録する場合は次のように実行します。nsh> gnss_addon -n -s 60 -o /mnt/sd0/nmea.log [その他のオプション]
SDカードへのファイルの保存は、スリープする直前にファイルを
fclose()
したタイミングで行われます。そのため、-s
オプションでスリープ時間を設定しておき、スリープしている間(測位中のLEDが点滅していないとき)にSDカードを引き抜くか電源を落とすことで、保存したファイルを安全に取り出すことができます。もし、NMEA出力をスリープ直前ではなく即時ファイルへの書き込みを行いたい場合は、
CONFIG_EXAMPLES_GNSS_ADDON_FSYNC_LOGGING
を有効にしてください。gnss_addon_nmea.c
のoutnmea()
関数内でfsync()
を発行することで毎回ファイルへの書き出しが行われます。ただし、このオプションを有効にした場合、SDカードへの書き込みに時間がかかること、及び、ファイル書き込み中に電源を落としてしまうリスクが高くなるので使い方には十分に注意してください。static int outnmea(char *buf) { int ret = fprintf(g_stream, "%s", buf); #ifdef CONFIG_EXAMPLES_GNSS_ADDON_FSYNC_LOGGING fsync(fileno(g_stream)); #endif return ret; }
-
RTCアラーム設定
-s
オプションによりスリープ時間が設定されているとき、alarm
コマンドを用いてRTCアラームを設定した後にシステムをスリープさせます。アプリケーションプログラム内からsystem()
関数を利用することでalarm
コマンドを実行しています。これを実現するために、configs/examples/gnss_addon/defconfig
コンフィグレーションファイルでは、CONFIG_EXAMPLES_ALARM=y
とCONFIG_SYSTEM_SYSTEM=y
を有効にしています。RTCアラーム設定をプログラム上で実装することもできますが、手軽に外部コマンドを実行する方法として参考にしてください。printf("RTC alarm after %d sec\n", args.sleep); snprintf(command, sizeof(command), "alarm %d", args.sleep); system(command); boardctl(BOARDIOC_POWEROFF, 0);
system()
関数でalarm
コマンドを発行した後に、boardctl()
関数を用いて、システム全体をディープスリープ状態へ遷移させています。ディープスリープ状態は、電源OFFに近しいレベルまで消費電力を削減します。ディープスリープ中にアラームタイマーが発火すると、システムはディープスリープ状態から起床して電源ON時と同じブートシーケンスで再び起動します。
プログラム内から
up_pm_get_bootcause()
関数を使って起動要因を取得することで、電源投入による起動なのか、ディープスリープからの起床なのかを判別することができます。/* Get the boot cause and executes different processes. * Specifically, if the system is started by RTC from DeepSleep state, * it injects the RTC time to GNSS and run GNSS hot start. */ bootcause = up_pm_get_bootcause();
本アプリケーションでは、この起動要因をみてディープスリープ状態からの起床だった場合は、以下のコードを実行します。
/* If the system is started by RTC from DeepSleep state, * set the RTC time to GNSS since the GNSS does not keep time. */ if (bootcause == PM_BOOT_DEEP_RTC) { struct cxd56_gnss_datetime_s datetime; get_datetime(&datetime); ret = ioctl(fd, CXD56_GNSS_IOCTL_SET_TIME, &datetime); if (ret < 0) { printf("ERROR: settime ret=%d, errno=%d\n", ret, errno); } }
ディープスリープ中でもRTC時刻は保持されています。スリープ前にRTCへ時刻を設定しているので、起床後に
get_datetime()
関数の中でRTCから現在時刻を取得します。現在時刻をioctl()
のCXD56_GNSS_IOCTL_SET_TIME
コマンドを用いてデバイスに対して時刻注入を行います。前回測位したときの位置やエフェメリス情報などはデバイス上のバックアップに保存されているので、ホットスタート測位が可能となり、測位がFIXするまでの時間(TTFF)を大幅に短縮できます。ただし、エフェメリスの有効期限切れ(通常3-4時間)や前回測位した位置から大きく離れた場所で測位した場合など、コールドスタート測位になりTTFFが長くなる可能性はありますのでご注意ください。
3.4.4. 補足
GNSS Add-onボード用ドライバのインターフェースは内蔵GNSSと互換性をもっています。
本章で説明した gnss_addon
サンプルアプリケーションの他に、既存のGNSSアプリケーションもGNSS Add-onボード上で簡単に動作させることができます。具体的には、コンフィグレーションを実行する際に、引数に feature/gnss_addon
を追加すれば GNSS Add-on ボード上で動作するようになります。各サンプルの詳しい説明は、それぞれのチュートリアルを参照してください。
サンプルアプリケーション | コンフィグレーション方法 |
---|---|
gnss |
$ tools/config.py feature/gnss_addon examples/gnss |
gnss_atcmd |
$ tools/config.py feature/gnss_addon examples/gnss_atcmd |
lte_lwm2m |
$ tools/config.py feature/gnss_addon examples/lte_lwm2m |
ambient_gnsslogger |
$ tools/config.py feature/gnss_addon examples/ambient_gnsslogger |
awsiot_gnsslogger |
$ tools/config.py feature/gnss_addon examples/wifi_awsiot_gnsslogger |
4. AudioLite チュートリアル
4.1. audiolite サンプルアプリケーション
この章では、Spresenseのaudioliteを用いたサンプルについて解説します。
このサンプルは、SDKv3.0.0から追加されたaudioliteの基本的な使い方をご理解いただくために用意しています。
4.1.1. audioliteについて
audioliteは、よりシンプルにSpreenseのAudio機能と利用するためのC++のライブラリです。 SDKv3.0.0では、既存のAudioが提供する一部機能が未対応になっており、次回以降のバージョンで対応予定です。 なお、排他利用にはなりますが、既存のAudioライブラリも今まで通り利用可能です。
4.1.2. サンプルコード
audioliteを用いたサンプルは、以下の3つになります。
-
audiolite_mp3player
-
audiolite_wavplayer
-
audiolite_wavrecorder
4.1.2.1. audiolite_mp3player
audioliteライブラリが提供する、audiolite_mp3decコンポーネントとaudiolite_outputcompコンポーネントを接続したシンプルなMP3プレーヤーのサンプルになります。
ソースコード概要
このサンプルでは以下の構造を作成して、引数で指定されたファイル名のMP3ファイルを再生し、曲が終了するとサンプルが終了します。
このコードではまず、audioliteから各種イベントを受け取るために、audiolite_eventlistenerを継承したmy_mp3listenerクラスを定義しています。システムが発行するイベントを受け取るには、audiolite_eventlistenerのon_event()メソッドをオーバーライドする必要があるため、自前のon_event()メソッドを追記しています。また、メンバ変数として、bool型のplayingを定義して、演奏終了イベントAL_EVENT_DECODEDONEを受信した際に、falseにすることで、演奏終了をアプリのメインスレッドに知らせるようにしています。
メインスレッドの中では、必要なインスタンスを生成して、上記構成に沿って各インスタンスの初期化を行います。
まず、コマンド引数で指定されたファイルのオープンを行います。
if (fstream->rfile(argv[1]) != OK)
audiolite_filestreammクラスのrfile()メソッドは読み出しモードでファイルを開きます。
audiolite_set_systemparam(48000, 16, 2)は、システムパラメータとして、サンプリング周波数、1サンプル当たりのビット長、チャネル数を設定しています。 このパラメータでオーディオジャックのDACに音声が出力されます。
audiolite_set_evtlistener(&lsn)は、冒頭で説明したmy_mp3listenerのインスタンスをシステムに登録し、イベントの受信をできるようにしています。
imempool→create_instance(4096, 8)では、ファイルから読み出したMP3のストリームを保持するメモリプールの初期化をしています。この例では、4096バイトのブロックを8枚保持するメモリープールを作成しています。
omempool→create_instance(4096, 16)は、MP3ファイルのデコード結果(PCMデータ)を格納するためのメモリープールを作成しています。4096バイトを16枚。
作成したメモリープールをMP3デコーダーインスタンスにセットしているのが下記のコードになります。
mp3->set_mempool(imempool); mp3->set_outputmempool(omempool);
デコーダーは、デコードするためのストリームを取得するaudiolite_streamを継承したクラスインスタンスを要求します。このサンプルではMP3をファイルから読み込んで実行するため、audiolite_filestreamクラスを用いています。 実際にaudiolite_streamをMP3デコーダーに設定しているのが以下のコードになります。
mp3->set_stream(fstream);
デコードしたデータをスピーカーに出力するために、出力を担う、audiolite_outputcompクラスのインスタンスとaudiolite_mp3decのインスタンスを接続するコードが、以下のコードになります。
mp3->bind(aoutdev);
以上で初期化が終了して、冒頭に記載した構成を構築することが出来たことになります。 あとは、my_mp3listenerのplayingメンバをtrueにして、終了時trueからfalseになった際にそれを検出できるように初期化を行ったのち、 audiolite_mp3decのstart()メソッドを呼ぶことで、指定されたファイルの再生を開始します。
ret = mp3->start();
ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/audiolite_mp3player
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/audiolite_mp3player make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
動作確認
再生したいMP3ファイルをSDカードに保存して、SpresenseのExtensionボードに挿入します。
シリアルターミナルを開いて、audiolite_mp3player コマンドを実行します。
nsh>プロンプトからaudiolite_mp3playerと入力し、その後ろにファイルパスを指定してEnterを押し、実行します。
nsh> audiolite_mp3player <mp3 ファイルパス>
仮に再生したいMP3ファイルが、SDカードにmusic.mp3として保存されている場合、
nsh> audiolite_mp3player /mnt/sd0/music.mp3
と実行します。 ファイル名が正しければ音楽がイヤホンジャックから流れます。
4.1.2.2. audiolite_wavplayer
audioliteライブラリが提供する、audiolite_wavdecコンポーネントとaudiolite_outputcompコンポーネントを接続したシンプルなWAVファイルプレーヤーのサンプルになります。
ソースコード概要
このサンプルでは以下の構造を作成して、引数で指定されたファイル名のWAVファイルを再生し、曲が終了するとサンプルが終了します。
ソースコードの構造は、audiolite_mp3playerとほぼ同一で、異なる点は、audiolite_mp3decをaudiolite_wavdecに置き換えた構造になります。 また、WAVファイルの場合、デコード処理が必要ないため、MemoryPoolはPCMデータを格納するために1つのみ利用しています。
このコードではまず、audioliteから各種イベントを受け取るために、audiolite_eventlistenerを継承したmy_wavlistenerクラスを定義しています。システムが発行するイベントを受け取るには、audiolite_eventlistenerのon_event()メソッドをオーバーライドする必要があるため、自前のon_event()メソッドを追記しています。また、メンバ変数として、bool型のplayingを定義して、演奏終了イベントAL_EVENT_DECODEDONEもしくはAudioDriverのDMA停止イベントAL_EVENT_STOPOUTPUTを受信した際に、falseにすることで、演奏終了をアプリのメインスレッドに知らせるようにしています。
メインスレッドの中では、必要なインスタンスを生成して、上記構成に沿って各インスタンスの初期化を行います。
まず、コマンド引数で指定されたファイルのオープンを行います。
if (fstream->rfile(argv[1]) != OK)
audiolite_filestreammクラスのrfile()メソッドは読み出しモードでファイルを開きます。
audiolite_set_systemparam(48000, 16, 2)は、システムパラメータとして、サンプリング周波数、1サンプル当たりのビット長、チャネル数を設定しています。 このパラメータでオーディオジャックのDACに音声が出力されます。
audiolite_set_evtlistener(&lsn)は、冒頭で説明したmy_wavlistenerのインスタンスをシステムに登録し、イベントの受信をできるようにしています。
mempool→create_instance(4096, 8)では、ファイルから読み出したPCMデータを保持するメモリプールの初期化をしています。この例では、4096バイトのブロックを8枚保持するメモリープールを作成しています。
作成したメモリープールをWAVデコーダーインスタンスにセットしているのが下記のコードになります。
wavdec->set_mempool(mempool);
デコーダーは、デコードするためのストリームを取得するaudiolite_streamを継承したクラスインスタンスを要求します。このサンプルではWAVをファイルから読み込みを行うため、audiolite_filestreamクラスを用いています。 実際にaudiolite_streamをWAVデコーダーに設定しているのが以下のコードになります。
wavdec->set_stream(fstream);
デコードしたデータをスピーカーに出力するために、出力を担う、audiolite_outputcompクラスのインスタンスとaudiolite_mp3decのインスタンスを接続するコードが、以下のコードになります。
wavdec->bind(aoutdev);
以上で初期化が終了して、冒頭に記載した構成を構築することが出来たことになります。 あとは、my_wavlistenerのplayingメンバをtrueにして、終了時trueからfalseになった際にそれを検出できるように初期化を行ったのち、 audiolite_wavdecのstart()メソッドを呼ぶことで、指定されたファイルの再生を開始します。
ret = wavdec->start();
ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/audiolite_wavplayer
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/audiolite_wavplayer make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
動作確認
再生したいWAVファイルをSDカードに保存して、SpresenseのExtensionボードに挿入します。
シリアルターミナルを開いて、audiolite_wavplayer コマンドを実行します。
nsh>プロンプトからaudiolite_wavplayerと入力し、その後ろにファイルパスを指定してEnterを押し、実行します。
nsh> audiolite_wavplayer <wav ファイルパス>
仮に再生したいWAVファイルが、SDカードにmusic.wavとして保存されている場合、
nsh> audiolite_wavplayer /mnt/sd0/music.wav
と実行します。 ファイル名が正しければ音楽がイヤホンジャックから流れます。
4.1.2.3. audiolite_wavrecorder
audioliteライブラリが提供する、audiolite_wavencコンポーネントとaudiolite_inputcompコンポーネントを接続したシンプルなWAVファイルレコーダーのサンプルになります。 また、ユーザーが独自のコンポーネントを実装して信号処理を行うことを想定した、audiolite_componentを継承したmy_interceptorクラスを定義し、audiolite_inputcompとaudiolite_wavencの間に挟むことで、audiolite_inputcompが送ってきているPCMデータをコンソールに出力しながらWAVファイルのレコーディングを行います。
ソースコード概要
このサンプルでは以下の構造を作成して、引数で指定されたファイル名のプレフィックスをベースに10秒間の録音を行います。
このコードではまず、イベントを取得用に、audiolite_eventlistenerを継承したmy_wavlistenerクラスを定義しています。受け取るイベントによって動作を変えることが無いため、on_event()では、単に受け取ったイベントの表示のみを行っています。
次に、流れるAudioPCMデータを受け取って表示するために、audiolite_componentを継承したmy_interceptorクラスを定義しています。 audiolite_componentのon_data()メソッドを継承することで、流れてきたデータが到達した際に、my_interceotpr::on_data()メソッドが呼ばれてデータを受け取ることが出来ます。
class my_interceptor : public audiolite_component { public: void on_data() { .... } }
on_data()の中では、到達したデータを受け取るためにaudiolite_inputnodeのインスタンス配列の0番目から、pop_data()メソッドを使ってaudiolite_memのインスタンスを取得しています。メモリプールとしてaudiolite_mempoolapbufを使っているため、audiolite_memを継承したaudiolite_memapbufにキャストして受け取ります。
audiolite_memapbuf *mem = (audiolite_memapbuf *)_ins[0]->pop_data(NULL);
受け取ったaudiolite_memから実際のデータにアクセスするには、audiolite_memのget_data()メソッドでデータが格納されているメモリのポインタを取得します。
int16_t *data = (int16_t *)mem->get_data();
後に設定するシステムパラメータで16bit / 2chのサンプルを指定しているため、データは、16bit毎に以下のように並びます。 Ch1, Ch2, Ch1, Ch2,….. このサンプルでは、データの末尾4サンプル分のCh1とCh2のデータを表示しています。
printf("DL %d : %d\n", samples, data[(samples - 4) * 2]); printf("DL %d : %d\n", samples, data[(samples - 3) * 2]); printf("DL %d : %d\n", samples, data[(samples - 2) * 2]); printf("DL %d : %d\n", samples, data[(samples - 1) * 2]); printf("DR %d : %d\n", samples, data[(samples - 4) * 2 + 1]); printf("DR %d : %d\n", samples, data[(samples - 3) * 2 + 1]); printf("DR %d : %d\n", samples, data[(samples - 2) * 2 + 1]); printf("DR %d : %d\n", samples, data[(samples - 1) * 2 + 1]);
取得したメモリは後段のコンポーネントに送るため、audiolite_outputnodeクラスのインスタンス配列の_outs[0]に対してpush_data()メソッドを呼び出します。
_outs[0]->push_data(mem);
最後に自身のメモリの利用が終わったため、そのメモリを解放します。
mem->release();
メインタスクは、まず上述の構造を作成するためのクラスインスタンスを作成しています。
audiolite_set_systemparam(48000, 16, 2)は、システムパラメータとして、サンプリング周波数、1サンプル当たりのビット長、チャネル数を設定しています。 このパラメータでマイクから音がADCされます。
audiolite_set_evtlistener(&lsn)は、冒頭で説明したmy_wavlistenerのインスタンスをシステムに登録し、イベントの受信をできるようにしています。
mempool→create_instance(4096, 16)では、ファイルから読み出したPCMデータを保持するメモリプールの初期化をしています。この例では、4096バイトのブロックを16枚保持するメモリープールを作成しています。SDカードへの書き込みの遅延でOverflowが起きる場合、このサイズを調整することで改善が期待できます。
続いてWAVエンコーダーに出力先として、audiolite_filestreamを設定します。
wavenc->set_stream(fstream);
ファイルのオープン等はwavencが直接行うため、ユーザー側のコードでは、filestreamを設定するのみになります。
wavencはWAVのサイズによってファイルを分割する機能を持っています。 そのため、ファイルのプレフィックスのみを設定します。ファイルのプレフィックスはコマンドラインオプションとして指定する仕様になるため、argv[1]をセットします。
wavenc->set_fileprefix(argv[1]);
そして、データの生成元である、aduiolite_inputcompに対して、作成したメモリプールを設定します。
aindev->set_mempool(mempool);
最後に、使用するコンポネントaudiolite_inputcomp、my_intercepter、audiolite_wavencを接続します。
aindev->bind(intercept); intercept->bind(wavenc);
これで準備は完了です。 データの生成元であるaudiolite_inputcompコンポーネントに対してstart()メソッドを呼び、録音を開始します。
ret = aindev->start();
あとは録音時間(このアプリでは10秒)経過するのを待ち、stop()メソッドで録音を停止します。
aindev->stop();
ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/audiolite_wavrecorder
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/audiolite_wavrecorder make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
動作確認
シリアルターミナルを開いて、audiolite_wavrecorder コマンドを実行します。
nsh>プロンプトからaudiolite_wavrecorderと入力し、その後ろに保存するファイルのプレフィックスを入力してEnterを押して実行します。
nsh> audiolite_wavrecorder <wav ファイルのプレフィックス>
仮に保存先のファイル名を、SDカード上のrec_00.wavとして保存したい場合、
nsh> audiolite_wavrecorder /mnt/sd0/rec
と実行します。 ファイル名の後ろの_00.wavは、wavencが自動的に付加します。 正しく実行できれば、my_interceptorによりPCMデータを表示しながら、WAVファイルが保存されます。 保存されたWAVファイルは、audiolite_wavplayerを用いて再生することが出来ます。
5. Audio チュートリアル
5.1. Audio Player サンプルアプリケーション
Audio Player サンプルアプリケーションの動作について説明します。
5.1.1. ビルド&ロード手順
ここではコマンドラインによるビルド手順を示します。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/audio_player
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/audio_player make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
-
Audio Playerの場合、デコード処理を行うDSPバイナリのロードが必要です。 DSPバイナリの置き場所は、SDカードか、SPI-Flashのどちらかを選択できますが、 ここでは、SDカードからロードする方法を行います。
DSPバイナリのパスの指定は、アプリケーションコード(audio_player_main.cxx)内で指定します。
audio_player_main.cxx
ではDSPBIN_FILE_PATH
で指定しています。#define DSPBIN_FILE_PATH "/mnt/sd0/BIN"
であれば、SDカードが指定されています。
SPI-flashにしたい場合は、"/mnt/spif/BIN" を指定してください。 この "/mnt/sd0/BIN" は、SDカードをPCで読み込んだ時の、ルートディレクトリの下の
BIN/
です。
このディレクトリを作成し、ここに必要なコーデックのDSPを置きます。MP3を再生(デコード)する場合は、
spresense/sdk/modules/audio/dsp/
の下のMP3DEC
を選択してください。 -
同時に、再生したい音楽ファイルをSDカードに書き込みます。 audio_player_main.cxx では、
PLAYBACK_FILE_PATH
で指定しています。#define PLAYBACK_FILE_PATH "/mnt/sd0/AUDIO"
このため、SDカードをPC上で読み込んだ時に、ルートディレクトリの下の
AUDIO/
以下に、 再生したいオーディオファイルを置いて下さい。サブディレクトリに置くこともできます。 -
現在のAudio Playerサンプルでは、簡易PlayListを利用した再生を行っています。 このため、playlistファイルの置き場所とファイル名を指定して再生します。
audio_player_main.cxx
では、PLAYLIST_FILE_PATH
でパスを指定、PLAYLIST_FILE_NAME
でファイル名を指定しています。#define PLAYLIST_FILE_PATH "/mnt/sd0/PLAYLIST" #define PLAYLIST_FILE_NAME "TRACK_DB.CSV"
このため、SDカードをPC上で読み込んだ時の、ルートディレクトリの下の
PLAYLIST/
以下に、TRACK_DB.CSV
というファイルを作成してください。TRACK_DB.CSV
の中身は、spresense/sdk/modules/audio/playlist/
の下のREADME.txt
を参照してください。
これらすべてを用意することで、音楽再生が行えます。
5.1.2. Audio Playerの動作確認
この nuttx.spk
を実機へロードするとAudio Playerのプログラムが実行されます。
Helloサンプルと同様に、シリアルターミナルを開きます。
minicom -D /dev/ttyUSB0 -b 115200 -s
builtinされている、 audio_player
アプリを実行すると、
というログが表示され、音声が再生されます。
エラーが発生した場合は、オーディオサブシステムのエラーについて を参照してください。
5.1.3. 付録: 独自の信号処理を行う
これまでのチュートリアルで、オーディオプレーヤーとして十分な機能を実現することができました。 ここからは、より高度な処理を行う方法を説明していきます。 |
AudioPlayerでは、再生する音声に対してユーザー独自の信号処理を行うことが出来ます。
これを行いたい場合にはコンフィグメニューで [Use Postprocess]
を有効にする必要があります。
-
Postprocessを有効にします
tools/cofig.py -m
[Use Postprocess]
にチェックを入れます。[Examples] [Audio player example] [Use Postprocess] <= Y
Postrocessの詳細についてはSDKデベロッパーガイドの Set preprocess を参照して下さい。 -
ビルドを行います。
make
全ての手順がうまくいけば、
POSTPROC
バイナリがspresense/examples/audio_player/worker/
の下に作成されます。
これをSDカードの/mnt/sd0/BIN
(PCから見るとBIN/
)フォルダに置いてください。本サンプルアプリケーションでは、 POSTPROC
には簡単なRCfilterがデフォルトで組み込まれています。
独自の信号処理などにカスタムをしたい場合には こちら を参考にして下さい。[Use Postprocess]
の有効、無効で音声ファイルを再生し違いを確認してみてください。
再生方法はこちら を参考にして下さい。
5.1.4. DSPバイナリ(POSTPROC)のカスタムについて
DSPバイナリ(POSTPROC)のカスタム方法について記載します。
5.1.4.1. Step1. POSTPROCのコード編集
POSTPROCのコード構成と編集箇所について説明します。
コードは、ユーザー編集すべき部分とフレームワークとして提供される部分の2つに分かれます。
ユーザーが編集するコード
ユーザーが主に編集すべきコードです。
これらのコードを編集してDSPで信号処理を記述することが出来ます。
worker
ディレクトリの中にDSPのコードがまとまっており、その中に userproc
ディレクトリがあります。
ユーザが信号処理などを書くのは userproc
ディレクトリ内のみで、その他は基本的に変更の必要はありません。
main.cpp
には、起動処理~MainCPUとのデータ通信制御が書かれていますので変更しないで下さい。
起動処理やDSP通信処理などが書かれています。編集の必要は有りません。
DSPとの通信コマンドを定義するヘッダファイルです。
必要なパラメータはこのファイルに記載します。
ユーザーコードのヘッダファイルです。
ユーザーコード本体です。
このファイルに信号処理などを書く、または呼び出します。
ユーザーコードに用意されるインタフェース
userproc.cpp
には、 Init
, Exec
, Flush
, Set
コマンドの枠組みが用意されており
ユーザーコードはそれぞれに対応する中身を書いていくことでDSP内での処理を実現することが出来ます。
ユーザーが記述すべき処理について説明します。
(※デフォルトではサンプルとしてRCフィルタが組み込まれています。)
コマンドによるDSP内部の状態遷移は下図の通り行われます。
各コマンドを使い以下のような流れで処理を行います。
-
AUDCMD_INIT_OUTPUTMIXERがコールされるとDSPが起動します。
-
Init
コマンドで必要なパラメータ(ch数やビット長など)を設定します。 -
再生開始するとキャプチャした音声データが
Exec
コマンドで定期的にDSPに送られるので所望のフィルタ処理をしてください。 -
任意のタイミングでDSP内部のパラメータなどを変更したい場合には、
Set
コマンドを送ることで実装することを想定しています。このコマンドの実行タイミングは、Exec
を含めた受信順になります。+ -
再生停止すると最後の音声データの
Exec
の後、Flush
コマンドが送られるので終端処理の必要がある場合はここで処理をします。
各機能で使用するデータ型は userproc_command.h
に書かれており、中身は自由に書き換えることが出来ます。
各コマンドのフォーマットは下図の様になっています。
先頭の白抜きの部分には最低限必要なパラメータが固定で配置されています。これらは変更しないで下さい。
ユーザーが userproc_command.h
で定義するパラメータは下図の User param
(ピンク色箇所)にあたる部分です。
各コマンドについて説明します。
struct InitParam : public CustomprocCommand::CmdBase
-
Init処理用のパラメータです。
デフォルトではすべてreserveとなっていますが、ch数やビット長など、必要なパラメータに変更してください。
struct ExecParam : public CustomprocCommand::CmdBase
-
Exec処理用のパラメータです。
音声データのアドレス・サイズは上図のExecParam
にある様に継承元のCustomprocCommand::ExecParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct FlushParam : public CustomprocCommand::CmdBase
-
Flush処理用のパラメータです。
音声データのアドレス・サイズは上図のExecParam
にある様に継承元のCustomprocCommand::FlushParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct SetParam : public CustomprocCommand::CmdBase
-
Set処理用のパラメータです。
様々な動的に変更したいパラメータを定義します。デフォルトではRCフィルタのOn/Offや係数を定義しています。
下記の関数群は userproc.cpp
に書かれています。中身は自由に書き換えることが出来ます。
それぞれのコマンド定義に従い処理を行います。
void UserProc::init(InitParam *)
-
InitParamに従い初期化を行う処理を書いて下さい。
アプリケーションコードからの AUDCMD_INITMPP コマンドで実行されます。
(デフォルトでは何もしていません。)
void UserProc::exec(ExecParam *)
-
ExecParamに従い信号処理を書いて下さい。
再生を開始するとSDK内部から定期的に呼ばれます。
1フレームはLPCMの場合には640サンプル、MP3の場合には1152(ただし16kHz時は1728)サンプルです。
入力データアドレスからデータを取得し、信号処理を行い、出力データアドレスへ書き出して下さい。
(デフォルトではRCフィルタ処理が書かれています。)
void UserProc::flush(FlushParam *)
-
FlushParamに従いFlush(終端)処理を書いて下さい。
再生の停止時にSDK内部から一度だけ呼ばれます。
IIRやFIRフィルタのように遅延が発生する場合は、最終フレームの後にflush
を行い、遅延分の出力を行います。
出力すべきデータがある場合には、出力データアドレスへ書き出して下さい。
(デフォルトでは何もしていません。)
void UserProc::set(SetParam *)
-
SetParamに従い設定処理を書いてください。
アプリケーションコードからの AUDCMD_SETMPPPARAM コマンドで実行されます。
(デフォルトではRCフィルタの係数を設定しています。)
5.1.4.2. Step2. POSTPROC
バイナリのビルド
Configuration で User Postprocess
を有効にしていれば、本アプリケーションのビルド時に自動で POSTPROC
バイナリが作成されます。
作成されるパスは spresense/examples/audio_player/worker/
の下の POSTPROC
です。
これをSDカードの /mnt/sd0/BIN
(PCから見ると \BIN
)フォルダに置いてください。
5.2. Audio Recorder サンプルアプリケーション
Audio Recorderのサンプルアプリケーションの動作について説明します。
5.2.1. ビルド&ロード手順
ここではコマンドラインによるビルド手順を示します。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/audio_recorder
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/audio_recorder make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
-
Audio Recorderの場合、エンコード処理を行うDSPバイナリのロードが必要です。 DSPバイナリの置き場所は、SDカードか、SPI-Flashのどちらかを選択できますが、 ここでは、SDカードからロードする方法を行います。
DSPバイナリのパスの指定は、アプリケーションコード内で指定します。
audio_recorder_main.cxx
では、DSPBIN_PATH
で設定していますので必要に応じてアプリケーションコードを変更して下さい。#define DSPBIN_PATH "/mnt/sd0/BIN"
であれば、SDカードが指定されています。
この
/mnt/sd0/BIN
は、SDカードをPCで読み込んだ時の、ルートディレクトリの下のBIN/
です。
このディレクトリを作成し、ここに必要なコーデックのDSPを置きます。SPI-flashにしたい場合は、 /mnt/spif/BIN
を指定してください。MP3で録音(エンコード)する場合は、
spresense/sdk/modules/audio/dsp/
の下のMP3ENC
を選択してください。その他のエンコードをする場合のCodec種別とDSPバイナリの組み合わせは下表の通りです。
Codec DSPバイナリ MP3
MP3ENC
LPCM
SRC
5.2.2. Audio Recorderの動作確認
この nuttx.spk
をSpresenseへロードするとAudio Recorderのプログラムが実行されます。
Helloサンプルと同様に、シリアルターミナルを開きます。
minicom -D /dev/ttyUSB0 -b 115200 -s
builtinされている、 audio_recorder
アプリを実行すると、
というログが表示され、音声が記録されます。
記録された音声はPCで再生することが出来ます。その際にはSDカードルートディレクトリの下の REC/
に音声ファイルがあります。
audio_recorder_main.cxx では、 RECFILE_ROOTPATH
で設定していますので必要に応じてアプリケーションコードを変更して下さい。
#define RECFILE_ROOTPATH "/mnt/sd0/REC"
であればSDカードのルートの下の REC/
に音声ファイルが作られます。
エラーが発生した場合は、オーディオサブシステムのエラーについて を参照してください。
5.2.3. 付録: 独自の信号処理を行う
これまでのチュートリアルで、レコーダーとして十分な機能を実現することができました。 ここからは、より高度な処理を行う方法を説明していきます。 |
AudioRecorderでは記録する音声に対してユーザー独自の信号処理を行うことが出来ます。
これを行いたい場合にはコンフィグメニューで [Use preprocess]
を有効にする必要があります。
-
Preprocessを有効にします
コンフィグメニューを開きます。
tools/cofig.py -m
[Use preprocess]
にチェックを入れます。[Examples] [Audio recorder example] [Use preprocess] <= Y
Preprocessの詳細についてはSDKデベロッパーガイドの Set preprocess を参照して下さい。 -
ビルドを行います。
make
全ての手順がうまくいけば、
PREPROC
バイナリがspresense/examples/audio_recorder/worker/
の下に作成されます。
これをSDカードの/mnt/sd0/BIN
(PCから見るとBIN/
)フォルダに置いてください。本サンプルアプリケーションでは、 PREPROC
には簡単なRCfilterがデフォルトで組み込まれています。
独自の信号処理などにカスタムをしたい場合には こちら を参考にして下さい。Preprocessの有効、無効で記録した音声ファイルを再生して、違いを確認してみてください。
記録、再生方法はこちら を参考にして下さい。== DSPバイナリ(PREPROC)のカスタムについて
DSPバイナリ(PREPROC)のカスタム方法について記載します。
5.2.3.1. Step1. PREPROCのコード編集
PREPROCのコード構成と編集箇所について説明します。
コードは、ユーザー編集すべき部分とフレームワークとして提供される部分の2つに分かれます。
ユーザーが編集するコード
ユーザーが主に編集すべきコードです。
これらのコードを編集してDSPで信号処理を記述することが出来ます。
worker
ディレクトリの中にDSPのコードがまとまっており、その中に userproc
ディレクトリがあります。
ユーザが信号処理などを書くのは userproc
ディレクトリ内のみで、その他は基本的に変更の必要はありません。
main.cpp
には、起動処理~MainCPUとのデータ通信制御が書かれていますので変更しないで下さい。
起動処理やDSP通信処理などが書かれています。編集の必要は有りません。
DSPとの通信コマンドを定義するヘッダファイルです。
必要なパラメータはこのファイルに記載します。
ユーザーコードのヘッダファイルです。
ユーザーコード本体です。
このファイルに信号処理などを書く、または呼び出します。
ユーザーコードに用意されるインタフェース
userproc.cpp
には、 Init
, Exec
, Flush
, Set
コマンドの枠組みが用意されており
ユーザーコードはそれぞれに対応する中身を書いていくことでDSP内での処理を実現することが出来ます。
ユーザーが記述すべき処理について説明します。
(※デフォルトではサンプルとしてRCフィルタが組み込まれています。)
コマンドによるDSP内部の状態遷移は下図の通り行われます。
各コマンドを使い以下のような流れで処理を行います。
-
AUDCMD_INIT_MICFRONTENDがコールされるとDSPが起動します。
-
Init
コマンドで必要なパラメータ(ch数やビット長など)を設定します。 -
記録開始するとキャプチャした音声データが
Exec
コマンドで定期的にDSPに送られるので所望のフィルタ処理をしてください。 -
任意のタイミングでDSP内部のパラメータなどを変更したい場合には、
Set
コマンドを送ることで実装することを想定しています。このコマンドの実行タイミングは、Exec
を含めた受信順になります。+ -
記録停止すると最後の音声データの
Exec
の後、Flush
コマンドが送られるので終端処理の必要がある場合はここで処理をします。
各機能で使用するデータ型は userproc_command.h
に書かれており、中身は自由に書き換えることが出来ます。
各コマンドのフォーマットは下図の様になっています。
先頭の白抜きの部分には最低限必要なパラメータが固定で配置されています。これらは変更しないで下さい。
ユーザーが userproc_command.h
で定義するパラメータは下図の User param
(ピンク色箇所)にあたる部分です。
各コマンドについて説明します。
struct InitParam : public CustomprocCommand::CmdBase
-
Init処理用のパラメータです。
デフォルトではすべてreserveとなっていますが、ch数やビット長など、必要なパラメータに変更してください。
struct ExecParam : public CustomprocCommand::CmdBase
-
Exec処理用のパラメータです。
音声データのアドレス・サイズは上図のExecParam
にある様に継承元のCustomprocCommand::ExecParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct FlushParam : public CustomprocCommand::CmdBase
-
Flush処理用のパラメータです。
音声データのアドレス・サイズは上図のExecParam
にある様に継承元のCustomprocCommand::FlushParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct SetParam : public CustomprocCommand::CmdBase
-
Set処理用のパラメータです。
様々な動的に変更したいパラメータを定義します。デフォルトではRCフィルタのOn/Offや係数を定義しています。
下記の関数群は userproc.cpp
に書かれています。中身は自由に書き換えることが出来ます。
それぞれのコマンド定義に従い処理を行います。
void UserProc::init(InitParam *)
-
InitParamに従い初期化を行う処理を書いて下さい。
アプリケーションコードからの AUDCMD_INIT_PREPROCESS_DSP コマンドで実行されます。
(デフォルトでは何もしていません。)
void UserProc::exec(ExecParam *)
-
ExecParamに従い信号処理を書いて下さい。
記録を開始するとSDK内部から定期的に呼ばれます。
1フレームは記録の設定がLPCMの場合には768サンプル、MP3の場合には1152(ただし16kHz時は1728)サンプルです。
入力データアドレスからデータを取得し、信号処理を行い、出力データアドレスへ書き出して下さい。
(デフォルトではRCフィルタ処理が書かれています。)
void UserProc::flush(FlushParam *)
-
FlushParamに従いFlush(終端)処理を書いて下さい。
記録の停止時にSDK内部から一度だけ呼ばれます。
IIRやFIRフィルタのように遅延が発生する場合は、最終フレームの後にflush
を行い、遅延分の出力を行います。
出力すべきデータがある場合には、出力データアドレスへ書き出して下さい。
(デフォルトでは何もしていません。)
void UserProc::set(SetParam *)
-
SetParamに従い設定処理を書いてください。
アプリケーションコードからの AUDCMD_SET_PREPROCESS_DSP コマンドで実行されます。
(デフォルトではRCフィルタの係数を設定しています。)
5.2.3.2. Step2. PREPROC
バイナリのビルド
Configuration で Preprocess
を有効にしていれば、本アプリケーションのビルド時に自動で PREPROC
バイナリが作成されます。
作成されるパスは spresense/examples/audio_recorder/worker/
の下の PREPROC
です。
これをSDカードの /mnt/sd0/BIN
(PCから見ると \BIN
)フォルダに置いてください。
5.3. Audio Recognizer サンプルアプリケーション
Audio Recognizer サンプルアプリケーションの動作について説明します。
5.3.1. ビルド&ロード手順
ここではコマンドラインによるビルド手順を示します。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/audio_recognizer
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/audio_recognizer make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
-
Audio Recognizerの場合、音声認識処理を行うDSPバイナリのロードが必要です。 DSPバイナリの置き場所は、SDカードかSPI-Flashのどちらかを選択できますが、 ここでは、SDカードからロードする方法を行いますので、 "/mnt/sd0/BIN" に置きます。
この
/mnt/sd0/BIN
は、SDカードをPCで読み込んだ時の、ルートディレクトリの下のBIN/
です。
このディレクトリを作成し、ここに音声認識に必要なDSPを置きます。本サンプルアプリケーションでは、音声認識のDSPバイナリは、ユーザーカスタムのものを使用する設定となっており、バイナリは spresense/examples/audio_recognizer/worker_recognizer/
の下にRCGPROC
として生成されます。認識処理をカスタムする場合には、RecognizerPROCのカスタムについてを参照してください。
5.3.2. Audio Recognizerの動作確認
ビルドした nuttx.spk
を実機へロードするとAudio Recognizerのプログラムが実行されます。
Helloサンプルと同様に、シリアルターミナルを開きます。
minicom -D /dev/ttyUSB0 -b 115200 -s
builtinされている、 audio_recognizer
アプリを実行すると、
というログが表示され、音声認識が開始されます。
認識結果はアプリケーションコード( audio_recognizer_main.cpp
)中にあるコールバック関数で受け取っています。
受け取るパラメータの構成は音声認識用DSPで決めています。 RecognizerPROC を参照して下さい。
データはMemoryHandleで受信していますので、下記の様に、そのアドレスを参照することでデータを取得することが出来ます。
static void recognizer_find_callback(AsRecognitionInfo info)
{
/* Get Recognition result */
MyRecognizerResultFormat *result =
static_cast<MyRecognizerResultFormat *>(info.getVa())
/* Print result */
...
printf("Data size %d byte\n", info.size);
printf("Data1 : %x, Data2 : %x\n", result->data1, result->data2);
...
}
エラーが発生した場合は、オーディオサブシステムのエラーについて を参照してください。
5.3.3. 付録: 独自の信号処理を行う
これまでのチュートリアルで、Recognizerとして十分な機能を実現することができました。 ここからは、より高度な処理を行う方法を説明していきます。 |
キャプチャした音声はサンプリング周波数が48kHzまたは192kHz、ビット長が16bitまたは32bitです。
Audio Recognizerではこれに対して、認識ライブラリの入力フォーマットに合わせ前処理を行うことが出来ます。
これを行いたい場合にはコンフィグメニューで [Use preprocess]
を有効にする必要があります。
-
Preprocessを有効にします
コンフィグメニューを開きます。
tools/cofig.py -m
[Use preprocess]
にチェックを入れます。[Examples] [Audio recognizer example] [Use preprocess] <= Y
Preprocessの詳細についてはSDKデベロッパーガイドの Set preprocess を参照して下さい。 -
ビルドを行います。
make
全ての手順がうまくいけば、
PREPROC
バイナリがspresense/examples/audio_recognizer/worker_preprocess/
の下に作成されます。
これをSDカードの/mnt/sd0/BIN
(PCから見るとBIN/
)フォルダに置いてください。本サンプルアプリケーションでは、 PREPROC
には簡単なRCfilterがデフォルトで組み込まれています。
独自の信号処理などにカスタムをしたい場合には こちら を参考にして下さい。
5.3.4. DSPバイナリのカスタムについて
audio_recognizerサンプルではPre処理用(以下 PREPROC
)、認識処理用(以下 RCGPROC
)の2つのDSPバイナリを使用します。
それらのカスタム方法について説明します。
5.3.4.1. Step1. PREPROC, RCGPROCのコード編集
PREPROC
, RCGPROC
のコード構成と編集箇所について説明します。
コードは、ユーザー編集すべき部分とフレームワークとして提供される部分の2つに分かれます。
ユーザーが編集するコード
ユーザーが主に編集すべきコードです。
これらのコードを編集してDSPで信号処理や認識処理を記述することが出来ます。
PREPROC
は worker_preprocess
ディレクトリの中に、 RCGPROC
は worker_recognizer
の中にDSPのコードがまとまっており、それぞれその中に userproc
ディレクトリがあります。
ユーザが信号・認識処理などを書くのは userproc
ディレクトリ内のみで、その他は基本的に変更の必要はありません。
main.cpp
には、起動処理~MainCPU(Supervisor)とのデータ通信制御が書かれていますので変更しないで下さい。
起動処理やDSP通信処理などが書かれています。編集の必要は有りません。
Pre処理用DSPとの通信コマンドを定義するヘッダファイルです。
必要なパラメータはこのファイルに記載します。
Pre処理用DSPのユーザーコードのヘッダファイルです。
Pre処理用DSPのユーザーコード本体です。
このファイルに信号処理などを書く、または呼び出します。
認識用DSPとの通信コマンドを定義するヘッダファイルです。
必要なパラメータはこのファイルに記載します。
認識用DSPのユーザーコードのヘッダファイルです。
認識用DSPのユーザーコード本体です。
このファイルに認識処理を書く、または呼び出します。
ユーザーコードに用意されるインタフェース
Init
, Exec
, Flush
, Set
コマンドの枠組みが用意されており
ユーザーコードはそれぞれに対応する中身を書いていくことでDSP内での処理を実現することが出来ます。
ユーザーが記述すべき処理について説明します。
(※デフォルトではサンプルとして PREPROC
にはRCフィルタが組み込まれています。)
コマンドによるDSP内部の状態遷移は下図の通り行われます。
各コマンドを使い以下のような流れで処理を行います。
-
AUDCMD_INIT_RECOGNIZERがコールされると認識用DSPが起動します。
-
Init
コマンドで必要なパラメータ(ch数やビット長など)を設定します。 -
認識処理を開始するとキャプチャした音声データが
Exec
コマンドで定期的にDSPに送られるので所望の認識処理をしてください。 -
任意のタイミングでDSP内部のパラメータなどを変更したい場合には、
Set
コマンドを送ることで実装することを想定しています。このコマンドの実行タイミングは、Exec
を含めた受信順になります。+ -
認識処理を停止すると最後の音声データの
Exec
の後、Flush
コマンドが送られるので終端処理の必要がある場合はここで処理をします。
各機能で使用するデータ型は、 PREPROC
では userproc_command.h
に、 RCGPROC
では rcgproc_command.h
に書かれており、中身は自由に書き換えることが出来ます。
各コマンドのフォーマットは下図の様になっており、これは PREPROC
RCGPROC
で同じです。
先頭の白抜きの部分には最低限必要なパラメータが固定で配置されています。これらは変更しないで下さい。
ユーザーが userproc_command.h
で定義するパラメータは下図の User param
(ピンク色箇所)にあたる部分です。
notification
は Exec
コマンドの応答(認識結果)フラグで、0以外の指定でアプリケーションまで応答を戻します。
例えば、通常は応答を戻さず認識結果の変化点(認識無し→有りになった点)などでのみ応答したい場合などに使用出来ます。
各コマンドについて説明します。
struct InitRcgParam : public CustomprocCommand::CmdBase
-
Init処理用のパラメータです。
デフォルトではch数とビット幅が設定されています。必要なパラメータに変更してください。
struct ExecRcgParam : public CustomprocCommand::CmdBase
-
Exec処理用のパラメータです。
音声データのアドレス・サイズは上図のExecParam
にある様に継承元のCustomprocCommand::ExecParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct FlushRcgParam : public CustomprocCommand::CmdBase
-
Flush処理用のパラメータです。
音声データのアドレス・サイズは上図のFlushParam
にある様に継承元のCustomprocCommand::FlushParamBase
に定義されています。
詳細は/sdk/modules/include/audio/dsp_framework/customproc_command_base.h
を参照してください。
struct SetRcgParam : public CustomprocCommand::CmdBase
-
Set処理用のパラメータです。
様々な動的に変更したいパラメータを定義します。デフォルトでは認識処理のOn/Offを定義しています。
下記の関数群は rcgproc.cpp
に書かれています。中身は自由に書き換えることが出来ます。
それぞれのコマンド定義に従い処理を行います。
void RcgProc::init(InitRcgParam *)
-
InitRcgParamに従い初期化を行う処理を書いて下さい。
アプリケーションコードからの AUDCMD_INIT_RECOGNIZER_DSP コマンドで実行されます。
(デフォルトではCh数とビット幅の設定をしています。)
void RcgProc::exec(ExecRcgParam *)
-
ExecRcgParamに従い信号処理を書いて下さい。
認識処理を開始するとSDK内部から定期的に呼ばれます。
当サンプルアプリケーションでは1フレームは320サンプルです(アプリケーションで自由に変更できます)。
入力データアドレスからデータを取得し、認識処理を行い、結果を出力データアドレスへ書き出して下さい。
(デフォルトでは入力フレーム内サンプル値の最大・最少・平均値を出力しています。)
void RcgProc::flush(FlushRcgParam *)
-
FlushRcgParamに従いFlush(終端)処理を書いて下さい。
認識処理の停止時にSDK内部から一度だけ呼ばれます。
認識処理にフレーム遅延が発生する場合は、最終フレームの後にflush
を行い遅延分の出力を行います。
出力すべきデータがある場合には、出力データアドレスへ書き出して下さい。
(デフォルトでは何もしていません。)
void RcgProc::set(SetRcgParam *)
-
SetRcgParamに従い設定処理を書いてください。
アプリケーションコードからの AUDCMD_SET_RECOGNIZER_DSP コマンドで実行されます。
(デフォルトでは認識処理のOn/Offを設定しています。)
5.3.4.2. Step2. PREPROC
, RCGPROC
バイナリのビルド
本アプリケーションのビルド時に自動で RCGPROC
バイナリが作成されます。
また、 Configuration で Preprocess
を有効にしていれば PREPROC
バイナリも作成されます。
作成されるパスは worker_recognizer/
の下に RCGPROC
、 worker_preprocess/
の下に PREPROC
です。
これをSDカードの /mnt/sd0/BIN
(PCから見ると \BIN
)フォルダに置いてください。
6. Camera チュートリアル
6.1. camera サンプルアプリケーション
この章では、Spresense Cameraボードを用いたサンプルについて解説します。
このサンプルでは、Spresense Cameraの基本的な使い方を体験していただくために用意しています。
6.1.1. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。
-
Spresense Main Board
-
Spresense Camera Board
-
Spresense Extension Board
-
Arduino UNO LCD Connector board
-
ILI9341 2.2inch LCD
6.1.2. ソースコード
このサンプルのソースコードは、 examples/camera
以下にあります。
ディレクトリの中のファイル構成は以下のようになります。
camera/
. ├── Kconfig ├── Make.defs ├── Makefile ├── README.txt ├── camera_bkgd.c ├── camera_bkgd.h ├── camera_fileutil.c ├── camera_fileutil.h └── camera_main.c
主要なファイル・フォルダの概略は以下のようになります。
ファイル・フォルダ名 | 概要 |
---|---|
camera_main.c |
main()関数が実装されているファイルです。 |
camera_bkgd.c |
NuttXのグラフィクスシステムであるNXを制御するためのユーティリティ関数の実装がされているファイルです。 |
camera_fileutil.c |
イメージセンサから取得したデータをファイルに保存するためのユーティリティ関数が実装されているファイルです。 |
6.1.3. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/camera
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/camera make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
6.1.4. 動作確認
シリアルターミナルを開いて、camera コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
camera
コマンドを実行します。nsh>プロンプトからcameraと入力してEnterを押し、実行します。
nsh> camera
正しく動作すれば、LCDにカメラの画像が表示されます。
なお、デフォルトでは10フレーム表示したのち、終了するようになっています。
カメラの画像を永遠に表示するためには、引数に0を入れて、以下のようにコマンドを実行してください。nsh> camera 0
6.2. multiwebcam サンプルアプリケーション
この章では、multiwebcamに関するサンプルアプリケーションの動作手順を示します。 このサンプルは、IDY Spresense Wi-Fi Add-onボードiS110Bを用いて、Cameraで撮ったJPEG画像をWi-Fiを介して接続先のデバイスに送るサンプルになります。 このサンプルには2つのモードが存在します。
-
1対1の通信で、Motion JPEG over HTTPを転送プロトコルとして用いるモード (ブラウザからSpresenseにアクセスするとカメラ画像をモニターできます)
-
1対多の通信で、独自の転送プロトコルを用いて複数のSpresenseから画像データを取得してPCアプリで表示させるモード (特殊なアプリが必要になりますが、複数のカメラ画像を一画面で見ることができます。)
どちらの場合も、Spresenseは画像を送信するサーバとして動作し、ブラウザもしくはPCツールからサーバに接続して画像を取得することになります。
このサンプルは、以下の技術要素をもとに実装されています。
-
Spresense Camera (V4L2 like I/F)
-
multi pthread programing
-
socket programing
-
Tiny HTTP server
6.2.1. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。
-
Spresense Main Board
-
Spresense Camera Board
-
IDY Wi-Fi Add-on Board iS110B
6.2.2. ソースコード
このサンプルのソースコードは、 examples/multi_webcamera
以下にあります。
ディレクトリの中のファイル構成は以下のようになります。
multi_wabcamera/
├── Kconfig ├── Make.defs ├── Makefile ├── README.txt ├── multiwebcam_main.c ├── multiwebcam_perf.h ├── multiwebcam_server.c ├── multiwebcam_server.h ├── multiwebcam_threads.c ├── multiwebcam_threads.h ├── multiwebcam_util.c ├── multiwebcam_util.h ├── startup_script/ │ └── init.rc └── host/ ├── ImgScaler.py ├── MultiCameraFrame.py ├── NetImgReceiver.py └── test_module/
主要なファイル・フォルダの概略は以下のようになります。
ファイル・フォルダ名 | 概要 |
---|---|
multiwebcam_main.c |
サンプルコードのmain処理の実装ファイル |
multiwebcam_server.c |
ネットワーク処理の実装ファイル |
multiwebcam_threads.c |
イメージセンサーからのJPEGデータを取得するThreadおよび取得したJPEGデータを接続されたクライアントに送信するThreadの実装ファイル |
multiwebcam_util.c |
Thread間でのメッセージ送受信用のQueueの実装ファイル |
startup_script/init.rc |
Spresense起動用サンプル(テンプレート)スクリプト |
host/ |
マルチカメラモードの場合のPC側のサンプルコード(Python) |
6.2.3. ソースコードの解説
この節では、ソースコードの動作内容について解説します。
アプリの全体の概要は以下の図のようになります。
このアプリでは、main()、camera_thread()、jpeg_sender()の3つのThreadが協調して動作しています。 次に3つのそれぞれの動作を解説します。
6.2.3.1. main()
メイン関数。
SpresenseのVideoドライバの初期化を行い(イメージセンサーの初期化含む)、camera_thread()をThreadとして起動します。(上図の緑のブロックの①)
その後、サーバとしてのソケットを生成し accept() 関数を呼び出してクライアントからの接続を待ちます。 (上図の緑のブロックの②)
クライアントから接続されると、JPEGを送信するためのThreadとしてjpeg_sender()を起動します。(上図の緑のブロックの③)
jpeg_sender()起動後、main()内では、jpeg_sender() Threadの終了を待ち、終了したら、再度 accept() にて新たなクライアントからの接続を待ちます。 (上図の緑のブロックの③)
ポイントとなるステップとソースコードを以下に抜粋します。
緑ブロックの番号 | ファイル名:行番号 | コード | 解説 |
---|---|---|---|
① |
multiwebcam_main.c:77 |
video_initialize(VIDEO_DEV_PATH); |
videoドライバ初期化をしています。 |
multiwebcam_main.c:79 |
v_fd = open(VIDEO_DEV_PATH, 0); |
Videoドライバデバイスファイルのオープンをします。 |
|
multiwebcam_main.c:86 |
ret = multiwebcam_prepare_camera_buf(v_fd, |
JPEGデータのバッファの作成とVideoドライバへの登録 |
|
multiwebcam_main.c:105 |
rsock = multiwebcam_initserver(MULTIWEBCAM_PORT_NO /* Port Number */); |
サーバソケットを作成しています。 |
|
multiwebcam_main.c:109 |
cam_thd = multiwebcam_start_camerathread(v_fd); |
camera_thread() Threadの生成 |
|
② |
multiwebcam_main.c:117 |
wsock = multiwebcam_waitconnection(rsock, &client); |
クライアントからの接続待ち、具体的にはaccept()関数を読んで接続待ちをしています。 |
③ |
multiwebcam_main.c:122 |
jpeg_thd = multiwebcam_start_jpegsender(wsock); |
jpeg_sender() Threadの起動を行なっています。 |
④ |
multiwebcam_main.c:123 |
pthread_join(jpeg_thd, NULL); |
jpeg_sender() Threadの終了待ち |
Thread終了後、②に戻ります。 |
6.2.3.2. camera_thread()
イメージセンサーから画像を取得するためのThread。
main()関数から起動されると、Videoドライバに対して、VIDIOC_DQBUFを発行してキャプチャしたデータを取得します。 (上図の青のブロックの①)
その後、jpeg_sender() Threadが起動しているかを確認して、起動していたら、取得したJPEGデータを、jpeg_sender() Threadに渡すために、action_queueにデータを送ります。(上図の青のブロックの②)
データ送信後にempty_queue()から空のバッファを取得します。(上図の青のブロックの③)
その後、VideoドライバにVIDIOC_QBUFで空のバッファをセットして、イメージセンサーからのJPEGデータの取得を待ちます。(上図の青のブロックの④)
あとは、これを繰り返します。
ポイントとなるステップとソースコードを以下に抜粋します。
青ブロックの番号 | ファイル名:行番号 | コード | 解説 |
---|---|---|---|
① |
multiwebcam_thread.c:72 |
multiwebcam_get_picture_buf(v_fd, &buf, V4L2_BUF_TYPE_STILL_CAPTURE); |
VideoドライバからJPEGイメージを取得します。 |
multiwebcam_thread.c:78 |
while (!is_run){ … } |
jpeg_sender() Thread起動待ち |
|
② |
multiwebcam_thread.c:93 |
multiwebcam_push_action(multiwebcam_get_vbuffer(&buf)); |
action_queueに読み出したJPEGデータをプッシュします。 |
③ |
multiwebcam_thread.c:98 |
while (multiwebcam_is_emptyqueue_empty() && is_run){ … } |
empty_queueに使い終わったバッファがプッシュされるまで待ちます。 |
multiwebcam_thread.c:98 |
for (vbuf = multiwebcam_pull_empty(); vbuf != NULL; vbuf = multiwebcam_pull_empty()){ … } |
empty_queueに入っているバッファ全てをVideoドライバに再登録しています。 |
|
Videoドライバに再登録が終わると、①に戻ります。 |
6.2.3.3. jpeg_sender()
クライアントからの接続が確立するとJPEGデータを送信するために動作するThread。
クライアントからの接続が確立したら、main() Threadから起動され、camera_thread()に起動した旨を伝えるために、is_run変数をtrueにします。
その後、action_queueにcamera_thread()がJPEGデータをプッシュするのを待ち、プッシュされたら取り出します。(上図の黄色のブロックの①)
データを取得したら、現在の選択されているプロトコル(Motion JPEG over HTTP、もしくは、独自転送プロトコル)にしたがって、JPEGデータをクライアントに送信します。(上図の黄色のブロックの②)
送信完了後、empty_queueに使い終わったJPEGデータのバッファを送ります。(上図の黄色のブロックの③)
なお、クライアントとの接続が切れた場合、camera_thread()に対して終了を伝えるためis_runをfalseにして、Threadを終了します。(上図の黄色のブロックから緑のブロックに向かっている点線④)
ポイントとなるステップとソースコードを以下に抜粋します。
黄色ブロックの番号 | ファイル名:行番号 | コード | 解説 |
---|---|---|---|
multiwebcam_thread.c:145 |
is_run = true; |
camera_thread() Threadに起動を知らせます。 |
|
multiwebcam_thread.c:149 |
multiwabcam_sendheader(sock); |
接続の最初の1回だけ送信されるべきデータを送ります。 |
|
① |
multiwebcam_thread.c:155 |
while(multiwebcam_is_actionqueue_empty()){ … } |
action_queueが空の間(camera_thread()がJPEGをプッシュするまでの間)待ちます。 |
multiwebcam_thread.c:159 |
buf = multiwebcam_pull_action(); |
action_queueからJPEGデータを取り出します。 |
|
② |
multiwebcam_thread.c:162 |
ret = multiwebcam_sendframe(sock, (char *)buf→start, (int)buf→jpg_len); |
取り出したデータをクライアントに送信します。 |
③ |
multiwebcam_thread.c:166 |
multiwebcam_push_empty(buf); |
送信し終わったバッファをempty_queueにプッシュします。 |
empty_queueにプッシュした後、①に戻ります。 |
6.2.4. ビルドおよび実行手順(1対1のMotion JPEG over HTTPモードの場合)
このサンプルコードは、1対1のMotion JPEG over HTTPで送信するモードと、多対1の独自転送プロトコルで送信するモードの2つのモードが存在します。
この節では、1対1のMotion JPEG over HTTPを用いた通信をさせる場合について解説します。
多対1の独自転送プロトコルモードでの通信を行う場合は、
ビルドおよび実行手順(多対1の独自転送プロトコルモード)
を参照してください。
6.2.4.1. ビルド手順
ここでは、CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/multiwebcam
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/multiwebcam make
-
nuttx.spk
を Spresense ボードへ書き込みます。ビルドが無事に完了すると sdk フォルダの中に nuttx.spk というファイルが生成されるので、これをターゲットのSpresenseに書き込みます。 この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
6.2.4.2. 動作確認
実機側のサンプルアプリを起動するために、シリアルターミナルを開いて、Wi-Fiに接続し、 multiwebcam コマンドを実行します。
-
シリアルターミナルを起動します。
まず、ターミナルソフトから、Spresenseのシリアルポートに接続して、NuttShellに入ります。
以下の例では、ターゲットのSpresenseと繋がっているシリアルポートは /dev/ttyUSB0 を、baudrate として 115200 bps を設定してminicomで接続しています。minicom -D /dev/ttyUSB0 -b 115200
-
Wi-Fi の接続を行います。
下記の例では、APモードでWi-Fiを起動し、SSIDをspresense_net、パスワードを0123456789としています。
Wi-Fiモジュールが正しく起動されると、IPアドレスが設定されるので、それを確認します。 下記の例では、Wi-Fiモジュールの起動が完了するまで、5秒ほど sleep が入っています。
ifconfigコマンドで、下記のように、IPアドレスが割り当てられます。nsh> gs2200m -a 1 spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:192.168.11.1 DRaddr:192.168.11.1 Mask:255.255.255.0
上記の例では、 192.168.11.1 が Spresense のIPアドレスになります。
なお、HWaddrは購入されたWi-Fiモジュールによって変わる場合があります。 -
アプリを起動します。
Wi-Fi の設定が完了したら、 multiwebcam アプリを起動します。
nsh> multiwebcam
これで、Spresense 側の準備は完了です。
-
PCやスマホで、作成したWi-Fiのネットワークに接続します。
次に、PCやスマホなどのブラウザでカメラからの画像を見るために、まずは先ほど Spresense で起動した Wi-Fi のネットワークにPCやスマホを接続します。 スマホなどで、Wi-Fiのネットワークに接続します。
接続するWi-FiのSSIDは、先ほど設定した、 spresense_net になります。 PCやスマホの Wi-Fi 接続設定で、 spresense_net を探し、接続を行います。
接続する際の暗号方式は、 WPA/WPA2 を選択してください。
パスワードは、上記で設定した、 0123456789 です。 -
ブラウザで Spresense カメラに接続して Live View を表示します。
無事に Wi-Fi ネットワークに接続ができたら、接続したPCやスマホのブラウザを開き、URL入力欄に、以下のURLを入力することで、カメラの画像を表示させることができます。
http://192.168.11.1
正しく動作すれば、ブラウザ上にカメラの画像が表示されます。
6.2.5. ビルドおよび実行手順(多対1の独自転送プロトコルモード)
続いて多対1の独自プロトコルを用いた場合のビルド方法および実行方法について説明します。
基本的にはMotion JPEG over HTTPとビルド方法は同じです。
ビルド方法の唯一の違いはExampleのConfigメニューにある、"Http MJPEG is used"オプションを無効にすることです。
実機側の使い方についてもほぼ同じで、唯一の違いはWiFiの接続設定をアクセスポイントではなく、ステーションにすることです。
では、ステップごとに説明します。
6.2.5.1. ビルド手順
ここでは、CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションを行います。
引数に
examples/multiwebcam
を指定してコンフィグレーションを実行します。make distclean tools/config.py examples/multiwebcam
その後、以下のコマンドでmenu configを開きます。
make menuconfig
メニューを開いたら、矢印キーでメニューの一番下にある、"Application Configuration"まで移動してEnterキーを押して中のメニューに入ります。Application Configurationの中にある、"Spresense SDK"メニューに同様にして入り、さらに"Examples"に進みます。
"Application Configuration" -> "Spresense SDK" -> "Examples"
Examplesに入ると、 ”[*] Multi Web Camera" というチェックが付いた項目の中に "[*] Http MJPEG is used" という項目があるので、この項目にカーソルを合わせてスペースキーでチェックを外します。
チェックを外したら、"<Exit>"にカーソルを合わせてエンターを押して行き、一番上の階層で<Exit>をすると、"Do you wish to save your new configuration?"と聞かれるので、<Yes>を選択してコンフィグの変更をセーブしてmenuconfigを終了します。
-
ビルドを行います。
コンフィグが完了したら、以下のコマンドでビルドを行います。
make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。ビルドが無事に完了すると sdk フォルダの中に nuttx.spk というファイルが生成されるので、これをターゲットのSpresenseに書き込みます。 この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
6.2.5.2. 動作確認
実機側のサンプルアプリを起動するために、シリアルターミナルを開いて、Wi-Fiに接続し、 multiwebcam コマンドを実行します。
-
シリアルターミナルを起動します。
まず、ターミナルソフトから、Spresenseのシリアルポートに接続して、NuttShellに入ります。
以下の例では、ターゲットのSpresenseと繋がっているシリアルポートは /dev/ttyUSB0 を、baudrate として 115200 bps を設定してminicomで接続しています。minicom -D /dev/ttyUSB0 -b 115200
-
Wi-Fi の接続を行います。
下記の例では、STAモードでWi-Fiを起動します。STAモードのため、既存のWi-Fiネットワークに接続を行うことになるので、予め接続するWi-FiネットワークのSSIDとパスワードを準備してください。
この例では、SSIDを hogehoge、パスワードを hogehoge1 として説明しています。
Wi-Fiモジュールが正しく起動されると、IPアドレスが設定されるので、それを確認します。 下記の例では、Wi-Fiモジュールの起動が完了するまで、5秒ほど sleep が入っています。
ifconfigコマンドで、下記のように、IPアドレスが割り当てられます。nsh> gs2200m hogehoge hogehoge1 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:XXX.XXX.XXX.XXX DRaddr:XXX.XXX.XXX.XXX Mask:255.255.255.0
ifconfigの結果、inet addrに接続された結果としてのIPアドレスが表示されます。
なお、HWaddrは購入されたWi-Fiモジュールによって変わる場合があります。
ここで取得したIPアドレスはPCアプリの設定で必要になるのでメモしておいてください。 -
アプリを起動します。
Wi-Fi の設定が完了したら、 multiwebcam アプリを起動します。
nsh> multiwebcam
これで、Spresense 側の準備は完了です。
複数のSpresenseを用いる場合は同様にWi-Fiの接続とmultiwebcameraの起動を行なってください。
-
PCアプリの起動
PC側のアプリは複数のカメラの画像を表示するために、参考としてPythonで作成されたアプリになっています。このアプリはLinux PCで動作することを確認しています。
実行するには、まずPython 2.7のインストールをしてください。
さらに、Pythonの以下のライブラリが必要になりますので、それぞれインストールをしてください。-
python-wxgtk3.0
-
python-wxtools
Linuxでは以下のコマンドでインストールが行えます。
$ sudo apt install python-wxgtk3.0 python-wxtools
必要なPythonライブラリのインストールが完了したら、まず、接続するSpresenseのIPアドレスを設定します。先ほど実機を起動した際にメモしたIPアドレスを用います。
host/ フォルダの中に移動して、MultiCameraFrame.pyを開きます。
そのファイルの183行目に記載されている、servers = ( ('192.168.11.1', 10080), ('192.168.11.2', 10080), ('192.168.11.3', 10080), ('192.168.11.4', 10080) )
というコードの192.168.11.1 ~ 4と記載されているIPアドレスを、メモしたIPアドレスに書き換えてください。
デバイスが4つまで表示が可能ですが、4つない場合は、持っている数分だけ変更し、残りはそのままで問題ありません。
例としてデバイスが2つで、それぞれ、10.0.0.5、10.0.0.8だった場合servers = ( ('10.0.0.5', 10080), ('10.0.0.8', 10080), ('192.168.11.3', 10080), ('192.168.11.4', 10080) )
となります。
編集が終わったらファイルをセーブしてコマンドプロンプトから以下のコマンドを叩くことで、アプリを起動させることが出来ます。python MultiCameraFrame.py
正しく起動すると、全画面にWindowが表示され、デバイスからの画像の表示が始まります。
なお、当然ながら、PCはデバイスが接続したものと同じWi-Fiネットワークに接続しておく必要があります。
-
6.2.5.3. PC側の側アプリの解説
ここでは、PCアプリの簡単な解説を行います。
まず、PCアプリの構造を以下の図に示します。
ホストアプリは、WindowプログラミングのフレームワークとしてwxPythonを利用しています。MultiCameraFrame.pyに実装されているカスタムパネル:WebCamPanelを持つMultiCamFrameを生成します。
その引数に接続するSpresenseのIPアドレスとポート番号のリストを渡します。
Frameが起動すると、WebCamPanelを生成し、その中で4つのStaticBitmapを生成してフレームに貼り、その後、渡されたIPアドレスとポート番号のリストを元に、4つのNetImgReceiverを生成します。NetImgReceiverには、NetImgReceiver.pyに実装しており、接続するサーバのIPアドレスとポート番号及びStaticBitmapに紐づくID番号が付与されます。
NetImgReceiverは生成された後、receiveThread()がThreadとして起動し、並列動作を始めます。
receiveThread()では、指定されたserver IPとポート番号に基づいて、Spresense デバイス側のサーバに対して接続要求を行います。
接続が確立すると、JPEGの画像の受信を開始します。
JPEGの受信が完了するとWebCamPanelのPictUpdateEventを発生させ、受信したJPEGデータをID番号と共にWebCamPanelに送ります。
WebCamPanel内では、PictUpdateEventが発生するとonPictUpdate()がコールバックされます。この関数では、受信したJPEGデータとID番号を受け取り、画像サイズの調整をしたのち、ID番号に基づいてStaticBitmapに受信した画像を表示します。
6.2.6. Appendix : パケットフォーマット
ここでは、各モードでやりとりされるパケットのフォーマットについて解説します。
6.2.6.1. Motion JPEG over HTTP
こちらは、HTMLの規格として定義されている、”multipart/x-mixed-replace"を用いています。詳しくは以下を参照してください。
https://html.spec.whatwg.org/#read-multipart-x-mixed-replace
6.2.7. Tips : Spresense カメラの自動起動
Spresenseのnshプロンプトで実行しているコマンドは、起動時に自動的に実行することも出来ます。
詳しくは、 アプリケーションの自動起動方法 を参照してください。
7. JPEG チュートリアル
7.1. JPEG デコード サンプルアプリケーション
7.1.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/jpeg_decode
を指定してコンフィグレーションを実行します。tools/config.py examples/jpeg_decode
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
7.1.3. 動作確認
シリアルターミナルを開いて、jpeg_decode
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
jpeg_decode
コマンドを実行します。jpeg_decode コマンドの使い方を以下に示します。
nsh> jpeg_decode <filename>
- filename
-
デコードしたいJPEGファイルをフルパスで指定します。
filenameで指定するファイルを
/mnt/spif/
もしくは/mnt/sd0/
に置いて実行してください。 デコード結果は、同じディレクトリに拡張子 .YUVで生成されます。
本サンプルアプリケーションはfilenameで指定されたファイルをデコードして、 デコード元と同じディレクトリにデコード結果を保存します。 デコード結果は、デコード元のファイルの拡張子を.YUVに変更したものになります。
jpeg_decode
コマンドを実行してSAMPLE.JPGというJPEGファイルを
デコードした例を以下に示します。
nsh> jpeg_decode /mnt/sd0/SAMPLE.JPG Decode result is saved in /mnt/sd0/SAMPLE.YUV.
また、本サンプルアプリケーションはデコード結果をファイルに保存しますが、
jpeg_decode_main.cに定義されているput_scanline_someplace()関数を編集することで、
LCDに描画するなど、ファイル以外の形式に結果を出力するようにすることもできます。
8. LTE チュートリアル
8.1. LTE HTTP GET サンプルアプリケーション
8.1.1. 概要
本サンプルプログラムは、LTE通信機能を用いて、HTTP GETを行うサンプルです。
8.1.1.1. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード
-
microSD カード
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。
本サンプルプログラムではネットワークに接続するため、SIM カードが必要です。
LTE-M 動作確認SIM Listをご確認ください。
8.1.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションを行います。
引数に
examples/lte_http_get
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_http_get
サンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> HTTP GET method using LTE example - Access Point Name (CONFIG_EXAMPLES_LTE_HTTP_GET_APN_NAME) - IP type Selection - Authentication type Selection - Username used for authentication (CONFIG_EXAMPLES_LTE_HTTP_GET_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_HTTP_GET_APN_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type Selection
APNプロトコル。
IPv4
、IPv6
、IPv4/v6
から選択します。Authentication type Selection
認証タイプ。
None
、PAP
、CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。 -
ビルドを実行します。
make
コマンドを実行しビルドします。make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.1.3. 動作確認
シリアルターミナルを開いて、lte_http_get
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_http_get
コマンドを実行します。lte_http_get コマンドの使い方を以下に示します。
nsh> lte_http_get <url>
- url
-
インターネット上に置かれているファイルのURLを指定します。
http://
もしくはhttps://
から始まる必要があります。urlを指定しない場合、http://example.com/index.html
となります。
本サンプルアプリケーションはurlに指定されたファイルをダウンロードしシリアルターミナルに出力します。
lte_http_get
コマンドを実行した例を以下に示します。
nsh> lte_http_get app_restart_cb called. reason:Modem restart by application. pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : 10.212.60.255 app_localtime_report_cb called: localtime : "19/12/06 : 18:24:33" set localtime completed: 2019/12/06,18:24:33 <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html> nsh>
|
本サンプルアプリケーションの、wget
を wget_post
に変更することによりHTTPのPOSTメソッドが使用できます。
以下の例を参考に wget_post
の第2引数にPOSTするデータを設定してください。
wget_post(url, "Hello spresense world!!" ,g_app_iobuffer, APP_IOBUFFER_LEN, app_wget_cb, NULL);
また、本サンプルアプリケーションはダウンロードしたファイルをシリアルターミナルに出力しますが、
以下の様に app_wget_cb()
関数を一部変更することにより、ファイルに保存することができます。
static void app_wget_cb(FAR char **buffer, int offset, int datend,
FAR int *buflen, FAR void *arg)
{
int fd;
fd = open("/mnt/spif/index.html", (O_WRONLY | O_APPEND));
if ((fd < 0) && (errno == ENOENT))
{
fd = open("/mnt/spif/index.html", (O_CREAT | O_WRONLY), 0666);
}
/* Write HTTP data to local file */
(void)write(fd, &((*buffer)[offset]), datend - offset);
close(fd);
}
上記の例では、 |
8.2. LTE TLS サンプルアプリケーション
8.2.1. 概要
本サンプルプログラムは、LTE通信機能を用いて、TLSプロトコルでサーバに接続し、HTTP POSTを行うサンプルです。
8.2.1.1. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード
-
microSD カード
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。
本サンプルプログラムではネットワークに接続するため、SIM カードが必要です。
LTE-M 動作確認SIM Listをご確認ください。
8.2.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションを行います。
引数に
examples/lte_tls
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_tls
サンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
-
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> TLS data communication over LTE network example - Access Point Name (CONFIG_EXAMPLES_LTE_TLS_APN_NAME) - IP type Selection - Authentication type Selection - Username used for authentication (CONFIG_EXAMPLES_LTE_TLS_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_TLS_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type Selection
APNプロトコル。
IPv4
、IPv6
、IPv4/v6
から選択します。Authentication type Selection
認証タイプ。
None
、PAP
、CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。 -
HTTPSの設定をします。
モデムのTLSプロトコルを使用することが可能です。
使用する場合は、 モデムのTLSプロトコルを使用する を参照してください。Application Configuration -> Spresense SDK -> Examples -> TLS data communication over LTE network example -> Directory for server certification files (CONFIG_EXAMPLES_LTE_TLS_CERTS_PATH)
HTTPSで使用するサーバのルート証明書を格納するディレクトリを指定します。
デフォルトの設定では/mnt/sd0/CERTSとなっています。ディレクトリのパスを
/mnt/spif/CERTS
にするとSPI-Flashに変更することができます。
-
-
ビルドを実行します。
make
コマンドを実行しビルドします。make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.2.3. 動作確認
シリアルターミナルを開いて、lte_tls
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_tls
コマンドを実行します。lte_tls コマンドの使い方を以下に示します。
nsh> lte_tls <url>
- url
-
インターネット上に置かれているファイルのURLを指定します。
https://
から始まる必要があります。urlを指定しない場合、https://example.com/post
となります。事前にサーバのルート証明書をコンフィグレーションで記述したディレクトリに格納する必要があります。 ルート証明書のダウンロード方法は HTTPSで使用するサーバアクセス用ルート証明書のダウンロード方法 をご参照ください。
本サンプルアプリケーションはHTTPのPOSTメソッドを使用して指定されたurlに任意のデータを送信します。
lte_tls
コマンドを実行した例を以下に示します。正常にデータを送信できた場合は "HTTP status code = 200" が出力されます。
nsh> lte_tls https://httpbin.org/post app_restart_cb called. reason:Modem restart by application. app_radio_on_cb called. result: 0 app_activate_pdn_cb called. result: 0 pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : 10.212.60.255 app_localtime_report_cb called: localtime : "19/12/10 : 17:26:18" set localtime completed: 2019/12/10,17:26:18 HTTP status code = 200 app_deactivate_pdn_cb called. result: 0 app_radio_off_cb called. result: 0 nsh>
本サンプルアプリケーションでは、 create_http_post()
の関数でPOSTするデータを作成しています。
static int create_http_post(const char *host,
const char *path,
char *buffer,
size_t buffer_size)
{
const char *post_data = "Spresense!";
const char http_post_request[] = "POST %s HTTP/1.1\r\n"
"HOST: %s\r\n"
"Connection: close\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s";
return snprintf(buffer, buffer_size,
http_post_request,
path,
host,
strlen(post_data),
post_data);
}
8.2.4. HTTPSで使用するサーバアクセス用ルート証明書のダウンロード方法
8.2.4.1. 概要
HTTPSなどTLSによるセキュアな通信を使ったサーバへアクセスするためには、ルート証明書をダウンロードしてアプリケーションで指定した場所にコピーしておく必要があります。
SpresenseではTLSによるセキュア通信を行うために MbedTLS を使用しており、以下の証明書に対応しています。
-
DER encoded binary X.509 (DER)
DER形式のバイナリ証明書ファイル。拡張子は
.cer
-
Base 64 encoded X.509 (PEM)
Base 64形式のASCIIテキスト証明書ファイル。拡張子は
.pem
/.cer
ここでは、サーバアクセス用ルート証明書のダウンロード方法について説明します。
8.2.4.2. ダウンロード方法
以下の手順でダウンロードします。 以下の手順ではWindows/Chromeを使っていますが、他のOSやブラウザの場合でも同様の手順で対応している形式を選んでダウンロードしてください。
-
アクセスしたいサイトのページを開きます。
ブラウザでアクセスしたいページを開きます。以下はアクセスしたいページが
https://example.com/
の例です。 -
サイトの証明書を表示します。
-
ページURL部分に表示されているセキュリティ通信ボタンをクリックします。
-
セキュリティ保護のメニューを開きます。
-
有効な証明書を開きます。
-
-
ルート証明書を表示します。
-
証明書のパス(階層)を表示します。
-
最上位層(ルート)の証明書を選択します。
-
証明書の表示をクリックします。
-
-
ルート証明書をコピー(エクスポート)します。
-
証明書のコピー(エクスポート)を選択します。
-
エクスポートファイルの形式を選択するページまで移動します。
-
エクスポートするファイルの形式を選択します。
Spresenseで対応している
DER encoded binary X.509
またはBase 64 encoded X.509
を選択します。 -
エクスポート先を選択します。
-
エクスポートを実行します。
-
以上の手順を実行することでルート証明書がコピー(エクスポート)されます。 そしてコピーされたルート証明書をアプリケーションで指定した場所にコピーすることでSpresenseでセキュア通信を行うことができます。
8.3. LTE MQTT サンプルアプリケーション
8.3.1. 概要
本サンプルプログラムは、LTE通信機能を用いて、MQTTブローカに接続し、指定したトピック名に対してパブリッシュまたはサブスクライブするサンプルです。
8.3.1.1. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。
本サンプルプログラムではネットワークに接続するため、SIM カードが必要です。
LTE-M 動作確認SIM Listをご確認ください。
8.3.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/lte_mqtt
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_mqtt
サンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
-
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> MQTT using LTE example - Access Point Name (CONFIG_EXAMPLES_LTE_MQTT_APN_NAME) - IP type (CONFIG_EXAMPLES_LTE_MQTT_APN_IPTYPE) - Authentication type (CONFIG_EXAMPLES_LTE_MQTT_APN_AUTHTYPE) - Username used for authentication (CONFIG_EXAMPLES_LTE_MQTT_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_MQTT_APN_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type
APNプロトコル。0~2の値を設定します。0:
IPv4
, 1:IPv6
2:IPv4/v6
から選択します。Authentication type
認証タイプ。0~2の値を設定します。 0:
None
、1:PAP
、2:CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.3.3. 動作確認
シリアルターミナルを開いて、lte_mqtt
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_mqtt
コマンドを実行します。lte_mqtt コマンドの使い方を以下に示します。
nsh> lte_mqtt topicname <options>
- topicname
-
パブリッシュ又はサブスクライブするトピック名
- options
オプション 説明 --host
MQTTブローカのホスト名。デフォルトは
localhost
です。--port
接続先ポート番号。デフォルトは
1883
です。--qos
QOS。0~2の値を指定します。デフォルトは
2
です。--delimiter
区切り文字。 デフォルトは
\n
です。--clientid
クライアントID。 デフォルトは
stdout_subscriber
です。--username
ユーザ名。 デフォルトは 未設定 です。
--password
パスワード。 デフォルトは 未設定 です。
--showtopics
トピック名の表示有無。
on
またはoff
を指定します。デフォルトはoff
です。--cafile <file>
ルートCA証明書ファイルを指定します。
--cert <file>
クライアント証明書ファイルを指定します。
--key <file>
クライアント秘密鍵ファイルを指定します。
--publish <message>
<message>文字列をパブリッシュします。このオプションが無いときは、サブスクライブを行います。
Spresenseでは
localhost
をサポートしていません。必ず--host
でホスト名を指定してください。
8.3.3.1. PC上からパブリッシュしたメッセージをSpresenseでサブスクライブする
MQTTブローカに接続し、指定したトピック名に対してサブスクライブする手順について説明します。
サブスクライブの実行に成功するとシリアルポートにサブスクライブしたメッセージを表示します。
当該トピック名に対してメッセージをパブリッシュするためには、別途操作が必要です。 |
lte_mqtt
コマンドを実行した例を以下に示します。正常にサブスクライブが完了した場合は "Subscribed 0" が出力されます。
サブスクライブ処理を終了する場合は、ターミナル上で Ctrl-C を押すことでアプリケーションが終了し NuttShell プロンプトに戻ります。
nsh> lte_mqtt /test --host test.mosquitto.org app_restart_cb called. reason:Modem restart by application. app_radio_on_cb called. result: 0 app_activate_pdn_cb called. result: 0 pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : 10.212.60.255 app_localtime_report_cb called: localtime : "19/12/11 : 11:36:39" set localtime completed: 2019/12/11,11:36:39 Connecting to test.mosquitto.org 1883 Connected 0 Subscribing to /test Subscribed 0
サブスクライブしているトピック名に対してパブリッシュします。
ここではUbuntu 16.04で mosquitto_pub
コマンドを実行してパブリッシュする例を示します。
-
以下のコマンドを実行し
mosquitto-clients
をインストールします。
sudo apt-get install mosquitto-clients
-
mosquitto_pub
コマンドを実行してメッセージをパブリッシュします。
mosquitto_pub -t /test -m "Hello Spresense world" -h test.mosquitto.org
-
パブリッシュに成功するとシリアルポートに以下のメッセージが出力されます。
Hello Spresense world
8.3.3.2. SpresenseからパブリッシュしたメッセージをPC上でサブスクライブする
続いて、MQTTブローカに接続し、指定したトピック名に対してパブリッシュする方法を説明します。
一つのパブリッシュ処理を完了するとアプリケーションは終了します。
当該トピック名に対してメッセージをサブスクライブするためには、別途操作が必要です。 |
lte_mqtt
コマンドを実行した例を以下に示します。正常にパブリッシュが完了した場合は "Published 0" が出力されます。
nsh> lte_mqtt /test --host test.mosquitto.org --publish "Hello Spresense world" app_restart_cb called. reason:Modem restart by application. app_radio_on_cb called. result: 0 app_activate_pdn_cb called. result: 0 pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : 10.198.58.124 app_localtime_report_cb called: localtime : "22/03/30 : 22:10:55" set localtime completed: 2022/03/30,22:10:55 Connecting to test.mosquitto.org 1883 Connected 0 Publishing to /test Published 0 app_deactivate_pdn_cb called. result: 0 app_radio_off_cb called. result: 0
mosquitto-clients
を用いてサブスクライブする方法を以下に示します。
-
PC上で
mosquitto_sub
コマンドを実行してメッセージをサブスクライブします。
mosquitto_sub -t /test -h test.mosquitto.org
-
サブスクライブに成功するとPC上に以下のメッセージが出力されます。
mosquitto_sub -t /test -h test.mosquitto.org Hello Spresense world
8.3.3.3. SSL/TLS接続を行う場合
前述した例ではポートの1883を使用していましたが、ここでは SSL/TLS 接続を利用してポート番号8883を使用する方法について説明します。
lte_mqtt
コマンドを実行する際に --cafile
オプションによりルート証明書のファイルパスを指定することができます。
test.mosquitto.org
を使用する場合は、mosquitto.org.crt ファイルをダウンロードしてください。
このファイルを予め Spresense からアクセスできる場所へ格納しておきます。 以下の例では、 Flash 上へ転送する方法を示しています。
./tools/flash.sh -c /dev/ttyUSB0 -w mosquitto.org.crt
転送に成功すると、Spresense からは /mnt/spif/mosquitto.org.crt
のパスでこのファイルにアクセスすることができます。
lte_mqtt
コマンドの実行方法は、--port
と --cafile
オプションを追加することを除けば、先ほどと手順は同じです。
-
SSL/TLS 接続による MQTT パブリッシュの例
nsh> lte_mqtt /test --host test.mosquitto.org --port 8883 --cafile /mnt/spif/mosquitto.org.crt --publish testmessage
-
SSL/TLS 接続による MQTT サブスクライブの例
nsh> lte_mqtt /test --host test.mosquitto.org --port 8883 --cafile /mnt/spif/mosquitto.org.crt
8.4. LTE LwM2M サンプルアプリケーション
8.4.1. 概要
本サンプルプログラムは、LTEによる通信機能と WakaamaのLwM2Mライブラリ を用いて、 Leshan などのLwM2Mサーバに接続し、Spresenseデバイスの管理を行うサンプルです。Spresense GNSS機能により取得されたデバイスの位置情報をサーバー経由で取得することができます。
8.4.3. 事前準備
8.4.3.1. デバイスの接続
SpresenseメインボードとSpresense LTE拡張ボードの接続方法、及びSIMカードの挿入方法はこちらを参照してください。 また、ネットワークに接続するためのSIMカードは LTE-M 動作確認SIM List を参照の上準備してください。
8.4.4. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションを行います。
引数に
examples/lte_lwm2m
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_lwm2m
必要に応じてサンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> LwM2M using LTE example - Access Point Name (CONFIG_EXAMPLES_LTE_LWM2M_APN_NAME) - IP type (CONFIG_EXAMPLES_LTE_LWM2M_APN_IPTYPE) - Authentication type (CONFIG_EXAMPLES_LTE_LWM2M_APN_AUTHTYPE) - Username used for authentication (CONFIG_EXAMPLES_LTE_LWM2M_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_LWM2M_APN_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type
APNプロトコル。0~2の値を設定します。
0: IPv4
,1: IPv6
,2: IPv4/v6
から選択します。Authentication type
認証タイプ。0~2の値を設定します。
0: None
,1: PAP
,2: CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。 -
ビルドを行います。
make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.4.5. 動作確認
シリアルターミナルを開いて、lte_lwm2m
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_lwm2m
コマンドを実行します。lte_lwm2m コマンドの使い方を以下に示します。
nsh> lte_lwm2m <options>
- options
オプション 説明 -n <NAME>
LwM2M のエンドポイント名を指定します。
-h <HOST>
LwM2MサーバのURLを指定します。
-p <PORT>
LwM2Mサーバへの接続ポートを指定します。
-4
LwM2Mサーバへの接続をIPv4で行う場合オプションに追加します。(デフォルトはIPv6接続です。)
-c
このオプションを追加した場合、ダミーのバッテリーレベルを時間経過で上書き更新します。
lte_lwm2m
コマンドを実行した例を以下に示します。
8.4.5.1. Spresenseターミナル
任意のエンドポイント名(例: Spresense_LwM2M)を引数に指定して、lte_lwm2m
コマンドを実行します。
nsh> lte_lwm2m -h leshan.eclipseprojects.io -p 5683 -4 -c -n Spresense_LwM2M app_restart_cb called. reason:Modem restart by application. app_radio_on_cb called. result: 0 app_activate_pdn_cb called. result: 0 pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : xxx.xxx.xxx.xxx Trying to bind LWM2M Client to port 56830 LWM2M Client "Spresense_LwM2M" started on port 56830 > New Battery Level: 71 value changed! app_localtime_report_cb called: localtime : "21/04/06 : 20:39:23" set localtime completed: 2021/04/06,20:39:23 -> State: STATE_REGISTERING 22 bytes received from [23.97.187.154]:5683 64 41 70 48 48 70 FB C6 82 72 64 0A 37 69 6D 77 dApHHp...rd.7imw 41 77 73 79 4C 36 AwsyL6 New Battery Level: 41 value changed! -> State: STATE_READY -> State: STATE_READY
8.4.5.2. Leshan LwM2M Server
Leshan LwM2M Server へアクセスして、Client Endpoint一覧から上で指定したエンドポイント名を選択します。
動作環境によっては通信状態が不安定になり、正しく動作しないことがあります。 |
本サンプルアプリケーションで実装されているオブジェクトについて以下に示します。
-
Device オブジェクト
サーバーからのRead操作によってデバイス情報を読み出すことができます。
表 1. Device Object リソース 説明 Manufacturer
"SONY SPRESENSE"
Model Number
"CXD5602PWBMAIN1"
Serial Number
ボード固有のシリアルナンバー (ボードユニークID)
Firmware Version
ファームウェアバージョン(アプリケーションのバージョン情報)
Reboot
EXEを実行するとボードを再起動します。
Battery Level
ランダムなダミー値です。
Memory Free
ヒープの空き容量(Kbyte)
Current Time
現在時刻
UTC Offset
"+09:00"
Timezone
"Asia/Japan"
Memory Total
アプリケーション用メモリのトータル容量(1.5MByte)
-
Firmware Update オブジェクト
Package
からパッケージファイルを送信し、Update
によってファームウェアアップデートを実行することができます。表 2. Firmware Update Object リソース 説明 Package
File Inputからパッケージファイルを選択してデバイスへ送信します。
Update
EXEを実行するとファームウェアアップデートを実行します。
Package
から選択するファイルは、fwupdate/package.shを用いて作成します。nuttx.spk
を含むパッケージファイルを作成するときは次のように実行すると、package.bin
ファイルが作成できます。cd spresense/sdk ../examples/fwupdate/package.sh nuttx.spk
Package
ボタンを押して、File Input
にpackage.bin
ファイルを選択して書き込みます。 ファイルのサイズにも依存しますが、書き込みには約15分ぐらいかかります。 このときLeshan LwM2M ServerのTimeout値が小さいと書き込みに失敗するので、 タイムアウトを30minに設定してから書き込みを実行してください。書き込みが終了したら、
Update
を実行するとファームウェアアップデートを行います。ファームウェアアップデートを実行するとボードは再起動します。 再起動後にもLeshanサーバーへ自動的に接続したい場合、アプリケーションの自動起動方法 を参照してください。
-
Location オブジェクト
Spresense GNSSから取得したデバイスの位置情報をサーバー経由で取得することができます。 非測位状態のとき、緯度、経度の値は 0.0、
Timestamp
はJan 01 1970
になります。 測位できたときにこれらの値が更新されます。表 3. Location Object リソース 説明 Latitude
緯度 (例) -43.5723
Longitude
経度 (例) 153.21760
Altitude
高度 [m]
Radius
精度 [m]
Velocity
速度情報 [3GPP-TS_23.032]
Timestamp
測位時刻
Speed
移動速度 [m/s]
-
Digital Input オブジェクト
サーバーからのRead操作によってデジタルピンの入力値を読み出すことができます。 ピン番号は nuttx/arch/arm/include/cxd56xx/pin.h を参照してください。
CREATEボタンを押して、
Instance Id
にピン番号、Application Type
に任意の名前を入力してインスタンスを作成します。 ここの例では、LTE拡張ボードに付属のボタンスイッチ(ピン番号=89)を指定しています。これはプルアップされているピンなので、Digital Input Polarity
に true を設定します。インスタンスを作成した後にRead読み出しを行うことでGPIO値を読み出すことができます。 LTE拡張ボードに付属のボタンスイッチを押すと
Digital Input State
が true になり、離すと false になります。表 4. Digital Input Object リソース 説明 Digital Input State
GPIOから読み出した値
Digital Input Counter
Edge Selection を使用した場合に割り込み回数を表示します。
Digital Input Polarity
極性
Digital Input Edge Selection
割り込みトリガの種類を選択します
Digital Input Counter Reset
割り込み回数をクリアします
Application Type
任意の名前
Timestamp
GPIOを読み出した時刻
-
Digital Output オブジェクト
サーバーからのWrite操作によって任意のデジタルピンを制御することができます。 ピン番号は nuttx/arch/arm/include/cxd56xx/pin.h を参照してください。
Digital Inputと同様に、 CREATEボタンを押して、
Instance Id
にピン番号、Application Type
に任意の名前を入力してインスタンスを作成します。ここの例では、メインボードのLED0(ピン番号=97)を指定しています。Digital Output State
に true/false を書き込むことで、LEDの点灯/消灯を制御することができます。表 5. Digital Output Object リソース 説明 Digital Output State
GPIO出力設定値
Digital Output Polarity
極性
Application Type
任意の名前
Timestamp
GPIOを書き込んだ時刻
-
Analog Input オブジェクト
サーバーからのRead操作によって任意のアナログピンの値を読み出すことができます。 LTE拡張ボードのSEN_AINアナログピン番号は、A/D変換器の使用方法 を参照してください。
CREATEボタンを押して、
Instance Id
にSEN_AINアナログピン番号、Application Type
に任意の名前を入力してインスタンスを作成します。ここの例では、LTE拡張ボード上のSEN_AIN0番号を指定しています。Analog Input Current Value
に0.0~1.0の範囲で正規化されたアナログ値を読み出すことができます。表 6. Analog Input Object リソース 説明 Analog Input Current Value
ピンから読み出したアナログ値
Min Measured Value
読み出したアナログ値の最小値
Max Measured Value
読み出したアナログ値の最大値
Min Range Value
レンジ最小値(0.0)
Max Range Value
レンジ最大値(1.0)
Application Type
任意の名前
Reset Min and Max Measured Values
最小値/最大値をクリアする
Timestamp
Analogを読み出した時刻
8.5. LTE AWS-IoT サンプルアプリケーション
8.5.2. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード
-
microSD カード
-
AWS-IoT Core
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。
本サンプルプログラムではネットワークに接続するため、SIM カードが必要です。
LTE-M 動作確認SIM Listをご確認ください。
また、AWS-IoTを利用するには、AWS-IoTの使用開始および、AWS-IoTへのデバイス(モノ)の登録が必要です。
開始手順については AWS IoT の使用開始 を参考にしてください。
詳細はAWS-IoT Coreでの説明を参照していただくことになりますが、サンプルの動作確認に当たりAWS-IoT Coreで必要になる操作の要点は以下になります。
・ モノの作成とアタッチ
・ 証明書の発行
・ ポリシーの作成とアタッチ
-
モノの作成とアタッチ
モノは、特定のデバイスまたは論理エンティティを表します。
証明書にモノをアタッチさせる必要があります。 -
証明書の発行
モノやポリシーは使用する証明書にアタッチさせる必要があります。
アタッチ方法については、 証明書へのアタッチ を参考にしてください。デバイスにて使用するため、発行した証明書をダウンロードします。ダウンロードするファイルは以下の3つです。
・ ルート証明書: AmazonRootCA1.pem
・ クライアント証明書: c3c4ff2375-certificate.pem.crt
・ 秘密鍵: c3c4ff2375-private.pem.keyビルド/参照時に、上記証明書は名前を変更して利用します。
また、ダウンロードしたファイルは使用するmicroSD カードにCERTSディレクトリを生成して格納します。 -
ポリシーの作成とアタッチ
ポリシーにてデバイスがアクセスできるAWS IoT リソースが決定されます。
証明書にポリシーをアタッチさせる必要があります。
ここでの証明書のファイル名は例を示すためのものです。環境によって異なるため適宜読み替えてください。 |
8.5.3. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/lte_awsiot device/sdcard
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_awsiot device/sdcard
サンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
-
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> AWS IoT using LTE example - Access Point Name (CONFIG_EXAMPLES_LTE_AWSIOT_APN_NAME) - IP type (CONFIG_EXAMPLES_LTE_AWSIOT_APN_IPTYPE) - Authentication type (CONFIG_EXAMPLES_LTE_AWSIOT_APN_AUTHTYPE) - Username used for authentication (CONFIG_EXAMPLES_LTE_AWSIOT_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_AWSIOT_APN_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type
APNプロトコル。0~2の値を設定します。0:
IPv4
, 1:IPv6
2:IPv4/v6
から選択します。Authentication type
認証タイプ。0~2の値を設定します。 0:
None
、1:PAP
、2:CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。 -
AWS-IoTを利用するためのパラメータを設定します。(ご使用の環境にあわせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> AWS IoT using LTE example - AWS IoT cert folder (CONFIG_EXAMPLES_LTE_AWSIOT_CERT)
コンフィグレーション名 デフォルト値 説明 AWS IoT cert folder
"/mnt/sd0/CERTS"
AWS-IOTと接続する際に必要な認証用ファイルの置き場所を設定します。
Application Configuration -> Spresense SDK -> Externals -> AWS IoT Device SDK for Embedded C -> AWS-IoT console - AWS_IOT_MQTT_HOST (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_MQTT_HOST) - AWS_IOT_MQTT_PORT (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_MQTT_PORT) - AWS_IOT_MQTT_CLIENT_ID (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_MQTT_CLIENT_ID) - AWS_IOT_MY_THING_NAME (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_MY_THING_NAME) - AWS_IOT_ROOT_CA_FILENAME (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_ROOT_CA_FILENAME) - AWS_IOT_CERTIFICATE_FILENAME (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_CERTIFICATE_FILENAME) - AWS_IOT_PRIVATE_KEY_FILENAME (CONFIG_EXTERNALS_AWSIOT_AWS_IOT_PRIVATE_KEY_FILENAME)
コンフィグレーション名 デフォルト値 説明 AWS_IOT_MQTT_HOST
MQTTブローカー名。ご使用のAWS-IoT環境のエンドポイントを設定します。
AWS_IOT_MQTT_PORT
443
MQTTブローカーのポート番号。AWS-IoTはデフォルト値で接続可能です。
AWS_IOT_MQTT_CLIENT_ID
"AWS-IoT-C-SDK"
MQTTのクライアントID。デバイス毎にユニークである必要があります。
AWS_IOT_MY_THING_NAME
"AWS-IoT-C-SDK"
モノの名前。
AWS_IOT_ROOT_CA_FILENAME
"rootCA.crt"
ルート証明書のファイル名。AWS-IoTサイトからダウンロードしたファイルを指定します。
AWS_IOT_CERTIFICATE_FILENAME
"cert.pem"
クライアント証明書のファイル名。AWS-IoTサイトからダウンロードしたファイルを指定します。
AWS_IOT_PRIVATE_KEY_FILENAME
"privkey.pem"
クライアント認証で用いる秘密鍵のファイル名。AWS-IoTサイトからダウンロードしたファイルを指定します。
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
AWS-IoT Coreコードのデバッグ情報を出力したい場合は、menuconfigから 'CONFIG_EXTERNALS_AWSIOT_ENABLE_IOT_DEBUG’を有効にしてビルドを行ってください。 TRACE, INFO, WARN, ERRORの情報についても、同様な設定を行うことで出力が可能になります。 その際、併せて以下のSTACKSIZEも増やす必要があります。 |
8.5.4. 動作確認
シリアルターミナルを開いて、lte_awsiot
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_awsiot
コマンドを実行します。lte_awsiot コマンドの使い方を以下に示します。
nsh> lte_awsiot <options>
- options
オプション 説明 -x
パブリッシュの繰り返し回数。デフォルト値は無限回です。
本サンプルアプリケーションはAWS-IoTにMQTTで接続し、"sdkTest/sub"トピックにサブクライブします。
サブスクライブ完了後、"sdkTest/sub"トピックにパブリッシュします。
lte_awsiot
コマンドを実行した例を以下に示します。
nsh> lte_awsiot -x 1 app_restart_cb called. reason:Modem restart by application. app_radio_on_cb called. result: 0 app_activate_pdn_cb called. result: 0 pdn.session_id : 1 pdn.active : 1 pdn.apn_type : 0x202 pdn.ipaddr[0].addr : 10.212.60.255 app_localtime_report_cb called: localtime : "19/12/13 : 14:15:16" set localtime completed: 2019/12/13,14:15:16 app_deactivate_pdn_cb called. result: 0 app_radio_off_cb called. result: 0
送信したパブリッシュメッセージはAWS-IoTコンソール上で確認できます。
動作環境によっては通信状態が不安定になり、正しく動作しないことがあります。 |
8.6. LTE Azure-IoT サンプルアプリケーション
8.6.1. 概要
本サンプルプログラムは、LTEによる通信機能とNuttXのWebClientを用いて、Azure IoT Hubに接続し、メッセージの送受信及びファイルの送受信を行うサンプルです。
8.6.3. 事前準備
8.6.3.1. デバイスの接続
SpresenseメインボードとSpresense LTE拡張ボードの接続方法、及びSIMカードの挿入方法はこちらを参照してください。 また、ネットワークに接続するためのSIMカードは LTE-M 動作確認SIM List を参照の上準備してください。
8.6.3.2. Azure IoT Hub/IoT デバイスの作成
Azure IoT Hubを利用するには、 Azure Portal からAzure IoT Hub及びIoTデバイスを作成しておく必要があります。
Azure IoT HubとIoT デバイスについては Azure Portal を使用して IoT Hub を作成する を参照し作成してください。
8.6.3.3. 接続用ファイルの作成
Azure IoT Hubに接続しSpresenseとデータの送受信を行うには、 Azure IoT サーバ証明書 と Azure IoT 設定ファイル が必要になります。 以下にそれぞれの取得方法及びファイルの保存方法について説明します。
Azure IoT サーバ証明書
Azure IoT Hubサーバへ接続するためには、Azure IoT サーバ証明書をダウンロードし、SDカードに保存しておく必要があります。
サイトAzure Portal https://portal.azure.com/
の Baltimore CyberTrust Root証明書 (ファイル名 portal-azure-com.pem)
を、 SDカードの CERTS
ディレクトリの中にコピーしてください。
SDカード
└── CERTS
└── portal-azure-com.pem
例としてFirefox webブラウザを利用したダウンロード方法を説明します。
Firefox以外のブラウザを使ったルート証明書のダウンロード方法は HTTPSで使用するサーバアクセス用ルート証明書のダウンロード方法 をご参照ください。 |
-
Azure Portal
https://portal.azure.com
にアクセスします。 -
Firefoxブラウザのアドレスバー左横の認証ボタンをクリックします。
-
安全な接続
から詳細を表示
をクリックします。 -
セキュリティ
から証明書を表示
をクリックします。 -
Baltimore CyberTrust Root
からPEM (証明書)
をクリックしportal-azure-com.pem
をダウンロードします。 -
SDカード直下に
CERTS
ディレクトリを作成し、その中にダウンロードしたportal-azure-com.pem
をコピーします。 -
コピーしたSDカードをSpresense LTE拡張ボードに挿入します。
Azure IoT 設定ファイル
lte_azureiotサンプルでAzure IoT Hubへ接続するためには、IoT Hub及びIoT デバイス名、IoT デバイスのプライマリ対象共有アクセスキー情報を含んだファイルをSDカードにコピーする必要があります。
Azure Portalで作成したAzure IoT Hub名 <IoT Hub Name>
及びIoT デバイス名 <Device ID>
と、プライマリ対象共有アクセスキー <Primary Key>
を以下のフォーマット通りに記載し resources.txt
として保存します。(プライマリ対象共有アクセスキーは、作成したIoT デバイス情報の中の 主キー
になります。)
<IoT Hub Name>
<Device ID>
<Primary Key>
そして、SDカードに azureiot
を作成しその中に resources.txt
をコピーします。
SDカード
└── azureiot
└── resources.txt
8.6.4. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションを行います。
引数に
examples/lte_azureiot
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_azureiot
必要に応じてサンプルアプリケーションのコンフィグレーションを変更します。
tools/config.py -m
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> Examples -> Azure IoT using LTE example - Access Point Name (CONFIG_EXAMPLES_LTE_AZUREIOT_APN_NAME) - IP type Selection (CONFIG_EXAMPLES_LTE_AZUREIOT_APN_IPTYPE_*) - Authentication type Selection (CONFIG_EXAMPLES_LTE_AZUREIOT_APN_AUTHTYPE_*) - Username used for authentication (CONFIG_EXAMPLES_LTE_AZUREIOT_APN_USERNAME) - Password used for authentication (CONFIG_EXAMPLES_LTE_AZUREIOT_APN_PASSWD)
コンフィグレーション名 説明 Access Point Name
アクセスポイント名
IP type Selection
APNプロトコル。0~2の値を設定します。
IPv4
,IPv6
,IPv4/v6
から選択します。Authentication type Selection
認証タイプ。0~2の値を設定します。
None
,PAP
,CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。 -
ビルドを行います。
make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.6.5. 動作確認
シリアルターミナルを開いて、lte_azureiot
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_azureiot
コマンドを実行します。lte_azureiot コマンドの使い方を以下に示します。
nsh> lte_azureiot <options> <arg1> <arg2>
- options
オプション 説明 send
Azure IoT Hubに対してメッセージを送信します。メッセージ内容は
<arg0>
に"Hello!"
などのようにコマンドを実行します。recv
Azure IoTからのメッセージを受信します。
upload
Azure IoT Hubのコンテナにファイルをアップロードします。アップロードするファイルは
<arg1>
, コンテナ上でのファイル名を<arg2>
として指定します。download
Azure IoT Hubのコンテナからファイルをダウンロードします。ダウンロードするファイル名は
<arg1>
, ダウンロードしたファイルの置き場所を<arg2>
として指定します。lte_azureiot
コマンドを実行した例を以下に示します。
8.6.5.1. メッセージを送信する場合
Azure Cloud Shell上で az iot hub monitor-events
コマンドを実行してモニターします。
8.6.5.2. メッセージを受信する場合
Azure Cloud Shell上で az iot device c2d-message send
コマンドを実行してメッセージを送信します。
Azure Cloud Shell
azure_user@Azure:~ az iot device c2d-message send -d <Device ID> --data "spresense hello azure" -n <IoT Hub Name>
Spresenseターミナル
nsh> lte_azureiot recv LTE connect... LTE connect...OK Successful Recv message: spresense hello azure LTE disconnect... lte_radio_off lte_power_off lte_finalize LTE disconnect...OK
動作環境によっては通信状態が不安定になり、正しく動作しないことがあります。 |
8.7. LTE Websocket サンプルアプリケーション(websocket_gmocoin
)
8.7.1. 概要
本サンプルプログラムは、LTE通信機能及びWebsocketライブラリを用いて、GMOコイン社で提供している仮想通貨取引情報の取得を行うものです。 GMOコイン社のAPIについては、 GMOコイン Public WebSocket API(外部リンク) をご参照ください。
8.7.1.1. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード
-
microSD カード
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。
本サンプルプログラムではネットワークに接続するため、SIM カードが必要です。
LTE-M 動作確認SIM Listをご確認ください。
8.7.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションを行います。
引数に
examples/lte_websocket_gmocoin
を指定してコンフィグレーションを実行します。tools/config.py examples/lte_websocket_gmocoin
-
ビルドを実行します。
make
コマンドを実行しビルドします。make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.7.3. TLS証明書のコピー
本サンプルプログラムを実行するためには、GMOコイン社のAPI用サーバルート証明書が必要です。 以下の手順に従い、証明書をダウンロードし所定の場所にコピーしてください。
-
https://api.coin.z.com/
にアクセスしルート証明書をダウンロードします。HTTPSで使用するサーバアクセス用ルート証明書のダウンロード方法 を参考に
https://api.coin.z.com/
用のルート証明書をダウンロードします。 -
ダウンロードしたルート証明書を
rootcacert_r3.cer
にリネームし、SDカードのトップディレクトリにコピーします。 -
コピー先のSDカードをLTE拡張ボードに挿入します。
8.7.4. 動作確認
シリアルターミナルを開いて、LTEネットワークへの接続を行い websocket_gmocoin
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_sysctl
コマンドを実行しLTEデーモンを開始します。以下の例は、APN名が
internet
、認証方式がCHAP
、ユーザ名がuser
、そしてパスワードがpass
の場合の例です。nsh> lte_sysctl -a internet -v 2 -u user -p pass start
-
NuttShell から
ifup
コマンドを実行しLTEネットワークへの接続を行います。nsh> ifup eth0 ifup eth0...OK
-
NuttShell から
websocket_gmocoin
コマンドを実行します。websocket_gmocoin コマンドの使い方を以下に示します。
nsh> websocket_gmocoin <command> <symbol>
- command
-
サブスクライブするか解除するかを選択します。
-
subscribe: サブスクライブする
-
unsubscribe: サブスクライブを解除する
-
- symbol
-
サブスクライブ(あるいは解除)する取引情報の種類を選択します。 使用できる
symbol
は以下のとおりです。BTC : Bitcoin ETH : Ethereum BCH : Bitcoin Cash LTC : Litecoin XRP : Ripple XEM : New Economy Movement XLM : Stellar BTC_JPY : Bitcoin - Yen ETH_JPY : Ethereum - Yen BCH_JPY : Bitcoin Cash - Yen LTC_JPY : Litecoin - Yen XRP_JPY : Ripple - Yen
websocket_gmocoin
コマンドを実行した例を以下に示します。正常にコマンドを実行できた場合は、取引情報の更新があるタイミングで取引情報がJsonフォーマットで出力されます。
nsh> websocket_gmocoin subscribe BTC nsh> wss main task started. {"channel":"ticker","ask":"5365700","bid":"5365300","high":"5452200","last":"5365500","low":"5288150","symbol":"BTC","timestamp":"2022-04-07T05:20:17.468Z","volume":"257.2177"} {"channel":"ticker","ask":"5365950","bid":"5365300","high":"5452200","last":"5365900","low":"5288150","symbol":"BTC","timestamp":"2022-04-07T05:21:39.003Z","volume":"257.1498"} {"channel":"ticker","ask":"5365950","bid":"5365300","high":"5452200","last":"5365950","low":"5288150","symbol":"BTC","timestamp":"2022-04-07T05:21:39.003Z","volume":"257.1498"} {"channel":"ticker","ask":"5366150","bid":"5365300","high":"5452200","last":"5366150","low":"5288150","symbol":"BTC","timestamp":"2022-04-07T05:21:59.119Z","volume":"257.2198"} {"channel":"ticker","ask":"5366200","bid":"5365300","high":"5452200","last":"5366200","low":"5288150","symbol":"BTC","timestamp":"2022-04-07T05:22:24.583Z","volume":"257.2297"}
8.8. SMS サンプルアプリケーション
8.8.1. 概要
本サンプルプログラムは、SMS(Short Message Service) の送信及び受信を行うサンプルです。
8.8.1.1. 動作環境
-
Spresense メインボード
-
Spresense LTE拡張ボード
-
SIM カード (SMS機能付き)
接続方法は、SpresenseメインボードとSpresense LTE拡張ボードの接続方法を参照してください。 また、SMSを利用するためにはSMS対応のSIMカードを用意する必要があります。 LTE-M 動作確認SIM List を参照の上SMSに対応したプランのSIMカードをご用意ください。
8.8.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/sms_send
とexamples/sms_recv
を指定してコンフィグレーションを実行します。tools/config.py examples/sms_send examples/sms_recv
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
8.8.3. 動作確認
シリアルターミナルを開いて、 sms_recv
コマンド、 sms_send
コマンドを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
lte_sysctl
コマンドとifup
コマンドを実行してネットワークに接続します。lte_sysctl
コマンドとifup
コマンドの詳細は こちら を参照してください。nsh> lte_sysctl <options> start nsh> nsh> ifup eth0 ifup eth0...OK
-
NuttShell から
sms_recv
コマンドを実行してSMSの受信待ちをします。nsh> sms_recv &
コマンドの最後に
&
をつけることで、コマンドをバックグラウンドで実行できます。sms_recv
コマンドはSMSの受信待ちを行い、SMSを受信した際にNuttShellに受信メッセージを出力します。 -
NuttShell から
sms_send
コマンドを実行してSMSを送信します。sms_send コマンドの使い方を以下に示します。
nsh> sms_send <phone number> <text message> [<enable status report>]
- <phone number>
-
宛先電話番号
- <text message>
-
メッセージ本文
- <enable status report>
-
SMSの受け取り確認通知を受信するかどうかのフラグ。 このパラメータは省略可能です。
値 説明 0
SMSの受け取り確認通知を受信しません
1
SMSの受け取り確認通知を受信します
sms_send
コマンドと sms_recv
コマンドを実行した例を以下に示します。
nsh> sms_recv & sms_recv [14:100] nsh> socket open success:3 nsh> nsh> sms_send 080xxxxxxxx こんにちは 1 socket open success:3 Successfully sent SMS to 080xxxxxxxx Get reference id[0] = 241
SMSを端末が受信した際はNuttShellに以下のように出力されます
nsh> ----------------------------------------------- sent time : 21/12/17 : 13:48:52 +09 message type : Deliver message source address length: 22 message body length : 10 source address : 080xxxxxxxx message body : こんにちは
sms_send
コマンドで <enable status report>
パラメータに 1
を入力して実行した場合、送信したSMSが宛先に到達した際に以下のようなメッセージがNuttShellに出力されます。
sent time : 21/12/17 : 13:48:52 +09 message type : Status report message source address length: 0 message body length : 10 reference ID : 241 status : success discharge time : 21/12/17 : 13:48:57 +09
SMS受信時に表示される各パラメータについて説明します。
パラメータ名 | 説明 |
---|---|
|
SMSがプロバイダのサーバに送信された時刻を表します。 |
|
受信したメッセージの種別を表します。 |
|
UCS2文字セットでエンコードされた送信元電話番号のbyte数を表します。 |
|
UCS2文字セットでエンコードされた本文のbyte数を表します。 |
|
送信元電話番号です。 |
|
受信したSMSの本文です。 |
|
送信したSMSの、どの受け取り確認通知かどうかを参照するIDです。 |
|
送信したSMSの到達結果を表します。 宛先にSMSが到達した場合は、 |
|
送信したSMSが宛先に到達した時刻を表します。 |
8.9. LTEのネットワークデーモンを使ってネットワーク接続を行う
LTEのネットワークデーモンを使ってネットワーク接続するコマンド(lte_sysctl
)について説明します。
ネットワーク接続に成功するとwgetなどのコマンドを使用してデータ通信が可能となります。
Spresense SDK v2.3.0 からコマンド名が lte_daemon から lte_sysctl に変わりました。v2.2.0以前のSDKをお使いの方は下記説明中の lte_sysctl を lte_daemon とお読み替えください。
|
8.9.1. lte_sysctl
コマンドについて
lte_sysctl
コマンドは、NuttShellコマンドライン上でLTEの電源・通信制御を行うコマンドです。
nsh> lte_sysctl <options> <action>
このコマンドを使うことで wget
や nslookup
などの通信系コマンドでネットワーク通信が可能になります。
このコマンドには action
というサブコマンドがあり、それぞれの機能は以下の通りになっています。
- サブコマンド (
<action>
)
action | 説明 |
---|---|
|
LTEのネットワークデーモンを開始します。 |
|
LTEのネットワークデーモンを停止します。 |
|
設定済みのアクセスポイント情報及び通信方式、LTEモジュールのファームウェアバージョンを表示します。 |
|
LTEモジュールの設定値を工場出荷時の値に戻します。 (※追加コンフィグレーションが必要) |
また、 start
サブコマンドには以下のようなオプションがあります。
-
start
サブコマンドオプション (<options>
)
オプション | 説明 |
---|---|
|
アクセスポイント名(APN)。 |
|
APNタイプ。16進数の値を設定します。詳細な値については lte_apn_setting.ip_type を参照してください。 |
|
APNプロトコル。0~2の値を設定します。(0: |
|
認証タイプ。0~2の値を設定します。 (0: |
|
APNのユーザ名。 認証タイプに 0: |
|
APNのパスワード。 認証タイプに 0: |
|
LTEの通信方式。Cat.M1を使う場合は |
8.9.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/lte
を指定してコンフィグレーションを実行します。tools/config.py feature/lte
APN情報を予め設定するコンフィグレーション方法は APN設定をデフォルト設定から変更する手順について を参照してコンフィグレーションを更新してください。
factoryreset
サブコマンドを有効にするためには factoryresetサブコマンドを有効にする手順について を参照してコンフィグレーションを更新してください。 -
make
を実行してビルドします。make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
LTEを使用したexample(examples/lte_http_getなど)のコンフィグレーションでも
CONFIG_LTE_SYSCTL
が有効になっているためそのままお使い頂けます。
8.9.3. 動作確認
8.9.3.1. start
サブコマンドを使ってLTE接続を開始する場合
-
NuttShell から
lte_sysctl
をstart
サブコマンドで実行しLTEのデーモンを開始ます。以下のコマンドは APN名が
internet
、認証方式がCHAP
、ユーザー名がuser
、パスワードがpass
の例になります。nsh> lte_sysctl -a internet -v 2 -u user -p pass start
-
NuttShell から
ifup eth0
コマンドを実行しLTEのネットワークインタフェースを有効にします。以下のように
ifconfig
コマンドを実行することによってネットワークアドレスが割り当てられていることがわかります。nsh> ifup eth0 ifup eth0...OK nsh> nsh> ifconfig eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 at UP inet addr:100.92.28.11 DRaddr:0.0.0.0 Mask:0.0.0.0 inet6 addr: ::/0 inet6 DRaddr: ::/0
-
ネットワークに接続した状態で、NuttShell から
wget
コマンドを実行してインターネット上に置かれているファイルのURLを指定しファイルをダウンロードします。nsh> ifconfig eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 at UP inet addr:100.92.28.11 DRaddr:0.0.0.0 Mask:0.0.0.0 inet6 addr: ::/0 inet6 DRaddr: ::/0 nsh> nsh> wget -o /mnt/spif/index.html http://www.example.com/index.html nsh> nsh> nsh> cat /mnt/spif/index.html <!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html> nsh> nsh>
8.9.3.2. stat
サブコマンドを使って接続状況を確認する場合
-
NuttShell から
lte_sysctl
をstat
サブコマンドで実行しLTEの接続状況を確認します。nsh> lte_sysctl stat Daemon state : running APN Name: internet IP type: IPv4 Authentication: CHAP Username: user Password: pass RAT: CAT-M1 VER: RK_02_01_02_10_108_54
上記の例ではデーモンの状態が
running
(動作中)で、APN名がinternet
、APNのIPタイプがIPv4
、認証タイプがCHAP
、ユーザ名がuser
、パスワードがpass
、通信方式がCAT-M1
、そしてLTEモジュールのファームウェアがRK_02_01_02_10_108_54
であることを示しています。
8.9.3.3. stop
サブコマンドを使ってLTE接続を終了する場合
-
NuttShell から
ifdown eth0
コマンドを実行しLTEのネットワークインタフェースを無効にします。以下のように
ifconfig
コマンドを実行することによってネットワークアドレスの割り当てが解除されていることがわかります。nsh> ifdown eth0 ifdown eth0...OK nsh> nsh> ifconfig eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 at DOWN inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0 inet6 addr: ::/0 inet6 DRaddr: ::/0
-
NuttShell から
lte_sysctl
をstop
サブコマンドで実行しLTEのデーモンを終了します。nsh> lte_sysctl stop nsh>
8.9.3.4. factoryreset
サブコマンドを使ってLTEモジュールの設定値を工場出荷時の状態に戻す場合
-
NuttShell から
lte_sysctl factoryreset
コマンドを実行します。nsh> lte_sysctl factoryreset Factory reset running... Please do not turn off the device. Factory reset takes around 30 sec. Factory reset done.
factoryreset
サブコマンドを有効にするためには factoryresetサブコマンドを有効にする手順について を参照してコンフィグレーションを更新してください。このコマンドの実行には30秒程度時間を要します。実行中はSpresenseの電源を切らないようにご注意ください。
このコマンドはLTEモジュールのファームウェアのバージョンが
RK_02_01_
から始まるボードでのみ使えます。
それ以外のボードではお使いいただけません。
8.9.4. APN設定をデフォルト設定から変更する手順について
ここではlte_sysctlの引数に指定するAPN設定のデフォルト値を変更する手順を示します。
-
lte_sysctlのコンフィグレーションを変更します。
tools/config.py -m
-
APNのパラメータを設定します。(ご使用のSIMに合わせて設定してください。)
Application Configuration -> Spresense SDK -> System tools -> lte_sysctl system command - Access Point Name (CONFIG_LTE_SYSCTL_APN_NAME) - IP type Selection - Authentication type Selection - Username used for authentication (CONFIG_LTE_SYSCTL_APN_USERNAME) - Password used for authentication (CONFIG_LTE_SYSCTL_APN_PASSWD)
コンフィグレーション名 デフォルト値 説明 Access Point Name
アクセスポイント名
IP type Selection
0:
IPv4
APNプロトコル。0~2の値を設定します。0:
IPv4
, 1:IPv6
2:IPv4/v6
から選択します。Authentication type Selection
0:
None
認証タイプ。0~2の値を設定します。 0:
None
、1:PAP
、2:CHAP
から選択します。Username used for authentication
ユーザ名。 認証タイプに
None
を選択した場合、設定は無視されます。Password used for authentication
パスワード。 認証タイプに
None
を選択した場合、設定は無視されます。
8.9.5. factoryreset
サブコマンドを有効にする手順について
ここではlte_sysctlで factoryreset
サブコマンドを有効にする手順を示します。
-
lte_sysctlのコンフィグレーションを変更します。
tools/config.py -m
-
Enable factoryreset sub-command
にチェックを入れます。Application Configuration -> Spresense SDK -> System tools -> lte_sysctl system command [*] Enable factoryreset sub-command
9. Digital Filter チュートリアル
9.1. digital_filter サンプルアプリケーション
この章では、digital_filterに関するサンプルアプリケーションの動作手順を示します。 このサンプルアプリケーションには、3つの NuttShell コマンドが含まれています。
NuttShell command name | Overview |
---|---|
fir |
入力されたWAVファイルに対して、各種(ローパス、ハイパス、帯域通過、帯域阻止)フィルタでフィルタ処理を行い、結果を指定のwavファイルに書き出します。 |
decimation |
入力されたWAVファイルに対して、デシメーション(データの間引き)を行い、結果を指定のwavファイルに書き出します。 |
envelope |
機械部品の劣化によるインパルス振動を検出するような場合によく用いられる、H関数を実装したサンプルコマンドになります。 |
9.1.1. ソースコード
このサンプルのソースコードは、 spresense/examples/digital_filter ディレクトリ内に入っています。
上記ディレクトリ内のにあるファイルは以下の通りです。
spresense/examples/digital_filter/
. ├── Kconfig ├── Make.defs ├── Makefile ├── fir_decimator_main.c ├── fir_envelope_main.c ├── fir_filter_main.c ├── wav.c └── wav.h
ソースコードファイルの概要は以下の通りです。
このサンプルでは、一つのフォルダ内で、3つのNuttShellコマンドがビルドされるようになっています。
File name | Overview |
---|---|
fir_filter_main.c |
fir コマンドサンプルソースコード |
fir_decimator_main.c |
decimation コマンドサンプルソースコード |
fir_envelope_main.c |
envelope コマンドサンプルソースコード |
wav.c |
WAVファイルの読み書きするためのユーティリティソースコード |
wav.h |
WAVファイ読み書きするためのユーティリティコードのヘッダファイル |
9.1.2. ビルドおよび実行手順
9.1.2.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/digital_filter
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/digital_filter make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を設定しています。
tools/flash.sh -c /dev/ttyUSB0 nuttx.spk
9.1.3. 動作確認
9.1.3.1. 事前準備
まずフィルタ処理を行う対象のWAVファイルをSpresense 拡張ボートのSDカードにコピーします。
PCにSDカードスロットがある場合、SDカードをPCに入れて、対象のWAVファイルをSDカードにコピーすることができますが、ここでは、カードスロットがないPCをお持ちの方向けに、Spresenseの拡張ボード側のmicroUSBを使ってUSBマスストレージとして認識させ、PCにファイルを保存する方法を記載します。
まず、Spresense拡張ボードのmicroSDカードスロットに、microSDカードを挿入し、Spresense拡張ボードのmicroUSBコネクタをPCと接続します。
SpresenseメインボードのmicroUSBポートとSpresense拡張ボードのmicroUSBポート両方をPCに接続してください。 |
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
ターミナルでSpresenseボードに入ると、以下のようにNuttShellのプロンプトが表示されます。
nsh>
-
USBマスストレージでPCにマウントします。
NuttShell上で、
msconn
と入力し、USBマスストレージを有効にします。nsh> msconn
これで、Spresense 拡張ボードに挿入したSDカードが、PC上にストレージデバイスとして接続されます。
-
フィルタ処理を行う入力WAVファイルをSDカードにコピーします。
このストレージデバイスの中に、フィルタ処理を行う入力信号となる、WAVファイルをコピーします。(仮にそのファイル名を
input.wav
とします) -
USBマスストレージをアンマウントします。
コピーが終わったら、NuttShellプロンプト上で、
msdis
を実行して、PCのストレージデバイス接続を終了しておきます。nsh> msdis
マスストレージをアンマウントしておかないと、サンプルのコマンドを実行した際、結果が正しく書き出されない場合があります。
これで事前準備が完了しました。
あとは各コマンドを使って実際にフィルタ処理を行ます。
9.1.3.2. fir コマンドの動作確認
firコマンドは、入力WAVファイルに対して、FIRを用いた(ローパス、ハイパス、帯域通過、帯域停止)フィルタをかけ、結果を指定されたWAVファイルに書き出すコマンドになっています。
firコマンドのコマンド仕様は以下のようになります。
-
nsh> fir <input wav file> <lpf/hpf> <transition width(Hz)> <cutoff freq(Hz)> <output wav file>
Argument Overview <input wav file>
入力WAVファイル名
<lpf/hpf>
フィルタの種類を指定
lpf:ローパスフィルタ
hpf:ハイパスフィルタ<transition width(Hz)>
遷移帯域幅
この値が小さければ小さいほど処理が重く、メモリが多く消費される代わりにフィルタのカットオフが急峻になります。
反対に大きいほど、処理が軽くメモリ消費量も少ない代わりに、カットオフがなだらかになります。<cutoff freq(Hz)>
フィルタのカットオフ周波数
<output wav file>
フィルタ結果の出力先ファイル名(WAV形式で保存されます)
もしくは
-
nsh> fir <input wav file> <bpf/bef> <transition width(Hz)> <cutoff1 freq(Hz)> <cutoff2 freq(Hz)> <output wav file>
Argument Overview <input wav file>
入力WAVファイル名
<bpf/bef>
フィルタの種類を指定
bpf:帯域通過フィルタ
bef:帯域停止フィルタ<transition width(Hz)>
遷移帯域幅
この値が小さければ小さいほど処理が重く、メモリが多く消費される代わりにフィルタのカットオフが急峻になります。
反対に大きいほど、処理が軽くメモリ消費量も少ない代わりに、カットオフがなだらかになります。<cutoff1 freq(Hz)>
低域側のフィルタのカットオフ周波数
<cutoff2 freq(Hz)>
高域側のフィルタのカットオフ周波数
<output wav file>
フィルタ結果の出力先ファイル名(WAV形式で保存されます)
事前準備でSDカードにコピーしたWAVファイル(仮に、 input.wav
とします)に対して、5kHzのローパスフィルタ(遷移帯域幅3kHz)をかけて、output_lpf.wavというファイルに結果を保存したい場合、
nsh> fir /mnt/sd0/input.wav lpf 3000 5000 /mnt/sd0/output_lpf.wav
とします。
また、5kHz〜15kHzの帯域通過フィルタ(遷移帯域幅3kHz)をかけて、output_bpf.wavというファイルに結果を保存したい場合、
nsh> fir /mnt/sd0/input.wav bpf 3000 5000 15000 /mnt/sd0/output_bpf.wav
とします。
SpresenseのターミナルからSDカードのファイルにアクセスする場合、そのマウントポイントは、 |
あとは、 フィルタ処理した結果ファイルのPCへのコピー方法 を参考に結果ファイルをPCに書き出して、音を聴くことでフィルタ処理の結果を耳で確認することができます。
9.1.3.3. decimate コマンドの動作確認
decimateコマンドは、入力WAVファイルに対して、指定された間引き率でデータの間引きを行うコマンドになっています。
decimateコマンドのコマンド仕様は以下のようになります。
-
nsh> decimate <input wav file> <Decimation Factor> <TransitionWidth or TapNum> <output wav file>
Argument Overview <input wav file>
入力WAVファイル名
<Decimation Factor>
間引き率
正の整数を入力します。<TransitionWidth or TapNum>
遷移帯域幅 もしくは、Tap数
内部で利用するFIRのローパスフィルタの遷移帯域幅もしくはTap数を指定します。
値が1000未満であればTap数、1000以上であれば遷移帯域幅と解釈されます。
また、0を指定した場合、フィルタなしで単にデータを間引くだけの処理を行ます。<output wav file>
フィルタ結果の出力先ファイル名(WAV形式で保存されます)
例えば、入力のWAVファイル input.wav
に対して、3kHzの遷移帯域幅のフィルタで、1/16にデータを間引き、結果をoutput_dec.wavに保存する場合、
nsh> decimate /mnt/sd0/input.wav 16 3000 /mnt/sd0/output_dec.wav
と入力します。
あとは、 フィルタ処理した結果ファイルのPCへのコピー方法 を参考に結果ファイルをPCに書き出して、音を聴くことでフィルタ処理の結果を耳で確認することができます。
9.1.3.4. envelope コマンドの動作確認
envelopeコマンドは、入力WAVファイルに対して、2kHz〜15kHzの帯域通過フィルタをかけたのち、その絶対値を取り、その後1kHzのローパスフィルタをかける処理を行う一連の処理を行い、結果を指定したファイルにWAV形式で書き出すコマンドになっています。
この処理は、機械部品の劣化によるインパルス振動を安定して検波する際に用いられる手法の一つです。
H関数に関しては以下のサイトが参考になるかと思います。 |
envelopeコマンドのコマンド仕様は以下のようになります。
-
nsh> envelope <input wav file> <output wav file>
Argument Overview <input wav file>
入力WAVファイル名
<output wav file>
結果の出力先ファイル名(WAV形式で保存されます)
入力のWAVファイル input.wav
に対して、envelope処理を行、結果をoutput_env.wavに保存する場合、
nsh> envelope /mnt/sd0/input.wav /mnt/sd0/output_env.wav
と入力します。
あとは、 フィルタ処理した結果ファイルのPCへのコピー方法 を参考に結果ファイルをPCに書き出して、波形データを表示することで、envelope処理の結果を見ることができるようになります。
9.1.3.5. フィルタ処理した結果ファイルのPCへのコピー方法
各コマンドを実行した結果のファイルを取り出すために、再度SDカードをPCにマウントし、ファイルをPCにコピーします。
-
USBマスストレージでPCにマウントします。
NuttShell上で、
msconn
と入力し、USBマスストレージを有効にします。nsh> msconn
これで、Spresense 拡張ボードに挿入されているSDカードが、再度PC上にストレージデバイスとして接続されます。
-
SDカードに保存されているコマンドの結果ファイルをPCにコピーします。
PC上で接続されたストレージデバイスを開いて、fir/decimate/envelopeの各コマンドの実行で得られた結果のWAVファイルをPCにコピーします。
-
USBマスストレージをアンマウントします。
コピーが終わったら、NuttShellプロンプト上で、
msdis
を実行して、PCのストレージデバイス接続を終了しておきます。nsh> msdis
これで、PCにコピーした結果ファイルを再生したり任意の波形表示ツールを使って表示することで、コマンドの実行結果を確認することができます。
10. Network チュートリアル
10.1. ftp サンプルアプリケーション
この章では、NuttXの標準サンプルである、ftpc及びftpdに関するサンプルアプリケーションの動作手順を示します。
10.1.1. ソースコードパス
このサンプルのソースコードは、
-
FTP Client側:
sdk/apps/examples/ftpc
-
FTP Server側:
sdk/apps/examples/ftpd
にそれぞれ入っています。
10.1.2. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。 サーバ用とクライアント用の2セット用意するか、サーバ用に1セットとクライアント用にftp clientがインストールされたPCを1台用意する必要があります。
Spresense Main Board
IDY Wi-Fi Add-on Board iS110B
10.1.3. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/ftp
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/ftp make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
Spresenseをもう1台使う場合はそちらにも同じnuttx.spkを書き込んでください。
10.1.4. 動作確認
シリアルターミナルを開いて、Wi-Fiに接続し、ftpd_start
コマンドを実行して、
クライアントの接続を待ちます。
この例では、SpresenseのSPI Flash上に適当なファイル(test_ftp.txt)を作成して、
それをクライアントが取得(get)し、また、PC側からSpresenseに対して適当なファイルを送信(put)する動作を確認します。
-
シリアルターミナルを起動します。
下記の例では、シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定してminicomで接続しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShellでSPI Flash上に適当なテキストファイルを作成します。
以下のコマンドを叩いて、test_ftp.txtというファイルを作成します。
nsh> echo This is Spresense FTPD > /mnt/spif/test_ftp.txt nsh> echo Everything is OK. >> /mnt/spif/test_ftp.txt
catコマンドを使って、正しくファイルが作られているかを確認します。
nsh> cat /mnt/spif/test_ftp.txt This is Spresense FTPD Everything is OK.
-
NuttShell から Wi-Fi接続を行い、
ftpd_start
コマンドを実行します。実機をAPモードでWi-Fiの設定を行い、ftpd_startでFTPデーモンを起動してClientからの接続待ち状態にします。 下記の例では、APモードでWi-Fiを起動し、SSIDをspresense_net、パスワードを0123456789としています。 ifconfigコマンドでIPアドレスを確認して、FTPデーモンを起動します。
nsh> gs2200m -a 1 spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:192.168.11.1 DRaddr:192.168.11.1 Mask:255.255.255.0 nsh> ftpd_start Initializing the network Starting the FTP daemon FTP daemon [10] started Adding accounts: 1. Root account: USER=root PASSWORD=abc123 HOME=(none) 2. User account: USER=ftp PASSWORD=(none) HOME=(none) 3. User account: USER=anonymous PASSWORD=(none) HOME=(none)
このftpdのサンプルでは、上記3つのアカウントが登録されています。これらのアカウント情報は、クライアントから接続する際に必要になります。
-
PCからSpresenseのFTPサーバに接続します。
上記の状態でPC側からSpresenseと同一のSSIDにWi-Fiを接続し、ftpコマンドでSpresense側に接続します。
以下、Spresense側のIPアドレスが192.168.11.1として説明します。お使いの環境に合わせて適宜読み替えてください。 PCから接続すると、ユーザ名とパスワードが要求されるので、上記の3つのアカウントから好きなものを選び入力して接続を行なってください。以下の例では、rootアカウントを利用しています。
(なお、お使いのPC環境によって、メッセージの出方は異なります)ftp 192.168.11.1 Connected to 192.168.11.1. 220 NuttX FTP Server Name (192.168.11.1:user): root 331 Password required for root Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp>
あとは通常のftpのコマンドでファイルを取り出したり書き込んだりすることが出来ます。 まず、先ほど作成した/mnt/spif/test_ftp.txtを取得してみます。
ftp> cd /mnt/spif 250 CWD command successful ftp> get test_ftp.txt local: test_ftp.txt remote: test_ftp.txt 229 Entering Extended Passive Mode (|||50000|). 150 Opening data connection 100% |**************************************************************************************************************************| 41 0.50 KiB/s 00:00 ETA 226 Transfer complete 41 bytes received in 00:00 (0.50 KiB/s)
無事に転送が成功すると、上記のようなメッセージがPC側に出て来ます。
FTPクライアントアプリを終了し、test_ftp.txtがあるか、中身が同じものかを確認します。ftp> quit 221 Good-bye $ ls test_ftp.txt test_ftp.txt $ cat test_ftp.txt This is Spresense FTPD Everything is OK.
無事に取得が出来たことがわかります。
続いて、ファイルの書き込みを行なってみます。 まず、PC側でファイルを準備します。(ファイル名:test_pc.txt)echo "This is Host PC." > test_pc.txt echo "Nothing wrong with me." >> test_pc.txt cat test_pc.txt This is Host PC. Nothing wrong with me
再度FTPクライアントを接続し、作成したファイルをputコマンドでSpresenseに転送します。
ftp 192.168.11.1 Connected to 192.168.11.1. 220 NuttX FTP Server Name (192.168.11.1:user): root 331 Password required for root Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp> put test_pc.txt /mnt/spif/test_pc.txt local: test_pc.txt remote: /mnt/spif/test_pc.txt 229 Entering Extended Passive Mode (|||50000|). 150 Opening data connection 100% |**************************************************************************************************************************| 40 63.61 KiB/s 00:00 ETA 226 Transfer complete 40 bytes sent in 00:00 (0.84 KiB/s)
無事に転送が完了すると上記のようなメッセージがPC側で表示されます。
Spresense側で転送されたファイルを見てみます。
Spresenseに接続しているminicomターミナル上で以下のように確認が出来ます。 (nsh> というプロンプトが見えない場合、Enterキーを押せば出て来ます。)nsh> cat /mnt/spif/test_pc.txt This is Host PC. Nothing wrong with me. nsh>
-
もう1台のSpresenseからクライアント接続する場合
もう1台のSpresenseからクライアント接続を行う場合を説明します。
サーバ側のSpresenseは上記のままで、Client側のSpresenseにminicomで接続し、Wi-Fi接続します。 サーバ側のSpresense同様にminicomでSpresenseのターミナルに接続してください。この例では、シリアルポートとして /dev/ttyUSB1 を、baudrate として 115200 bps を設定してminicomで接続しています。minicom -D /dev/ttyUSB1 -b 115200
続いて、Wi-Fiに接続後、ftpcコマンドでサーバに接続します。
nsh> gs2200m spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:192.168.11.2 DRaddr:192.168.11.1 Mask:255.255.255.0 nsh> nsh> ftpc 192.168.11.1 NuttX FTP Client:
NuttX標準のftpクライアントでは、特にプロンプト等は表示されません。
この状態でログインを行います。この例では、アカウントrootでログインしています。login root abc123
特になんの応答もありませんが、これでログインは成功します。
先ほどPCで取得したサーバ側のSpreseneにある、/mnt/spif/test_ftp.txtを取得してみます。get /mnt/spif/test_ftp.txt /mnt/spif/test_ftp.txt
login同様になんの応答もありませんが、これでファイルの取得が成功しています。
ftpcコマンドから抜けて、ファイルが取得出来たかを確認します。quit nfc> Exiting... nsh> cat /mnt/spif/test_ftp.txt This is Spresense FTPD Everything is OK.
無事に転送が出来ていれば、上記のようにサーバ側で作成したファイルを見ることが出来ます。
10.1.5. Tips 既存のWi-Fiネットワークに接続する場合
場合によっては、APモードではなく、Spresenseを既存でお使いのWi-Fiネットワークに接続したい場合もあるかと思います。 その場合は、実機側でのコマンド入力を以下のようにしてください。
nsh> gs2200m <接続したいSSID> <SSIDのパスワード> & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:XXX.XXX.XXX.XXX DRaddr:XXX.XXX.XXX.XXX Mask:XXX.XXX.XXX.XXX nsh> ftpd_start Initializing the network Starting the FTP daemon FTP daemon [10] started Adding accounts: 1. Root account: USER=root PASSWORD=abc123 HOME=(none) 2. User account: USER=ftp PASSWORD=(none) HOME=(none) 3. User account: USER=anonymous PASSWORD=(none) HOME=(none)
IPアドレスやネットマスクは、そのSSIDによって割り振られ、ifconfigで確認できます。
10.2. tcpecho サンプルアプリケーション
この章では、NuttXの標準サンプルである、tcpechoに関するサンプルアプリケーションの動作手順を示します。 TCPのシンプルなエコーサーバのサンプルになります。
10.2.2. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。
Spresense Main Board
IDY Wi-Fi Add-on Board iS110B
ホストPC (telnetクライアントがインストールされていること)
10.2.3. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/tcpecho
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/tcpecho make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
10.2.4. 動作確認
シリアルターミナルを開いて、Wi-Fiに接続し、tcpecho コマンドを実行して、クライアントから接続してechoバックを確認します。
-
シリアルターミナルを起動します。
まず、シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定してminicomで接続しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
tcpecho
コマンドを実行します。実機をAPモードでWi-Fiの設定を行い、tcpechoを起動してClientからの接続待ち状態にします。 下記の例では、APモードでWi-Fiを起動し、SSIDをspresense_net、パスワードを0123456789としています。 ifconfigコマンドでIPアドレスを確認して、tcpechoを起動します。
nsh> gs2200m -a 1 spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:192.168.11.1 DRaddr:192.168.11.1 Mask:255.255.255.0 nsh> tcpecho
この状態でPC側から上記のSSIDにWi-Fiを接続し、telnetで192.168.11.1のポート80番に接続します。
telnet 192.168.11.1 80 Trying 192.168.11.1... Connected to 192.168.11.1. Escape character is '^]'.
後はPCで適当な文字を打ってEnterキーを打てば、エコーバックが帰ってきます。
hello hello <- エコーバック文字列 Spresense Spresense <- エコーバック文字列
10.3. tcpblaster サンプルアプリケーション
この章では、NuttXの標準サンプルである、tcpblasterに関するサンプルアプリケーションの動作手順を示します。 TCPで接続したserver / client間でデータの送受信を行い、その転送レートを計測するサンプルです。
10.3.2. 動作環境
このサンプルを動作させるには、以下のハードウェアを2セット使う前提となっています。 なお、対向をPCにして、1セットのみで動作させることも可能です。 最後にTipsとして、コンフィグの変更方法を載せています。
Spresense Main Board
IDY Wi-Fi Add-on Board iS110B
10.3.3. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/tcpblaster
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/tcpblaster make
-
nuttx.spk
を Spresense ボードへ書き込みます。2つの機材に同じプログラムを焼き込みます。 この例では シリアルポートとして /dev/ttyUSB0, /dev/ttyUSB1 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk tools/flash.sh -c /dev/ttyUSB1 -b 500000 nuttx.spk
10.3.4. 動作確認
シリアルターミナルを開いて、Wi-Fiに接続し、tcpserver / tcpclient コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、2つのminicom ターミナルを使用する例です。 まず、一つ目のターミナルから、シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定してminicomで接続しています。
minicom -D /dev/ttyUSB0 -b 115200
まず、二つ目も同様に、シリアルポートを /dev/ttyUSB1 として接続しています。
minicom -D /dev/ttyUSB1 -b 115200
-
それぞれのNuttShell から
tcpserver
もしくはtcpclient
コマンドを実行します。まず、片方の実機をAPモードでWi-Fiの設定を行います。 下記の例では、APモードでWi-Fiを起動し、SSIDをspresense_net、パスワードを0123456789としています。 Wi-Fiモジュールが正しく起動されると、IPアドレスが設定されるので、それを確認します。 ifconfigコマンドで、下記のように、IPアドレスが割り当てられます。
★ターミナル1 nsh> gs2200m -a 1 spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:56:49 at UP inet addr:192.168.11.1 DRaddr:192.168.11.1 Mask:255.255.255.0
続いてもう一方のminicomのターミナルに対して、上記で作成したAPにSTAモードで接続し、同様に割り当てられたIPアドレスを確認します。 gs2200mにてWi-Fiの設定を行なった後、5秒程度待ちます。これは、Wi-Fi APからのDHCPでのIPアドレスが付与されるなどを待つのが目的です。 無事に接続が上手く出来ると、下記のように、デフォルトルーターが上記APのアドレスになって、自己のIPアドレスが割り振られます。
★ターミナル2 nsh> gs2200m spresense_net 0123456789 & nsh> sleep 5 nsh> ifconfig eth0 Link encap:Ethernet HWaddr 3c:95:09:00:64:91 at UP inet addr:192.168.11.2 DRaddr:192.168.11.1 Mask:255.255.255.0
この状態で、tcpserverを起動してClientからの接続待ち状態にします。
★ターミナル1 nsh> tcpserver Binding to IPv4 Address: 00000000 server: Accepting connections on port 5471
続いて、tcpclientを起動します。引数に接続先のIPアドレスを設定します。 ターミナル1側のIPアドレス(この例では、192.168.11.1)を設定しています。 正しく動作すると、データの送受信が開始され、通信レートが算出されて表示されます。
★ターミナル2 nsh> tcpclient 192.168.11.1 Connecting to IPv4 Address: 010ba8c0 client: Connected Sent 50 buffers: 50.0 Kb (avg 1.0 Kb) in 0.25 Sec ( 195.1 Kb/Sec) Sent 50 buffers: 50.0 Kb (avg 1.0 Kb) in 0.16 Sec ( 308.8 Kb/Sec) Sent 50 buffers: 50.0 Kb (avg 1.0 Kb) in 0.15 Sec ( 329.8 Kb/Sec) Sent 50 buffers: 50.0 Kb (avg 1.0 Kb) in 0.17 Sec ( 282.6 Kb/Sec) Sent 50 buffers: 50.0 Kb (avg 1.0 Kb) in 0.17 Sec ( 286.9 Kb/Sec)
10.3.4.1. Tips 対向機をPCにする方法
この例では2セットのSpresenseを用いて速度計測をしていましたが、 片方をPCにすることも可能です。
その場合、上記コンフィグ手順まで終わった状態で、 menuconfigを開いて、以下のようにビルド設定を変更します。 spresense/sdk以下で、
make menuconfig
とし、
Application Configuration -> Examples -> TCP Performance Test
にある、
Second endpoint is a target
のチェックを外します。 これで、一旦cleanしてから再度ビルドを行います。
make clean make
無事にビルドが完了すると、ホスト側のプログラムとして、tcpclient
が、sdk/apps/examples/tcpblasterの下にできています。
この使い方は、上記のtcpclientと同様です。
Spresense側でtcpserverを立ち上げておき、PCからtcpclientで接続することで、
動作可能です。
11. Graphics チュートリアル
11.1. NX サンプルアプリケーション
この章では、NuttXのグラフィックスシステムである、NXに関するサンプルアプリケーションの動作手順を示します。 NuttXのグラフィックスサブシステムに関する詳細は、 NuttX NX Graphic Subsystem を参照してください。
Spresenseで動作確認をしているNXに関するサンプルコードとそれぞれのソースコードのディレクトリパスは、 下記の様になります。
サンプル名 | ソースコードパス | デフォルトコンフィグ名 | 概要 |
---|---|---|---|
fb |
sdk/apps/examples/fb |
examples/fb |
フレームバッファをダイレクトに操作するサンプル |
nx |
sdk/apps/examples/nx |
examples/nx |
NXのWindowシステムの描画に関するサンプル |
nxdemo |
sdk/apps/examples/nxdemo |
examples/nxdemo |
NXの描画に関するサンプル |
nxhello |
sdk/apps/examples/nxhello |
examples/nxhello |
NXのテキスト描画に関するサンプル |
nximage |
sdk/apps/examples/nximage |
examples/nximage |
NXのイメージ描画に関するサンプル |
nxlines |
sdk/apps/examples/nxlines |
examples/nxlines |
NXの直線描画に関するサンプル |
nxtext |
sdk/apps/examples/nxtext |
examples/nxtext |
NXのテキスト描画とポップアップウィンドウの描画に関するサンプル |
11.1.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に 上記の表の
デフォルトコンフィグ名
に記載されている値を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py <デフォルトコンフィグ名> make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
11.1.2. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。
Spresense Main Board
Spresense Extension Board
Arduino UNO LCD Connector board
ILI9341 2.2inch LCD
11.1.3. 動作確認
シリアルターミナルを開いて、nx コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
11.1.3.1. NuttShell から それぞれのコマンドを実行します。
-
fb
サンプルの場合以下の様なメッセージとともに、LCDディスプレイに様々な色の矩形が描画されます。
nsh> fb VideoInfo: fmt: 11 xres: 320 yres: 240 nplanes: 1 PlaneInfo (plane 0): fbmem: 0xd0353c0 fblen: 153600 stride: 640 display: 0 bpp: 16 Mapped FB: 0xd0353c0 0: ( 0, 0) (319,239) 1: ( 29, 21) (290,218) 2: ( 58, 42) (261,197) 3: ( 87, 63) (232,176) 4: (116, 84) (203,155) 5: (145,105) (174,134) Test finished
-
nx
サンプルの場合以下の様なメッセージとともに、LCDディスプレイにWindowが描画されます。
nsh> nx nx_main: NX handle=0xd032050 nx_main: Set background color=8087790 nx_main: Create window #1 nx_main: hwnd1=0xd03aeb0 nx_main: Screen resolution (319,239) nx_main: Set window #1 size to (159,119) nx_main: Sleeping nxeg_position1: hwnd=0xd03aeb0 size=(159,119) pos=(4,4) bounds={(0,0),(319,239)} nxeg_position1: hwnd=0xd03aeb0 size=(159,119) pos=(4,4) bounds={(0,0),(319,239)} nxeg_redraw1: hwnd=0xd03aeb0 rect={(0,0),(158,118)} more=false nx_main: Set window #1 position to (39,29) nx_main: Sleeping nxeg_position1: hwnd=0xd03aeb0 size=(159,119) pos=(39,29) bounds={(0,0),(319,239)} nxeg_redraw1: hwnd=0xd03aeb0 rect={(0,0),(158,118)} more=false nx_main: Add toolbar to window #1 nx_main: Sleeping nxeg_redraw1: hwnd=0xd03aeb0 rect={(0,0),(158,102)} more=false nxeg_tbredraw1: hwnd=0xd03aeb0 rect={(0,0),(158,15)} more=false nx_main: Create window #2 nx_main: hwnd2=0xd03af10 nx_main: Sleeping nxeg_position2: hwnd=0xd03af10 size=(0,0) pos=(0,4) bounds={(0,0),(319,239)} nx_main: Set hwnd2 size to (159,119) nx_main: Sleeping nxeg_position2: hwnd=0xd03af10 size=(159,119) pos=(4,4) bounds={(0,0),(319,239)} nxeg_redraw2: hwnd=0xd03af10 rect={(0,0),(158,118)} more=false nx_main: Set hwnd2 position to (121,91) nx_main: Sleeping nxeg_position2: hwnd=0xd03af10 size=(159,119) pos=(121,91) bounds={(0,0),(319,239)} nxeg_redraw2: hwnd=0xd03af10 rect={(0,0),(158,118)} more=false nxeg_redraw1: hwnd=0xd03aeb0 rect={(0,0),(158,41)} more=false nxeg_tbredraw1: hwnd=0xd03aeb0 rect={(0,0),(158,15)} more=false nxeg_redraw1: hwnd=0xd03aeb0 rect={(0,42),(77,102)} more=false nx_main: Add toolbar to window #2 nx_main: Sleeping nxeg_redraw2: hwnd=0xd03af10 rect={(0,0),(158,102)} more=false nxeg_tbredraw2: hwnd=0xd03af10 rect={(0,0),(158,15)} more=false nx_main: Lower window #2 nx_main: Sleeping nxeg_redraw1: hwnd=0xd03aeb0 rect={(78,42),(158,102)} more=false nx_main: Raise window #2 nx_main: Sleeping nxeg_redraw2: hwnd=0xd03af10 rect={(0,0),(158,102)} more=false nxeg_tbredraw2: hwnd=0xd03af10 rect={(0,0),(158,15)} more=false nx_main: Close window #2 nx_main: Close window #1 nx_main: Disconnect from the server nxeg_redraw1: hwnd=0xd03aeb0 rect={(78,42),(158,102)} more=false nx_listenerthread: Lost server connection: 117
-
nxdemo
サンプルの場合以下の様なメッセージがターミナルに表示され、LCDディスプレイに様々な模様が描画されます。
nsh> nxdemo nxdemo_listener: Connected nxdemo_main: NX handle=0xd031440 nxdemo_main: Screen resolution (320,240) nxdemo_main: Disconnect from the server nxdemo_listener: Lost server connection: 117
-
nxhello
サンプルの場合以下の様なメッセージがターミナルに表示され、LCDディスプレイの中央に
Hello, World!
という文字が描画されます。nsh> nxhello nxhello_main: NX handle=0xd031440 nxhello_main: Set background color=31581 nxhello_main: Screen resolution (320,240) nxhello_hello: Position (114,105) nxhello_main: Disconnect from the server nxhello_listener: Lost server connection: 117
-
nximage
サンプルの場合このサンプルでは、コマンドが
nxhello
となります。 実行すると以下の様なメッセージがターミナルに表示され、LCDディスプレイの中央にNuttXのロゴマークが描画されます。nsh> nxhello nximage_main: NX handle=0xd033d80 nximage_main: Set background color=0 nximage_listener: Connected nximage_main: Screen resolution (320,240) nximage_main: Disconnect from the server nximage_listener: Lost server connection: 117
-
nxlines
サンプルの場合以下の様なメッセージがターミナルに表示され、LCDディスプレイに円と円の中央に線が描画され続けます。
nsh> nxlines Angle: 0002bfaa vector: (184,60)->(136,180) Angle: 0002f1ed vector: (172,57)->(148,183) Angle: 00032430 vector: (160,56)->(160,184) Angle: 00035673 vector: (147,57)->(173,183) Angle: 000388b6 vector: (135,60)->(185,180) Angle: 0003baf9 vector: (124,66)->(196,174) Angle: 0003ed3c vector: (114,74)->(206,166) Angle: 00041f7f vector: (106,84)->(214,156) Angle: 000451c2 vector: (100,95)->(220,145) Angle: 00048405 vector: (97,107)->(223,133) Angle: 0004b648 vector: (96,119)->(224,121) Angle: 0004e88b vector: (97,132)->(223,108) Angle: 00051ace vector: (100,144)->(220,96) Angle: 00054d11 vector: (106,155)->(214,85) Angle: 00057f54 vector: (114,165)->(206,75)
-
nxtext
サンプルの場合以下の様なメッセージがターミナルに表示され、LCDディスプレイに様々な文字が描画されると共にポップアップ矩形が描画されます。
nsh> nxtext nxtext_initialize: Starting NX server nxtext_main: NX handle=0xd032450 nxtext_main: Set background color=31581 nxtext_listener: Connected nxtext_main: Screen resolution (320,240) nxpu_open: Create pop-up nxpu_open: Set pop-up position to (22,99) nxtext_main: Close pop-up nxpu_open: Create pop-up nxpu_open: Set pop-up position to (90,46) nxtext_main: Close pop-up nxpu_open: Create pop-up nxpu_open: Set pop-up position to (171,136) nxtext_main: Close pop-up nxpu_open: Create pop-up nxpu_open: Set pop-up position to (42,164) nxtext_main: Close pop-up nxpu_open: Create pop-up nxpu_open: Set pop-up position to (100,16) nxtext_main: Close pop-up nxpu_open: Create pop-up nxpu_open: Set pop-up position to (132,67) nxtext_main: Close pop-up nxpu_open: Create pop-up
11.1.4. Tips LCD画面のオリエンテーションの変更方法
作成されるアプリケーションによって、LCD画面の前後左右を変更したい場合、
以下のコンフィグを変更することで、LCDのオリエンテーションを変更することが可能です。
tools/config.py -m
でコンフィグメニューを開き、下記の階層にある、 LCD Orientation
の設定値を変更してください。
Device Drivers -> LCD Driver Support -> Graphic LCD Driver Support -> LCD driver selection -> LCD Orientation ()
12. FileSystem チュートリアル
12.1. SmartFS
SPI-Flash のファイルシステムに使用している SmartFS について説明します。
SmartFS ファイルシステムの詳細については以下のNuttX Wikiを参照してください。
12.1.1. 初期化&マウント処理
起動時に呼ばれる cxd56_bringup() 関数から board_flash_initialize() を呼び出します。
File: nuttx/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c
#ifdef CONFIG_CXD56_SFC
ret = board_flash_initialize();
if (ret < 0)
{
_err("ERROR: Failed to initialize SPI-Flash. %d\n", errno);
}
#endif
board_flash_initialize() 関数の中で、SPI-Flash を SmartFS ファイルシステムとして
初期化し、/mnt/spif
ディレクトリへマウントします。
File: nuttx/boards/arm/cxd56xx/common/src/cxd56_flash.c
int board_flash_initialize(void)
{
int ret;
FAR struct mtd_dev_s *mtd;
mtd = cxd56_sfc_initialize(); (1)
if (!mtd)
{
ferr("ERROR: Failed to initialize SFC. %d\n ", ret);
return -ENODEV;
}
/* use the FTL layer to wrap the MTD driver as a block driver */
ret = ftl_initialize(CONFIG_SFC_DEVNO, mtd);
if (ret < 0)
{
ferr("ERROR: Initializing the FTL layer: %d\n", ret);
return ret;
}
#if defined(CONFIG_FS_SMARTFS)
/* Initialize to provide SMARTFS on the MTD interface */
ret = smart_initialize(CONFIG_SFC_DEVNO, mtd, NULL); (2)
if (ret < 0)
{
ferr("ERROR: SmartFS initialization failed: %d\n", ret);
return ret;
}
ret = mount("/dev/smart0d1", "/mnt/spif", "smartfs", 0, NULL); (3)
if (ret < 0)
{
ferr("ERROR: Failed to mount the SmartFS volume: %d\n", errno);
return ret;
}
#elif defined(CONFIG_FS_NXFFS)
1 | Memory Technology Device (MTD) デバイスとして登録します。 |
2 | MTD デバイスを SmartFS ファイルシステムとして初期化します。 |
3 |
/dev/smart0d1 デバイスファイルを /mnt/spif へマウントします。 |
12.1.2. コンフィグレーション
SmartFS を使用するにあたり、いくつかのコンフィグレーションが存在します。
SDK としてデフォルトで設定している推奨構成(sdk/configs/default/defconfig
)を以下に示します。
Configuration | Value | Description |
---|---|---|
CONFIG_FS_SMARTFS |
y |
SmartFS ファイルシステムを有効にします |
CONFIG_SMARTFS_ERASEDSTATE=0xff |
0xff |
SPI-Flashの値が0xFFのときにErase状態を意味します。 |
CONFIG_SMARTFS_MAXNAMLEN |
30 |
ファイル名の最大長は30文字です。 |
CONFIG_SMARTFS_MULTI_ROOT_DIRS |
y |
マルチルートディレクトリをサポートしていますが、 デフォルトでは 1 つのルートディレクトリエントリを使用しています。 |
CONFIG_MTD_SMART |
y |
MTD デバイスとして SmartFS を使用します |
CONFIG_MTD_SMART_SECTOR_SIZE |
4096 |
1 セクタのサイズは 4096 バイトです。ファイルの最小単位として 1 セクタ分を使用します。 このサイズを小さくすると管理できるファイル数は増えますが、 小さくしすぎるとファイルのサーチ処理に時間がかかるようになります。 |
CONFIG_MTD_SMART_WEAR_LEVEL |
n |
これを有効にすると Read-only ファイルについても定期的にセクタ移動を行います。 Read-only ファイルについても移動中に電源がOffされてファイルが消去される可能性があるため、 途中で電源断が発生し得るシステムの場合は Disable することを推奨します。 |
CONFIG_MTD_SMART_ENABLE_CRC |
y |
CRCを使用して書き込み不良のチェックを行います。 |
CONFIG_MTD_SMART_FSCK |
y |
ファイル操作中に電源断が発生した場合など、ファイルシステムとして不整合のある状態が発生します。 これを有効にすると、起動時にファイルシステムの整合性をチェックし、ファイルとして成立していない ファイルを削除してファイルシステムを整合性の取れた状態に保ちます。 |
CONFIG_MTD_SMART_MINIMIZE_RAM |
n |
論物変換セクタをキャッシュする操作ですが、有効にするとアクセス速度が低下するため デフォルトではdisableしています。 |
12.1.3. 動作確認
NuttShell プロンプトから df
コマンドによって Filesystem を確認することができます。
nsh> df -h Filesystem Size Used Available Mounted on smartfs 4M 68K 4028K /mnt/spif procfs 0B 0B 0B /proc
/mnt/spif
が smartfs
ファイルシステムとしてマウントされていること、
トータル 4Mバイトのサイズのうち、使用サイズ (Used)、空きサイズ (Available) を確認することができます。
- ファイルを作成する
nsh> echo "This is a test file." > /mnt/spif/test.txt
- 作成されたファイルのサイズを確認する
nsh> ls -l /mnt/spif /mnt/spif: -rw-rw-rw- 21 test.txt
- ファイルの内容を確認する
nsh> cat /mnt/spif/test.txt This is a test file.
プログラムからファイル操作を行う場合は、 open/read/write/closeといった低水準入出力関数や fopen/fread/fwrite/fcloseといったファイル入出力関数を使うことができます。
12.1.4. フォーマット手順
SPI-Flash は工場出荷時に SmartFS ファイルシステムとして使用できるように初期化されています。
SPI-Flash をクリーンアップしたいときには mksmartfs
コマンドを利用することができます。
- Usage
nsh> help mksmartfs mksmartfs usage: mksmartfs [-s <sector-size>] [-f] <path> [<num-root-directories>]
- Example
nsh> mksmartfs -s 4096 -f /dev/smart0d1 1
mksmartfs
コマンドを実行後に、root directory 領域として数セクタが予約され、残りを使用することが可能です。
nsh> df -h Filesystem Size Used Available Mounted on smartfs 4M 28K 4068K /mnt/spif procfs 0B 0B 0B /proc
12.1.5. Flash 消去
起動時に /dev/smart0d1
デバイスファイルが見つからない場合や、
アプリケーションで使用している SPI-Flash 領域を完全に削除したい場合は、
flash_eraseall
コマンドを利用することができます。
flash_eraseall
コマンドを有効にするには、CONFIG_SYSTEM_FLASH_ERASEALL
を有効にしてください。
- Configuration
Application Configuration -> System Libraries and NSH Add-Ons FLASH Erase-all Command (CONFIG_SYSTEM_FLASH_ERASEALL)
- Usage
nsh> flash_eraseall usage: flash_eraseall flash_block_device
- Command
nsh> flash_eraseall /dev/mtdblock0
SPI-Flash を削除した後に SmartFS として使用する場合は、 ボードを再起動した後に、前述したフォーマット手順を参考にしてください。
12.2. FAT ファイルシステム
SD カードおよび eMMC のファイルシステムに使用している FAT ファイルシステムについて説明します。
-
SD カード: 拡張ボードやLTE拡張ボードに SD カード用のスロットが搭載されています
-
eMMC: Spresense 用のeMMC拡張ボード をサポートしています
12.2.1. 初期化&マウント処理
起動時に呼ばれる cxd56_bringup() 関数から board_sdcard_initialize() や board_emmc_initialize() を呼び出して初期化を行います。
File: nuttx/boards/arm/cxd56xx/spresense/src/cxd56_bringup.c
SD カード
#ifdef CONFIG_CXD56_SDIO
ret = board_sdcard_initialize();
if (ret < 0)
{
_err("ERROR: Failed to initialize sdhci. \n");
}
#endif
eMMC
#if defined(CONFIG_CXD56_EMMC) && !defined(CONFIG_CXD56_EMMC_LATE_INITIALIZE)
/* Mount the eMMC block driver */
ret = board_emmc_initialize();
if (ret < 0)
{
_err("ERROR: Failed to initialize eMMC: %d\n", ret);
}
#endif
SD カードの処理
board_sdcard_initialize() 関数の中で、
SD カードの挿抜検出をするための GPIO 割り込み設定を行います。
SD カードが挿入されている場合は、board_sdcard_enable() 関数が呼ばれ、
SD ホストコントローラを初期化し、SD カードを /mnt/sd0
ディレクトリへマウントします。
SD カードが抜かれた場合は、board_sdcard_disable() が呼ばれ、
SD ホストコントローラの終了処理を行い、/mnt/sd0
をアンマウントします。
File: nuttx/boards/arm/cxd56xx/spresense/src/cxd56_sdcard.c
int board_sdcard_initialize(void)
{
#ifdef CONFIG_MMCSD_HAVE_CARDDETECT
/* Configure Interrupt pin with internal pull-up */
cxd56_pin_config(PINCONF_SDIO_CD_GPIO);
ret = cxd56_gpioint_config(PIN_SDIO_CD,
GPIOINT_PSEUDO_EDGE_FALL,
board_sdcard_detect_int,
NULL); (1)
:
}
static void board_sdcard_enable(FAR void *arg)
{
:
g_sdhci.sdhci = cxd56_sdhci_initialize(0); (2)
if (!stat("/dev/mmcsd0", &stat_sdio) == 0)
{
/* Now bind the SDHC interface to the MMC/SD driver */
ret = mmcsd_slotinitialize(0, g_sdhci.sdhci);
finfo("Successfully bound SDHC to the MMC/SD driver\n");
}
/* Handle the initial card state */
cxd56_sdhci_mediachange(g_sdhci.sdhci);
if (stat("/dev/mmcsd0", &stat_sdio) == 0)
{
if (S_ISBLK(stat_sdio.st_mode))
{
ret = mount("/dev/mmcsd0", "/mnt/sd0", "vfat", 0, NULL); (3)
}
}
:
}
static void board_sdcard_disable(FAR void *arg)
{
ret = umount("/mnt/sd0"); (4)
cxd56_sdhci_finalize(0); (5)
}
1 | SD カードの挿抜検出用の GPIO 割り込みを設定します。 |
2 | SD ホストコントローラを初期化します。 |
3 |
/dev/mmcsd0 デバイスファイルを /mnt/sd0 へマウントします。 |
4 |
/mnt/sd0 をアンマウントします。 |
5 | SD ホストコントローラの終了処理を実行します。 |
eMMCの処理
board_emmc_initialize() 関数の中で、
eMMC ドライバを初期化し、eMMC デバイスを /mnt/emmc
ディレクトリへマウントします。
一方、終了処理は、board_emmc_finalize() 関数を呼び出すことでアンマウント処理を行います。
File: nuttx/boards/arm/cxd56xx/common/src/cxd56_emmcdev.c
int board_emmc_initialize(void)
{
/* Power on the eMMC device */
ret = board_power_control(POWER_EMMC, true); (1)
:
/* Initialize the eMMC device */
ret = cxd56_emmcinitialize(); (2)
:
/* Mount the eMMC device */
ret = nx_mount("/dev/emmc0", "/mnt/emmc", "vfat", 0, NULL); (3)
:
}
int board_emmc_finalize(void)
{
/* Un-mount the eMMC device */
ret = nx_umount2("/mnt/emmc", MNT_DETACH); (4)
:
/* Uninitialize the eMMC device */
ret = cxd56_emmcuninitialize(); (5)
:
/* Power off the eMMC device */
ret = board_power_control(POWER_EMMC, false); (6)
:
}
1 | eMMC の電源を入れます。 |
2 | eMMC ドライバを初期化します。 |
3 |
/dev/emmc0 デバイスファイルを /mnt/emmc へマウントします。 |
4 |
/mnt/emmc をアンマウントします。 |
5 | eMMC ドライバの終了処理を実行します。 |
6 | eMMC の電源を落とします。 |
12.2.2. コンフィグレーション
FAT ファイルシステムを使用するにあたり、いくつかのコンフィグレーション項目が存在します。
SDK としてデフォルトで設定しているコンフィグレーション値を以下に示します。
Configuration | Value | Description |
---|---|---|
CONFIG_CXD56_SDIO |
y |
SD カードの使用を有効にします |
CONFIG_CXD56_EMMC |
y |
eMMC の使用を有効にします |
CONFIG_CXD56_EMMC_POWER_PIN_XXX |
y |
eMMC デバイスの電源制御に使用するピンを選択します。デフォルトはPIN_I2S0_BCKを使用します。 |
CONFIG_FS_FAT |
y |
FAT ファイルシステムを有効にします |
CONFIG_FAT_LCNAMES |
y |
ファイル名の大文字/小文字を区別します |
CONFIG_FAT_LFN |
y |
FAT ロングファイルネームをサポートします |
CONFIG_FAT_MAXFNAME |
64 |
ファイル名の最大文字数を定義します |
CONFIG_FS_FATTIME |
y |
ファイルのタイムスタンプ機能をサポートします。 RTC に現在時刻が設定されている場合 (正確には RTC が1980年1月1日以降のとき) に ファイルの作成日時及び更新日時を記録します。 |
12.2.3. ビルド手順
SD カードや eMMC を使用する際のコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
SD カードを使用する場合は引数に
device/sdcard
を、eMMC を使用する場合は引数にdevice/emmc
を指定してコンフィグレーションを実行します。 両方を指定して同時に使用することも可能です。tools/config.py device/sdcard (SD カードを使用する場合) tools/config.py device/emmc (eMMC を使用する場合)
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
12.2.4. 動作確認
NuttShell プロンプトから df
コマンドによって Filesystem を確認することができます。
nsh> df -h Filesystem Size Used Available Mounted on vfat 14G 2762M 11G /mnt/sd0 smartfs 4M 28K 4068K /mnt/spif procfs 0B 0B 0B /proc
例えば、 /mnt/sd0
が vfat
ファイルシステムとしてマウントされていることや、
トータルサイズ (Size) のうち、使用サイズ (Used)、空きサイズ (Available) を確認することができます。
- RTCに時刻を設定する(ファイルのタイムスタンプ機能を使用する)
nsh> date -s "Feb 22 12:34:00 2021" nsh> date Feb 22 12:34:02 2021
- ファイルを作成する
nsh> echo "This is a test file." > /mnt/sd0/test.txt
- 作成されたファイルのサイズを確認する
nsh> ls -l /mnt/sd0/test.txt -rw-rw-rw- 21 /mnt/sd0/test.txt
- ファイルの内容を確認する
nsh> cat /mnt/sd0/test.txt This is a test file.
PC から SD カード内のファイルのプロパティをみると、タイムスタンプが正しく設定されていることが確認できます。
プログラムからファイル操作を行う場合は、 open/read/write/closeといった低水準入出力関数や fopen/fread/fwrite/fcloseといったファイル入出力関数を使うことができます。
12.2.5. フォーマット手順
PC 上で SD メモリーカードフォーマッター等を用いて、FAT ファイルシステムのフォーマットを行ってください。
exFAT ファイルシステムはサポートされていません。
|
また、ボード上で SD カードや eMMC のフォーマットを行う場合は、mkfatfs
コマンドを利用してください。
nsh> help mkfatfs mkfatfs usage: mkfatfs [-F <fatsize>] [-r <rootdirentries>] <block-driver>
FAT32 フォーマットの方法を以下に示します。
SD カード
nsh> mkfatfs -F 32 /dev/mmcsd0
eMMC
nsh> mkfatfs -F 32 /dev/emmc0
12.3. fsperf サンプルアプリケーション
ファイルシステムのread/writeパフォーマンスを測定するためのサンプルアプリケーション fsperf
の使い方について説明します。
12.3.1. ビルド手順
コマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/fsperf
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/fsperf make
eMMC デバイスを使用する場合は、コンフィグレーションの引数に
device/emmc
を追加してください。tools/config.py examples/fsperf device/emmc make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
12.3.2. 動作確認
NuttShell プロンプトから fsperf
コマンドを実行した例を以下に示します。
引数に -f
オプションとテストファイルのパスを指定して、fsperf
コマンドを実行します。
指定するパスは、測定対象のメディアによって変更してください。
はじめに mkdir
コマンドで "temp" ディレクトリを作成しています。
最後に rm
コマンドを用いて、実行中に作成したテストファイル群をディレクトリごと削除しています。
SD カード
nsh> mkdir /mnt/sd0/temp nsh> fsperf -f /mnt/sd0/temp/test File access speed monitor!! --- fwrite summary: Size: 1 [KB], Min: 4.064, Avg: 4.190, Max: 4.572 [Mbps] --- fwrite summary: Size: 2 [KB], Min: 1.954, Avg: 6.010, Max: 7.877 [Mbps] --- fwrite summary: Size: 4 [KB], Min: 14.028, Avg: 14.105, Max: 14.423 [Mbps] --- fwrite summary: Size: 8 [KB], Min: 23.541, Avg: 23.704, Max: 24.095 [Mbps] --- fwrite summary: Size: 16 [KB], Min: 34.713, Avg: 37.169, Max: 37.927 [Mbps] --- fwrite summary: Size: 32 [KB], Min: 18.833, Avg: 28.825, Max: 37.407 [Mbps] --- fwrite summary: Size: 64 [KB], Min: 21.817, Avg: 32.483, Max: 38.551 [Mbps] --- fwrite summary: Size: 128 [KB], Min: 27.149, Avg: 32.367, Max: 37.708 [Mbps] --- fwrite summary: Size: 256 [KB], Min: 27.026, Avg: 30.648, Max: 33.217 [Mbps] --- fwrite summary: Size: 512 [KB], Min: 18.553, Avg: 25.683, Max: 30.892 [Mbps] --- fwrite summary: Size: 1024 [KB], Min: 12.002, Avg: 22.746, Max: 29.715 [Mbps] --- fread summary: Size: 1 [KB], Min: 17.067, Avg: 18.156, Max: 18.286 [Mbps] --- fread summary: Size: 2 [KB], Min: 26.948, Avg: 27.235, Max: 28.445 [Mbps] --- fread summary: Size: 4 [KB], Min: 39.385, Avg: 39.691, Max: 40.961 [Mbps] --- fread summary: Size: 8 [KB], Min: 51.201, Avg: 51.201, Max: 51.201 [Mbps] --- fread summary: Size: 16 [KB], Min: 57.691, Avg: 57.854, Max: 58.515 [Mbps] --- fread summary: Size: 32 [KB], Min: 52.853, Avg: 53.058, Max: 53.196 [Mbps] --- fread summary: Size: 64 [KB], Min: 57.288, Avg: 57.428, Max: 57.489 [Mbps] --- fread summary: Size: 128 [KB], Min: 60.126, Avg: 60.192, Max: 60.236 [Mbps] --- fread summary: Size: 256 [KB], Min: 60.739, Avg: 60.773, Max: 60.795 [Mbps] --- fread summary: Size: 512 [KB], Min: 61.079, Avg: 61.080, Max: 61.089 [Mbps] --- fread summary: Size: 1024 [KB], Min: 61.350, Avg: 61.363, Max: 61.364 [Mbps] nsh> rm -r /mnt/sd0/temp
eMMC
nsh> mkdir /mnt/emmc/temp nsh> fsperf -f /mnt/emmc/temp/test File access speed monitor!! --- fwrite summary: Size: 1 [KB], Min: 6.564, Avg: 7.211, Max: 8.000 [Mbps] --- fwrite summary: Size: 2 [KB], Min: 11.637, Avg: 14.546, Max: 16.516 [Mbps] --- fwrite summary: Size: 4 [KB], Min: 26.257, Avg: 27.602, Max: 28.445 [Mbps] --- fwrite summary: Size: 8 [KB], Min: 43.575, Avg: 45.613, Max: 47.629 [Mbps] --- fwrite summary: Size: 16 [KB], Min: 57.691, Avg: 63.211, Max: 71.861 [Mbps] --- fwrite summary: Size: 32 [KB], Min: 67.149, Avg: 75.573, Max: 88.088 [Mbps] --- fwrite summary: Size: 64 [KB], Min: 55.352, Avg: 76.922, Max: 94.707 [Mbps] --- fwrite summary: Size: 128 [KB], Min: 77.103, Avg: 86.781, Max: 102.083 [Mbps] --- fwrite summary: Size: 256 [KB], Min: 79.247, Avg: 86.442, Max: 104.692 [Mbps] --- fwrite summary: Size: 512 [KB], Min: 80.168, Avg: 88.355, Max: 105.281 [Mbps] --- fwrite summary: Size: 1024 [KB], Min: 80.636, Avg: 88.837, Max: 100.904 [Mbps] --- fread summary: Size: 1 [KB], Min: 42.667, Avg: 58.183, Max: 64.001 [Mbps] --- fread summary: Size: 2 [KB], Min: 73.144, Avg: 80.002, Max: 85.335 [Mbps] --- fread summary: Size: 4 [KB], Min: 102.402, Avg: 102.402, Max: 102.402 [Mbps] --- fread summary: Size: 8 [KB], Min: 113.780, Avg: 119.768, Max: 120.473 [Mbps] --- fread summary: Size: 16 [KB], Min: 120.473, Avg: 123.749, Max: 124.124 [Mbps] --- fread summary: Size: 32 [KB], Min: 120.473, Avg: 121.007, Max: 122.271 [Mbps] --- fread summary: Size: 64 [KB], Min: 124.124, Avg: 125.743, Max: 126.033 [Mbps] --- fread summary: Size: 128 [KB], Min: 128.504, Avg: 128.504, Max: 128.504 [Mbps] --- fread summary: Size: 256 [KB], Min: 128.757, Avg: 128.969, Max: 129.010 [Mbps] --- fread summary: Size: 512 [KB], Min: 130.944, Avg: 131.048, Max: 131.074 [Mbps] --- fread summary: Size: 1024 [KB], Min: 130.748, Avg: 130.789, Max: 130.813 [Mbps] nsh> rm -r /mnt/emmc/temp
ファイルサイズを 1 ~ 1024 KB まで増やしながら、複数回 fwrite を実行したときのファイル書き込み速度(単位:Mbps) を最小値、平均値、最大値の順番に fwrite summary
の行に表示します。続けて、複数回 fread を実行したときファイル読み込み速度(単位:Mbps)を fread summary
の行に表示します。
fsperf
は次のコマンドオプションをもっています。
nsh> fsperf Usage: fsperf [-i] [-n <num>] -f <file> FileSystem Performance Monitor: -i: Display the information of each result -n: Specify the repeat count, default is 10 -f: Specify the path to prefix of example files e.g. "-f /mnt/spif/test" on SPI-Flash "-f /mnt/sd0/test" on SD card "-f /mnt/emmc/test" on eMMC board
-i
-
個々の実行結果を表示したいときに指定してください。
-n
-
ファイルの読み書きを繰り返し行う回数を指定します。デフォルトは10回です。
-f
-
本サンプルで使用するファイルパスのプレフィックスを指定します。 SPI-Flash, SD カード, eMMC など、測定対象のデバイスがマウントされているパスを指定してください。
-i
オプションと -n
の繰り返し回数を3回にしたときの表示例は以下の通りです。
summary
行の前に個別の実行結果3回分が表示されてます。
nsh> fsperf -f /mnt/sd0/temp/test -i -n 3 File access speed monitor!! 1 [KB] / 1.129 [ms], speed= 6.919 [Mbps] 1 [KB] / 1.068 [ms], speed= 7.314 [Mbps] 1 [KB] / 1.099 [ms], speed= 7.111 [Mbps] --- fwrite summary: Size: 1 [KB], Min: 6.919, Avg: 7.111, Max: 7.314 [Mbps] 2 [KB] / 1.068 [ms], speed= 14.629 [Mbps] 2 [KB] / 1.038 [ms], speed= 15.059 [Mbps] 2 [KB] / 1.038 [ms], speed= 15.059 [Mbps] --- fwrite summary: Size: 2 [KB], Min: 14.629, Avg: 14.913, Max: 15.059 [Mbps] :
fsperf
の実行結果は、SD カードの種類や使用状況によって結果が異なります。
手持ちの SD カードでパフォーマンスを測定してみてください。
13. HostIF チュートリアル
13.1. HostIF サンプルアプリケーション
この章では、HostIF サンプルアプリケーションの動作手順を示します。
本サンプルアプリケーションは、対向Host機器にも Spresense ボードを使用し、 Spresense 同士を接続して HostIF 通信を実現するアプリケーションになります。 サンプルプログラム内には、Host側の実装コードも含まれています。
13.1.1. 動作環境
-
Spresense メインボード x2
-
ジャンパワイヤ
I2C 接続構成
B2Bコネクタピッチ変換基板のI2C3端子と、Host環境としてメインボードのI2C0端子とを接続します。
I/O電圧は1.8Vです。
B2Bコネクタピッチ変換基板 | Host | ||
---|---|---|---|
No. |
端子名 |
端子名 |
I/O電圧 |
77 |
I2C3_BCK |
I2C0_SCL |
1.8V |
71 |
I2C3_BDT |
I2C0_SDA |
1.8V |
SPI 接続構成
B2Bコネクタピッチ変換基板のSPI2端子と、Host環境としてメインボードのSPI5端子とを接続します。
I/O電圧は1.8Vです。
B2Bコネクタピッチ変換基板 | Host | ||
---|---|---|---|
No. |
端子名 |
端子名 |
I/O電圧 |
77 |
SPI2_CS_X |
SPI5_CS_X |
1.8V |
75 |
SPI2_MOSI |
SPI5_MOSI |
1.8V |
73 |
SPI2_MISO |
SPI5_MISO |
1.8V |
71 |
SPI2_SCK |
SPI5_SCK |
1.8V |
13.1.2. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
I2CかSPIのどちらか接続構成に合わせて、適切な方を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/hostif_i2c (I2C接続時) tools/config.py examples/hostif_spi (SPI接続時) make
-
nuttx.spk
を 両方のSpresense ボードへ書き込みます。この例では、シリアルポートとして、HostIF側は /dev/ttyUSB0、Host側は /dev/ttyUSB1 に接続されているものとします。 シリアルポートの番号はユーザ環境に依存して変わります。 書き込み速度の baudrate として 500000 bps を設定しています。 書き込みに失敗する場合は、baudrate を 115200 bps へ変更してください。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk tools/flash.sh -c /dev/ttyUSB1 -b 500000 nuttx.spk
13.1.3. 動作確認
HostIF側、Host側それぞれのシリアルターミナルを開きます。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして、HostIF側は /dev/ttyUSB0、Host側は /dev/ttyUSB1 に接続されているものとします。 シリアルポートはユーザ環境に依存して変わります。baudrate はどちらも 115200 bps を設定してください。
minicom -D /dev/ttyUSB0 -b 115200 minicom -D /dev/ttyUSB1 -b 115200
-
HostIF側のNuttShell から
hostif
コマンドを実行します。HostIFドライバを初期化した後に、
HostIF通信用バッファにBuild Versionを書き込みます。
HostIF通信用バッファに周期的にタイムスタンプを書き込むスレッドを起動します。
Hostから送られてきたデータをループバックして送り返すスレッドを起動します。nsh> hostif Start updater: update the information periodically version: 0.0.0-SDK2.2.0-81ac8ad May 12 2021 15:53 Start loopback: loopback the received data
-
Host側のNuttShell から
host_i2c
もしくはhost_spi
コマンドを実行します。I2CまたはSPI通信により、HostIF側のBuild Versionを読み出して表示します。
Hostからデータを送信し、HostIF側でループバックされて戻ってきたデータを受信し表示します。
最後に、HostIF側のタイムスタンプ情報を読み出して表示します。nsh> host_i2c version=0.0.0-SDK2.2.0-81ac8ad May 12 2021 15:53 (sz=41) Send done. 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f Send done. 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 Send done. 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 Send done. 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 Send done. 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 Send done. 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 Send done. 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 Send done. 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 Send done. 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 Send done. 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 sec=15 nsec=85478117 (sz=8) sec=16 nsec=95518210 (sz=8) sec=17 nsec=105558303 (sz=8) sec=18 nsec=115598396 (sz=8) sec=19 nsec=125638489 (sz=8) sec=20 nsec=135678582 (sz=8) sec=21 nsec=145718675 (sz=8) sec=22 nsec=155758768 (sz=8) sec=23 nsec=165798861 (sz=8) sec=24 nsec=175838954 (sz=8)
13.1.4. サンプルコード解説
サンプルコードにおける通信バッファの構成や通信内容について解説します。
HostIFの詳細仕様については、SDK開発ガイドを参照してください。
13.1.4.1. 通信バッファ構成
HostからSpresenseへ送信する通信バッファを1個(Index=0)と、SpresenseからHostへ送信する通信バッファを3個(Index=1,2,3)を作成します。
各通信バッファの用途は以下の通りです。
Index | Size | Direction | Device filename | Description |
---|---|---|---|---|
0 |
0x100 |
Read |
/dev/hostifr0 |
ループバック受信用(汎用通信用途) |
1 |
0x100 |
Write |
/dev/hostifw1 |
ループバック送信用(汎用通信用途) |
2 |
0x029 |
Write |
/dev/hostifw2 |
バージョン固定値送信用(固定データ用途) |
3 |
0x008 |
Write |
/dev/hostifw3 |
タイムスタンプ送信用(リアルタイム更新データ用途) |
バッファ構成のサンプルコードを以下に示します。
#ifdef CONFIG_EXAMPLES_HOSTIF_I2C
static struct hostif_i2cconf_s conf =
#else
static struct hostif_spiconf_s conf =
#endif
{
#ifdef CONFIG_EXAMPLES_HOSTIF_I2C
.address = 0x24, /* own slave address */
#endif
.buff[0] =
{
/* BUFFER0: receive buffer from host */
0x100,
HOSTIF_BUFF_ATTR_READ | HOSTIF_BUFF_ATTR_VARLEN
},
.buff[1] =
{
/* BUFFER1: send buffer to host */
0x100,
HOSTIF_BUFF_ATTR_WRITE | HOSTIF_BUFF_ATTR_VARLEN
},
.buff[2] =
{
/* BUFFER2: send the constant version information */
VERSION_NAMELEN,
HOSTIF_BUFF_ATTR_WRITE | HOSTIF_BUFF_ATTR_FIXLEN
},
.buff[3] =
{
/* BUFFER3: send the variable timestamp information */
sizeof(struct timespec),
HOSTIF_BUFF_ATTR_WRITE | HOSTIF_BUFF_ATTR_FIXLEN
},
};
13.1.4.2. HostIF 動作
HostIF側のサンプルコードは以下を参照してください。
サンプルコードの処理の流れを以下に示します。
-
指定したバッファ構成で HostIF ドライバを初期化します。
#ifdef CONFIG_EXAMPLES_HOSTIF_I2C ret = hostif_i2cinitialize(&conf); #else ret = hostif_spiinitialize(&conf); #endif
-
hostif_updater
スレッドを起動します。Buffer(Index=2)へ
uname()
で得られるビルドバージョンを書き込みます。 これはHostIFが一度だけ情報を書き込み、HostからはRead-onlyな固定値データとして参照するような用途を想定しています。/* Write-once the constant software version to BUFFER2 */ struct utsname name; uname(&name); ret = write(wfd2, &name.version, VERSION_NAMELEN);
Buffer(Index=3)へ
clock_gettime()
で得られるタイムスタンプ情報を1秒周期で書き込みます。 これはHostIF側が定期的に情報を上書き更新し、Hostからは非同期に読み出しを行うことで常に最新のデータを取得するような用途を想定しています。struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ret = write(wfd3, &ts, sizeof(ts));
-
hostif_loopback
スレッドを起動します。Host から送信されたデータを Buffer(Index=0) で受信し、ループバックして Buffer(Index=1) 経由でHostに送信します。
/* blocking read */ size = read(rfd, buffer, sizeof(buffer)); /* blocking write */ size = write(wfd, buffer, size);
13.1.4.3. Host 動作
Host側のサンプルコードは以下を参照してください。
サンプルコードの処理の流れを以下に示します。
-
I2C または SPI ドライバを open します。
/* Open the i2c driver */ fd = open("/dev/i2c0", O_WRONLY);
/* Open the spi driver */ fd = open("/dev/spi5", O_WRONLY);
-
Buffer(Index=2) からバージョン情報を読み出します。
/* Get the version information from slave */ get_version(fd);
HostからはRead-onlyな固定値情報として常に参照することができるようにするために、 通信プロトコル上、バッファロックフラグを立てた状態で受信操作を行います。 バッファロック状態をキープすることで、HostIF側からの更新が禁止され常にHostから読み出し可能な状態になります。
-
Buffer(Index=0)へデータを送信し、ループバックされたデータをBuffer(Index=1)から受信します。
この動作を10回繰り返します。
/* Loopback */ for (i = 0; i < 10; i++) { /* Send incremental data to slave */ send_data(fd); /* Wait a moment */ usleep(10 * 1000); /* Receive looped-back data */ receive_data(fd); }
-
Buffer(Index=3) からタイムスタンプ情報を読み出します。
1秒周期でこの動作を10回繰り返します。
for (i = 0; i < 10; i++) { /* Get the timestamp from slave */ get_timestamp(fd); /* Wait a second until the timestamp is updated */ sleep(1); }
-
最後にI2C または SPI ドライバを close します。
/* Close the i2c or spi driver */ close(fd);
14. FW Update チュートリアル
14.1. FW Update サンプルアプリケーション
この章では、ファームウェアアップデートを行うサンプルアプリケーションの動作手順を示します。
アップデート対象となる各種ファームウェア(SPKファイル)を結合した package.bin
パッケージファイルを作成し、
SPI-FlashやSD Cardなどのストレージ上に置いておきます。アプリケーションからそのパッケージファイルを指定して、ファームウェアをアップデートすることができます。
14.1.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/fwupdate
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/fwupdate make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
14.1.2. FW Update パッケージの作成
examples/fwupdate
ディレクトリ以下にある package.sh
スクリプトを用いて、アップデート対象のファームウェアを結合したパッケージファイル package.bin
を作成します。
nuttx.spk
, loader.espk
, gnssfw.espk
をまとめて一度にアップデートするときは package.sh
スクリプトの引数に複数のファイルを指定します。スクリプトの実行に成功すると、カレントディレクトリに package.bin
ファイルを作成します。
cd spresense/sdk ../examples/fwupdate/package.sh nuttx.spk ../firmware/spresense/{loader,gnssfw}.espk Pack: 0 181392 nuttx.spk Pack: 1 129968 ../proprietary/spresense/bin/loader.espk Pack: 1 454512 ../proprietary/spresense/bin/gnssfw.espk ==================== Created package.bin ====================
次のようにして、nuttx.spk
単独のパッケージファイルを作成することも可能です。
../examples/fwupdate/package.sh nuttx.spk Pack: 0 332512 nuttx.spk ==================== Created package.bin ====================
作成した package.bin
ファイルを SPI-Flash 上に転送します。
./tools/flash.sh -c /dev/ttyUSB0 -w package.bin xmodem >>> Install files ... nsh> xmodem /mnt/spif/package.bin Install package.bin |0%-----------------------------50%------------------------------100%| ###################################################################### nsh> Transfer completed.
この例では、USBシリアル経由で package.bin
をSPI-Flashのアプリケーション領域に転送しています。
応用例として、WiFiやLTEなどネットワーク経由で package.bin
を転送したり、package.bin
の配置場所としてSD Cardを使用することもできます。
14.1.3. 動作確認
シリアルターミナルを開いて、fwupdate コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から fwupdate コマンドを実行します。
fwupdateコマンドのUsageを以下に示します。
nsh> fwupdate FW Update Example!! Free space 1343488 bytes Usage: fwupdate [-f <filename>]... [-p <pkgname>] [-h] Description: FW Update operation Options: -f <filename>: update a file. -p <pkgname> : update a package. -z : update a package via USB CDC/ACM Zmodem. -h: Show this message
Free space にファームウェア格納領域の空き容量が表示されます。
ファームウェアアップデートは冗長化のために十分な空き容量が必要になります。 目安として、fwupdateで指定するパッケージファイルのサイズはこの空き容量の半分以下になるようにしてください。
SPI-Flash上の
package.bin
を指定してファームウェアアップデートを行います。nsh> fwupdate -p /mnt/spif/package.bin FW Update Example!! Free space 2449408 bytes File: /mnt/spif/package.bin Size: 765896 File: /mnt/spif/package.bin(0) Size: 181392 Type: FW_APP ->dl(0x2d03caf0, 65536 / 181392): ret=0 ->dl(0x2d03caf0, 131072 / 181392): ret=0 ->dl(0x2d03caf0, 181392 / 181392): ret=0 File: /mnt/spif/package.bin(1) Size: 129968 Type: FW_SYS ->dl(0x2d03caf0, 65536 / 129968): ret=0 ->dl(0x2d03caf0, 129968 / 129968): ret=0 File: /mnt/spif/package.bin(2) Size: 454512 Type: FW_SYS ->dl(0x2d03caf0, 65536 / 454512): ret=0 ->dl(0x2d03caf0, 131072 / 454512): ret=0 ->dl(0x2d03caf0, 196608 / 454512): ret=0 ->dl(0x2d03caf0, 262144 / 454512): ret=0 ->dl(0x2d03caf0, 327680 / 454512): ret=0 ->dl(0x2d03caf0, 393216 / 454512): ret=0 ->dl(0x2d03caf0, 454512 / 454512): ret=0 Package validation is OK. Saving package to "gnssfw" Package validation is OK. Saving package to "loader" Package validation is OK. Saving package to "nuttx" NuttShell (NSH) NuttX-10.1.0 nsh>
ファームウェアアップデートに成功すると、自動的に再起動されて新しいファームウェアで起動します。
ファームウェアアップデート中にリセットや電源断などが発生しないように注意してください。 空き領域不足やリセットなどにより万が一再起動中にエラーが発生したときはリカバリ処理が走り、 パッケージ内の全ファームウェア(この例では、gnssfw, loader, nuttx)のアップデートがキャンセルされ、 アップデート実行前の旧ファームウェアで起動します。
15. ELTRES チュートリアル
15.1. ELTRES サンプルアプリケーション
ELTRES SDK を Spresense 向けにポーティングしたソースコードが外部ライブラリに追加されています。
ELTRES SDK についての詳細は、ELTRES ホームページをご参照ください。
ユーザ登録を行うことで各種データシートやサンプルコードを入手することができます。
ELTRES サンプルアプリケーションとして次の3つのアプリケーションを用意しています。
また、ELTRES ボードは、以下の2種類に対応しています。
どちらのボードを使用するかは、SDKコンフィグレーションによって切り替えることができます。
15.1.1. eltres_lpwa サンプルアプリケーション
ELTRESホームページからダウンロード可能な LPWA Sample Application を Spresense 向けにポーティングしたサンプルコードです。
本サンプルは、予めモジュールに設定された通信プロファイルにしたがって、周期的に ELTRES 送信を行います。 また、送信周期間隔が一定時間以上空いた場合、省電力化のため CXM150x の電源を OFF する制御を行います。
ELTRESの送信にはGPSから取得した正確な時刻が必要になるため、GPSを測位可能な環境で動作させてください。
15.1.1.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/eltres_lpwa
を追加してコンフィグレーションを実行します。tools/config.py examples/eltres_lpwa
デフォルトはSPEXELボード用になっています。Add-onボードで使用する場合は、menuconfigでボードの選択を切り替えてください。
make menuconfig Application Configuration -> Spresense SDK -> Externals -> ELTRES SDK library -> ELTRES board selection => Add-on board
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
15.1.1.2. 動作確認
シリアルターミナルを開いて、eltres_lpwa コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から eltres_lpwa コマンドを実行します。
GPSから時刻情報を取得した後に、通信プロファイルにしたがって周期的に送信動作を行います。
nsh> eltres_lpwa main_LPWA_sample_app:Ver.3.0.3, API:Ver.3.0.4 *** pow_enable_remain_offset:340 *** periodic1_eanable:1 periodic2_eanable:0 *** periodic enable:1 *** event enable:0 -wait GNSS ready- sys_stt_event_callback:code=1(FETCHING_TIME) sys_stt_event_callback:code=3(EPM_FILL) -GNSS ready- local time:11:26.59(utc) RTC init:2023-03-02 11:26:59 +++++time check start+++++ current time:11:26.59(utc) next time:11:29.42(utc) next interval:-177 sec CXM150x power not change +++++time check end +++++ *** push button to event send *** int1_callback *** normal send start! *** sys_stt_event_callback:code=9(DF_WAIT_TX_START) GGA: time[112931.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112932.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112933.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112934.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112935.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112936.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112937.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112938.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112939.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] GGA: time[112940.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] sys_stt_event_callback:code=10(DF_TX_PROGRESS) *** START LPWA TX: Stop get GNSS! *** GGA: time[112941.00] lat[N 3518.xxxx] lng[E 13934.xxxx] cs_correct[1] sys_stt_event_callback:code=3(EPM_FILL) +++++time check start+++++ current time:11:29.57(utc) next time:11:32.41(utc) next interval:-176 sec CXM150x power not change +++++time check end +++++ *** normal send end! ***
15.1.2. eltres_standalone サンプルアプリケーション
ELTRESホームページからダウンロード可能な Standalone Mode Sample Application を Spresense 向けにポーティングしたサンプルコードです。
スタンドアローン機能は、電源制御を CXM150x 自身が行い、自動ペイロード生成機能を利用したモードになります。
本サンプルは、通信制御および電源制御、および基本的なペイロードのデータ生成は CXM150x の EEPROM 設定に従って CXM150x 自身が行い、アプリケーションコードでは CXM150x の起動時の動作モード設定とペイロードの一部変更のみを行います。ペイロードへのユーザーデータ付加の例として、CXM150x が自動生成したペイロードの末尾部分をボードのtick(動作時間)に置き換えるサンプルとなっています。
ELTRESの送信にはGPSから取得した正確な時刻が必要になるため、GPSを測位可能な環境で動作させてください。
スタンドアローンモードで動作させる場合は、EEPROM の値を正しく設定する必要があります。詳細は、ELTRESホームページ上のConfiguration Manualやアプリケーションノートを参照してください。 |
CXM1501GR チップはスタンドアローンモードに非対応なので、Add-on ボードでは動作しません。 |
15.1.2.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/eltres_standalone
を追加してコンフィグレーションを実行します。tools/config.py examples/eltres_standalone
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
15.1.2.2. 動作確認
シリアルターミナルを開いて、eltres_standalone コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から eltres_standalone コマンドを実行します。
GPSから時刻情報を取得した後に、通信プロファイルにしたがって周期的に送信動作を行います。
nsh> eltres_standalone main_standalone_mode_sample_app:Ver.1.0.3 evt:| SYS RESET POR_PIN snd:< SYS MODE SET 00 rcv:> SYS MODE SET OK response OK host resume: evt:| TX PLD xxxxxxxxxxxxxxxxxxxxxxxxxxxxx3FF snd:< TX PLD SET xxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyy rcv:> TX PLD SET OK response OK host resume: evt:| TX PLD xxxxxxxxxxxxxxxxxxxxxxxxxxxxx3FF snd:< TX PLD SET xxxxxxxxxxxxxxxxxxxxxxxxxxxxxzzz rcv:> TX PLD SET OK response OK
15.1.3. eltres_eeprom サンプルアプリケーション
本サンプルは、ELTRESモジュール内のEEPROMを読み書きするためのユーティリティツールです。
EEPROM値の詳細は、ELTRESホームページ上のConfiguration Manualを参照してください。
ELTRESボード内のEEPROMには、予め通信プロファイルにしたがった設定値が書き込まれて出荷されています。誤って書き換えた場合に正しく通信できなくなる恐れがあるため、書き換える際は十分に留意して行ってください。 |
15.1.3.1. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/eltres_eeprom
を追加してコンフィグレーションを実行します。tools/config.py examples/eltres_eeprom
デフォルトはSPEXELボード用になっています。Add-onボードで使用する場合は、menuconfigでボードの選択を切り替えてください。
make menuconfig Application Configuration -> Spresense SDK -> Externals -> ELTRES SDK library -> ELTRES board selection => Add-on board
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
15.1.3.2. 動作確認
シリアルターミナルを開いて、eltres_eeprom コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から eltres_eeprom コマンドを実行します。
Usage は以下の通りです。
nsh> eltres_eeprom Usage: eltres_eeprom command dump : Dump all EEPROM data get <address> : Read data from an EEPROM address put <address> <value> : Write any value to an EEPROM address setlist : Write EEPROM data pre-set by the user version : Show version information
サブコマンドにversionを指定すると、バージョン情報を取得することができます。
nsh> eltres_eeprom version Bootloader : FY0100 / Apr 9 2021 16:54:39 Firmware : 002000243233393412473931 / RA2400 / 877F5FC1 / Apr 9 2021 16:56:48 GNSS FW : 17166,3dac91c,122 / 0x00151d31 / 0x00850401 API version : 3.0.4
サブコマンドにdumpを指定すると、LfourIDとEEPROM値をダンプ表示することができます。
nsh> eltres_eeprom dump LfourID = 0001018350 Name, Address, Value(HEX), Value(DEC) DEVICE ID UPPER, 0x0000, 0x8004610, 134235664 DEVICE ID_LOWER, 0x0004, 0x1EB2DB3, 32189875 LFOUR ID UPPER, 0x0008, 0x0, 0 LFOUR ID LOWER, 0x000C, 0x1018350, 16876368 MODULE_SELECT, 0x0020, 0x1, 1 MODULE_BRANCH, 0x0028, 0x1, 1 SM_TOUT, 0x0204, 0x0, 0 :
EEPROMの特定アドレスの値を取得するときは、サブコマンドにget、引数にアドレスを指定してください。
EEPROMの特定アドレスの値を設定するときは、サブコマンドにput、引数にアドレスと値を指定してください。
サブコマンドのsetlistを使ってEEPROM値をまとめて書き換えることも可能です。 eltres_eeprom_main.c の s_userlist[] 配列の中身を書き換えて、設定したいアドレスとデータのペアを設定した後にビルドし直して使用してください。
static struct eeprom_addr_value_s s_userlist[] = { { アドレス1, データ1 }, { アドレス2, データ2 }, };
16. その他のチュートリアル
16.1. json サンプルアプリケーション
この章では、NuttXの標準サンプルである、jsonに関するサンプルアプリケーションの動作手順を示します。 このサンプルは、組み込み向けオープンソースの、 cJSONをライブラリとして利用しています。
cJSONはjsonフォーマットで記載されたテキストをパースするためのライブラリです。+ json形式のファイルはネットなどでのやり取りする情報などの構造化によく用いられています。
ビルド時にcJSONをwgetにてダウンロードされるため、wgetをインストールしておく必要があります。
16.1.1. ソースコードパス
このサンプルのソースコードは、 sdk/apps/examples/json
以下にあります。
また、ダウンロードされるオープンソースcJSONは、 sdk/apps/netutils/cJSON
以下にダウンロードされます。
16.1.2. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/json
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/json make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
16.1.3. 動作確認
シリアルターミナルを開いて、json コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
json
コマンドを実行します。このサンプルコマンドでは、cJSONを用いて、サンプルコード内にハードコードされたjson形式のテキストデータのパースや、 json形式のテキストの生成を行います。
nsh> json { "name": "Jack (\"Bee\") Nimble", "format": { "type": "rect", "width": 1920, "height": 1080, "interlace": false, "frame rate": 24 } } ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] [[0, -1, 0], [1, 0, 0], [0, 0, 1]] { "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http:/*www.example.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] } } [{ "precision": "zip", "Latitude": 37.7668, "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", "Zip": "94107", "Country": "US" }, { "precision": "zip", "Latitude": 37.371991, "Longitude": -122.02602, "Address": "", "City": "SUNNYVALE", "State": "CA", "Zip": "94085", "Country": "US" }] { "name": "Jack (\"Bee\") Nimble", "format": { "type": "rect", "width": 1920, "height": 1080, "interlace": false, "frame rate": 24 } } ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] [[0, -1, 0], [1, 0, 0], [0, 0, 1]] { "Image": { "Width": 800, "Height": 600, "Title": "View from 15th Floor", "Thumbnail": { "Url": "http:/*www.example.com/image/481989943", "Height": 125, "Width": "100" }, "IDs": [116, 943, 234, 38793] } } [{ "precision": "zip", "Latitude": 37.7668, "Longitude": -122.3959, "Address": "", "City": "SAN FRANCISCO", "State": "CA", "Zip": "94107", "Country": "US" }, { "precision": "zip", "Latitude": 37.371991, "Longitude": -122.026, "Address": "", "City": "SUNNYVALE", "State": "CA", "Zip": "94085", "Country": "US" }]
16.2. ini_dumper サンプルアプリケーション
この章では、NuttXの標準サンプルである、ini_dumperに関するサンプルアプリケーションの動作手順を示します。 このサンプルは、組み込み向けオープンソースのiniファイルパーサー、 inihを利用しています。
iniファイルはWindowsで設定ファイルとしてよく用いられているフォーマットです。+ アプリ開発を行う際に、複数の機材に対して同じアプリを使い、それぞれの機材に合わせて変更したい場合などに便利です。
ビルド時にinihをwgetにてダウンロードされるため、wgetをインストールしておく必要があります。
16.2.1. ソースコードパス
このサンプルのソースコードは、 sdk/apps/examples/ini_dumper
以下にあります。
また、ダウンロードされるオープンソースinihは、 sdk/apps/fsutils/inih
以下にダウンロードされます。
16.2.2. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/ini_dumper
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/ini_dumper make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
16.2.3. 動作確認
シリアルターミナルを開いて、ini_dumper コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
ini_dumper
コマンドを実行します。このサンプルコマンドは、引数にiniファイルのパスを指定することで、そのファイルをパースして表示してくれます。
このチュートリアルでは、以下のコマンドで、まずは、/mnt/spif/sample.iniを作成し、それをパースしてみます。nsh> echo [System] > /mnt/spif/sample.ini nsh> echo Board = Spresense >> /mnt/spif/sample.ini nsh> echo >> /mnt/spif/sample.ini nsh> echo [Information] >> /mnt/spif/sample.ini nsh> echo ProvidedBy = Sony Semiconductor Solutions >> /mnt/spif/sample.ini
上記コマンドで/mnt/spifにsample.iniが作られているかcatコマンドで確認します。 無事にファイルが作られていれば、以下の様なメッセージが出力されます。
nsh> cat /mnt/spif/sample.ini [System] Board = Spresense [Information] ProvidedBy = Sony Semiconductor Solutions
ファイルが作られていることが確認できたら、サンプルコマンドを使ってそのファイルをパースします。
nsh> ini_dumper /mnt/spif/sample.ini ------ --------------- ------------- --------------------------- line section key value ------ --------------- ------------- --------------------------- 2 System Board Spresense 5 Information ProvidedBy Sony Semiconductor Solutions ------ --------------- ------------- --------------------------- ini_parse() exited with 0
16.3. pdcurses サンプルアプリケーション
この章では、NuttXの標準サンプルである、pdcursesに関するサンプルアプリケーションの動作手順を示します。 このサンプルは、オープンソースのPDCursesをNuttXにポーティングされた PDCursesをNuttXにポーティングされたものを利用しています。
このサンプルには、
charset, newdemo, testcurs, worm, firework, rain, tui, xmas
という8つのデモが含まれています。
16.3.1. ソースコードパス
このサンプルのソースコードは、 sdk/apps/examples/pdcurses
以下にあります。
また、PDCursesのポーティングされたソースコードは、 sdk/apps/graphics/pdcurs34
以下にあります。
16.3.2. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/pdcurses
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/pdcurses make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
16.3.3. 動作環境
このサンプルを動作させるには、以下のハードウェアを使う前提となっています。
Spresense Main Board
Spresense Extension Board
Arduino UNO LCD Connector board
ILI9341 2.2inch LCD
16.3.4. 動作確認
このサンプルには、PDCursesを使った複数のサンプルデモコマンドが用意されています。 シリアルターミナルを開いて、各コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
16.3.4.1. NuttShell から 各サンプルのコマンドを実行します。
-
charset
の実行charset
サンプルコマンドは、PDCursesで扱う文字をLCD画面中央に表示し終了します。nsh> charset
-
newdemo
の実行newdemo
サンプルコマンドは、PDCursesを使って様々なテキストウィンドウを表示したり、 文字を動かしたりします。このコマンドは一度実行すると終了せずに動きっぱなしになります。 別のサンプルコマンドを実行したい場合は、Spresemseメインボードのリセットボタンを押して再起動してください。nsh> newdemo
-
worm
の実行worm
サンプルコマンドは、赤、青、緑のワーム(ミミズの様なもの)がLCD上をうねうねします。 このコマンドは一度実行すると終了せずに動きっぱなしになります。 別のサンプルコマンドを実行したい場合は、Spresemseメインボードのリセットボタンを押して再起動してください。nsh> worm
-
firework
の実行firework
サンプルコマンドは、PDCursesを用いて花火の様なグラフィックを表示します。 このコマンドは一度実行すると終了せずに動きっぱなしになります。 別のサンプルコマンドを実行したい場合は、Spresemseメインボードのリセットボタンを押して再起動してください。nsh> firework
-
rain
の実行rain
サンプルコマンドは、PDCursesを用いて雨の雫が落ちた様なグラフィックを表示します。 このコマンドは一度実行すると終了せずに動きっぱなしになります。 別のサンプルコマンドを実行したい場合は、Spresemseメインボードのリセットボタンを押して再起動してください。nsh> rain
-
tui
の実行tui
サンプルコマンドは、PDCursesを用いてテキストベースのユーザインターフェイスを表示します。 このコマンドは一度実行すると終了せずに動きっぱなしになります。 別のサンプルコマンドを実行したい場合は、Spresemseメインボードのリセットボタンを押して再起動してください。nsh> tui
-
xmas
の実行xmas
サンプルコマンドは、PDCursesを用いクリスマスっぽいアニメーションを表示します。nsh> xmas
16.4. embedlog サンプルアプリケーション
この章では、NuttXの標準サンプルである、embedlogに関するサンプルアプリケーションの動作手順を示します。 このサンプルは、組み込み向けの非常に軽いオープンソースのログライブラリ、 embedlogを利用しています。
ビルド時にembedlogをwgetにてダウンロードされるため、wgetをインストールしておく必要があります。
16.4.1. ソースコードパス
このサンプルのソースコードは、 sdk/apps/examples/embedlog
以下にあります。
また、ダウンロードされるオープンソースembedlogは、 sdk/apps/system/embedlog
以下にダウンロードされます。
16.4.2. ビルド手順
CLI 版を使ったビルド手順について書かれていますが、IDE 版でも同様のコンフィグレーションを選択することにより本サンプルアプリケーションをビルドすることができます。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、コンフィグレーションツールのTab補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
コンフィグレーションとビルドを行います。
引数に
examples/embedlog
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make distclean tools/config.py examples/embedlog make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして /dev/ttyUSB0 を、書き込み速度の baudrate として 500000 bps を設定しています。
tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
16.4.3. 動作確認
シリアルターミナルを開いて、embedlog コマンドを実行します。
-
シリアルターミナルを起動します。
以下は、minicom ターミナルを使用する例です。 シリアルポートとして /dev/ttyUSB0 を、baudrate として 115200 bps を設定しています。
minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
embedlog
コマンドを実行します。実行すると、以下の様に、サンプルコードの内容にしたがって、様々なフォーマットでのログ出力を確認することができます。
nsh> embedlog i/Right after init, embedlog will print to stderr with just log level information - these are default settings. We can disable information about log level message still will be filtered by log level but there is no way to tell what level message is [24] As every respected logger, we also have timestamps [24] which work well with time from time() [8] or CLOCK_MONOTONIC from POSIX [1970-01-01 00:00:24] we also have long format that works well with time() [1970-01-01 00:00:24] if higher precision is needed we can use CLOCK_REALTIME [24] we can also mix REALTIME with short format [24] and if you don't need high resolution [24] you can disable fractions of seconds to save space! [24.878] or enable only millisecond resolution [24.879011] or enable only microsecond resolution [24.879255804] or enable only nanosecond resolution (not that it makes much sense on nuttx) no time information, if your heart desire it [embedlog_main.c:134] log location is very useful for debugging [1970-01-01 00:00:24.880201831][embedlog_main.c:139] f/Different scenarios need different options [1970-01-01 00:00:24.880690103][embedlog_main.c:140] a/So we can mix options however we want [1970-01-01 00:00:24.888532972][embedlog_main.c:143] f/you can also remove printing new line to join el_oprint and el_oputs in a singld [1970-01-01 00:00:24.901472180][embedlog_main.c:150] d/And if we have [1970-01-01 00:00:24.909162464][embedlog_main.c:151] i/modern terminal [1970-01-01 00:00:24.916822231][embedlog_main.c:152] n/we can enable colors [1970-01-01 00:00:24.924543032][embedlog_main.c:153] w/to spot warnings [1970-01-01 00:00:24.929822473][embedlog_main.c:154] e/or errors [1970-01-01 00:00:24.937543274][embedlog_main.c:155] c/with a quick [1970-01-01 00:00:24.945203041][embedlog_main.c:156] a/glance into [1970-01-01 00:00:24.950482482][embedlog_main.c:157] f/log file [1970-01-01 00:00:24.958142249][embedlog_main.c:160] i/embedlog: you can also use prefixes [1970-01-01 00:00:24.965954601][embedlog_main.c:161] i/embedlog: to every message you send [1970-01-01 00:00:24.973766953][embedlog_main.c:164] i/set prefix to null to disable it [1970-01-01 00:00:24.984020665][embedlog_main.c:196] i/print whole ASCII table [1970-01-01 00:00:24.991802500][embedlog_main.c:197] i/0x0000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................ [1970-01-01 00:00:25.002319292][embedlog_main.c:197] i/0x0010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................ [1970-01-01 00:00:25.015258500][embedlog_main.c:197] i/0x0020 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f !"#$%&'()*+,-./ [1970-01-01 00:00:25.028228225][embedlog_main.c:197] i/0x0030 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 0123456789:;<=>? [1970-01-01 00:00:25.038695556][embedlog_main.c:197] i/0x0040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO [1970-01-01 00:00:25.051604247][embedlog_main.c:197] i/0x0050 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_ [1970-01-01 00:00:25.064573972][embedlog_main.c:197] i/0x0060 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f `abcdefghijklmno [1970-01-01 00:00:25.075041303][embedlog_main.c:197] i/0x0070 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f pqrstuvwxyz{|}~. [1970-01-01 00:00:25.087888960][embedlog_main.c:199] i/print memory region that contains string with NULL chars [1970-01-01 00:00:25.098356291][embedlog_main.c:201] i/0x0000 73 6f 6d 65 20 6d 65 73 73 61 67 65 00 74 68 61 some message.tha [1970-01-01 00:00:25.111264982][embedlog_main.c:201] i/0x0010 74 20 63 6f 6e 74 61 69 6e 73 00 6e 75 6c 6c 20 t contains.null [1970-01-01 00:00:25.121701796][embedlog_main.c:201] i/0x0020 63 68 61 72 61 63 74 65 72 73 00 characters. [1970-01-01 00:00:25.134457902][embedlog_main.c:203] i/print the same region but this time with nice ascii table [1970-01-01 00:00:25.144772648][embedlog_main.c:205] i/------ ----------------------------------------------- ---------------- [1970-01-01 00:00:25.157620305][embedlog_main.c:205] i/offset hex ascii [1970-01-01 00:00:25.167935051][embedlog_main.c:205] i/------ ----------------------------------------------- ---------------- [1970-01-01 00:00:25.180874259][embedlog_main.c:205] i/0x0000 73 6f 6d 65 20 6d 65 73 73 61 67 65 00 74 68 61 some message.tha [1970-01-01 00:00:25.191341590][embedlog_main.c:205] i/0x0010 74 20 63 6f 6e 74 61 69 6e 73 00 6e 75 6c 6c 20 t contains.null [1970-01-01 00:00:25.204250281][embedlog_main.c:205] i/0x0020 63 68 61 72 61 63 74 65 72 73 00 characters. [1970-01-01 00:00:25.214595544][embedlog_main.c:205] i/------ ----------------------------------------------- ----------------
17. System tools 一覧
Spresense SDKでは、NuttShell から 各種 System tools を利用することができます。
カテゴリ | System tool名 | 説明 |
---|---|---|
LOG |
ログレベルを動的に変更します。 |
|
BackupSRAMに保存されたロギング情報をダンプします。 |
||
BackupSRAMに保存されたロギング情報をSPI-Flashに保存します。 |
||
GPIO |
||
GPIO割り込みを確認するためのテストコマンドです。 |
||
I2C |
I2Cデバイスとの通信を確認するためのユーティリティツールです。 |
|
PMIC |
||
USB |
||
Zmodem |
||
Stack |
Stack使用量をモニタするためのツールです。 |
|
Network |
18. GPIO ユーティリティツール
GPIO ユーティリティツールを利用して、各ピンの状態を確認したり、GPIO ピンへの入出力を設定することができます。
18.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/gpiotool
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/gpiotool make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
18.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
gpio
コマンドを実行します。コマンドオプションを以下に示します。nsh> gpio -h USAGE: gpio command stat [<from_pin>] [<end_pin>] conf <pin> [-m <0|1|2|3>] [-i] [-H] [-p <0|1|2|3>] -m: function mode -i: input enable -H: Higher drive current/slew rate -p: 0=float, 1=pullup, 2=pulldown, 3=buskeeper read <pin> write <pin> <0|1|-1>
gpio stat
コマンドにより、指定したピン番号の設定値を表示します。
gpio conf
コマンドにより、指定したピン番号の設定を変更することができます。
gpio read
コマンドにより、指定したピン番号の入力値を読み出します。
gpio write
コマンドにより、指定したピン番号へ出力値を書き込みます。
18.2.1. gpio stat コマンド
gpio stat
コマンドにより、デジタルピン一覧の状態を表示します。
引数で表示範囲を指定することもできます。
nsh> gpio stat 97 100 ------------------------------------------------------------- ( No)PIN NAME : Mode I/O mA Pull Read IRQ Type NF EN ------------------------------------------------------------- ( 97)PIN_I2S1_BCK : 0 / 2 -- 0 -1 ( 98)PIN_I2S1_LRCK : 0 / 2 -- 0 -1 ( 99)PIN_I2S1_DATA_IN : 0 / 2 -- 0 -1 (100)PIN_I2S1_DATA_OUT : 0 / 2 -- 0 -1
Mode
-
ピンの機能モードを表します。
Mode 0
は GPIO 機能、Mode 1~3
は I2C や UART といった GPIO 以外の機能・用途で使用されます。
各ピンはいくつかのグループに分けられており、Mode はグループ単位で設定されます。
ピンの詳細は、開発ガイド Pin specification を参照してください。 I/O
-
Input はピンの入力が許可されているかどうかを表します。
Output は GPIO モードに設定されたピンの出力が有効かどうかを表します。 mA
-
ドライブ電流 (2mA or 4mA) を表します。
Pull
-
--
:Float,PU
:Pull-Up,PD
:Pull-Down,BK
:Bus-Keeper を表します。 Read
-
読み出した値を表示します。
IRQ
-
GPIO 割り込み機能が設定されている場合、IRQ 番号を表します。
Type
-
GPIO 割り込み機能が設定されている場合、極性を表します。
(High
:レベル,Low
:レベル,Rise
:立ち上がりエッジ,Fall
:立ち下がりエッジ,Both
:両エッジ) NF
-
GPIO 割り込み機能が設定されている場合、チャタリング防止用のノイズフィルタの有効/無効を表します。
EN
-
GPIO 割り込み機能が設定されている場合、割り込みの許可/禁止を表します。
18.2.2. gpio conf コマンド
gpio conf
コマンドは、指定したピン番号に対して、機能モードや入出力設定を変更することができます。
例えば PIN_SEN_IRQ_IN
(37番) ピンを GPIO モードの入力ピン、Pull-Downに設定する場合、gpio conf 37 -m 0 -i -p 2
と入力します。
nsh> gpio conf 37 -m 0 -i -p 2 nsh> gpio stat 37 ------------------------------------------------------------- ( No)PIN NAME : Mode I/O mA Pull Read IRQ Type NF EN ------------------------------------------------------------- ( 37)PIN_SEN_IRQ_IN : 0 I/ 2 PD 0 -1
18.3. プログラミング
18.3.1. GPIO API
GPIO の API の詳細については APIリファレンスマニュアル を参照してください。
GPIO API を使用する場合は、以下のファイルを include してください。
#include <arch/board/board.h>
#include <arch/chip/pin.h>
GPIO API のプロトタイプ宣言はこちらに定義されています
nuttx/boards/arm/cxd56xx/spresense/include/cxd56_gpioif.h
GPIO API で使用するピン名はこちらに定義されています
nuttx/arch/arm/include/cxd56xx/pin.h
18.3.2. GPIO 入力設定
GPIO 入力ピンとして設定してポートの読み出しを行う場合は次のように行います。
/* 入力ピン設定 */
board_gpio_config(PIN_XXX, 0, true, false, PIN_FLOAT); (1)
board_gpio_config(PIN_XXX, 0, true, false, PIN_PULLUP); (2)
board_gpio_config(PIN_XXX, 0, true, false, PIN_PULLDOWN); (3)
board_gpio_config(PIN_XXX, 0, true, false, PIN_BUSKEEPER); (4)
/* ポート入力 */
int status = board_gpio_read(PIN_XXX); (5)
1 | PIN_XXX の入力を許可します。 |
2 | PIN_XXX をPull-Upに設定し入力を許可します。 |
3 | PIN_XXX をPull-Downに設定し入力を許可します。 |
4 | PIN_XXX をBus-Keeperに設定し入力を許可します。 |
5 | PIN_XXX の入力値を読み出します。 |
18.3.3. GPIO 出力設定
GPIO 出力ピンとして設定してポートの書き込みを行う場合は次のように行います。
/* 出力ピン設定 */
board_gpio_config(PIN_XXX, 0, false, true, PIN_FLOAT); (1)
board_gpio_config(PIN_XXX, 0, false, false, PIN_FLOAT); (2)
/* ポート出力 */
board_gpio_write(PIN_XXX, 0); (3)
board_gpio_write(PIN_XXX, 1); (4)
board_gpio_write(PIN_XXX, -1); (5)
1 | PIN_XXX の入力を禁止し、ドライブ電流を4mAに設定します。 |
2 | PIN_XXX の入力を禁止し、ドライブ電流を2mAに設定します。 |
3 | PIN_XXX へ LOW を出力します。 |
4 | PIN_XXX へ HIGH を出力します。 |
5 | PIN_XXX の出力を禁止にします。 |
18.3.4. GPIO 割り込み設定
GPIO 割り込みを使用する場合は次のように行います。
static int gpio_handler(int irq, FAR void *context, FAR void *arg)
{
/* 割り込みハンドラ */
}
/* 割り込み設定 */
board_gpio_intconfig(PIN_XXX, INT_HIGH_LEVEL, false, gpio_handler); (1)
board_gpio_intconfig(PIN_XXX, INT_LOW_LEVEL, false, gpio_handler); (2)
board_gpio_intconfig(PIN_XXX, INT_RISING_EDGE, true, gpio_handler); (3)
board_gpio_intconfig(PIN_XXX, INT_FALLING_EDGE, true, gpio_handler); (4)
board_gpio_intconfig(PIN_XXX, INT_BOTH_EDGE, true, gpio_handler); (5)
board_gpio_int(PIN_XXX, false); (6)
board_gpio_int(PIN_XXX, true); (7)
1 | PIN_XXX を HIGH レベル割り込みを設定し、割り込みハンドラを登録します。 |
2 | PIN_XXX を LOW レベル割り込みを設定、割り込みハンドラを登録します。 |
3 | PIN_XXX を立ち上がりエッジ割り込みを設定し、割り込みハンドラを登録します。ノイズフィルタを有効にしています。 |
4 | PIN_XXX を立ち下がりエッジ割り込みを設定し、割り込みハンドラを登録します。ノイズフィルタを有効にしています。 |
5 | PIN_XXX を両エッジ割り込みを設定し、割り込みハンドラを登録します。ノイズフィルタを有効にしています。 |
6 | PIN_XXX の割り込みを禁止します。 |
7 | PIN_XXX の割り込みを許可します。 |
19. PMIC ユーティリティツール
PMIC ユーティリティツールを利用して、PMIC(CXD5247) に接続されたロードスイッチやGPO出力を設定することができます。
19.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/pmictool
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/pmictool make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
19.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
pmic
コマンドを実行します。コマンドオプションを以下に示します。nsh> pmic -h Usage: pmic [-h] [-l] [-e <target>] [-d <target>] [-r <addr>] [-w <addr> -v <value>] Description: PMIC utility tool Options: -l: Show power status of the target -e <target>: Enable power to the target -d <target>: Disable power to the target -z <target>: Set GPO to HiZ to the target -r <addr>: Single read from <addr> -w <addr> -v <value>: Single write <value> to <addr> -h: Show this message
pmic -l
オプションにより、一覧を表示します。nsh> pmic -l Target Name : on/off ----------- : ------ DDC_IO : on LDO_EMMC : on DDC_ANA : off LDO_ANA : on DDC_CORE : on LDO_PERI : off LSW2 : off LSW3 : on LSW4 : on GPO0 : hiz GPO1 : off GPO2 : off GPO3 : off GPO4 : off GPO5 : off GPO6 : off GPO7 : off
pmic -e GPO0
と入力すると GPO0 を Enable に設定します。
pmic -d GPO0
と入力すると GPO0 を Disable に設定します。
pmic -z GPO0
と入力すると GPO0 を Hi-Z に設定します。
19.3. 接続先
ロードスイッチ(LSW) や GPO は主に各種電源コントロールに使用されています。
メインボードや拡張ボードでの接続先についての一覧を表示します。
DDC_CORE, DDC_IO, LDO_ANA についてはそれぞれプロセッサの CORE 電源, IO 電源, アナログ電源に接続されているため、Disable しないでください。 また、LDO_PERI についてはボード上、未接続のため記載を省略しています。 |
Target | 出力電圧 | メインボード | 拡張ボード | LTE 拡張ボード |
---|---|---|---|---|
LDO_EMMC |
3.3V |
ソケット3.3V出力 |
- |
- |
LSW2 |
1.8V |
Audio DVDD |
- |
- |
LSW3 |
SPI-Flash |
- |
- |
|
LSW4 |
TCXO 26MHz |
- |
- |
|
GPO0 |
VSYS(4.0V) |
- |
- |
3.3V LDO |
GPO1 |
- |
Audio 3.3V LDO |
||
GPO2 |
- |
- |
LTE DCDC |
|
GPO3 |
- |
- |
(LTE VBAT) |
|
GPO4 |
Camera LDO |
- |
- |
|
GPO5 |
- |
- |
- |
|
GPO6 |
- |
Audio Headphone Amp. |
||
GPO7 |
- |
- |
- |
19.4. プログラミング
19.4.1. PMIC API
PMIC 制御 API を使用する場合は、以下のファイルを include してください。
#include <arch/board/board.h>
PMIC API のプロトタイプ宣言はこちらに定義されています
nuttx/boards/arm/cxd56xx/spresense/include/cxd56_power.h
PMIC API で使用するターゲット名はボード依存ファイルの中で POWER_LTE
のようなエイリアス名が定義されています
nuttx/boards/arm/cxd56xx/spresense/include/board.h
19.4.2. GPO 出力設定
GPO 出力ピンに書き込みを行う場合は次のように行います。
ON/OFF する場合は、board_power_control(), board_power_control_tristate() のどちらを使用しても構いません。
HiZ へ設定する場合は、board_power_control_tristate() 関数を使用してください。
/* GPOポート出力 */
board_power_control(PMIC_GPO(0), true); (1)
board_power_control(PMIC_GPO(0), false); (2)
board_power_control_tristate(PMIC_GPO(0), 1); (3)
board_power_control_tristate(PMIC_GPO(0), 0); (4)
board_power_control_tristate(PMIC_GPO(0), -1); (5)
1 | GPO0 を Enable します。 |
2 | GPO0 を Disable します。 |
3 | GPO0 を Enable します。 |
4 | GPO0 を Disable します。 |
5 | GPO0 を HiZ へ設定します。 |
19.4.3. GPO 出力モニタ
GPO 出力ピンの状態を読み出す場合は次のように行います。
ON/OFF を読み出す場合は、board_power_monitor(), board_power_monitor_tristate() のどちらを使用しても構いません。
HiZ 状態も読み出す場合は、board_power_monitor_tristate() 関数を使用してください。
/* GPOポート出力モニタ */
bool bstate = board_power_monitor(PMIC_GPO(0)); (1)
int istate = board_power_monitor_tristate(PMIC_GPO(0)); (2)
1 | GPO0 の設定値を読み出します。true のときは Enable、false のときは Disable です。 |
2 | GPO0 の設定値を読み出します。1 のときは Enable、0 のときは Disable、-1 のときは Hi-Z です。 |
20. USB MSC 機能を使う
USB MSC (Mass Storage Class) 機能を使うためのユーティリティコマンドについて説明します。
USB MSC 機能を有効にするとホスト PC からSpresense ボード上の SD カードへ直接アクセスすることができます。
20.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/usbmsc
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/usbmsc make
SD カードを USB MSC としてマウントするので SD カード機能も有効化しています。
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
20.2. 動作確認
拡張ボードに SD カードが挿入されている状態で、拡張ボードの USB 端子とホスト PC とを USB ケーブルで接続します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
USB MSC 機能を開始する場合、NuttShell から
msconn
コマンドを実行します。nsh> msconn mcsonn_main: Creating block drivers mcsonn_main: Configuring with NLUNS=1 mcsonn_main: handle=d038d50 mcsonn_main: Bind LUN=0 to /dev/mmcsd0 mcsonn_main: Connected
ホスト PC に新たなリムーバブルディスクが認識され、 ホスト PC から拡張ボードの SD カードの内容にアクセスすることができます。
-
USB MSC 機能を終了する場合、NuttShell から
msdis
コマンドを実行します。nsh> msdis msdis: Disconnected
21. USB CDC/ACM 機能を使う
USB CDC/ACM 機能を使うためのユーティリティコマンドについて説明します。
USB CDC/ACM 機能を有効にすると拡張ボードの USB をシリアルポートとして使用することができます。
21.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/usbcdcacm
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/usbcdcacm make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
21.2. 動作確認
拡張ボードの USB 端子とホスト PC とを USB ケーブルで接続します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
USB CDC/ACM 機能を開始する場合、NuttShell から
sercon
コマンドを実行します。nsh> sercon sercon: Registering CDC/ACM serial driver sercon: Successfully registered the CDC/ACM serial driver
Spresense ボード上に
/dev/ttyACM0
が追加され、ホスト PC には新たな COM ポートが見つかります。 そのポートを使って、USB 経由でシリアル通信をすることができるようになります。 -
USB CDC/ACM 機能を終了する場合、NuttShell から
serdis
コマンドを実行します。nsh> serdis serdis: Disconnected
22. Zmodem を使ったファイル転送
この章では、Zmodem 転送を利用して HostPC と Spresense ボードとの間でファイルを送受信する方法について示します。
22.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/zmodem
を指定してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/zmodem make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
22.2. 動作手順
Zmodem 転送機能に対応したシリアルターミナルを使用してください。
ここでは、minicom を例にとって説明します。
minicom や lrzsz がインストールされていない場合は事前にインストールしてください。
sudo apt install minicom lrzsz
minicom を起動します。
minicom -D /dev/ttyUSB0 -b 115200
NuttShell から Zmodem の rz (受信), sz (送信) コマンドを使用することができます。
- rz コマンドの使い方
-
- sz コマンドの使い方
-
22.2.1. HostPC から Spresense ボードへのファイル転送
HostPC から Spresense ボードへファイルを転送する手順を以下に示します。
-
minicom 上で
CTRL-a
を押下した後にz
キーを押してメニューを開きます。(このショートカットキーの割り当てはユーザー側で変更可能です。詳細は minicom のマニュアルを参照してください。)
続けてs
キーを押して Send files (ファイル送信) を選択します。 -
カーソルキーで zmodem を選択して
Enter
キーで実行します。 -
カーソルキーとスペースキーでフォルダを移動をして転送したいファイルを選択します。
カーソルキーでフォルダを選びスペースキーを2回押すとフォルダへ移動できます。
カーソルキーでファイルを選びスペースキーで選択した後にEnter
キーを押すと転送を開始します。もしくは、
Enter
キーを押してファイル名を入力して転送を実行することもできます。 -
ファイル転送が始まり、Transfer complete と表示されれば転送完了です。
-
Spresense ボード上のファイルの転送先は、CONFIG_SYSTEM_ZMODEM_MOUNTPOINT で変更することができます。
デフォルトのコンフィギュレーションでは、Flash 上の/mnt/spif
以下にファイルが転送されます。
TeraTerm を使用する場合は、TeraTerm メニューから ファイル → 転送 → ZMODEM → 送信 から選択したファイルを送信することができます。
|
22.2.2. Spresense ボードから HostPC へのファイル転送
Spresense ボードから HostPC へファイルを転送する手順を以下に示します。
-
NuttShell 上で、
sz
コマンドの引数に転送したいファイルを指定して実行します。
ファイル名は / から始まるフルパス名を入力してください。
以下の例は、-x 1
バイナリ転送オプションを付けています。nsh> sz -x 1 /mnt/spif/test00.dat
-
ファイル転送が始まり、Transfer complete と表示されれば転送完了です。
-
HostPC 上の minicom を実行したフォルダにファイルが転送されます。
TeraTerm を使用する場合は、NuttShell から sz コマンドを入力した後に、ファイル → 転送 → ZMODEM → 受信 によりファイルを受信することができます。HostPC 側のファイル受信ディレクトリは、ファイル → ディレクトリを変更 によって指定可能です。
|
23. アプリケーションの自動起動方法
この章では、電源投入時に NuttShell プロンプトではなくユーザーアプリケーションを自動的に起動する方法について記述します。 NuttShellでは、簡単なシェルスクリプトを実行することが出来、かつ、特定のスクリプトを起動時に実行する機能を持っています。 この章では、その機能を用いた、自動起動について解説します。
NuttShell 上で利用できる基本的なコマンドや、if, whileといった制御構文については、 NuttShell (NSH) documentation を参照してください。
23.1. Spresense SDK でのスタートアップスクリプトの使い方
NuttX で自動起動スクリプトを利用するには、コンフィグでその機能を有効にする必要があります。 Spresense SDK では、自動起動を有効にするためのデフォルトとなるコンフィグを提供しています。
この章での例としては、"hello" ビルドインコマンドを自動起動スクリプトを使って、 起動後、3秒おきにhelloを表示させるスクリプトを作成してみます。
23.1.1. コンフィグレーション
まずは、今回の例で使用する "hello" ビルドインコマンドと、自動起動を有効にするデフォルトコンフィグを使って、
SDKのコンフィグを行います。
spresense/sdk ディレクトリに移動して、以下のようにconfig.pyに2つのパラメータを指定してを実行してください。
./tools/config.py examples/hello feature/startup_script
一つ目のパラメータ examples/hello は "hello" ビルドインコマンドを有効にするオプションで、2つ目のパラメータ feature/startup_script は、自動起動の仕組みを有効にするオプションになります。
このように、Spresense SDK の config.py では、オプションに色々と追加していくことでSDKとして用意しているデフォルトコンフィグを追加していく、ということが出来るようになっています。 |
23.1.2. ビルドとフラッシュ
コンフィグが完了したら、同じ spresense/sdk ディレクトリ下で、以下のコマンドを実行して nuttx.spk を実機に書き込みます。
make tools/flash.sh -c /dev/ttyUSB0 nuttx.spk >>> Install files ... install -b 115200 Install nuttx.spk |0%-----------------------------50%------------------------------100%| ###################################################################### xxxxx bytes loaded. Package validation is OK. Saving package to "nuttx" updater# sync updater# Restarting the board ... reboot
23.1.3. 動作確認(自動起動なし)
nuttx.spk を書き込んだだけでは、自動的に起動することはありません。 ここでは、まずは書き込んだ nuttx.spk が正しく "hello" ビルドインコマンドを含んでいるか、 確認してみます。 まず、適当なターミナルソフト(以下の例は minicom を使用しています)を使って、実機のUARTポートに接続します。この例では、実機のポートは、 /dev/ttyUSB0 としていますが、お使いの環境に合わせて設定してください。
minicom -D /dev/ttyUSB0 -b 115200
実機に接続すると、以下のメッセージが出て、 nsh> プロンプトが表示されます。
No /mnt/spif/init.rc. NuttShell (NSH) NuttX-8.2 nsh>
ターミナルによっては、接続時にボードにリセットをかけないものもあるようです。上記のメッセージはリセット直後に表示されるものなので、表示されないような場合は、ターミナルは接続したまま、Spresenseボードのリセットを押してみてください。 |
この状態で "help" と叩くと以下のように Builtin Apps: の中に hello があることが確認できます。
nsh> help help usage: help [-v] [<cmd>] [ dirname free mb mv set unset ? date help mkdir mw sh usleep basename dd hexdump mkfatfs poweroff sleep xd break df ifconfig mkfifo ps test cat echo ifdown mkrd pwd time cd exec ifup mksmartfs reboot true cp exit kill mh rm uname cmp false ls mount rmdir umount Builtin Apps: hello nsh nsh>
ここで、 hello を実行して、動作を確認します。
nsh> hello Hello, World!! nsh>
これで、 hello が動作することは確認できました。 次に、これを3秒おきに実行するスクリプトを作成して、実機で動作させます。
23.1.4. 動作確認(自動起動)
前の節で hello の動作を確認したら、一度ターミナルから抜け、スクリプトファイルを作成します。
スクリプトファイル名は、 init.rc としてください。 以下のようなスクリプトを作成します。
-
init.rc
while true do sleep 3 hello done
シンプルなスクリプトですが、 while true で無限ループを作り、 sleep 3 で3秒待ち、 hello を実行する、というのを延々と繰り返すスクリプトになります。
このスクリプトをSpresenseメインボードのSPIフラッシュに書き込みます。 init.rc が spresense/sdk ディレクトリ内にあるとして、spresense/sdk ディレクトリ内で、以下のようなコマンドを実行してください。
./tools/flash.sh -w init.rc xmodem >>> Install files ... nsh> xmodem /mnt/spif/init.rc Install init.rc |0%-----------------------------50%------------------------------100%| ###################################################################### nsh>
flash.sh は、 -w オプションを指摘することで、その後の引数で指定されたファイルを、実機のSPIフラッシュに書き込みを行います。
flash.shを -w で実行すると、nuttx.spk を再度書き込む必要が出てきます。 すでにビルド済みの nuttx.spk が spresense/sdk にあるので、それを再度書き込みます。
tools/flash.sh -c /dev/ttyUSB0 nuttx.spk >>> Install files ... install -b 115200 Install nuttx.spk |0%-----------------------------50%------------------------------100%| ###################################################################### xxxxx bytes loaded. Package validation is OK. Saving package to "nuttx" updater# sync updater# Restarting the board ... reboot
この状態で再度ターミナルに接続してみます。
Run /mnt/spif/init.rc. sh [8:100] NuttShell (NSH) NuttX-8.2 nsh> Hello, World!! Hello, World!! Hello, World!! Hello, World!! Hello, World!!
繋ぐと、3秒おきに、意図した通り、 "Hello, World!!" というメッセージが表示されることが確認できます。
23.2. TIPS: Application エントリーポイント
スタートアップスクリプトとは別に CONFIG_INIT_ENTRYPOINT を変更するという方法もあります。
デフォルトのコンフィギュレーションでは、CONFIG_INIT_ENTRYPOINT=spresense_main となっています。
これを例えば hello_main に変更すると、起動時に hello アプリケーションを起動するように変更できます。
エントリーポイントの関数名は、サンプルコードのMakefileで定義している PROGNAME 変数に入っている文字列に、_main を付けたものになります。例:spresense/sdk/apps/examples/hello/Makefileに、PROGNAMEの定義が $(CONFIG_EXAMPLES_HELLO_PROGNAME) となっています。これは、Kconfigのパラメータで名前が確定しており、spresense/sdk/apps/examples/Kconfigを見ると、config EXAMPLES_HELLO_PROGNAME の欄に、default "hello" と記載されています。この場合、PROGNAMEがhelloとなるため、 "hello_main"がエントリー関数名となります。 |
起動時にアプリケーションの初期化処理が必要です。以下を参考に、#include <sys/boardctl.h> を追加し、ユーザーエントリーポイント関数の中から boardctl(BOARDIOC_INIT, 0); を呼び出してください。 |
#include <sys/boardctl.h>
int main(int argc, FAR char *argv[])
{
/* Initialize apllication */
boardctl(BOARDIOC_INIT, 0);
printf("Hello, World!!\n");
return 0;
}
24. ローダブルELFチュートリアル
ローダブルELFとは、OSとアプリケーションを別々のバイナリで作成し、動作時にアプリケーションをロードして実行できる機能です。
アプリケーションをローダブルELFとして作成すると、必要に応じてメモリにロードすることが可能になるため、実行時の総メモリ量を抑えたり、アプリケーションを単独で更新することができるようになります。ただし、アプリケーションの起動時間が伸びたり、ロード/アンロードを繰り返す事によるメモリの断片化が発生する可能性もあるため注意が必要です。
ASMP ELFとの互換性はありません。起動するアプリケーションはメインコアでのみ実行されます。 |
このチュートリアルでは、アプリケーションのELFファイルの格納場所にSDカードを使用します。
24.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/loadable
device/sdcard
を指定してコンフィグレーションを実行します。tools/config.py feature/loadable device/sdcard tools/config.py -m
メニューコンフィグを開き、
Hello, World! example
を有効にします。この時、Hello, World! example
がM
となるように設定するとそのアプリケーションがローダブルELFとしてビルドされます。[Application Configuration] [Examples] ["Hello, World!" example] => M
コンフィグレーションが完了したらビルドします。
make
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが、sdk/apps/bin
以下に ELFファイルhello
がそれぞれ生成されます。hello
は別途SDカードにコピーしてください。 -
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
24.2. 動作確認
シリアルターミナルを開いて、hello
アプリケーションを実行します。
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
hello
アプリケーションを実行します。SDカードにある
hello
ELFファイルまでのフルパスを指定します。nsh> /mnt/sd0/hello Hello, World!!
24.3. PATH変数を使用する
NuttShellでは、bashの環境変数と同様 PATH
変数を用いてELFファイルを検索するパスの設定ができます。 feature/loadable
にはこれを使用するための設定が含まれていますが、実際に使用するパスはユーザー自身で設定する必要があります。
メニューコンフィグを開いて PATH
変数にSDカードのパスを設定します。この設定を行うことでSDカードの直下に置かれているアプリケーションはフルパスを指定しなくても実行することができるようになります。
[Binary Loader] [Initial PATH Value] => "/mnt/sd0"
ビルドして nuttx.spk
を書き込んでください。起動後、NuttShellから hello
とタイプするだけでSDカード上の hello
アプリケーションを起動することができるようになります。
nsh> hello Hello, World!!
25. LLVM C++ 標準ライブラリ
ユーザープログラムから LLVM C++ 標準ライブラリを利用する方法について説明します。 ビルド中に LLVM ソースコードをダウンロードしコンパイルを行うため、ネットワークに接続された環境でビルドを行ってください。
コンパイラを gcc-arm-none-eabi-9-2019-q4-major 以降のバージョンへ更新する必要があります。
バージョンが古い場合は、開発ツールのセットアップ を参考にコンパイラのバージョンアップを行ってください。
|
25.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/helloxx
といったアプリケーションの他にfeature/libcxx
を追加してコンフィグレーションを実行します。 また、ここではC++テストプログラムを実行するため、-m
オプションを追加して menuconfig を開きます。tools/config.py examples/helloxx feature/libcxx -m
Application Configuration
→Testing
→C++ test program
を有効にします。SDKではコンパイルオプションに
-fno-rtti
を付けて RTTI(実行時型情報) を無効にしているため、sdk/apps/testing/cxxtest/cxxtest_main.cxx
ファイルを開いて、test_rtti()
をコメントアウトしてください。diff --git a/testing/cxxtest/cxxtest_main.cxx b/testing/cxxtest/cxxtest_main.cxx index 6baa7d3..288aa40 100644 --- a/testing/cxxtest/cxxtest_main.cxx +++ b/testing/cxxtest/cxxtest_main.cxx @@ -184,6 +184,7 @@ static void test_stl(void) static void test_rtti(void) { +#ifdef __GXX_RTTI std::cout << "test rtti===============================" << std::endl; Base *a = new Base(); Base *b = new Extend(); @@ -199,6 +200,7 @@ static void test_rtti(void) delete a; delete b; +#endif } //***************************************************************************
make
を実行し、ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
25.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
cxxtest
コマンドを実行します。nsh> cxxtest test ofstream=========================== printf: Starting test_ostream printf: Successfully opened /dev/console cout: Successfully opened /dev/console Writing this to /dev/console test iostream=========================== Hello, this is only a test Print an int: 190 Print a char: d test vector============================= v1=1 2 3 Hello World Good Luck test map================================
このテストプログラムは、
iostream
,vector
やmap
を使ったシンプルなプログラム例になりますが、その他のC++標準ライブラリ(C++11規格まで)もサポートされています。 C++標準ライブラリの詳細については以下を参考にしてください。
26. SMP (Symmetric Multiprocessing)
ここではアプリケーションを SMP 環境で動かす方法や taskset
コマンドの使い方について説明します。
26.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/hello
といったアプリケーションの他にfeature/smp
を追加してコンフィグレーションを実行します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/hello feature/smp make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
feature/smp
のデフォルトはデュアルコア(2コア)構成になっています。 コア数を変更する場合は、sdk/configs/feature/smp/defconfig
ファイルのSMP_NCPUS=2
の数字を変更してください。 2 ~ 最大 6 まで指定可能です。
26.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
ps
コマンドを実行します。ps
の表示結果にCPU
列が表示されこれがコア番号を表します。nsh> ps PID GROUP CPU PRI POLICY TYPE NPX STATE EVENT SIGMASK STACK USED FILLED COMMAND 0 0 0 FIFO Kthread N-- Assigned 00000000 001024 000480 46.8% CPU0 IDLE 1 1 0 FIFO Kthread N-- Running 00000000 002048 000220 10.7% CPU1 IDLE 2 2 0 FIFO Kthread N-- Running 00000000 002048 000220 10.7% CPU2 IDLE 3 3 0 FIFO Kthread N-- Running 00000000 002048 000120 5.8% CPU3 IDLE 4 4 0 FIFO Kthread N-- Running 00000000 002048 000120 5.8% CPU4 IDLE 5 5 0 FIFO Kthread N-- Running 00000000 002048 000120 5.8% CPU5 IDLE 7 --- 224 RR Kthread --- Waiting Signal 00000000 002008 000324 16.1% hpwork 8 --- 100 RR Kthread --- Waiting Signal 00000000 002008 000332 16.5% lpwork 9 --- 100 RR Kthread --- Waiting Signal 00000000 002008 000332 16.5% lpwork 10 --- 100 RR Kthread --- Waiting Signal 00000000 002008 000332 16.5% lpwork 12 --- 200 RR Task --- Waiting MQ empty 00000000 000976 000480 49.1% cxd56_pm_task 13 0 100 RR Task --- Running 00000000 008152 001204 14.7% init
audio アプリケーションなど一部のアプリケーションには、コア番号が
CPU=0
固定でないと動作しないという制約があります。 コア番号を指定してプログラムを実行する場合、taskset
コマンドを利用することができます。 -
NuttShell から
taskset
コマンドを実行します。taskset
コマンドの使い方は以下の通りです。引数mask
には CPU 番号をビットで表したマスク値(1 << CPU番号)を指定します。CPU番号
0
1
2
3
4
5
mask
1
2
4
8
16
32
nsh> taskset -h taskset mask command ... taskset -p [mask] pid
例えば、CPU番号=0 で動かす場合は、
mask
に 1 を指定してください。nsh> taskset 1 hello
27. Task Trace ツール
ここでは Trace Compass を用いて、タスクトレース情報をグラフィカルに表示する方法について説明します。
27.1. Trace Compass インストール
グラフィカル表示ツールとして、Trace Compass を使用します。
Trace Compass ツールのインストールについては、
NuttX Task Trace User Guide マニュアル を参照してください。
-
Trace Compass ツールをダウンロードしてインストールします。
-
2021年8月現在の最新版は
Trace Compass 7.0.0, latest release (requires Java 11)
です。 -
起動に JRE も必要になるので、別途、インストールしてください。
-
-
マニュアルに記載されている通り、Add-on の Trace Compass ftrace (Incubation) をインストールしてください
-
Tools → Add-ons … → Install Extensions
Trace Compass ftrace (Incubation)
-
27.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
examples/camera
といったアプリケーションの他にfeature/tasktrace
を追加してコンフィグレーションを実行します。 また、SD Card へ保存したトレースデータを拡張ボードの USB 経由で取り出すためにfeature/usbmsc
も追加します。
ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py examples/camera feature/tasktrace feature/usbmsc make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
27.3. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
trace
コマンドを実行します。trace
コマンドを実行すると現在の設定情報を確認することができます。nsh> trace Task trace mode: Trace : enabled Overwrite : on (+o) Syscall trace : on (+s) Filtered Syscalls : 0 Syscall trace with args : on (+a) IRQ trace : on (+i) Filtered IRQs : 0
trace
コマンドのUsageは以下の通りです。
詳細は NuttX Trace command description を参照してください。nsh> trace -h Usage: trace <subcommand>... Subcommand: start [-c][<duration>] : Start task tracing stop : Stop task tracing cmd [-c] <command> [<args>...] : Get the trace while running <command> dump [-c][<filename>] : Output the trace result mode [{+|-}{o|s|a|i}...] : Set task trace options syscall [{+|-}<syscallname>...] : Configure syscall trace filter irq [{+|-}<irqnum>...] : Configure IRQ trace filter
trace start
→camera
→trace stop
コマンドでトレースデータを取得し、trace dump
結果を SD Card に保存します。nsh> trace start nsh> camera nximage_listener: Connected nximage_initialize: Screen resolution (320,240) Take 10 pictures as RGB file in /mnt/sd0 after 5 seconds. After finishing taking pictures, this app will be finished after 10 seconds. Expire time is pasted. GoTo next state. Start captureing... FILENAME:/mnt/sd0/VIDEO001.RGB FILENAME:/mnt/sd0/VIDEO002.RGB FILENAME:/mnt/sd0/VIDEO003.RGB FILENAME:/mnt/sd0/VIDEO004.RGB FILENAME:/mnt/sd0/VIDEO005.RGB FILENAME:/mnt/sd0/VIDEO006.RGB FILENAME:/mnt/sd0/VIDEO007.RGB FILENAME:/mnt/sd0/VIDEO008.RGB FILENAME:/mnt/sd0/VIDEO009.RGB FILENAME:/mnt/sd0/VIDEO010.RGB Finished captureing... Expire time is pasted. GoTo next state. nsh> trace stop nsh> trace dump /mnt/sd0/trace.log
-
NuttShell から
msconn
コマンドを実行します。拡張ボード側の USB を PC に接続し、
msconn
コマンドを実行して、PC から SD Card 内のファイルへアクセスします。nsh> msconn mcsonn_main: Creating block drivers mcsonn_main: Configuring with NLUNS=1 mcsonn_main: handle=0x2d04b690 mcsonn_main: Bind LUN=0 to /dev/mmcsd0 mcsonn_main: Connected
-
Trace Compass ツールからトレースデータを読み込みます。
File
→Open Trace…
→ SD Card 上のtrace.log
を開きます。タスクスイッチや割り込み発生の時系列情報をグラフィカルに表示することができます。
28. デバッグログ機能について
この章では、SDK が提供するログ機能について説明します。
28.1. syslog 機能
デバッグログ出力は、システムログ (syslog
) 機能を用いて行われます。syslog
は、Error
(エラー)、Warnings
(警告)、Informational
(情報) の3種類のログレベルをもち、サブシステムやドライバといったモジュールごとにログ出力を行うかどうかをコンフィグレーションにより選択することができます。
デバッグログ機能を有効にするためには、コンフィグレーション済みの状態から menuconfig
を表示します。
cd spresense/sdk tools/config.py -m または make menuconfig
Build Setup
→ Debug Options
から Enable Debug Features
を有効にしてください。
次のメニューが表示されます。
*** Debug SYSLOG Output Controls ***
の項目で全体のログ出力レベルを決定します。
ログレベルの選択はネスト構造になっているので、例えば、Informational
を有効にするときは、Error
および Warnings
も有効にする必要があります。
*** Debug SYSLOG Output Controls ***
[] Enable Error Output
[] Enable Warnings Output
[] Enable Informational Output
プログラム中のログ出力関数と CONFIG
名の関係を以下に示します。
それぞれのログ出力関数は、該当する CONFIG
を有効にしたときにログが出力されるようになります。
例えば、CONFIG_DEBUG_INFO=y
にしたときに _info()
関数を用いたログが出力されます。
CONFIG_DEBUG_INFO=n
のように無効にしたときは、_info()
はコンパイル非対象になりログは出力されません。
ログ出力関数 | CONFIG名 |
---|---|
_err() |
CONFIG_DEBUG_ERROR |
_warn() |
CONFIG_DEBUG_WARN |
_info() |
CONFIG_DEBUG_INFO |
NuttX共通で利用するモジュールごとのログ出力関数は、nuttx/include/debug.h に定義されています。モジュールごとにそれぞれ先頭にprefixを付けたログ出力関数が存在します。例として、ファイルシステムに関するコンフィグレーションを以下に示します。ファイルシステムに関するログ出力関数には先頭に f
が付いたログ出力関数が用意されています。
[*] File System Debug Features
[ ] File System Error Output
[ ] File System Warnings Output
[ ] File System Informational Output
ログ出力関数 | CONFIG名 |
---|---|
ferr() |
CONFIG_DEBUG_FS_ERROR |
fwarn() |
CONFIG_DEBUG_FS_WARN |
finfo() |
CONFIG_DEBUG_FS_INFO |
また、nuttx/include/debug.h に共通定義されているもの以外に、個別にデバッグログ出力をもつドライバやSDK側のモジュールにも別途コンフィグレーションが存在します。
SDK環境で使用する主なモジュールとデバッグログ機能の CONFIG
名を以下に示します。
該当モジュールに対するデバッグログを有効にする場合は、menuconfig
から以下の CONFIG
名で検索してください。
モジュール | CONFIG名 |
---|---|
SCUドライバ |
CONFIG_CXD56_SCU_DEBUG |
modemドライバ |
CONFIG_MODEM_ALT1250_DEBUG |
HostIFドライバ |
CONFIG_CXD56_HOSTIF_DEBUG |
GNSSドライバ |
CONFIG_CXD56_GNSS_DEBUG_FEATURE |
ASMP |
CONFIG_ASMP_DEBUG_FEATURE |
Audio |
CONFIG_AUDIOUTILS_{EVENT,STATE, DETAIL}LOG |
mbedTLS_stub |
CONFIG_LTE_NET_MBEDTLS_{ERROR,DEBUG}_MSG |
MPCOMM |
CONFIG_MPCOMM_DEBUG_FEATURE |
Sensor Manager |
CONFIG_SENSING_MANAGER_DEBUG_FEATURE |
Step Counter |
CONFIG_SENSING_STEPCOUNTER_DEBUG_FEATURE |
xmodem |
CONFIG_DEBUG_XMODEM |
詳細な動作を確認したいときや個々のモジュールをデバッグしたいときなど、デバッグログ機能を有効利用してみてください。
syslog 機能と printf を併用する場合、printf 出力はバッファリングされて表示されるため、syslog ログと順序関係が前後する可能性があります。
|
28.2. RAM log 機能
前述した syslog
は、通常、UART
等のシリアルコンソールへログを出力しますが、コンフィグレーションを変更することで
別のデバイスへ出力先を切り替えることができます。ここでは、RAM
メモリ上のバッファ(以降、RAM
バッファと呼ぶ)へログを出力する方法について説明します。
RAM
バッファへ出力することにより、UART
へアクセスするときのような速度的なオーバーヘッドを減らすことができます。
RAM
バッファに溜まったログは dmesg
コマンドによってまとめてコンソールに出力することが可能です。
28.2.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数にアプリケーションの他に
feature/ramlog
もしくはfeature/ramlog_circular
を追加してコンフィグレーションを実行します。ramlog
のコンフィグレーションについては、用途に応じてどちらか適切な方を選択してください。defconfig 説明 feature/ramlog
RAM バッファがフル(満杯)になるまでロギングします。フルになるとログのバッファリングが止まります。
dmesg
コマンドを実行するとバッファは空になり、バッファリングを再開します。feature/ramlog_circular
RAM バッファがリングバッファ構造になっており、常に最新のログで上書き更新されます。
tools/config.py feature/ramlog または tools/config.py feature/ramlog_circular
もし
RAM
バッファのサイズを変更したいときは、menuconfig
によりCONFIG_RAMLOG_BUFSIZE
の値を変更してください。make
を実行し、ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
28.2.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
dmesg
コマンドを実行することで、RAM バッファに溜まったタイムスタンプ付きのログをコンソールに出力します。
以下はファイルシステムの詳細ログを有効にしたときのログ例です。nsh> dmesg [ 51.161556] smart_ioctl: Entry [ 51.161648] smart_readsector: Entry [ 51.161709] cxd56_bread: bread: 00009000 (1 blocks) [ 51.163510] smart_ioctl: Entry [ 51.163571] smart_readsector: Entry [ 51.163662] cxd56_bread: bread: 00009000 (1 blocks) [ 51.165463] smart_ioctl: Entry [ 51.165524] smart_readsector: Entry [ 51.165615] cxd56_bread: bread: 00009000 (1 blocks) [ 51.167446] smart_ioctl: Entry [ 51.167507] smart_readsector: Entry [ 51.167599] cxd56_bread: bread: 00009000 (1 blocks)
28.3. crash dump 機能
assert
や Hard fault
による crash が発生したときのログ(crash dump
ログ)をファイルに保存する機能をサポートしています。
この機能は、feature/crashdump
コンフィグレーションを使用することで利用可能です。
はじめに簡単に動作を確認するための手順を説明した後に、ソースコードの解説を行います。
28.3.1. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/crashdump
を追加してコンフィグレーションを実行します。 また、crash
を発生させる目的でここではexamples/watchdog
も同時に指定します。tools/config.py feature/crashdump examples/watchdog
make
を実行し、ビルドに成功するとsdk
フォルダ直下にnuttx.spk
ファイルが生成されます。make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
28.3.2. 動作確認
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell から
wdog
コマンドを実行するとHard fault
が発生し、その後、リブートします。nsh> wdog ping elapsed=0 ping elapsed=496 (snip) up_assert: Assertion failed at file:irq/irq_unexpectedisr.c line: 50 task: wdog up_registerdump: R0: 00000008 00000001 2d02e7f8 00000008 2d02e7f8 2d02e7f8 2d02e7f8 00000001 up_registerdump: R8: 000f4240 0d026575 00000020 2d035bf4 0000001d 2d035b08 0d006601 0d006604 (snip) up_stackdump: 2d035c60: 00000000 0d00421d 00000000 00000000 2d035c78 00000000 676f6477 deadbe00 up_taskdump: Idle Task: PID=0 Stack Used=468 of 1024 up_taskdump: hpwork: PID=1 Stack Used=324 of 2008 up_taskdump: lpwork: PID=2 Stack Used=332 of 2008 up_taskdump: lpwork: PID=3 Stack Used=332 of 2008 up_taskdump: lpwork: PID=4 Stack Used=332 of 2008 up_taskdump: cxd56_pm_task: PID=6 Stack Used=400 of 976 up_taskdump: init: PID=7 Stack Used=944 of 8152 up_taskdump: wdog: PID=8 Stack Used=636 of 2008 up_taskdump: wdog: PID=8 Stack Used=636 of 2008 NuttShell (NSH) NuttX-10.1.0 nsh>
-
リブートした後に、NuttShell から
logdump crash
コマンドを実行すると、Watchdog
が発生したときのcrash dump
情報を表示することができます。nsh> logdump crash === Dump crash at 0x04408200 (1020 bytes) date: Jan 01 00:00:12 1970 file: irq/irq_unexpectedisr.c line: 50 task: wdog pid: 8 user sp: 2d035b08 stack base: 2d035c70 stack size: 000007d8 int sp: 2d027338 stack base: 2d0273b0 stack size: 00000800 regs: S0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 S8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 S16: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 S24: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 FPSCR: 00000000 R0: 00000008 00000001 2d02e7f8 00000008 2d02e7f8 2d02e7f8 2d02e7f8 00000001 R8: 000f4240 0d026575 00000020 2d035bf4 0000001d 2d035b08 0d006601 0d006604 xPSR: 61000000 BASEPRI: 000000e0 EXC_RETURN: ffffffe9 interrupt stack: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000000d 676f6477 0d000333 00000001 2d02e7f8 2d02e7f8 2d035a34 000000e0 0d00194d 000000e0 0d003413 0d003439 0d00344d 00000080 0d006549 2d035bf4 00000020 0d026575 000f4240 00000000 00000002 2d035a34 2d029a84 2d02e5b0 0d006539 0d006604 0d006601 2d035b08 0000001d 2d035bf4 00000000 000000e0 0d008279 0d021d7c 2d035c70 2d029a84 2d035b08 2d027338 0d00d619 04408200 04408200 044085fc 07249e03 0000000c 0d005aab 0d021d7c 2d027338 04408200 04408200 ffffffff 0d005383 2d027308 00000032 00000032 000003fc 2d027338 2d02e5b0 2d027338 0d011cab 000001e0 0000001e 0d006949 00000030 0d006949 0d00fd9d 2d0273b0 0d00fd57 2d0273b0 2d02e5b0 00000000 2d029ab8 00000080 0d00809d 2d0272d4 user stack: 2d035bf4 2d035bf0 0d01db85 0d026560 00000000 0d026575 000f4240 00000000 00001b54 0d026575 2d02e7f8 ffffffff 00000000 2d035ba8 0d005897 00000000 2d02e5b0 00000014 00000000 00000000 00000000 0d026576 00000000 00000000 0d006977 00000000 2d035bb8 0d01dba1 0d01dbaf 00000020 2d035bb8 2d035bf4 2002e7f8 00000020 0d01e4f5 00000000 00001b54 2d02e7f8 00000020 0d01dba1 0d01d9e5 2d02e7f8 2d02e7f8 2d035b37 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 61000000 0d006604 0d006601 0000001d 00000008 2d02e7f8 00000001 00000008 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 No such file: /mnt/spif/crash.log
-
また、NuttShell から
logsave
コマンドを実行すると、crash dump
のRAWバイナリデータを/mnt/spif/crash.log
に保存することができます。 保存したバイナリファイルは、後からlogdump crash
コマンドを使うことでデコードして表示することができます。nsh> logsave Save at 0x04408200 (1020 bytes) into /mnt/spif/crash.log
28.3.3. 解説
NuttX では、Hard fault
が発生したときに、board_crashdump()
関数が呼び出されます。
board_crashdump()
関数は、nuttx/boards/arm/cxd56xx/common/src/cxd56_crashdump.c に定義されています。
up_backuplog_alloc()
関数を呼び出し、バックアップSRAMから "crash" というキーワード名でメモリを確保しています。
#ifdef CONFIG_CXD56_BACKUPLOG
pdump = up_backuplog_alloc("crash", sizeof(fullcontext_t));
#else
確保したバックアップSRAMメモリに対して crash dump
情報を書き込みます。
board_crashdump()
関数の最後に、board_reset_on_crash()
関数を呼び出してリブートを行います。
#if defined(CONFIG_CXD56_RESET_ON_CRASH)
board_reset_on_crash();
#endif
ポイントとして、バックアップSRAMに保存された内容は、電源を落とさない限り保持され続けます。
crash dump
はこの仕組みを利用しています。バックアップSRAMに一時的に情報を保存しておき、リブート後にその情報を参照しています。
リブート後に情報を参照することで、例えば、crash
発生時にファイルへの書き込みができないような問題を回避しています。
次に、リブート後に crash dump
を取得する方法について説明します。
logdump
コマンドのソースコードは sdk/system/logdump/logdump.c にあります。
コマンド引数 "crash" というキーワード名を指定して、up_backuplog_region()
関数により、crash dump
が保存されているアドレスとサイズを取得します。
/* Dump from memory */
up_backuplog_region(name, &addr, &size);
アドレスとサイズを logdump_sub()
関数に渡して、バックアップSRAMへ保存していた crash dump
情報をデコードして表示します。
printf("=== Dump %s at 0x%08x (%d bytes)\n", name, (uint32_t)addr, size);
logdump_sub(name, addr, size);
crash dump
のRAWバイナリデータをファイルへ保存するには logsave
コマンドを利用します。logsave
コマンドのソースコードは sdk/system/logsave/logsave.c にあります。
up_backuplog_entry()
関数により、バックアップSRAMに保存されたキーワード名"crash"とアドレス、サイズ情報を取得します。
/* Get a log entry */
ret = up_backuplog_entry(name, &addr, &size);
バックアップSRAMに保持されている情報を CONFIG_SYSTEM_LOGSAVE_MOUNTPOINT
の指定先へファイルとして保存します。
CONFIG_SYSTEM_LOGSAVE_MOUNTPOINT
のデフォルトは "/mnt/spif" となっており、crash dump
のRAWバイナリデータは "/mnt/spif/crash.log" へ保存します。
このファイルへは追記で書き込みを行うため、起動時に毎回 logsave
コマンドを発行するようにしておくことで、crash
の履歴をファイルとして保存しておくことが可能です。また、ここで保存したデータは、前述した logdump
コマンドによって後からデコードして表示することができます。
最後に、crash dump
以外にもバックアップSRAMに何かしら情報を保存しておき、リブート後にそれを参照するといった応用的な使い方も可能です。
ここで実装されているソースコードを参考にしてみてください。
29. コールスタックログの解析方法
この章では、Spresense上で動作させているプログラムがアサートした場合などに表示されるダンプログからコールスタックを抽出するスクリプト callstack.py
の使い方について説明します。
29.1. callstack.py
について
Spresenseでプログラムを実行させているとプログラムの問題などで以下のようなダンプログが表示されることがあります。
arm_hardfault: Hard Fault escalation:
arm_hardfault: PANIC!!! Hard Fault!:arm_hardfault: IRQ: 3 regs: 0x2d035d2c
arm_hardfault: BASEPRI: 000000e0 PRIMASK: 00000000 IPSR: 00000003 CONTROL: 00000000
arm_hardfault: CFSR: 00040000 HFSR: 40000000 DFSR: 00000000 BFAR: e000ed38 AFSR: 00000000
arm_hardfault: Hard Fault Reason:
up_assert: Assertion failed at file:armv7-m/arm_hardfault.c line: 173 task: hello
arm_registerdump: R0: 2d0284c8 R1: 0d0258aa R2: 2d035e18 R3: 00000028
arm_registerdump: R4: 0d012481 R5: 2d0284c8 R6: 0d0258aa FP: 2d035e18
arm_registerdump: R8: 00000028 SB: 2d02e930 SL: 2d035e18 R11: 00000000
arm_registerdump: IP: 2d02e930 SP: 2d035e00 LR: 2d035e18 PC: 00000000
arm_registerdump: xPSR: ffffffe9 BASEPRI: 000000e0 CONTROL: 00000000
arm_registerdump: EXC_RETURN: ffffffe9
...
arm_dump_stack: User Stack:
arm_dump_stack: sp: 2d035e00
arm_dump_stack: base: 2d035688
arm_dump_stack: size: 000007d8
arm_stackdump: 2d035e00: 2d035e18 00000028 2d02e930 2d035e18 00000000 ffffffe9 00000000 00000000
arm_stackdump: 2d035e20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d035e40: 00000000 00000000 00000000 2d035e00 000000e0 0d012481 2d0284c8 0d0258aa
arm_showtasks: PID PRI STACK USED FILLED COMMAND
arm_showtasks: ---- ---- 2048 456 22.2% irq
arm_dump_task: 0 0 1000 396 39.6% Idle Task
arm_dump_task: 1 224 1992 276 13.8% hpwork 0x2d028720
arm_dump_task: 2 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 3 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 4 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 13 100 2008 532 26.4% hello
arm_dump_task: 6 200 976 464 47.5% cxd56_pm_task
arm_dump_task: 7 100 8144 1076 13.2% spresense_main
このログメッセージを callstack.py
で解析させることによって、以下のようなコールスタックとして抽出することができます。
[0d006eb5] vsyslog + 0x15
[0d005d17] _assert + 0x7
[0d001b03] arm_hardfault + 0xa7
[0d0258aa] g_builtins + 0x76
[0d00365f] irq_dispatch + 0x17
[0d001a49] arm_doirq + 0x1d
[0d012481] hello_main + 0x1
[0d00030d] exception_common + 0x35
[0d012481] hello_main + 0x1
[0d0258aa] g_builtins + 0x76
29.2. callstack.py
の使い方について
ダンプログからコールスタックを抽出するためには、以下のバイナリとテキスト情報を使います。
-
ダンプログを含むSpresenseの動作ログ(
log.txt
) -
動作させているプログラムをビルドした際に生成されたMAPファイル(
System.map
)
以上のファイルを使って、以下のコマンドを使ってコールスタックを表示します。
$ cd sdk
$ ../nuttx/tools/callstack.py System.map log.txt
以下は examples/hello
サンプルに assert
処理を意図的に入れた場合の解析結果の例になります。
$ ../nuttx/tools/callstack.py System.map log.txt
NuttShell (NSH) NuttX-11.0.0
nsh> hello
Hello, World!!
up_assert: Assertion failed at file:hello_main.c line: 40 task: hello
arm_hardfault: Hard Fault escalation:
arm_hardfault: PANIC!!! Hard Fault!:arm_hardfault: IRQ: 3 regs: 0x2d035d2c
arm_hardfault: BASEPRI: 000000e0 PRIMASK: 00000000 IPSR: 00000003 CONTROL: 00000000
arm_hardfault: CFSR: 00040000 HFSR: 40000000 DFSR: 00000000 BFAR: e000ed38 AFSR: 00000000
arm_hardfault: Hard Fault Reason:
up_assert: Assertion failed at file:armv7-m/arm_hardfault.c line: 173 task: hello
arm_registerdump: R0: 2d0284c8 R1: 0d0258aa R2: 2d035e18 R3: 00000028
arm_registerdump: R4: 0d012481 R5: 2d0284c8 R6: 0d0258aa FP: 2d035e18
arm_registerdump: R8: 00000028 SB: 2d02e930 SL: 2d035e18 R11: 00000000
arm_registerdump: IP: 2d02e930 SP: 2d035e00 LR: 2d035e18 PC: 00000000
arm_registerdump: xPSR: ffffffe9 BASEPRI: 000000e0 CONTROL: 00000000
arm_registerdump: EXC_RETURN: ffffffe9
arm_dump_stack: IRQ Stack:
arm_dump_stack: sp: 2d027a50
arm_dump_stack: base: 2d0272c0
arm_dump_stack: size: 00000800
arm_stackdump: 2d027a40: 00000001 00000000 00000000 0d006eb5 40000000 00000003 2d035d2c 00040000
arm_stackdump: 2d027a60: 00000028 2d02e930 2d035e18 0d005d17 00000080 0d001b03 40000000 00000000
arm_stackdump: 2d027a80: e000ed38 00000000 00000000 00000000 2d0284c8 0d0258aa 2d035e18 0d00365f
arm_stackdump: 2d027aa0: 00000000 0d001a49 00000003 00000003 2d035e00 0d012481 2d0284c8 0d00030d
arm_dump_stack: User Stack:
arm_dump_stack: sp: 2d035e00
arm_dump_stack: base: 2d035688
arm_dump_stack: size: 000007d8
arm_stackdump: 2d035e00: 2d035e18 00000028 2d02e930 2d035e18 00000000 ffffffe9 00000000 00000000
arm_stackdump: 2d035e20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d035e40: 00000000 00000000 00000000 2d035e00 000000e0 0d012481 2d0284c8 0d0258aa
arm_showtasks: PID PRI STACK USED FILLED COMMAND
arm_showtasks: ---- ---- 2048 456 22.2% irq
arm_dump_task: 0 0 1000 396 39.6% Idle Task
arm_dump_task: 1 224 1992 276 13.8% hpwork 0x2d028720
arm_dump_task: 2 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 3 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 4 100 1992 276 13.8% lpwork 0x2d028730
arm_dump_task: 13 100 2008 532 26.4% hello
arm_dump_task: 6 200 976 464 47.5% cxd56_pm_task
arm_dump_task: 7 100 8144 928 11.3% spresense_main
----------------- callstack -----------------
[0d006eb5] vsyslog + 0x15
[0d005d17] _assert + 0x7
[0d001b03] arm_hardfault + 0xa7
[0d0258aa] g_builtins + 0x76
[0d00365f] irq_dispatch + 0x17
[0d001a49] arm_doirq + 0x1d
[0d012481] hello_main + 0x1
[0d00030d] exception_common + 0x35
[0d012481] hello_main + 0x1
[0d0258aa] g_builtins + 0x76
このログから [0d012481] hello_main + 0x1
が最後のコールスタック情報であることから、 hello_main
の先頭付近でアサートしていることがわかります。
30. VTUN (Virtual Tunnels over TCP/IP networks)
VTUNはTCP/IPネットワーク上で仮想トンネルを設定できるネットワークアプリケーションです。
2つの異なるネットワークアドレス上で仮想トンネルを設定し仮想ネットワークアドレスを構築することでサーバ・クライアント間で相互Socket通信を行うことができます。
以下の構成のようにクライアントからグローバルネットワーク(aaa.bbb.ccc.0)に存在するサーバへは直接アクセスが可能でも、サーバからはLTEのローカルネットワーク(xxx.yyy.zzz.0)上に存在するSpresenseに対しては直接アクセスすることはできません。
VTUNを使い仮想ネットワーク(192.168.254.0)を構築することで、サーバからクライアントであるSpresenseに対し直接アクセスすることができるようになります。
詳しくはVTUN公式ページをご参照ください。
ここではVTUNで仮想ネットワークを構成する方法について説明します。
30.1. VTUN設定ファイルの作成
VTUNによる仮想ネットワークを構築するためには、サーバ・クライアントともに設定ファイルを用意する必要があります。
ここでは、サーバ対クライアントの1対1間の構成を例に取り設定内容について説明します。
30.1.1. サーバ側の設定ファイル
サーバ側の vtund
で使用する設定ファイルです。
-
options
ネットワーク設定時に使用する
ip
コマンドのパスを設定します。通常は/sbin/ip
に存在するので、/sbin/ip
と設定します。 -
default
セッション共通の設定をします。
-
type
VTUNが使用するトンネルのタイプを指定します。
-
tun
: IPトンネル -
ether
: イーサーネットトンネル
-
-
proto
VTUNが使用するプロトコルを指定します。
-
udp
: UDPプロトコル経由でVTUN接続 -
tcp
: TCPプロトコル経由でVTUN接続
-
-
keepalive
定期的な接続確認を行うかを設定します。
-
yes
: 定期的に接続状態を確認する。 -
no
: 定期的に接続状態を確認しない。
-
-
encrypt
トンネル内でやり取りするデータの暗号化方法を指定します。
-
no
: 平文のままトンネルで送受信する。 -
aes128cbc
: AES暗号 128bitキー モードCBCを使って暗号化し、トンネルで送受信する。 -
aes128cfb
: AES暗号 128bitキー モードCFBを使って暗号化し、トンネルで送受信する。 -
aes128ecb
: AES暗号 128bitキー モードECBを使って暗号化し、トンネルで送受信する。 -
aes256cbc
: AES暗号 256bitキー モードCBCを使って暗号化し、トンネルで送受信する。 -
aes256cfb
: AES暗号 256bitキー モードCFBを使って暗号化し、トンネルで送受信する。 -
aes256ecb
: AES暗号 256bitキー モードECBを使って暗号化し、トンネルで送受信する。 -
blowfish128ecb
: Blowfish暗号 128bitキー モードECBを使って暗号化し、トンネルで送受信する。 -
blowfish256ecb
: Blowfish暗号 256bitキー モードECBを使って暗号化し、トンネルで送受信する。
-
-
stat
統計情報のログ保存を設定します。
-
yes
: 統計カウンターをログに残す。 -
no
: 統計カウンターをログに残さない。
-
-
-
session
任意のセッション名を指定できます。以下の例では
vpn
を使っています。-
passwd
クライアント認証用のパスワードを設定します。
-
device
サーバ上のネットワークデバイス名を指定します。
tun
の場合はtun0
、ether
の場合はtap0
を指定します。 -
up
ネットワークデバイスが有効化した時に実行するコマンドを記載します。
-
down
ネットワークデバイスが無効化した時に実行するコマンドを記載します。
-
30.1.1.1. 設定ファイル例
以下の例では tun
モードを使いサーバ・クライアント間を 192.168.254.0
のネットワークで構成します。
FILE: vtund_server.conf
options { ip /sbin/ip; } default { type tun; proto tcp; keepalive yes; encrypt no; stat yes; } vpn { passwd spresense_vtun; device tun0; up { ip "addr add 192.168.254.1/32 dev %%"; ip "addr add 2222::2/128 dev %%"; ip "link set mtu 1450 dev %%"; ip "link set up dev %%"; ip "route add default via 192.168.254.1 dev %%"; ip "-6 route add default dev %%"; }; down { ip "link set down dev %%"; ip "route del default"; ip "-6 route del default"; }; }
30.2. ビルド手順
ここではコマンドラインによるビルド手順を示します。
IDE を使用してビルドする場合、以下に示すコンフィグレーション情報を参考にしてください。
-
sdk
ディレクトリへ移動します。build-env.sh
スクリプトを読み込むことで、config.py
ツールの Tab 補完機能が有効になります。cd spresense/sdk source tools/build-env.sh
-
SDK のコンフィグレーションとビルドを行います。
引数に
feature/lte
といったネットワーク機能にfeature/vtun
を追加してコンフィグレーションを実行します。
また、 以下のコンフィグをmenuconfig
で追加することによりwget
やwebserver
を有効にすることでSpresenseへの直接アクセスを確認できるアプリケーションを追加できます。EXAMPLES_WEBSERVER=y EXAMPLES_WEBSERVER_DHCPC=y NETUTILS_WEBSERVER=y NETUTILS_WEBCLIENT=y WEBCLIENT_USE_SSL=y
ビルドに成功すると
sdk
フォルダ直下にnuttx.spk
ファイルが生成されます。tools/config.py feature/ethernet feature/vtun -m <追加のコンフィグを設定> make
-
nuttx.spk
を Spresense ボードへ書き込みます。この例では シリアルポートとして
/dev/ttyUSB0
を、書き込み速度の baudrate に500000
bps を設定しています。お使いの環境に合わせて変更してください。tools/flash.sh -c /dev/ttyUSB0 -b 500000 nuttx.spk
ネットワーク機能として、 LTE(ALT1250):
feature/lte
, Wifi(GS2200m):feature/wifi
, Ethernet(WIZnet):feature/ethernet
がVTUNに対応しています。
30.3. 設定ファイルの転送
作成した vtund.conf
ファイルを以下のコマンドでSpresenseに転送します。
./tools/flash.sh -w vtund.conf xmodem >>> Install files ... nsh> xmodem /mnt/spif/vtund.conf Install vtund.conf |0%-----------------------------50%------------------------------100%| ###################################################################### nsh>
30.4. 動作確認
30.4.1. サーバ側
以下のコマンドでVTUNのデーモンをサーバモードで起動します。
(vtund_server.conf
は作成した設定ファイルです。)
sudo vtund -s -f vtund_server.conf -n vtund[21313]: VTUN server ver 3.X 07/30/2015 (standalone)
sudo apt-get install vtund
|
30.4.2. クライアント(Spresesne)側
-
シリアルターミナルを起動します。
シリアルポートに
/dev/ttyUSB0
を、baudrate に115200
bps を指定して、 minicom ターミナルを使用する例を示します。minicom -D /dev/ttyUSB0 -b 115200
-
NuttShell でWIZnetのデーモンを起動します。
nsh> wiznet & wiznet [8:50] ifcowiznet device configured
-
vtun
コマンドでVTUNのデーモンを起動します。nsh> vtun vpn 192.168.11.7 -f /mnt/spif/vtund.conf -n & vtun [11:100] Reloading configuration file VTun client ver 3.X 06/17/2020 started Connecting to 192.168.11.7 Remote Server sends <TuK> . Session vpn[192.168.11.7] opened Created TUN device: tun0 Couldn't run up commands: fork() not available
-
ifconfig
でネットワークインタフェースの状態を確認するとtun0
のアドレスが空でDOWN
状態であることがわかります。nsh> ifconfig tun0 Link encap:TUN at DOWN inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0 eth0 Link encap:Ethernet HWaddr 02:1a:80:00:00:00 at UP inet addr:192.168.11.8 DRaddr:192.168.11.1 Mask:255.255.255.0
-
ifconfig
コマンドでネットワークアドレスを指定し、インタフェースを有効にします。nsh> ifconfig tun0 192.168.254.2 nsh> ifup tun0 ifup tun0...OK
-
再度
ifconfig
でネットワークインタフェースの状態を確認するとtun0
のアドレスが設定されUP
状態であることがわかります。この状態になると、192.168.254.0
というネットワーク上で相互アクセス可能になります。nsh> ifconfig tun0 Link encap:TUN at UP inet addr:192.168.254.2 DRaddr:192.168.254.1 Mask:255.255.255.0 eth0 Link encap:Ethernet HWaddr 02:1a:80:00:00:00 at UP inet addr:192.168.11.8 DRaddr:192.168.11.1 Mask:255.255.255.0
この中の eth0
がローカルネットワークアドレス、tun0
が仮想ネットワークアドレスになります。 -
webserver
コマンドでSpresense上でWebServerを立ち上げます。nsh> webserver Starting webserver
-
サーバ側で
http://192.168.254.2
(Spresense側のTUN0のIPアドレス) をcurl
コマンドで表示すると正しく表示され、サーバからSpresenseへアクセスできることがわかります。curl -x "" http://192.168.254.2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Welcome to the uIP web server!</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body bgcolor="#fffeec" text="black"> <div class="menu"> <div class="menubox"><a href="/">Front page</a></div> <div class="menubox"><a href="files.shtml">File statistics</a></div> <div class="menubox"><a href="stats.shtml">Network statistics</a></div> <br> </div> <div class="contentblock"> <p> These web pages are served by a small web server running on top of the <a href="http://www.sics.se/~adam/uip/">uIP embedded TCP/IP stack</a>. </p> <p> Click on the links above for web server statistics. </p> </div> </body> </html>
31. バックトレース機能について
ここではバックトレース機能を有効にして、スタックダンプのログからコールスタックを取得する方法や、dump_stack()
及び backtrace()
関数の使い方について解説します。
この機能を使うためには、SDK のコンフィグレーションに、feature/backtrace
または feature/debug
を追加してください。
31.1. コールツリーの取得方法
feature/backtrace
または feature/debug
コンフィグレーションを有効にした状態で、Hard Fault が発生したときに次のようなスタックダンプログが表示されます。
arm_hardfault: Hard Fault escalation:
arm_hardfault: PANIC!!! Hard Fault!:arm_hardfault: IRQ: 3 regs: 0x2d044e14
arm_hardfault: BASEPRI: 000000e0 PRIMASK: 00000000 IPSR: 00000003 CONTROL: 00000000
arm_hardfault: CFSR: 00008200 HFSR: 40000000 DFSR: 00000000 BFAR: 05000000 AFSR: 00000000
arm_hardfault: Hard Fault Reason:
up_assert: Assertion failed at file:armv7-m/arm_hardfault.c line: 173 task: spresense_main
backtrace| 7: 0x0d029de6 0x0d01db40 0x0d01a964 0x0d01b43a 0x0d01deea 0x0d01e842 0x0d01a06a 0x0d0062d8
backtrace| 7: 0x0d0048ba
arm_registerdump: R0: 05000000 R1: 00000010 R2: 2d044ec4 R3: 00000000
arm_registerdump: R4: 2d03de70 R5: 2d03de70 R6: 00000000 FP: 05000000
arm_registerdump: R8: 00000001 SB: 05000000 SL: 00000000 R11: 0d033421
arm_registerdump: IP: 00000000 SP: 2d044ee8 LR: 0d0070b9 PC: 0d01db40
arm_registerdump: xPSR: 81000000 BASEPRI: 000000e0 CONTROL: 00000000
arm_registerdump: EXC_RETURN: ffffffe9
arm_dump_stack: IRQ Stack:
arm_dump_stack: sp: 2d036a88
arm_dump_stack: base: 2d0362f8
arm_dump_stack: size: 00000800
arm_stackdump: 2d036a80: 0d01db40 0d007339 40000000 00000003 2d044e14 00008200 00000001 05000000
arm_stackdump: 2d036aa0: 00000000 0d0061bb 00000080 0d001d73 40000000 00000000 05000000 00000000
arm_stackdump: 2d036ac0: 0d0004d1 00000000 2d037500 00000000 05000000 0d003aa7 00000000 0d001cb1
arm_dump_stack: User Stack:
arm_dump_stack: sp: 2d044ee8
arm_dump_stack: base: 2d043110
arm_dump_stack: size: 00001fd0
arm_stackdump: 2d044ee0: 00000000 0d01db0d 2d03de70 00000000 2d044f78 2d03de70 00000000 2d044f78
arm_stackdump: 2d044f00: ffffffff 00000002 00000000 0d0333b4 00000000 0d01a969 00000000 ffffffe9
arm_stackdump: 2d044f20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d044f40: 00000000 2d03de70 2d03e2dc 00000002 00000000 00000000 00000000 0d0333b4
arm_stackdump: 2d044f60: 00000000 0d01b43f 00000000 0d0003cb 2d03e2e8 00000000 2d03e2dc 2d03e2df
arm_stackdump: 2d044f80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d044fa0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d044fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d044fe0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d045000: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d045020: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
arm_stackdump: 2d045040: 00000000 00000000 00000000 00000000 2d03e2dc 2d03de70 2d042e68 2d03e2dc
arm_stackdump: 2d045060: 0d0333a6 00000001 00000000 00000000 00000000 0d01deef 2d03de70 00000001
arm_stackdump: 2d045080: 2d03de70 2d0430f8 00000000 00000000 00000000 0d01e847 2d0430f8 00000001
arm_stackdump: 2d0450a0: 00000001 0d01a06f 00000000 00000000 0d00cdad 00000064 00000000 0d00cdad
arm_stackdump: 2d0450c0: 00000000 0d0062db 2d0430f8 00000001 2d0430f8 0d0048bf 00000000 00000000
arm_showtasks: PID PRI STACK USED FILLED COMMAND
arm_showtasks: ---- ---- 2048 592 28.9% irq
arm_dump_task: 0 0 1000 380 38.0% Idle Task
arm_dump_task: 1 224 1992 588 29.5% hpwork 0x2d037758
arm_dump_task: 2 100 1992 276 13.8% lpwork 0x2d037768
arm_dump_task: 3 100 1992 276 13.8% lpwork 0x2d037768
arm_dump_task: 4 100 1992 276 13.8% lpwork 0x2d037768
arm_dump_task: 6 200 976 464 47.5% cxd56_pm_task
arm_dump_task: 7 100 8144 716 8.7% spresense_main
backtrace| 0: 0x0d00797e 0x0d00399e 0x0d003996 0x0d0002a0
backtrace| 1: 0x0d007efa 0x0d00400e 0x0d00400a 0x0d00402a 0x0d004a7a 0x0d0048a6
backtrace| 2: 0x0d007efa 0x0d00400e 0x0d00400a 0x0d00402a 0x0d004a7a 0x0d0048a6
backtrace| 3: 0x0d007efa 0x0d00400e 0x0d00400a 0x0d00402a 0x0d004a7a 0x0d0048a6
backtrace| 4: 0x0d007efa 0x0d00400e 0x0d00400a 0x0d00402a 0x0d004a7a 0x0d0048a6
backtrace| 6: 0x0d007efa 0x0d003d7c 0x0d003d78 0x0d003cea 0x0d001926 0x0d0062d8 0x0d0048ba
backtrace| 7: 0x0d029de6 0x0d03459b 0x0d003d75 0x0d01db40 0x0d01a964 0x0d01b43a 0x0d01deea 0x0d01e842
backtrace| 7: 0x0d01a06a 0x0d0062d8 0x0d0048ba
backtrace
行に PID 番号ごとのコールスタックアドレスが表示されます。
backtrace| PID番号: コールスタックアドレス
arm-none-eabi-addr2line
コマンドを用いて、このログを取得したときのビルドイメージ nuttx
の ELF ファイルと、backtrace
行に表示されたアドレスを入力することによって、コールツリーのソースコードの場所(ファイル名と行番号)を取得することができます。
$ arm-none-eabi-addr2line -e nuttx 0x0d029de6 0x0d01db40 0x0d01a964 0x0d01b43a 0x0d01deea 0x0d01e842 0x0d01a06a 0x0d0062d8 0x0d0048ba
/home/username/spresense/nuttx/arch/arm/src/common/arm_backtrace_thumb.c:485
/home/username/spresense/sdk/apps/nshlib/nsh_dbgcmds.c:255
/home/username/spresense/sdk/apps/nshlib/nsh_parse.c:741
/home/username/spresense/sdk/apps/nshlib/nsh_parse.c:2592
/home/username/spresense/sdk/apps/nshlib/nsh_session.c:217
/home/username/spresense/sdk/apps/nshlib/nsh_consolemain.c:106
/home/username/spresense/sdk/apps/system/nsh/nsh_main.c:153
/home/username/spresense/nuttx/libs/libc/sched/task_startup.c:70
/home/username/spresense/nuttx/sched/task/task_start.c:134
31.2. dump_stack() 関数の使い方
ソースコード中に、execinfo.h
を include して、dump_stack()
関数を追加することで、
#include <execinfo.h>
dump_stack();
ログ上に backtrace
行を表示することができます。
backtrace|21: 0x0d01f7ba 0x0d010440 0x0d0003e6 0x0d005794 0x0d0184c0 0x0d0184d0 0x0d003bba 0x0d006abe
backtrace|21: 0x0d01227c 0x0d005d90 0x0d004372
前述した方法で、arm-none-eabi-addr2line
コマンドを用いて、dump_stack()
を挿入した箇所への呼び出しパスを表示することができます。
$ arm-none-eabi-addr2line -e nuttx 0x0d01f7ba 0x0d010440 0x0d0003e6 0x0d005794 0x0d0184c0 0x0d0184d0 0x0d003bba 0x0d006abe 0x0d01227c 0x0d005d90 0x0d004372
/home/username/spresense/nuttx/arch/arm/src/common/arm_backtrace_thumb.c:485
/home/username/spresense/nuttx/libs/libc/sched/sched_dumpstack.c:69
/home/username/spresense/nuttx/arch/arm/src/chip/cxd56_serial.c:1007
/home/username/spresense/nuttx/drivers/serial/serial.c:1266
/home/username/spresense/nuttx/fs/vfs/fs_write.c:138
/home/username/spresense/nuttx/fs/vfs/fs_write.c:202
/home/username/spresense/nuttx/sched/semaphore/sem_post.c:224
/home/username/spresense/nuttx/include/nuttx/mutex.h:259
/home/username/spresense/sdk/apps/examples/hello/hello_main.c:40
/home/username/spresense/nuttx/libs/libc/sched/task_startup.c:70
/home/username/spresense/nuttx/sched/task/task_start.c:134
また、Linux Programmer’s Manual と同じ方法で、backtrace()
関数を使用することもできます。
backtrace_symbols() backtrace_symbols_fd() 関数も呼び出しは可能ですが、シンボル情報を表示することはできません。
|
32. GNSS RAMメモリ使用機能について
Spresense内蔵GNSS測位機能を使用しないユースケースにおいて、ユーザーアプリケーションから GNSS RAM (640KB) を汎用メモリとして利用することができます。
この機能を使うためには、ブートローダーのインストール より SDKv3.2.0以降のブートローダーへ更新してください。
32.1. 制約事項
GNSS RAM を使用するにあたって以下の制約事項があります。
-
内蔵GNSS機能と同時に利用することはできません
-
内蔵GNSSファームウェアが動作している場合、アプリケーションからGNSS RAMへアクセスするとHardfaultエラーが発生します。
-
内蔵GNSS機能との排他なので、GNSS Add-onボードを利用している場合はこの制約の対象外です。
-
-
メモリアクセス速度が遅い
-
アプリケーションが通常利用している RAM に比べて 1/8 以下にパフォーマンスが落ちます。
-
メモリアクセスが低速でも構わない用途で使用してください。
-
-
ハードウェアDMAが直接アクセスするバッファとしては利用できません
-
Camera (CISIF) 用のバッファとしては使用できない
-
Audio 用のバッファとしては使用できない
-
32.2. GNSS RAMへコードやデータを配置する方法
ソースコードに GNSSRAM_CODE
、 GNSSRAM_DATA
、 GNSSRAM_BSS
を付与することで、任意のコードやデータを GNSS RAM に配置することができます。
ユーザーは、これらのキーワードを含むプログラムをビルドして nuttx.spk
を生成します。
実際のGNSS RAMへの配置は、起動時にブートローダーによって行われます。
サンプルコードを以下に示します。
#include <arch/chip/gnssram.h> (1)
static const int g_alloc_sizes[NTEST_ALLOCS] GNSSRAM_DATA = (2)
{
1024, 12, 962, 5692, 10254, 111, 9932, 601,
222, 2746, 3, 124321, 68, 776, 6750, 852,
4732, 28, 901, 480, 5011, 1536, 2011, 81647,
646, 1646, 69179, 194, 2590, 7, 969, 70
};
static void *g_allocs[NTEST_ALLOCS] GNSSRAM_BSS; (3)
static GNSSRAM_CODE void function(void) (4)
{
}
1 | gnssram.h を include してください。 |
2 | 初期値付きデータ(data) に GNSSRAM_DATA を付与することで、GNSS RAM 上の data セクションに配置することができます。 |
3 | 初期値無しデータ(bss) に GNSSRAM_BSS を付与することで、GNSS RAM 上の bss セクションに配置することができます。 |
4 | 関数に GNSSRAM_CODE を付与することで、 GNSS RAM上のtext セクションに配置することができます。 |
関数や変数の単位ではなくライブラリ(アーカイブ)やオブジェクト単位でGNSS RAMへ配置したいときは、リンクスクリプトファイルを直接編集してください。
リンクスクリプトファイルの変更例を以下に示します。
/* GNSS memory */
.gnssram.text : {
_sgnsstext = ABSOLUTE(.);
/* Possible to locate text of any object file.
* *libxxx.a:*.o(.text .text.*)
* *libxxx.a:*.o(.rodata .rodata.*)
*/
*libapps.a:*.o(.text .text.*) (1)
*libapps.a:*.o(.rodata .rodata.*)
} > gnssram
.gnssram.data . : ALIGN(4) {
/* Possible to locate data of any object file.
* *libxxx.a:*.o(.data .data.*)
*/
*libapps.a:*.o(.data .data.*) (2)
} > gnssram
.gnssram.bss . (NOLOAD) : {
. = ALIGN(4);
_gnssramsbss = ABSOLUTE(.);
/* Possible to locate bss of any object file.
* *libxxx.a:*.o(.bss .bss.*)
* *libxxx.a:*.o(COMMON)
*/
*libapps.a:*.o(.bss .bss.*) (3)
*libapps.a:*.o(COMMON)
} > gnssram
1 | libapps.a 全オブジェクトのtextやrodataを GNSS RAM上の text セクションに配置することができます。 |
2 | libapps.a 全オブジェクトのdata を GNSS RAM 上の data セクションに配置することができます。 |
3 | libapps.a 全オブジェクトのbssを GNSS RAM 上の bss セクションに配置することができます。 |
ここの記述を変更することで、特定のオブジェクトファイルのみGNSS RAMに貼り付けることも可能です。 詳しくは、GNU ld のドキュメントを参照してください。
32.3. GNSS RAMをヒープ領域として利用する方法
up_gnssram_initialize()
関数を呼び出すことで、GNSS RAMメモリをヒープ領域として使用することができます。
前述した方法でコードやデータをGNSS RAMに配置している場合は、それらを除いた空きメモリをヒープ領域に割り当てます。
#include <arch/chip/gnssram.h> (1)
up_gnssram_initialize(); (2)
1 | gnssram.h を include してください。 |
2 | GNSS RAMヒープ領域として使用するための初期化関数を呼び出します。 |
このヒープ領域を使用するための専用のメモリアロケート関数群が提供されています。 malloc/free の代わりに、以下の関数を呼び出すことで GNSS RAM上のヒープ領域を利用することができます。
#include <arch/chip/gnssram.h>
void *up_gnssram_malloc(size_t size);
void *up_gnssram_calloc(size_t n, size_t elem_size);
void *up_gnssram_realloc(void *ptr, size_t size);
void *up_gnssram_zalloc(size_t size);
void up_gnssram_free(void *mem);
void *up_gnssram_memalign(size_t alignment, size_t size);
struct mallinfo up_gnssram_mallinfo(void);