1. Spresense Arduino スケッチ開発
Spresense Arduino Library をインストールすると、Arduino開発環境を使用して Spresense 上でスケッチの開発を始めることができます。 Spresense Arduino Library のインストール方法については、Spresense Arduino スタートガイド を参照してください。
- Spresense Arduino Core ライブラリ
-
Spresense は、Arduino互換のAPIをサポートしています。 Arduino プログラミング言語仕様については、Arduino Language Reference を参照してください。 Spresense での使用にあたりAPIの制限事項やArduinoとの違いについては Spresense Arduino Core ライブラリ に記載されています。 また、ハードウェアの違いについては Spresense と Arduino Uno の違い を参照してください。
- Spresense Arduino 拡張ライブラリ
-
Spresense の特徴である Audio, GPS, Camera, Deep Neural Network, MutiCore, Low Power といった機能を簡単に使うための独自ライブラリも一緒に提供されています。 これらのサンプルスケッチについては、Arduino IDE のメニューの
File → Examples → Spresense
から利用することができます。 各ライブラリの詳細については、Spresense Arduino ライブラリ を参照してください。
1.1. Spresense Arduino Core ライブラリ
1.1.1. LED
Spresense メインボードには4つのビルトインLEDが搭載されています。これらはアプリケーションから自由に使うことができます。LEDのピン番号は LED0
、LED1
、LED2
、LED3
として定義されています。LED_BUILTIN
の定義は、LED0
に割り当てられています。これらは通常のデジタル端子と同様に pinMode(LED番号, OUTPUT) と digitalWrite(LED番号, HIGH/LOW) で操作できます。また、 ledOn(LED番号)
もしくは ledOff(LED番号)
という専用APIを使うこともできます。
1.1.2. Serial
Spresense には二つのシリアルポート(UART)が備わっており、Serial 機能をサポートしています。メインボード上の USB ポートはデバッグシリアル専用で Serial
と定義して使用できます。一方、DO0、DO1 端子のシリアルは、 Serial2
のインスタンス名で使用することができます。
Serial.begin(115200, SERIAL_8E1) のように2つ目のパラメータでデータ長、パリティの有無、ストップビットを設定することができます。引数を省略した場合のデフォルトは、データ長8bit、パリティ無し、1ストップビットの SERIAL_8N1
になります。
パラメータ | データ長 | パリティ | ストップビット |
---|---|---|---|
SERIAL_5N1 |
5 |
無し |
1 |
SERIAL_6N1 |
6 |
無し |
1 |
SERIAL_7N1 |
7 |
無し |
1 |
SERIAL_8N1 |
8 |
無し |
1 |
SERIAL_5N2 |
5 |
無し |
2 |
SERIAL_6N2 |
6 |
無し |
2 |
SERIAL_7N2 |
7 |
無し |
2 |
SERIAL_8N2 |
8 |
無し |
2 |
SERIAL_5E1 |
5 |
偶数 |
1 |
SERIAL_6E1 |
6 |
偶数 |
1 |
SERIAL_7E1 |
7 |
偶数 |
1 |
SERIAL_8E1 |
8 |
偶数 |
1 |
SERIAL_5E2 |
5 |
偶数 |
2 |
SERIAL_6E2 |
6 |
偶数 |
2 |
SERIAL_7E2 |
7 |
偶数 |
2 |
SERIAL_8E2 |
8 |
偶数 |
2 |
SERIAL_5O1 |
5 |
奇数 |
1 |
SERIAL_6O1 |
6 |
奇数 |
1 |
SERIAL_7O1 |
7 |
奇数 |
1 |
SERIAL_8O1 |
8 |
奇数 |
1 |
SERIAL_5O2 |
5 |
奇数 |
2 |
SERIAL_6O2 |
6 |
奇数 |
2 |
SERIAL_7O2 |
7 |
奇数 |
2 |
SERIAL_8O2 |
8 |
奇数 |
2 |
また、Serial2
はハードウェアフロー制御をサポートしています。Serial2.begin(115200, SERIAL_8N1 | SERIAL_RTSCTS) のように SERIAL_RTSCTS
を追加することでハードウェアフロー制御が有効になります。引数を省略した場合のデフォルトは、ハードウェアフロー制御は無効になっています。
ハードウェアフロー制御を無効にした場合でも、UART2_RTS , UART2_CTS ピンを GPIO など別の用途で使用することはできません。
|
パラメータ | 説明 |
---|---|
SERIAL_CTS |
ハードウェア CTS を有効にします。 |
SERIAL_RTS |
ハードウェア RTS を有効にします。 |
SERIAL_RTSCTS |
ハードウェア RTS / CTS 両方を有効にします。 |
1.1.3. pinMode()
pinMode(pin, mode) の mode
について、 INPUT
, OUTPUT
, INPUT_PULLUP
の他に INPUT_PULLDOWN
をサポートしています。I/O電圧に関して、メインボード側のデジタル端子は1.8Vですが、拡張ボードのデジタル端子は 3.3V もしくは 5V 出力(ジャンパJP1で選択)になるように設計されています。この電圧レベル変換は、レベルシフタとプルアップ抵抗で行っているため、拡張ボードのデジタル端子にはいくつかの制約があります。
-
起動時は、拡張ボードの全てのデジタル端子がプルアップされ
HIGH
になります。pinMode()で、INPUT_PULLDOWN
を指定してもプルアップされるレベルの方が高いため、入力はHIGH
になります。 -
ピンがインプットに設定されている場合、初期値は
HIGH
に設定されます。これはプルダウン抵抗を必要とする回路に影響を与えますので注意してください。 -
ピンの出力は、
digitalWrite()
で設定されてはじめて、HIGH
もしくは、LOW
にセットされます。
レベルシフタやプルアップ抵抗の詳細については、Spresense拡張ボード回路図 を参照してください。
pinMode() は、指定されたピンを GPIO モードに設定しますが、このモード設定はピングループ単位で制御されることに注意してください。 例えば、SPIの場合、CS, SCK, MOSI, MISO の 4 つのピンが同じグループに属しており、CS ピンに対して pinMode() を呼び出した場合、SPI 機能としては動作できなくなります。 ピングループの詳細については、コネクタ ピンリスト (xlsx) を参照してください。 |
1.1.4. analogRead()
Spresense は A0 から A5 まで 6 つのアナログ入力専用ピンをもっています。これらのピンをデジタルピンとして使用することはできません。 analogRead() に指定するピンには、0 ~ 5 のピン番号の数字か、もしくは A0
、A1
、A2
、A3
、A4
、A5
という定義を使用してください。
1.1.5. analogReadMap() [独自拡張]
analogRead() 関数は、ADC から取得される 符号付き16bitの値(signed short)を map(value, fromLow, fromHigh, toLow, toHigh) 関数を用いて 0 ~ 1023 にマップした値を返します。
analogReadMap() 関数によって、map() 関数の引数 fromLow
, fromHigh
で使用する値を変更することができます。
また、analogReadMap() 関数の min
と max
に同じ値を設定した場合、analogRead() 関数は map() による変換を行わずに、ADC の生値を返します。
void analogReadMap(uint8_t pin, int16_t min, int16_t max);
pin
: 0 ~ 5 または A0 ~ A5 のピン番号
min
: map() するときの fromLow 値
max
: map() するときの fromHigh 値
1.1.6. analogReference()
Spresense 拡張ボードのアナログ入力基準電圧は5V固定、メインボードのアナログ入力基準電圧は0.7V固定です。 analogReference() 関数はサポートされていません。
1.1.7. analogWrite()
analogWrite(pin, value) にて、約 490 Hz 周期の PWM 信号を出力します。指定する pin
番号が、3, 5, 6, 9 の場合は、ハードウェア機能により PWM 信号を出力します。それ以外の pin
番号を指定した場合は、タイマーを使用して信号を交互に High / Low 出力することでソフトウェア制御により PWM 信号を生成します。
-
pin 3, 5, 6, 9 : ハードウェア制御 PWM
-
上記以外の pin : ソフトウェア制御 PWM
ハードウェア制御 PWM を使用する場合、3 番 pin と 9 番 pin は連動して PWM モードに切り替わります。analogWrite() 関数で指定した pin には PWM 信号が出力されますが、同時にもう一方の pin も PWM モードに切り替わるため Low 信号が出力されます。両方の pin に対して順番に analogWrite() を呼び出して、二つの pin を PWM として使用することは可能ですが、どちらか一方だけを GPIO として使用するような使い方はできません。また、5 番 pin と 6 番 pin の組み合わせに対しても同様の制約があります。 |
1.1.8. tone()
tone(pin, frequency [, duration]) は、タイマーを使用してソフトウェア制御により tone 信号を生成します。このときタイマーの分解能が 1 マイクロ秒なので、frequency
の半周期が 1 マイクロ秒で割り切れない場合に周波数誤差が発生します。
設定可能な最大 frequency
は約 166 kHz です。
tone()
関数は、attachTimerInterrupt()
と同じタイマーリソースを使用するため、attachTimerInterrupt()
と同時に使用することはできません。
1.1.9. F()
F()
マクロはサポートされていません。F()
マクロを使用してもコンパイルは可能ですが、通常の文字列データと同様に RAM 上に配置されます。(Fマクロの例: Serial.println(F("This string will be stored in flash memory"));
)
1.1.10. PROGMEM
PROGMEM 機能はサポートされていません。 PROGMEM は空マクロとして定義されているため、使用箇所があってもコンパイルエラーにはなりません。
1.1.11. attachInterrupt()
ピンに対する割り込み番号は、attachInterrupt() 関数内で動的に割り当てられます。
digitalPinToInterrupt()
は空マクロとして定義されており、 次のどちらの使い方も可能です。
attachInterrupt(digitalPinToInterrupt(pin), void (*isr)(void), mode);
attachInterrupt(pin, void (*isr)(void), mode);
attachInterrupt(digitalPinToInterrupt(pin), void (*isr)(void), mode, filter);
attachInterrupt(pin, void (*isr)(void), mode, filter);
pin
: D05 などのピン番号
isr
: 割り込みが発生したときに呼ばれる関数。この関数は引数も戻り値もありません。
この関数は割り込みハンドラから呼ばれるため、呼び出し可能な API には制限があります。 例えば、この関数内から Analog I/O 関数を使用することはできません。 |
mode
: 割り込みを発生させるトリガ
-
LOW: ピンの状態がLOWのとき
-
CHANGE: ピンの状態が変化したとき
-
RISING: ピンの状態がLOWからHIGHに変わったとき
-
FALLING: ピンの状態がHIGHからLOWに変わったとき
-
HIGH: ピンの状態がHIGHのとき
filter
: チャタリング防止用フィルタの有効・無効フラグ
-
true: チャタリング防止用フィルタが有効
-
false: チャタリング防止用フィルタが無効
Spresense は、チャタリング防止用にRTC(32.768kHz) 3サイクル分のノイズフィルタをもっています。 このフィルタの有効・無効の設定ができます。設定を行わなかった場合は有効になります。 無効にすることで、割り込みの応答速度が上がりますが、スイッチングノイズによる誤動作の可能性があります。
割り込み登録可能な上限数が決まっており、SYS GPIO グループから最大6本まで、APP GPIO グループから最大6本まで、合わせて最大12本まで登録することができます。
上限数を超えて
|
1.1.12. attachTimerInterrupt()
タイマー割り込み機能をサポートしています。 この機能は、tone() と同じタイマーリソースを使用するため、tone() と同時に使用することはできません。 attachTimerInterrupt() 機能はシステム上で一つだけ動作します。既に使用中の状態で、 再び attachTimerInterrupt() を呼び出すとエラーになります。異なるハンドラや周期で再設定する際は、detachTimerInterrupt() を呼び出してリソースを解放した後に、再度、attachTimerInterrupt() を呼び出してください。
void attachTimerInterrupt(unsigned int (*isr)(void), unsigned int us);
isr
: タイマー割り込みが発生したときに呼ばれる関数。この関数は次のタイマー周期を戻り値として返します。
-
この関数が 0 を return したときは、タイマーが停止し、ワンショットタイマーとして使用できます。
-
周期タイマーとして使用したいときは、
attachTimerInterrupt()
で指定したus
時間と等しい値を return で返してください。 -
その他、return で任意の値を返すことで、次のタイマー割り込みまでの時間を動的に変更することができます。
この関数は割り込みハンドラから呼ばれるため、呼び出し可能な API には制限があります。 例えば、この関数内から Analog I/O 関数を使用することはできません。 |
us
: マイクロ秒
1.1.13. micros()
micros() は 電源ONされてからの経過時間をマイクロ秒単位で返します。 RTC (32.768kHz) サイクルでカウントしているため、分解能は約 30 マイクロ秒です。
uint64_t micros(void);
戻り値は、符号なしの64bit整数です。
1.1.14. millis()
millis() は 電源ONされてからの経過時間をミリ秒単位で返します。
uint64_t millis(void);
戻り値は、符号なしの64bit整数です。
1.1.15. Fast digital I/O
通常のdigitalRead, digitalWrite 関数とは別に、デジタルピンのI/O制御をより高速に行うための関数について説明します。
Function | 説明 |
---|---|
digitalPinToPort(pin) |
|
portInputRegister(port) |
|
portOutputRegister(port) |
|
portModeRegister(port) |
|
digitalPinToBitMask(pin) |
|
/* Set pin to input mode */
pinMode(PIN_D22, INPUT);
volatile uint8_t *port = portInputRegister(digitalPinToPort(PIN_D22));
volatile uint8_t *mode = portModeRegister(digitalPinToPort(PIN_D22));
*mode = 1; /* Input setting */
uint8_t val = *port; /* Read */
if (val & 1)
Serial.println("High");
else
Serial.println("Low");
/* Set pin to output mode */
pinMode(PIN_LED0, OUTPUT);
volatile uint8_t *port = portOutputRegister(digitalPinToPort(PIN_LED0));
volatile uint8_t *mode = portModeRegister(digitalPinToPort(PIN_LED0));
*mode = 0; /* Output setting */
*port = 1; /* High */
*port = 0; /* Low */
1.2. Spresense Arduino 拡張ライブラリ
ライブラリの詳細仕様については、Spresense Arduino ライブラリ に記述しています。
1.3. メモリの使用状況レポートに関して
Spresense の特徴として、コンパイルされたスケッチは全てフラッシュメモリ内にインストールされ、 それが実行されるときに、コードや読み出し専用のデータを含めてすべて、フラッシュメモリからRAM 上に展開されて RAM 上で実行されます。
展開先の RAM サイズ容量は、 デフォルトの構成でアプリケーション SRAM 1.5 MB のうちの半分 768 キロバイト(= 786432 バイト) が割り当てられています。 このスケッチのプログラムサイズがこの RAM サイズ容量を超えてしまった場合は、コンパイルに失敗しエラーが発生します。
Arduino IDE上で、スケッチをコンパイルした後に以下のようなメモリ使用状況のレポートが出力されます。 このレポートにより、スケッチが消費するメモリサイズを確認することができます。
最大786432バイトのフラッシュメモリのうち、スケッチがxxxxxxバイト(xx%)を使っています。 最大786432バイトのRAMのうち、グローバル変数がxxxxxxバイト(xx%)を使っていて、ローカル変数でxxxxxxバイト使うことができます。
このレポートでは、本来とは異なる意味で用語が使用されているので次のように読み替えてください。
-
フラッシュメモリ
: 展開先の RAM サイズ容量を表します -
グローバル変数
:スケッチが静的に使用する RAM サイズを表します -
ローカル変数
:RAM サイズ容量からスケッチが静的に使用する RAM サイズを差し引いた、残りのRAMサイズを表します
スケッチプログラムが消費するメモリとして、静的に確保されるサイズの他に、動的に確保されるヒープ領域があります。
ローカル変数
で表される残りの RAM サイズは全てこのヒープ領域に割り当てられます。
そのためスケッチ作成時にはヒープ領域の使用分も考慮し、残りの RAM サイズを空けておく必要があります。
目安として、スケッチプログラムの使用サイズが全体の 75% を超えると
スケッチが使用できるメモリが少なくなっています。動作が不安定になる可能性があります。
という警告が出力されますので、そのときはスケッチプログラムのコードサイズを削減するなど、プログラムを見直してください。
1.4. Arduino メモリサイズ変更
Arduino 環境におけるアプリケーション SRAM 1.5 MByte の標準的なメモリ構成を以下に示します。
アプリケーション SRAM は 128 KByte 単位のタイルと呼ばれるメモリブロックに分かれています。
デフォルトのメモリ構成では MainCore に先頭の 6 タイル (768 KByte) が割り当てられ、 残りの 6 タイル (768 KByte) を SubCore や Audio DSP やその他のライブラリ等で共有して使用します。
Arduino IDE メニューから MainCore に割り当てるメモリサイズを変更することができます。
SubCore が使用するメモリサイズは SubCore スケッチをビルドしたときに自動的に決定されます。 |
SubCore, Audio DSP を使用しないユースケースにおいて、最大 1.5 MByte (1536 KB) のメモリをフルにユーザースケッチに割り当てることができます。 一方、SubCore, Audio DSP 領域のサイズを増やしたいときは、MainCore への割り当てサイズをデフォルトの 768 KB から減らすことで実現可能となります。 アプリケーションのユースケースに応じてメモリサイズを調整してください。
2. Spresense Arduino ライブラリ
Spresense Arduino 環境が提供するライブラリについて記載しています。
2.1. Audio ライブラリ
Spresense Audio ライブラリは、ハイレゾ音源含むオーディオデータの再生・録音を SD カードを使って行うことができます。シンプルなスケッチでハイレゾリューションオーディオの世界を体験することができます。
Spresense は、ADC と DAC (フルデジタルアンプ機能含む) を搭載しており、Audio ライブラリからこれらの機能を制御します。Spresense は 6つの CPU コアが搭載されており、オーディオの信号処理をアプリケーションプロセッサとは別のコア(以降、それらのコアをDSP と呼びます)で動作させることにより、非常に効率的かつ簡単な記述でオーディオのアプリケーションを構築することができます。
|
Audio ライブラリの主な特徴
-
Audio recorder 及び Capture
-
Audio player 及び Renderer
-
Sound Effector (例えば、音声通話用のバンドパスフィルタなど)
-
Sound Sensing (例えば、ノイズ計測、異常音検知など)
-
Volume control
-
Balance (L/R Gain)
-
Beep generation
-
Beep音は、Arduino の tone() 関数と異なり、ヘッドホンに出力されますので注意してください。
-
この Audio ライブラリは input channel、output channel を選択できます。
- Audio Input Channels
-
-
Analog microphone
-
Digital microphone
-
- Audio Output Channel
-
-
Analog headphone
-
I2S
-
DSP codec は以下のフォーマットを扱うことができます。
-
MP3
MP3 ファイルは、ID3v2 TAG(特に画像データのような大きなメタデータ)がある場合、 デコーダがparseエラーになります。 MP3Tag などのツールで、タグ情報を削除してください。 |
-
WAV (PCM)
録音・再生時に、サンプリングレート、ビットレートを指定してください。例えば、MP3 decoder は、サンプリングレート 32000, 44100, 48000 Hz をサポートしています。
詳細については、Audio Subsystem を参照してください。
2.1.1. Audio 動作環境
Audio ライブラリを動作させるために事前に準備が必要なものを以下に示します。
-
Spresense 拡張ボード
-
録音用マイク
-
再生用ヘッドホン
-
マイクロ SD カード
Spresense 拡張ボードは、マイク入力専用ピンと SD カードスロット、ヘッドホンジャックを備えています。ヘッドホンジャックは、3極 3.5mm ステレオジャックです。
ピン配置やオーディオ関連のコネクタに関する詳細については、以下のハードウェアガイドを参照してください。
-
スピーカーの使用方法, マイクの使用方法 (拡張ボード)
-
スピーカーの使用方法, マイクの使用方法 (LTE拡張ボード)
2.1.2. レイヤ構造について
オーディオ・サブシステムのスタックダイアグラムを以下に示します。
オーディオ・サブシステムは、大きく3つのレイヤを持ちます。
- High Level Interface
-
最上位のレイヤで、最上位の抽象度での制御を行うレイヤです。システム全体の整合を取りながら制御します。
Arduino ライブラリでは、AudioClass一つだけを使います。
使える機能は、-
音楽再生(発音)
-
音声記録(キャプチャ)
-
マイク音声出力(信号処理なし)
-
Beep発音
等になります。
-
- Object Level Interface
-
音声記録や音声再生などのある程度の抽象度の機能ブロック単位(Object)をAPIのレイヤーとし、それらをさまざまに組み合わせることで、より自由度の高いアプリケーションが開発可能なインターフェースを提供します。 各Object内での詳細な信号処理・DSP処理などに関してはObject内で整合を取ります。
これにより、High Level Interfaceで定義されていないような機能を実現することが可能です。
各オブジェクトには、
-
音声キャプチャ機能(MicFrontEnd Object)
-
録音機能(Recorder Object)
-
再生機能(Player Object)
-
信号処理ありマイク音声出力(MicFrontEnd & OutputMixer Object)
-
発音機能(OutputMixer Object)
-
認識機能(Recognizer Object)
-
シンセサイザ機能(Synthesizer Object)
があります。
-
- Low Level Interface(未対応)
-
音声デコードやエンコード、イコライジング等のプリミティブな信号処理処理ブロック(Component)単位をAPIのレイヤーとし、組み合わせることで非常に高度な自由度のアプリケーションが開発可能なインターフェースを提供します。ただし、それぞれの信号処理の整合はアプリケーション側が取る必要があります。
現在、Low Level Interfaceは、未対応です。
2.1.3. DSP Codec バイナリのインストール
Audioの各種機能を使う場合、SubCoreにproprietaryな信号処理を実装したDSPと呼ばれるバイナリをインストールする必要があります。 バイナリファイルをインストールする手順は以下になります。
2.1.4. High Level Interfaceについて
最上位の抽象度でのレイヤになります。 簡便に使用できますが、機能(動作モード)は、限定されます。
使用するクラスオブジェクトはAudioClass一つだけで、以下のように定義してインスタンスを生成すれば、 使用できます。
#include <Audio.h>
AudioClass *theAudio;
theAudio = AudioClass::getInstance();
このHigh Level Interfaceは、以下のような状態遷移を持ちます。
各モードの説明は以下になります。
-
Ready状態
オーディオ・サブシステムのオブジェクトを生成し、起動した直後の状態です。
オーディオを使用しない場合には、この状態に遷移しておくことで、オーディオブロックでの消費電力をほぼ0にします。
setReadyMode によって、Ready状態にのみ遷移します。
状態の遷移は、以下になります。
setPlayerMode によって、Player状態に遷移できます。
setRecorderMode によって、Recorder状態に遷移できます。
setThroughMode によって、Through状態に遷移できます。
-
Player状態
SDカードやネットワークからの圧縮音声ファイルをデコードし、AnalogOutやI2Sに発音する機能を実現する状態です。
状態の中にPlayerReady状態とPlayerActive状態の2つのサブ状態を持ちます。
PlayerReady状態は、音楽再生停止の状態です。 startPlayer によってPlayerActiveに遷移し音楽再生動作を行います。
PlayerActive状態は、音楽再生中の状態です。
stopPlayer によってPlayerReadyに遷移し音楽再生を停止します。
Playerのインスタンスは2個持つことができます。
それそれが、独立してPlayerのサブ状態を持ちます。
setReadyMode によって、Ready状態にのみ遷移します。
-
Recorder状態
Micから入力された音声データを圧縮して、SDカードなどのストレージに書き出したり、WiFi/LTE などのネットワークに打ち上げて記録する機能を実現する状態です。
状態の中にRecorderReady状態とRecorderActive状態の2つのサブ状態を持ちます。
RecorderReady状態は、音声記録停止の状態です。 startRecorder によってRecorderActiveに遷移し音声記録動作を行います。
RecorderActive状態は、音声記録中の状態です。
stopRecorder によってRecorderReadyに遷移し音声記録を停止します。
setReadyMode によって、Ready状態にのみ遷移します。
-
Through状態
Micから入力された音声データを、エフェクト処理などを行わず、AnalogOut、または、I2Sに非常に省電力・低遅延で出力する機能を実現する状態です。 この状態は、サブ状態を持ちません。
setReadyMode によって、Ready状態にのみ遷移します。
2.1.5. Object Level Interfaceについて
High Level Interfaceの場合、動作モードがある程度決められています。このモードだけでは所望の機能が実現できない場合、Object Level Interfaceを使用し、Objectを組み合わせてシステムを構成することで、所望の機能が実現できる可能性があります。
このObject Level Interfaceを使用する場合、各オブジェクト単位で、クラスオブジェクトのincludeとインスタンスを生成をする必要があります。
各オブジェクトの概要は以下になります。
-
音声キャプチャ機能(MicFrontEnd Object)
マイクからの音声入力をキャプチャします。
キャプチャした音声は、他の Object
へ渡すことが可能です。
#include <Frontend.h>
FrontEnd *theFrontEnd;
theFrontEnd = FrontEnd::getInstance();
キャプチャした音声データは、RecorderObjectへ送りエンコードを行ったり、またRecognizerObjectへ送り音声認識に利用したりします。
加えて、OutputMixerObjcetへ送りそのまま発音することで、入力から遅延の少ない発音をすることが可能です。
-
録音機能(Recorder Object)
音声PCMデータをエンコードし、その結果データを SimpleFIFO
などのインタフェースを経由して得ることが出来ます。
#include <MediaRecorder.h>
MediaRecorder *theRecorder;
theRecorder = MediaRecorder::getInstance();
-
再生機能(Player Object)
SimpleFIFO
経由で供給した音声データをデコードし、その結果をcallback関数で得ることが出来ます。
#include <MediaPlayer.h>
MediaPlayer *thePlayer;
thePlayer = MediaPlayer::getInstance();
デコードした結果のPCMデータを OutputMixerObjcet
へ送ることで、発音することが出来ます。
-
発音機能(OutputMixer Object)
受け取った音声データを発音します。
#include <OutputMixer.h>
OutputMixer *theMixer;
theMixer = OutputMixer::getInstance();
-
認識機能(Recognizer Object)(未対応)
受け取った音声データの音声認識を行います。
-
シンセサイザ機能(Synthesizer Object)(未対応)
指定したパラメータに基づき音声データを作成します。
作成した音声データはOutputMixerObjectへ送ることで発音が可能です。
2.1.5.1. 各オブジェクトの組み合わせと機能例
各Object Level Interface用サンプルとその チュートリアル を参照ください。
2.1.6. 各種動作に関する注意点
ここでは各動作に関する注意点を示します。
2.1.6.1. 音声周波数関する制約
Spresense のAudio機能は、HW制約上、HWからの入出力音声データは、48kHzサンプリングか、192kHzサンプリングになります。そのため、内部での処理は、特にSWでのリサンプリングなどを行わない限り、48kHzサンプリングか、192kHzサンプリングで処理を行うことになります。
2.1.6.2. 音声キャプチャサイズとPCMデータ読み出しに関する制約
Spresense の FrontEnd Object
による音声キャプチャ動作は、HW制約上、フレームサイズが最大で1024サンプルになります。また、リアルタイム処理の観点から最小サンプル数は240サンプルになっています。そのため、 init
関数で指定できるフレームサイズは 240 ~ 1024 になります。
また、上記制約から、High Level Interface での Audio
クラスと Object Level Interface での MediaRecorder Object
では、音声キャプチャ動作やWAV記録動作のフレームサイズは、768サンプルになっています。
readFrames
では、バッファのサイズに寄らず、読み出し可能なデータが存在する場合、そのサイズ分読み出しを行います。そのため、バッファをすべて埋めるようにデータを読み込みたい場合は、残りの分を書き込むまで readFrames
を繰り返すか、データが揃うだけ十分に待ってください。
SRC(Sampling Rate Converter)によるリサンプリングを行う場合、読み出すフレームサイズは倍数比で変わります。下記を参考にしてください。
Samplingrate | Max samples |
---|---|
16kHz |
341 |
48kHz |
1024 |
192kHz |
1024 |
2.1.7. Audioライブラリで発生するエラーとエラー処理について
Audioライブラリで発生するエラーは、SDK内部から発生するエラーと、Arduinoライブラリから発生するエラーの2つがあります。
2.1.7.1. Arduinoライブラリ内部で発生するエラー
Error Code | Value | Description |
---|---|---|
AUDIOLIB_ECODE_OK |
0 |
正常終了 |
AUDIOLIB_ECODE_SHARED_MEMORY_ERROR |
1 |
Shared Memory 確保エラー |
AUDIOLIB_ECODE_SIMPLEFIFO_ERROR |
2 |
Simple FIFO エラー |
AUDIOLIB_ECODE_AUDIOCOMMAND_ERROR |
3 |
API実行エラー |
AUDIOLIB_ECODE_FILEACCESS_ERROR |
4 |
ファイルアクセスエラー |
AUDIOLIB_ECODE_FILEEND |
5 |
ファイル終端エラー |
AUDIOLIB_ECODE_BUFFER_AREA_ERROR |
6 |
バッファ領域未定義エラー |
AUDIOLIB_ECODE_BUFFER_SIZE_ERROR |
7 |
バッファサイズ指定エラー |
AUDIOLIB_ECODE_INSUFFICIENT_BUFFER_AREA |
8 |
バッファ領域不足エラー |
AUDIOLIB_ECODE_WAV_PARSE_ERROR |
9 |
未使用 |
AUDIOLIB_ECODE_PARAMETER_ERROR |
10 |
パラメータエラー |
Error Code | Value | Description |
---|---|---|
FRONTEND_ECODE_OK |
0 |
正常終了 |
FRONTEND_ECODE_COMMAND_ERROR |
1 |
API実行エラー |
FRONTEND_ECODE_BASEBAND_ERROR |
2 |
AudioDriverエラー |
Error Code | Value | Description |
---|---|---|
MEDIARECORDER_ECODE_OK |
0 |
正常終了 |
MEDIARECORDER_ECODE_COMMAND_ERROR |
1 |
API実行エラー |
MEDIARECORDER_ECODE_BUFFER_INIT_ERROR |
2 |
バッファ初期化エラー |
MEDIARECORDER_ECODE_BUFFER_POLL_ERROR |
3 |
バッファポーリングエラー |
MEDIARECORDER_ECODE_DSP_ACCESS_ERROR |
4 |
DSPバイナリファイルアクセスエラー |
MEDIARECORDER_ECODE_FILEACCESS_ERROR |
5 |
ファイルアクセスエラー |
MEDIARECORDER_ECODE_BUFFER_SIZE_ERROR |
6 |
バッファサイズ指定エラー |
MEDIARECORDER_ECODE_BUFFER_AREA_ERROR |
7 |
バッファ領域未定義エラー |
MEDIARECORDER_ECODE_INSUFFICIENT_BUFFER_AREA |
8 |
バッファ領域不足エラー |
MEDIARECORDER_ECODE_BASEBAND_ERROR |
9 |
未使用 |
MEDIARECORDER_ECODE_BUFFER_ALLOC_ERROR |
10 |
バッファ領域確保エラー |
Error Code | Value | Description |
---|---|---|
MEDIAPLAYER_ECODE_OK |
0 |
正常終了 |
MEDIAPLAYER_ECODE_COMMAND_ERROR |
1 |
API実行エラー |
MEDIAPLAYER_ECODE_SIMPLEFIFO_ERROR |
2 |
Simple FIFO エラー |
MEDIAPLAYER_ECODE_FILEACCESS_ERROR |
3 |
ファイルアクセスエラー |
MEDIAPLAYER_ECODE_FILEEND |
4 |
ファイル終端エラー |
MEDIAPLAYER_ECODE_SHARED_MEMORY_ERROR |
5 |
未使用 |
MEDIAPLAYER_ECODE_WAV_PARSER_ERROR |
6 |
未使用 |
MEDIAPLAYER_ECODE_BUFFERSIZE_ERROR |
7 |
バッファサイズ指定エラー |
MEDIAPLAYER_ECODE_BUFFERALLOC_ERROR |
8 |
バッファ領域確保エラー |
Error Code | Value | Description |
---|---|---|
OUTPUTMIXER_ECODE_OK |
0 |
正常終了 |
OUTPUTMIXER_ECODE_COMMAND_ERROR |
1 |
API実行エラー |
2.1.8. レスポンスエラー
Audioライブラリで実行したAPIが、状態違反やパラメータの誤りなど、仕様と異なった制御を行った場合、レスポンスエラーが発生し、パラメータにエラー内容が格納されます。
リザルトのレスポンスエラーのデータ形式については、 リザルトフォーマット と ErrorResponse を参照してください。
この "ErrorResponse" には、"Error Code" が付加されており、この "Error Code" によって、どのような要因で、エラーが発生しているかがわかるようになっています。
以下に"Error Code" の一覧を示します。
Error Code | Value | Description |
---|---|---|
0x01 |
状態違反 |
|
0x02 |
パケット長パラメータの誤り |
|
0x03 |
不明なコマンド |
|
0x04 |
無効なコマンド |
|
0x05 |
電源ONの失敗 |
|
0x06 |
電源OFFの失敗 |
|
0x07 |
DSPの起動失敗 |
|
0x08 |
DSPの終了失敗 |
|
0x09 |
DSPのバージョン不一致 |
|
0x0A |
入出力パラメータの誤り |
|
0x0B |
データパスのクリア失敗 |
|
0x0C |
入出力が無効 |
|
0x0D |
Decoder DSPの初期化失敗 |
|
0x0E |
Encoder DSPの初期化失敗 |
|
0x0F |
Filter DSPの初期化失敗 |
|
0x11 |
コーデック種別の指定の誤り |
|
0x13 |
チャンネル数の指定の誤り |
|
0x14 |
サンプリング周波数の指定の誤り |
|
0x15 |
ビットレートの指定の誤り |
|
0x16 |
ビット長の指定の誤り |
|
0x18 |
Playerインスタンスの指定の誤り |
|
0x19 |
入力デバイスの指定の誤り |
|
0x1A |
出力デバイスの指定の誤り |
|
0x1B |
入力デバイスハンドルの指定の誤り |
|
0x28 |
ミュートパラメータの指定の誤り |
|
0x2B |
入出力機能の初期化失敗 |
|
0x2C |
入力データの取得失敗 |
|
0x2F |
SimpleFIFOのデータが枯渇 |
|
0x30 |
マイクゲインの指定誤り |
|
0x32 |
出力先設定の指定誤り |
|
0x33 |
ボリュームの指定誤り |
|
0x34 |
ボリュームの指定誤り |
|
0x35 |
ミュート対象の指定誤り |
|
0x36 |
ビープパラメータの指定誤り |
|
0x37 |
データキュー管理の失敗 |
|
0x39 |
動作モードの指定誤り |
"Error Code" の詳細は こちら を参照してください。
2.1.9. アテンションエラー
Audio SubSystem内部での処理中(コマンド処理ではなく)に何らかのエラーを検出した場合、通知用のイベントが発生します。
アテンションエラーのデータ形式については ErrorAttention を参照してください。
アテンションエラーには
再生動作時のES(Elementary Stream)の供給の途切れ(アンダーフロー)や、記録動作時のES書き込みバッファのあふれ(オーバーフロー)などのフロー制御のエラー、メモリリソースの枯渇や、リアルタイム処理の遅延といったシステムエラー、
HWから発生したエラーなど、復帰にシステムのリセットが必要となる致命的なエラーなどがあります。
これらのエラーは、"ErrorAttention"に付加されている"Attention Code"で判断することが出来ます。 発生した"Attention Code"に基づいて修正を行ってください。 また、実装方法を変えることで、エラーが改善されることもあります。
以下に、"ErrorAttention" に付加される、 "Attention Code" の一覧を示します。
Attention Code | Value | Description |
---|---|---|
0x01 |
DMA転送のアンダーフロー |
|
0x02 |
DMA転送のオーバーフロー |
|
0x03 |
DMA転送の失敗 |
|
0x05 |
SimpleFIFOのアンダーフロー |
|
0x06 |
SimpleFIFOのオーバーフロー |
|
0x07 |
不正なイベントの受信 |
|
0x08 |
内部状態の異常 |
|
0x09 |
内部パラメータの異常 |
|
0x0A |
内部キューのPOPエラ |
|
0x0B |
内部キューのPUSHエラ |
|
0x0C |
内部キューの枯渇 |
|
0x0D |
メモリハンドルの取得失敗 |
|
0x0E |
メモリハンドルの解放失敗 |
|
0x0F |
タスクの生成失敗 |
|
0x10 |
インスタンスの生成や削除の失敗 |
|
0x12 |
DSPの起動失敗 |
|
0x13 |
DSPの終了失敗 |
|
0x14 |
DSPの処理でエラー |
|
0x16 |
DSPから不正なデータ受信 |
|
0x18 |
DSPのバージョン不一致 |
|
0x19 |
AudioDriverでエラー |
|
0x1A |
ESデータの解析エラー |
|
0x1F |
DSPの処理で致命的エラー |
|
0x20 |
DSPへのコマンド送信エラー |
"Attention Code" の詳細は こちら を参照してください。
Attention通知にはレベルが指定されており、そのエラーに対する深刻度と同時に復帰の処理方法が変わります。
Level | value | Description |
---|---|---|
FATAL |
0x03 |
システムコールエラー等、回復不能なもので、復帰にリセットを要求します。 |
ERROR |
0x02 |
内部エラー(キューFull/Empty,DSPロード/アンロードなど)でAudioシステムの動作が継続できないようなエラーです。システムを初期状態(Ready状態)に戻すことで復帰が可能になります。 |
WARN |
0x01 |
エンコード・デコードエラー、データのアンダーフロー・オーバーフローなど、動作に異常があり、音声データなどには異常が発生している可能性があるが、動作は継続できるものです。 |
2.1.12. Module ID List
AudioSubSystem内部で使用するモジュールのID一覧です。
Attention callbackでアテンションコードとともに通知され、どのモジュールでエラーが発生したかを判断します。
Module ID | Value | Description |
---|---|---|
AS_MODULE_ID_AUDIO_MANAGER |
0 |
Audio Manager |
AS_MODULE_ID_AUDIO_DRIVER |
1 |
Audio Baseband Driver |
AS_MODULE_ID_MIC_FRONTEND_OBJ |
2 |
FrontEnd Object |
AS_MODULE_ID_INPUT_DATA_MNG_OBJ |
3 |
Input Data Manager Object |
AS_MODULE_ID_MEDIA_RECORDER_OBJ |
4 |
Media Recorder Object |
AS_MODULE_ID_OUTPUT_MIX_OBJ |
5 |
Output Mix Object |
AS_MODULE_ID_PLAYER_OBJ |
6 |
Player Object |
AS_MODULE_ID_RECOGNITION_OBJ |
7 |
Recognition Object |
AS_MODULE_ID_SOUND_EFFECT_OBJ |
8 |
Sound Effect Object |
AS_MODULE_ID_SYNTHESIZER_OBJ |
9 |
Synthesizer Object |
AS_MODULE_ID_CAPTURE_CMP |
10 |
Capture Component |
AS_MODULE_ID_DECODER_CMP |
11 |
Decoder Component |
AS_MODULE_ID_ENCODER_CMP |
12 |
Encoder Component |
AS_MODULE_ID_FILTER_CMP |
13 |
Filter Component |
AS_MODULE_ID_RECOGNITION_CMP |
14 |
Recognition Component |
AS_MODULE_ID_RENDERER_CMP |
15 |
Renderer Component |
AS_MODULE_ID_POSTPROC_CMP |
16 |
Postfilter Component |
AS_MODULE_ID_OSCILLATOR_CMP |
17 |
Oscillator Component |
AS_MODULE_ID_CUSTOM_CMP |
18 |
Custom Component |
2.2. Camera ライブラリ
ここでは、Spresense のArduino IDE で利用可能なCameraライブラリについて説明します。
2.2.1. 概要
下記にCamera ライブラリの概略図を示します。
Spresense Cameraには、2つのライブラリクラスが用意されています。 1つは、CameraClassのインスタンスである"theCamera"で、もう一つがCameraから取得した画像を操作するCamImageクラスです。
"theCamera"には大きく3つの機能が備わっています。
-
CameraのPreviewを取得するVideoStream機能
-
Cameraのパラメータを制御する機能
-
Cameraで高解像度なJPEG画像を写真として取得する機能
CamImageクラスは、theCameraから取得した画像イメージをユーザが操作するための関数です。 CamImageクラスの概要を以下の図に示します。
CamImageクラスには、2つの機能が備わっています。
-
Cameraで撮影された画像の情報を取得する。
-
取得した画像を変換する。
以下に、theCameraおよびCamImageが持つ、これら5つの機能について説明します。
2.2.2. CameraのPreviewを取得するVideoStream機能
通常カメラのファインダーには、Cameraに映るリアルタイムの画像が映っています。 ここでは、このリアルタイム画像(リアルタイム動画)をPreview画像と呼びます。 "theCamera"には、このPreview画像を毎フレーム取得する機能が備わっています。
Preview画像を取得するには、まず、begin()メソッド関数を用いて、Preview画像の画像フォーマットを決定します。 begin()メソッド関数の定義は以下のようになっています。
begin(
int buff_num=1,
CAM_VIDEO_FPS fps = CAM_VIDEO_FPS_30,
int video_width = CAM_IMGSIZE_QVGA_H,
int video_height = CAM_IMGSIZE_QVGA_V,
CAM_IMAGE_PIX_FMT fmt=CAM_IMAGE_PIX_FMT_YUV422,
int jpgbufsize_divisor = 7)
begin()に与えるパラメータはすべてPreview画像のパラメータを決定するものです。 それぞれ、theCamera内部で持つPreview用画像バッファの数とVideoのフレームレート(1秒間に何コマの画像を取得するか)、 画像の縦横サイズと画像データのピクセルフォーマット、JPEGフォーマット指定時のバッファサイズ計算に用いられる除数になります。 デフォルトではそれぞれ、内部画像バッファ数が1枚、フレームレートが30FPS(1秒間に30枚)、画像サイズがQVGA(320 x 240)、ピクセルフォーマットがYUV422、JPEGフォーマット指定時のバッファサイズ計算に用いられる除数が7となっています。 内部画像バッファの数は通常使用であればデフォルトの値をご使用ください。
内部画像バッファの数を増やす際の例としては、 取得した画像を色々と加工するなどの重たい処理をさせたい場合に、画像処理とCameraからの画像取得を並列化したい、という場合が考えられます。 そのような場合、内部画像バッファ数を2にすることで、その重たい処理をさせながら、その裏でCameraからの画像取得を並行して行うということが可能となり、結果的にフレームレートが改善する場合もあります。 ただし、QVGAでバッファのメモリを約150KB消費しますので、枚数を多く設定する場合はご注意ください。
Preview画像のピクセルフォーマットはYUV422、RGB565およびJPEGをサポートしています。 各ピクセルフォーマット時に使用可能なフレームサイズ、フレーム間隔は、 SDKがサポートしているものと同一になります。 使用デバイスに応じて、ISX012で使用可能な設定もしくはISX019で使用可能な設定を参照ください。 |
begin()メソッド関数は、theCameraを利用する際に最初に呼び出す必要のある関数です。 begin()メソッド関数が正常に終了したらstartStreaming()メソッド関数を使ってPreview画像を取得するためのコールバック関数を登録します。 コールバック関数の型は以下のようになります。
void camera_callback(CamImage img)
ユーザはこの型の関数を独自に実装して、startStreaming()メソッド関数を用いて登録します。 startStreaming()の第一引数に"true"を指定すると、Preview用のVideo画像の取得が開始され、画像が取得されるたびに登録されたコールバック関数が呼び出されます。 画像を取得する頻度は、begin()メソッド関数で指定した、フレームレートによって決定します。 ただし、ユーザが実装したコールバック関数が終了しない限り、次のフレームのコールバック関数が呼び出されることはありません。 Preview画像の取得を停止したい場合は、startStreaming()メソッド関数の第一引数をfalseにしてstartStreaming()メソッド関数を呼び出してください。
2.2.3. Cameraのパラメータを制御する機能
通常のCameraには、色味の調整や明るさなど、様々な設定が出来るようになっており、Spresense Cameraにも、いくつかの設定が出来るようになっています。
Method name | Description |
---|---|
Cameraの自動ホワイトバランスの開始停止 |
|
自動ホワイトバランス時のモード設定 |
|
Cameraの自動露光調整の開始停止 |
|
Cameraの露光時間(100マイクロ秒単位)設定 |
|
Cameraの自動ISO感度の開始停止 |
|
CameraのISO感度設定 |
|
画像効果設定 |
|
HDRモード設定 |
|
JPEG品質設定 |
また、以下のAPIを用いて、現在値を取得出来るパラメータもあります。
Method name | Description |
---|---|
Cameraの露光時間(100マイクロ秒単位)取得 |
|
CameraのISO感度取得 |
|
HDRモード取得 |
|
JPEG品質取得 |
これらの設定メソッド関数はbegin()メソッド関数をエラー無く呼び出した後であれば、任意のタイミングで呼び出すことが可能です。
2.2.4. Cameraで高解像度なJPEG画像を写真として取得する機能
Preview画像は低解像度な半面、動画としてフレームレートの頻度で画像を取得することが出来ます。 一方、写真としてデータを取得する場合、Spresense Cameraでは、高解像度なJPEG圧縮された画像を取得することが出来ます。
まず、theCameraに対して「フィルムをセットする」という処理を行います。 この処理を行うメソッド関数が、setStillPictureImageFormat()になります。 このメソッド関数を用いて、静止画(写真)用の画サイズやピクセルフォーマットを設定します。
setStillPictureImageFormat(
int width,
int height,
CAM_IMAGE_PIX_FMT fmt = CAM_IMAGE_PIX_FMT_JPEG,
int jpgbufsize_divisor = 7)
第一、第二引数で画像の縦横サイズを指定します。第三引数で画像のピクセルフォーマットを指定します。第四引数でJPEGフォーマット指定時のバッファサイズ計算に用いられる除数を指定します。
setStillPictureImageFormat()メソッド関数は、1度設定を行えば、パラメータの変更をしない限り、永続的に設定が有効になります。 ピクセルフォーマットはYUV422、RGB565およびJPEGをサポートしています。 各ピクセルフォーマット時に使用可能なフレームサイズ、フレーム間隔は、 SDKがサポートしているものと同一になります。 使用デバイスに応じて、ISX012で使用可能な設定もしくはISX019で使用可能な設定を参照ください。 |
画像の設定が終わったら、任意のタイミングで「シャッターを切る」という処理を行い、写真データを取得します。 そのためのメソッド関数がtakePicture()になります。 takePicture()は戻り値としてCamImageのインスタンスを返します。 写真撮影で何らかのエラーが発生した場合、空のCamImageを返します。 CamImageのインスタンスが空かどうかを判断するには、CamImageクラスのisAvailable()で確認することが出来ます。
JPEGでのCamImageの取得に失敗する場合、 |
2.2.5. Cameraで撮影された画像の情報を取得する。
startStreaming()でのコールバック及びtakePicture()の戻り値で得られるCamImageインスタンスは、取得した画像の情報が入っています。 CamImageクラスのメソッド関数を用いて、画像の情報を取得することが出来ます。
Method name | Description |
---|---|
isAvailable() |
取得したCamImageインスタンスが利用可能なものかどうかを確認する |
getWidth() |
画像の幅をピクセル単位で取得 |
getHeight() |
画像の高さをピクセル単位で取得 |
getPixFormat() |
画像のピクセルフォーマットを取得 |
getImgSize() |
画像のデータのサイズをバイト単位で取得 |
getImgBuff() |
画像データのバッファアドレスを取得 |
getImgBuffSize() |
画像バッファサイズをバイト単位で取得 |
2.2.6. 取得した画像を変換する。
CamImageインスタンスには3つの画像変換メソッド関数が用意されています。
Method name | Description |
---|---|
convertPixFormat() |
現状のピクセルフォーマットから別のピクセルフォーマットに画像を変換する |
resizeImageByHW() |
画像の拡大縮小を行う |
clipAndResizeImageByHW() |
画像の一部を切り出し、切り出し部分の拡大縮小を行う |
画像をディスプレイに出したいような場合、ディスプレイのピクセルフォーマットは通常、RGBフォーマットが用いられます。 特にPreview画像を取得した場合、取得した画像をディスプレイ表示したいケースは多いと思います。 このようなケースで、ピクセルフォーマットの変換を行う際などに、convertPixFormat()を用いることが出来ます。
convertPixFormat()は自身データメモリ上でピクセルフォーマットが変換されるため、 現在のCamImageインスタンスが上書きされます。
また、画像の拡大・縮小を行うのにresizeImageByHW()を、 画像の一部のみを切り出すのにclipAndResizeImageByHW()を、それぞれ用いることができます。 clipAndResizeImageByHW()は、切り出した部分に対して、拡大・縮小を行うこともできます。
現時点では以下の制約があります。
|
2.2.7. サンプルコードによる解説
ここでは、実際に、Spresense Arduino Packageに含まれるCameraのサンプルコードを用いて、 Spresense Cameraの使い方を解説します。
サンプルコードは、Arduino IDEのメニューバーから開くことが出来ます。
「ファイル」⇒「スケッチ例」⇒「Spresenseのスケッチ例の中のCamera」⇒「camera」
/*
* camera.ino - Simple camera example sketch
* Copyright 2018, 2022 Sony Semiconductor Solutions Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* This is a test app for the camera library.
* This library can only be used on the Spresense with the FCBGA chip package.
*/
#include <SDHCI.h>
#include <stdio.h> /* for sprintf */
#include <Camera.h>
#define BAUDRATE (115200)
#define TOTAL_PICTURE_COUNT (10)
SDClass theSD;
int take_picture_count = 0;
/**
* Print error message
*/
void printError(enum CamErr err)
{
Serial.print("Error: ");
switch (err)
{
case CAM_ERR_NO_DEVICE:
Serial.println("No Device");
break;
case CAM_ERR_ILLEGAL_DEVERR:
Serial.println("Illegal device error");
break;
case CAM_ERR_ALREADY_INITIALIZED:
Serial.println("Already initialized");
break;
case CAM_ERR_NOT_INITIALIZED:
Serial.println("Not initialized");
break;
case CAM_ERR_NOT_STILL_INITIALIZED:
Serial.println("Still picture not initialized");
break;
case CAM_ERR_CANT_CREATE_THREAD:
Serial.println("Failed to create thread");
break;
case CAM_ERR_INVALID_PARAM:
Serial.println("Invalid parameter");
break;
case CAM_ERR_NO_MEMORY:
Serial.println("No memory");
break;
case CAM_ERR_USR_INUSED:
Serial.println("Buffer already in use");
break;
case CAM_ERR_NOT_PERMITTED:
Serial.println("Operation not permitted");
break;
default:
break;
}
}
/**
* Callback from Camera library when video frame is captured.
*/
void CamCB(CamImage img)
{
/* Check the img instance is available or not. */
if (img.isAvailable())
{
/* If you want RGB565 data, convert image data format to RGB565 */
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
/* You can use image data directly by using getImgSize() and getImgBuff().
* for displaying image to a display, etc. */
Serial.print("Image data size = ");
Serial.print(img.getImgSize(), DEC);
Serial.print(" , ");
Serial.print("buff addr = ");
Serial.print((unsigned long)img.getImgBuff(), HEX);
Serial.println("");
}
else
{
Serial.println("Failed to get video stream image");
}
}
/**
* @brief Initialize camera
*/
void setup()
{
CamErr err;
/* Open serial communications and wait for port to open */
Serial.begin(BAUDRATE);
while (!Serial)
{
; /* wait for serial port to connect. Needed for native USB port only */
}
/* Initialize SD */
while (!theSD.begin())
{
/* wait until SD card is mounted. */
Serial.println("Insert SD card.");
}
/* begin() without parameters means that
* number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */
Serial.println("Prepare camera");
err = theCamera.begin();
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Start video stream.
* If received video stream data from camera device,
* camera library call CamCB.
*/
Serial.println("Start streaming");
err = theCamera.startStreaming(true, CamCB);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Auto white balance configuration */
Serial.println("Set Auto white balance parameter");
err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Set parameters about still picture.
* In the following case, QUADVGA and JPEG.
*/
Serial.println("Set still picture format");
err = theCamera.setStillPictureImageFormat(
CAM_IMGSIZE_QUADVGA_H,
CAM_IMGSIZE_QUADVGA_V,
CAM_IMAGE_PIX_FMT_JPG);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
}
/**
* @brief Take picture with format JPEG per second
*/
void loop()
{
sleep(1); /* wait for one second to take still picture. */
/* You can change the format of still picture at here also, if you want. */
/* theCamera.setStillPictureImageFormat(
* CAM_IMGSIZE_HD_H,
* CAM_IMGSIZE_HD_V,
* CAM_IMAGE_PIX_FMT_JPG);
*/
/* This sample code can take pictures in every one second from starting. */
if (take_picture_count < TOTAL_PICTURE_COUNT)
{
/* Take still picture.
* Unlike video stream(startStreaming) , this API wait to receive image data
* from camera device.
*/
Serial.println("call takePicture()");
CamImage img = theCamera.takePicture();
/* Check availability of the img instance. */
/* If any errors occur, the img is not available. */
if (img.isAvailable())
{
/* Create file name */
char filename[16] = {0};
sprintf(filename, "PICT%03d.JPG", take_picture_count);
Serial.print("Save taken picture as ");
Serial.print(filename);
Serial.println("");
/* Remove the old file with the same file name as new created file,
* and create new file.
*/
theSD.remove(filename);
File myFile = theSD.open(filename, FILE_WRITE);
myFile.write(img.getImgBuff(), img.getImgSize());
myFile.close();
}
else
{
/* The size of a picture may exceed the allocated memory size.
* Then, allocate the larger memory size and/or decrease the size of a picture.
* [How to allocate the larger memory]
* - Decrease jpgbufsize_divisor specified by setStillPictureImageFormat()
* - Increase the Memory size from Arduino IDE tools Menu
* [How to decrease the size of a picture]
* - Decrease the JPEG quality by setJPEGQuality()
*/
Serial.println("Failed to take picture");
}
}
else if (take_picture_count == TOTAL_PICTURE_COUNT)
{
Serial.println("End.");
theCamera.end();
}
take_picture_count++;
}
このサンプルは、Preview画像をQVGA、フレームレートを30FPSに設定し、30コマのデータを取得すると1枚JPEG写真を撮り、SDCardに保存する、 という動作をします。
ステップとしては、「初期設定」、「エラー表示」、「setup()」、「Previewコールバック」そして「loop()」の5つで動作しています。
それでは、これら5つについて詳しく見ていきましょう。
2.2.7.1. 初期設定
/*
* camera.ino - Simple camera example sketch
* Copyright 2018, 2022 Sony Semiconductor Solutions Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* This is a test app for the camera library.
* This library can only be used on the Spresense with the FCBGA chip package.
*/
#include <SDHCI.h>
#include <stdio.h> /* for sprintf */
#include <Camera.h>
#define BAUDRATE (115200)
#define TOTAL_PICTURE_COUNT (10)
SDClass theSD;
int take_picture_count = 0;
まず、Camera ライブラリを利用する場合、ヘッダファイル <Camera.h> をインクルードする必要があります。
#include <Camera.h>
このヘッダファイルをインクルードすることで、thCameraインスタンスを利用することが出来るようになります。
その後、loop()関数で使う変数を定義しています。
int take_picture_count = 0;
take_picture_countは、1秒おきにtakePicture()を呼ばれる度にカウントアップしていく変数で、この変数を用いて、 SDCardに書き出されるファイル名と作成するファイル数の上限を制御しています。 (このサンプルでは10枚の写真を撮ると写真撮影を終了するようになっています。)
2.2.7.2. エラー表示
/**
* Print error message
*/
void printError(enum CamErr err)
{
Serial.print("Error: ");
switch (err)
{
case CAM_ERR_NO_DEVICE:
Serial.println("No Device");
break;
case CAM_ERR_ILLEGAL_DEVERR:
Serial.println("Illegal device error");
break;
case CAM_ERR_ALREADY_INITIALIZED:
Serial.println("Already initialized");
break;
case CAM_ERR_NOT_INITIALIZED:
Serial.println("Not initialized");
break;
case CAM_ERR_NOT_STILL_INITIALIZED:
Serial.println("Still picture not initialized");
break;
case CAM_ERR_CANT_CREATE_THREAD:
Serial.println("Failed to create thread");
break;
case CAM_ERR_INVALID_PARAM:
Serial.println("Invalid parameter");
break;
case CAM_ERR_NO_MEMORY:
Serial.println("No memory");
break;
case CAM_ERR_USR_INUSED:
Serial.println("Buffer already in use");
break;
case CAM_ERR_NOT_PERMITTED:
Serial.println("Operation not permitted");
break;
default:
break;
}
}
Camera ライブラリで定義しているエラーコードを解釈して、エラーの内容をシリアルモニタに表示しています。
2.2.7.3. Previewコールバック
/**
* Callback from Camera library when video frame is captured.
*/
void CamCB(CamImage img)
{
/* Check the img instance is available or not. */
if (img.isAvailable())
{
/* If you want RGB565 data, convert image data format to RGB565 */
img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565);
/* You can use image data directly by using getImgSize() and getImgBuff().
* for displaying image to a display, etc. */
Serial.print("Image data size = ");
Serial.print(img.getImgSize(), DEC);
Serial.print(" , ");
Serial.print("buff addr = ");
Serial.print((unsigned long)img.getImgBuff(), HEX);
Serial.println("");
}
else
{
Serial.println("Failed to get video stream image");
}
}
startStreaming()で登録される、カメラのPreviewが出力された際に呼び出される関数になります。 この関数内では、関数の引数として取得したCamImageのインスタンスが利用可能なものかどうかのチェックを行い、 その後、ピクセルフォーマットをRGB565に変換しています。 変換後、getImgSize()とgetImgBuff()で取得したデータサイズとメモリアドレスを表示しています。 一般的には、この段階で接続したディスプレイなどにイメージデータを出力して、 カメラのファインダービューを構築します。
2.2.7.4. setup()
/**
* @brief Initialize camera
*/
void setup()
{
CamErr err;
/* Open serial communications and wait for port to open */
Serial.begin(BAUDRATE);
while (!Serial)
{
; /* wait for serial port to connect. Needed for native USB port only */
}
/* Initialize SD */
while (!theSD.begin())
{
/* wait until SD card is mounted. */
Serial.println("Insert SD card.");
}
/* begin() without parameters means that
* number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */
Serial.println("Prepare camera");
err = theCamera.begin();
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Start video stream.
* If received video stream data from camera device,
* camera library call CamCB.
*/
Serial.println("Start streaming");
err = theCamera.startStreaming(true, CamCB);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Auto white balance configuration */
Serial.println("Set Auto white balance parameter");
err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
/* Set parameters about still picture.
* In the following case, QUADVGA and JPEG.
*/
Serial.println("Set still picture format");
err = theCamera.setStillPictureImageFormat(
CAM_IMGSIZE_QUADVGA_H,
CAM_IMGSIZE_QUADVGA_V,
CAM_IMAGE_PIX_FMT_JPG);
if (err != CAM_ERR_SUCCESS)
{
printError(err);
}
}
setup()では、初めにメッセージ表示用にSerialのセットアップを行い、続いてCameraのbegin()メソッド関数を呼び出しています。 Cameraのbegin()はデフォルトではフレームバッファメモリは1枚、フレームレートが30FPS、画サイズはQVGAになっています。 その後、startStreaming()でPreview用コールバック関数の設定とコールバックを有効にし、setAutoWhiteBalanceMode()で日中設定にしています。 最後に、setStillPictureImageFormat()で、QUAD VGAサイズの写真用の設定を行っています。
2.2.7.5. loop()
/**
* @brief Take picture with format JPEG per second
*/
void loop()
{
sleep(1); /* wait for one second to take still picture. */
/* You can change the format of still picture at here also, if you want. */
/* theCamera.setStillPictureImageFormat(
* CAM_IMGSIZE_HD_H,
* CAM_IMGSIZE_HD_V,
* CAM_IMAGE_PIX_FMT_JPG);
*/
/* This sample code can take pictures in every one second from starting. */
if (take_picture_count < TOTAL_PICTURE_COUNT)
{
/* Take still picture.
* Unlike video stream(startStreaming) , this API wait to receive image data
* from camera device.
*/
Serial.println("call takePicture()");
CamImage img = theCamera.takePicture();
/* Check availability of the img instance. */
/* If any errors occur, the img is not available. */
if (img.isAvailable())
{
/* Create file name */
char filename[16] = {0};
sprintf(filename, "PICT%03d.JPG", take_picture_count);
Serial.print("Save taken picture as ");
Serial.print(filename);
Serial.println("");
/* Remove the old file with the same file name as new created file,
* and create new file.
*/
theSD.remove(filename);
File myFile = theSD.open(filename, FILE_WRITE);
myFile.write(img.getImgBuff(), img.getImgSize());
myFile.close();
}
else
{
/* The size of a picture may exceed the allocated memory size.
* Then, allocate the larger memory size and/or decrease the size of a picture.
* [How to allocate the larger memory]
* - Decrease jpgbufsize_divisor specified by setStillPictureImageFormat()
* - Increase the Memory size from Arduino IDE tools Menu
* [How to decrease the size of a picture]
* - Decrease the JPEG quality by setJPEGQuality()
*/
Serial.println("Failed to take picture");
}
}
else if (take_picture_count == TOTAL_PICTURE_COUNT)
{
Serial.println("End.");
theCamera.end();
}
take_picture_count++;
}
loop()関数では、まず、1秒ほどsleep()関数で待ちます。 1秒後、take_picture_count変数の値が10を超えていないかチェックし、超えていなければ写真撮影処理に入ります。 撮影する処理では、 takePicture()メソッド関数をコールし、写真撮影を行って、取得した写真をimg変数に代入します。 img変数が利用可能であることをisAvailable()関数で確認し、取得した画像をSDカードに保存します。 take_picture_count変数の値が10になったとき、Cameraのend()メソッド関数を呼び出してCameraライブラリの処理を終了します。 最後に、take_picture_countをインクリメント(1増やす)して、loop()関数を終了しています。
以上でサンプルを使った説明は終わりになります。
さあ、Spresense Cameraを使ってオリジナルカメラデバイスを作ってみましょう。
2.3. DNNRTライブラリ
DNN Runtimeライブラリは、Sonyが提供するNeural Network LibrariesまたはNeural Network Consoleで学習したモデルを使用して、Deep Neural Network (DNN) を用いた認識処理を行うことができます。
DNNRTライブラリには、コアとなる DNNRT
と、データの入出力に使用する DNNVariable
があります。
ここでは、0~9までの手書き文字を認識するためのサンプル(number_recognition.ino
)を例に解説していきます。
2.3.1. 学習済みモデルの準備
2.3.1.1. Neural Network Console
学習済みモデルを作成するために、Neural Network Console (NNC)を使用します。こちらの、公式サイト からクラウド版の使用、またはWindows版インストーラがダウンロードできます。
2.3.1.2. 学習
-
クラウド版では、サンプルプロジェクトの
image_recognition.MNIST.LeNet
をベースに新しいプロジェクトを作成します。サンプルのプロジェクトを選択すると選択されたプロジェクトを元に新しいプロジェクトを作成します。新しいプロジェクトの名前を入力するダイアログボックスが表示されるので、好きな名前を入力してください。(ここでは、myproject
とします)作成された
myproject
を選択すると編集画面が表示されます。図 4. 編集画面(クラウド版)Windows版では、
LeNet.sdcproj
を選択して使用します。 -
ここでは、サンプルのネットワークモデルをそのまま使用して学習を行います。
クラウド版では、編集画面の右上にある
Run
ボタンを押します。図 5. 学習開始(クラウド版)Windows版では、
Training
の下にある三角ボタンを押します。図 6. 学習開始(Windows版) -
ウィンドウ下部のコンソールに
Training Completed
が表示されれば学習は完了です。
機械学習は非常に時間がかかります。 |
-
学習が完了したら学習結果を評価します。
クラウド版では、学習画面の右上にある
Run
ボタンを押します。図 7. 評価開始(クラウド版)Windows版では、
Evaluation
の下にある三角ボタンを押します。図 8. 評価開始(Windows版) -
評価が完了すると評価結果が表示されます。
x:image
の列に表示されている画像とy:label
の列に表示されている数字が一致しているはずです。DNNRTで使用するためにこの学習済みモデルをダウンロードします。クラウド版では、評価画面右上のドロップダウンリストから
NNB (NNabla C Runtime file format)
を選択し、下のDownload Project
を押します。Windows版では、
ACTION
メニューから、Export
→NNB (NNabla C Runtime file format)
を選択します。 -
ダウンロードした学習済みモデル
result.nnb
(クラウド版)またはmodel.nnb
(Windows版)と認識させたい画像をSDカードの直下にコピーします。学習済みモデルは、network.nnb
というファイル名に変更してください。このサンプルで対応している画像フォーマットはPGM (Portable Greyscale Map) のみです。PGMファイルを作れない場合は、こちらのサンプルPGM画像ファイルを使用してください。Neural Network Console (NNC) で生成したnetwork.nnb
のサンプルファイルも同じ場所においてあります。
以上で number_recognition.ino
サンプルを動作させる準備は完了です。
2.3.2. 手書き文字認識サンプル
image_recognition.MNIST.LeNet
および LeNet.sdcproj
で作成された学習モデルは、28x28サイズの画像を1つ入力にとり、10個の配列を出力します。この10個の配列はインデックスが認識した数字を意味しており、配列の中にそれぞれの数字である確率が出力されます。例えば、配列の先頭(インデックス0)には、入力された画像が数字の「0」である確率が出力されます。
DNNVariable output = dnnrt.outputVariable(0);
Serial.println(output[0]); // 入力画像が「0」である確率
...
Serial.println(output[9]); // 入力画像が「9」である確率
number_recognition.ino
では、出力された確率の配列の中から一番大きい確率のインデックスを認識した数字として、その確率とともにシリアルに出力します。
入力させたい画像は、number_recognition.ino
の以下の行で変更できます。
File pgmfile("number4.pgm");
2.4. EEPROM ライブラリ
EEPROM は、電源を切っても内容が消去されない不揮発なデータを保持することができます。 Spresense では EEPROM が搭載されていないので、SPI-Flash メモリを用いて EEPROM をエミュレートしています。 このライブラリは、SPI-Flash によってエミュレートされた EEPROM に対して、書き込みと読み込みを可能にします。
EEPROM ライブラリの API 仕様については、Arduino EEPROM ライブラリ を参照してください。
EEPROM のサンプルコードは、Arduino IDE のメニューから ファイル → スケッチ例 → Spresense用のスケッチ例 EEPROM
以下に用意されています。
EEPROM ライブラリは、Arduino EEPROM ライブラリと互換性をもち Arduino 用のサンプルコードをそのまま動かすことができます。
EEPROM サイズは、EEPROM.h に定義されている E2END
の値によって決められ、4000 バイトです。
Spresense ボードにおいて、アプリケーションからアクセスできる SPI-Flash の最大容量は 4MByte です。
この最大容量を超えない範囲で、E2END を変更することによって EEPROM のサイズをさらに増やすことも可能です。
|
2.5. eMMC ライブラリ
2.5.1. 概要
eMMC ライブラリは eMMC Add-on ボードの eMMC デバイスにアクセスするためのライブラリです。
eMMC ライブラリは、Arduino SD ライブラリ に類似した API 構成となっており、オブジェクト名を SD
から eMMC
へ置き換えることで、SD ライブラリと同じインターフェースを用いて eMMC デバイスへアクセスすることができます。
また、追加機能として、USB MSC (Mass Storage Class) 機能をサポートしています。
Spresense 拡張ボードにある USB と PC を接続し、beginUsbMsc()
を呼び出すことで、PC から eMMC デバイス上のファイルに直接アクセスすることができます。
RTC ライブラリ により 1980/1/1 以降の現在時刻が設定されている場合、ファイルやディレクトリの作成日時や更新日時など、RTC 時刻をもとにしたタイムスタンプがファイルシステム内に記録されます。 |
2.5.2. 機能
各種APIの詳細は、APIリファレンスマニュアル eMMC Library API を参照してください。
Function | Description |
---|---|
eMMC.begin() |
eMMC デバイスを初期化します。本 API を呼び出すことで eMMC デバイスが使用可能になります。 |
eMMC.end() |
eMMC デバイスの終了処理を行います。begin()で電源制御のピンが指定されていた場合、最後にeMMCデバイスの電源をOFFします。 |
eMMC.beginUsbMsc() |
USB MSC (Mass Storage Class) 機能を開始します。 |
eMMC.endUsbMsc() |
USB MSC (Mass Storage Class) 機能を終了します。 |
eMMC.format() |
eMMC デバイスをフォーマットします。デフォルト FAT32 ファイルシステムでフォーマットします。 |
eMMC.open() |
ファイル名を指定して eMMC デバイス内のファイルをオープンします。 |
eMMC.exists() |
eMMC デバイス内にファイルが存在するかどうかを確認します。 |
eMMC.mkdir() |
eMMC デバイス内にディレクトリを作成します。 |
eMMC.rmdir() |
eMMC デバイス内にディレクトリを削除します。 |
eMMC.remove() |
eMMC デバイス内のファイルを削除します。 |
2.5.3. サンプル
eMMC ライブラリには、4 つのスケッチのサンプルが提供されています。
Example | Description |
---|---|
eMMC デバイスをフォーマットします。eMMC デバイスを初めて利用する際に一度だけ実行してください。 |
|
eMMC デバイス上のファイルを読み書きするサンプルです。 |
|
USB MSC 機能のサンプルです。eMMC デバイスが PC 上のドライブとしてマウントされ、PC から eMMC デバイスに直接アクセスすることができます。 |
|
USB MSC 機能とファイル操作を組み合わせた複合アプリケーションです。eMMC デバイス内のファイルに対して、スケッチからのファイル操作と、USB MSC による PC からのファイル操作は、排他的に動作させる必要があります。このサンプルでは、アプリケーションプログラムからファイル一覧を取得・表示した後に、USB MSC 機能を有効にし、PC から eMMC デバイス内のファイルを操作できるようになります。USB MSC 機能を終了した後に、再びプログラム中からファイル一覧を取得・表示します。 |
2.6. File ライブラリ
2.6.2. 機能
各種APIの詳細は、APIリファレンスマニュアル File Library API を参照してください。
File インスタンス名が myFile のとき、次のようにファイルをオープンします。
#include <SDHCI.h>
SDClass SD;
File myFile;
myFile = SD.open("test.txt");
File オブジェクトに対して、次に示すような関数が提供されています。
Function | Description |
---|---|
myFile.write() |
ファイル位置からファイルにデータを書き込みます。 |
myFile.read() |
ファイル位置からファイルのデータを読み出します。 |
myFile.peek() |
ファイルから読み取り位置を進めずに 1 バイト読み出します。 |
myFile.available() |
ファイルから読み出し可能なバイトがあるかを確認します。 |
myFile.flush() |
ファイルに書き込んだデータがストレージに書き込まれることを保証します。 |
myFile.seek() |
ファイル内のファイル位置を先頭から指定した位置に移動します。 |
myFile.position() |
ファイル内の現在位置を取得します。 |
myFile.size() |
ファイルのサイズを取得します。 |
myFile.close() |
ファイルをクローズします。 |
myFile.bool() |
ファイルやディレクトリが存在するかどうかを返します。 |
myFile.name() |
ファイル名を取得します。 |
myFile.isDirectory() |
ファイルがディレクトリなのかどうかを返します。 |
myFile.openNextFile() |
ディレクトリ内の次のファイルをオープンします。 |
myFile.rewindDirectory() |
ディレクトリ内の最初のファイルに戻します。 |
2.7. Flash ライブラリ
2.7.1. 概要
Flash ライブラリは Spresense メインボード上の Flash デバイスにアクセスするためのライブラリです。
Flash ライブラリは、Arduino SD ライブラリ に類似した API 構成となっており、オブジェクト名を SD
から Flash
へ置き換えることで、SD ライブラリと同じインターフェースを用いて Flash デバイスへアクセスすることができます。
2.7.2. 機能
各種APIの詳細は、APIリファレンスマニュアル Flash Library API を参照してください。
Function | Description |
---|---|
Flash.begin() |
ダミー関数です。常に true を返します。 |
Flash.format() |
Flash デバイスをフォーマットします。 |
Flash.open() |
ファイル名を指定して Flash デバイス内のファイルをオープンします。 |
Flash.exists() |
Flash デバイス内にファイルが存在するかどうかを確認します。 |
Flash.mkdir() |
Flash デバイス内にディレクトリを作成します。 |
Flash.rmdir() |
Flash デバイス内にディレクトリを削除します。 |
Flash.remove() |
Flash デバイス内のファイルを削除します。 |
2.7.3. サンプル
Flash ライブラリには、2 つのスケッチのサンプルが提供されています。
Example | Description |
---|---|
Flash デバイスをフォーマットします。Flash デバイスはフォーマット済みの状態で出荷されていますが、Flash 内のデータを削除したい等の目的で再フォーマットが必要な際に実行してください。フォーマットを実行すると、ブートローダやスケッチからロードしたプログラムを除くすべてのユーザー領域が削除されます。Flash に存在する EEPROM データも削除されます。 |
|
Flash デバイス上のファイルを読み書きするサンプルです。 |
2.8. GNSS ライブラリ
GNSS ライブラリは、Spresense の GNSS測位機能をコントロールし、位置情報を取得するためのライブラリです。Arduino のスケッチから簡単に使うことができます。
GNSS測位機能を利用するには次の2種類の環境があります。
GNSSライブラリは共通のライブラリで両方の環境をサポートしています。
-
内蔵 GNSS
-
GNSS Add-on ボード
内蔵GNSSを使用するにあたって、特別なハードウェアの設定は必要ありません。アンテナも Spresense メインボード上にマウントされていますので、見晴らしのよい屋外に出れば簡単に位置情報を得ることができます。ただし、起動時に衛星を捕捉するのに1〜2分かかりますので、アプリケーション設計時には留意してください。
内蔵GNSS機能を使用する場合、Spresense拡張ボードは必要ありません。メインボード単体で動作させることができます。
GNSS Add-on ボードを利用する際は、GNSS Add-onボード本体とアンテナが別途必要になります。 詳細は、GNSS Add-onボードの接続方法 を参照してください。
内蔵GNSSを用いたアプリケーションをGNSS Add-onボード上で動かす場合、スケッチ上の |
GNSS ライブラリには、次のサンプルスケッチが提供されています。
-
gnss.ino は、内蔵GNSSで測位された情報を USBシリアルポートから出力する簡単なサンプルです。このサンプルでは位置情報を GNSS ライブラリ特有のフォーマットで出力されます。詳細については GNSS.h を参照してください。
-
gnss_tracker.ino は、少し複雑なサンプルです。このサンプルは、SDカードに位置情報を保存するので、Spresense拡張ボードが必要です。SDカードには、位置情報で一般的に使われている NMEA フォーマットで保存されますので、様々なアプリケーションから利用できます。本サンプルのチュートリアルは GPS チュートリアル を参照してください。
-
gnss_nmea.ino は、内蔵GNSSで測位された情報を NMEA 形式でシリアルへ出力するサンプルです。
-
gnss_addon.ino は、GNSS Add-onボードを使って測位した情報をシリアルポートへ出力する簡単なサンプルです。
-
gnss_addon_nmea.ino は、GNSS Add-onボードで測位された情報を NMEA 形式でシリアルへ出力するサンプルです。
2.9. LowPower ライブラリ
LowPowerライブラリは、Spresenseがもつ省電力機能をサポートしています。
LowPowerライブラリは、主に以下の機能を提供しています。
-
Deep Sleep や Cold Sleep など各種スリープ状態への遷移
Deep Sleep
-
最も消費電力が低いスリープモードです。CXD5247 PMIC (Power Management IC) のみ電源が入っており、CXD5602 は電源が OFF されます。
Cold Sleep
-
CXD5602 内で必要最小限の電源ドメインのみ ON されているスリープモードです。
Deep Sleep
に比べると消費電力は高くなりますが、GPIO の変化を起動要因のトリガとして、Cold Sleep
状態から起床することができます。
Sleep 中の消費電力に関して、拡張ボードに SD カードが挿入されていると SD カードの電源消費分により 約 5 mA ほど消費電流が増加します。 |
-
スリープ状態から起床したときの起動要因の取得
-
起動要因の許可/禁止を設定する起動マスクの設定
-
3 種類のクロックモードへの動的切り替え
CLOCK_MODE_156MHz
-
パフォーマンスが最も高いクロックモードです。起動時はこのクロックモードが選択されています。CPU は PLL を使用して 156MHz で動作します。
CLOCK_MODE_32MHz
-
システム全体のクロックを 32MHz に落として消費電力を削減します。このクロックモードが選択された場合、CXD5602 の Core 電圧は 0.7V で動作します。CPU は PLL を使用して 32MHz で動作します。
CLOCK_MODE_8MHz
-
システム全体のクロックを 8MHz に落とします。これは最も消費電力の少ないクロックモードです。Core 電圧は 0.7V で動作し、CPU は PLL を使用せずに内蔵発振器で動作します。PLL を使用しない場合、クロックモードをこのモードにして、さらに TCXO の電源を落とすことでさらに消費電力を削減することができます。
一般的に、クロックを下げれば下げるほど消費電力を削減することができますが、それに応じて動作パフォーマンスも低下します。 また、低クロックモードにおいて、すべてのハードウェア機能が動作するわけではありません。詳細については後述します。 |
各種APIの詳細は、APIリファレンスマニュアル LowPower Library API を参照してください。
2.9.1. クロックモードについて
clockMode()
の引数に CLOCK_MODE_156MHz
, CLOCK_MODE_32MHz
, CLOCK_MODE_8MHz
のいずれかを指定することにより
アプリケーション CPU のクロック、及び、システム全体のクロックを動的に切り替えます。動作クロックを下げることにより、
消費電力を削減することができます。
参考までに 3 つのモードについてバッテリー端の消費電流を示します。 測定条件は、Spresense メインボードのみを使用し、電源はバッテリーコネクタから 3.7V を供給しています。 ソフトウェアは特に何も動作していないアイドル状態です。
Clock Mode | Battery current |
---|---|
CLOCK_MODE_156MHz |
6.68 mA |
CLOCK_MODE_32MHz |
3.66 mA |
CLOCK_MODE_8MHz |
3.20 mA |
CLOCK_MODE_8MHz + TCXO=PowerOff |
1.16 mA |
この測定結果は、メインボード上の電源 LED による電流消費分も含まれています。
ユーザーアプリケーションからのクロックモード制御とは別に、システム内部で自動的にクロックモードを切り替えることがあります。
-
USB MSC (Mass Storage) など USB 通信機能を使用している間、クロックモードは自動的に
CLOCK_MODE_156MHz
になります -
GNSS 測位機能を使用している際は、クロックモードは自動的に
CLOCK_MODE_156MHz
もしくはCLOCK_MODE_32MHz
になります -
SD カードのマウント処理中は、自動的に
CLOCK_MODE_156MHz
へクロックアップしマウント後に以前の状態に戻ります。
そのため、必ずしもユーザーが指定したクロックモードに変更されるわけではないことに留意してください。
クロックモードが切り替わったかどうかを確認するために、現時点のクロックモードを getClockMode()
関数により取得することができます。
また、低クロックモードですべての機能が動作するわけではありません。制約事項を次に示します。
-
Audio 機能は、
CLOCK_MODE_156MHz
で動作させてください -
Camera 機能は、
CLOCK_MODE_156MHz
もしくはCLOCK_MODE_32MHz
で動作させてください
2.9.2. サンプル
LowPower ライブラリの基本的な使い方は、examples にあるサンプルスケッチをご覧ください。
サンプルスケッチは、Arduino IDE メニューの
ファイル → スケッチ例 → Spresense 用のスケッチ例 LowPower
から開くことができます。
Example | Description |
---|---|
ExternalWakeup |
GPIO外部ピンの状態変化によって、Cold Sleepから起床します |
TimedWakeup |
RTCアラームによって、Cold Sleepから起床します |
TimedWakeupDeep |
RTCアラームによって、Deep Sleepから起床します |
Reboot |
システムを再起動します |
WatchdogReboot |
ウォッチドッグタイマーによって、システムを再起動します |
ClockChange |
クロックモードについて 156MHz/32MHz/8MHz へ順番に切り替えます |
2.10. LTE ライブラリ
Spresense LTEライブラリはLTEネットワークを介してインターネットに接続することができます。
2.10.1. ライブラリ構成
Spresense LTEライブラリ構成を図 10に示します。
Spresense LTEは2つのカテゴリに属するライブラリクラスを用意しています。
1つは、モデムと通信するライブラリクラス、もう一つがイーサネットやWiFiライブラリのような
クライアントインターフェースを実現するライブラリクラスです。
これら2つのカテゴリに属するライブラリクラスについて、以下に説明します。
2.10.2. モデムと通信するライブラリクラス
モデムと通信するライブラリクラスを3つ用意しています。
-
LTEクラス
-
LTEScannerクラス
-
LTEModemクラス
これらは、Arduino GSM ライブラリに類似した機能が用意されています。
2.10.2.1. モデムの状態
モデムと通信するライブラリクラスは、モデムの状態を管理しています。
モデムの状態について、表 15に示します。
状態 | 説明 |
---|---|
OFF |
モデムの電源がOFFの状態 |
IDLE |
モデムの電源をONにし、無線がOFFの状態 |
CONNECTING |
LTEネットワークにモデムを登録中の状態 |
SEARCHING |
無線をONにし、LTEネットワークの探索を実施している状態 |
READY |
LTEネットワークにモデムを登録し、IPアドレスが付与された状態 |
ERROR |
モデムがエラーの状態 |
クラスのメソッド呼び出し、もしくはLTEネットワークとの処理で状態が遷移します。
モデムの状態遷移図を図 11に示します。
モデム通信するライブラリクラスが提供する機能について、以下に説明します。
2.10.2.2. LTEクラス
LTEネットワークにモデムを登録し、モデムにIPアドレスを付与する機能を提供します。
- LTEネットワークを探索する
-
LTEネットワークにモデムを登録するためには、モデムとLTEネットワーク間で通信するための通信経路を構築する必要があります。
まずbegin()メソッドを使用してモデムの電源をONにし、LTEネットワークの探索を開始します。 begin()メソッドの定義は以下の通りです。
begin(
char* pinCode = NULL,
bool restart = true,
bool synchronous = true)
-
pinCodeはPINロック解除コードを示し、ご使用のSIMにPINロックをかけている場合、PINロック解除コードを文字列で指定してください。 (例: "1234" )
PINロックをかけていない場合、PINロック解除コードにNULL
を指定してください。
PINロックの解除に失敗した場合、モデムが |
-
restartは再起動フラグを示し、
true
の場合モデムの電源をOFFにしてから、モデムの電源をONにしてLTEネットワークの探索を開始します。false
の場合、モデムの電源をONにしてLTEネットワークの探索を開始します。 -
synchronousは同期フラグを示し、
false
の場合、begin()の処理を非同期実行します。
現在、非同期実行はサポートしておらず、 |
デフォルトでは、PINロック解除コードがなし、再起動フラグが true
、同期フラグを true
としています。
戻り値でモデムの状態を返します。LTEネットワークの探索を開始すると SEARCHING
状態を返します。
begin()メソッドに失敗した場合、戻り値で
|
- LTEネットワークにモデムを登録する
-
LTEネットワークの探索を開始したら、attach()メソッドを使用してLTEネットワークにモデムを登録し、モデムとLTEネットワーク間で通信するための通信経路を構築します。
ご使用の電波環境により、モデムの登録処理に数分かかる事があります。 |
attach()メソッドの定義は以下の通りです。
attach(
char *apn,
char *userName = NULL,
char* password = NULL,
LTENetworkAuthType authType = LTE_NET_AUTHTYPE_CHAP,
LTENetworkIPType ipType = LTE_NET_IPTYPE_V4V6,
bool synchronous = true)
attach()メソッドに与えるパラメータはAPN(Access Point Name)とメソッドの振る舞いを決定するものです。 APNはLTEネットワークのデータ通信で必要になる接続先を指定します。 APNのパラメータについて、表 17に示します。
パラメータ | 説明 |
---|---|
apn |
アクセスポイント名 |
userName |
ユーザ名。デフォルト設定が |
password |
パスワード。デフォルト設定が |
authType |
認証タイプ。 |
ipType |
APNプロトコル。 |
APNのパラメータはご使用のSIMに合わせて、設定してください。 |
synchronousは同期フラグを示し、 true
の場合、LTEネットワークにモデムを登録すると、attach()メソッドを返します。
false
の場合、モデムの登録を開始すると、attach()メソッドを返します。
戻り値でモデムの状態を返します。
-
同期フラグが、
true
の場合、LTEネットワークにモデムの登録を登録するとREADY
状態を返します。 -
同期フラグが、
false
の場合、モデムの登録処理を開始するとCONNECTING
状態を返します。
モデムの登録が完了したことを確認するには、getStatus()メソッドでモデムの状態を確認します。LTEネットワークにモデムを登録するとREADY
状態を返します。
attach()メソッドに失敗した場合、戻り値で
|
- IPアドレスを取得する
-
getIPAddress()メソッドを使用してLTEネットワークがモデムに割り当てたIPアドレスが取得できます。
モデムの状態が |
- 時刻を取得する
-
getTime()メソッドを使用して紀元 (Epoch; 1970-01-01 00:00:00 (UTC)) からの秒数が取得できます。
モデムの状態が |
- LTEネットワークからモデムを切り離す
-
detach()メソッドを使用して、モデムをネットワークから切り離し、モデムに付与されたIPアドレスを解放することができます。
モデムの状態が |
- モデムの電源をOFFにする
-
shutdown()メソッドを使用して、モデムの電源をOFFにすることができます。
モデムの状態が |
2.10.2.3. LTEScannerクラス
モデムが受信している電波強度(RSSI)・通信に使用している事業者名を取得する機能を提供します。
- モデムが受信している電波強度(RSSI)を取得する
-
getSignalStrength()メソッドを使用して、モデムが受信している電波強度(RSSI)を取得することができます。 単位はdBmです。圏外の場合、取得する値が "N/A" となります。
本メソッドを使用するためには、LTEクラスを使用してモデムの状態を |
- モデムを登録したネットワーク事業者名を取得する
-
getCurrentCarrier()メソッドを使用して、モデムを登録したネットワーク事業者名を取得することができます。
本メソッドを使用するためには、LTEクラスを使用してモデムの状態を |
2.10.2.4. LTEModemクラス
モデムのファームウェアバージョン・国際移動体装置識別番号(IMEI)を取得する機能を提供します。
本クラスの機能を使用するためには、begin()メソッドを使用してモデムの状態を |
- モデムのファームウェアバージョンを取得する
-
getFirmwareVersion()メソッドを使用して、モデムのファームウェアバージョンを取得することができます。
- 国際移動体装置識別番号(IMEI)を取得する
-
getIMEI()メソッドを使用して、国際移動体装置識別番号(IMEI)を取得することができます。
2.10.3. クライアントインターフェースライブラリクラス
クライアントインターフェースライブラリクラスを3つ用意しています。
-
LTEClient
-
LTETLSClient
-
LTEUDP
LTEライブラリはEthernetライブラリやWiFiライブラリと可能な限り互換性を保って提供しています。
Arduino EthernetやArduino WiFiライブラリのプログラムを移植することが容易にできるでしょう。
Ethernet互換のコードをそのまま実行することはできませんが、LTEネットワークに登録する処理など、
LTEライブラリ固有のマイナーな修正で実行することができるようになります。
クライアントインターフェースライブラリクラスが提供する機能について、以下に説明します。
2.10.3.1. LTEClientクラス
TCPプロトコルを使用したクライアント通信機能を提供します。
Arduino Client インターフェースを実現しています。
LTEClientクラスを使用するためには、LTEクラスを使用してモデムの状態を |
メソッド の詳細は、API リファレンスマニュアル LTE Client API を参照してください。
2.10.3.2. LTETLSClientクラス
TLSプロトコルを使用したクライアント通信機能を提供します。
Arduino Client インターフェースを実現しています。
LTEClientクラスを使用するためには、LTEクラスを使用してモデムの状態を |
メソッド の詳細は、API リファレンスマニュアル LTE TLS Client API を参照してください。
- 証明書の設定
-
TLSプロトコルで使用するルート証明書・クライアント証明書・秘密鍵の設定方法について説明します。
設定方法を3種類用意しています。 ご使用環境に合わせて適時選択してください。 +-
microSDカード等に証明書・秘密鍵のファイルをおいて、本クラスのメソッドを使用して設定する方法です。
microSDカードを使用した例を TLSプロトコルを使用したHTTP Clientの動作を確認する で解説しています。 -
プログラムにPEM形式の配列を生成して、本クラスのメソッドを使用して設定する方法です。
-
プログラムにDER形式の配列を生成して、本クラスのメソッドを使用して設定する方法です。
-
2.10.3.3. LTEUDPクラス
UDPプロトコルを使用したクライアント通信機能を提供します。
Arduino UDP インターフェースを実現しています。
LTEClientクラスを使用するためには、LTEクラスを使用してモデムの状態を |
メソッド の詳細は、API リファレンスマニュアル LTE UDP API を参照してください。
2.10.4. サンプルコードによる解説
実際に、Spresense Arduino Packageに含まれるLTEのサンプルコードを用いて、 Spresense LTEの使い方をチュートリアルで解説しています。
詳しくは、LTE チュートリアル を参照してください。
さあ、Spresense LTEを使って、オリジナルIoTデバイスを作ってみましょう。
2.11. MultiCore MP ライブラリ
2.11.1. 概要
MultiCore MP ライブラリ (以下、MP ライブラリ) は Arduino 環境でマルチコアプログラミングをサポートするためのライブラリです。デフォルトで起動される CPU コアを MainCore
、そして MainCore
から起動される CPU コアを SubCore
と呼びます。SubCore 1
から SubCore 5
まで全部で 5 個の SubCore
があります。
MainCore
, SubCore 1~5
の選択は、Arduino IDE メニューの Tools → Core
(ツール → Core
)で選択します。それぞれのコアでプログラミングして、コアごとにコンパイルされたバイナリを Spresense 基板にロードして動かします。MP ライブラリを用いることで各コアのプログラムを協調して動作させることができるようになります。
2.11.2. 機能
MP ライブラリは、主に以下の機能を提供します。
-
SubCore の起動/終了制御
-
コア間通信機能
-
コア間排他制御機能
-
共有メモリの獲得/解放
-
排他機能付きログ出力機能
各種APIの詳細は、APIリファレンスマニュアル MP Library API を参照してください。
2.11.2.1. MPクラス
MP.h を include することで MP
という名前のオブジェクトが生成されます。
#include <MP.h>
MP クラスが提供する関数一覧を以下に示します。
一部、MainCore
と SubCore
で機能が異なる関数や、 SubCore
ではサポートされていない関数もあります(*
: サポート, -
: 非サポート)
Function | Description | MainCore | SubCore |
---|---|---|---|
MP.begin() |
マルチコアの起動に関する制御を行います。 |
* |
* |
MP.end() |
マルチコアの停止に関する制御を行います。 |
* |
* |
MP.Send() |
指定したコアへデータを送信します。 |
* |
* |
MP.Recv() |
指定したコアからデータを受信します。 |
* |
* |
MP.RecvTimeout() |
Recv() 受信時のモードやタイムアウト値を設定します。 |
* |
* |
MP.GetRecvTimeout() |
RecvTimeout() で設定した値を取得します。 |
* |
* |
MP.Virt2Phys() |
引数で指定された仮想アドレスを物理アドレスに変換します。物理アドレスマップはすべてのコアで共通です。一方、仮想アドレスは各コアごとに異なります。SubCore は仮想アドレス上で動作するため、異なるコアにアドレスを送信する場合は、この関数を用いて物理アドレスへ変換してください。 |
* |
* |
MP.GetMemoryInfo() |
アプリケーションメモリの空き状況を取得します。 |
* |
* |
MP.EnableConsole() |
シリアルモニタ (Serial) からの入力を許可します。 |
* |
* |
MP.DisableConsole() |
シリアルモニタ (Serial) からの入力を禁止します。 |
* |
* |
MP.AllocSharedMemory() |
共有メモリを確保し、先頭の物理アドレスを返します。共有メモリの確保と解放は 128 KByte 単位です。引数に指定したサイズから 128 Kbyte アライメントされたメモリを確保します。メモリ不足により確保できなかった場合は、NULL が返ります。 |
* |
- |
MP.FreeSharedMemory() |
AllocSharedMemory() で確保したアドレスを渡して、共有メモリを解放します。 |
* |
- |
2.11.2.2. MPMutex クラス
マルチコア間で排他制御を行うための機能です。 MP_MUTEX_ID 番号(0~10) を引数に指定して、mutex オブジェクトを生成します。
#include <MPMutex.h>
MPMutex mutex(MP_MUTEX_ID0);
MPMutex が提供する関数を以下に示します。
Function | Description | MainCore | SubCore |
---|---|---|---|
mutex.Trylock() |
ロックを獲得します。獲得できた場合は 0, 失敗した場合は非 0 の値が返ります。 |
* |
* |
mutex.Unlock() |
Trylock() で獲得した mutex をアンロックで解放します。 |
* |
* |
2.11.2.3. MPLog() 関数
マルチコア環境でログ出力を行うための関数です。
Function | Description | MainCore | SubCore |
---|---|---|---|
MPLog() |
コア間で排他制御されたログ出力を行うための関数マクロです。引数は一般的な printf() と同じ書式を使うことができます。 |
* |
* |
2.11.2.4. アプリケーション用メモリ
アプリケーション用の SRAM メモリは、全部で 1.5 MByte (= 1536 KByte) です。 ハードウェア内部では 128 KByte x 12 個のメモリタイルに分かれて構成されています。 各 CPU と SRAM との間は、メモリタイル単位でバスマトリックス状に接続されています。 あるタイルへアクセスする CPU が一つだった場合は、waitサイクル無しで SRAM を読み書きできます。 (これは CPU アーキテクチャでよく聞かれる Cache と同等のパフォーマンスを意味します)。 一方、同一メモリタイルへ複数の CPU からアクセスが発生した場合、 メモリへのアクセス速度が低下します。
このアクセス競合を防ぐために、基本的に SubCore を動かす際は、 専用のメモリタイルを確保して SubCore プログラムはそのメモリタイル上で動作します。
Arduino 環境における SRAM 1.5 MByte の内訳を次に示します。
MainCore は先頭の 6 タイル (768 KByte) を固定的に使用します。 残りの 6 タイル (768 KByte) を SubCore やその他のライブラリ等で共有して使用します。
上の図では、SubCore1 に 256 KByte, SubCore2 に 128 Kbyte のメモリを割り当てた例です。
SubCore は、割り当てられた物理メモリを 0 番地から始まる仮想アドレスにマップして動作します。
CPU 間通信等で共通のアドレスを参照する必要があれば、MP.Virt2Phys()
で物理アドレスへ変換してください。
また、MainCore 使用領域を除く後半 768 KByte の共有メモリは、SubCore 以外にも各種ライブラリから使用されることがあります。 各ライブラリ、及び、そのユースケースごとの使用メモリサイズを以下に示します。
Library | UseCase | Used Memory Size |
---|---|---|
Audio, Sensing |
初期化時における各種バッファ用 |
256 KByte |
Audio |
MP3 再生時における |
128 KByte |
Audio |
MP3 録音時における |
256 KByte |
Audio |
WAV 再生時における |
256 KByte |
Audio |
WAV 録音時における |
128 KByte |
DNNRT |
初期化時における |
128 KByte |
SubCore に必要なメモリサイズは、ユーザーアプリケーションに依存します。 スケッチをコンパイルした際に、コンパイル結果表示のウィンドウに以下のようなログが出力されます。この値が、その SubCore を動作させるのに必要なメモリサイズを表します。
アプリケーションの組み合わせによっては、メモリ不足で動作させることができないかもしれません。
MP.GetMemoryInfo()
を使って、メモリの使用状況/空き状況を確認することができます。
サンプルコードを以下に示します。
{
int usedMem, freeMem, largestFreeMem;
MP.GetMemoryInfo(usedMem, freeMem, largestFreeMem);
MPLog("Used:%4d [KB] / Free:%4d [KB] (Largest:%4d [KB])\n",
usedMem / 1024, freeMem / 1024, largestFreeMem / 1024);
}
2.11.2.5. SubCore 起動方法
引数に起動したい SubCore 番号(1 ~ 5) を入れてMainCore から MP.begin(1~5)
を呼び出します。
起動された SubCore 側では、同様に MP.begin()
を引数無しで呼び出しすことで、起動完了通知を行います。
2.11.2.6. SubCore 終了方法
引数に終了させたい SubCore 番号(1 ~ 5) を入れて MainCore から MP.end(1~5)
を呼び出します。
指定された SubCore は動作を終了してシャットダウンします。
2.11.2.7. コア間通信方法
MP.Send()
, MP.Recv()
関数を使用して任意のデータを送受信することができます。
受信の待ち方には 3 つのモードがあり、MP.RecvTimeout()
によりモードを設定します。
デフォルトは、MP_RECV_BLOCKING が設定されています。
-
MP_RECV_BLOCKING (0): データを受信するまで永久に受信待ちに入るモードです。(デフォルト)
-
MP_RECV_POLLING (0xffffffff): データの受信をポーリングするモードです。Recv() を呼び出したときに受信データが無かった場合はすぐに抜けます。このモードでは受信待ちに入ることはありません。
-
時間 (上記以外): 待ちのタイムアウト時間 (ミリ秒) を設定します。Recv() を呼び出したときに指定された時間だけ待ち、受信データが来ない場合はタイムアウトで抜けます。
MP.Send()
, MP.Receive()
の通信方式には、データを渡す方法とアドレスを渡す方法の 2 種類が用意されています。
-
データ送受信
-
書式
int MP.Send(int8_t msgid, uint32_t msgdata, int subid)
int MP.Recv(int8_t *msgid, uint32_t *msgdata, int subid)
-
引数
msgid
: ユーザ側で0を含む正値の Message ID (8 bit 符号付きデータ)を定義することができます。負値を使用することはできません。
msgdata
: ユーザー側で任意の Message Data (32 bit データ) を定義することができます。
subid
: メッセージをやり取りする SubCore 番号を指定します。省略した場合は、MainCore と通信します。 -
戻り値
Send() が成功した場合は 0、エラーの場合は 0 以外の値が返ってきます。
Recv() が成功した場合はmsgid
、エラーの場合は負値が返ってきます。 -
説明
Message ID, Message Data ともに、Send() で送信した ID と Data がそのまま Recv() 側で受信できます。
Send() は非同期で送信が行われます。内部で 8 段の送信バッファをもっており、送信データをバッファに積んだ時点で Send() 関数はすぐに成功 0 を返します。もし、受信側のコアがデータを引き取る前にこの送信バッファがフル状態になると、Send() 関数は -EAGAIN(-11) のエラーを返します。
一方、受信側も 8 段の受信バッファをもっています。Recv() が呼ばれずにこの受信バッファがフルになった場合、システムは異常状態であると判断してプログラムは assert します。この assert が発生した場合、受信側のコアが正しく動作していない、または、通信の負荷が高すぎるといった可能性が考えられます。
-
-
アドレス送受信
-
書式
int Send(int8_t msgid, void *msgaddr, int subid)
int Recv(int8_t *msgid, void *msgaddr, int subid)
-
引数
msgid
: ユーザ側で0を含む正値の Message ID (8 bit 符号付きデータ)を定義することができます。負値を使用することはできません。
msgaddr
: ユーザー側で任意の Message Address (ポインタ) を定義することができます。
subid
: メッセージをやり取りする SubCore 番号を指定します。省略した場合は、MainCore と通信します。 -
戻り値
Send() が成功した場合は 0、エラーの場合は 0 以外の値が返ってきます。
Recv() が成功した場合はmsgid
、エラーの場合は負値が返ってきます。 -
説明
Message ID, Message Address ともに、Send() で送信した ID と Address がそのまま Recv() 側で受信できます。 実際に通信したいデータは別のメモリにあって、そのデータのポインタアドレスのみを送信するようなケースで使用します。
SubCore からアドレスを送信する場合に、仮想アドレスから物理アドレスへの変換が必要ですが、msgaddr については、 Send() 関数の内部でアドレス変換を行っています。もし、msgaddr ポインタの指し示す先にもアドレス情報があり、 コアを跨いでそのアドレスを参照する場合は、ユーザー側でアドレス変換を行ってください。
Send() が非同期であることはデータ送受信のときと同様です。Send() 関数は、実際に相手がメッセージを受信したかどうかに 関係なく return で返ってきます。そのため、Send() した直後にポインタが指し示す先のデータを書き換えてしまうと、 受信側で受け取るデータについて保証ができなくなります。同期を取るための Acknowledge のような通信を別途 Send()/Recv() で実現するか、 もしくは、データパケットの中にデータを保証するためのフラグを追加する、といった工夫が必要になります。
-
Send()/Recv() 機能の具体的な使い方は、サンプルコード の Message
を参照してください。
- Message/MessageData
-
データ渡しについてのサンプルコード
- Message/MessageHello
-
アドレス渡しについてのサンプルコード
2.11.2.8. SubCore から使用可能なライブラリ
Arduino 標準コアライブラリは SubCore からも使用可能です。
Spresense 特有のライブラリのいくつかは SubCore から使用することはできません。 もし組み込んだ場合にコンパイル時に以下のエラーメッセージが出力されます。
XXX library is NOT supported by SubCore.
SubCore から使用可能なライブラリを以下に示します。
Library | MainCore | SubCore | Description |
---|---|---|---|
MP |
〇 |
〇 |
|
RTC |
〇 |
〇 |
Alarm 機能は SubCore では使用できません。 |
SPI |
〇 |
〇 |
|
Servo |
〇 |
〇 |
|
SoftwareSerial |
〇 |
〇 |
|
Watchdog |
〇 |
〇 |
|
Wire |
〇 |
〇 |
|
Audio |
〇 |
- |
|
Camera |
〇 |
- |
|
DNNRT |
〇 |
- |
|
GNSS |
〇 |
- |
|
LowPower |
〇 |
- |
|
LTE |
〇 |
- |
|
Sensing |
〇 |
- |
|
Storage (EEPROM, eMMC, File, Flash, SDHCI) |
〇 |
- |
2.11.2.9. SubCore プログラミングTIPS
SubCore プログラムのヒープサイズを増やす方法
SubCore で必要なメモリサイズはコンパイル時に自動的に決定されますが、詳細なロジックを説明します。
.stack
までのサイズはコンパイル時に静的に決定されますが、.heap
のサイズはプログラムに依存します。
ヒープメモリとして最低 32 KByte 分が確保されており、 最終的にリンクする際に、全体のメモリを 128 KByte に
アライメントされた上限までをヒープメモリとして割り当てます。
上記のルールによって、最低 32 KByte 分のヒープ領域が確保されています。 ただし、ユーザープログラムによっては、ヒープ領域が不足するかもしれません。 ヒープ領域を拡張したい場合は、ユーザースケッチ上で次のように USER_HEAP_SIZE() マクロを使用することで そのサイズを拡張することができます。
USER_HEAP_SIZE(64 * 1024);
このように 64 KByte を指定すると、必ず 64 KByte 以上のヒープメモリが確保されます。
SubCore 番号を識別するためのコンパイルオプションについて
SubCore をビルドする際には、コンパイルオプションとして -DSUBCORE=コア番号が指定されています。 共通ソースコードを使用して、コアごとに ifdef によってコードを分けたい場合は以下を参考にしてください。
#if (SUBCORE == 1)
// SubCore1 ビルド
#elif (SUBCORE == 2)
// SubCore2 ビルド
#elif (SUBCORE == 3)
// SubCore3 ビルド
#elif (SUBCORE == 4)
// SubCore4 ビルド
#elif (SUBCORE == 5)
// SubCore5 ビルド
#else
// MainCore ビルド
#endif
これを応用して、ユーザーのスケッチに以下のような記述を追加することで、 間違ったコアが選択されてビルドやアップロードしてしまうことを防止することができます。
-
MainCore のスケッチに、SubCore が指定されていた場合にビルドエラーにする
#ifdef SUBCORE
#error "Core selection is wrong!!"
#endif
-
SubCore のスケッチに、MainCore が指定されていた場合にビルドエラーにする
#ifndef SUBCORE
#error "Core selection is wrong!!"
#endif
-
SubCore1 のスケッチに、SubCore1 以外のコアが指定されていた場合にビルドエラーにする
#if (SUBCORE != 1)
#error "Core selection is wrong!!"
#endif
スケッチディレクトリ構成について
MainCore, SubCore とで共通のヘッダファイルを参照したい場合があると思います。
一つの案として、例えば、次のようなディレクトリ構成にすることによって、 共通の common.h ヘッダファイルを include することができます。
SubSketch.ino の中で、
#include "common.h"
MainSketch.ino の中で、
#include "SubSketch/common.h"
別案として、Arduino 環境の libraries ライブラリの置き場所に共通のヘッダファイルを置くという方法もあります。
libraries 配下にヘッダファイルがあればどのスケッチからも参照することが可能です。
libraries 以下にヘッダファイルを置くには Arduino IDE メニューの Sketch → Include Library → Add .ZIP Library…
(スケッチ → ライブラリをインクルード → .ZIP形式のライブラリをインストール…
)
からヘッダファイルを含むフォルダの場所を指定することによって libraries へ追加することができます。
2.11.3. サンプル
MP ライブラリの基本的な使い方は、examples にあるサンプルスケッチを参照してください。
サンプルスケッチは、Arduino IDE メニューの
File → Examples → Examples for Spresense → MultiCore MP
(ファイル → スケッチ例 → Spresense用のスケッチ例 → MultiCore MP
)にあります。
Example | Description |
---|---|
Boot |
4 つのSubCore を起動するサンプルです。起動された SubCore はそれぞれ別の LED を制御し、マルチコアを使って L チカします。 |
Message/MessageData |
MainCore と SubCore 間でデータの通信を行うサンプルです。 |
Message/MessageHello |
MainCore と SubCore 間でアドレスの通信を行うサンプルです。 |
Mutex |
ハードウェアセマフォ MPMutex の機能を用いて、MainCore, SubCore 間で排他制御を行います。 |
SharedMemory |
MainCore から共有メモリを確保/解放するサンプルです。 |
Shell |
MainCore から起動された SubCore 側でシェルを動作するサンプルです。 |
AudioFFT |
SubCore を使った応用アプリケーションのサンプルです。MainCore で Audio ライブラリを使ってPCM 4chデータをキャプチャし SubCore へ渡します。SubCore はリアルタイムに FFT (Fast Fourier Transform) 解析をかけてピーク周波数を表示します。Arduino IDEのシリアルプロッタを使って時系列データとしてグラフ化して表示することができます。 |
2.12. RTC ライブラリ
RTC (Real-Time Clock) ライブラリは、Spresense の RTC 絶対時刻を管理します。 Spresense がもつ RTC ハードウェアは 初期値 0 からはじまる単調増加カウンタです。 RTC は UNIX 時刻で管理されるため、初期値 0 は 1970年1月1日午前0時0分0秒を表します。 Deep Sleep や Cold Sleep といったスリープ期間中も時刻を保持し続けることができます。 ただし、電源がオフされると、RTC カウンタはリセットされ初期値 0 に戻ります。
RTCライブラリを使用する場合は、初めに必ずRTC.begin()を呼び出してください。 電源が供給されてから、RTC XTALが安定して発振するまでに約2秒かかります。 RTC.begin() の中で、この発振安定待ちを行いますので、 RTC.begin() の呼び出しから戻ってきた後で、RTC 機能を安全に使用することができます。 |
RTC ライブラリは、以下の機能を提供しています。 各種 API の詳細は、API リファレンスマニュアル RTC Library API を参照してください。
-
RTC.setTime() 絶対時刻を設定
-
RTC.getTime() 絶対時刻を取得
-
RTC.attachAlarm() アラームハンドラを登録
-
RTC.detachAlarm() アラームハンドラを解除
-
RTC.setAlarm() アラーム時刻を設定
-
RTC.setAlarmSeconds() 指定時間(秒数)の相対時刻アラームを設定
-
RTC.cancelAlarm() アラーム設定をキャンセル
RTC ライブラリの基本的な使い方は、examples にあるサンプルスケッチをご覧ください。
サンプルスケッチは、Arduino IDE メニューの
ファイル → スケッチ例 → Spresense 用のスケッチ例 RTC
から開くことができます。
その他、RTC ライブラリとは別に #include <time.h> をインクルードすることで、 strftime() や clock_gettime(CLOCK_REALTIME, tp) のような POSIX 標準の API もサポートされています。
詳細はNuttX User’s Manualを参照してください。 なお、NuttX Configurationにて Local time 機能は無効化されているため、localtime() はサポートされておりません。
2.13. SDHCI ライブラリ
2.13.1. 概要
SDHCI ライブラリは Spresense 拡張ボードにある micro SD にアクセスするためのライブラリです。
SDHCI ライブラリは、Arduino SD ライブラリ に類似した API 構成となっており、SD ライブラリを用いた既存のスケッチから簡単に移植することができます。
SPI インターフェースを用いた SD ライブラリとは異なり、SD Host Controller Interface の専用ハードウェアを用いて、SD カードへアクセスするため、次のような特徴をもちます。
-
SD カードは専用端子で接続されるため、SPI 端子を必要としません。SPI 端子を他の用途で使用することができます。
-
SPI 通信と比べて非常に高速です。SDR25 転送モードまでサポートしています。
また、特徴的な機能として、USB MSC (Mass Storage Class) 機能を提供します。 Spresense 拡張ボードにある USB と PC を接続することで、PC から SD カード上のファイルに直接アクセスすることができます。
RTC ライブラリ により 1980/1/1 以降の現在時刻が設定されている場合、ファイルやディレクトリの作成日時や更新日時など、RTC 時刻をもとにしたタイムスタンプがファイルシステム内に記録されます。 |
2.13.2. 機能
各種APIの詳細は、APIリファレンスマニュアル SD card Library API を参照してください。
SDHCI ライブラリ内では、SDClass のインスタンスを生成していないため、スケッチ内で次のように定義してください。
#include <SDHCI.h>
SDClass SD;
Function | Description |
---|---|
SD.begin() |
SD カードがマウントされているかどうかを確認します。この関数が true で返ってきてマウント済みであることを確認した後にその他の API を使用してください。 |
SD.beginUsbMsc() |
USB MSC (Mass Storage Class) 機能を開始します。 |
SD.endUsbMsc() |
USB MSC (Mass Storage Class) 機能を終了します。 |
SD.format() |
SD デバイスをフォーマットします。デフォルト FAT32 ファイルシステムでフォーマットします。 |
SD.open() |
ファイル名を指定して SD デバイス内のファイルをオープンします。 |
SD.exists() |
SD デバイス内にファイルが存在するかどうかを確認します。 |
SD.mkdir() |
SD デバイス内にディレクトリを作成します。 |
SD.rmdir() |
SD デバイス内にディレクトリを削除します。 |
SD.remove() |
SD デバイス内のファイルを削除します。 |
2.13.3. サンプル
SDHCI ライブラリには、3 つのスケッチのサンプルが提供されています。 SD カードは、FAT32 でフォーマット済みの状態で使用してください。
Example | Description |
---|---|
SD カード上のファイルを読み書きするサンプルです。 |
|
USB MSC 機能のサンプルです。Spresense 拡張ボードの SD カードが PC 上のドライブとしてマウントされ、PC から SD カードに直接アクセスすることができます。 |
|
USB MSC 機能とファイル操作を組み合わせた複合アプリケーションです。SD カード内のファイルに対して、スケッチからのファイル操作と、USB MSC による PC からのファイル操作は、排他的に動作させる必要があります。このサンプルでは、アプリケーションプログラムからファイル一覧を取得・表示した後に、USB MSC 機能を有効にし、PC から SD カード内のファイルを操作できるようになります。USB MSC 機能を終了した後に、再びプログラム中からファイル一覧を取得・表示します。 |
2.14. Sensing ライブラリ
Spresense はLow Powerで常時Sensingを行う機能と、Edgeコンピューティングができるパフォーマンスを有しています。また、各種センサデータを組み合わせつつ信号処理・AI処理などを施すことによって、データ量の少ない抽象的なデータに変換することができます。この一連の処理をセンサ(論理センサと呼びます)として作成することができます。
Sensingライブラリは、このような論理センサを使用・作成するためのフレームワークを提供します。
論理センサは、Spresense の持つ特徴であるMulti Coreを利用し、別のコア(以降、それらのコアをDSP と呼びます)で信号・認識処理をさせることも可能です。
- Sensing ライブラリの主な特徴
-
-
Publish-Subscribe Architectureに基づき、複数のSensorのフュージョンが実行・変更が容易です。
-
Arduinoが供給するエコシステムで作成されたセンサドライバを用いてセンシングしたデータを、作成された論理センサにpublishし、Arduinoのアプリケーションがsubscribeすることで、Spresense SDKと同様の機能がArduino上から使用できます。
-
Arduinoライブラリは、基本的には、Spresense SDKの有する機能・APIのArduino向けラッパライブラリになっています。 詳細情報に関しては、SDK側 を参照してください。 |
2.14.1. アーキテクチャとデータフロー
まず、SpresenseでのSensor Frameworkを示します。
こちらに関しては Sensor Fusion Framework を参照してください。
次に、Arduino向けSensingライブラリのアーキテクチャを示します。
Spresense SDK で提供しているSensor Framework部分を "Sensing" ライブラリとして提供することで、SDKと同等の機能を実現します。
Arduinoで開発する方は、センサのドライバ、センサを使用したアプリケーション、および、より抽象度の高い論理センサの信号処理部分などを作成することで、所望のセンサーフュージョンを行ったアプリケーションを作成できます。
- Sensing ライブラリのクラス
-
-
SensorManagerClass:
SDK内部にある各センサクライアントを管理するクラス(Sensor Manager)のラッパクラスです。 -
SensorClient:
各センサの要素であるSensorClientのベースクラス。ユーザは、直接このクラスを呼ぶことはありません。
また、独自の論理センサを作成する場合は、このクラスを継承してください。-
AccelSensorClass:
加速度センサの物理センサクライアント、Arduinoでのセンサのドライバから取得したセンサデータをPublishすることで各センサクライアントが加速度データを利用できます。 -
ApplicationSensorClass:
アプリケーションがセンサデータをsubsribeするためのセンサクライアントです。-
StepCountReaderClass:
アプリケーションの中で、ステップカウンタセンサのデータを読み出すためのセンサクライアントです。ApplicationSensorClassを継承して作成しています。
-
-
AesmClass:
Spresense SDK が提供する歩数計アルゴリズム(AESM: Activity Engine and StepMeter) が実装されている論理センサクライアントです。 加速度センサを使用します。
SDK提供の論理センサのため、Arduinoからのpublish/Subscribe処理は不要です。
-
-
2.14.2. 各クラスのAPIリファレンス
以下に、各クラスのAPIリファレンスを示します。
2.14.2.4. ApplicationSensorClass
アプリケーションセンサは、センサデータをアプリケーションに受け渡すためのセンサクライアントです。そのため、subscribeしか実装されません。
2.14.3. サンプルスケッチについて
2.14.3.1. Step Counterサンプル
今回、Sensingに関しては、Sonyが提供するStepCounterを使用するサンプルを提供しています。
このサンプルでは、v1.3.0以降のブートローダへの更新が必要です。 |
Spresense SDKでの、Step Counter機能は、以下で構成されています。
こちらに関しては、Sensor Fusion Framework を参照してください。
Arduino向け、Sensingライブラリのでは、以下の図に示す部分が、ライブラリとして提供されています。
サンプルスケッチとしては、加速度センサを読みだしフレームワークに供給する部分と、生成されたStepCounterデータを読み出す部分の実装を行うことで、実現が可能です。
以下が、シーケンスになります。
このように、実装することで、StepCounterデータが取得できます。
使い方の詳細に関しては、チュートリアル を参照してください。
2.15. Servo ライブラリ
Servo ライブラリは、Spresense に RCサーボを制御する機能を提供します。
Servo ライブラリは、Arduino で定義されているArduino Servo ライブラリ と同様に扱うことができます。
Spresense は4つの PWM をサポートしており、これらを使って RC サーボを制御することができます。
-
D06 PWM0
-
D05 PWM1
-
D09 PWM2
-
D03 PWM3
多くのサーボは 5V電源を要求し、また多くの電力を要求します。そのため、Spresense 拡張ボードから供給すると、モーターの回転に多くの電力を消費し、本体に電源が十分に供給されない可能性があります。そのため、モーターへの電源は外部電源で供給することを検討してください。
また、Spresense拡張ボードは、IOREFジャンパーで 3.3V もしくは 5V を選択できることも注意してください。ただ、多くのRCサーボは、3.3V も 5V も受け付けることができますが、仕様をよく確認する必要があります。
2.16. SignalProcessing ライブラリ
Spresense SignalProcessing ライブラリは、センシング、音声処理などを行う上での基本的な信号処理を行うためのライブラリです。
SignalProcessing ライブラリの主な特徴
-
マルチチャンネルFFT処理を行います。
-
双二次IIRフィルタ処理を行います。
Input Data
-
チャンネルごとにインタリーブされたマルチチャンネルデータを入力します。
Out Data
-
FFT:各チャネルごとのFFT結果が出力されます。
-
IIR:信号処理後のインタリーブされたマルチチャンネルデータが出力されます。
各信号処理はメモリリソース・処理時間などを鑑みて、16bit精度相当のみ対応としています。 |
2.16.1. ライブラリの構造について
SignalProcessing ライブラリは3つのオブジェクトで構成されています。
-
FFTClass
FFT処理を行うオブジェクト -
IIRClass
IIRフィルタ処理を行うオブジェクト -
RingBuff
マルチチャンネルの入力データを格納するリングバッファ
(ユーザは意識する必要はありません。)
各オブジェクトでのデータフローは以下の様な構成になります。
-
FFT
-
IIR
入力データは、FFT/IIRのクラスのIFを通して、RingBuffクラス
に格納されます。
取り出し要求を受けた際に、各信号処理を行いながらデータを出力します。
2.16.2. 入力・出力のマルチチャネルデータについて
マルチチャネルの入力/出力データは以下のようなインタリープされたデータ形式をとるようにします。
-
16bitの場合
-
24bitの場合
24bitの場合、32ビットでalignし、下位24ビットにデータを格納してください。 |
2.16.3. FFTライブラリ詳細
以下のパラメータはインスタンスごとに静的に指定(コンパイル時指定)します。
-
最大のチャンネル数
確保すべき最大チャンネル数ぶんのメモリリソース確保を行います。 実際に実行するデータのチャンネル数はこれ以下であれば同じである必要はありません。 -
FFTのTap数
実行するFFTのTAP数を指定します。指定できるTAP数は以下になります。
32 / 64 / 128 / 256 / 512 / 1024 / 2048 / 4096
最大チャンネルおよびTap数を大きくするとメモリリソースを大きく使用しますので目的に合わせた設定を行ってください。 |
Tap数はtemplate変数によるコンパイル時の指定なので、実行時にTap数を変えたい場合は、Tap数の異なるインスタンスを生成して使用してください。 |
以下のパラメータはbeginを介してパラメータの変更が可能です。
-
窓関数
FFTに掛ける窓関数を指定します。窓関数は以下のみサポートしています。-
矩形窓
-
ハニング窓
-
ハミング窓
-
フラットトップ窓
-
-
オーバーラップサイズ
窓関数などをかけてFFTを行う際に、入力データをオーバーラップして実施することができます。そのオーバーラップするサンプル数を指定します。
0からFFTのTAP数の1/2サイズまで指定することが可能です。
2.16.4. IIRライブラリ詳細
以下のパラメータはインスタンスごとに静的に指定(コンパイル時指定)します。
-
最大のチャンネル数(
MAX_CHANNEL_NUM
)
確保すべき最大チャンネル数ぶんのメモリリソース確保を行います。 実際に実行するデータのチャンネル数はこれ以下であれば同じである必要はありません。 -
ビット長(
BITLEN
)
入力データのビット長になります。現在は、16ビットのみ対応です。 -
最小フレームサンプル数(
MIN_FRAMESIZE
)
最小のフレームサイズになります。240を指定しています。 NOTE: この値を変更するとオーディオのリアルタイム処理が間に合わなくなります。 -
入力バッファサイズ(
INPUT_BUFFER_SIZE
)
ライブラリへの入力用のリングバッファのサイズを指定します。 出力のフレームサイズの倍数を指定しています。 現在は、フレームサイズの4倍になっています。 NOTE: サイズを増やすと動作のロバスト性が向上しますが、メモリを消費します。
以下のパラメータをbeginを介してパラメータの変更が可能です。
-
フィルタモード
IIRによってどのようなフィルタを実現するかを指定します。以下のモードを設定できます。-
HPF(ハイパスフィルタ)
-
LPF(ローパスフィルタ)
-
BPF(バンドパスフィルタ)
-
BEF(バンドエリミネーションフィルタ)
-
-
カットオフ周波数(HFP/BPF)/ 中心周波数(BPF/BEF)
フィルタのカットオフ周波数または、中心周波数を指定します。 -
Q値
フィルタのQ値を指定します。 -
フレームサイズ
IIR処理の1回の実行サンプル数を指定します。小さくすると処理までの遅延が減りますが、オーバーヘッドが増えてしまいます。 デフォルト値は768サンプルになります。 -
チャンネルマッピングモード
フィルタ結果のチャンネルマッピングのモードを指定します。以下のどちらかが選択できます。-
Interleave (チャンネルインターリーブ出力)
-
Planar (チャンネルごとの出力)
-
-
サンプリングレート
入力データのサンプリングレートを指定します。 デフォルト値は48000Hzになります。
2.16.5. 動かし方(シーケンス)について
2.16.5.1. FFTのシーケンスについて
IIRライブラリのシーケンスは以下になります。
-
begin
で指定可能なパラメータは上記を参照してください。 -
put
での入力サンプル数は、FFTのTap数と同じである必要はありません。 -
get
実行時に充分な入力データ(FFTのTap数以上の入力データ)が揃っている場合、信号処理結果が取得できます。
信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(FFTの場合は、Tap数からオーバーラップするサンプルを引いたもの)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。
オーバーラップするサンプルに関わらずTAP数分のデータが戻ります。 -
end
で各種リソースが解放されます。
入力バッファは、出力フレームの4フレーム分バッファされます。バッファサイズを超えて入力してしまうと古いデータから上書きしてしまいます。入力バッファは溢れないようにご注意ください。 |
2.16.5.2. IIRのシーケンスについて
IIRライブラリのシーケンスは以下になります。
出力フォーマットが Planar
でのシーケンス
1 |
begin で指定可能なパラメータは上記を参照してください。
出力フォーマットを Planar にしたい場合は、 begin で出力フォーマットを指定しないか、出力フォーマットを Planar に指定した場合する必要があります。 |
||
2 |
put での入力サンプル数は、IIRライブラリで指定したフレームサイズと同じである必要はありません。 |
||
3 |
get 実行時に充分な入力データ(IIRのフレームサイズ以上の入力データ)が揃っている場合、信号処理結果が取得できます。信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(IIRのフレームサイズ)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。 begin で、出力フォーマットを Planar に指定した場合、get では、チャンネルごとにチャンネル番号を channel を指定して出力します。
|
||
4 |
end で各種リソースが解放されます。 |
出力フォーマットが Interleave
でのシーケンス
1 |
begin で指定可能なパラメータは上記を参照してください。
出力フォーマットを Interleave にしたい場合は、 begin で出力フォーマットを Interleave に指定した場合する必要があります。 |
||
2 |
put での入力サンプル数は、IIRライブラリで指定したフレームサイズと同じである必要はありません。 |
||
3 |
get 実行時に充分な入力データ(IIRのフレームサイズ以上の入力データ)が揃っている場合、信号処理結果が取得できます。信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(IIRのフレームサイズ)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。
|
||
4 |
end で各種リソースが解放されます。 |
2.16.6. API詳細について
各APIの詳細は、APIリファレンスを参照してください。
Signal Processing Libraries API
2.16.7. エラー情報について
begin
, put
, get
等のAPIでエラーが発生した際、そのエラーが何の要因で発生しているか?を getErrorCause
で取得することができます。
以下がエラーコードになります。
Error Code | Value | Description |
---|---|---|
ECODE_OK |
0 |
正常終了 |
ERR_CH_NUM |
-1 |
チャンネル数の指定エラー |
ERR_FORMAT |
-2 |
出力フォーマットの指定エラー |
ERR_MEMORY |
-3 |
メモリ確保失敗 |
ERR_FILTER_TYPE |
-4 |
フィルタタイプの指定エラー |
ERR_FRAME_SIZE |
-5 |
フレームサイズの指定エラー |
ERR_BUF_FULL |
-6 |
バッファの書き込み領域確保失敗 |
ERR_FS |
-7 |
サンプリングレート指定エラー |
get は、エラーの際には、戻り値にエラーコードが返ると同時に、getErrorCause でエラー要因を取得することもできます。
|
2.17. Software Serial ライブラリ
Spresense Arduino Library は、2つのシリアルポートを有しています。USBコネクタのデバッグシリアルは、 Serial
で、DO, D1 ピンは Serial2
に割り当てられています。
SoftwareSerial
ライブラリは Spresense のデジタル端子をシリアル端子として使うことができるようになります。
SoftwareSerial
ライブラリは Arduino の SoftwareSerial ライブラリと互換性があり、そのまま使うことができます。
SoftwareSerial(uint8_t receivePin, uint8_t transmitPin) を宣言する際の引数に受信端子、送信端子のピン番号を指定します。
ここで指定されたピンはどちらも GPIO モードへ切り替えて使用されます。GPIO モードへの切り替えはピングループ単位で行われます。
ピングループの詳細については、コネクタ ピンリスト (xlsx) を参照してください。
また、受信側のピン |
2.18. SPI ライブラリ
Spresense SPI ライブラリは Spresense に各種 SPI インターフェースを備えたスレーブデバイスを接続するための標準インターフェースを提供します。 Spresense SPI ライブラリは、Arduino SPI ライブラリ と互換性をもち同様に使うことができます。
Spresense ボードは、メインボードと拡張ボードのそれぞれに独立した SPI インターフェースを有しています。
各SPIインターフェースの端子を以下に示します。
SPI インスタンス名 | コネクタ | MOSI | MISO | SCK | SS | IO電圧 |
---|---|---|---|---|---|---|
SPI (or SPI4) |
拡張ボード |
D11 |
D12 |
D13 |
D10 |
3.3V or 5V (JP1ジャンパーにより切替) |
SPI5 |
メインボード |
D16 |
D17 |
D23 |
D24 |
1.8V |
SPI
というインスタンス名を使用した場合、拡張ボード上の SPI インターフェースが使われます。
メインボード上の SPI インターフェースを使う場合は、例えば、SPI5.beginTransaction()
のように、
インスタンス名を SPI5
に置き換えて使用してください。
2.18.1. 機能と制限
-
Spresense SPI ライブラリは 8bit ならびに 16bit データ長の転送をサポートしています
-
SPI SS は自動的に個々のトランザクションを開始するときに
LOW
に落ちます。トランザクションが終了するとHIGH
になります。これは高速転送のときに非常に便利な機能です。もし、この機能が検討しているアプリケーションにそぐわない場合は、他のデジタル端子を SS に割り当てて、digitalWrite()
関数でHIGH
/LOW
制御することを検討してください -
SPI_MODE ごとに SS の振る舞いが以下のように異なります(紫: SPI_CS_X 信号)。
SPI_MODE0
,SPI_MODE2
では転送ワードごとに SS がHIGH
に戻ります。一方、SPI_MODE1
,SPI_MODE3
では連続的にデータを送信している間は SS がLOW
になります。CPU で SPI 転送をしている場合、割り込み等によって転送が中断されるとHIGH
に戻ります。SPI_MODE0 SPI_MODE1 SPI_MODE2
SPI_MODE3
-
16 bit data は MSB first, Little Endian で転送されます
-
最大転送スピードについては、ハードウェアドキュメントを参照してください。
-
SPI ライブラリのサンプルについては、Arduino IDE から ファイル → スケッチ例 → Spresense 用のスケッチ例 → SPI を参照してください。
2.19. Storage ライブラリ
2.19.1. 概要
Storage ライブラリは SDHCI, SPI-Flash, eMMC など各種ストレージライブラリのベースクラスです。 基本的にはデバイスごとの SDHCI, Flash, eMMC ライブラリ経由で使用されますが、 マウントディレクトリを含む絶対パス名を指定することにより、Storage ライブラリを直接使用することも可能です。
参考までに、各種ストレージとマウントディレクトリ名の関係を以下に示します。
Device | Mount Path |
---|---|
SD card |
/mnt/sd0 |
Flash |
/mnt/spif |
eMMC |
/mnt/emmc |
2.19.2. 機能
各種APIの詳細は、APIリファレンスマニュアル Storage Library API を参照してください。
Function | Description |
---|---|
Storage.open() |
マウントディレクトリを含むファイル名を指定して Storage デバイス内のファイルをオープンします。 |
Storage.exists() |
Storage デバイス内にファイルが存在するかどうかを確認します。 |
Storage.mkdir() |
Storage デバイス内にディレクトリを作成します。 |
Storage.rmdir() |
Storage デバイス内にディレクトリを削除します。 |
Storage.remove() |
Storage デバイス内のファイルを削除します。 |
2.20. Watchdog ライブラリ
Spresense Watchdog ライブラリは Spresense の システム状態を監視し、異常時にHW リセットをするための Hardware watchdog 機能を提供します。
このライブラリによって以下の機能をアプリケーションから使う事ができます。
-
HW リセットを実行するまでの時間を設定する
-
リセットまでの時間を取得する
-
リセットまでの時間をリセットする
例えば”10秒以内に loop()
を抜けなければならないのにそれを経過してしまったらリセットするようにしたい”場合に使うことができます。
2.20.1. 使い方
このライブラリは以下の手順で使うことができます。また、 WatchdogClass
のインスタンス Watchdog
を使います。
-
Watchdog.begin()
でWatchdogを初期化する -
Watchdog.start(time)
で監視を開始するtime
にリセットするまでの時間(ms)をセットします。 その時間を経過するとHW リセットが発生します。time
は最大40秒を設定できます -
Watchdog.kick()
でリセットまでの時間をリセットするプログラムが正常に動作している場合はそれを通知してリセット時間をリセットします。
-
Watchdogで監視する必要がなくなったら
Watchdog.stop()
を実行するWatchdog.stop()
及びWatchdog.kick()
せずに所定時間が経過すると、HWリセットが発生してしまいます。
必要に応じて、HWリセットが発生するまでの時間を Watchdog.timeleft()
で確認してください。
LowPower ライブラリ を利用してのクロックモードの切り替えを行った場合やSDカードの挿抜時は Watchdog のタイマーがリセットされます。
|
2.21. Wire ライブラリ
Spresense Wire ライブラリは、Spresense で I2C / TWI デバイスと通信することができます。I2C は多くのセンサーデバイスで採用されている通信インターフェースです。
Spresense Wire ライブラリは、Arduino Wire ライブラリ と同じ様に使用することができます。
Spresense メインボード/拡張ボードのピン配置を以下に示します。IO電圧は、メインボードでは 1.8V、拡張ボードでは 3.3V もしくは 5.0Vになります。Wireインスタンスは、拡張ボードとメインボードとで同じピンを使っていますので、使用の際は注意してください。
Wire インスタンス名 | コネクタ | SCL | SDA | IO電圧 |
---|---|---|---|---|
Wire |
メインボード |
D15 |
D14 |
1.8V |
Wire |
拡張ボード |
D15 |
D14 |
3.3V or 5V (JP1ジャンパーにより切替) |
Wire1 |
拡張ボード |
D09 |
D03 |
3.3V or 5V (JP1ジャンパーにより切替) |
Wire1 |
LTE拡張ボード |
D09 |
D03 |
3.3V or 5V (CN2ジャンパーにより切替) |
拡張ボードのIO電圧は IOREF ジャンパーによって変更することができます。I2C のIO電圧もIOREF ジャンパーによって変更されます。
メインボード上のピンソケットからも I2C を利用できますが、IOREF に関係なく、IO電圧は1.8V固定です。
ボード上には、I2C 通信のために必要なプルアップ抵抗がマウントされています。
-
Spresense 拡張ボードは、1kΩのプルアップ抵抗がマウントされています。
-
Spresense メインボードは、4.7kΩのプルアップ抵抗がマウントされています。
2.21.1. 機能と制限
通信速度はStandard mode(100kHz)かFast mode(400kHz)のどちらかを選択できます。
-
#define TWI_FREQ_100KHZ (100000) // standard mode
-
#define TWI_FREQ_400KHZ (400000) // fast mode
デフォルトの通信速度は 100kHz です。変更する場合は、setClock(TWI_FREQ_400KHZ) 関数を使用します。
ライブラリは、二つの I2C アドレス長をサポートしています。
-
#define TWI_ADDR_LEN_7_BIT (7)
-
#define TWI_ADDR_LEN_10_BIT (10)
デフォルトのアドレス長は、7 bit です。
オリジナルの Arduino Wire ライブラリと同じ様に、Spresense Wire ライブラリも 32 byte buffer です。したがって、デバイスとの通信データはその範囲内に収める必要があります。それを超えるデータを受信した場合、超過分のデータは捨てられます。