Developer World Spresense
English 中文
目次

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のピン番号は LED0LED1LED2LED3 として定義されています。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 のピン番号の数字か、もしくは A0A1A2A3A4A5 という定義を使用してください。

1.1.5. analogReadMap() [独自拡張]

analogRead() 関数は、ADC から取得される 符号付き16bitの値(signed short)を map(value, fromLow, fromHigh, toLow, toHigh) 関数を用いて 0 ~ 1023 にマップした値を返します。

analogReadMap() 関数によって、map() 関数の引数 fromLow, fromHigh で使用する値を変更することができます。 また、analogReadMap() 関数の minmax に同じ値を設定した場合、analogRead() 関数は map() による変換を行わずに、ADC の生値を返します。

API

void analogReadMap(uint8_t pin, int16_t min, int16_t max);

Parameter

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() は空マクロとして定義されており、 次のどちらの使い方も可能です。

API

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);

Parameter

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本まで登録することができます。 上限数を超えて attachInterrupt() を呼び出したとき、シリアルモニタに ERROR: Out of interrupt resources というエラーメッセージが表示されます。 各ピン番号がSYS/APPのどちらのグループに所属しているかについては以下を参照してください。

  • SYS GPIO ピングループから最大6本まで (LTEを動作させたときにLTEライブラリが1本を使用します)

    D02, D03, D04, D05, D06, D07, D08, D09, D14, D15, D22, D29, D30, D31, D32, D39, D40, D41, D42, D43, D44

  • APP GPIO ピングループから最大6本まで (SDカードの挿抜検出用に1本を使用しています)

    D00, D01, D10, D11, D12, D13, D16, D17, D18, D19, D20, D21, D23, D24, D25, D26, D27, D28, D33, D34, D35, D36, D37, D38

1.1.12. attachTimerInterrupt()

タイマー割り込み機能をサポートしています。 この機能は、tone() と同じタイマーリソースを使用するため、tone() と同時に使用することはできません。 attachTimerInterrupt() 機能はシステム上で一つだけ動作します。既に使用中の状態で、 再び attachTimerInterrupt() を呼び出すとエラーになります。異なるハンドラや周期で再設定する際は、detachTimerInterrupt() を呼び出してリソースを解放した後に、再度、attachTimerInterrupt() を呼び出してください。

API

void attachTimerInterrupt(unsigned int (*isr)(void), unsigned int us);

Parameter

isr: タイマー割り込みが発生したときに呼ばれる関数。この関数は次のタイマー周期を戻り値として返します。

  • この関数が 0 を return したときは、タイマーが停止し、ワンショットタイマーとして使用できます。

  • 周期タイマーとして使用したいときは、attachTimerInterrupt() で指定した us 時間と等しい値を return で返してください。

  • その他、return で任意の値を返すことで、次のタイマー割り込みまでの時間を動的に変更することができます。

この関数は割り込みハンドラから呼ばれるため、呼び出し可能な API には制限があります。 例えば、この関数内から Analog I/O 関数を使用することはできません。

us: マイクロ秒

1.1.13. micros()

micros() は 電源ONされてからの経過時間をマイクロ秒単位で返します。 RTC (32.768kHz) サイクルでカウントしているため、分解能は約 30 マイクロ秒です。

API

uint64_t micros(void);

Returns

戻り値は、符号なしの64bit整数です。

1.1.14. millis()

millis() は 電源ONされてからの経過時間をミリ秒単位で返します。

API

uint64_t millis(void);

Returns

戻り値は、符号なしの64bit整数です。

1.1.15. Fast digital I/O

通常のdigitalRead, digitalWrite 関数とは別に、デジタルピンのI/O制御をより高速に行うための関数について説明します。

Function 説明

digitalPinToPort(pin)

uint8_t port = digitalPinToPort(PIN_Dxx);
portRegister関数の引数へ渡すために使用されます。
PIN_Dxx デジタルピン番号をport番号へ変換します。

portInputRegister(port)

volatile uint8_t *in = portInputRegister(digitalPinToPort(PIN_Dxx));
digitalPinToPort関数により変換されたport番号を入力して、GPIO入力レジスタ値を返します。
レジスタから読み出した値は 0:Low, 1:High を表します。

portOutputRegister(port)

volatile uint8_t *out = portOutputRegister(digitalPinToPort(PIN_Dxx));
digitalPinToPort関数により変換されたport番号を入力して、GPIO出力レジスタ値を返します。
レジスタへ書き込む値は 0:Low, 1:High になります。

portModeRegister(port)

volatile uint8_t *mode = portModeRegister(digitalPinToPort(PIN_Dxx));
digitalPinToPort関数により変換されたport番号を入力して、GPIO方向レジスタ値を返します。
レジスタへ書き込む値は 0:Output, 1:Input になります。
このレジスタ制御の他に、ピン機能を GPIO モードに設定しておく必要があるため、
入力ピンとして使用する場合は、pinMode(PIN_Dxx, INPUT) を、
出力ピンとして使用する場合は、pinMode(PIN_Dxx, OUTPUT) を、事前に呼び出してください。

digitalPinToBitMask(pin)

uint8_t mask = digitalPinToBitMask(PIN_Dxx);
常に0x01固定値を返します。
Input, Output, Mode のいずれのレジスタも最下位bit (0x01) を用いて制御します。

例) PIN_D22ピンの入力値を読み出す
/* 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");
例) PIN_LED0ピンの出力値を変化させる
/* 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 の標準的なメモリ構成を以下に示します。

Diagram

アプリケーション SRAM は 128 KByte 単位のタイルと呼ばれるメモリブロックに分かれています。

デフォルトのメモリ構成では MainCore に先頭の 6 タイル (768 KByte) が割り当てられ、 残りの 6 タイル (768 KByte) を SubCore や Audio DSP やその他のライブラリ等で共有して使用します。

Arduino IDE メニューから MainCore に割り当てるメモリサイズを変更することができます。

SubCore が使用するメモリサイズは SubCore スケッチをビルドしたときに自動的に決定されます。
arduino memsize

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 と呼びます)で動作させることにより、非常に効率的かつ簡単な記述でオーディオのアプリケーションを構築することができます。

  • ハイレゾは、現時点では、192kHzのWAV(LPCM)のみサポートしています。

  • アプリケーションが求めるオーディオ機能に応じて、適切な DSP Codec バイナリを事前にインストールし、アプリケーションプログラムから 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 ステレオジャックです。

ピン配置やオーディオ関連のコネクタに関する詳細については、以下のハードウェアガイドを参照してください。

2.1.2. レイヤ構造について

オーディオ・サブシステムのスタックダイアグラムを以下に示します。

Audio Sub-system Stack Diagram
図 1. Audio Sub-system Stack diagram

オーディオ・サブシステムは、大きく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は、以下のような状態遷移を持ちます。

Diagram

各モードの説明は以下になります。

  • 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.4.1. High Level InterfaceのAPIについて

各APIの詳細は、API リファレンスを参照ください。

2.1.4.2. High Level Interfaceを使用したサンプルについて

このHigh Level Interfaceを用いたサンプルは以下になります。

  • beep

  • dual_players

  • pcm_capture

  • player

  • player_hires

  • player_playlist

  • player_wav

  • rec_play

  • recorder

  • recorder_wav

  • through

各サンプルの詳細情報は、チュートリアルをご覧ください。

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へ送りそのまま発音することで、入力から遅延の少ない発音をすることが可能です。

Diagram
  • 録音機能(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 へ送ることで、発音することが出来ます。

Diagram
  • 発音機能(OutputMixer Object)

受け取った音声データを発音します。

#include <OutputMixer.h>

OutputMixer *theMixer;
theMixer  = OutputMixer::getInstance();
  • 認識機能(Recognizer Object)(未対応)

受け取った音声データの音声認識を行います。

  • シンセサイザ機能(Synthesizer Object)(未対応)

指定したパラメータに基づき音声データを作成します。

作成した音声データはOutputMixerObjectへ送ることで発音が可能です。

Diagram
2.1.5.1. 各オブジェクトの組み合わせと機能例

各Object Level Interface用サンプルとその チュートリアル を参照ください。

2.1.5.2. Object Level InterfaceのAPIについて

各APIの詳細は、APIリファレンスを参照ください。

2.1.5.3. Object Level Interfaceを使用したサンプルについて

このObject Level Interfaceを用いたサンプルは以下になります。

  • dual_players_objif

  • pcm_capture_objif

  • player_ObjIf

  • recorder_objif

  • recorder_wav_objif

  • recorder_with_rendering

各サンプルエラー通知のリザルトデータとしての形式での詳細情報は、チュートリアルをご覧ください。

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)によるリサンプリングを行う場合、読み出すフレームサイズは倍数比で変わります。下記を参考にしてください。

表 1. Arduino Audio Max Capture Size
Samplingrate Max samples

16kHz

341

48kHz

1024

192kHz

1024

2.1.7. Audioライブラリで発生するエラーとエラー処理について

Audioライブラリで発生するエラーは、SDK内部から発生するエラーと、Arduinoライブラリから発生するエラーの2つがあります。

2.1.7.1. Arduinoライブラリ内部で発生するエラー
表 2. Arduino Audio Lib Error Code
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

パラメータエラー

表 3. Arduino FrontendObject Error Code
Error Code Value Description

FRONTEND_ECODE_OK

0

正常終了

FRONTEND_ECODE_COMMAND_ERROR

1

API実行エラー

FRONTEND_ECODE_BASEBAND_ERROR

2

AudioDriverエラー

表 4. Arduino RecorderObject Error Code
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

バッファ領域確保エラー

表 5. Arduino PlyerObject Error Code
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

バッファ領域確保エラー

表 6. Arduino OutputMixerObject Error Code
Error Code Value Description

OUTPUTMIXER_ECODE_OK

0

正常終了

OUTPUTMIXER_ECODE_COMMAND_ERROR

1

API実行エラー

2.1.7.2. SDK内部で発生するエラー

SDK内部で発生するエラーは、begin で登録したcallback関数にエラー通知のリザルトデータとしての形式で通知されます。

エラーには、実行したAPIに問題があった場合に、発生するレスポンスエラーと内部処理でエラーを検出した際に発生するアテンションエラーがあります。 レスポンスエラー、アテンションエラーに対しては、それぞれのエラーに応じて、不具合対応、エラー処理追加などを行って下さい。

2.1.8. レスポンスエラー

Audioライブラリで実行したAPIが、状態違反やパラメータの誤りなど、仕様と異なった制御を行った場合、レスポンスエラーが発生し、パラメータにエラー内容が格納されます。

リザルトのレスポンスエラーのデータ形式については、 リザルトフォーマットErrorResponse を参照してください。

この "ErrorResponse" には、"Error Code" が付加されており、この "Error Code" によって、どのような要因で、エラーが発生しているかがわかるようになっています。

以下に"Error Code" の一覧を示します。

表 7. Error Code List Table
Error Code Value Description

AS_ECODE_STATE_VIOLATION

0x01

状態違反

AS_ECODE_PACKET_LENGTH_ERROR

0x02

パケット長パラメータの誤り

AS_ECODE_COMMAND_CODE_ERROR

0x03

不明なコマンド

AS_ECODE_COMMAND_NOT_SUPPOT

0x04

無効なコマンド

AS_ECODE_AUDIO_POWER_ON_ERROR

0x05

電源ONの失敗

AS_ECODE_AUDIO_POWER_OFF_ERROR

0x06

電源OFFの失敗

AS_ECODE_DSP_LOAD_ERROR

0x07

DSPの起動失敗

AS_ECODE_DSP_UNLOAD_ERROR

0x08

DSPの終了失敗

AS_ECODE_DSP_VERSION_ERROR

0x09

DSPのバージョン不一致

AS_ECODE_SET_AUDIO_DATA_PATH_ERROR

0x0A

入出力パラメータの誤り

AS_ECODE_CLEAR_AUDIO_DATA_PATH_ERROR

0x0B

データパスのクリア失敗

AS_ECODE_NOT_AUDIO_DATA_PATH

0x0C

入出力が無効

AS_ECODE_DECODER_LIB_INITIALIZE_ERROR

0x0D

Decoder DSPの初期化失敗

AS_ECODE_ENCODER_LIB_INITIALIZE_ERROR

0x0E

Encoder DSPの初期化失敗

AS_ECODE_FILTER_LIB_INITIALIZE_ERROR

0x0F

Filter DSPの初期化失敗

AS_ECODE_COMMAND_PARAM_CODEC_TYPE

0x11

コーデック種別の指定の誤り

AS_ECODE_COMMAND_PARAM_CHANNEL_NUMBER

0x13

チャンネル数の指定の誤り

AS_ECODE_COMMAND_PARAM_SAMPLING_RATE

0x14

サンプリング周波数の指定の誤り

AS_ECODE_COMMAND_PARAM_BIT_RATE

0x15

ビットレートの指定の誤り

AS_ECODE_COMMAND_PARAM_BIT_LENGTH

0x16

ビット長の指定の誤り

AS_ECODE_COMMAND_PARAM_ACTIVE_PLAYER

0x18

Playerインスタンスの指定の誤り

AS_ECODE_COMMAND_PARAM_INPUT_DEVICE

0x19

入力デバイスの指定の誤り

AS_ECODE_COMMAND_PARAM_OUTPUT_DEVICE

0x1A

出力デバイスの指定の誤り

AS_ECODE_COMMAND_PARAM_INPUT_HANDLER

0x1B

入力デバイスハンドルの指定の誤り

AS_ECODE_COMMAND_PARAM_INPUT_DB

0x28

ミュートパラメータの指定の誤り

AS_ECODE_DMAC_INITIALIZE_ERROR

0x2B

入出力機能の初期化失敗

AS_ECODE_DMAC_READ_ERROR

0x2C

入力データの取得失敗

AS_ECODE_SIMPLE_FIFO_UNDERFLOW

0x2F

SimpleFIFOのデータが枯渇

AS_ECODE_SET_MIC_GAIN_ERROR

0x30

マイクゲインの指定誤り

AS_ECODE_SET_OUTPUT_SELECT_ERROR

0x32

出力先設定の指定誤り

AS_ECODE_INIT_CLEAR_STEREO_ERROR

0x33

ボリュームの指定誤り

AS_ECODE_SET_VOLUME_ERROR

0x34

ボリュームの指定誤り

AS_ECODE_SET_VOLUME_MUTE_ERROR

0x35

ミュート対象の指定誤り

AS_ECODE_SET_BEEP_ERROR

0x36

ビープパラメータの指定誤り

AS_ECODE_QUEUE_OPERATION_ERROR

0x37

データキュー管理の失敗

AS_ECODE_COMMAND_PARAM_RENDERINGCLK

0x39

動作モードの指定誤り

"Error Code" の詳細は こちら を参照してください。

2.1.9. アテンションエラー

Audio SubSystem内部での処理中(コマンド処理ではなく)に何らかのエラーを検出した場合、通知用のイベントが発生します。

アテンションエラーのデータ形式については ErrorAttention を参照してください。

アテンションエラーには 再生動作時のES(Elementary Stream)の供給の途切れ(アンダーフロー)や、記録動作時のES書き込みバッファのあふれ(オーバーフロー)などのフロー制御のエラー、メモリリソースの枯渇や、リアルタイム処理の遅延といったシステムエラー、 HWから発生したエラーなど、復帰にシステムのリセットが必要となる致命的なエラーなどがあります。

これらのエラーは、"ErrorAttention"に付加されている"Attention Code"で判断することが出来ます。 発生した"Attention Code"に基づいて修正を行ってください。 また、実装方法を変えることで、エラーが改善されることもあります。

以下に、"ErrorAttention" に付加される、 "Attention Code" の一覧を示します。

表 8. Attention Code List Table
Attention Code Value Description

AS_ATTENTION_SUB_CODE_DMA_UNDERFLOW

0x01

DMA転送のアンダーフロー

AS_ATTENTION_SUB_CODE_DMA_OVERFLOW

0x02

DMA転送のオーバーフロー

AS_ATTENTION_SUB_CODE_DMA_ERROR

0x03

DMA転送の失敗

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW

0x05

SimpleFIFOのアンダーフロー

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW

0x06

SimpleFIFOのオーバーフロー

AS_ATTENTION_SUB_CODE_ILLEGAL_REQUEST

0x07

不正なイベントの受信

AS_ATTENTION_SUB_CODE_INTERNAL_STATE_ERROR

0x08

内部状態の異常

AS_ATTENTION_SUB_CODE_UNEXPECTED_PARAM

0x09

内部パラメータの異常

AS_ATTENTION_SUB_CODE_QUEUE_POP_ERROR

0x0A

内部キューのPOPエラ

AS_ATTENTION_SUB_CODE_QUEUE_PUSH_ERROR

0x0B

内部キューのPUSHエラ

AS_ATTENTION_SUB_CODE_QUEUE_MISSING_ERROR

0x0C

内部キューの枯渇

AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR

0x0D

メモリハンドルの取得失敗

AS_ATTENTION_SUB_CODE_MEMHANDLE_FREE_ERROR

0x0E

メモリハンドルの解放失敗

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR

0x0F

タスクの生成失敗

AS_ATTENTION_SUB_CODE_RESOURCE_ERROR

0x10

インスタンスの生成や削除の失敗

AS_ATTENTION_SUB_CODE_DSP_LOAD_ERROR

0x12

DSPの起動失敗

AS_ATTENTION_SUB_CODE_DSP_UNLOAD_ERROR

0x13

DSPの終了失敗

AS_ATTENTION_SUB_CODE_DSP_EXEC_ERROR

0x14

DSPの処理でエラー

AS_ATTENTION_SUB_CODE_DSP_ILLEGAL_REPLY

0x16

DSPから不正なデータ受信

AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR

0x18

DSPのバージョン不一致

AS_ATTENTION_SUB_CODE_BASEBAND_ERROR

0x19

AudioDriverでエラー

AS_ATTENTION_SUB_CODE_STREAM_PARSER_ERROR

0x1A

ESデータの解析エラー

AS_ATTENTION_SUB_CODE_DSP_ASSETION_FAIL

0x1F

DSPの処理で致命的エラー

AS_ATTENTION_SUB_CODE_DSP_SEND_ERROR

0x20

DSPへのコマンド送信エラー

"Attention Code" の詳細は こちら を参照してください。

Attention Level

Attention通知にはレベルが指定されており、そのエラーに対する深刻度と同時に復帰の処理方法が変わります。

表 9. Attention Level
Level value Description

FATAL

0x03

システムコールエラー等、回復不能なもので、復帰にリセットを要求します。

ERROR

0x02

内部エラー(キューFull/Empty,DSPロード/アンロードなど)でAudioシステムの動作が継続できないようなエラーです。システムを初期状態(Ready状態)に戻すことで復帰が可能になります。

WARN

0x01

エンコード・デコードエラー、データのアンダーフロー・オーバーフローなど、動作に異常があり、音声データなどには異常が発生している可能性があるが、動作は継続できるものです。

2.1.10. Error Code List

"Error Code"の詳細は下記の通りです。

2.1.10.1. AS_ECODE_STATE_VIOLATION
code

0x01

description

Audio Sub System内で状態違反が発生しています。
要求したコマンドとAudioSubSystem内の状態が合っていませんのでコマンドを受け付けることが出来ません。
状態を遷移するコマンドにて正しい状態への遷移を行った後、改めてコマンドを送信し直してください。

AudioSubSystem内の状態遷移については下記を参照してください。

状態遷移について

2.1.10.2. AS_ECODE_PACKET_LENGTH_ERROR
code

0x02

description

コマンドパケットのパケット長パラメータが誤っています。
パケット長はWord(4byte)単位の指定です。byte単位ではありません。
正しい値が設定されていることを確認してください。

2.1.10.3. AS_ECODE_COMMAND_CODE_ERROR
code

0x03

description

不明なコマンドを受信しました。
コマンドIDを再度確認してください。

2.1.10.4. AS_ECODE_COMMAND_NOT_SUPPOT
code

0x04

description

送信したコマンドは有効になっていません。
コマンドを使用するには該当する機能をコンフィグで有効にする必要があります。

Audio PlayerとAudio Recorderのコンフィグについては下記を参照してください。

2.1.10.5. AS_ECODE_AUDIO_POWER_ON_ERROR
code

0x05

description

Audio電源のONが出来ません。既に電源が入っている可能性があります。

2.1.10.6. AS_ECODE_AUDIO_POWER_OFF_ERROR
code

0x06

description

Audio電源のOFFが出来ません。既に電源が落ちている可能性があります。

2.1.10.7. AS_ECODE_DSP_LOAD_ERROR
code

0x07

description

DSPのロード・起動が出来ません。

DSPの配置パスが正しく設定されていることを確認してください。
配置パスの設定については下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

また、配置パスに、必要なDSPが置かれていない可能性があります。
AudioPlayerでは(再生ファイル種別に応じて) MP3DEC, WAVDEC が必要です。
AudioRecorderでは(記録ファイル種別に応じて) MP3ENC, SRC が必要です。
これらは sdk/modules/audio/dsp/ に提供されています。

2.1.10.8. AS_ECODE_DSP_UNLOAD_ERROR
code

0x08

description

DSPの終了・アンロードが出来ません。
既にアンロードされているか、またはロードがされていない可能性があります。

2.1.10.9. AS_ECODE_DSP_VERSION_ERROR
code

0x09

description

DSPのバージョンがAudioSubSytemが期待しているものと異なっており、使用できません。
使用しているSDKパッケージに同梱されるDSP sdk/modules/audio/dsp/ を使用してください。

2.1.10.10. AS_ECODE_SET_AUDIO_DATA_PATH_ERROR
code

0x0a

description

Audioデータのパス設定(入力/出力)が間違っています。
以下のパラメータが正しく設定されていることを確認してください。

AudioRecorder では initRecorder
Through mode では setThroughMode

2.1.10.11. AS_ECODE_CLEAR_AUDIO_DATA_PATH_ERROR
code

0x0b

description

Audioデータのパス設定がクリアできません。

2.1.10.12. AS_ECODE_NOT_AUDIO_DATA_PATH
code

0x0c

description

入力デバイスまたは出力デバイスが有効になっていません。
または ThroughMode に遷移する必要があります。

ThroughStatusへの遷移は setThroughMode

2.1.10.13. AS_ECODE_DECODER_LIB_INITIALIZE_ERROR
code

0x0d

description

Decoder DSPから初期化エラーが応答されています。

2.1.10.14. AS_ECODE_ENCODER_LIB_INITIALIZE_ERROR
code

0x0e

description

Encoder DSPから初期化エラーが応答されています。

2.1.10.15. AS_ECODE_FILTER_LIB_INITIALIZE_ERROR
code

0x0f

description

Filter DSPから初期化エラーが応答されています。

2.1.10.16. AS_ECODE_COMMAND_PARAM_CODEC_TYPE
code

0x11

description

指定されたAudio Codecの種別が誤っています。

AudioSubSystemで対応しているCodecは下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

2.1.10.17. AS_ECODE_COMMAND_PARAM_CHANNEL_NUMBER
code

0x13

description

指定されたch数が誤っている、もしくは他パラメータとの組み合わせでエラーとなっています。
AudioPlayer, AudioRecorderともに、Codecタイプなど他パラメータとch数の組み合わせには制限があります。

それぞれの制限の詳細については下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

2.1.10.18. AS_ECODE_COMMAND_PARAM_SAMPLING_RATE
code

0x14

description

指定されたサンプリング周波数が誤っている、もしくは他パラメータとの組み合わせでエラーとなっています。
AudioPlayer, AudioRecorderともに、Codecタイプなど他パラメータとサンプリング周波数の組み合わせには制限があります。

またAudioPlayerの場合は、Audioデータのヘッダなどに含まれるサンプリング周波数の情報と
指定されたサンプリング周波数が異なる場合も当エラーとなります。

それぞれの制限の詳細については下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

2.1.10.19. AS_ECODE_COMMAND_PARAM_BIT_RATE
code

0x15

description

指定されたビットレートが誤っている、もしくは他パラメータとの組み合わせでエラーとなっています。
AudioRecorderでは、Codecタイプなど他パラメータとビットレートの組み合わせには制限があります。

制限の詳細については下記を参照してください。

Recorder設定の制限

2.1.10.20. AS_ECODE_COMMAND_PARAM_BIT_LENGTH
code

0x16

description

指定されたビット長が誤っている、もしくは他パラメータとの組み合わせでエラーとなっています。

それぞれの制限の詳細については下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

また、Recorder状態で記録をする場合に24bitを指定する際は、HiResoモードに切り替える必要があります。

モードの切り替えについては レンダリングクロック切り替え を参照してください。

2.1.10.21. AS_ECODE_COMMAND_PARAM_ACTIVE_PLAYER
code

0x18

description

有効にするPlayerの指定が誤っています。
Player状態へ遷移できません。

パラメータについては下記を参照してください。

setPlayerMode

2.1.10.22. AS_ECODE_COMMAND_PARAM_INPUT_DEVICE
code

0x19

description

指定された入力デバイスが誤っています。

パラメータについては下記を参照してください。

setPlayerMode setRecorderMode

2.1.10.23. AS_ECODE_COMMAND_PARAM_OUTPUT_DEVICE
code

0x1A

description

指定された出力デバイスが誤っています。

パラメータについては下記を参照してください。

setPlayerMode setRecorderMode

2.1.10.24. AS_ECODE_COMMAND_PARAM_INPUT_HANDLER
code

0x1B

description

指定された入力デバイスハンドルが誤っています。
SimpleFIFOのハンドルやcallback関数が正しく設定されているか確認してください。

パラメータについては下記を参照してください。

setPlayerMode

2.1.10.25. AS_ECODE_COMMAND_PARAM_INPUT_DB
cod

0x28

description

ミュート指定パラメータが誤っています。

パラメータについては下記を参照してください。

setVolume

2.1.10.26. AS_ECODE_DMAC_INITIALIZE_ERROR
code

0x2B

description

音声キャプチャ・レンダリングの初期設定に失敗しました。

2.1.10.27. AS_ECODE_DMAC_READ_ERROR
code

0x2C

description

Audioデータ取り込みに失敗しました。

2.1.10.28. AS_ECODE_SIMPLE_FIFO_UNDERFLOW
code

0x2F

description

Audio再生開始時に、ESバッファがアンダーフローしています。
再生を開始するとAudioSubSystemはすぐにESバッファからESデータを抜出し、デコードを開始しますので
アプリケーションではあらかじめ再生開始前にESデータを入れておく必要があります。

Diagram
2.1.10.29. AS_ECODE_SET_MIC_GAIN_ERROR
code

0x30

description

マイク入力のゲイン設定値が誤っています。
アナログマイクとデジタルマイクで設定の値域が異なります。

パラメータについては下記を参照してください。

AudioRecorder では setRecorderMode Throughモード では setThroughMode

2.1.10.30. AS_ECODE_SET_OUTPUT_SELECT_ERROR
code

0x32

description

指定された出力先設定に誤りがあります。

AudioPlayer では setPlayerMode AudioRecorder では setRecorderMode Throughモード では setThroughMode

2.1.10.31. AS_ECODE_INIT_CLEAR_STEREO_ERROR
code

0x33

description

Clear Stereoの設定エラーが発生しました。

2.1.10.32. AS_ECODE_SET_VOLUME_ERROR
code

0x34

description

指定した再生ボリュームが誤っています。
ボリュームの設定値には制限があります。パラメータの詳細は下記を参照してください。

setVolume

2.1.10.33. AS_ECODE_SET_VOLUME_MUTE_ERROR
code

0x35

description

AudioDriverへのボリューム設定が失敗しました。

2.1.10.34. AS_ECODE_SET_BEEP_ERROR
code

0x36

description

指定したビープ音パラメータが誤っています。
音量・周波数の設定値には制限があります。パラメータの詳細は下記を参照してください。

2.1.10.35. AS_ECODE_QUEUE_OPERATION_ERROR
code

0x37

description

AudioSubSystem内部キューの操作(push, pop)エラーが発生しました。

2.1.10.36. AS_ECODE_COMMAND_PARAM_RENDERINGCLK
code

0x39

description

HiResoモード設定のパラメータエラーです。
設定できるパラメータについては下記を参照してください。

setRenderingClockMode

2.1.11. Attention Code List

"Attention Code" の詳細は下記の通りです。

2.1.11.1. AS_ATTENTION_SUB_CODE_DMA_UNDERFLOW
Code

0x01

Attention Level

ERROR

Description

DMA転送のアンダーフローが発生しました。
DMAへの転送リクエストがDMAのデータ転送スピードよりも遅い可能性があります。 またはDMA転送が停止されているかもしれません。
DMAの転送スピードは、通常モード時で48000サンプル/秒、HiResoモード時は192000サンプル/秒です。

Error Handling

このエラーが発生する場合、アプリケーションタスク処理がリアルタイム処理よりも優先されている可能性があります。
各タスクの優先度を見直してみてください。

2.1.11.2. AS_ATTENTION_SUB_CODE_DMA_OVERFLOW
Code

0x02

Attention Level

ERROR

Description

DMA転送のオーバーフローが発生しました。
DMAへの転送リクエストがDMAのデータ転送スピードよりも速い可能性があります。
またはDMA転送が開始されていないかもしれません。

DMAの転送スピードは、通常モード時で48000サンプル/秒、HiResoモード時は192000サンプル/秒です。

Error Handling

または、記録動作時の場合、HWが供給しているAudioのマスタクロックが停止している可能性があります。クロックが正しく供給されいるか?を確認してください。 再生動作時に発生する場合は、正しいクロックが発信されているかを確認してください。

2.1.11.3. AS_ATTENTION_SUB_CODE_DMA_ERROR
Code

0x03

Attention Level

FATAL, ERROR

Description

DMAハードウェアからエラーが応答されています。
DMAへの転送リクエストを送る前に転送開始を要求した可能性があります。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.4. AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW
Code

0x05

Attention Level

WARNING

Description

AudioPlayer動作中にESバッファのアンダーフローが発生しました。
ESバッファはアプリケーションからAudioSubSystemへESデータの渡すバッファに使用しています。
AudioSubSystemのデータ引き抜きスピードにアプリケーションがついていけていません。

Error Handling

タスク優先度を調整しアプリケーションからのバッファ供給が間に合うようにする、
バッファサイズを増やすなどしてデータ投入が間に合うようにしてください。

2.1.11.5. AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW
Code

0x06

Attention Level

WARNING

Description

AudioRecorder動作中にESバッファのオーバーフローが発生しました。
ESバッファはAudioSubSystemからアプリケーションへEncodedESデータを渡すバッファに使用しています。
AudioSubSystemのデータ投入スピードにアプリケーションがついていけていません。

Error Handling

タスク優先度を調整しアプリケーションのバッファデータ引き抜きが間に合うようにする、
バッファサイズを増やすなどしてデータ引き抜きが間に合うようにしてください。

2.1.11.6. AS_ATTENTION_SUB_CODE_ILLEGAL_REQUEST
Code

0x07

Attention Level

ERROR

Description

AudioSubSystemの内部で不正なイベントが受信されました。
制御シーケンスが異常となっている可能性があります。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.7. AS_ATTENTION_SUB_CODE_INTERNAL_STATE_ERROR
Code

0x08

Attention Level

ERROR

Description

MediaPlayer内で状態異常が起きています。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.8. AS_ATTENTION_SUB_CODE_UNEXPECTED_PARAM
Code

0x09

Attention Level

ERROR

Description

コマンドパラメータが誤っています。

Error Handling

コマンドパラメータを見直してください。

2.1.11.9. AS_ATTENTION_SUB_CODE_QUEUE_POP_ERROR
Code

0x0A

Attention Level

ERROR

Description

内部キューのPOPエラーが発生しています。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.10. AS_ATTENTION_SUB_CODE_QUEUE_PUSH_ERROR
Code

0x0B

Attention Level

ERROR

Description

内部キューのPUSHエラーが発生しています。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.11. AS_ATTENTION_SUB_CODE_QUEUE_MISSING_ERROR
Code

0x0C

Attention Level

ERROR

Description

内部キューが意図せず空になっています。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.12. AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR
Code

0x0D

Attention Level

ERROR

Description

メモリハンドルの取得に失敗しました。
全てのメモリハンドルが使用中になっているか、ハンドルのIDが間違っています。

Error Handling

Arduinoの場合、通常では発生しえないエラーです。
アプリケーションの処理の負荷を変えると回避できる可能性があります。

2.1.11.13. AS_ATTENTION_SUB_CODE_MEMHANDLE_FREE_ERROR
Code

0x0E

Attention Level

ERROR

Description

メモリハンドルの解放に失敗しました。
解放しようとしたハンドルは既に解放されていた可能性があります。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.14. AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR
Code

0x0F

Attention Level

ERROR

Description

AudioSubSystem内部で使用するタスクの生成に失敗しました。
システム全体でのタスク生成数が上限に達している可能性があります。

Error Handling

タスク生成数の上限を増やすか、アプリケーションで使用するタスクを減らしてください。

タスク生成数の上限を増やす場合は、SDKのコンフィグでタスク数を変更し、変更したSDKを取り込みなおしてください。

タスク数生成変更については、以下を参照してください。
SDKでのタスク生成エラーについて

また、自分で作成したSDKのArduinoIDEへの取り込みは、以下を参照してください。

2.1.11.15. AS_ATTENTION_SUB_CODE_RESOURCE_ERROR
Code

0x10

Attention Level

ERROR

Description

AudioSubSystem内で使用するインスタンスの生成・削除に失敗しました。
begin を2重にコールしている可能性があります。
またはHeap領域が不足してるかもしれません。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.16. AS_ATTENTION_SUB_CODE_DSP_LOAD_ERROR
Code

0x12

Attention Level

ERROR

Description

DSPバイナリのロードに失敗しました。
DSPバイナリファイルが指定されたフォルダパスに無い可能性があります。

Error Handling

ファイル有無の確認、またはフォルダパスの指定を見直しをして下さい。
フォルダパスの指定については下記を参照してください。

AudioPlayer では initPlayer
AudioRecorder では initRecorder

2.1.11.17. AS_ATTENTION_SUB_CODE_DSP_UNLOAD_ERROR
Code

0x13

Attention Level

ERROR

Description

DSPアンロードに失敗しました。 既にアンロードされているか、そもそもロードされていない可能性があります。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.18. AS_ATTENTION_SUB_CODE_DSP_EXEC_ERROR
Code

0x14

Attention Level

ERROR, WARNING

Description

DSPでの処理実行時にエラーが発生しました。
直ちにAudioSubSystemの動作に影響が出るものではありませんが
デコード・エンコード・フィルタの結果が正常でない可能性があります。
(一時的に音が乱れる、データが抜けるなどの可能性があります。)

Error Handling

再生動作時の場合、Audioデータが壊れている可能性があります。
Audioデータの確認をして下さい。

2.1.11.19. AS_ATTENTION_SUB_CODE_DSP_ILLEGAL_REPLY
Code

0x16

Attention Level

ERROR

Description

DSPからの応答コマンドパケットが壊れています。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.20. AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR
Code

0x18

Attention Level

ERROR

Description

DSPバージョンエラーが発生しました。DSPをロードできません。

Error Handling

SDKにパックされているDSPバイナリを使用してください。
DSPバイナリは sdk/modules/audio/dsp にあります。

2.1.11.21. AS_ATTENTION_SUB_CODE_BASEBAND_ERROR
Code

0x19

Attention Level

ERROR

Description

Audio Driverでレジスタの設定エラーが発生しました。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.11.22. AS_ATTENTION_SUB_CODE_STREAM_PARSER_ERROR
Code

0x1A

Attention Level

ERROR

Description

AudioPlayerにてESデータの解析エラーが発生しています。
initPlayer で設定したパラメータとESデータを解析した結果が異なっています。

Error Handling

AudioSubSystemに渡すESデータが間違っていないか、壊れていないかを確認してください。

2.1.11.23. AS_ATTENTION_SUB_CODE_DSP_ASSETION_FAIL
Code

0x1F

Attention Level

ERROR

Description

DSP内部でエラーが発生し処理を継続することが不可能です。

Error Handling

システムのリセットが必要です。

2.1.11.24. AS_ATTENTION_SUB_CODE_DSP_SEND_ERROR
Code

0x20

Attention Level

ERROR

Description

DSPへのコマンド送信エラーが発生しました。

Error Handling

通常は発生し得ないエラーです。
SDK内部に不具合がある可能性があります。

2.1.12. Module ID List

AudioSubSystem内部で使用するモジュールのID一覧です。
Attention callbackでアテンションコードとともに通知され、どのモジュールでエラーが発生したかを判断します。

表 10. Module ID List Table
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 ライブラリの概略図を示します。

arduino camera overview
図 2. Camera Overview

Spresense Cameraには、2つのライブラリクラスが用意されています。 1つは、CameraClassのインスタンスである"theCamera"で、もう一つがCameraから取得した画像を操作するCamImageクラスです。

"theCamera"には大きく3つの機能が備わっています。

  • CameraのPreviewを取得するVideoStream機能

  • Cameraのパラメータを制御する機能

  • Cameraで高解像度なJPEG画像を写真として取得する機能

CamImageクラスは、theCameraから取得した画像イメージをユーザが操作するための関数です。 CamImageクラスの概要を以下の図に示します。

arduino camera camimage
図 3. CamImage Overview

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にも、いくつかの設定が出来るようになっています。

表 11. Camera Parameter Control method functions
Method name Description

setAutoWhiteBalance()

Cameraの自動ホワイトバランスの開始停止

setAutoWhiteBalanceMode()

自動ホワイトバランス時のモード設定

setAutoExposure()

Cameraの自動露光調整の開始停止

setAbsoluteExposure()

Cameraの露光時間(100マイクロ秒単位)設定

setAutoISOSensitivity()

Cameraの自動ISO感度の開始停止

setISOSensitivity()

CameraのISO感度設定

setColorEffect()

画像効果設定

setHDR()

HDRモード設定

setJPEGQuality()

JPEG品質設定

また、以下のAPIを用いて、現在値を取得出来るパラメータもあります。

表 12. Camera Parameter Getting method functions
Method name Description

getAbsoluteExposure()

Cameraの露光時間(100マイクロ秒単位)取得

getISOSensitivity()

CameraのISO感度取得

getHDR()

HDRモード取得

getJPEGQuality()

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の取得に失敗する場合、setStillPictureImageFormat() で設定するJPEGバッファサイズの容量が不足していることが考えられます。関数のパラメータ jpgbufsize_divisor の値を小さくすることでJPEGバッファサイズを増やすことができます。また、全体的なメモリ容量不足でバッファサイズを獲得できない場合、MainCoreアプリケーションが使用するメモリを拡張することで解決できるかもしれません。詳細は、Arduino メモリサイズ変更 を参照してください。

2.2.5. Cameraで撮影された画像の情報を取得する。

startStreaming()でのコールバック及びtakePicture()の戻り値で得られるCamImageインスタンスは、取得した画像の情報が入っています。 CamImageクラスのメソッド関数を用いて、画像の情報を取得することが出来ます。

表 13. Methods to get Informations from CamImage
Method name Description

isAvailable()

取得したCamImageインスタンスが利用可能なものかどうかを確認する

getWidth()

画像の幅をピクセル単位で取得

getHeight()

画像の高さをピクセル単位で取得

getPixFormat()

画像のピクセルフォーマットを取得

getImgSize()

画像のデータのサイズをバイト単位で取得

getImgBuff()

画像データのバッファアドレスを取得

getImgBuffSize()

画像バッファサイズをバイト単位で取得

2.2.6. 取得した画像を変換する。

CamImageインスタンスには3つの画像変換メソッド関数が用意されています。

表 14. Methods to convert CamImage
Method name Description

convertPixFormat()

現状のピクセルフォーマットから別のピクセルフォーマットに画像を変換する

resizeImageByHW()

画像の拡大縮小を行う

clipAndResizeImageByHW()

画像の一部を切り出し、切り出し部分の拡大縮小を行う

画像をディスプレイに出したいような場合、ディスプレイのピクセルフォーマットは通常、RGBフォーマットが用いられます。 特にPreview画像を取得した場合、取得した画像をディスプレイ表示したいケースは多いと思います。 このようなケースで、ピクセルフォーマットの変換を行う際などに、convertPixFormat()を用いることが出来ます。

convertPixFormat()は自身データメモリ上でピクセルフォーマットが変換されるため、 現在のCamImageインスタンスが上書きされます。

また、画像の拡大・縮小を行うのにresizeImageByHW()を、 画像の一部のみを切り出すのにclipAndResizeImageByHW()を、それぞれ用いることができます。 clipAndResizeImageByHW()は、切り出した部分に対して、拡大・縮小を行うこともできます。

現時点では以下の制約があります。

  • convertPixformat()は、YUV422からRGB565、RGB565からYUV422、YUV422からGRAY、RGB565からGRAYの4つのみ対応しています

  • resizeImageByHW()およびclipAndResizeImageByHW()の拡大・縮小比率は2のべき乗(2^(-6) ~ 2^6)のみ対応しています

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 overview ja

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. 学習
  1. クラウド版では、サンプルプロジェクトの image_recognition.MNIST.LeNet をベースに新しいプロジェクトを作成します。サンプルのプロジェクトを選択すると選択されたプロジェクトを元に新しいプロジェクトを作成します。新しいプロジェクトの名前を入力するダイアログボックスが表示されるので、好きな名前を入力してください。(ここでは、myproject とします)

    作成された myproject を選択すると編集画面が表示されます。

    edit
    図 4. 編集画面(クラウド版)

    Windows版では、LeNet.sdcproj を選択して使用します。

  2. ここでは、サンプルのネットワークモデルをそのまま使用して学習を行います。

    クラウド版では、編集画面の右上にある Run ボタンを押します。

    start
    図 5. 学習開始(クラウド版)

    Windows版では、Training の下にある三角ボタンを押します。

    start
    図 6. 学習開始(Windows版)
  3. ウィンドウ下部のコンソールに Training Completed が表示されれば学習は完了です。

    TRAINING
機械学習は非常に時間がかかります。
  1. 学習が完了したら学習結果を評価します。

    クラウド版では、学習画面の右上にある Run ボタンを押します。

    EVALUATE
    図 7. 評価開始(クラウド版)

    Windows版では、Evaluation の下にある三角ボタンを押します。

    EVALUATE
    図 8. 評価開始(Windows版)
  2. 評価が完了すると評価結果が表示されます。 x:image の列に表示されている画像と y:label の列に表示されている数字が一致しているはずです。DNNRTで使用するためにこの学習済みモデルをダウンロードします。

    クラウド版では、評価画面右上のドロップダウンリストから NNB (NNabla C Runtime file format) を選択し、下の Download Project を押します。

    DOWNLOAD

    Windows版では、ACTION メニューから、ExportNNB (NNabla C Runtime file format) を選択します。

    DOWNLOAD
  3. ダウンロードした学習済みモデル 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.3.2.1. 複数のサブコア使用する場合

number_recognition.ino サンプルスケッチのデフォルトは、1つのサブコアを使用して数字認識処理を行います。begin() 関数の第2引数にサブコアの数を指定することで、複数のサブコアを使用してより高速に認識処理を実行することができます。指定できるサブコアの数は、実行時の空きサブコア数に依存しますが、1から最大5まで指定可能です。

  int ret = dnnrt.begin(nnbfile, 2); // 2つのサブコアを使用する場合

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 デバイスが使用可能になります。
引数に電源制御を行うピン番号を指定することで、電源をONした後にデバイス初期化を行います。

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 デバイス内のファイルをオープンします。
FILE_READ: 読み取り専用でファイルをオープンします (デフォルト)
FILE_WRITE: 読み書き可能でファイルをオープンします。ファイル位置は末尾を指します。
この関数は File オブジェクトを返します。ファイル操作については File ライブラリ を参照してください。

eMMC.exists()

eMMC デバイス内にファイルが存在するかどうかを確認します。

eMMC.mkdir()

eMMC デバイス内にディレクトリを作成します。

eMMC.rmdir()

eMMC デバイス内にディレクトリを削除します。

eMMC.remove()

eMMC デバイス内のファイルを削除します。

2.5.3. サンプル

eMMC ライブラリには、4 つのスケッチのサンプルが提供されています。

Example Description

format.ino

eMMC デバイスをフォーマットします。eMMC デバイスを初めて利用する際に一度だけ実行してください。

read_write.ino

eMMC デバイス上のファイルを読み書きするサンプルです。

UsbMsc.ino

USB MSC 機能のサンプルです。eMMC デバイスが PC 上のドライブとしてマウントされ、PC から eMMC デバイスに直接アクセスすることができます。

UsbMscAndFileOperation.ino

USB MSC 機能とファイル操作を組み合わせた複合アプリケーションです。eMMC デバイス内のファイルに対して、スケッチからのファイル操作と、USB MSC による PC からのファイル操作は、排他的に動作させる必要があります。このサンプルでは、アプリケーションプログラムからファイル一覧を取得・表示した後に、USB MSC 機能を有効にし、PC から eMMC デバイス内のファイルを操作できるようになります。USB MSC 機能を終了した後に、再びプログラム中からファイル一覧を取得・表示します。


2.6. File ライブラリ

2.6.1. 概要

File ライブラリは各種ストレージから共通に利用されるライブラリです。 File オブジェクトは、SDHCI, Flash, eMMC ライブラリから open() 関数によって生成されます。 本ライブラリは、オープンされた 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.6.3. サンプル

File ライブラリには、以下のサンプルが提供されています。

Example Description

read_write.ino

ファイルを読み書きするサンプルです。


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 デバイス内のファイルをオープンします。
FILE_READ: 読み取り専用でファイルをオープンします (デフォルト)
FILE_WRITE: 読み書き可能でファイルをオープンします。ファイル位置は末尾を指します。
この関数は File オブジェクトを返します。ファイル操作については File ライブラリ を参照してください。

Flash.exists()

Flash デバイス内にファイルが存在するかどうかを確認します。

Flash.mkdir()

Flash デバイス内にディレクトリを作成します。

Flash.rmdir()

Flash デバイス内にディレクトリを削除します。

Flash.remove()

Flash デバイス内のファイルを削除します。

2.7.3. サンプル

Flash ライブラリには、2 つのスケッチのサンプルが提供されています。

Example Description

format.ino

Flash デバイスをフォーマットします。Flash デバイスはフォーマット済みの状態で出荷されていますが、Flash 内のデータを削除したい等の目的で再フォーマットが必要な際に実行してください。フォーマットを実行すると、ブートローダやスケッチからロードしたプログラムを除くすべてのユーザー領域が削除されます。Flash に存在する EEPROM データも削除されます。
このスケッチはシリアルモニタを使用します。通信レート 115200 baud でシリアルモニタを開いてください。
シリアルモニタから y を入力することにより、フォーマットを開始します。
フォーマット中は 4 つの LED が点灯し、フォーマット完了後に LED は点滅します。
フォーマットには約 40 秒ほどの時間がかかります。フォーマット中は電源を切らないように注意してください。

read_write.ino

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ボード上で動かす場合、スケッチ上の SpGnss クラスを SpGnssAddon クラスへ変更するだけで簡単に移植することができます。

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.8.1. 詳細情報

さらに詳細の情報については、 Spresense SDK GNSS documentation を参照してください。


2.9. LowPower ライブラリ

LowPowerライブラリは、Spresenseがもつ省電力機能をサポートしています。

LowPowerライブラリは、主に以下の機能を提供しています。

  • Deep SleepCold 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 を供給しています。 ソフトウェアは特に何も動作していないアイドル状態です。

lowpower current
図 9. Battery current measurement with LowPower
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に示します。

Diagram
図 10. Spresense LTEライブラリ構成

Spresense LTEは2つのカテゴリに属するライブラリクラスを用意しています。
1つは、モデムと通信するライブラリクラス、もう一つがイーサネットやWiFiライブラリのような クライアントインターフェースを実現するライブラリクラスです。

これら2つのカテゴリに属するライブラリクラスについて、以下に説明します。

2.10.2. モデムと通信するライブラリクラス

モデムと通信するライブラリクラスを3つ用意しています。

  • LTEクラス

  • LTEScannerクラス

  • LTEModemクラス

これらは、Arduino GSM ライブラリに類似した機能が用意されています。

2.10.2.1. モデムの状態

モデムと通信するライブラリクラスは、モデムの状態を管理しています。
モデムの状態について、表 15に示します。

表 15. モデムの状態
状態 説明

OFF

モデムの電源がOFFの状態

IDLE

モデムの電源をONにし、無線がOFFの状態

CONNECTING

LTEネットワークにモデムを登録中の状態

SEARCHING

無線をONにし、LTEネットワークの探索を実施している状態

READY

LTEネットワークにモデムを登録し、IPアドレスが付与された状態

ERROR

モデムがエラーの状態

クラスのメソッド呼び出し、もしくはLTEネットワークとの処理で状態が遷移します。
モデムの状態遷移図を図 11に示します。

Diagram
図 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ロックの解除に失敗した場合、モデムが ERROR 状態になります。
ご使用のSIMによりますが、PINロックの解除には試行回数の制限があるので、PINロックの解除に失敗した場合は 正しいPINロック解除コードを使用しているか確認してください。

  • restartは再起動フラグを示し、 true の場合モデムの電源をOFFにしてから、モデムの電源をONにしてLTEネットワークの探索を開始します。 false の場合、モデムの電源をONにしてLTEネットワークの探索を開始します。

  • synchronousは同期フラグを示し、 false の場合、begin()の処理を非同期実行します。

現在、非同期実行はサポートしておらず、 false を指定しても同期で動作します。

デフォルトでは、PINロック解除コードがなし、再起動フラグが true 、同期フラグを true としています。
戻り値でモデムの状態を返します。LTEネットワークの探索を開始すると SEARCHING 状態を返します。

begin()メソッドに失敗した場合、戻り値で ERROR 状態を返します。
ERROR 状態になった原因の情報をシリアルに出力します。
主なエラー原因と修正方法を示します。

表 16. begin()メソッドのエラー原因と修正方法
エラー原因 修正方法

Failed to get PIN status

SIMを正しく挿入してください。

Failed to enter PIN code

指定しているPINロック解除コードを修正してください。

Failed to radio on

PINロック解除コードを指定してください。

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に示します。

表 17. APNパラメータ
パラメータ 説明

apn

アクセスポイント名

userName

ユーザ名。デフォルト設定が 未設定

password

パスワード。デフォルト設定が 未設定

authType

認証タイプ。 PAPCHAPなし から選択。デフォルト設定が CHAP

ipType

APNプロトコル。 IPv4IPv6IPv4v6 から選択。デフォルト設定が IPv4v6

APNのパラメータはご使用のSIMに合わせて、設定してください。

synchronousは同期フラグを示し、 true の場合、LTEネットワークにモデムを登録すると、attach()メソッドを返します。 false の場合、モデムの登録を開始すると、attach()メソッドを返します。

戻り値でモデムの状態を返します。

  • 同期フラグが、 true の場合、LTEネットワークにモデムの登録を登録すると READY 状態を返します。

  • 同期フラグが、 false の場合、モデムの登録処理を開始すると CONNECTING 状態を返します。
    モデムの登録が完了したことを確認するには、getStatus()メソッドでモデムの状態を確認します。LTEネットワークにモデムを登録すると READY 状態を返します。

attach()メソッドに失敗した場合、戻り値で ERROR 状態を返します。
ERROR 状態になった原因の情報をシリアルに出力します。
主なエラー原因と修正方法を示します。

表 18. attach()メソッドのエラー原因と修正方法
エラー原因 修正方法

Rejected from the network

ご使用のSIMに合わせたAPNに修正してください。

IPアドレスを取得する

getIPAddress()メソッドを使用してLTEネットワークがモデムに割り当てたIPアドレスが取得できます。

モデムの状態が READY 状態でない場合、IPアドレスが取得できません。
本メソッドで取得できるIPアドレスのタイプはIPv4のみです。

時刻を取得する

getTime()メソッドを使用して紀元 (Epoch; 1970-01-01 00:00:00 (UTC)) からの秒数が取得できます。

モデムの状態が READY 状態でない場合、時刻が取得できません。

LTEネットワークからモデムを切り離す

detach()メソッドを使用して、モデムをネットワークから切り離し、モデムに付与されたIPアドレスを解放することができます。

モデムの状態が CONNECTING 状態の場合、detach()メソッドを使用して SEARCHING 状態に戻すことができます。

モデムの電源をOFFにする

shutdown()メソッドを使用して、モデムの電源をOFFにすることができます。

モデムの状態が ERROR 状態の場合、shutdown()メソッドを使用して OFF 状態に戻すことができます。

2.10.2.3. LTEScannerクラス

モデムが受信している電波強度(RSSI)・通信に使用している事業者名を取得する機能を提供します。

モデムが受信している電波強度(RSSI)を取得する

getSignalStrength()メソッドを使用して、モデムが受信している電波強度(RSSI)を取得することができます。 単位はdBmです。圏外の場合、取得する値が "N/A" となります。

本メソッドを使用するためには、LTEクラスを使用してモデムの状態を SEARCHING 状態もしくは READY 状態にする必要があります。

モデムを登録したネットワーク事業者名を取得する

getCurrentCarrier()メソッドを使用して、モデムを登録したネットワーク事業者名を取得することができます。

本メソッドを使用するためには、LTEクラスを使用してモデムの状態を READY 状態にする必要があります。

2.10.2.4. LTEModemクラス

モデムのファームウェアバージョン・国際移動体装置識別番号(IMEI)を取得する機能を提供します。

本クラスの機能を使用するためには、begin()メソッドを使用してモデムの状態を IDLE 状態にする必要があります。 SEARCHING 状態、 READY 状態の場合も使用することができます。

モデムのファームウェアバージョンを取得する

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クラスを使用してモデムの状態を READY 状態にする必要があります。

メソッド の詳細は、API リファレンスマニュアル LTE Client API を参照してください。

2.10.3.2. LTETLSClientクラス

TLSプロトコルを使用したクライアント通信機能を提供します。
Arduino Client インターフェースを実現しています。

LTEClientクラスを使用するためには、LTEクラスを使用してモデムの状態を READY 状態にする必要があります。

メソッド の詳細は、API リファレンスマニュアル LTE TLS Client API を参照してください。

証明書の設定

TLSプロトコルで使用するルート証明書・クライアント証明書・秘密鍵の設定方法について説明します。
設定方法を3種類用意しています。 ご使用環境に合わせて適時選択してください。 +

  • microSDカード等に証明書・秘密鍵のファイルをおいて、本クラスのメソッドを使用して設定する方法です。
    microSDカードを使用した例を TLSプロトコルを使用したHTTP Clientの動作を確認する で解説しています。

  • プログラムにPEM形式の配列を生成して、本クラスのメソッドを使用して設定する方法です。

  • プログラムにDER形式の配列を生成して、本クラスのメソッドを使用して設定する方法です。

2.10.3.3. LTEUDPクラス

UDPプロトコルを使用したクライアント通信機能を提供します。
Arduino UDP インターフェースを実現しています。

LTEClientクラスを使用するためには、LTEクラスを使用してモデムの状態を READY 状態にする必要があります。

メソッド の詳細は、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 クラスが提供する関数一覧を以下に示します。 一部、MainCoreSubCore で機能が異なる関数や、 SubCore ではサポートされていない関数もあります(*: サポート, -: 非サポート)

Function Description MainCore SubCore

MP.begin()

マルチコアの起動に関する制御を行います。
(MainCore) 引数に指定した番号の SubCore を起動します。
(SubCore) 引数無しで呼び出し、MainCore へ起動完了を通知します。
詳細はSubCore 起動方法 を参照してください。

*

*

MP.end()

マルチコアの停止に関する制御を行います。
(MainCore) 引数に指定した番号の SubCore を停止します。
(SubCore) 特に何もしません。
詳細は、SubCore 終了方法 を参照してください。

*

*

MP.Send()

指定したコアへデータを送信します。
(MainCore) 引数に指定した番号の SubCore へデータを送信します。
(SubCore) 引数に指定した番号の SubCore へデータを送信します。番号を省略したときは MainCore へ送信します。
詳細は、コア間通信方法 を参照してください。

*

*

MP.Recv()

指定したコアからデータを受信します。
(MainCore) 引数に指定した番号の SubCore からデータを受信します。
(SubCore) 引数に指定した番号の SubCore からデータを受信します。番号を省略したときは MainCore から受信します。
詳細は、コア間通信方法 を参照してください。

*

*

MP.RecvTimeout()

Recv() 受信時のモードやタイムアウト値を設定します。
3 種類の待ちモードがあり、引数によって選択します。
詳細は、コア間通信方法 を参照してください。

*

*

MP.GetRecvTimeout()

RecvTimeout() で設定した値を取得します。

*

*

MP.Virt2Phys()

引数で指定された仮想アドレスを物理アドレスに変換します。物理アドレスマップはすべてのコアで共通です。一方、仮想アドレスは各コアごとに異なります。SubCore は仮想アドレス上で動作するため、異なるコアにアドレスを送信する場合は、この関数を用いて物理アドレスへ変換してください。
詳細は、アプリケーション用メモリ を参照してください。

*

*

MP.GetMemoryInfo()

アプリケーションメモリの空き状況を取得します。
usedMem: 使用メモリのトータルサイズ (Byte)
freeMem: 空きメモリのトータルサイズ (Byte)
largestFreeMem: 空きメモリの連続最大サイズ (Byte)
詳細は、アプリケーション用メモリ を参照してください。

*

*

MP.EnableConsole()

シリアルモニタ (Serial) からの入力を許可します。
Serial からの入力は、いずれか一つのコアで受け付けるようにしてください。 起動直後は、MainCore のみ許可されています。

*

*

MP.DisableConsole()

シリアルモニタ (Serial) からの入力を禁止します。
Serial 入力を特定の SubCore で受け付けるように変更したい場合は、MainCore から DisableConsole() を呼び出し、SubCore 側で EnableConsole() を呼び出してください。
使い方は、サンプルコードShell を参照してください。

*

*

MP.AllocSharedMemory()

共有メモリを確保し、先頭の物理アドレスを返します。共有メモリの確保と解放は 128 KByte 単位です。引数に指定したサイズから 128 Kbyte アライメントされたメモリを確保します。メモリ不足により確保できなかった場合は、NULL が返ります。
使い方は、サンプルコードSharedMemory を参照してください。

*

-

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 を参照してください。

*

*

mutex.Unlock()

Trylock() で獲得した mutex をアンロックで解放します。

*

*

2.11.2.3. MPLog() 関数

マルチコア環境でログ出力を行うための関数です。

Function Description MainCore SubCore

MPLog()

コア間で排他制御されたログ出力を行うための関数マクロです。引数は一般的な printf() と同じ書式を使うことができます。
(MainCore) ログの先頭に [Main] が表示されます。
(SubCore) ログの先頭に [Sub番号] が表示されます。
マルチコア環境でコアごとのログ出力を識別することが可能です。
ただし、割り込みハンドラ内から呼び出した場合はログが混在して出力されることがあります。

*

*

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 の内訳を次に示します。

Diagram
図 12. アプリケーションSRAM

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 再生時における MP3DEC デコーダのロード用

128 KByte

Audio

MP3 録音時における MP3ENC エンコーダのロード用

256 KByte

Audio

WAV 再生時における WAVDEC デコーダのロード用

256 KByte

Audio

WAV 録音時における SRC サンプリングレートコンバータのロード用 (ただしサンプリングレート 48kHz の場合を除く)

128 KByte

DNNRT

初期化時における dnnrt-mp のロード用

128 KByte

SubCore に必要なメモリサイズは、ユーザーアプリケーションに依存します。 スケッチをコンパイルした際に、コンパイル結果表示のウィンドウに以下のようなログが出力されます。この値が、その SubCore を動作させるのに必要なメモリサイズを表します。

arduino multicore boot6 sub1

アプリケーションの組み合わせによっては、メモリ不足で動作させることができないかもしれません。 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() を引数無しで呼び出しすことで、起動完了通知を行います。

Diagram
2.11.2.6. SubCore 終了方法

引数に終了させたい SubCore 番号(1 ~ 5) を入れて MainCore から MP.end(1~5) を呼び出します。 指定された SubCore は動作を終了してシャットダウンします。

Diagram
2.11.2.7. コア間通信方法

MP.Send(), MP.Recv() 関数を使用して任意のデータを送受信することができます。
受信の待ち方には 3 つのモードがあり、MP.RecvTimeout() によりモードを設定します。 デフォルトは、MP_RECV_BLOCKING が設定されています。

  • MP_RECV_BLOCKING (0): データを受信するまで永久に受信待ちに入るモードです。(デフォルト)

  • MP_RECV_POLLING (0xffffffff): データの受信をポーリングするモードです。Recv() を呼び出したときに受信データが無かった場合はすぐに抜けます。このモードでは受信待ちに入ることはありません。

  • 時間 (上記以外): 待ちのタイムアウト時間 (ミリ秒) を設定します。Recv() を呼び出したときに指定された時間だけ待ち、受信データが来ない場合はタイムアウトで抜けます。

Diagram

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 に アライメントされた上限までをヒープメモリとして割り当てます。

Diagram
図 13. SubCore プログラムサイズ

上記のルールによって、最低 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 することができます。

Diagram

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 カードがマウントされていないときは最大で 2 秒間待ってから結果を返します。

SD.beginUsbMsc()

USB MSC (Mass Storage Class) 機能を開始します。

SD.endUsbMsc()

USB MSC (Mass Storage Class) 機能を終了します。

SD.format()

SD デバイスをフォーマットします。デフォルト FAT32 ファイルシステムでフォーマットします。

SD.open()

ファイル名を指定して SD デバイス内のファイルをオープンします。
FILE_READ: 読み取り専用でファイルをオープンします (デフォルト)
FILE_WRITE: 読み書き可能でファイルをオープンします。ファイル位置は末尾を指します。
この関数は File オブジェクトを返します。ファイル操作については File ライブラリ を参照してください。

SD.exists()

SD デバイス内にファイルが存在するかどうかを確認します。

SD.mkdir()

SD デバイス内にディレクトリを作成します。

SD.rmdir()

SD デバイス内にディレクトリを削除します。

SD.remove()

SD デバイス内のファイルを削除します。

2.13.3. サンプル

SDHCI ライブラリには、3 つのスケッチのサンプルが提供されています。 SD カードは、FAT32 でフォーマット済みの状態で使用してください。

Example Description

read_write.ino

SD カード上のファイルを読み書きするサンプルです。

UsbMsc.ino

USB MSC 機能のサンプルです。Spresense 拡張ボードの SD カードが PC 上のドライブとしてマウントされ、PC から SD カードに直接アクセスすることができます。

UsbMscAndFileOperation.ino

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 を参照してください。

Sensor Framework(Publish/subscribe) Architecture
図 14. Sensing Library (Publish/subscribe) Architecture

次に、Arduino向けSensingライブラリのアーキテクチャを示します。

Sensor Framework(Publish/subscribe) Architecture
図 15. Sensing Library (Publish/subscribe) Architecture

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.1. SensorManagerClass

以下、SensorManagerClassのAPIです。

begin
begin();
  • センサマネージャの起動を行います。フレームワークを使用する前に一度呼んでください。

end
end();
  • センサマネージャの停止を行います。フレームワークを使用を終了したら、一度呼んでください。

2.14.2.2. SensorClient

以下、SensorClientのAPIです。 このクラスは、各センサクライアントのベースクラスです。

begin
begin(int      id,
      uint32_t subscriptions        = 0,
      int      rate                 = 0,
      int      sample_watermark_num = 0,
      int      size_per_sample      = 0,
      sensor_data_mh_callback_t cb  =NULL):

センサクライアント生成時に一度だけ呼んでください。

  • int id
    センサクライアントのIDになります。

  • uint32_t subscriptions
    Subscribeしたいセンサを指定します。 ID番目のbitを1にすることで、そのIDのデータを読むことができます。

  • int rate
    入力するセンサデータのサンプリングレートを指定します。

  • int sample_watermark_num
    一回の処理でのサンプル数を指定します。

  • int size_per_sample
    1サンプルのサイズを指定します。

  • sensor_data_mh_callback_t cb
    センサデータがsubscribeされた時に呼ばれるcallbackを指定します。

publish
int publish(FAR void* data,
            uint32_t  size_per_sample,
            uint32_t  freq,
            uint32_t  sample_watermark_num,
            uint32_t  timestamp);

センサクライアントで取得・生成されたセンサーデータをPublishするAPIです。

  • FAR void* data
    送信するセンサーデータのアドレスを指定します。

  • uint32_t size_per_sample
    サンプル単位でのサイズを指定します。

  • uint32_t freq
    センシングの周波数を指定します。

  • uint32_t sample_watermark_num
    センサデータのサンプル数を指定します。

  • uint32_t timestamp
    送信するセンサデータの最初のサンプルのタイムスタンプを指定します。

int publish(PoolId    id,
            FAR void* data,
            uint32_t  size_per_sample,
            uint32_t  freq,
            uint32_t  sample_watermark_num,
            uint32_t  timestamp);

Memory管理エリアを独自に定義し、メモリを削減する際に呼び出します。現在は使用しません。

int publish(MemMgrLite::MemHandle& mh,
            uint32_t size_per_sample,
            uint32_t freq,
            uint32_t sample_watermark_num,
            uint32_t timestamp);

センサクライアントでのセンサデータの管理をMemoryUtilのMHandleを用いた場合に呼び出します。現在は、使用しません。

subscribe
int subscribe(sensor_command_data_mh_t& data);

SensorClientのSubscribeを呼びことで、センシングデータが格納されているアドレスを取得できます。 SubClassで、使用してください。

subscribeされるデータ型は、

sensor_command_data_mh_t

になります。これは、Spresense SDKで定義されています。

typedef struct
{
  sensor_command_header_t header;  /**< command header    */
  unsigned int self: 8;            /**< sender sensor ID  */
  unsigned int time: 24;           /**< time stamp        */
  unsigned int fs: 16;             /**< frequensy         */
  unsigned int size: 16;           /**< number of samples */
  MemMgrLite::MemHandle  mh;       /**< mem handle for send data */

  unsigned int get_self(void)
  {
    return self;
  }

} sensor_command_data_mh_t;

です。 timestamp情報など、必要に応じて取得してください。

2.14.2.3. AccelSensorClass

実際に加速度センシング用の物理センサクライアントもライブラリとして提供しています。SensorClientを 継承する形で作られています。

begin
bool begin(int id,
           int rate                 = 0,
           int sample_watermark_num = 0);

加速度センサクライアントの生成をします。

  • int id
    自分のセンサIDを指定します。SEN_accelID を指定してください。

  • int rate
    加速度センサのレートを指定します。 今回提供のStepCounter(AESM)の場合は、50Hzにしてください。   

  • int sample_watermark_num
    一回の転送サンプル数です。指定できる値は、50以下です。特に変更をする必要がなければ50を指定してください。

write_data
int write_data(float x,
               float y,
               float z);

実際に加速度データを書き込む関数です。 センサから取得したデータをGに換算して書き込んでください。 このインターフェースで1サンプルずつ書き込み、sample_watermark_num数だけ書き込まれると、Publishされます。

2.14.2.4. ApplicationSensorClass

アプリケーションセンサは、センサデータをアプリケーションに受け渡すためのセンサクライアントです。そのため、subscribeしか実装されません。

begin
bool begin(int id,
           uint32_t subscriptions,
           sensor_data_mh_callback_t cb);
  • int id
    自分のセンサIDを指定します。 SEN_app*ID(*:0~3) を指定してください。

  • uint32_t subscriptions
    Subscribeしたいセンサを指定します。 ここでは、ID番目のbitを1にすることで、そのIDのデータを読むことができます。

  • sensor_data_mh_callback_t cb
    センサデータがsubscribeされた時に呼ばれるcallbackを指定します。

subscribe
int subscribe(sensor_command_data_mh_t& data);

subscribeによって、所望のセンサ(物理センサ・論理センサ)のデータを取得できます。 アプリケーションに応じて、実装してください。

2.14.2.5. StepCountReaderClass

アプリケーションセンサの中で、StepCounterデータを読み出すために、用意したアプリケーションセンサクライアントです。

begin
bool begin(int      id,
           uint32_t subscriptions,
           sensor_data_mh_callback_t cb);
  • int id
    自分のセンサIDを指定します。 SEN_app0ID を指定してください。

  • uint32_t subscriptions
    Subscribeしたいセンサを指定します。 ここでは、StepCounterの論理センサを読み出しますので SUBSCRIPTION(SEN_stepcounterID) を指定してください。

  • sensor_data_mh_callback_t cb
    センサデータがsubscribeされた時に呼ばれるcallbackを指定します。

subscribe
int subscribe(sensor_command_data_mh_t& data);

subscribeによって、Step Counterの論理センサからのデータを取得することができます。

通知されるデータ構造は以下になります。

typedef struct
{
  SensorExecResult exec_result;

  union
    {
      StepCounterStepInfo steps;
      SensorAssertionInfo assert_info;
    };
} SensorResultStepCounter;

この中の StepCounterStepInfo steps; がセンサデータの実体です。

以下が、StepCounterセンサーデータです。

typedef struct {

  float    tempo;
  float    stride;
  float    speed;
  float    distance;
  uint32_t step;
  StepCounterMovementType  movement_type;
  uint64_t          time_stamp;

} StepCounterStepInfo;
2.14.2.6. AesmClass:

ソニーが独自に用意した、ステップカウンタライブラリを呼び出すためのセンサクライアントです。 本アルゴリズムは、Bosch社製BMI160をベースにチューニングされています。BMI160のセンシングデータを利用することを推奨しますが、加速度データとして、所望のサンプリングレートでデータが取得できれば、論理センサとして機能はします。

begin
bool begin(int      id,
           uint32_t subscriptions,
           int      input_rate,
           int      input_sample_watermark_num,
           int      input_size_per_sample);

   * int id
自分のセンサIDを指定します。 SEN_stepcounterID を指定してください。

  • uint32_t subscriptions
    Subscribeしたいセンサを指定します。 ここでは、加速度センサのデータを使用しますので、 SEN_accelID を指定してください。  

  • int rate
    入力するセンサデータのサンプリングレートを指定します。今回のアルゴリズムは、50Hzをベースに作成されていますので、50にしてください。

  • int sample_watermark_num
    一回の処理でのサンプル数を指定します。 今回のアルゴリズムは、1秒単位での処理を行いますので、50にしてください。

  • int size_per_sample
    floatの値が、x、y、zの3軸分ありますので、12を指定してください。

set
int set(uint8_t walking_stride,
        uint8_t running_stride)

歩幅をセットする関数です。現在は使用できません。

2.14.3. サンプルスケッチについて

2.14.3.1. Step Counterサンプル

今回、Sensingに関しては、Sonyが提供するStepCounterを使用するサンプルを提供しています。

このサンプルでは、v1.3.0以降のブートローダへの更新が必要です。

Spresense SDKでの、Step Counter機能は、以下で構成されています。

こちらに関しては、Sensor Fusion Framework を参照してください。

Sensor Framework(Publish/subscribe) Architecture
図 16. Sensing Library (Publish/subscribe) Architecture

Arduino向け、Sensingライブラリのでは、以下の図に示す部分が、ライブラリとして提供されています。

Sensor Framework(Publish/subscribe) Architecture
図 17. Sensing Library (Publish/subscribe) Architecture

サンプルスケッチとしては、加速度センサを読みだしフレームワークに供給する部分と、生成されたStepCounterデータを読み出す部分の実装を行うことで、実現が可能です。

以下が、シーケンスになります。

Diagram
図 18. 初期化シーケンス
Diagram
図 19. 実行シーケンス

このように、実装することで、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.15.1. 制限

  • サーボ機能には PWM が必要です。したがって、Spresense の Servo ライブラリでコントロールできる RC サーボは最大4つになります。


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

Diagram
  • IIR

Diagram

入力データは、FFT/IIRのクラスのIFを通して、RingBuffクラス に格納されます。
取り出し要求を受けた際に、各信号処理を行いながらデータを出力します。

2.16.2. 入力・出力のマルチチャネルデータについて

マルチチャネルの入力/出力データは以下のようなインタリープされたデータ形式をとるようにします。

  • 16bitの場合

Diagram
  • 24bitの場合

Diagram
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ライブラリのシーケンスは以下になります。

Diagram
  • begin で指定可能なパラメータは上記を参照してください。

  • put での入力サンプル数は、FFTのTap数と同じである必要はありません。

  • get 実行時に充分な入力データ(FFTのTap数以上の入力データ)が揃っている場合、信号処理結果が取得できます。
    信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(FFTの場合は、Tap数からオーバーラップするサンプルを引いたもの)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。
    オーバーラップするサンプルに関わらずTAP数分のデータが戻ります。

  • end で各種リソースが解放されます。

入力バッファは、出力フレームの4フレーム分バッファされます。バッファサイズを超えて入力してしまうと古いデータから上書きしてしまいます。入力バッファは溢れないようにご注意ください。
2.16.5.2. IIRのシーケンスについて

IIRライブラリのシーケンスは以下になります。

出力フォーマットが Planar でのシーケンス
Diagram
1 begin で指定可能なパラメータは上記を参照してください。 出力フォーマットを Planar にしたい場合は、 begin で出力フォーマットを指定しないか、出力フォーマットを Planar に指定した場合する必要があります。
2 put での入力サンプル数は、IIRライブラリで指定したフレームサイズと同じである必要はありません。
3 get 実行時に充分な入力データ(IIRのフレームサイズ以上の入力データ)が揃っている場合、信号処理結果が取得できます。
信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(IIRのフレームサイズ)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。
begin で、出力フォーマットを Planar に指定した場合、get では、チャンネルごとにチャンネル番号を channel を指定して出力します。
入力バッファは、出力フレームの INPUT_BUFFER_SIZE フレーム分バッファされます。バッファサイズを超えて入力してしまうと古いデータから上書きしてしまいます。入力バッファは溢れないようにご注意ください。
4 end で各種リソースが解放されます。
出力フォーマットが Interleave でのシーケンス
Diagram
1 begin で指定可能なパラメータは上記を参照してください。 出力フォーマットを Interleave にしたい場合は、 begin で出力フォーマットを Interleave に指定した場合する必要があります。
2 put での入力サンプル数は、IIRライブラリで指定したフレームサイズと同じである必要はありません。
3 get 実行時に充分な入力データ(IIRのフレームサイズ以上の入力データ)が揃っている場合、信号処理結果が取得できます。
信号処理が行えた場合は、今回の処理で破棄される入力データのサンプル数(IIRのフレームサイズ)が戻ります。破棄されたサンプル分だけ、入力すると次の信号処理が可能です。
入力バッファは、出力フレームの INPUT_BUFFER_SIZE フレーム分バッファされます。バッファサイズを超えて入力してしまうと古いデータから上書きしてしまいます。入力バッファは溢れないようにご注意ください。
4 end で各種リソースが解放されます。

2.16.6. API詳細について

各APIの詳細は、APIリファレンスを参照してください。
Signal Processing Libraries API

2.16.7. エラー情報について

begin , put , get 等のAPIでエラーが発生した際、そのエラーが何の要因で発生しているか?を getErrorCause で取得することができます。

以下がエラーコードになります。

表 19. Arduino Signal Processing Lib Error Code
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.16.8. サンプルコードについて

2.16.8.1. FFTライブラリを用いたサンプルコードについて

FFTを使ったサンプルコードは以下になります。

  • PeakDetector

  • SoundDetector

2.16.8.2. IIRライブラリを用いたサンプルコードについて

IIRを使ったサンプルコードは以下になります。

  • HighPassSound

  • LowPassSound

2.16.8.3. FFTとIIRライブラリを用いたサンプルコードについて

FFTとIIR両方を使ったサンプルコードは以下になります。

  • VoiceChanger

各サンプルコードの詳細情報は、チュートリアルをご覧ください。


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) を参照してください。 また、受信側のピン receivePin は、割り込みピンとして使用されます。割り込みに使用するピンについての制約事項は、attachInterrupt() を参照してください。


2.18. SPI ライブラリ

Spresense SPI ライブラリは Spresense に各種 SPI インターフェースを備えたスレーブデバイスを接続するための標準インターフェースを提供します。 Spresense SPI ライブラリは、Arduino SPI ライブラリ と互換性をもち同様に使うことができます。

Spresense ボードは、メインボードと拡張ボードのそれぞれに独立した SPI インターフェースを有しています。

各SPIインターフェースの端子を以下に示します。

表 20. 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 mode0
    spi mode1

    SPI_MODE2

    SPI_MODE3

    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 デバイス内のファイルをオープンします。
FILE_READ: 読み取り専用でファイルをオープンします (デフォルト)
FILE_WRITE: 読み書き可能でファイルをオープンします。ファイル位置は末尾を指します。
この関数は File オブジェクトを返します。ファイル操作については File ライブラリ を参照してください。

Storage.exists()

Storage デバイス内にファイルが存在するかどうかを確認します。

Storage.mkdir()

Storage デバイス内にディレクトリを作成します。

Storage.rmdir()

Storage デバイス内にディレクトリを削除します。

Storage.remove()

Storage デバイス内のファイルを削除します。

2.19.3. サンプル

Storage ライブラリには、1 つのスケッチのサンプルが提供されています。

Example Description

read_write.ino

ファイルを読み書きするサンプルです。


2.20. Watchdog ライブラリ

Spresense Watchdog ライブラリは Spresense の システム状態を監視し、異常時にHW リセットをするための Hardware watchdog 機能を提供します。

このライブラリによって以下の機能をアプリケーションから使う事ができます。

  • HW リセットを実行するまでの時間を設定する

  • リセットまでの時間を取得する

  • リセットまでの時間をリセットする

例えば”10秒以内に loop() を抜けなければならないのにそれを経過してしまったらリセットするようにしたい”場合に使うことができます。

2.20.1. 使い方

このライブラリは以下の手順で使うことができます。また、 WatchdogClass のインスタンス Watchdog を使います。

  1. Watchdog.begin() でWatchdogを初期化する

  2. Watchdog.start(time) で監視を開始する

    time にリセットするまでの時間(ms)をセットします。 その時間を経過するとHW リセットが発生します。 time は最大40秒を設定できます

  3. Watchdog.kick() でリセットまでの時間をリセットする

    プログラムが正常に動作している場合はそれを通知してリセット時間をリセットします。

  4. Watchdogで監視する必要がなくなったら Watchdog.stop() を実行する

    Watchdog.stop() 及び Watchdog.kick() せずに所定時間が経過すると、HWリセットが発生してしまいます。

必要に応じて、HWリセットが発生するまでの時間を Watchdog.timeleft() で確認してください。

Diagram
LowPower ライブラリ を利用してのクロックモードの切り替えを行った場合やSDカードの挿抜時は Watchdog のタイマーがリセットされます。

2.20.2. サンプル

このライブラリのサンプルスケッチは、Arduino IDE上で ファイル > スケッチ例 > Watchdog > Watchdog_bite にあります。


2.21. Wire ライブラリ

Spresense Wire ライブラリは、Spresense で I2C / TWI デバイスと通信することができます。I2C は多くのセンサーデバイスで採用されている通信インターフェースです。

Spresense Wire ライブラリは、Arduino Wire ライブラリ と同じ様に使用することができます。

Spresense メインボード/拡張ボードのピン配置を以下に示します。IO電圧は、メインボードでは 1.8V、拡張ボードでは 3.3V もしくは 5.0Vになります。Wireインスタンスは、拡張ボードとメインボードとで同じピンを使っていますので、使用の際は注意してください。

表 21. Wire(I2C)インターフェース端子
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 です。したがって、デバイスとの通信データはその範囲内に収める必要があります。それを超えるデータを受信した場合、超過分のデータは捨てられます。