Spresense Header CodeSpresense Header Code

Spresense - IoTの新しい体験をあなたの手で

Spresense を使って、あなたならではの新しいIoTシステムを作ってみませんか?IoTの未来は、あなたの手の中にあります。

Spresense SDK 開発ガイド

1. Spresense SDKの概要

Spresense SDKはSony Semiconductor Solutions Corp.が提供するCXD5602用に開発されたCXD5602を制御するためのソフトウェアです。 CXD5602の内部ブロックは以下のようになります。

CXD5602 blockdiagram
図 1. CXD5602 内部フロック図

CXD5602は大きく4つのドメインと呼ばれるブロックから構成されています。

  • Application Domain

    • 主にユーザアプリケーションプログラムが制御するブロックで、この中にユーザプログラムが動作するCPU (ARM社製 Cortex®-M4F) が6個搭載されています。

  • System IOP Domain

    • システムの起動やCXD5602内部の電源ドメイン管理などを行うブロックで、ARM社製 Cortex-M0が搭載されています。

  • GNSS Domain

    • 衛星を使った位置測位を行うブロックで、ARM社製 Cortex-M4Fが搭載されています。

  • Sensor Domain

    • I2CやSPIバスに接続されたセンサーのデータをCPUの介在無しに取得するブロックで低消費電力での常時センシングを行うためのソニー独自のハードウェアになります。

CXD5602に関する詳しい情報は、 ソニーセミコンダクタソリューションズ(株) Spresenseホームページを参照してください。

Spresense SDKは上記のハードウェアを制御するためのソフトウェアになります。 Spresense SDKはOSとしてRTOSの1つであるNuttXを利用しており、このOSをベースにして、CXD5602の性能を引き出すための細かな機能を提供します。 Spresenseの各ドライバは、NuttXがもつLinuxライクなDriver Frameworkに準拠して実装されており、そのドライバレイヤの上に、Spresenseが持つ、Audio、GNSS、ASMPなどのミドルウェアのレイヤがあります。

sdk overview
図 2. SDK Overview

各ミドルウェアと特徴的なドライバの概要は以下の通りになります。

表 1. Spresense SDK Middleware Overview
Module Name Summary

Audio Middleware

Spresense SDKのAudio機能を提供します。様々なデータパスに対応し、各種フォーマットでの録音、再生に加えて音声加工処理を実現できます。

Sensor Framework

Spresense SDKの各種センサーデータの出力・加工などの処理を行う際に、センサーもしくは加工データのやり取りをPublish/Subscribeアーキテクチャにて簡便にプログラム出来るようなフレームワークになります。

Memory Utility

Spresense SDKにて、リファレンスカウンター付、固定長メモリープール機能の提供及び、インスタンスの非同期送受信するタスク同期機構を提供しています。

ASMP Framework

CXD5602が持つマルチコアに対してユーザプログラムのロードなどの管理に加えて、CXD5602のメモリ構造の特徴の一つである12枚のタイルの管理を行っています。

Power Management

省電力を実現するための機能を提供します。

GNSS Driver

CXD5602にはGNSSの測位を行うHWサブシステムが備わっています。このドライバはそのサブシステムとのやり取りを行い、ユーザにPOSIX I/FのキャラクタデバイスライクなI/FとしてGNSSに関する機能を提供しています。

各モジュールの詳細は、「Spresense SDKが提供する機能」の章を参照してください。

2. License

Spresense SDKはNuttXと同様、BSD 3項型ライセンスの元でオープンソースとして公開しています。詳しいライセンス条項は、下記の通りです。

3. システム起動シーケンス

CXD5602はリセットが解除されると、BootCPUが起動します。このBootCPUで動作するのが、loader.espkになります。loader.espkが起動すると、loader.espkに制御が移り、loader.espkはnuttx.spkをロードし、アプリケーションCPUをスタートさせます。

nuttx.spkは本SDKでビルドされたバイナリですので、nuttx.spkの実行内容自体は、ビルド時の設定やアプリケーションの動作によって変わります。

アプリケーションがGNSSの機能を使う場合、初期化のAPIをコールした段階でgnss.espkがloader.espkによってロードされるようになっています。

したがって、loader.espkとgnss.espkはSpresense基板を利用する上で、必須のバイナリコードになります。 バイナリの入手方法については、こちらを参照してください。

4. ソフトウェア構成管理

この章ではSpresense SDKのソースコードについてその概要を説明します。

4.1. リポジトリ

Spresense SDKでは以下の2つのRepositoryで構成されます。

リポジトリ名 サブリポジトリ 説明

Spresense SDK のメインリポジトリで開発環境を整える場合はこちらのレポジトリをCloneします。
SpresenseのBSP及びSpresenseがサポートするドライバ、各種Exampleコードが含まれ、spresense-nuttxをSubmoduleとして参照しています。

spresense-nuttx

Spresense NuttX のクローンリポジトリです
SpresenseにおけるKernelがこのレポジトリで管理されています

4.2. ソースツリー

Spresense SDKのソースツリー構成は以下のようになっています

spresense directory structure
図 3. Spresense SDKのディレクトリ構成

各ディレクトリの内容は以下のようになっています

ディレクトリ名 説明

spresense

spresenseをCloneすると生成されるディレクトリです

nuttx

Spresense NuttX のKernelソースコードが含まれます

examples

Spresense SDKでサポートされるドライバ、モジュールを使ったExampleコードが含まれます

sdk

Spresense SDKでサポートされるドライバ、モジュール類が含まれます

bsp

Spresense SDKでのBSPが含まれます

configs

Spresense SDKで提供しているConfigurationが含まれます

drivers

Spresense SDKで提供しているドライバが含まれます

modules

Spresense SDKで提供しているオーディオやセンサなどのモジュールが含まれます

system

Spresense SDKで提供しているシステムツールが含まれます

tools

Spresense SDKでの開発に必要なツールおよびスクリプトが含まれます

5. 開発環境構築

この章ではSpresense SDKを使ってユーザが自身のアプリケーションを開発するのに必要なツールや環境などの説明を行います。

  • なお、現時点でサポートしているPC環境は、Ubuntu 16.04 LTS 64bitになります。

5.1. ツールの準備

  1. GCC ARM toolchain の他、必要なパッケージをインストールします。

    $ sudo apt-get install git gperf libncurses5-dev flex bison gcc-arm-none-eabi genromfs pkg-config autoconf automake cmake --install-recommends
  2. nuttx-tools から kconfig-frontends を取得し、インストールします。

    $ git clone https://bitbucket.org/nuttx/tools.git
    $ cd tools/kconfig-frontends/
    $ ./configure --disable-shared
    $ make
    $ sudo make install

5.2. リポジトリのクローン

$ git clone --recursive https://github.com/sonydevworld/spresense.git

5.3. ブートローダーのインストール

Spresense メインボードを正しく動作させるためにはバージョンに合わせたブートローダーのインストールが必要になります。

Spresense ボードは出荷状態ではローダーはインストールされていません。
Spresenseのローダーを利用するためにはEnd User License Agreementの同意が必要です。

tools/config.py 及び tools/flash.sh 実行時にバージョンに合わせたブートローダーが見つからない場合は次のような WARNING が出るのでそれに従ってインストールを行います。

WARNING: New loader v1.0.003 is required, please download and install.
         Download URL   : https://developer.sony.com/file/download/eula-binaries-vx.x.x.zip
         Install command:
                          1. Extract loader archive into host PC.
                             ./tools/flash.sh -e <download zip file>
                          2. Flash loader into Board.
                             ./tools/flash.sh -l /home/user/mySpresense/spresense/firmware/spresense -c <port>
  1. バイナリのダウンロード

    WARNING 上の Download URL に記載されているリンクを開きバイナリのZIPファイルをダウンロードします。

  2. バイナリのPCへのインストール

    ダウンロードしたZIPファイルで次のコマンドを使いPCにインストールします。

    $ ./tools/flash.sh -e eula-binaries-vx.x.x.zip
  3. バイナリのSpresense メインボードへのロード

    WARNING 上で表示されたコマンドをそのまま実行します。

    $ ./tools/flash.sh -l /home/user/mySpresense/spresense/firmware/spresense -c <port>
  4. ロードが完了し自動で再起動されます。

6. ビルド方法

この章では、ビルド方法について説明します。

6.1. コンフィギュレーション

NuttXカーネルおよび Spresense SDK は、様々な状況に対応できるよう、ユーザーの目的にあったコンフィギュレーションを行うことが可能です。

コンフィギュレーションは、Linuxでも使用されているKconfigビルドシステムを使用します。ツールの準備 を参照して、コンフィギュレーションツールをインストールしてください。

コンフィギュレーションは、NuttXカーネルとSDKのコンフィギュレーションに分かれています。Spresense SDKでは、それらのコンフィギュレーションを行うためのツール tools/config.py tools/mkdefconfig.py を提供しています。

Usage of tools/config.py
~/spresense/sdk$ tools/config.py -h
usage: config.py [-h] [-k] [-l] [-m] [-q] [-g] [-d DIR] [-v]
                 [<config name> [<config name> ...]]

Configuration tool

positional arguments:
  <config name>      configuration name

optional arguments:
  -h, --help         show this help message and exit
  -k, --kernel       kernel config
  -l, --list         list default configurations. show kernel defconfigs with
                     --kernel.
  -m, --menuconfig   run config in "menuconfig"
  -q, --qconfig      run config in "qconfig"
  -g, --gconfig      run config in "gconfig"
  -d DIR, --dir DIR  change configs directory
  -v, --verbose      verbose messages
Usage of tools/mkdefconfig.py
~/spresense/sdk$ tools/mkdefconfig.py -h
usage: mkdefconfig.py [-h] [-k] [-d DIR] [--all] [--verbose] <config name>

Make default config from current config

positional arguments:
  <config name>      configuration name

optional arguments:
  -h, --help         show this help message and exit
  -k                 save kernel configuration
  -d DIR, --dir DIR  change configs directory
  --all              Save SDK and kernel configuration with same name
  --verbose, -v      verbose messages

tools/config.py ツールは、 menuconfig などのフロントエンドおよび定義済みコンフィギュレーション(後述)のロードなどを行います。

このツールは、NuttXカーネルおよび Spresense SDK の設定を行うことができますが、どちらの設定を行うかどうかは -k または --kernel オプションによって切り替えます。 -k オプションが指定されていた場合はNuttXカーネルの設定、指定されていない場合はSDKの設定を変更します。例えば、カーネルのコンフィギュレーションを変更したい場合は、以下のようにします。

e.g.
$ cd spresense/sdk
$ tools/config.py -k -m
tools/config.py tools/mkdefconfig.py はディレクトリ構造に依存しているため、必ず sdk ディレクトリ以下で実行してください。

6.1.1. menuconfig, qconfig, gconfig

設定を変更したい場合は、 tools/config.py の以下のオプションを指定し、設定画面を呼び出します。

表 2. 設定画面呼び出しオプション

オプション

-m または --menuconfig

ncursesライブラリを用いた、CUIメニュー選択

-q または --qconfig

Qtライブラリを使用したGUIメニュー選択

-g または --gconfig

gtkライブラリを使用したGUIメニュー選択

上記のメニュー選択方式は kconfig-frontend の機能に依存しています。kconfig-frontend をビルドする際のオプションによっては使用できない場合がありますが、いずれの方式でも機能は同等です。

6.1.2. 定義済みコンフィギュレーション(defconfig)

定義済みコンフィギュレーション(defconfig)は、ある機能を使用したい場合に必要な設定の組み合わせを事前に定義したものです。defconfigを使用したい場合は、 tools/config.py ツールの引数にdefconfig名を指定します。defconfig名には、 -l オプションで表示されdefconfigを指定できます。

定義済みdefconfigのリストは次のようにして確認できます。

$ tools/config.py --kernel --list   # list kernel predefined configs
$ tools/config.py --list            # list SDK predefined configs

定義済みコンフィギュレーションを指定する場合は次のようにして行うことができます。

$ tools/config.py --kernel release
$ tools/config.py board/spresense

defconfigは同時に複数指定することができます。defconfigを複数指定した場合は、指定されたdefconfigの組み合わせとなります。

$ tools/config.py board/spresense device/sdcard
tools/config.py にコンフィグ名を指定した場合は、指定されたdefconfigにリセットされます。

6.1.3. 設定の保存

ユーザーが変更した設定は保存しておくことが可能です。以下のコマンドで現在のSDKの設定を <config name> として保存します。

$ tools/mkdefconfig.py <config name>

上記の例では、SDKの設定のみ保存され、NuttXカーネルの設定は保存されません。カーネルの設定を保存したい場合は、 -k オプションまたは --all オプションを使用します。 --all オプションを指定した場合は、SDKとカーネルの両方の現在の設定が指定された名前で保存されます。

$ tools/mkdefconfig.py -k <config name>

保存した設定は tools/config.py に指定することができるようになります。

<config name> に指定した名前が既に存在する場合は、上書きするかどうかの確認が表示されます。

tools/config.pytools/mkdefconfig.py は、 sdk/configs 以下にあるdefconfigを対象に適用/保存を行います。もしユーザーが別のディレクトリでコンフィギュレーションを管理したい場合は、 -d または --dir オプションで保存先を変更することができます。

$ tools/mkdefconfig.py -d ../path/to/configs <config name>

別のディレクトリに保存したdefconfigを使用する場合は以下のようにします。

$ tools/config.py -d ../path/to/configs <config name>

ディレクトリの変更は、 -k オプションと組み合わせても使用可能です。

6.2. ビルド

ビルドは、コンフィギュレーションと同様にNuttXカーネルとSDKに分かれています。それぞれビルドする必要があります。どちらの場合も、 sdk ディレクトリ以下で行います。

diag e747f32f27b233a12281e5df1ced4ba4
図 4. ビルドワークフロー

6.2.1. NuttXカーネルのビルド

NuttXカーネルのビルドを行う場合は、以下のように入力します。ビルドを行う前に、カーネルのコンフィギュレーションを行っておく必要があります。

$ cd spresense/sdk
$ tools/config.py -k release
$ tools/config.py -k -m
(設定の変更)
$ make buildkernel

カーネルのコンフィギュレーションを省略したい場合は、以下のようにすることもできます。

$ cd spresense/sdk
$ make buildkernel KERNCONF=release
NuttXカーネルの設定変更およびソースの修正を行っていない場合は、再度ビルドする必要はありません。

6.2.2. SDKのビルド

SDKのビルドを行う場合は、以下のように入力します。カーネルの場合と同様、設定は make コマンドの前に行っておく必要があります。

$ tools/config.py default
$ tools/config.py -m
(設定の変更)
$ make

ビルドが成功すると sdk ディレクトリ以下に nuttx ファイルと nuttx.spk ファイルができます。

nuttx

ELF形式の実行ファイルです。デバッガでロードする場合などで使用します。

nuttx.spk

実機に書き込むためにパッケージングされた独自形式のファイルです。

7. 実機へのロード方法

この章ではブートローダ及びビルドしたビルドしたソフトウェアイメージをSpresense基板に書き込む方法について、説明します。

7.1. Spresense メインボードへのブートローダーのインストール

Spresense メインボードを正しく動作させるためにはバージョンに合わせたブートローダーのインストールが必要になります。

Spresense ボードは出荷状態ではローダーはインストールされていません。
Spresenseのローダーを利用するためにはEnd User License Agreementの同意が必要です。

SDKのコンフィギュレーション 及び Spresense メインボードへのイメージのロード 時にバージョンに合わせたブートローダーが見つからない場合は次のような WARNING が出るのでそれに従ってインストールを行います。

WARNING: New loader v1.0.003 is required, please download and install.
         Download URL   : https://developer.sony.com/file/download/spresense-binaries-vx.x.x.zip
         Install command:
                          1. Extract loader archive into host PC.
                             ./tools/flash.sh -e <download zip file>
                          2. Flash loader into Board.
                             ./tools/flash.sh -l /home/user/mySpresense/spresense/firmware/spresense -c <port>
  1. バイナリのダウンロード

    WARNING 上の Download URL に記載されているリンクを開きバイナリのZIPファイルをダウンロードします。

  2. バイナリのPCへのインストール

    ダウンロードしたZIPファイルで次のコマンドを使いPCにインストールします。

    $ ./tools/flash.sh -e spresense-binaries-vx.x.x.zip
  3. バイナリのSpresense メインボードへのロード

    WARNING 上で表示されたコマンドをそのまま実行します。

    $ ./tools/flash.sh -l ../firmware/spresense -c <port>
  4. ロードが完了し自動で再起動されます。

7.2. Spresense メインボードへのイメージのロード

ビルドしたイメージ nuttx.spk をSpresenseにロードするためには tools/flash.sh を用います。

  1. Spresense メインボードとPCをUSBケーブルで接続します。

  2. Spresense メインボードが接続されているシリアルポートを探すには、以下のコマンドを試してみてください。

    $ dmesg | grep "cp21.*attached"
    [12220.625979] usb 1-1: cp210x converter now attached to ttyUSB0

    この場合は、 ttyUSB0 に接続されていることになります。フルパスは、 /dev/ttyUSB0 になります。

  3. 次のコマンドを使い nuttx.spk をSpresenseへロードします。

    $ tools/flash.sh -c /dev/ttyUSB0 nuttx.spk
    tutorial nuttx image load
    図 5. nuttx.spk ロード画面
  4. ロードが完了し自動で再起動されます。

8. examples

この章では、このSpresense SDKで提供している各exampleの説明と各exampleのビルド手順、例としてexample内のhelloのビルドと実行手順を説明します。

8.1. 各Example

Spresense SDKでは、NuttXがもつ、NSHシェルの機能を用いて、Built-inコマンドの形で各Exampleを実装・提供しています。 各Exampleは以下のようになります。

Example名 説明

accel

加速度センサのサンプルです

adc

A/Dコンバータのサンプルです

alarm

アラームのサンプルです

asmp

ASMPのサンプルです

audio_player

オーディオプレーヤのサンプルです

audio_recorder

オーディオレコーダのサンプルです

audio_through

オーディオパス

camera

カメラのサンプルです

colorsensor

色センサのサンプルです

epaper

電子ペーパのサンプルです

fwupdate

Firmwareアップデートのサンプルです

geofence

Geofenceのサンプルです

gnss

GPSのサンプルです

gyro

ジャイロセンサのサンプルです

hello

Cベースのhelloworldサンプルです

helloxx

C++のhelloworldサンプルです

light

照度センサのサンプルです

mag

地磁気センサのサンプルです

press

気圧センサのサンプルです

proximity

近接センサのサンプルです

tilt

チルトセンサのサンプルです

8.2. "hello" Exampleの実行手順

8.2.1. "hello" Exampleのビルド方法

Configuration方法

まず、以下のコマンドでKernelおよびSDKのコンフィギュレーションを行います

$ tools/config.py --kernel release
$ tools/config.py board/spresense

次に、以下のコマンドでSDKのコンフィギュレーションを更新します

$ tools/config.py -m

するとMenuが開くので "Examples" → "Hello, World! example" にチェックを入れて保存してください

spresense hello example configuration1
図 6. SDKのコンフィギュレーション例
spresense hello example configuration2
図 7. SDKのコンフィギュレーション例
Build方法

ビルドは次のコマンドを使います

$ make buildkernel
$ make
Load方法

Build方法で生成された nuttx.spktools/flash.sh を用いて Spresense 基板にロードします。

$ tools/flash.sh -c /dev/ttyUSB0 nuttx.spk

8.2.2. "hello" Exampleの実行方法

ターミナルにて"hello"と入力し改行すると実行されます

spresense hello example execute
図 8. hello実行例

9. ユーザーアプリの追加

ユーザーが新しいアプリを作成する場合は、以下の方法があります。

ASMP のWorkerプログラムをビルドする方法は、ASMP Framework の章を参照してください。

9.1. examplesに追加する

もっとも簡単な方法は、hello をテンプレートとして使用することです。 hello をディレクトリごと examples 以下にコピーし、MakefileMake.defsKconfighello_main.c の中にある hello の文字列をすべて任意の文字列に置き換えてください。hello_main.c のファイル名も任意のファイル名に変更してください。(アプリ追加例参照)

すべての文字列を置き換えたら、sdk ディレクトリで一旦 make clean をして、tools/config.py でコンフィグメニューを表示します。 追加した項目が表示されるので、それを有効にします。

$ cd sdk
$ make clean
$ tools/config.py -m
kconfigメニュー
Examples  --->
  [ ] My first app example (NEW)
Kconfig ファイルを追加または削除した場合は、sdk ディレクトリで make clean を実行することで、コンフィグメニューが更新されます。

有効にしたらSDKをビルドします。

$ make

作成された nuttx.spk をインストールし、再起動すれば追加したアプリがコマンドとして実行可能になります。

9.1.1. アプリ追加例

Kconfig
config EXAMPLES_MYFIRSTAPP
	bool "My first app example"
	default n
	---help---
		Enable the my first app example

if EXAMPLES_MYFIRSTAPP

config EXAMPLES_MYFIRSTAPP_PROGNAME
	string "Program name"
	default "myfirstapp"
	depends on BUILD_KERNEL
	---help---
		This is the name of the program that will be use when the NSH ELF
		program is installed.

config EXAMPLES_MYFIRSTAPP_PRIORITY
	int "My firstapp task priority"
	default 100

config EXAMPLES_MYFIRSTAPP_STACKSIZE
	int "My firstapp stack size"
	default 2048

endif

Kconfigファイル内の config <symbol> で定義したシンボルは、Makefile内で CONFIG_<symbol> という変数で参照可能です。

Kconfig ファイルに定義するオプションシンボルはSDKで一意である必要があります。シンボルが重複した場合、コンフィギュレーションツール実行時に警告が表示されます。
Makefile
-include $(TOPDIR)/Make.defs
-include $(SDKDIR)/Make.defs

# My first app built-in application info

CONFIG_EXAMPLES_MYFIRSTAPP_PRIORITY ?= SCHED_PRIORITY_DEFAULT
CONFIG_EXAMPLES_MYFIRSTAPP_STACKSIZE ?= 2048

APPNAME = myfirstapp
PRIORITY = $(CONFIG_EXAMPLES_MYFIRSTAPP_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_MYFIRSTAPP_STACKSIZE)

# My first app Example

ASRCS =
CSRCS =
MAINSRC = myfirstapp_main.c

CONFIG_EXAMPLES_MYFIRSTAPP_PROGNAME ?= myfirstapp$(EXEEXT)
PROGNAME = $(CONFIG_EXAMPLES_MYFIRSTAPP_PROGNAME)

include $(APPDIR)/Application.mk
APPNAME

この変数に設定されている文字列がコマンド名になります

PRIORITY

コマンドタスクの優先度を設定します

STACKSIZE

コマンドタスクのスタックサイズを設定します

上記のAPPNAME、PRIORITYおよびSTACKSIZEのいずれかが設定されていない場合は、コマンドになりません。

Make.defs
ifeq ($(CONFIG_EXAMPLES_MYFIRSTAPP),y)
CONFIGURED_APPS += myfirstapp
endif
CONFIGURED_APPS

この変数に設定されているディレクトリがビルド対象になります

9.2. 別ディレクトリに追加する

ユーザーがリポジトリの外でアプリを管理したい場合は、別のディレクトリを作成し、それをビルド対象に追加することができます。 別ディレクトリをビルド対象に加えるには以下のようにします。

  1. 任意のディレクトリをsdkと同じディレクトリに作成

  2. examples ディレクトリから、LibTarget.mkMakefileMake.defs および Application.mk をコピー

  3. LibTarget.mk 内のアーカイブのパスを変更

  4. Application.mk 内のアーカイブのパスを変更

  5. Makefile 内の BIN 変数のファイル名を LibTarget.mk で変更したファイル名と同じファイル名に変更

  6. 上述のexamplesに追加すると同じ手順で、新規に作成したディレクトリ内に任意のアプリケーションを追加

  7. sdk ディレクトリで make

9.2.1. 別ディレクトリ追加例

ディレクトリを myapps 、アプリケーションを myfirstapp とした場合の例

作成後のファイル構成
|-- sdk
|-- examples
|-- myapps
    |-- Application.mk
    |-- LibTarget.mk
    |-- Make.defs
    |-- Makefile
    `-- myfirstapp
        |-- Kconfig
        |-- Make.defs
        |-- Makefile
        `-- myfirstapp_main.c
myapps/LibTarget.mk
# ディレクトリをexamplesからmyappsに変更
# アーカイブ名をlibexamplesからlibmyappsに変更

$(SDKDIR)$(DELIM)..$(DELIM)myapps$(DELIM)libmyapps$(LIBEXT): context
	$(Q) $(MAKE) -C $(dir $@) TOPDIR="$(TOPDIR)" SDKDIR="$(SDKDIR)" $(notdir $@)

lib$(DELIM)libmyapps$(LIBEXT): $(SDKDIR)$(DELIM)..$(DELIM)myapps$(DELIM)libmyapps$(LIBEXT)
	$(Q) install $< $@

EXTLIBS += lib$(DELIM)libmyapps$(LIBEXT)
DELIM

パスデリミタ(Windowsの場合は \ 、Linuxの場合は /

LIBEXT

ライブラリファイル拡張子( .a

myapps/Makefile
MENUDESC = "My Apps"

BIN = libmyapps$(LIBEXT)  # libexamplesをlibmyappsに変更

include $(SDKDIR)/Makefile.ext
MENUDESC

コンフィギュレーションメニューに表示される文字列

myapps/Application.mk (一部)
ifeq ($(WINTOOL),y)
  BIN = "${shell cygpath -w $(APPDIR)$(DELIM)libmyapps$(LIBEXT)}" # libexamplesをlibmyappsに変更
  INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}"
else
  BIN = $(APPDIR)$(DELIM)libmyapps$(LIBEXT) # libexamplesをlibmyappsに変更
  INSTALL_DIR = $(BIN_DIR)
endif

ROOTDEPPATH = --dep-path .

VPATH =

all: .built
.PHONY: clean preconfig depend distclean
.PRECIOUS: $(APPDIR)/libmyapps$(LIBEXT)    # libexamplesをlibmyappsに変更

9.3. ツールを使用する

前述のexamplesに追加する手順及び別ディレクトリに追加する手順は、下記ヘルパーツールを使用して簡単に行うことができます。

アプリ追加ツール
usage: mkcmd.py [-h] [-d BASEDIR] [-v] <app name> [desc]

Create a new application

positional arguments:
  <app name>            New application name
  desc                  Menu description

optional arguments:
  -h, --help            show this help message and exit
  -d BASEDIR, --basedir BASEDIR
                        Base directory to create new application
  -v, --verbose         Verbose messages

This tool create a new application at examples directory.
You can use '-d' option to change application directory, it is a same level
of sdk and examples.
ディレクトリ追加ツール
usage: mkappsdir.py [-h] [-v] <dir name> [desc]

Create a new application directory at the outside of sdk repository

This tool must be run on sdk directory.

positional arguments:
  <dir name>     New application directory name
  desc           Menu description

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose  verbose messages
上記ツールは、 sdk ディレクトリで実行してください。

9.3.1. 使用例

examplesにアプリ myfirstapp を追加する
$ cd spresense/sdk
$ tools/mkcmd.py myfirstapp "My first app example"
新規ディレクトリ myapps を作成し、そこにアプリ myfirstapp を追加する
$ cd spresense/sdk
$ tools/mkappsdir.py myapps "My Apps"
$ tools/mkcmd.py -d myapps myfirstapp "My first app example"

10. Debug方法

ここでは、ユーザアプリをデバッグする際に有効となる情報やツールなどについて説明します。

10.1. Eclipse IDEでのデバッグ方法

10.1.1. ハードウェア

SWDコネクタのマウント

SWD コネクタのマウント方法は、ハードウェアドキュメントを参照してください。

10.1.2. OpenOCDのインストール

ビルドの準備

OpenOCDのビルドには、以下の外部ライブラリが必要です。Ubuntuでは以下のようにしてインストールします。

$ sudo apt install build-essential autoconf automake libtool pkg-config libusb-1.0.0-dev libhidapi-dev
ビルドとインストール
  1. このリポジトリからクローンします https://github.com/sonydevworld/spresense-openocd

  2. ビルド&インストール

$ git clone https://github.com/sonydevworld/spresense-openocd.git
$ cd spresense-openocd
$ ./bootstrap
$ ./configure --disable-werror
$ make
$ sudo make install

Ubuntuの場合は、さらに以下のコマンドでICEに接続する権限を付与する必要があります。 ICEを接続する前に行ってください。

$ sudo cp /usr/local/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d/
$ sudo udevadm control --reload

10.1.3. Eclipseのインストール

Eclipseを使用するために、JREをインストールします。

$ sudo apt install default-jre

Eclipse 公式サイト ( https://www.eclipse.org/downloads/ ) から最新版をダウンロードします。インストーラー(eclipse-inst)を実行すると、以下のようなメニューが表示されるので、Eclipse IDE for C/C++ Developers をクリックします。

Install CDT
図 9. Eclipse IDE for C/C++ Developers のインストール

Eclipseのインストールが完了したら、追加のプラグインをインストールします。

  1. メニュー HelpEclipse Marketplace…​

  2. 検索ボックスに gnu mcu と入力し、Go ボタンを押す

  3. GNU MCU Eclipse をインストール

Install GNU MCU

10.1.4. Eclipse (CDT)のインストール (obsolete)

WARNING

(2019/02/22現在) Eclipse 環境の更新に伴い、ここに記載されているインストール手順は情報が古く、正しくインストールできないことがあります。前章のEclipseのインストールを参照してください。

Ubuntuでは、APT経由でインストールできます。

$ apt install eclipse-cdt

Windowsの場合は、Eclipseのサイトからインストーラをダウンロードしてインストールしてください。

Eclipseのインストールが完了したら、追加のプラグインをインストールします。

  1. メニュー HelpInstall New Software…​

  2. ダウンロードするサイトを選択し、以下のプラグインをインストール

    • CDT Optional Features

      • C/C++ GDB Hardware Debugging

eclipse debug install plugin
図 10. プラグインのインストール

10.1.5. Spresense ボードの設定

Spresenseボードは、nuttx という名前のファイルがインストールされている場合、自動的にこれを起動します。 ファイルがインストールされていない場合は、デバッグモードに入ります。 Eclipseでデバッグを行う前に、Spresenseボードをデバッグモードにする必要があります。

  1. 'r' キーを押したままリセット

  2. nuttx という名前のファイルを別の名前に変更

updater# mv nuttx nuttx.old

デバッグモードに入ると、ターミナルに以下のメッセージが表示されます。

Waiting for debugger connection..

デバッグモードを解除したい場合は、変更したファイルを元の nuttx に戻してください。

GDBの設定

OpenOCDはgdbserverとして動作し、SpresenseでEclipseを使用する場合はこの機能を使用するため、ユーザーはgdbの設定をする必要があります。 Eclipseワークスペースの .cproject, .project のあるディレクトリに .gdbinit という名前のファイルを作成し、以下のスクリプトを記述します。

define hookpost-load

 if &g_readytorun != 0
  eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
  eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
  eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
  eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
  eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
 end

end

10.1.6. デバッグ (GNU MCU Eclipse plugin)

設定
  1. メニュー RunDebug Configurations…​

  2. GDB OpenOCD Debugging を選択

  3. New ボタンを押して新しいOpenOCDデバッグ設定を作成

  4. 下記を設定する

OpenOCDデバッグ設定
  • Main

    • C/C++ Application → nuttx

eclipse debug gnu mcu main
図 11. Mainタブ
  • Debugger

    • OpenOCD Setup グループの Executable path, Actual executableopenocd へのパス

    • Start GDB Session → 有効

    • GDB Client Setup グループの Actual executablearm-none-eabi-gdb へのパス

    • OpenOCD Setup グループの Config options → 下記を設定

-f interface/cmsis-dap.cfg -f target/cxd5602_adsp0.cfg
eclipse debug gnu mcu debugger
図 12. Debuggerタブ
  • Startup

    • Load symbols → 有効

    • Load executable → 有効

    • Debug in RAM → 有効

eclipse debug gnu mcu startup
図 13. Startupタブ
デバッグの実行

以下の手順でデバッグを開始します。

  1. Spresenseボードのリセットスイッチを押す

  2. OpenOCDデバッグ設定の Debug ボタンを押す

10.1.7. デバッグ (obsolete)

WARNING

(2019/02/22現在) GDB Hardware Debugging プラグインを使用したデバッグができないことが確認されています。前章のデバッグ (GNU MCU Eclipse plugin)を参照してください。

  1. メニュー RunDebug Configurations…​

  2. GDB Hardware Debugging を選択

  3. New ボタンを押して新しいデバッグ設定を作成

  4. 下記を設定する

  5. Spresenseボードのリセットスイッチを押す

  6. Debug ボタンを押してデバッグ開始

デバッグ設定
  • Main

    • C/C++ Application → nuttx

eclipse debug main
  • Debugger

    • GDB Command → arm-none-eabi-gdb へのパス

    • Use remote target → 有効

    • JTAG Device → OpenOCD を選択

    • GDB Connection String → 下記を設定

| openocd -f interface/cmsis-dap.cfg -f target/cxd5602_adsp0.cfg -c "gdb_port pipe; log_output openocd.log"
eclipse debug debugger
  • Startup

    • Reset and Delay → 有効

    • Halt → 有効

    • Load image → 有効

    • Load symbols → 有効

eclipse debug startup

11. Spresense SDKが提供する機能

ここでは、Spresense SDKで提供している各機能について、説明します。

11.1. BSP

11.1.1. 概要

BSP (Board Support Package) は、ボード固有の設定や処理を行うためのソースコードが含まれています。

NuttXでは、以下のようなドライバソフトウェアアーキテクチャになっており、BSPディレクトリには Driver (Lower Half)Board specific code および Architecture specific code などのドライバソフトウェアが含まれます。

diag 7b3a8011eb336e2a51fcad7d4f0a6496
図 14. デバイスドライバ階層図
Driver (Lower Half)

NuttX には、標準的なデバイスやバスに対してUpper Halfと呼ばれるドライバがあります。Upper Halfドライバは、アプリケーションへのインターフェースやプロトコル処理などを行いますが、それ単体で動作させることはできません。このため、BSPでLower Half ドライバを適切に実装することで、そのデバイスを使用することができるようになります。

Spresense SDKが提供しているLower Halfドライバには以下のようなものがあります。

  • I2C (cxd56_i2c.c)

  • PWM (cxd56_pwm.c)

  • RTC (cxd56_rtc_lowerhalf.c)

  • SDIO Device (cxd56_sdhci.c)

  • Serial Device (cxd56_serial.c)

  • SPI (cxd56_spi.c)

  • Timer (cxd56_timer.c)

  • USB Device (cxd56_usbdev.c)

  • Watchdog timer (cxd56_wdt.c)

NuttXのドライバに関する詳細は、NuttX Device Drivers を参照してください。

Architecture specific code

アーキテクチャ固有ドライバは、チップに搭載されている機能を使用するためのドライバ(電源管理など)が含まれます。

Board specific code

ボード固有の処理には、ボードの実装によって可変になるもの(ピン設定など)があります。これらの処理には、ある程度共通化できるものと完全にボード依存になっているものに分かれます。これらはそれぞれ、bsp/board/common および bsp/board/<board name><board name> は対応しているボード名)に格納されています。

また、ボードの初期化処理もこれに含まれます。

11.1.2. ディレクトリ構成

sdk/bsp
|-- board
|   |-- common
|   `-- spresense
|-- include
|   |-- arch
|   |   `-- chip
|   |-- nuttx
|   |   |-- lcd
|   |   |-- sensors
|   |   `-- video
|   `-- sdk
|-- scripts
`-- src
ディレクトリ名 内容

bsp/board/common

ボード固有の処理だが、処理シーケンスが同じで、マクロの変更等で共通化できるルーチンが含まれます。

bsp/board/spresense

Spresense基板を動作させるための処理(ピン設定など)が含まれます。

bsp/include/arch/chip

SoCに搭載されているデバイスドライバが提供しているAPIを呼び出す場合のヘッダファイルが含まれます。

bsp/include/arch/nuttx

アーキテクチャ非依存のデバイスのヘッダファイルが含まれます。(NuttXカーネルとの互換性のため、このディレクトリ名となっています)

bsp/include/arch/sdk

Spresense SDKで共通のヘッダファイルが含まれます。SDKのコンフィグヘッダ(config.h)はビルド時にここに生成されます。

bsp/scripts

make ルールやリンカスクリプトが含まれます。

bsp/src

Lower Halfドライバやチップ固有のデバイスドライバなどが含まれます。

11.1.3. ボードの初期化処理

diag a9610c0d7fd737aea7e960b7ac7fcc6c
図 15. 起動シーケンス

メインCPUが起動すると、NuttXカーネルの初期化が行われ、SDKのエントリポイント関数が呼び出されます。デフォルトの設定では、nsh (NuttShell) を起動します。

nsh では、ボードの初期化( boardctl() )が呼び出されます。実際のボードの初期化は、NuttXのルールに従い board_app_initialize 関数に実装されています。この関数では、使用するボードの初期化を行うための処理を行います。

初期化の処理には、Spresenseを使用するための最低限の機能の初期化や、使用するデバイスドライバの初期化などがあります。

SDK_USER_ENTRYPOINT で起動するタスクを nsh から変更した場合は、ユーザーが自ら boardctl() の呼び出しを行う必要があります。

11.2. GPIO/Pin Specification

11.2.1. Software Structure

diag 2ccf26c7a02c2ea94fe313d124e620e3

11.2.2. GPIO Driver Interface

gpioifは、アプリケーションに対して以下の機能を提供します。

  • GPIO ピン設定

    • 機能モード

    • 入出力設定

    • ドライブ電流/スルーレート設定

    • プルアップ/プルダウン設定

  • GPIO 割り込み設定

    • レベル・エッジトリガ設定

    • ノイズフィルタ設定

  • GPIO 入出力制御

  • GPIO 状態取得

APIの詳細は、こちらを参照してください。

GPIO Utility tool

System tools に GPIO Command が用意されており、 CONFIG_SYSTEM_GPIO=y にすることで、NuttShell から gpio コマンドが利用可能です。

gpio コマンドの使い方

nsh> gpio
USAGE: gpio command
 stat [<from_pin>] [<end_pin>]
 conf <pin> [-m <0|1|2|3>] [-i] [-H] [-p <0|1|2|3>]
  -m: function mode
  -i: input enable
  -H: Higher drive current/slew rate
  -p: 0=float, 1=pullup, 2=pulldown, 3=buskeeper
 read <pin>
 write <pin> <0|1|-1>

CONFIG_SYSTEM_GPIO_STATUS=y にすることで、NuttShell から gpio stat 状態表示コマンドが有効になります。

nsh> gpio stat
-------------------------------------------------------------
( No)PIN NAME          : Mode I/O mA Pull Read IRQ Type NF EN
-------------------------------------------------------------
(  1)PIN_I2C4_BCK      : 1    I/  2  --   1    -1
(  2)PIN_I2C4_BDT      : 1    I/  2  --   1    -1
(  3)PIN_PMIC_INT      : 1    I/  2  --   0    -1
(  4)PIN_RTC_IRQ_OUT   : 0     /  2  --   0    -1
(  5)PIN_AP_CLK        : 0     /  2  --   0    -1
(  6)PIN_GNSS_1PPS_OUT : 0     /  2  --   0    -1
( 17)PIN_SPI0_CS_X     : 1     /  2  --   0    -1
( 18)PIN_SPI0_SCK      : 1    I/  2  --   1    -1
( 19)PIN_SPI0_MOSI     : 0     /  2  --   0    -1
( 20)PIN_SPI0_MISO     : 0     /  2  --   0    -1
  :
(101)PIN_MCLK          : 0     /  2  --   0    -1
(102)PIN_PDM_CLK       : 0     /  2  --   0    -1
(103)PIN_PDM_IN        : 0     /  2  --   0    -1
(104)PIN_PDM_OUT       : 0     /  2  --   0    -1
(105)PIN_USB_VBUSINT   : 1    I/  2  --   1    -1

11.2.3. Pin specification

ピンは複数の機能が割り当てられており、Mode(0-3) によって機能を変更することができます。 各種ピンは Pin Group に割り当てられており、Mode指定によって Pin Group 単位で機能が変更されます。

例えば、 PWM0,1 について、

  • Mode0 の場合は、PWM0 と PWM1 の Pin は 両方とも GPIO 機能に設定されます

  • Mode1 の場合は、PWM0 と PWM1 の Pin は 両方とも PWM 機能に設定されます

つまり、Group 単位で機能が割り当てられるため、PWM0 を GPIO として、PWM1 を PWM として個別に設定することはできません

全てのピンは、初期状態で Mode0 (GPIO) になります。

Pin List
  • Pin Name: sdk/bsp/include/arch/chip/pin.h に、PIN_XXX という形式で定義されています

  • WLCSP: 100-pin package (CXD5602GF) の定義です。いくつか使用できないピンがあります。

  • FCBGA: 185-pin full package (CXD5602GG) の定義です。Spresense 基板で使用されています。

  • Mode0-3: それぞれのモードにおけるピンの機能が記述されています。

表 3. SDK が制御できるピンのリスト
Pin Name Arduino
compatible
Pin Name
WLCSP FCBGA Mode0 Mode1 Mode2 Mode3

I2C4_BCK

*

*

GPIO

I2C#4
(CXD5247)

I2C4_BDT

*

*

PMIC_INT

*

*

GPIO

PMIC
Interrupt

PMIC Interrupt
(OpenDrain)

RTC_IRQ_OUT

*

GPIO

RTC_IRQ_OUT

RTC_IRQ_OUT
(OpenDrain)

AP_CLK

*

*

GPIO

AP_CLK

PMU_WDT

PMU_WDT
(OpenDrain)

GNSS_1PPS_OUT

*

GPIO

GNSS_1PPS_OUT

CPU_WDT

CPU_WDT
(OpenDrain)

SPI0_CS_X

*

*

GPIO

UART#1
(Console)

SPI#0

SPI0_SCK

*

*

SPI0_MOSI

*

GPIO

I2C#2

SPI0_MISO

*

SPI1_CS_X

*

*

GPIO

SPI#1
(SPI-Flash)

SPI#0

SPI1_SCK

*

*

SPI1_IO0

*

*

SPI1_IO1

*

*

SPI1_IO2

*

*

GPIO

SPI1_IO3

*

*

SPI2_CS_X

*

*

GPIO

SPI#2
(HostIF)

UART#0
(HostIF)

I2C#3
(HostIF)

SPI2_SCK

*

*

SPI2_MOSI

D04

*

*

GPIO

SPI2_MISO

D08

*

*

HIF_IRQ_OUT

D02

*

*

GPIO

HIF_IRQ_OUT

HIF_IRQ_OUT
(OpenDrain)

GNSS_1PPS_OUT

HIF_GPIO0

*

GPIO

GPS_EXTLD

SEN_IRQ_IN

D22

*

*

GPIO

SEN_IRQ_IN

SPI3_CS0_X

*

*

GPIO

SPI3_CS0_X

SPI3_CS1_X

D07

*

*

GPIO

SPI3_CS1_X

SPI3_CS2_X

*

*

GPIO

SPI3_CS2_X

SPI3_SCK

*

*

GPIO

SPI#3
(Sensor)

SPI3_MOSI

*

*

SPI3_MISO

*

*

I2C0_BCK

D15

*

*

GPIO

I2C#0
(Sensor)

I2C0_BDT

D14

*

*

PWM0

D06

*

*

GPIO

PWM#0,1

PWM1

D05

*

*

PWM2

D09

*

*

GPIO

PWM#2,3

I2C#1
(Sensor)

PWM3

D03

*

*

IS_CLK

*

GPIO

CMOS Image Sensor

IS_VSYNC

*

IS_HSYNC

*

IS_DATA0

*

IS_DATA1

*

IS_DATA2

*

IS_DATA3

*

IS_DATA4

*

IS_DATA5

*

IS_DATA6

*

IS_DATA7

*

UART2_TXD

D01

*

*

GPIO

UART#2

UART2_RXD

D00

*

*

UART2_CTS

D27

*

*

UART2_RTS

D28

*

*

SPI4_CS_X

D10

*

*

GPIO

SPI#4

SPI4_SCK

D13

*

*

SPI4_MOSI

D11

*

*

SPI4_MISO

D12

*

*

EMMC_CLK

D23

*

*

GPIO

eMMC

SPI#5

EMMC_CMD

D24

*

*

EMMC_DATA0

D16

*

*

EMMC_DATA1

D17

*

*

EMMC_DATA2

D20

*

*

GPIO

EMMC_DATA3

D21

*

*

SDIO_CLK

*

GPIO

SDIO

SPI#5

SDIO_CMD

*

SDIO_DATA0

*

SDIO_DATA1

*

SDIO_DATA2

*

GPIO

SDIO_DATA3

*

SDIO_CD

*

GPIO

SDIO
(Card)

SDIO_WP

*

SDIO_CMDDIR

*

GPIO

SDIO

SDIO_DIR0

*

SDIO_DIR1_3

*

SDIO_CLKI

*

GPIO

SDIO
(Card)

I2S0_BCK

D26

*

*

GPIO

I2S#0

I2S0_LRCK

D25

*

*

I2S0_DATA_IN

D19

*

*

I2S0_DATA_OUT

D18

*

*

I2S1_BCK

LED0

*

GPIO

I2S#1

I2S1_LRCK

LED1

*

I2S1_DATA_IN

LED2

*

I2S1_DATA_OUT

LED3

*

MCLK

*

*

GPIO

MCLK
(Audio)

PDM_CLK

*

*

GPIO

PDM
(Audio)

PDM_IN

*

*

PDM_OUT

*

*

USB_VBUSINT

*

*

GPIO

USB VBUS Interrupt

Pin Configuration

Pin 設定は、pinconfigドライバで設定されます。例えば、Mode0(GPIO)以外の I2C や SPI 機能として使用する場合は、 それぞれ I2C, SPI ドライバの中で、Pin が設定されます。そのため、アプリケーションが Mode の変更などを 意識する必要はありません。

Mode0(GPIO) として使用する場合に限り、前述した gpioif を使用して設定してください。

Board Specific Pin Pull and Drive Current Setting

Pin のプル設定やドライブ電流のデフォルト設定は、 sdk/bsp/src/chip/cxd5602_pinconfig.h に定義されています。

基本的に、プル設定は Hi-Z フローティング状態、ドライブ電流は多くが 2mA に設定されています。

基板に依存して、これらの設定を変更する場合は、CONFIG_BOARD_CUSTOM_PINCONFIG=y 有効にして、 sdk/bsp/board/spresense/include/board_pinconfig.h を参考に定義してください。

Spresense基板の例では、

/* Customize from default to the board specific pin configuration
 * The default pin configurations are defined in sdk/bsp/src/chip/cxd5602_pinconfig.h.
 *  Mode: shared pin function mode
 *  ENZI: 1=Input Enable, 0=Input Disable
 *  4mA : Drive Current 1=4mA, 0=2mA
 *  Pull: 0=HiZ floating, PINCONF_PULLUP, PINCONF_PULLDOWN
 *                                                                      M  E     P
 *                                                  P                   o  N  4  u
 *                                                  i                   d  Z  m  l
 *                                                  n                   e  I  A  l
 */
#undef PINCONF_UART2_CTS
#define PINCONF_UART2_CTS                   PINCONF(PIN_UART2_CTS,      1, 1, 0, PINCONF_PULLDOWN)

#undef PINCONF_SPI4_CS_X
#undef PINCONF_SPI4_SCK
#undef PINCONF_SPI4_MOSI
#define PINCONF_SPI4_CS_X                   PINCONF(PIN_SPI4_CS_X,      1, 0, 1, 0)
#define PINCONF_SPI4_SCK                    PINCONF(PIN_SPI4_SCK,       1, 0, 1, 0)
#define PINCONF_SPI4_MOSI                   PINCONF(PIN_SPI4_MOSI,      1, 0, 1, 0)

#undef PINCONF_PWM0
#undef PINCONF_PWM1
#undef PINCONF_PWM2
#undef PINCONF_PWM3
#define PINCONF_PWM0                        PINCONF(PIN_PWM0,           1, 0, 1, 0)
#define PINCONF_PWM1                        PINCONF(PIN_PWM1,           1, 0, 1, 0)
#define PINCONF_PWM2                        PINCONF(PIN_PWM2,           1, 0, 1, 0)
#define PINCONF_PWM3                        PINCONF(PIN_PWM3,           1, 0, 1, 0)
  • UART2_CTS ピンを Pull Down を有効

  • SPI4 のドライブ電流を 2mA から 4mA に変更

  • PWM のドライブ電流を 2mA から 4mA に変更

しています。

11.3. Audio Subsystem

11.3.1. General

CXD5602 はハイレゾリューションを扱えるオーディオ機能(オーディオ・サブシステム)が搭載されています。 オーディオ・サブシステムの機能概要を以下に示します。

  • Audio Codec ハードウェア (AD/DA, DNC, DEQ, etc.) の制御

  • Audio Player 機能

  • Audio Recorder 機能

  • Bluetooth 関連機能(for BT-A2DP)

  • Sound Effector 機能(例えば、音声通話用のバンドパスフィルタなど)

このドキュメントは、CXD5602 のハードウェア上で実現できるオーディオ機能を制御するためのソフトウェアが記載されています。オーディオハードウェアに関しては、別紙Spresenseハードウェアドキュメント を参照ください。

現在のファームウェアでは、Bluetooth 関連機能(for BT-A2DP) 及び、Sound Effector 機能(例えば、音声通話用のバンドパスフィルタなど) は、未対応です。

11.3.2. レイヤ構造について

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

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

オーディオ・サブシステムは、大きく3つのレイヤを持ちます。

Audio Manager(High Level API)

最上位のレイヤで、最上位の抽象度での制御を行うレイヤです。システム全体の整合を取りながら制御します。

Object Layer(ObjectLevel API)

各機能Objectのレイヤで、機能ブロック単位での抽象度で制御を行うレイヤです。各機能内の信号処理・DSP処理などに関して整合を取ります。

Component Layer(Low Level API)

各信号処理componetのレイヤで、信号処理ブロック単位での抽象度で制御を行うレイヤです。信号処理ブロックの組み合わせで処理を構成することで、自由度の高いオーディオ処理を実現できます。

11.3.3. High Level API

High Level API は Audio UtilityAudio Manager が提供する API です。

コマンド送受信による制御ついて

High Level API は、オーディオ・サブシステムをコマンドオブジェクトで制御します。(High Level API Command System)
コマンドオブジェクトは、AS_SendAudioCommandでオーディオ・サブシステムに送信されます。
送信されるコマンドオブジェクトは、AudioCommandになります。
コマンドの詳細は コマンドフォーマット に記載します。

オーディオ・サブシステムは、送信されたコマンドに応じて処理を行い、結果を返します。
結果は、AudioResult オブジェクトで返され、AS_ReceiveAudioResult で取得することができます。
リザルトの詳細は リザルトフォーマット に記載します。

コマンドは同期コマンドになります。コマンドを発行したらリザルトが返るまで次のコマンドを発行できません。
Audio Manager を介して High Level API を使う場合は、送信・受信の手順が1コマンド単位で対になるようにプログラムしてください。
High Level API Command System
図 17. Audio High Level API Command System
制御データ形式(コマンドフォーマット)について

コマンドオブジェクト AudioCommand は1 ワード(4 バイト)の AudioCommandHeader で始まり、その後に必要なだけのパラメータ領域を付加したデータ構造です。
コマンドオブジェクトは、ワード単位をベースとしているため、1 ワード(32 ビット、4バイト)の整数倍の長さで構成されています。
コマンドオブジェクトのreserved フィールドには、0 を設定してください。

typedef struct
{
  AudioCommandHeader header;
  union
  {
    Command Parameters (Payload)
    ...
    ...
  };
} AudioCommand;
コマンド・ヘッダ

全てのコマンドオブジェクトの先頭1 ワード(4 バイト)は、以下の形式です。この1 ワードをコマンドヘッダ('AudioCommandHeader')と呼びます。

typedef struct
{
  uint8_t reserved;
  uint8_t sub_code;
  uint8_t command_code;
  uint8_t packet_length;
} AudioCommandHeader;
packet_length

コマンドヘッダを含めたコマンドオブジェクトの長さを示します。
全てのコマンドオブジェクトは整数個のワード(4バイト)で構成されており、
packet_lengthで指定する値はコマンド・パケットのワード長、すなわちコマンドオブジェクトのバイト長の4分の1となります。

command_code

コマンドに固有のコードです。値0x00は使用しません。
コマンドの種類については コマンド一覧 を参照してください。

sub_code

各コマンドにおいて設定および制御を行う対象を識別するためのコードです。

通知データ形式(リザルトフォーマット)

リザルトオブジェクトは1 ワード(4バイト) 'AudioResultHeader' で始まり、その後に必要なだけのパラメータ領域が付加されたデータ構造です。
リザルトオブジェクトは、ワード単位をベースとしているため、1 ワード(32 ビット、4 バイト)の整数倍の長さで構成されています。
リザルトオブジェクトのreservedフィールドは無視してください。

typedef struct
{
  AudioResultHeader header;
  union
  {
    Result Parameters (Payload)
    ...
    ...
  };
} AudioResult;
リザルト・ヘッダ

全てのリザルトオブジェクトの先頭1ワード(4バイト)は、以下の形式です。
この1ワードをリザルト・ヘッダ('AudioResultHeader')と呼びます。

typedef struct
{
  uint8_t reserved;
  uint8_t sub_code;
  uint8_t result_code;
  uint8_t packet_length;
} AudioResultHeader;
packet_length

リザルトヘッダを含めたリザルトオブジェクトの長さを示します。
全てのリザルトオブジェクトは整数個のワード(4バイト)で構成されており、
packet_lengthで指定する値はリザルトオブジェクトのワード長、すなわちリザルトオブジェクトのバイト長の4分の1となります。

result_code

リザルトの種類を識別するためのコードです。
リザルトの種類については リザルト一覧 を参照してください。 このコードにより、パラメータ領域のデータ内容が変わります。

sub_code

実行したコマンドのsub_codeと同じ値が入ります。

コマンド一覧

各コマンドの一覧は以下になります。
コマンド・ヘッダ にこのコマンドIDを指定し送信することで機能を使用することが出来ます。

General or Common Command

どの状態でも共通のコマンドです。 どの状態からも呼べます。

表 4. General or common Command List
Command Name Command ID Response Result Detail

GetStatus

0x01

NotifyStatus

現在の状態を取得します

詳細は、以下の、Doxygenファイルを参照してください。

Baseband Initialize Command

Baseband HWの初期化を行うコマンドです。 Ready状態からのみ呼べます。

表 5. Baseband Initialize Command List
Command Name Command ID Response Result Detail

InitMicGain

0x53

InitMicGainCmplt

マイクゲインの設定を行います

InitI2SParam

0x54

InitI2SCmplt

I2Sの設定を行います

InitOutputSelect

0x56

InitOutputSelectCmplt

発音するデバイスの設定を行います

InitClearStereo

0x58

InitClearStereoCmplt

クリアステレオ機能の設定を行います

initRenderClk

0x5c

SetRenderingClkCmplt

HiReso設定の切り替えを行います

詳細は、以下の、Doxygenファイルを参照してください。

Baseband Set Command

Baseband HWの設定を行うコマンドです。 PowerOff状態以外の状態から呼べます。

表 6. Baseband Set Command List
Command Name Command ID Response Result Detail

SetVolume

0x59

SetVolumeCmplt

発音時のボリュームの設定を行います

SetVolumeMute

0x5a

SetVolumeMuteCmplt

発音ボリュームのMute設定を行います

SetBeep

0x5b

SetBeepCmplt

BEEP音の設定を行います

詳細は、以下の、Doxygenファイルを参照してください。

Player Command

Playerの制御を行うコマンドです。 Player状態から呼べます。

表 7. Player Command List
Command Name Command ID Response Result Detail

InitPlayer

0x21

InitPlayCmplt

Playerの再生情報を設定します

StartPlayer

0x22

PlayCmplt

バッファの先頭からデコードを行います

StopPlayer

0x23

StopPlayCmplt

バッファの状態に依らずPlayerを停止させます

ClkRecovery

0x24

ClkRecoveryComplete

出音時間の微調整をします

SetDecoderGain

0x25

SetDecoderGainComplete

出音レベルにL/RそれぞれGainをかけます

詳細は、以下の、Doxygenファイルを参照してください。

Recorder Command

Recorderの制御を行うコマンドです。 Recorder状態から呼べます。

表 8. Recorder Command List
Command Name Command ID Response Result Detail

InitRecorder

0x31

InitRecCmplt

音声記録機能を初期化します

StartRecorder

0x32

RecCmplt

音声記録を開始します

StopRecorder

0x33

StopRecCmplt

音声記録を停止します

詳細は、以下の、Doxygenファイルを参照してください。

State Transition Command
表 9. State Transition Command List
Command Name Command ID Response Result Detail

PowerOn

0x71

StatusChanged

Ready状態へ遷移します

SetPowerOffStatus

0x72

StatusChanged

Power Off 状態へ遷移します

SetBaseBandStatus

0x73

StatusChanged

Baseband状態へ遷移します

SetPlayerStatus

0x74

StatusChanged

Player状態へ遷移します

SetRecorderStatus

0x75

StatusChanged

Recorder状態へ遷移します

SetReadyStartus

0x76

StatusChanged

Ready状態へ遷移します

SetThroughStartus

0x77

StatusChanged

Audio path through状態へ遷移します

詳細は、以下の、Doxygenファイルを参照してください。

リザルト一覧

オーディオサブシステムからのリザルト通知です。
リザルト・ヘッダ にこのリザルトIDを格納して応答されます。

General or Common Result
表 10. General or common result List
Result Name Command ID Trigger Command Detail

NotifyStatus

0x01

GetStatus

現在の状態を通知します。

Baseband Initialize Result
表 11. Baseband Initialize Result List
Result Name Command ID Trigger Command Detail

InitMicGainCmplt

0x53

InitMicGain

マイクゲインの設定が完了したことを通知します。

InitI2SCmplt

0x54

InitI2SParam

I2Sの設定が完了したことを通知します。

InitOutputSelectCmplt

0x56

InitOutputSelect

発音するデバイスの設定が完了したことを通知します。

InitClearStereoCmplt

0x58

InitClearStereo

クリアステレオ機能の設定が完了したことを通知します。

SetRenderingClkCmplt

0x5c

InitRenderClk

HiReso設定の切り替えが完了したことを通知します。

Baseband Set Result
表 12. Baseband Set Result List
Result Name Command ID Trigger Command Detail

SetVolumeCmplt

0x59

SetVolume

発音時のボリュームの設定が完了したことを通知します。

SetVolumeMuteCmplt

0x5a

SetVolumeMute

発音ボリュームのMute設定が完了したことを通知します。

SetBeepCmplt

0x5b

SetBeep

BEEP音の設定が完了したことを通知します。

Player Result
表 13. Player Result List
Result Name Command ID Trigger Command Detail

InitPlayCmplt

0x21

InitPlayer

Playerの再生情報設定が完了したことを通知します。

PlayCmplt

0x22

StartPlayer

Playerが動作を開始したことを通知します。

StopPlayCmplt

0x23

StopPlayer

Playerが動作を停止したことを通知します。

ClkRecoveryComplete

0x24

ClkRecovery

出音時間の微調整設定が完了したことを通知します。

SetDecoderGainComplete

0x25

SetDecoderGain

出音レベルL/R Gain設定が完了したことを通知します。

Recorder Result
表 14. Recorder Result List
Result Name Command ID Trigger Command Detail

InitRecCmplt

0x31

nitRecorder

音声記録機能の初期化が完了したことを通知します。

RecCmplt

0x32

StartRecorder

音声記録が開始したことを通知します。

StopRecCmplt

0x33

StopRecorder

音声記録が停止したことを通知します。

State Transition Result
表 15. State Transition Result List
Result Name Command ID Trigger Command Detail

StatusChanged

0x71

PowerOn SetPowerOffStatus SetBaseBandStatus SetPlayerStatus SetRecorderStatus SetReadyStartus

状態遷移が完了したことを通知します。

Error Notification Result
表 16. Error Notification Result List
Result Name Command ID Trigger Command Detail

ErrorResponse

0xf1

エラーが発生したことを通知します。

ErrorAttention

0xf2

内部処理エラーが発生したことを通知します。

コマンドパケット詳細
GetStatus

AudioSubSystem内の状態を取得します。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x01
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitMicGain

マイクの入力ゲインを設定します。
各マイクのゲインを個別に設定することが出来ます。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x53
  uint8_t packet_length : 0x05
}
  • Parameters

InitI2SParam

I2Sの入出力に関する設定をします。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x54
  uint8_t packet_length : 0x03
}
  • Parameters

InitOutputSelect

出力先の設定をします。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x56
  uint8_t packet_length : 0x02
}
  • Parameters

InitClearStereo

Clear Stereoの設定をします。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x58
  uint8_t packet_length : 0x02
}
  • Parameters

initRenderClk

HiResoモードの設定を行います。

  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x5c
  uint8_t packet_length : 0x02
}
  • Parameters

SetVolume
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x59
  uint8_t packet_length : 0x03
}
  • Parameters

SetVolumeMute
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x5a
  uint8_t packet_length : 0x02
}
  • Parameters

SetBeep
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x5b
  uint8_t packet_length : 0x03
}
  • Parameters

InitPlayer
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x21
  uint8_t packet_length : 0x09
}
  • Parameters

StartPlayer
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x22
  uint8_t packet_length : 0x02
}
  • Parameters

StopPlayer
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x23
  uint8_t packet_length : 0x02
}
  • Parameters

ClkRecovery
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x24
  uint8_t packet_length : 0x02
}
  • Parameters

SetDecoderGain
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x25
  uint8_t packet_length : 0x02
}
  • Parameters

InitRecorder
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x31
  uint8_t packet_length : 0x0a
}
  • Parameters

StartRecorder
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x32
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

StopRecorder
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x33
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

PowerOn
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x71
  uint8_t packet_length : 0x02
}
  • Parameters

SetPowerOffStatus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x72
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetBaseBandStatus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x73
  uint8_t packet_length : 0x09
}
  • Parameters

SetPlayerStatus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x75
  uint8_t packet_length : 0x06
}
  • Parameters

SetRecorderStatus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x76
  uint8_t packet_length : 0x04
}
  • Parameters

SetReadyStartus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x77
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetThroughStatus
  • Header

AudioCommandHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t command_code  : 0x78
  uint8_t packet_length : 0x02
}
  • parameters

有りません。

リザルトパケット詳細
NotifyStatus

GetStatus を発行すると応答されます。

  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x01
  uint8_t packet_length : 0x02
}
  • Parameters

typedef struct
{
  uint8_t vad_status;
  uint8_t reserved1;
  uint8_t sub_status_info;
  uint8_t status_info;
} NotifyStatus;
vad_status

現在の音声検知状態が入ります。

sub_status_info

現在のサブ状態が入ります。

status_info

現在の状態が入ります。

InitMicGainCmplt

InitMicGain を発行すると応答されます。

  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x53
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitI2SCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x54
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitOutputSelectCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x56
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitClearStereoCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x58
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetRenderingClkCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x5c
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetVolumeCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x59
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetVolumeMuteCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x5a
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetBeepCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x5b
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitPlayCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x21
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

PlayCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x22
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

StopPlayCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x23
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

ClkRecoveryComplete
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x24
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

SetDecoderGainComplete
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x25
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

InitRecCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x31
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

RecCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x32
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

StopRecCmplt
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x33
  uint8_t packet_length : 0x02
}
  • Parameters

有りません。

StatusChanged
  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0x7f
  uint8_t packet_length : 0x02
}
  • Parameters

typedef struct
{
  uint8_t changed_status;
  uint8_t reseved1;
  uint8_t reseved2;
  uint8_t reseved3;
} StatusChangedParam;
changed_status

遷移後の状態が入ります。

ErrorResponse

コマンド処理でエラーが発生した場合に通知されます。
エラーの詳細はパラメータ領域に格納されます。

  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0xf1
  uint8_t packet_length : 0x02
}
  • Parameters

typedef struct
{
  uint32_t error_code;
  uint16_t reserved1;
  uint8_t  sub_module_id;
  uint8_t  module_id;
  uint32_t error_sub_code;
  uint32_t reserved2;
  uint32_t ErrorCommand[];
} ErrorResponseParam;
error_code

エラー内容を示す エラーコード が入ります。

module_id

エラーが発生した モジュールのID が入ります。

sub_module_id

現在使用していません。

error_sub_code

エラーのサブコードが入ります。コマンドにより異なります。

ErrorCommand[]

現在使用していません。

ErrorAttention

内部処理でエラーが発生した場合に通知されます。

  • Header

AudioResultHeader
{
  uint8_t reserved      : 0x00
  uint8_t sub_code      : 0x00
  uint8_t result_code   : 0xf2
  uint8_t packet_length : 0x0e
}
  • Parameters

typedef struct
{
  uint32_t reserved1;
  uint8_t  error_code;
  uint8_t  cpu_id;
  uint8_t  sub_module_id;
  uint8_t  module_id;
  uint32_t error_att_sub_code;
  uint32_t reserved2;
  uint16_t line_number;
  uint8_t  task_id;
  uint8_t  reserved3;
  uint8_t  error_filename[];
} ErrorAttentionParam;
error_code

エラーの種別を示すコードが通知されます。

module_id

エラーの発生したモジュールのIDが通知されます。

error_att_sub_code

エラーの詳細を示す コード が通知されます。

line_number

エラーの発生したLineが通知されます。

error_filename

エラーの発生したファイル名(最大32byte)が通知されます。

状態遷移

High Level API は、複数の状態を持ちます。 以下に、状態遷移図を示します。

diag 1cd1ed11837767c5451b2aedcd69ede8

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

PowerOff 状態:

オーディオ・サブシステムのオブジェクトを生成し、起動した直後の状態です。オーディオを使用しない場合には、この状態に遷移しておくことで、オーディオブロックでの消費電力をほぼ0にします。

AUDCMD_POWERON コマンドによって、Ready状態にのみ遷移します。

Ready状態:

オーディオブロックに電源を入れて、動作モードにオーディオ機能を動作できるように準備している状態です。この状態では、消費電力は下がっていないのですが、IO/アナログが起動している状態ですので、モード遷移が速やかに行えます。

状態の遷移は、以下になります。

AUDCMD_SETPOWEROFFSTATUS コマンドによって、PowerOff状態に遷移できます。 AUDCMD_SETPLAYERSTATUS コマンドによって、Player状態に遷移できます。 AUDCMD_SETRECORDERSTATUS コマンドによって、Recorder状態に遷移できます。 AUDCMD_SETBASEBANDSTATUS コマンドによって、Baseband状態に遷移できます。

Player状態:

SDカードなどのストレージや WiFi/LTE などのネットワークからの圧縮音声ファイルをデコードし、AnalogOutやI2Sに発音する機能を実現する状態です。状態の中にPlayerReady状態とPlayerActive状態の2つのサブ状態を持ちます。 PlayerReady状態は、音楽再生停止の状態です。AUDCMD_PLAYPLAYER によってPlayerActiveに遷移し音楽再生動作を行います。 PlayerActive状態は、音楽再生中の状態です。AUDCMD_STOPPLAYER によってPlayerReadyに遷移し音楽再生を停止します。

AUDCMD_SETREADYSTATUS コマンドによって、Ready状態にのみ遷移します。

Recorder状態:

Mic、I2Sから入力された音声データを圧縮して、SDカードなどのストレージに書き出したり、WiFi/LTE などのネットワークに打ち上げて記録する機能を実現する状態です。 状態の中にRecorderReady状態とRecorderActive状態の2つのサブ状態を持ちます。 RecorderReady状態は、音声記録停止の状態です。AUDCMD_STARTREC によってRecorderActiveに遷移し音声記録動作を行います。 RecorderActive状態は、音声記録中の状態です。AUDCMD_STOPREC によってRecorderReadyに遷移し音声記録を停止します。

AUDCMD_SETREADYSTATUS コマンドによって、Ready状態にのみ遷移します。

Baseband状態:

Mic、または、I2Sから入力された音声データを、内部でエフェクト処理を行い、AnalogOut、または、I2Sに出力する機能を実現する状態です。 状態の中にBasebandReady状態とBasebandActive状態の2つのサブ状態を持ちます。 BasebandReady状態は、音声入出力停止の状態です。AUDCMD_STARTBB によってBasebandActiveに遷移し音声入出力動作を開始します。 RecorderActive状態は、音声入出力動作中状態です。AUDCMD_STOPBB によってBasebandReadyに遷移し音声入出力動作を停止します。

AUDCMD_SETREADYSTATUS コマンドによって、Ready状態にのみ遷移します。

現在のファームウェアでは、Baseband状態は未対応です。
メモリ管理とタスク間同期について
Memory Manager Library

AudioSubSystemは、使用するデータ領域を特殊な管理方法で管理します。 MemoryUtilityのMemoryManagerと呼ばれるライブラリは、Memory Layout定義ファイルのLayout情報に従い、必要なメモリエリアを固定長のメモリプールとして確保します。 このLayout情報は複数定義することができ、Layout番号を指定して切り替えることで、機能ごとの必要メモリを確保することができます。 Layout情報は、Applicationのニーズに従って自由に決めてもらうものになりますが、各機能で最低限必要なリソースはありますので、ご注意ください。

詳細は、MemoryManagerのライブラリ説明をご参照ください。

また、各機能に合わせた必要なLayout情報に関しては、各exampleの説明をご参照下さい。

AudioSubSystem内の、各オブジェクトは、必要なメモリエリアのセグメントを指し示すMemHandleのインスタンスを生成することで、それに紐付くメモリセグメントを確保し、そこを利用します。

Get memHandle

データパイプラインの次に位置するオブジェクトに、このMemHandleのインスタンスを渡していくことで、確保されたエリアを次のオブジェクトが使用ることができ、不要になった場合、このインスタンスを破棄することで、メモリ領域が解放されます。

インスタンスはコピーでき、必要なオブジェクトが各自メモリが必要な間インスタンスを確保し、不要になったら各自のタイミングで破棄したとしても、安全にメモリを確保・解放することができます。

Copy memHandle

セグメントの使用が不要になった際、非同期に実行されるオブジェクトは、メモリ管理を意識することなく、インスタンスを破棄することで、暗黙の裡に参照が外れます。

Use memHandle

これにより、非同期オブジェクト間でのメモリ管理を簡便に行っています。 すべての参照がなくなったら、メモリを開放します。

Release memHandle

Layout情報は、Applicationが使うためのヘッダファイル群として、あらかじめ用意する必要があります。 これらのヘッダファイルは、Memory Layout定義ファイル(mem_layout.conf)を作成し、ツールを使うことで、生成されます。

  使: ruby -Itool_path mem_layout.conf layout_header fence_header pool_header
各引数の説明は下記の通りです。
-Itool_path

mem_layout.rbのパス

mem_layout.conf

Memory Layout定義ファイル

layout_header

各種定数値が、C言語のマクロとして出力されるヘッダファイル

fence_header

FixedAreaのメモリフェンスアドレスが出力されるヘッダファイル

pool_header

PoolAreaの各種定義が出力されるヘッダファイル

Message Library

このメモリ管理機構を使用するうえで、各タスク間でのクラスオブジェクトの送受信が必要になります。これを実現するため、タスク同期機構にクラスインスタンスの送受信を可能にしたmessageライブラリを用意しており、AudioSubSystemは、これを利用しています。

各タスクにあるオブジェクトに送受信先のIDを付加していくことで、送受信したいタスクへの送信が可能になります。

例えば、送信する場合は、送信先のIDにオブジェクトを送信し、受信側のタスクは、自分のIDの送信要求が発生したときのみ、受信されることになります。 受信するまでは、そのタスクはsleepして待ちます。

これにより、AudioSubSystemは、イベント駆動でのオブジェクト設計を行っています。

Messageに関しては、Messageを使うためのヘッダファイル群をあらかじめ用意する必要があります。 これらのヘッダファイルは、MessageQueueLayout定義ファイル(msgq_layout.conf)を作成し、ツールを使うことで、生成されます。

  使: ruby -Itool_path msgq_layout.conf area_address area_size id_header pool_header
各引数の説明は下記の通りです。
-Itool_path

msgq_layout.rbのパス

msgq_layout.conf

Message Layout定義ファイル

area_address

Message領域のアドレス

area_size

Message領域のサイズ

id_header

MessageQueueIDマクロが出力されるファイル

pool_header

MessageQueuePoolの定義が出力されるファイル

詳細は、Message Libraryのライブラリ説明をご参照ください。

Simple FIFO Library

AudioSubSystem とユーザアプリケーションとの間でのオーディオデータの受け渡しを行う場合、Simple FIFOを用います。このFIFOは、単純なFIFOであり、特に特筆すべきものはありません。

詳細は、Simple FIFOのライブラリ説明をご参照ください。

各機能の詳細
Audio Player Functions

Audio Player の簡単なデータの流れを以下に示します。

Audio Player Dataflow
図 18. Audio Player Dataflow

オーディオ・サブシステムがPlayerModeで動作する場合、User Applicationは、FIFOにESデータを入力します。 一定以上たまった状態で、Playerを起動すると、発音時間に合わせて、このESデータを消費していきます。このFIFOがUnderflowしない限り、音声データは途切れることなく発音します。

Playerは、2つのインスタンスを生成することが可能です。それぞれでデコードした音声は、OutputMixerで、Mixingして発音します。

データフロー内部は、Messageで通信します。 Message通信は、各クライアントごとにIDを持ちます。 Audio Playerの場合、exampleにあるサンプルLayouをもとに、IDを示すと以下のようになります。

User Application                       : MSGQ_AUD_APP
Audio Manager                          : MSGQ_AUD_MNG
Audio Player (Main Sound)              : MSGQ_AUD_PLY
Audio Player (Effect Sound)            : MSGQ_AUD_SFX
Output Mixer                           : MSGQ_AUD_OUTPUT_MIX
Audio DSP                              : MSGQ_AUD_DSP
Rendering Component(Main Sound)        : MSGQ_AUD_RND_PLY
Rendering Component(Effect Sound)      : MSGQ_AUD_RND_SFX
Rendering Component Sync(Main Sound)   : MSGQ_AUD_RND_PLY_SYNC
Rendering Component Sync(Effect Sound) : MSGQ_AUD_RND_SFX_SYNC
Post Filter (Channel0)                 : MSGQ_AUD_PFDSP0
Post Filter (Channel1)                 : MSGQ_AUD_PFDSP1
MSGQ_AUD_RND_PLY/SFX_SYNCは削除されます。
Audio Player Message ID
図 19. Audio Player Message ID

また、各データのデータ領域は、以下になります。

ES Data (Main Sound)                             : DEC_ES_MAIN_BUF_POOL
ES Data (Effect Sound)                           : DEC_ES_SFX_BUF_POOL
PCM Data (Main Sound)                            : REND_PCM_BUF_POOL
PCM Data (Effect Sound)                          : REND_PCM_SFX_BUF_POOL
Audio Decoder DSP Command                        : DEC_APU_CMD_POOL
SamplingRateConverter Work Buffer (Main Sound)   : SRC_WORK_BUF_POOL
SamplingRateConverter Work Buffer (Effect Sound) : SRC_WORK_SFX_BUF_POOL
Post Filter PCM Data (Channel0)                  : PF0_PCM_BUF_POOL
Post Filter PCM Data (Channel1)                  : PF1_PCM_BUF_POOL
Post Filter DSP Command (Channel0)               : PF0_APU_CMD_POOL
Post Filter DSP Command (Channel1)               : PF1_APU_CMD_POOL
Audio Player Pool ID
図 20. Audio Player Pool ID

これらのIDを生成時に指定する必要があります。

How to use
Preparation

"AudioManager", "MediaPlayerObject", "OuputpuMixerObject", "RendererComponent" と呼ばれる
オーディオ・サブシステムを制御するために設計されたソフトウェアコンポーネントで、Audio Player を実現します。

そのため、Playerを実現するには、以下のオブジェクトの生成関数を事前に呼ぶ必要があります。

Create AudioManager

AudioManager を有効にするには、AS_CreateAudioManager(AudioSubSystemIDs, AudioAttentionCb) を呼ぶ必要があります。
AudioSubSystemIDs の中で、Message Library Configuration で定義された MsgQueID を指定する必要があります。
0xFF が指定された項目は使用しないことを意味します。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。NULLを指定した場合、通知は行われません。

static void attention_callback(const ErrorAttentionParam *attparam)
{
  ...
}

AudioSubSystemIDs ids;

ids.app         = MSGQ_AUD_APP;
ids.mng         = MSGQ_AUD_MNG;
ids.player_main = MSGQ_AUD_PLY;
ids.player_sub  = MSGQ_AUD_SFX;
ids.mixer       = MSGQ_AUD_OUTPUT_MIX;
ids.recorder    = 0xFF;
ids.effector    = 0xFF;
ids.recognizer  = 0xFF;

AS_CreateAudioManager(ids, attention_callback);
Create MediaPlayerObject

MediaPlayerObject を有効にするには、AS_CreatePlayerMulti(AsPlayerId, AsCreatePlayerParam_t, AudioAttentionCb) を呼ぶ必要があります。
AsPlayerId には、2つあるPlayer (AsPlayerIdAS_PLAYER_ID_0, AS_PLAYER_ID_1) のいずれかを指定します。2つのPlayerを使用する場合は、それぞれCreateして下さい。
AsCreatePlayerParam_t の中で、Message Library Configuration で定義された MsgQueID と、Memory Manager Configuration で定義された PoolId を指定する必要があります。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。AudioManagerを使用しない場合に指定して下さい。AS_CreateAudioManagerでコールバック関数を登録した場合、NULLを指定した場合は通知は行われません。

static void attention_callback_from_player0(const ErrorAttentionParam *attparam)
{
  ...
}

static void attention_callback_from_player1(const ErrorAttentionParam *attparam)
{
  ...
}

AsCreatePlayerParam_t cparam;

cparam.msgq_id.player = MSGQ_AUD_PLY;
cparam.msgq_id.mng    = MSGQ_AUD_MNG;
cparam.msgq_id.mixer  = MSGQ_AUD_OUTPUT_MIX
cparam.msgq_id.dsp    = MSGQ_AUD_DSP;
cparam.pool_id.es     = DEC_ES_MAIN_BUF_POOL;
cparam.pool_id.pcm    = REND_PCM_BUF_POOL;
cparam.pool_id.dsp    = DEC_APU_CMD_POOL;
cparam.pool_id.src_work = SRC_WORK_BUF_POOL;

bool act_rst = AS_CreatePlayerMulti(AS_PLAYER_ID_0, &cparam, attention_callback_from_player0);

cparam.msgq_id.player = MSGQ_AUD_SFX;
cparam.msgq_id.mng    = MSGQ_AUD_MNG;
cparam.msgq_id.mixer  = MSGQ_AUD_OUTPUT_MIX
cparam.msgq_id.dsp    = MSGQ_AUD_DSP;
cparam.pool_id.es     = DEC_ES_SFX_BUF_POOL;
cparam.pool_id.pcm    = REND_PCM_SFX_BUF_POOL;
cparam.pool_id.dsp    = DEC_APU_CMD_POOL;
cparam.pool_id.src_work = SRC_WORK_SFX_BUF_POOL;

act_rst = AS_CreatePlayerMulti(AS_PLAYER_ID_1, &cparam, attention_callback_from_player1);
Create OutputMixerObject

OutputMixerObject を有効にするには、AS_CreateOutputMixer(AsCreateOutputMixParam_t) を呼ぶ必要があります。
AsCreateOutputMixParam_t の中で、AMessage Library Configuration で定義された MsgQueID と、Memory Manager Configuration で定義された PoolId を指定する必要があります。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。AudioManagerを使用しない場合に指定して下さい。AS_CreateAudioManagerでコールバック関数を登録した場合、NULLを指定した場合は通知は行われません。

static void attention_callback_from_outputmixer(const ErrorAttentionParam *attparam)
{
  ...
}

AsCreateOutputMixParam_t cparam;

cparam.msgq_id.mixer                   = MSGQ_AUD_OUTPUT_MIX;
cparam.msgq_id.render_path0_filter_dsp = MSGQ_AUD_PFDSP0;
cparam.msgq_id.render_path1_filter_dsp = MSGQ_AUD_PFDSP1;
cparam.pool_id.render_path0_filter_pcm = PF0_PCM_BUF_POOL;
cparam.pool_id.render_path1_filter_pcm = PF1_PCM_BUF_POOL;
cparam.pool_id.render_path0_filter_dsp = PF0_APU_CMD_POOL;
cparam.pool_id.render_path1_filter_dsp = PF1_APU_CMD_POOL;

result = AS_CreateOutputMixer(&output_mix_act_param, attention_callback_from_outputmixer);
Create RendererComponent

RendererComponent を有効にするには、AS_CreateRenderer(AsCreateRendererParam_t) を呼ぶ必要があります。
AsCreateRendererParam_t の中で、Message Library Configuration で定義された MsgQueID と、Memory Manager Configuration で定義された PoolId を指定する必要があります。
もしアプリケーションがPlayerを1つしか使わない場合は、3つめと4つめの引数(dev1_req, dev1_sync)を 0xFF に設定する必要があります。

AsCreateRendererParam_t renderer_act_param;
cparam.msgq_id.dev0_req  = MSGQ_AUD_RND_PLY;
cparam.msgq_id.dev0_sync = MSGQ_AUD_RND_PLY_SYNC;
cparam.msgq_id.dev1_req  = MSGQ_AUD_RND_SFX;
cparam.msgq_id.dev1_sync = MSGQ_AUD_RND_SFX_SYNC;

result = AS_CreateRenderer(&renderer_act_param);
将来的には、HighLevelAPIでの生成関数は、AudioManagerのみになります。
Initialize and Status change

必要なオブジェクトが生成されたら、Player動作を行わせるためにAudioのHWの設定や電源On、動作モードの変更などの初期化処理を行います。

以下のコマンドを順に発行することで、実現が可能です。

Power on Audio SubSystem

Audioブロックに電源を入れるために、AUDCMD_POWERON, PowerOnParamコマンドを発行することで、電源を入れてAudioSubSystemの状態をReady状態に遷移します。 
enable_sound_effectは、AS_DISABLE_SOUNDEFFECT固定としてください。

  AudioCommand command;
  command.header.packet_length = LENGTH_POWERON;
  command.header.command_code  = AUDCMD_POWERON;
  command.header.sub_code      = 0x00;
  command.power_on_param.enable_sound_effect = AS_DISABLE_SOUNDEFFECT;
  AS_SendAudioCommand(&command);
Initialize output device

PowerOnを行い、Ready状態に遷移したら、AUDCMD_INITOUTPUTSELECT, InitOutputSelectParam コマンドでMixerからの出力先の選択を行います。

output_device_selの設定は以下の通りです。

output_device_sel
  AS_OUT_OFF : 出力OFF
  AS_OUT_SP  : スピーカーからの出力
  AS_OUT_I2S : I2Sからの出力
コマンド設定例
  AudioCommand command;
  command.header.packet_length = LENGTH_INITOUTPUTSELECT;
  command.header.command_code  = AUDCMD_INITOUTPUTSELECT;
  command.header.sub_code      = 0x00;
  command.init_output_select_param.output_device_sel = AS_OUT_SP;
  AS_SendAudioCommand(&command);
AUDCMD_INITI2SPARAMは未対応です。I2Sの設定はKconfigから変更して下さい。
Set speaker driver mode

スピーカーを駆動するデジタルアンプの駆動能力を、AUDCMD_SETSPDRVMODE, SetSpDrvModeParam コマンドで設定することが出来ます。

駆動能力を示すmodeの設定は以下の通りです。

スピーカーの使用方法に関しては、ハードウェアドキュメントのスピーカーの使用方法を参照ください。

mode
  AS_SP_DRV_MODE_LINEOUT : 駆動能力 弱。ライン出力用。
  AS_SP_DRV_MODE_1DRIVER : 駆動能力 中。ヘッドホン出力用。
  AS_SP_DRV_MODE_4DRIVER : 駆動能力 強。スピーカー出力用。
コマンド設定例
  AudioCommand command;
  command.header.packet_length = LENGTH_SETSPDRVMODE;
  command.header.command_code  = AUDCMD_SETSPDRVMODE;
  command.header.sub_code      = 0x00;
  command.set_sp_drv_mode.mode = AS_SP_DRV_MODE_LINEOUT;
  AS_SendAudioCommand(&command);
Change to Player Status

AUDCMD_SETPLAYERSTATUS, SetPlayerStsParam コマンドでAudioSubSystemの状態をPlayer状態に遷移します。

各パラメータの設定は以下の通りです。

active_player
  AS_ACTPLAYER_MAIN : player0のみ再生
  AS_ACTPLAYER_SUB  : player1のみ再生
  AS_ACTPLAYER_BOTH : player0とplayer1をMixして再生
input_device
  AS_SETPLAYER_INPUTDEVICE_RAM:: RAMからの入力(固定)
ram_handler

SimpleFifoのハンドル情報のポインタを指定します。

simple_fifo_handler

CMN_SimpleFifoInitialize()で取得されたハンドラを指定します。

callback_function

PlayerObjectがSimpleFifoから読み出したイベントを通知するCallbackです。読みだしたデータのサイズが通知されます。

notification_threshold_size

PlayerObjectが何バイト読み出した時点で、callbackの通知を行うかを指定します。ここで指定したサイズ以上読みだした際に通知されます。 0を指定すると、PlayerObjectが読みだす度に通知します。

output_device
  AS_SETPLAYER_OUTPUTDEVICE_SPHP : スピーカーからの出力
  AS_SETPLAYER_OUTPUTDEVICE_I2S  : I2Sからの出力
output_deviceは未対応です。出力先の選択は、AUDCMD_INITOUTPUTSELECT (InitOutputSelectParam) コマンドで行ってください。
コマンド設定例
  AsPlayerInputDeviceHdlrForRAM input0_ram_handler;
  input0_ram_handler.simple_fifo_handler         = &input0_handle;
  input0_ram_handler.callback_function           = input0_device_callback;
  input0_ram_handler.notification_threshold_size = 0;

  AsPlayerInputDeviceHdlrForRAM input1_ram_handler;
  input1_ram_handler.simple_fifo_handler         = &input1_handle;
  input1_ram_handler.callback_function           = input1_device_callback;
  input1_ram_handler.notification_threshold_size = 0;
  AudioCommand command;
  command.header.packet_length = LENGTH_SET_PLAYER_STATUS;
  command.header.command_code = AUDCMD_SETPLAYERSTATUS;
  command.header.sub_code = 0x00;
  command.set_player_sts_param.active_player         = AS_ACTPLAYER_BOTH;
  command.set_player_sts_param.player0.input_device  = AS_SETPLAYER_INPUTDEVICE_RAM;
  command.set_player_sts_param.player0.ram_handler   = &input0_ram_handler;
  command.set_player_sts_param.player0.output_device = 0x00;
  command.set_player_sts_param.player1.input_device  = AS_SETPLAYER_INPUTDEVICE_RAM;
  command.set_player_sts_param.player1.ram_handler   = &input1_ram_handler;
  command.set_player_sts_param.player1.output_device = 0x00;
  AS_SendAudioCommand(&command);
player1を利用する場合は、AS_CreatePlayerMulti(AsPlayerId, AsCreatePlayerParam_t, AudioAttentionCb)で、 AS_PLAYER_ID_1 を有効にしてください。
Set volume

出力にスピーカーを設定した場合、AUDCMD_SETVOLUME, SetVolumeParam で音量を設定できます。 各パラメータの設定は以下の通りです。

I2Sでは音量は変更できません。

input1_db

player0の音量。dBを10倍の整数値で設定します。設定範囲は-1020(-102.0dB)から120(+12.0dB)で、ステップ幅5(0.5dB)で設定できます。

input2_db

player1の音量。設定範囲はinput1_dbと同じです。

master_db

player0とplayer1のMix後の音量。設定範囲はinput1_dbと同じです。

  AudioCommand command;
  command.header.packet_length = LENGTH_SETVOLUME;
  command.header.command_code  = AUDCMD_SETVOLUME;
  command.header.sub_code      = 0;
  command.set_volume_param.input1_db = 0;    /* 0.0dB */
  command.set_volume_param.input2_db = 0;    /* 0.0dB */
  command.set_volume_param.master_db = -200; /* -20.0dB */
  AS_SendAudioCommand(&command);
diag 44af99e80b64cd8bfe5e385d87fa81a3
図 21. Initial sequence
Initialize and Start player

音楽再生初期化及び開始シーケンスを示します。  

Initialize player

AUDCMD_INITPLAYER, PlayerCommand, AsInitPlayerParam で再生の初期設定を行います。

player_id

AsPlayerIdのインスタンスのIDを設定します。インスタンスは2つあり、どちらかを設定して下さい。

インスタンス番号 設定値

0

AS_PLAYER_ID_0

1

AS_PLAYER_ID_1

codec_type

再生コンテンツのコーデックの種別を設定して下さい。MP3, WAVに対応しています。

コーデック種別 設定値

MP3

AS_CODECTYPE_MP3

WAV

AS_CODECTYPE_WAV

MP3ファイルに関して、すべてのファイルに現時点で対応できていません。現在、ID3v2 TAG(特に画像データのような大きなメタデータ)がある場合、デコーダがparseエラーになります。
MP3Tag などのツールで、タグ情報を削除してください。
bit_length

再生コンテンツの1サンプルあたりのbit長を設定します。16bitと24bitに対応しています。

bit長 設定値

16

AS_BITLENGTH_16

24

AS_BITLENGTH_24

24bitのデコードができるメモリのLayoutが必要です。
channel_number

再生コンテンツのチャンネル数を設定します。モノラル(1ch), ステレオ(2ch)に対応しています。

チャンネル数 設定値

1

AS_CHANNEL_MONO

2

AS_CHANNEL_STEREO

sampling_rate

再生コンテンツのサンプリング周波数を設定します。コーデック種別ごとに設定可能な設定値が異なります。

サンプリング周波数 設定値 対応コーデック種別

16kHz

AS_SAMPLINGRATE_16000

MP3,WAV

32kHz

AS_SAMPLINGRATE_32000

MP3,WAV

44.1kHz

AS_SAMPLINGRATE_44100

MP3,WAV

48kHz

AS_SAMPLINGRATE_48000

MP3,WAV

88.2kHz

AS_SAMPLINGRATE_88200

WAV

96kHz

AS_SAMPLINGRATE_96000

WAV

176.4kHz

AS_SAMPLINGRATE_176400

WAV

192kHz

AS_SAMPLINGRATE_192000

WAV

自動判別

AS_SAMPLINGRATE_AUTO

MP3

AS_SAMPLINGRATE_AUTO は、ストリーム上のSyntaxからサンプリング周波数を自動判定して欲しいときに 使用します。現時点では、MP3のみ対応です。
ハイレゾリューションサンプリングレート、すなわち、AS_SAMPLINGRATE_88200AS_SAMPLINGRATE_96000AS_SAMPLINGRATE_176400 の場合、DSPをDualCore使用しWorking領域も大きく使用するため、Dual Decodeを行おうとする場合、DSP領域だけで384kB必要になります。必要に応じて、SDKのConfigurationを変更しDSP領域を変更して下さい。
dsp_path

DecoderのDSPバイナリイメージを格納している絶対パスを指定します。最大24文字です。

コマンド設定例
  AudioCommand command;
  command.header.packet_length = LENGTH_INIT_PLAYER;
  command.header.command_code  = AUDCMD_INITPLAYER;
  command.header.sub_code      = 0x00;
  command.player.player_id                 = AS_PLAYER_ID_0;
  command.player.init_param.codec_type     = AS_CODECTYPE_MP3;
  command.player.init_param.bit_length     = AS_BITLENGTH_16;
  command.player.init_param.channel_number = AS_CHANNEL_STEREO;
  command.player.init_param.sampling_rate  = AS_SAMPLINGRATE_48000;
  command.player.init_param.dsp_path       = "/mnt/sd0/bin";
  AS_SendAudioCommand(&command);
Start Player

AUDCMD_PLAYPLAYER, PlayerCommandで再生を開始します。 音楽再生を開始するとFIFOから圧縮音声データを読み出し始めます。
このため、音楽生成開始時までに、十分な量の圧縮音声データをFIFOに入力しておくようにしてください。

開始時に、十分な量のデータをFIFOに入力していないと、開始直後にUnderflowしてしまい音声再生が停止してしまいます。
player_id

AsPlayerIdのインスタンスのIDを設定します。AUDCMD_INITPLAYERで初期設定済みのインスタンスIDを 設定して下さい。

インスタンス番号 設定値

0

AS_PLAYER_ID_0

1

AS_PLAYER_ID_1

  AudioCommand command;
  command.header.packet_length = LENGTH_PLAY_PLAYER;
  command.header.command_code  = AUDCMD_PLAYPLAYER;
  command.header.sub_code      = 0x00;
  command.player.player_id     = AS_PLAYER_ID_0;
  AS_SendAudioCommand(&command);
diag a8509e15c2c648bf8d1db91d8477cc60
図 22. Player State sequence
Stop play

音声再生停止のシーケンスを示します。

Stop Player

AUDCMD_PLAYPLAYER, PlayerCommand, AsStopPlayerParamで再生を停止します。

player_id

AsPlayerIdのインスタンスのIDを設定します。AUDCMD_PLAYPLAYERで再生を停止したいインスタンスIDを指定してください。開始済みのインスタンスIDでなければいけません。

インスタンス番号 設定値

0

AS_PLAYER_ID_0

1

AS_PLAYER_ID_1

stop_mode

AsStopPlayerStopModeの停止モードを設定します。停止モードは通常停止とES終端停止、強制停止の3種類があります。
通常停止は、停止要求のタイミングでできるだけ早く停止します。すなわちFIFOの中身は残っている状態になります。
ES終端停止は、停止要求時点で、FIFOに入っているデータをすべて発音してから停止します。
強制停止は、Audio SubSystem内部でのエラー時に使用されるモードで、アプリケーションからは発行しません。

停止モード 設定値

通常停止

AS_STOPPLAYER_NORMAL

ES終端停止

AS_STOPPLAYER_ESEND

強制停止

AS_STOPPLAYER_FORCIBLY

  AudioCommand command;
  command.header.packet_length = LENGTH_STOP_PLAYER;
  command.header.command_code  = AUDCMD_STOPPLAYER;
  command.header.sub_code      = 0x00;
  command.player.player_id     = AS_PLAYER_ID_0;
  command.player.stop_param.stop_mode = AS_STOPPLAYER_NORMAL;
  AS_SendAudioCommand(&command);
diag 26a3281b7edddf7527816ed3a6748369
図 23. Stop sequence
Build Configurations

AudioPlayer の機能を使用するためには

$>cd sdk
$>tools/config.py -m

でConfig menu を開き、以下のConfigを設定する必要があります。

Select options in below:

[CXD65xx Configuration]
  [SDIO SD Card]                 <= Y (If use SD card)
  [Audio]                        <= Y

[SDK audio]                      <= Y
  [Audio Utilities]
    [Audio Player]               <= Y
      [Playlist manager]         <= Y (If use PlayList)

[Memory Manager]                 <= Y
  [Memory Utilities]             <= Y

[ASMP]                           <= Y
Error Attentions and Approach

音楽再生時の警告の一覧と、対処方法は以下の通りです。詳細は オーディオサブシステムのエラーについてを参照してください。

ID Attention Code Attention Level Approach

0x05

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW

WARNING

AudioSubSystemが再生データを読み込めなかったことが原因です。再生データをSimpleFIFOにWriteするタスクのCPU占有度を上げてください。

0x0D

AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR

ERROR

データ領域のセグメント数が不足したことが原因です。AudioSubSystem以外のタスクの優先度を下げるか、データ領域のセグメント数を増やしてください。

0x0F

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR

ERROR

ヒープ領域が不足していることが原因です。ヒープ領域を拡張して下さい。

0x18

AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR

ERROR

DSPバイナリのバージョンが異なることが原因です。DSP バイナリイメージを"sdk/modules/audio/dsp"のファイルで更新して下さい。

0x1A

AS_ATTENTION_SUB_CODE_STREAM_PARSER_ERROR

ERROR

再生ファイルにSync wordが見つからなかったことが原因です。再生ファイルと指定したコーデックが合っているか確認してください。

0x21

AS_ATTENTION_SUB_CODE_ALLOC_HEAP_MEMORY

WARNING

プール領域ではなく、ヒープ領域が使われたことが原因です。Sampling Rate Converterのwork bufferのプール領域(SRC_WORK_BUF_POOL)が設定されているか確認して下さい。

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW が発生した場合、音声再生が停止し、再生エラーの状態になります。 この状態が発生した場合は、直ちにAsStopPlayerParamコマンドを発行し、再生停止状態に遷移させてください。
再生停止に遷移後、FIFOのクリアを必ず行ってください。行わないとノイズが発生してしまいます。
DSP install
DSP binary image install

DSPバイナリイメージをKconfigで設定したパスに格納して下さい。バイナリイメージは、 sdk/modules/audio/dsp にあります。

表 17. Binary image required for audio player according to configuration:
Image size

MP3DEC

61kbyte

WAVDEC

32kbyte

ハイレゾリューションサンプリングレートの再生を行う場合、DSPを2 Core(1Coreあたり192kB)使用します。
※2Coreの場合、384kB。
使用するリソースにご注意ください。

Audio Player Example

音楽再生の簡単なサンプリアプリケーションとして、Audio Player exampleがあります。ここでは、その使い方などを説明します。

Preparation
Build Configurations (kconfig)

Audio Player のサンプルプログラムを使うには、build configurationを以下の設定をしてください。

[Examples]
  [Audio player example] <= Y

または、

$>cd sdk
$>tools/config.py examples/audio_player
Audio & Logical sensor example と他の複数のサンプルは同時に選択できません。複数選択するとコンパイルエラーが出ます。
Memory and Message Utility Configurations and Layout

タスク間通信ライブラリ(Message Library)とメモリ管理ライブラリ(Memory Manager)の設定は、以下のように行ってください。

Message Library Configuration

AudioPlayer機能を使用する際に必要となるMessageQueueの定義を行う必要があります。 定義はMessageQueueLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

Audio Player のexampleでは下記のように行います。

$>cd examples/audio_player/config
$>ruby -I../../../sdk/modules/memutils/message/tool msgq_layout.conf 0x000fe000 0x1000 msgq_id.h msgq_pool.h

MessageQueueLayout定義ファイル(msgq_layout.conf)の記述内容は下記の通りです。

MsgQuePool
 # ID,                        n_size  n_num  h_size  h_nums
  ["MSGQ_AUD_MNG",            88,      4,    0,      0],
  ["MSGQ_AUD_APP",            40,      2,    0,      0],
  ["MSGQ_AUD_DSP",            20,      5,    0,      0],
  ["MSGQ_AUD_PFDSP0",         20,      5,    0,      0],
  ["MSGQ_AUD_PFDSP1",         20,      5,    0,      0],
  ["MSGQ_AUD_PLY",            48,      5,    0,      0],
  ["MSGQ_AUD_SFX",            48,      5,    0,      0],
  ["MSGQ_AUD_OUTPUT_MIX",     48,      8,    0,      0],
  ["MSGQ_AUD_RND_PLY",        32,     16,    0,      0],
  ["MSGQ_AUD_RND_PLY_SYNC",   16,      8,    0,      0],
  ["MSGQ_AUD_RND_SFX",        32,     16,    0,      0],
  ["MSGQ_AUD_RND_SFX_SYNC",   16,      8,    0,      0],

各パラメータの説明は以下の通りです。

パラメータ 説明

ID

メッセージキュープールIDの名称を、"MSGQ_"で始まる文字列で指定。

n_size

通常優先度キューの各要素のバイト数(8以上512以下)。固定ヘッダ長(8byte) + パラメタ長を4の倍数で指定する。

n_num

通常優先度キューの要素数(1以上16384以下)。

h_size

高優先度キューの各要素のバイト数(0または、8以上512以下)。未使用時は0を指定すること。

h_num

高優先度キューの要素数(0または、1以上16384以下)。未使用時は0を指定すること。

各IDはAudio Player FunctionsのAudio Player Message IDを参照してください。

n_sizeは最適値となっているため、変更は行わないでください。

n_numも変更の必要はありませんが、他のApplicationでAudioPlayer機能を使う場合は、負荷を考慮して値を増やす必要が出てくる可能性があります。

h_size, h_numsはAudioPlayer機能を優先的に処理したい場合に利用して下さい。

それぞれの定義の詳細については、 examples/audio_player/config/msgq_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。
Memory Manager (Intelligent Fix Pool) Configuration

AudioPlayer機能を使用する際に必要となるMemoryLayout(pool)の定義を行う必要があります。
定義はMemoaryLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

Audio Player のexampleでは下記のように行います。

$>cd examples/audio_player/config
$>ruby -I../../../sdk/modules/memutils/memory_manager/tool -I. mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定義ファイル(mem_layout.conf)の記述内容は下記の通りです。

FixedAreas
FixedAreas
 # name,                  device,     align,        size,         fence
  ["AUDIO_WORK_AREA",     "AUD_SRAM", U_STD_ALIGN,  0x0003e000,   false], # Audio work area
  ["MSG_QUE_AREA",        "AUD_SRAM", U_STD_ALIGN,  0x00001000,   false], # message queue area
  ["MEMMGR_WORK_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000200,   false], # MemMgrLite WORK Area
  ["MEMMGR_DATA_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000100,   false], # MemMgrLite DATA Area

各パラメータの説明は以下の通りです。

パラメータ 説明

name

領域名(英大文字で始まり、"_AREA"で終わる名称。英大文字, 数字, _が使用可能)

device

領域を確保するMemoryDevicesのデバイス名

align

領域の開始アライメント。0を除くMinAlign(=4)の倍数を指定する

size

領域のサイズ。0を除く4の倍数の値を指定する

fence

フェンスの有効・無効を指定する(この項目は、UseFenceがfalseの場合は無視される)

各nameの用途は以下の通りです。

AUDIO_WORK_AREA

AudioSubSystemが利用する

MSG_QUE_AREA

MessageQueueが利用する(固定名)。msgq_id.hの(MSGQ_END_DRM - MSGQ_TOP_DRAM)のサイズを超えないこと。

MEMMGR_WORK_AREA

Memory Managerが利用する作業領域(固定名, 固定サイズ)

MEMMGR_DATA_AREA

Memery Managerが利用するデータ領域(固定名, 固定サイズ)

各nameの合計のサイズがmpshm_init(), mpshm_remap()で確保するシェアメモリのサイズを超えないようにしてください。

Fixed Areas can not be customized
PoolAreas
PoolAreas
 # name,                    area,              align,        pool-size,                    seg,                        fence
  ["DEC_ES_MAIN_BUF_POOL",  "AUDIO_WORK_AREA", U_STD_ALIGN,  U_DEC_ES_MAIN_BUF_POOL_SIZE,  U_DEC_ES_MAIN_BUF_SEG_NUM,  true ],
  ["REND_PCM_BUF_POOL",     "AUDIO_WORK_AREA", U_STD_ALIGN,  U_REND_PCM_BUF_POOL_SIZE,     U_REND_PCM_BUF_SEG_NUM,     true ],
  ["DEC_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  U_DEC_APU_CMD_POOL_SIZE,      U_DEC_APU_CMD_SEG_NUM,      true ],
  ["SRC_WORK_BUF_POOL",     "AUDIO_WORK_AREA", U_STD_ALIGN,  U_SRC_WORK_BUF_POOL_SIZE,     U_SRC_WORK_BUF_SEG_NUM,     true ],
  ["PF0_PCM_BUF_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  U_POF_PCM_BUF_SIZE,           U_POF_PCM_BUF_SEG_NUM,      true ],
  ["PF1_PCM_BUF_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  U_POF_PCM_BUF_SIZE,           U_POF_PCM_BUF_SEG_NUM,      true ],
  ["PF0_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  U_DEC_APU_CMD_POOL_SIZE,      U_DEC_APU_CMD_SEG_NUM,      true ],
  ["PF1_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  U_DEC_APU_CMD_POOL_SIZE,      U_DEC_APU_CMD_SEG_NUM,      true ],

各パラメータの説明は以下の通りです。

パラメータ 説明

name

プール名(英大文字で始まり、"_POOL"で終わる名称。英大文字, 数字, _が使用可能)

area

プール領域として使用するFixedAreaの領域名。領域はRAMに配置されていること

align

プールの開始アライメント。0を除くMinAlign(=4)の倍数を指定する

pool-size

プールのサイズ。0を除く4の倍数の値。Basicプールでは、セグメントサイズ * セグメント数

seg

セグメント数。1以上、255以下の値を指定する

fence

フェンスの有効・無効を指定する。この項目は、UseFenceがfalseの場合は無視される

各nameの用途は以下の通りです。

DEC_ES_MAIN_BUF_POOL

player0用入力データの格納用バッファ領域

REND_PCM_BUF_POOL

player0用Decode済みデータの出力用バッファ領域

DEC_APU_CMD_POOL

DSP(Decoder)用のコマンド領域

SRC_WORK_BUF_POOL

DSP(SamplingRateConverter)のワークバッファ領域

PF0_PCM_BUF_POOL

PostFilter0用のバッファ領域

PF1_PCM_BUF_POOL

PostFilter1用のバッファ領域

PF0_APU_CMD_POOL

PostFilter0用のコマンド領域

PF1_APU_CMD_POOL

PostFilter1用のコマンド領域

それぞれの定義の詳細については、 examples/audio_player/config/mem_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。
表 18. Only support the following format
sampling rate PCM bit length channel number CPU frequency lock

mp3

16kHz / 32kHz 44.1kHz / 48kHz

16bit

1ch / 2ch

High voltage

wav (Low Power)

16kHz / 32kHz 44.1kHz / 48kHz

16bit

1ch/2ch

Low voltage

wav

48kHz / 88.4kHz / 96kHz / 176.4kHz / 196kHz

16bit/24bit

1ch/2ch

High voltage

DSP and Sound files
Music file

"AUDIO/" ディレクトリをSDカードのルートディレクトリに生成し、 音楽ファイルをコピーしてください。

Playlist

再生したい音楽ファイルのリストを管理します。csv ファイルからデータベースを生成します。ファイル名は "TRACK_DB.CSV" とします。

"PLAYLIST/" ディレクトリを SDカードのルートディレクトリに生成し、"TRACK_DB.CSV" をコピーします。

"TRACK_DB.CSV"のフォーマット
[filename],[artist],[album],[channel number],[bit length],[sampling rate],[file format]
   ABC.mp3,artist1,album1,2,16,44100,mp3
exampleはPlaylistを使う前提となっています。再生されるのはリストの1行目のみです。
Using SPI-Flash instead of SD Card

ファイルシステムに SPI-Flashを使いたい場合、exampleの再生ファイル、Playlist、DSPバイナリイメージのパス指定を"/mnt/spif/*"に変更してください。 また、再生ファイル、Playlist、DSPバイナリイメージを変更したパスにコピーして下さい。

How to execute

NuttShell から player アプリケーションを起動します。

nsh> player

playerアプリケーションが起動し、次のログが表示されます。

Start AudioPlayer example

PlayListの先頭のファイルの再生が開始されます。

sdカードを認識できない場合は、次のエラーログが表示されます。sdカードの状態を確認して下さい。

Error: /mnt/sd0/AUDIO directory path error. check the path!
Error: app_open_contents_dir() failure.
Exit AudioPlayer example

PlayListを認識できない場合は、次のエラーログが表示されます。PlayListのpathが正しいか確認してください。

Track db(playlist) /mnt/sd0/PLAYLIST/TRACK_DB.CSV open error. check paths and files!
/mnt/sd0/PLAYLIST/alias_list_alltrack.bin cannot opened.

PlayFileを認識できない場合は、次のエラーログが表示されます。pathにFileがあるかどうか、またはPlayListとFile名が一致しているかを確認して下さい。

Error: /mnt/sd0/AUDIO/***.mp3 open error. check paths and files!
Error: app_start_player() failure.

SamplingRateConverterのwork bufferのプール領域(SRC_WORK_BUF_POOL)を設定しない場合は、次の警告ログが表示されます。プール領域の代わりにヒープ領域が使用され、フラグメンテーションが発生する可能性があります。AS_CreatePlayerMultiでSRC_WORK_BUF_POOLを設定してください。

Attention: module[5] attention id[1]/code[33] (objects/media_player/media_player_obj.cpp L****)

10秒再生後、Playerアプリケーションは終了します

Exit AudioPlayer example
Audio Recorder Functions

Audio Recorder の簡単なデータの流れを以下に示します。

Audio Recorder Dataflow
図 24. Audio Recorder Dataflow.

Audio SubSystemがRecorderModeで動作する場合、User Applicationは、 ESデータを格納するためのFIFOを用意する必要があります。 音声データの記録を開始すると、一定時間動作後、このFIFOに音声データがたまります。この音声データは、指定された圧縮フォーマットにエンコードされており、をFIFOから適宜読みだし、FIFOから溢れないようにすることで、連続音声データを取得することができます。

Recorderは、HWとしては、2系統キャプチャが可能ですが、現時点では、2つのインスタンスを生成し、2系統記録する機能には未対応です。

User Applicationは、この音声を各システムの要求に合わせて、(例えば、Strageに書き出し記録したり、Connectivityモジュールに送ってクラウド処理するなど。)処理を行うことで、Recorderアプリケーションを実現します。

データフロー内部は、Messageで通信します。 Message通信は、各クライアントごとにIDを持ちます。 Audio Recorderの場合、exampleにあるサンプルLayouをもとに、IDを示すと以下のようになります。

User Application           : MSGQ_AUD_APP
Audio Manager              : MSGQ_AUD_MGR
Audio Recorder             : MSGQ_AUD_RECORDER
Audio Capture Component    : MSGQ_AUD_CAP
Audio DSP                  : MSGQ_AUD_DSP

※MSGQ_AUD_CAP_SYNCは削除されます。

Audio Recorder Message ID
図 25. Audio Recorder Message ID

また、各データのデータ領域は、以下になります。

PCM (Input) Data Buffer    : INPUT_BUF_POOL
ES Data Buffer (for DSP)   : ES_BUF_POOL
Audio Encoder DSP Command  : ENC_APU_CMD_POOL
Audio Recorder Pool ID
図 26. Audio Recorder Pool ID

これらのIDを生成時に指定する必要があります。

How to use
Preparation

"AudioManager", "MediaRecorderObject", "CaptureComponent" と呼ばれる オーディオ・サブシステムを制御するために設計されたソフトウェアコンポーネントで、Audio Recorder を実現します。

Create AudioManager

AudioManager を有効にするには AS_CreateAudioManager(AudioSubSystemIDs) を呼ぶ必要があります。
AudioSubSystemIDs の中で、Message Library Configuration で定義された MsgQueID を指定する必要があります。 0xFF が指定された項目は使用しないことを意味します。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。NULLを指定した場合、通知は行われません。

static void attention_callback(const ErrorAttentionParam *attparam)
{
  ...
}

AudioSubSystemIDs ids;

ids.app         = MSGQ_AUD_APP;
ids.mng         = MSGQ_AUD_MGR;
ids.player_main = 0xFF;
ids.player_sub  = 0xFF;
ids.mixer       = 0xFF;
ids.recorder    = MSGQ_AUD_RECORDER;
ids.effector    = 0xFF;
ids.recognizer  = 0xFF;

AS_CreateAudioManager(ids, attention_callback);
Create MediaRecorderObject

MediaRecorderObject を有効にするには AS_CreateMediaRecorder(AsActRecorderParam_t) を呼ぶ必要があります。 Message Library Configuration で定義された MsgQueID と、Memory Manager Configuration で定義された PoolId を指定する必要があります。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。AudioManagerを使用しない場合に指定して下さい。AS_CreateAudioManagerでコールバック関数を登録した場合、NULLを指定した場合は通知は行われません。

static void attention_callback_from_recorder(const ErrorAttentionParam *attparam)
{
  ...
}

AsActRecorderParam_t cparam;

cparam.msgq_id.recorder      = MSGQ_AUD_RECORDER;
cparam.msgq_id.mng           = MSGQ_AUD_MGR;
cparam.msgq_id.dsp           = MSGQ_AUD_DSP;
cparam.pool_id.input         = INPUT_BUF_POOL;
cparam.pool_id.output        = ES_BUF_POOL;
cparam.pool_id.dsp           = ENC_APU_CMD_POOL;

result = AS_CreateMediaRecorder(&cparam, attention_callback_from_recorder);
Activate CaptureComponent

CaptureComponent を有効にするには AS_CreateCapture(AsActCaptureParam_t)を呼ぶ必要があります。 Message Library Configuration で定義された MsgQueID と、Memory Manager Configuration で定義された PoolId を指定する必要があります。 もしアプリケーションが 2つ目のチャンネルを使わない場合は、3つめと4つめの引数を 0xFF に設定する必要があります。

AsActCaptureParam_t capture_act_param;

cparam.msgq_id.dev0_req  = MSGQ_AUD_CAP;
cparam.msgq_id.dev0_sync = MSGQ_AUD_CAP_SYNC;
cparam.msgq_id.dev1_req  = 0xFF;
cparam.msgq_id.dev1_sync = 0xFF;

result = AS_CreateCapture(&cparam);
Initialize and Change state

必要なオブジェクトが生成されたら、Recorder動作を行わせるためにAudioのHWの設定や電源On、動作モードの変更などの初期化処理を行います。

以下のコマンドを順に発行することで、実現が可能です。

Power on Audio SubSystem

Audioブロックに電源を入れるために、AUDCMD_POWERON, PowerOnParamコマンドを発行することで、電源を入れてAudioSubSystemの状態をReady状態に遷移します。 

enable_sound_effect

enable_sound_effectは、AS_DISABLE_SOUNDEFFECT固定となります。

AS_DISABLE_SOUNDEFFECT: SoundEffect無効
コマンド設定例
AudioCommand command;
command.header.packet_length = LENGTH_POWERON;
command.header.command_code  = AUDCMD_POWERON;
command.header.sub_code      = 0x00;
command.power_on_param.enable_sound_effect = AS_DISABLE_SOUNDEFFECT;
AS_SendAudioCommand(&command);
Initialize Mic Gain

AUDCMD_INITMICGAINでMicのGainを設定します。

init_mic_gain_param[]

アナログマイクの場合、dB値を10倍にした値を、5の倍数で0(0.0dB)~210(21.0dB)の範囲で設定できます。デフォルト値は0.0dBです。
デジタルマイクの場合、dB値を100倍にした値を、-7850(-78.50dB)~0(0.00dB)の範囲で設定できます。デフォルト値は-78.50dBです。
Gainの値を変更したくない場合は、'AS_MICGAIN_HOLD'を指定してください。

コマンド設定例
AudioCommand command;
command->header.packet_length = LENGTH_INITMICGAIN;
command->header.command_code  = AUDCMD_INITMICGAIN;
command->header.sub_code      = 0;
command->init_mic_gain_param.mic_gain[0] = 210;
command->init_mic_gain_param.mic_gain[1] = 210;
command->init_mic_gain_param.mic_gain[2] = 210;
command->init_mic_gain_param.mic_gain[3] = 210;
command->init_mic_gain_param.mic_gain[4] = AS_MICGAIN_HOLD;
command->init_mic_gain_param.mic_gain[5] = AS_MICGAIN_HOLD;
command->init_mic_gain_param.mic_gain[6] = AS_MICGAIN_HOLD;
command->init_mic_gain_param.mic_gain[7] = AS_MICGAIN_HOLD;
AS_SendAudioCommand(&command);

mic_gain[]の各要素はマイクのIDに対応しています。マイクのIDはConfigの"MIC channel select map"の値で設定されます。デフォルトの設定は、アナログマイク1/2/3/4が設定されています。

以下に、configrationの情報を記載します。

MIC channel select map の設定
[CXD56xx Configuration]
  [Audio]
    [Audio baseband config settings]
      [CXD5247 settings]
        (0xFFFF4321) MIC channel select map

"MIC channel select map"の値は4bitごとにMICのIDを示します。
mic_gainの要素と"MIC channel select map"のbitフィールドの関係は下記の通りです。

mic_gainの要素 [7] [6] [5] [4] [3] [2] [1] [0]

bitフィールド

31-28

27-24

23-20

19-16

15-12

11-8

7-4

3-0

"MIC channel select map"の値(ID)とマイクの種別の関係は下記の通りです。

HEX値(ID) マイク種別

0x1

CXD5247アナログマイク1

0x2

CXD5247アナログマイク2

0x3

CXD5247アナログマイク3

0x4

CXD5247アナログマイク4

0x5

CXD5247デジタルマイク1

0x6

CXD5247デジタルマイク2

0x7

CXD5247デジタルマイク3

0x8

CXD5247デジタルマイク4

0x9

CXD5247デジタルマイク5

0xA

CXD5247デジタルマイク6

0xB

CXD5247デジタルマイク7

0xC

CXD5247デジタルマイク8

使用するマイクを要素0から順に設定して下さい。要素番号をSkipして設定することはできません。 アナログマイクとデジタルマイクの混合は対応していません。 アナログマイクを設定する場合は要素0-3を設定して下さい。 要素が偶数の場合、Lチャンネル、要素が奇数の場合、Rチャンネルとなります。

Change to Recorder Status

AUDCMD_SETRECORDERSTATUSでAudioSubSystemの状態をRecorder状態に遷移します。

input_device

記録対象の入力デバイスを指定します。AUDCMD_INITMICGAINで設定したマイク種別と合わせる必要があります。

AS_SETRECDR_STS_INPUTDEVICE_MIC_A  : CXD5247アナログマイク
AS_SETRECDR_STS_INPUTDEVICE_MIC_D  : CXD5247デジタルマイク
AS_SETRECDR_STS_INPUTDEVICE_I2S_IN : I2S入力
input_device_handler

現時点では0固定です。

output_device

エンコードしたESデータの出力先デバイスを指定します。
現時点ではRAMデバイスの出力のみサポートされます。

AS_SETRECDR_STS_OUTPUTDEVICE_RAM : RAMデバイスへ出力
output_device_handler

出力(Encoded ES data)の格納先SimpleFIFOのハンドラを指定します。
simple_fifo_handlerは、CMN_SimpleFifoInitialize()で取得されます。

コマンド設定例
AudioCommand command;
command.header.packet_length = LENGTH_SET_RECORDER_STATUS;
command.header.command_code  = AUDCMD_SETRECORDERSTATUS;
command.header.sub_code      = 0x00;
command.set_recorder_status_param.input_device          = AS_SETRECDR_STS_INPUTDEVICE_MIC_A;
command.set_recorder_status_param.input_device_handler  = 0x00;
command.set_recorder_status_param.output_device         = AS_SETRECDR_STS_OUTPUTDEVICE_RAM;
command.set_recorder_status_param.output_device_handler = &s_recorder_info.fifo.output_device;
AS_SendAudioCommand(&command);
Start Recording

音声記録開始シーケンスを示します。

Init recorder information

AUDCMD_INITREC, RecorderCommand, AsInitRecorderParamで記録動作の設定をします。

sampling_rate
AS_SAMPLINGRATE_8000  : 8kHz
AS_SAMPLINGRATE_16000 : 16kHz
AS_SAMPLINGRATE_48000 : 48kHz
channel_number
AS_CHANNEL_MONO   : Monoral
AS_CHANNEL_STEREO : Stereo
AS_CHANNEL_4CH    : 4ch
AS_CHANNEL_6CH    : 6ch
AS_CHANNEL_8CH    : 8ch
bit_length
AS_BITLENGTH_16 : 16bit
AS_BITLENGTH_24 : 24bit
codec_type
AS_CODECTYPE_MP3  : MP3
AS_CODECTYPE_LPCM : LinerPCM
bitrate

MP3エンコード時のみ有効

AS_BITRATE_8000   : 8000
AS_BITRATE_16000  : 16000
AS_BITRATE_24000  : 24000
AS_BITRATE_32000  : 32000
AS_BITRATE_40000  : 40000
AS_BITRATE_48000  : 48000
AS_BITRATE_56000  : 56000
AS_BITRATE_64000  : 64000
AS_BITRATE_80000  : 80000
AS_BITRATE_96000  : 96000
AS_BITRATE_112000 : 112000
AS_BITRATE_128000 : 128000
AS_BITRATE_144000 : 144000
AS_BITRATE_160000 : 160000
AS_BITRATE_192000 : 192000
AS_BITRATE_224000 : 224000
AS_BITRATE_256000 : 256000
AS_BITRATE_320000 : 320000
dsp_path

DecoderのDSPイメージを格納している絶対パスを指定します。最大24文字です。

入力デバイスとch数の組み合わせは制限が有ります。
入力 ch数

Mic

1ch(Monoral), 2ch(Stereo), 4ch(*1), 6ch(*2), 8ch(*2)

I2S

2ch(Stereo)

  • (*1. LPCMのみ)

  • (*2. LPCMかつDigitalMic使用時のみ)

Codec, bit長, サンプリング周波数, ビットレートの組み合わせには制限が有ります。
Codec bit長 サンプリング周波数 ビットレート

MP3

16bit

16kHz

8000(*1), 16000 〜 160000

48kHz

32000 〜 320000

LPCM

16bit

16kHz, 48kHz

-

24bit(*2)

16kHz, 48kHz, 192kHz(*2)

-

  • (*1. 1ch指定時)

  • (*2. 要 HiResoモード指定)

コマンド設定例
AudioCommand command;
command.header.packet_length = LENGTH_INIT_RECORDER;
command.header.command_code  = AUDCMD_INITREC;
command.header.sub_code      = 0x00;
command.recorder.init_param.sampling_rate  = s_recorder_info.file.sampling_rate;
command.recorder.init_param.channel_number = s_recorder_info.file.channel_number;
command.recorder.init_param.bit_length     = AS_BITLENGTH_16;
command.recorder.init_param.codec_type     = AS_CODECTYPE_OPUS;
command.recorder.init_param.bitrate        = AS_BITRATE_8000;
command.recorder.init_param.computational_complexity = AS_INITREC_COMPLEXITY_0
command.recorder.init_param.dsp_path       = "/mnt/sd0/bin";
diag 1af7990e157cd98907a82587fc886a53
図 27. 記録初期化シーケンス
Start Recorder

AUDCMD_STARTRECで記録を開始します。

記録を開始して少しすると、Audio Systemは、FIFOにESデータを書き込みます。 正しく音声データを記録するためには、書き込んだデータをFIFOがあふれる前に読み出す必要があります。
データの書き込みに関しては、通知されますので、このイベントに合わせて適宜読み出してください。

FIFOがFullの場合、Audio Systemは、書き込むことができないため、書き込めない音声データを破棄してしまいます。そのため、そのまま記録すると音声データとしては不連続の音声になってしまうことになります。
コマンド設定例
AudioCommand command;
command.header.packet_length = LENGTH_START_RECORDER;
command.header.command_code  = AUDCMD_STARTREC;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag ad799f8c8c84423f9ac636dfec32b054
図 28. 記録シーケンス
Stop Rec
Stop Recorder.

AUDCMD_STOPRECで記録を停止します。 停止指示を受けた時点でキャプチャしている音声データまで、Encodeした時点で、Recorderは停止します。

コマンド設定例
AudioCommand command;
command.header.packet_length = LENGTH_STOP_RECORDER;
command.header.command_code  = AUDCMD_STOPREC;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag 141673b0c405b9524069e62844cd50bf
図 29. 記録停止シーケンス
Build Configurations

AudioRecorderの機能を使用するために

$>cd sdk/
$>tools/config.py -m

でConfig menuを開き、以下のConfigを設定する必要が有ります。

Select options in below:

:(Select audio recorder)
[CXD56xx Configuration]
  [SDIO SD Card]                 <= Y (If using the SD card)
  [Audio]                        <= Y
    [Audio baseband config settings]
      [CXD5247 settings]
        [X'tal frequency of the CXD5247] <= 49.152MHz (If DVT board)

[SDK audio]                      <= Y
  [Audio Utilities]
    [Audio Recorder]             <= Y

[Memory Manager]                 <= Y
  [Memory Utilities]             <= Y

[ASMP]                           <= Y
Error Attentions and Approach

音声録音時の警告の一覧と、対処方法は以下の通りです。詳細は オーディオサブシステムのエラーについてを参照してください。

ID Attention Code Attention Level Approach

0x06

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW

WARNING

AudioSubSystemが録音データををSimpleFIFOに出力できなかったことが原因です。録音データをSimpleFIFOから取得するタスクのCPU占有度を上げてください。

0x0D

AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR

ERROR

データ領域のセグメント数が不足したことが原因です。AudioSubSystem以外のタスクの優先度を下げるか、データ領域のセグメント数を増やしてください。

0x0F

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR

ERROR

ヒープ領域が不足していることが原因です。ヒープ領域を拡張して下さい。

0x18

AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR

ERROR

DSPバイナリのバージョンが異なることが原因です。DSP バイナリイメージを"sdk/modules/audio/dsp"のファイルで更新して下さい。

DSP install
DSP binary image install

DSPバイナリイメージをKconfigで設定したパスに格納して下さい。バイナリイメージは、 sdk/modules/audio/dsp にあります。

表 19. Binary image required for audio recorder according to configuration
Image size

MP3ENC

111kbyte

SRC (Sampling Rate Converter)

21kbyte

LPCM は、圧縮処理を必要としていませんが、周波数変換処理が必要なため、SRC (Sampling Rate Converter) のDSPのloadが必要になります。
Audio Recorder Example

単純なRecorder Exampleがあり、Recorder動作を確認することが出来ます。

Preparation
Build Configuration (kconfig)

Audio Recorder のサンプルプログラムを使うには、以下の設定を行って下さい。

audio_recorderのconfigを読み込みます。

$>cd sdk/
$>tools/config.py examples/audio_recorder

Audio recorderが有効になっていることを確認します。

$>tools/config.py -m

(audio recorder:)
[Examples]
  [Audio recorder example] <= Y
Audio & Logical sensor example と他の複数のサンプルは同時に選択できません。複数選択するとコンパイルエラーが出ます。
Only support the following format:

詳細はStart Recの項目を参照して下さい。

Memory Utility Configurations and Layout
Message Library Configuration

AudioRecorder機能を使用する際に必要となるMessageQueueの定義を行う必要があります。 定義はMessageQueueLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

Audio Recorder のexampleでは下記のように行います。

$>cd examples/audio_recorder/config
$>ruby -I../../../sdk/modules/memutils/message/tool msgq_layout.conf 0x000fe000 0x1000 msgq_id.h msgq_pool.h

MessageQueueLayout定義ファイル(msgq_layout.conf)の記述内容は下記の通りです。

MsgQuePool
 # ID,                           n_size  n_num  h_size  h_num
  ["MSGQ_AUD_MNG",               88,     3,     0,      0],
  ["MSGQ_AUD_APP",               40,     2,     0,      0],
  ["MSGQ_AUD_DSP",               20,     5,     0,      0],
  ["MSGQ_AUD_RECORDER",          48,     5,     0,      0],
  ["MSGQ_AUD_CAP",               24,    16,     0,      0],
  ["MSGQ_AUD_CAP_SYNC",          16,     8,     0,      0],

各パラメータの説明は以下の通りです。

パラメータ 説明

ID

メッセージキューIDの名称を、"MSGQ_"で始まる文字列で指定。

n_size

通常優先度キューの各要素のバイト数(8以上512以下)。固定ヘッダ長(8byte) + パラメタ長を4の倍数で指定する。

n_num

通常優先度キューの要素数(1以上16384以下)。

h_size

高優先度キューの各要素のバイト数(0または、8以上512以下)。未使用時は0を指定すること。

h_num

高優先度キューの要素数(0または、1以上16384以下)。未使用時は0を指定すること。

各IDの用途は以下の通りです。

MSGQ_AUD_MNG

AudioManagerのコマンド受信に利用する

MSGQ_AUD_APP

Applicationがコマンドの応答受信に利用する

MSGQ_AUD_DSP

DSP(Decorder)からの応答受信に利用する

MSGQ_AUD_RECORDER

MediaRecorderObjectのコマンド受信に利用する

MSGQ_AUD_CAP

CaptureComponentのコマンド受信に利用する

MSGQ_AUD_CAP_SYNC

CaptureComponentの内部同期処理に利用する

それぞれの定義の詳細については、 examples/audio_recorder/config/msgq_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。
Memory Manager (Intelligent Fix Pool) Configuration

AudioRecorder機能を使用する際に必要となるMemoryLayout(pool)の定義を行う必要があります。
定義はMemoaryLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

Audio Recorder のexampleでは下記のように行います。

$>cd examples/audio_recorder/config
$>ruby -I../../../sdk/modules/memutils/memory_manager/tool -I. mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定義ファイル(mem_layout.conf)の記述内容は下記の通りです。

FixedAreas
FixedAreas
 # name,                  device,     align,        size,         fence
  ["AUDIO_WORK_AREA",     "AUD_SRAM", U_TILE_ALIGN, 0x0003c000,   false],
  ["MSG_QUE_AREA",        "AUD_SRAM", U_MSGQ_ALIGN, 0x00003140,   false],
  ["MEMMGR_WORK_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000200,   false],
  ["MEMMGR_DATA_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000100,   false],

各パラメータの説明は以下の通りです。

パラメータ 説明

name

領域名(英大文字で始まり、"_AREA"で終わる名称。英大文字, 数字, _が使用可能)

device

領域を確保するMemoryDevicesのデバイス名

align

領域の開始アライメント。0を除くMinAlign(=4)の倍数を指定する

size

領域のサイズ。0を除く4の倍数の値を指定する

fence

フェンスの有効・無効を指定する(この項目は、UseFenceがfalseの場合は無視される)

各nameの用途は以下の通りです。

AUDIO_WORK_AREA

AudioSubSystemが利用する

MSG_QUE_AREA

MessageQueueが利用する(固定名)。msgq_id.hの(MSGQ_END_DRM - MSGQ_TOP_DRAM)のサイズを超えないこと。

MEMMGR_WORK_AREA

Memory Managerが利用する作業領域(固定名, 固定サイズ)

MEMMGR_DATA_AREA

Memery Managerが利用するデータ領域(固定名, 固定サイズ)

各nameの合計のサイズがmpshm_init(), mpshm_remap()で確保するシェアメモリのサイズを超えないようにしてください。

Fixed Areas can not be customized
PoolAreas
PoolAreas
 # name,                    area,              align,        pool-size,  seg, fence
  ["ES_BUF_POOL",           "AUDIO_WORK_AREA", U_STD_ALIGN,  0x00008700, 5,   true],
  ["INPUT_BUF_POOL",        "AUDIO_WORK_AREA", U_STD_ALIGN,  0x00003000, 2,   true],
  ["ENC_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x000000FC, 3,   true],
  ["SRC_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x000000FC, 3,   true],

各パラメータの説明は以下の通りです。

パラメータ 説明

name

プール名(英大文字で始まり、"_POOL"で終わる名称。英大文字, 数字, _が使用可能)

area

プール領域として使用するFixedAreaの領域名。領域はRAMに配置されていること

align

プールの開始アライメント。0を除くMinAlign(=4)の倍数を指定する

pool-size

プールのサイズ。0を除く4の倍数の値。Basicプールでは、セグメントサイズ * セグメント数 In the final area of each area, RemainderSize indicating the remaining size can be specified.

seg

セグメント数。1以上、255以下の値を指定する

fence

フェンスの有効・無効を指定する。この項目は、UseFenceがfalseの場合は無視される

各nameの用途は以下の通りです。

ES_BUF_POOL

入力音声をエンコードした結果の格納バッファ領域

INPUT_BUF_POOL

記録する音声データの入力格納バッファ領域

ENC_APU_CMD_POOL

Encoder DSPとの通信コマンドバッファ領域

SRC_APU_CMD_POOL

SRC DSPとの通信コマンドバッファ領域の通信

それぞれの定義の詳細については、 examples/audio_recorder/config/mem_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。
How to execute

NuttShell から Recorder アプリケーションを起動します。

nsh>recorder

Audio Recorderアプリケーションが起動し記録が開始されます。
記録ファイルは "/mnt/sd0/REC/YYMMDD_HHMMSS.mp3"となります。

Start AudioRecorder example

10秒記録後、AudioRecorderアプリケーションは終了します。

Exit AudioRecorder example
Audio Through Functions

Audio Through の簡単なデータの流れを以下に示します。

Audio Through Dataflow
図 30. Audio Through Dataflow

Audio SubSystemがThroughModeで動作する場合、User Applicationは、 CPUを介さないデータフローを設定することが出来ます。

データの入力元は、I2SもしくはMICが指定できます。 データの出力先は、スピーカーもしくはI2Sが指定できます。

また、User Applicationは2つのデータフローを設定できます。 MIXERを利用することで、2つの入力データを1つにMIXすることが出来ます。

User Applicationからの設定はコマンドを、Messageで通信します。 Message通信は、各クライアントごとにIDを持ちます。 Audio Throughの場合、IDを示すと以下のようになります。

User Application           : MSGQ_AUD_APP
Audio Manager              : MSGQ_AUD_MNG
Audio Through Message ID
図 31. Audio Through Message ID

これらのIDを生成時に指定する必要があります。

Audio HW internal dataflow

Audio Throughにおいて、Audio HWの内部ではAudio HW internal dataflowに示すデータフローとなります。
データフローの入力元として、I2S In、MIC In、Mixer Outがあります。
データフローの出力先として、Mixer In1、 Mixer In2、I2SOutがあります。出力先にMixer In1もしくは、Mixer In2を設定した場合は、Mixer Outからスピーカーに出力されます。

diag 65e983773cddcc639db0941b79e4fdb8
図 32. Audio Through internal dataflow

設定可能な入力元と出力先の関係は下記の通りです。

表 20. Audio Through dataflow combination
入力元 出力先

I2S In

Mixer In1, Mixer In2

MIC In

Mixer In1, Mixer In2, I2S Out

Mixer Out

I2S Out

How to use
Preparation

"AudioManager" と呼ばれる
オーディオ・サブシステムを制御するために設計されたソフトウェアコンポーネントで、Audio Throughを実現します。

そのため、Audio Throughを実現するには、以下のオブジェクトの生成関数を事前に呼ぶ必要があります。

Activate AudioManager

AudioManager を有効にするには、AS_CreateAudioManager(AudioSubSystemIDs) を呼ぶ必要があります。
AudioSubSystemIDs の中で、Message Library Configuration で定義された MsgQueID を指定する必要があります。
0xFF が指定された項目は使用しないことを意味します。
AudioAttentionCb は、非同期の通知を行うためのコールバック関数を指定します。AudioManagerを使用しない場合に指定して下さい。AS_CreateAudioManagerでコールバック関数を登録した場合、NULLを指定した場合は通知は行われません。

static void attention_callback(const ErrorAttentionParam *attparam)
{
  ...
}

AudioSubSystemIDs ids;

ids.app         = MSGQ_AUD_APP;
ids.mng         = MSGQ_AUD_MNG;
ids.player_main = 0xFF;
ids.player_sub  = 0xFF;
ids.mixer       = 0xFF;
ids.recorder    = 0xFF;
ids.effector    = 0xFF;
ids.recognizer  = 0xFF;

AS_CreateAudioManager(ids, attention_callback);
Initialize and Status change

必要なオブジェクトが生成されたら、Audio Through動作を行わせるためにAudioのHWの設定や電源On、動作モードの変更などの初期化処理を行います。

以下のコマンドを順に発行することで、実現が可能です。

Power on Audio SubSystem

Audioブロックに電源を入れるために、AUDCMD_POWERON, PowerOnParamコマンドを発行することで、電源を入れてAudioSubSystemの状態をReady状態に遷移します。 
enable_sound_effectは、AS_DISABLE_SOUNDEFFECT固定としてください。

  AudioCommand command;
  command.header.packet_length = LENGTH_POWERON;
  command.header.command_code  = AUDCMD_POWERON;
  command.header.sub_code      = 0x00;
  command.power_on_param.enable_sound_effect = AS_DISABLE_SOUNDEFFECT;
  AS_SendAudioCommand(&command);
Initialize output device

PowerOnを行い、Ready状態に遷移したら、AUDCMD_INITOUTPUTSELECT, InitOutputSelectParam コマンドでMixerからの出力先の選択を行います。

output_device_selの設定は以下の通りです。

output_device_sel
  AS_OUT_OFF : 出力OFF
  AS_OUT_SP  : スピーカーからの出力
  AS_OUT_I2S : I2Sからの出力
HWの電源を制御するため、AS_OUT_I2Sを選択すると、スピーカーから出力されなくなります。Audio ThroughでI2Sとスピーカーを両方使いたい場合は、AS_OUT_SPを選択してください。
コマンド設定例
  AudioCommand command;
  command.header.packet_length = LENGTH_INITOUTPUTSELECT;
  command.header.command_code  = AUDCMD_INITOUTPUTSELECT;
  command.header.sub_code      = 0x00;
  command.init_output_select_param.output_device_sel = AS_OUT_SP;
  AS_SendAudioCommand(&command);
Change to Through Status

AUDCMD_SETTHROUGHSTATUSコマンドでAudioSubSystemの状態をThrough状態に遷移します。

コマンド設定例
  AudioCommand command;
  command.header.packet_length = LENGTH_SET_THROUGH_STATUS;
  command.header.command_code = AUDCMD_SETTHROUGHSTATUS;
  command.header.sub_code = 0x00;
  AS_SendAudioCommand(&command);
Set volume

出力にスピーカーを設定する場合、AUDCMD_SETVOLUME, SetVolumeParam で音量を設定できます。 各パラメータの設定は以下の通りです。

I2Sでは音量は変更できません。

input1_db

MIXER1の音量。dBを10倍の整数値で設定します。設定範囲は-1020(-102.0dB)から120(+12.0dB)で、ステップ幅5(0.5dB)で設定できます。

input2_db

MIXER2の音量。設定範囲はinput1_dbと同じです。

master_db

MIXER1とMIXER2のMix後の音量。設定範囲はinput1_dbと同じです。

  AudioCommand command;
  command.header.packet_length = LENGTH_SETVOLUME;
  command.header.command_code  = AUDCMD_SETVOLUME;
  command.header.sub_code      = 0;
  command.set_volume_param.input1_db = 0;    /* 0.0dB */
  command.set_volume_param.input2_db = 0;    /* 0.0dB */
  command.set_volume_param.master_db = -200; /* -20.0dB */
  AS_SendAudioCommand(&command);
Initialize Mic Gain

AudioRecorder を参照してください。

使用できるマイクは、CXD5247アナログマイク1, CXD5247アナログマイク2の組み合わせか、 CXD5247デジタルマイク1,CXD5247デジタルマイク1の組み合わせのどちらかです。
diag 2b8a4a49f27ab40876436d4cf990da81
図 33. Initial sequence
Start Audio Through

データフローのパスを設定することで、データの入出力を開始します。

Set Through Path

AUDCMD_SETTHROUGHPATH, AsSetThroughPathParam, AsThroughPathでデータパスを同時に2つ設定できます。 それぞれのデータパスの各パラメータの設定は以下の通りです。

en

データパスの有効、無効を設定します。

true : 有効
false: 無効
in

データの入力元を設定します。

AS_THROUGH_PATH_IN_MIC : MICを入力元にします
AS_THROUGH_PATH_IN_I2S1 : I2Sを入力元にします
AS_THROUGH_PATH_IN_MIXER : Mixer Outを入力元にします
MICはアナログマイクの場合、CXD5247アナログマイク1とCXD5247アナログマイク2を指します。デジタルマイクの場合は、CXD5247デジタルマイク1とCXD5247デジタルマイク2を指します。I2Sは、I2S0を指します。
out

データの出力先を設定します。

AS_THROUGH_PATH_OUT_MIXER1 : Mixer In1を出力先にします
AS_THROUGH_PATH_OUT_MIXER2 : Mixer In2を出力先にします
AS_THROUGH_PATH_OUT_I2S1 : I2Sを出力先にします
I2Sは、I2S0を指します。
command example 1
  AudioCommand command;
  command.header.packet_length = LENGTH_SET_THROUGH_PATH;
  command.header.command_code  = AUDCMD_SETTHROUGHPATH;
  command.header.sub_code      = 0x00;
  command.set_through_path.path1.en  = true; (1)
  command.set_through_path.path1.in  = AS_THROUGH_PATH_IN_MIC; (2)
  command.set_through_path.path1.out = AS_THROUGH_PATH_OUT_I2S1; (3)
  command.set_through_path.path2.en  = true; (4)
  command.set_through_path.path2.in  = AS_THROUGH_PATH_IN_I2S1;   (5)
  command.set_through_path.path2.out = AS_THROUGH_PATH_OUT_MIXER1; (6)
  AS_SendAudioCommand(&command);
1 データパス1の設定を有効にします
2 データパス1はMIC Inを入力元にします
3 データパス1はI2S Outを出力先にします
4 データパス2の設定を有効にします
5 データパス2はI2S Inを入力元にします
6 データパス2はMixer In1を出力先にします
diag cd6d142421022eb676e8d1fbc5aad9bf
図 34. command example 1 dataflow
command example 2
  AudioCommand command;
  command.header.packet_length = LENGTH_SET_THROUGH_PATH;
  command.header.command_code  = AUDCMD_SETTHROUGHPATH;
  command.header.sub_code      = 0x00;
  command.set_through_path.path1.en  = true; (1)
  command.set_through_path.path1.in  = AS_THROUGH_PATH_IN_MIC; (2)
  command.set_through_path.path1.out = AS_THROUGH_PATH_OUT_MIXER1; (3)
  command.set_through_path.path2.en  = true; (4)
  command.set_through_path.path2.in  = AS_THROUGH_PATH_IN_MIXER;  (5)
  command.set_through_path.path2.out = AS_THROUGH_PATH_OUT_I2S1; (6)
  AS_SendAudioCommand(&command);
1 データパス1の設定を有効にします
2 データパス1はMIC Inを入力元にします
3 データパス1はMixer In2を出力先にします
4 データパス2の設定を有効にします
5 データパス2はMixer Outを入力元にします
6 データパス2はI2S Outを出力先にします
diag 9e31aab8ad24a88571c9d1f443a4db31
図 35. command example 2 dataflow
command example 3
  AudioCommand command;
  command.header.packet_length = LENGTH_SET_THROUGH_PATH;
  command.header.command_code  = AUDCMD_SETTHROUGHPATH;
  command.header.sub_code      = 0x00;
  command.set_through_path.path1.en  = true; (1)
  command.set_through_path.path1.in  = AS_THROUGH_PATH_IN_MIC; (2)
  command.set_through_path.path1.out = AS_THROUGH_PATH_OUT_MIXER2; (3)
  command.set_through_path.path2.en  = false; (4)
  AS_SendAudioCommand(&command);
1 データパス1の設定を有効にします
2 データパス1はMIC Inを入力元にします
3 データパス1はMixer In2を出力先にします
4 データパス2の設定を無効にします
diag 7d633c524d51c4368fc35ca75018a85d
図 36. command example 3 dataflow
command example 4
  AudioCommand command;
  AudioResult result;
  command.header.packet_length = LENGTH_SET_THROUGH_PATH;
  command.header.command_code  = AUDCMD_SETTHROUGHPATH;
  command.header.sub_code      = 0x00;
  command.set_through_path.path1.en  = true; (1)
  command.set_through_path.path1.in  = AS_THROUGH_PATH_IN_I2S1; (2)
  command.set_through_path.path1.out = AS_THROUGH_PATH_OUT_MIXER1; (3)
  command.set_through_path.path2.en  = true; (4)
  command.set_through_path.path2.in  = AS_THROUGH_PATH_IN_I2S1;  (5)
  command.set_through_path.path2.out = AS_THROUGH_PATH_OUT_MIXER2; (6)
  AS_SendAudioCommand(&command);

  AS_ReceiveAudioResult(&result); (7)

  command.header.packet_length = LENGTH_SET_THROUGH_PATH;
  command.header.command_code  = AUDCMD_SETTHROUGHPATH;
  command.header.sub_code      = 0x00;
  command.set_through_path.path1.en  = true;
  command.set_through_path.path1.in  = AS_THROUGH_PATH_IN_MIXER; (8)
  command.set_through_path.path1.out = AS_THROUGH_PATH_OUT_I2S1; (9)
  command.set_through_path.path2.en  = false;
  AS_SendAudioCommand(&command);
1 データパス1の設定を有効にします
2 データパス1はI2S Inを入力元にします
3 データパス1はMixer In1を出力先にします
4 データパス2の設定を有効にします
5 データパス2はMic Inを入力元にします
6 データパス2はMixer In1を出力先にします
7 結果を受け取ります
8 データパス1はMixer Outを入力元にします
9 データパス1はI2S Outを出力先にします
diag 37574f27f4d427b95cf63048a3e8a9d8
図 37. command example 4 dataflow
diag a534705637004add5d1cd8c71c2118be
図 38. Player State sequence
Build Configurations

AudioThrough の機能を使用するためには

$>cd sdk
$>tools/config.py -m

でConfig menu を開き、以下のConfigを設定する必要があります。

Select options in below:

[CXD65xx Configuration]
  [Audio]                        <= Y

[SDK audio]                      <= Y
Error Attentions and Approach

音楽再生時の警告の一覧と、対処方法は以下の通りです。詳細はオーディオサブシステムのエラーについてを参照してください。

ID Attention Code Attention Level Approach

0x0F

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR

ERROR

ヒープ領域が不足していることが原因です。ヒープ領域を拡張して下さい。

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW が発生した場合、音声再生が停止し、再生エラーの状態になります。 この状態が発生した場合は、直ちにAsStopPlayerParamコマンドを発行し、再生停止状態に遷移させてください。
再生停止に遷移後、FIFOのクリアを必ず行ってください。行わないとノイズが発生してしまいます。

11.3.4. Object Level API

Audio機能では、High Level API よりも細かい単位でもAPIを提供しています。
High Level API をコールした際に内部で使用されるObject群を個別に組み合わせて
使用することでより自由なアプリケーションを作成することが出来ます。

これを Object Level API と呼ぶこととします。

About Usecase

Object Level APIを使用したUsecaseの例を示します。
(組み合わせ方・使い方は自由ですので、これはあくまで例です。)

Usecase 1

MediaPlayerObjectとOutputMixerObjectを使用して、Audioデータのデコード〜出音を行うケースです。
MediaPlayerObjectから応答されたPCMデータをApplicationで処理した後OutputMixerObjectへ送ることが出来ます。

diag 4204fbef0eb792a443a75c866e549e77
Usecase 2

MediaPlayerObjectを使用せずに、RAM上に置かれたPCMデータをOutputMixerObjectへ送るケースです。
デコードをしないので、例えば効果音など即応性が求められるような音源の再生に適します。

diag b7df2b8e4aac27e266c6bc299f1a0748
Usecase 3

MediaRecorderObjectを使い記録したMIC・I2S入力をApplicationで加工して
OutputMixer経由でスピーカーやI2S出力に送出するケースです。

diag f542fa47dd0cda7cbbc0b02aa2aa51f4
MediaPlayerObject

MediaPlayerObjectは、Audioデータのデコード管理とデコード結果PCMの出力を行います。
2つのPlayerを同時に使用することが出来、各APIにあるPlayerIDのパラメータで個別に制御します。

ApplicationはSimpleFIFOと呼ばれるバッファ経由でMediaplayerObjectにESデータを渡します。
バッファがアンダーフローすると再生が停止します。Applicationはそれを考慮した設計をする必要が有ります。
デコードが完了するとMediaPlayerObjectからはPCMデータのMemoryHandleが通知されます。

diag f4b4ec84d21ebaf098aadeca6c6e0294

PCMデータをOutputMixerObjectへ送ることも可能です。この場合はApplicationへの応答はありません。
ただし、当然ですがOutputMixerObjectの生成・起動をしておくことが必要です。
(Defaultは上図の通りApplicationへのCallback応答です。)

diag bcaf7c36bef0baccb48dd3e7ffb724d4
Functions
Create

MediaPlayerObjectを使用する際に必ずコールする必要があります。
タスク,インタンスの生成,MsqQueue待ちへの移行までを行います。

API
bool AS_CreatePlayer(AsPlayerId id, FAR AsCreatePlayerParam_t *param);
Activate

MediaPlayerObjectのActivationを行います。必ずコールする必要があります。
ApplicationからMediaPlayerObjectへAudioデータを渡すためのバッファのハンドルはここで設定します。

API
bool AS_ActivatePlayer(AsPlayerId id, FAR AsActivatePlayer &actparam);
Init

再生するコンテンツの情報を設定しMediaPlayerObjectを初期化します。
コンテンツの情報 (※) が変わるたびにコールする必要があります。
(※コーデック種別,ビット長,サンプリング周波数)

API
bool AS_InitPlayer(AsPlayerId id, FAR AsInitPlayerParam &initparam);
Play

再生を開始します。
再生開始後はデコード結果(PCMデータ)が応答され続けます。
Applicationは、Activateの際に指定したバッファにAudioデータを供給する必要があります。
供給が追い付かない場合はバッファがアンダーフローし再生が停止します。

デコード結果のPCMデータをApplicatoinへ応答するか、OutputMixerObjectへ直接送るかを選択出来ます。

API
bool AS_PlayPlayer(AsPlayerId id, FAR AsPlayPlayerParam &playparam);
Stop

再生を停止します。
本APIをコールした時点でAudioデータバッファに残っているデータを再生しきってから停止するか
即時停止をするかを選択することが出来ます。前者の場合は停止までに時間がかかることが有ります。

また、コールのタイミングにより、入れ違いでコール後にデコード完了の通知が届くことが有ります。

API
bool AS_StopPlayer(AsPlayerId id, FAR AsStopPlayerParam &stopparam);
Set Gain

再生音量のGainをL/Rそれぞれ設定します。Init後~Deactivateするまで設定可能です。
コールしない場合は100%(デフォルト音量)です。(BaseBandの音量設定と依存関係はありません)

API
bool AS_SetPlayerGain(AsPlayerId id, FAR AsSetGainParam &gainparam);
Next Request

次のDecode処理(再生継続処理)を要求します。
デコード結果データ用のバッファが空いた等の契機で継続的にコールしてください。
本APIをコールしないと後続のデコード処理が行われず、音が止まったり途切れたりします。

(※PCMデータの送信先を直接OutputMixerObjectにしている場合はコール不要です。)

API
bool AS_RequestNextPlayerProcess(AsPlayerId id, FAR AsRequestNextParam &nextparam);
Deactivate

MediaPlayerObjectのDeactivationを行います。 再度MediaPlayerObjectを使用するにはAcitvateからやり直す必要があります。

API
bool AS_DeactivatePlayer(AsPlayerId id, FAR AsDeactivatePlayer &deactparam);
Delete

MediaPlayerObjectのタスク,インスタンスを削除します。
再度MediaPlayerObjectを使用するにはCreateからやり直す必要があります。

API
bool AS_DeletePlayer(AsPlayerId id);
Sequence

MediaPlayerObjectの簡易シーケンスです。

diag 7c3d27117a526c6276ca92dfb2e6f8a1
OutputMixerObject

OutputMixerObjectはPCMデータの送出(Rendering)を管理します。
ApplicationはPCMデータをMemoryHandle経由でOutputMixerObjectへ送ります。
送出(Rendering)が完了するとOutputMixerObjectからはcallbackが応答されます。

diag bfaf0f6425a975302f975fae14b46c76
Functions
Create

OutputMixerObjectを使用する際に必ずコールする必要があります。
タスク,インタンスの生成,MsqQueue待ちへの移行までを行います。

API
bool AS_CreateOutputMixer(FAR AsCreateOutputMixParam_t *param);
Activate

OutputMixerObjectのActivationを行います。必ずコールする必要があります。
出力先(スピーカーまたはI2S)の選択をこの時に行います。

API
bool AS_ActivateOutputMixer(uint8_t handle, FAR AsActivateOutputMixer &actparam);
Send Data

PCMデータを送出します。送出が完了すると応答がcallbackされます。

本APIで渡したデータの送出が完了する前に、次のデータを渡して下さい。
間に合わない場合はDMA転送がアンダフローを起こし停止します。

また、実際にPCMデータが送出されるのは本APIが2回以上コールされた時です。

diag f83fa0788034a206b8791424296c75d6
API
bool AS_SendDataOutputMixer(FAR AsSendDataOutputMixer &sendparam);
Frame Term Control

PCMデータの送出時間を調整します。
実際のPCMデータの発音時間よりも長くまたは短く微調整することが出来ます。
主にPCMデータ用のバッファ残量の調整(アンダー/オーバーフロー抑制)などに使用します。
(※調整実行時には小さいノイズが入ることがあります。)

API
bool AS_FrameTermFineControlOutputMixer(uint8_t handle, FAR AsFrameTermFineControl &ftermparam);
Deactivate

OutputMixerObjectのDeactivationを行います。

API
bool AS_DeactivateOutputMixer(uint8_t handle, FAR AsDeactivateOutputMixer &deactparam);
Delete

OutputMixerObjectのタスク,インスタンスを削除します。
再度OutputMixerObjectを使用するにはCreateからやり直す必要があります。

API
bool AS_DeleteOutputMix(void);
Sequence

OutputMixerObjectの簡易シーケンスです。

diag bf0de5766d7bfc587c55aa39ad5272bf
MediaRecorderObject

MediaRecorderObjectは、Audioデータのエンコード管理とエンコード結果ESの出力を行います。

CaptureしたMICまたはIS2からの入力(PCMデータ)をエンコードしSimpleFIFOバッファに順次格納します。
Applicationはそれを引き抜くことで、ESデータを取得することが出来ます。引き抜きが間に合わずバッファが
オーバーフローすると記録が停止しますので、Applicationはそれを考慮して設計する必要が有ります。

diag 75593d76f238c730ff85bb837905911b
Functions
Create

MediaRecorderObjectを使用する際に必ずコールする必要があります。
タスク,インタンスの生成,MsqQueue待ちへの移行までを行います。

API
bool AS_CreateMediaRecorder(FAR AsActRecorderParam_t *param);
Activate

MediaRecorderObjectのActivateを行います。
この時にエンコードしたAudioデータの受け渡しにつかうバッファのハンドルを渡します。

API
bool AS_ActivateMediaRecorder(FAR AsActivateRecorder *actparam);
Init

記録するコンテンツの情報を設定しMediaRecorderObjectを初期化します。
記録中に動的に変更することは出来ません。

API
bool AS_InitMediaRecorder(FAR AsInitRecorderParam *initparam);
Start

Initで設定した情報に基づいて記録を開始します。
エンコードされたESデータは、Activate時に指定したAudio用のバッファに順次格納されていきます。
ApplicationではAudioバッファからESデータを引き抜く必要が有ります。

API
bool AS_StartMediaRecorder(void);
Stop

記録を停止します。
即時停止のみ対応します。

API
bool AS_StopMediaRecorder(void);
Deactivate

MediaRecorderObjectのDeactivateを行います。

API
bool AS_DeactivateMediaRecorder(void);
Delete

MediaRecorderObjectを削除します。

API
bool AS_DeleteMediaRecorder(void);
Sequence
diag b597a4e4a1a83b8828de9e81b9e949fa

11.3.5. Low Level API

Now Under constructions. mOm

11.3.6. オーディオサブシステムのエラーについて

概要

Audio SubSystem のHigh Level API は、コマンド・リザルトのデータ送受信によるインターフェースを持っています。

Audio SubSystem に向けて発行したコマンドに問題があった場合に、リザルトでAUDRLT_ERRORRESPONSEが返り、 ErrorResponseパラメータにエラー内容が格納されます。 このエラーをレスポンスエラーと呼びます。

また、Audio SubSystemの内部処理でエラーを検出した場合、内部イベントが発生し、AS_CreateAudioManagerで登録した callback関数でエラーが通知され、ErrorAttentionパラメータにエラー内容が格納されます。 これをアテンションエラーと呼びます。

レスポンスエラー、アテンションエラーに対しては、それぞれのエラーに応じて、不具合対応、エラー処理追加などを行って下さい。

レスポンスエラー

Audio SubSystem に発行したコマンドで、仕様通りの制御を行った場合、リザルトはそれぞれのコマンドに対する完了レスポンスとなります。
しかし、状態違反やパラメータの誤りなど、仕様と異なった制御を行った場合、リザルトでAUDRLT_ERRORRESPONSEが返り、 ErrorResponseパラメータにエラー内容が格納されます。

diag 2d16d40accd0ab9b0e8a73c73c14ac62

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

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

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

表 21. 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_COMPLEXITY

0x17

圧縮率の指定の誤り

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_CHECK_MEMORY_POOL_ERROR

0x2E

メモリプールの設定誤り

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

動作モードの指定誤り

AS_ECODE_SET_RENDERINGCLK_ERROR

0x3A

動作モードの設定失敗

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

アテンションエラー

Audio SubSystem内部での処理中(コマンド処理ではなく)に何らかのエラーを検出した場合、通知用のイベントが発生します。 このイベントを受け取るためには、AS_CreateAudioManager でcallback関数を登録しておく必要があります。

diag 5645bafbeb2928e2f14412d0aa9f3326

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

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

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

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

表 22. 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_LOG_ALLOC_ERROR

0x1E

DSPのログ用バッファの取得失敗

AS_ATTENTION_SUB_CODE_DSP_ASSETION_FAIL

0x1F

DSPの処理で致命的エラー

AS_ATTENTION_SUB_CODE_DSP_SEND_ERROR

0x20

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

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

Attention Level

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

表 23. Attention Level
Level value Description

FATAL

0x03

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

ERROR

0x02

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

WARN

0x01

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

Error Code List

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

AS_ECODE_STATE_VIOLATION
code

0x01

description

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

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

状態遷移について

AS_ECODE_PACKET_LENGTH_ERROR
code

0x02

description

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

AS_ECODE_COMMAND_CODE_ERROR
code

0x03

description

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

AS_ECODE_COMMAND_NOT_SUPPOT
code

0x04

description

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

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

Audio Player
Audio Recorder

AS_ECODE_AUDIO_POWER_ON_ERROR
code

0x05

description

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

AS_ECODE_AUDIO_POWER_OFF_ERROR
code

0x06

description

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

AS_ECODE_DSP_LOAD_ERROR
code

0x07

description

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

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

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

AS_ECODE_DSP_UNLOAD_ERROR
code

0x08

description

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

AS_ECODE_DSP_VERSION_ERROR
code

0x09

description

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

AS_ECODE_SET_AUDIO_DATA_PATH_ERROR
code

0x0a

description

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

AudioRecorder は Init recorder information
BaseBand は SetBaseBandStatusParam
Through mode は AsSetThroughPathParam

AS_ECODE_CLEAR_AUDIO_DATA_PATH_ERROR
code

0x0b

description

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

AS_ECODE_NOT_AUDIO_DATA_PATH
code

0x0c

description

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

BasebandStatusへの遷移は SetBasebandStatus
ThroughStatusへの遷移は SetThroughStatus

AS_ECODE_DECODER_LIB_INITIALIZE_ERROR
code

0x0d

description

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

AS_ECODE_ENCODER_LIB_INITIALIZE_ERROR
code

0x0e

description

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

AS_ECODE_FILTER_LIB_INITIALIZE_ERROR
code

0x0f

description

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

AS_ECODE_COMMAND_PARAM_CODEC_TYPE
code

0x11

description

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

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

AS_ECODE_COMMAND_PARAM_CHANNEL_NUMBER
code

0x13

description

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

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

AS_ECODE_COMMAND_PARAM_SAMPLING_RATE
code

0x14

description

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

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

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

AS_ECODE_COMMAND_PARAM_BIT_RATE
code

0x15

description

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

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

Init recorder information

AS_ECODE_COMMAND_PARAM_BIT_LENGTH
code

0x16

description

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

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

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

モードの切り替えについては Init Rendering Clock を参照してください。

AS_ECODE_COMMAND_PARAM_COMPLEXITY
code

0x17

description

指定されたOPUSエンコードの圧縮率が誤っています。

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

Init recorder information

AS_ECODE_COMMAND_PARAM_ACTIVE_PLAYER
code

0x18

description

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

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

Change to Player Status

AS_ECODE_COMMAND_PARAM_INPUT_DEVICE
code

0x19

description

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

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

Change to Player Status
Change to Recorder Status

AS_ECODE_COMMAND_PARAM_OUTPUT_DEVICE
code

0x1A

description

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

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

Change to Player Status
Change to Recorder Status

AS_ECODE_COMMAND_PARAM_INPUT_HANDLER
code

0x1B

description

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

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

Change to Player Status

AS_ECODE_COMMAND_PARAM_CONFIG_TABLE
code

0x1F

description

MFEまたはMPPフィルタの係数テーブルアドレスが正しくありません。 (※MFEおよびMPPは未サポートです。)

AS_ECODE_COMMAND_PARAM_WITH_MFE
code

0x20

description

MFEのアクティベーション指定パラメータが誤っています。
(※MFEは未サポートです。)

AS_ECODE_COMMAND_PARAM_WITH_MPP
code

0x21

description

MPPのアクティベーション指定パラメータが誤っています。
(※MPPは未サポートです。)

AS_ECODE_COMMAND_PARAM_INPUT_DB
cod

0x28

description

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

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

Set Volume Mute

AS_ECODE_DMAC_INITIALIZE_ERROR
code

0x2B

description

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

AS_ECODE_DMAC_READ_ERROR
code

0x2C

description

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

AS_ECODE_CHECK_MEMORY_POOL_ERROR
code

0x2E

description

AudioSubSystem内のObject Create時にMemoryPoolのチェックエラーが発生しました。
メモリプールIDが正しくCreateのAPIに渡されていない、またはMemoryPoolの作成が誤っている可能性があります。

メモリプールIDの指定についてはこちらを参考にして下さい。

Create Media Player
Create Media Recorder

MemoryPoolの作成についてはこちらを参考にして下さい。

AudioPlayerのPoolAreas設定

AS_ECODE_SIMPLE_FIFO_UNDERFLOW
code

0x2F

description

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

diag 9c9e93ae810905fbcd949394dae15254
AS_ECODE_SET_MIC_GAIN_ERROR
code

0x30

description

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

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

Initialize Mic Gain

AS_ECODE_SET_OUTPUT_SELECT_ERROR
code

0x32

description

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

InitOutputSelect

AS_ECODE_INIT_CLEAR_STEREO_ERROR
code

0x33

description

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

AS_ECODE_SET_VOLUME_ERROR
code

0x34

description

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

Set Volume

AS_ECODE_SET_VOLUME_MUTE_ERROR
code

0x35

description

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

AS_ECODE_SET_BEEP_ERROR
code

0x36

description

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

AS_ECODE_QUEUE_OPERATION_ERROR
code

0x37

description

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

AS_ECODE_COMMAND_PARAM_RENDERINGCLK
code

0x39

description

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

SetRenderingClock

AS_ECODE_SET_RENDERINGCLK_ERROR
code

0x3A

description

HiResoモード設定エラーです。
HiResoモードを使用するには、コンフィグでAudioのクロックを49.152Mhzに設定する必要があります。

$>cd sdk
$>tools/config.py -m
[CXD56xx Configuration]
  [Audio]
    [Audio baseband config settings]
      [CXD5247 settings]
        [X'tal frequency of the CXD5247] <- 49.152Mhz
Attention Code List

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

AS_ATTENTION_SUB_CODE_DMA_UNDERFLOW
Code

0x01

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DMA_OVERFLOW
Code

0x02

Attention Level

ERROR

Description

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

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DMA_ERROR
Code

0x03

Attention Level

FATAL, ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW
Code

0x05

Attention Level

WARNING

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW
Code

0x06

Attention Level

WARNING

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_ILLEGAL_REQUEST
Code

0x07

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_INTERNAL_STATE_ERROR
Code

0x08

Attention Level

ERROR

Description

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

error handling

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

AS_ATTENTION_SUB_CODE_UNEXPECTED_PARAM
Code

0x09

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_QUEUE_POP_ERROR
Code

0x0A

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_QUEUE_PUSH_ERROR
Code

0x0B

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_QUEUE_MISSING_ERROR
Code

0x0C

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR
Code

0x0D

Attention Level

ERROR

Description

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

Error Handling

メモリハンドルの段数が足りない場合はメモリプール設定を見直してください。
設定の方法は下記を参考にして下さい。(AudioPlayerの設定例です)+
PlayerのMemoryPool概要
PlayerのMemoyPool定義

AS_ATTENTION_SUB_CODE_MEMHANDLE_FREE_ERROR
Code

0x0E

Attention Level

ERROR

Description

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

Error Dandling

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

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR
Code

0x0F

Attention Level

ERROR

Description

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

Error Handling

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

タスク生成数の上限を増やす場合はコンフィグで設定できます。

$>cd sdk
$>cd tools/config.py -k -m
[RTOS Features]
  [Tasks and Scheduling]
    [Max number of tasks] <- Set this.
AS_ATTENTION_SUB_CODE_RESOURCE_ERROR
Code

0x10

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DSP_LOAD_ERROR
Code

0x12

Attention Level

ERROR

Description

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

Error Handling

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

AudioPlayer は Initialize player
AudioRecorder は Init recorder information

AS_ATTENTION_SUB_CODE_DSP_UNLOAD_ERROR
Code

0x13

Attention Level

ERROR

Description

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

Error handling

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

AS_ATTENTION_SUB_CODE_DSP_EXEC_ERROR
Code

0x14

Attention Level

ERROR, WARNING

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DSP_ILLEGAL_REPLY
code

0x16

Attention Level

ERROR

Description

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

Error handling

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

AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR
Code

0x18

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_BASEBAND_ERROR
Code

0x19

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_STREAM_PARSER_ERROR
Code

0x1A

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DSP_LOG_ALLOC_ERROR
Code

0x1E

Attention Level

ERROR

Description

DSPログ用バッファの取得に失敗しました。
複数のDSPが立ち上がっている場合はログ用バッファ領域の残量が足りない可能性があります。

Error Handling

DSPログ用バッファ領域はアプリケーションやコンフィグから設定することはできません。

ただし、DSPログが不要であればコンフィグでロギング機能そのものをOFFすることが出来ます。

$>cd sdk
$>cd tools/config.py -k -m
[Audio Utilities]
  [Audio component menu]
    [dsp debug dump] <- Set to "No".
AS_ATTENTION_SUB_CODE_DSP_ASSETION_FAIL
Code

0x1F

Attention Level

ERROR

Description

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

Error Handling

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

AS_ATTENTION_SUB_CODE_DSP_SEND_ERROR
Code

0x20

Attention Level

ERROR

Description

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

Error Handling

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

Module ID List

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

AS_MODULE_ID_AUDIO_MANAGER

Audio Manager ID.

AS_MODULE_ID_AUDIO_DRIVER

Audio Baseband Driver Module ID.

AS_MODULE_ID_INPUT_DATA_MNG_OBJ

Input Data Manager Object ID.

AS_MODULE_ID_MEDIA_RECORDER_OBJ

Media Recorder Object ID.

AS_MODULE_ID_OUTPUT_MIX_OBJ

Output Mix Object ID.

AS_MODULE_ID_PLAYER_OBJ

Player Object ID.

AS_MODULE_ID_RECOGNITION_OBJ

Recognition Object ID.

AS_MODULE_ID_SOUND_EFFECT_OBJ

Sound Effect Object ID.

AS_MODULE_ID_CAPTURE_CMP

Capture Component ID.

AS_MODULE_ID_DECODER_CMP

Decoder Component ID.

AS_MODULE_ID_ENCODER_CMP

Encoder Component ID.

AS_MODULE_ID_FILTER_CMP

Filter Component ID.

AS_MODULE_ID_RECOGNITION_CMP

Recognition Component ID.

AS_MODULE_ID_RENDERER_CMP

Renderer Component ID.

AS_MODULE_ID_POSTFILTER_CMP

Postfilter Component ID.

11.3.7. 使用しているライブラリ

オーディオ・サブシステムは以下のライブラリを必要とします。

11.4. Camera

11.4.1. 概要

CXD5602には8ビットパラレルのCamera I/Fが備わっており、このI/Fを持つカメラモジュールを接続することができます。現在、Spresenseでは、Sony ISX012を搭載するカメラモジュールをサポートしています。 通常、カメラモジュールはデータ用のインターフェースに加えて、モジュールの制御を行うインターフェースを持っています。ISX012では、その制御用I/FにI2Cが用いられています。 以下にHWの構成の概要を示します。

camera hw overview
図 39. Camra HW Overview

CXD5602内部には、CISIFと呼ばれるCamera I/Fブロックがあり、このブロックで8ビットパラレル信号とCXD5602内部バスのブリッジを行なっています。ISX012カメラモジュールの場合、これに加えて、I2Cバスを使って制御を行なっています。

この章では、このCamera I/Fに接続されたカメラモジュールをSpresense SDKで制御するための概要を説明します。

Spresense SDKのCamera制御では、Linuxでお馴染みのV4L2に非常によく似たドライバI/Fを提供しており、V4L2を用いたコードからの流用をしやすくしています。このI/FをV4S (Video for Spresense) と呼びます。V4Sでは、デバイスファイルを介して、open, close, ioctlなどの標準のI/Fを用い、ISX012などのデバイスを意識することなくCameraとしての機能を抽象化したAPIを提供します。

camera v4s overview
図 40. V4S SW Overview

V4Sでは、カメラの制御として、2つの仮想Videoストリームを提供します。 2つの仮想ストリームのうち、1つはCameraのPreview画像のような動画を扱うためのストリームとして、もう一つは静止画を取得するためのストリームとしての役割を持っています。

camera v4s dataflow
図 41. V4S Dataflow

これら2つのストリームに対して、アプリケーションからデータを取得するには、アプリケーションで用意したバッファをVIDIOC_QBUFを用いてドライバにセットし、VIDIOC_DQBUFでVIDIOC_QBUFでセットしたバッファを取ることでイメージデータを取り出すことができます。

アプリケーションが用意するバッファは、memalign()等を用いて獲得した、32ビットアラインメントである必要があります。

各ストリームの指定は、v4l2_buf_typeで指定し、V4L2_BUF_TYPE_VIDEO_CAPTUREが動画を扱うストリーム、V4L2_BUF_TYPE_STILL_CAPTUREが静止画用のストリームに対応しています。

この、V4L2_BUF_TYPE_STILL_CAPTUREは、V4S固有のパラメータになります。

V4Sの初期化からイメージデータをキャプチャするまでの概略の流れは以下のようになります。

diag a00acb00cc4c9d6fe1c833146e10468b
図 42. V4S Sequence Overview

11.4.2. 状態遷移

ストリーム毎に状態を管理しており、アプリケーションからは並行して制御可能です。 ただし、imageの取得についてはV4L2_BUF_TYPE_STILL_CAPTURE制御優先であり、VIDIOC_TAKEPICT_START - VIDIOC_TAKEPICT_STOP間はV4L2_BUF_TYPE_VIDEO_CAPTURE側のimage取得は停止します(状態遷移図において"dma"状態ではなくなる)。

diag 9c43b21ed55567f36f926c13b3de1532

11.4.3. V4Sサポート ioctlコマンド

表 24. V4Sサポート ioctlコマンド
分類 command 目的 Spresenseカスタマイズ

バッファ制御

VIDIOC_REQBUFS

ドライバのバッファ管理領域の初期設定を行う。

パラメータ"v4l2_buf_mode mode"を追加し、 バッファ群にRING構造を持たせられるようにしています。

VIDIOC_QBUF

アプリが用意したバッファをエンキューする。

V4L2準拠

VIDIOC_DQBUF

imageデータが入ったバッファをデキューする。

V4L2準拠

VIDIOC_CANCEL_DQBUF

VIDIOC_DQBUFを取り消す。

左記目的のために追加したSpresense独自コマンド。

ストリーム制御

VIDIOC_STREAMON

ストリームを開始する。

V4L2準拠

VIDIOC_STREAMOFF

ストリームを停止する。

V4L2準拠

VIDIOC_TAKEPICT_START

静止画撮影開始

左記目的のために追加したSpresense独自コマンド。

VIDIOC_TAKEPICT_STOP

静止画撮影停止

左記目的のために追加したSpresense独自コマンド。

フレーム設定の値域確認

VIDIOC_ENUM_FMT

カメラデバイスが対応しているpixelフォーマットの確認

V4L2準拠

VIDIOC_ENUM_FRAMESIZES

カメラデバイスが対応しているimageサイズの確認

パラメータにv4l2_buf_typeを追加し、ストリーム毎に確認できるようにしています。

VIDIOC_ENUM_FRAMEINTERVALS

カメラデバイスが対応しているframe intervalの確認

パラメータにv4l2_buf_typeを追加し、ストリーム毎に確認できるようにしています。

VIDIOC_TRY_FMT

INパラメータで指定したpixelフォーマットとimageサイズの組み合わせが 設定可能かどうかの確認。

V4L2準拠

フレーム設定の変更

VIDIOC_S_FMT

pixelフォーマットとimageサイズを設定する。

V4L2準拠

VIDIOC_S_PARM

frame intervalを設定する(分数の分子と分母を指定できる)。

V4L2準拠

カメラ設定の値域確認

VIDIOC_QUERYCTRL

カメラ設定の値域を確認する。

V4L2準拠

VIDIOC_QUERY_EXT_CTRL

カメラ設定の値域を確認する。 VIDIOC_QUERYCTRLの拡張APIで、VIDIOC_QUERYCTRLを包含する。

V4L2準拠

VIDIOC_QUERYMENU

カメラ設定で離散値をとる項目について、とりうる値を取得する。

V4L2準拠

カメラ設定の現在値確認

VIDIOC_G_CTRL

カメラ設定の現在値を確認する。

V4L2準拠

VIDIOC_G_EXT_CTRLS

カメラ設定の現在値を確認する。 VIDIOC_G_CTRLの拡張APIで、VIDIOC_G_CTRLを包含する。

V4L2準拠

カメラ設定の変更

VIDIOC_S_CTRL

カメラ設定を変更する。

V4L2準拠

VIDIOC_S_EXT_CTRLS

カメラ設定を変更する。 VIDIOC_S_CTRLの拡張APIで、VIDIOC_S_CTRLを包含する。

V4L2準拠

VIDIOC_DO_HALFPUSH

シャッターボタンを半押しした場合に相当する設定変更を行う。

アプリケーションにおける半押し制御を簡略化するために追加したSpresense独自コマンド。

11.4.4. ISX012独自仕様

JPEG + YUV4:2:2フォーマット

ioctl(VIDIOC_S_FMT)において、

  • パラメータ pixelformat に V4L2_PIX_FMT_JPEG_WITH_SUBIMG

  • パラメータ subimg_pixelformat に V4L2_PIX_FMT_UYVY

を設定することによって、 ある1フレームのimageを JPEG、YUV4:2:2の2つのデータフォーマットで同時に取得することができます。

例えば、写真を撮ってJPEGで保存しつつ、保存したものと同じ画像をディスプレイに表示するようなアプリをJPEGデコーダを用いずに実現できます。

ただし、それぞれのフォーマットを単独で取得する場合と比較して、imageサイズとframe rateの制約が厳しくなっております。

diag c25f72fe2a2fa4e91246c472be29732e
図 43. JPEG + YUV4:2:2フォーマット

11.4.5. imageサイズとframe rateの制約

VIDIOC_S_FMTで設定できるimageサイズと、VIDIOC_S_PARMで設定できるframe interval(frame rateの逆数)には関連があります。
(imageサイズを大きくすると、大きいframe rateは設定できなくなります。)

以下、Spresense + ISX012におけるサポート範囲をpixelフォーマット毎に表したものになります。 ISX012に設定できるframe rateは離散値をとり、120 / 60 / 30 / 15 / 7.5 / 6 / 5 の7種類が設定可能です。
下図において、例えば、YUV4:2:2フォーマットの場合は

  • QVGA以下: max FPS=120なので、120FPS~5FPSの7種類を設定可能

  • QVGAより大きい: max FPS=60なので、60FPS~5FPSの6種類を設定可能

という制約になります。

diag e20be42c17fe936f4b3ca31aee2cb114
図 44. YUV4:2:2フォーマットのimageサイズと設定可能な最大frame rate
diag 2d164fbd359fa17a6c4988de576bdaef
図 45. JPEGフォーマットのimageサイズと設定可能な最大frame rate
diag 1415c4a641b352130a344b6b54cad2cc
図 46. JPEG + YUV4:2:2フォーマットのJPEG imageサイズと設定可能な最大frame rate

JPEG + YUV4;2;2フォーマットにおいて、 YUV422 imageサイズは 96x64からWQVGA(400x240)までをサポートしており、 この範囲内であればframe rateの制約には影響しません。

11.4.6. サンプルコード

11.5. DNN Runtime

11.5.1. DNN Runtime 概要

DNN Runtimeライブラリ(dnnrt)は、Sonyが提供するNeural Network LibrariesまたはNeural Network Console(NNC)で学習したモデルを使用して、Deep Neural Network (DNN) を用いた認識処理を行うことができます。

DNN Runtime を使用して認識処理を行うためには、事前にNNCで学習済みモデル(nnbファイル形式)を作成する必要があります。 学習済みモデルの作成方法は、こちら学習済みモデルの準備を参照してください。

dnnrt overview ja
図 47. DNN Runtime 概要

Neural Network Libraries および Neural Network Console は、以下の公式サイトをご覧ください。

また、DNN Runtime ライブラリは、NNabla C Runtimeを使用しています。

11.5.2. サンプルコード

このサンプルコードは、こちら学習済みモデルの準備の章で使用している image_recognition.MNIST.LeNet で作成された学習モデルを実行し、手書き文字認識を行うためのサンプルコードです。

image_recognition.MNIST.LeNet で作成された学習モデルは、28x28サイズの画像を1つ入力にとり、10個の配列を出力します。この10個の配列はインデックスが認識した数字を意味しており、配列の中にそれぞれの数字である確率が出力されます。例えば、配列の先頭(インデックス0)には、入力された画像が数字の「0」である確率が出力されます。

詳細は、DNNRT example READMEを参照してください。

diag 0f8b65c27b49bed6c7986b4ffa7eb1fd
図 48. DNNRT 動作シーケンス

11.6. GNSS

GNSS library はGPS/GLONASS 衛星の信号を受信し現在位置を算出する機能を提供します。 この機能を使うには、GNSS用のアンテナを装着する必要があります。 Spresenseボードでは、チップアンテナが搭載されているため、追加のアンテナは不要です。

11.6.1. 主な特徴

  • GPS/GLONASS に加え QZSS (みちびき)衛星システムからの信号を受信可能な Multi GNSS をサポート

  • SBAS(WAAS)及びQZSS L1Sによる測位補強が利用可能です

  • アプリケーションコアとGNSSコアは分離しているため、独立して測位と通知を行うことができます

  • Geofence をサポートします

これらの機能は POSIX 準拠のデバイスファイルでアプリケーションから操作することができます。 デバイスファイルは、"/dev/gps" で、open(), close(), read(), seek(), ioctl() で操作します。

NuttX RTOS の ioctl は3つの引数を持ちます。 GNSS デバイスファイルに関しては、2番目の引数"req" が GNSS コマンド、3番目の引数"arg" が in/out data の引き渡しになります。

11.6.2. Configuration

GNSS 機能を使うには、CONFIG_CXD56_GNSS を "y" にセットする必要があります。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS device] (CXD56_GNSS)  = Y

NMEA 形式を使いたい場合は、CONFIG_CXD56_GNSS, CONFIG_LIBM, CONFIG_GPSUTILS_CXD56NMEA_LIB を "y" にセットする必要があります。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS device] (CXD56_GNSS) = Y
[Library Routines]
  [Standard Math library] (LIBM) = Y
[Application Configuration]
  [GPS Utilities]
    [Support CXD56xx gnss NMEA convert library] (GPSUTILS_CXD56NMEA_LIB) = Y

また、サンプルアプリケーションを有効にするには、CONFIG_CXD56_GNSS に加え CONFIG_EXAMPLES_GNSS を "y" にセットしてください。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS device] (CXD56_GNSS) = Y
[Application Configuration]
  [Examples]
    [GNSS positioning example] (EXAMPLES_GNSS) = Y

NMEAのサンプルをアプリケーションを有効にするには、NMEA設定の他に、CONFIG_EXAMPLES_GNSS_ATCMD を "y" にセットする必要があります。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS device] (CXD56_GNSS) = Y
[Library Routines]
  [Standard Math library] (LIBM) = Y
[Device Drivers]
  [USB Device Driver Support]
    [USB Modem (CDC/ACM) support] = Y
[Application Configuration]
  [GPS Utilities]
    [Support CXD56xx gnss NMEA convert library] (GPSUTILS_CXD56NMEA_LIB) = Y
[Application Configuration]
  [Examples]
    [GNSS CXD5603 @command emulator example] (EXAMPLES_GNSS_ATCMD) = Y

(参考情報) ファクトリテストを有効にしたい場合は、CONFIG_CXD56_GNSS に加え CONFIG_EXAMPLES_GNSS_FACTORY を "y" にセットします。 また、EXAMPLES_GNSS_FACTORY_SVID をテスト環境に合わせて設定してください。 ファクトリテストを直接動かす場合は、[Application entry point] を "gnss_factory_test" に変更します。 テスト結果 (cn と doppler) は 1000000 倍の値が出てきます。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS device] (CXD56_GNSS) = Y
[Application Configuration]
  [Examples]
    [GNSS FACTORY test] (EXAMPLES_GNSS_FACTORY) = Y
    [FACTORY TEST svid] (EXAMPLES_GNSS_FACTORY_SVID) = 1
[RTOS Features]
  [Tasks and Scheduling]
    [Application entry point]
      set 'gnss_factory_test'

詳細については、以下の README を参照してください。 spresense/examples/gnss_factory/README.txt

以下の設定はどんな場合でも変更可能です。

  • 'Disable power control of the LNA device from GNSS device driver' は、PMIC による基盤上の LNA (Low Noise Amplifier) デバイス電源制御設定の項目です。 PMICにて電源制御しない場合は 'Y' としてください。詳細は基板の回路図を参照して、設定するべきか否か判断してください。

  • 'Enable GNSS HOT Sleep' は GNSS 測位停止中に GNSS CPU を "Hot Sleep" 状態にするかどうかを設定します。

  • 'GNSS backup file name' と 'GNSS CEP file name' は GNSS によって使用されるファイルです。パス名をシステムの構成にあわせて変更してください。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS setting]
      [Disable power control of the LNA device from GNSS device driver] = N
      [Enable GNSS HOT Sleep] = N
      [GNSS backup file name] = '/mnt/spif/gnss_backup.bin'
      [GNSS CEP file name] = '/mnt/vfat/gnss_cep.bin'

GNSS デバイスドライバは アプリケーションに POSIX形式の poll もしくは シグナルを通じて測位結果を通知します。 poll できる数は以下のコンフィギュレーションで設定できます。デフォルトでは、poll 数は 4、signal 数は 3 です。 詳細については、 Position calculation notification を参照してください。

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS setting]
      [GNSS max poll waiters] = 4
      [GNSS max signal receivers] = 3

11.6.3. Device control

GNSS ライブラリは ioctl() を通じて制御します。

ioctl のコマンドは、IOCTL_ のサフィックスが付与されて定義されています。 GNSS デバイスファイルは、複数のアプリケーションから同時に open() することができます。 ただし、GNSS デバイスは、一度に一つの IOCTL コマンドしか受け付けません。言い換えると、どのアプリケーションが優先されるということでなく、受け付けられた順番に処理されます。

Startup

どの衛星システムを起動時に使うか CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM で設定できます。また測位間隔については、CXD56_GNSS_IOCTL_SET_OPE_MODE で設定します。

"Hot Start" の場合("Hot Start")、直近の位置と時間を設定する必要があります。詳細については、Using GNSS backup data の "Warm Start と Hot Start" の設定を参照してください。

Start positioning

"start mode" を CXD56_GNSS_IOCTL_START で指定することができます。

以下の初期位置算出時間 TTFF は参考値です。お使いのシステム及び環境によって変動します。
Start mode IOCTL command parameter TTFF [1] Information to use

Cold Start

CXD56_GNSS_STMOD_COLD

> 45 sec

全ての測位データ、時間、衛星軌道情報は全て消去され、次回起動時は衛星の捕捉から開始します。

Warm Start

CXD56_GNSS_STMOD_WARM

> 20 sec

直近の測位データ、時間、アルマナック(粒度の粗い衛星軌道情報)を使って起動します。エフェメリス(詳細な衛星軌道情報)は用いません。

Hot Start

CXD56_GNSS_STMOD_HOT

>= 1 sec

直近の測位データ、時間、アルマナック、エフェメリスを使って起動します。

"Warm Start" もしくは、"Hot Start" であったとしても、前回の動作時から長い時間が経過し、衛星軌道情報が古く期限切れの条件では、GNSS デバイスは "Cold Start" と同様に衛星の捕捉から開始します。

Stop positioning

測位を停止するには、 CXD56_GNSS_IOCTL_STOP を使用します。停止するには200から300ミリ秒かかります。

Position calculation notification

通知は、poll と シグナルの2種類あります。

poll を使う場合は、CONFIG_CXD56_GNSS_NPOLLWAITERS でポーリング数を設定することができます。

シグナルを使う場合は、フィールド fd に GNSS デバイスのファイルディスクリプタを, enable には 1 を, signo に任意のシグナル番号を、さらに gnsssig に CXD56_GNSS_SIG_GNSS を設定した cxd56_gnss_signal_setting_s データを、IOCTRLコマンド CXD56_GNSS_IOCTL_SIGNAL_SET の引数として ioctl関数を呼び出してシグナルと測位通知を関連付けして下さい。

アプリケーションは、sigwaitinfo で通知をシグナルとして受け取ることができます。 シグナルが不要になった場合は、フィールドenableに 0 を指定した cxd56_gnss_signal_setting_s データを、 CXD56_GNSS_IOCTL_SIGNAL_SET で設定することで関連付けをクリアすることができます。 シグナルの関連付けの最大数は、コンフィギュレーションの CONFIG_CXD56_GNSS_NSIGNALRECEIVERS で変更できます。

CONFIG_EXAMPLES_GNSS_USE_SIGNAL を設定した場合のサンプルは、gnss application example programで参照できます。

11.6.4. For faster positioning

"Hot Start" でTTFFを短くするためには、バックアップデータ中に含まれる衛星軌道上やその他の情報を活用することが早道です。 ioctl コマンドを使って、バックアップデータを活用した標準的な "Hot Start" の手順を示します。

diag f946ad0c041f4b9e6693fd4ee6dc22e8
図 49. Standard flow for hot start using backupdata
Using GNSS backup data

バックアップデータに含まれる最終測位位置、エフェメリス、アルマナック、TCXO クロックのオフセット値が、 "Hot Start" で測位を開始する際に利用されます。 バックアップデータは ioctl コマンドによって、フラッシュメモリに蓄積することができます。その場合、電源がオフになった場合でも次の起動時にフラッシュメモリからSRAMに展開され、"Hot Start" に利用することができます。

Power condition and backup data

システムが起動している状態では、GNSS測位は動いており、全ての関連情報はストアされます。システムが "Hot Sleep" している状態では、SRAM のデータは保持され、 RTC は動き続けているため、"Hot Start" で測位を開始することができます。"Deep Sleep" 状態では RTC は動作を続けますが、SRAM はオフとなるため、"Hot Start" のためにはフラッシュメモリに保存したバックアップデータをリストアして利用する必要があります。

Saving backup data

バックアップデータをフラッシュメモリなどに保存するには、ioctl コマンド CXD56_GNSS_IOCTL_SAVE_BACKUP_DATA を使用します。バックアップデータは、CONFIG_CXD56_GNSS_BACKUP_FILENAME に指定されたファイル名で保存されます。 ただし、フラッシュメモリは頻繁に書き込むとメモリの故障の原因になりますので、頻繁な書き込みは控えるようにしてください。例えば、システムがシャットダウンするタイミングで保存するのが良いでしょう。

Invalid backup data

まれに、保存したバックアップデータが壊れていることがあります。その場合、データのリストアはチェックサムエラーで失敗し、測位も "Cold Start" から開始します。

Expired data

エフェメリスやアルマナックの期限が切れていた場合、それらのデータは無視されます。その場合は、"Cold Start" 相当の処理となりますのでTTFFも長くなります。測位を開始後、最新のエフェメリスやアルマナックを衛星から受信した際に、バックアップデータの衛星軌道情報も上書きされます。

GPS time

"Hot Start" を行うためには、GNSS デバイスに誤差 60 秒以内の現在時刻が設定されている必要があります。以前に測位を行いシステムの電源が切られていなければ RTC_GPS に最後の測位時に設定された時刻が設定されています。電源投入直後には RTC_GPS の値は不定ですのでアプリケーションから ioctl コマンドにて時刻を設定する必要があります。

Accuracy of RTC_GPS

測位の停止時に、GNSS デバイスはLSI内に持つRTCクロック精度のタイマー RTC_GPS を GPS 時間に更新します。 測位停止中は GNSS デバイスの時計は停止し、この RTC_GPS が計時します。 RTC_GPS が保持する時刻と実時間の誤差は、外付けRTC Xtalのクロック精度に依存します。 測位を再開するさい、GNSS デバイスはこの RTC_GPS の時刻を基に測位演算を行うため、停止期間が長いほど RTC_GPS の時刻は実時間に対して誤差を持ち、TTFFと初回測位位置の精度に影響を与えます。 測位停止から15分以上経つとRTC_GPS の時刻誤差は、その後の "Hot Start" の測位結果に対して無視し得なくなります。 長い測位停止期間の後にも、短いTTFFや高い初回位置精度を求める場合は、ioctlコマンドで時刻を設定することを考慮しても良いでしょう。

システムが電源オンされた直後は、RTC_GPS は "0h 6 - Jan - 1980" を示します。測位が完了すると GPS 時間が取得できるため、RTC_GPSがGPS時間にセットされます。時刻が指定されていない限り、測位計算は RTC_GPS をベースに行われます。

Set time by the command

アプリケーションがネットワーク等から取得した時刻を指定する場合は、ioctl コマンド CXD56_GNSS_IOCTL_SET_TIME を用います。

Current location

"Hot Start" のためには、直近の位置データが必要です。アプリケーションが位置データを保持していない場合は、GNSS デバイスは前回測定した位置情報をベースに "Hot Start" を行います。

Set location by the command

アプリケーションがネットワーク等から取得した位置情報を指定する場合は、ioctl コマンド CXD56_GNSS_IOCTL_SET_RECEIVER_POSITION_ELLIPSOIDAL もしくは、CXD56_GNSS_IOCTL_SET_RECEIVER_POSITION_ORTHOGONAL を用います。

11.6.5. Accurate Positioning

正確な測位を行うために、適切な受信条件で測位を行う必要があります。ビル街における衛星の見えにくさや大きな建物の反射波の影響、WIFIからのノイズなど、測位環境が精度の高い測位に影響を与えていないかが、測位データからある程度類推することができます。

Indication in receiver positioning data
Field numsv, numsv_tracking, numsv_calcpos, numsv_calcvel
Type

uint8_t

Unit

none

フィールド numsv, numsv_tracking, numsv_calcpos, numsv_calcvel は、それぞれ可視衛星数、追尾衛星数、位置演算に利用している衛星数、速度演算に利用している衛星数です。 可視衛星には、衛星軌道情報から現在の天空に存在が予想されるが、実際には障害物があり信号を受信していない衛星も含みます。 追尾している衛星の中でも受信が弱く正確性に欠く信号は測位や測速の演算に利用しません。 位置精度は後述の信号の強度や衛星の配置にも依存するため一概には言えませんが、一般的に numsv_calcpos の個数を 6 個以上に保つと数メートルの誤差で測位を続けられることが多いようです。

Field posDop, velIdx of struct cxd56_gnss_receiver_s
Type

struct cxd56_gnss_dop_s

Sub fields

pDop, hDop, vDop, ewDop, nsDop as float

Unit

none

posDop は 衛星の幾何学的な配置から求められる位置精度低下率である DOP(Dilution Of Precision) を含みます。 'p' は全体的な精度低下率、 'h' は水平方向の精度低下率、 'v' は縦方向の精度低下率、 'ew' は東西の精度低下率、 'ns' は南北の精度低下率を表しています。

DOP が小さいほど、測位するのに適した場所であることを示しています。例えば、街中のような狭い空では受信できる衛星は少なく、DOP は悪化します。pDOP が 5 を超えるような場合、測位には不適な条件であることを意味しています。一方、pDOP が 2以下だった場合は、測位するのに十分な条件を満たしています。

Field posAcc of struct cxd56_gnss_receiver_s
Type

struct cxd56_gnss_var_s

Sub fields

hVar, vVar as float

Unit

meter

これらの値は、測位データの正確さを表し、位置と速度の時系列値に対する共分散の平方根です。これらは、受信ノイズやその他の要因による測位データへの影響を見ることができます。'h' は水平方向の正確さ、 'v' は縦方向の正確さを表しています。

PosAcc は、測位誤差の標準偏差を表しています。衛星信号に対するノイズやマルチパスの影響、DOP の悪化などが測位結果に誤差を与えます。この値が大きいほど、測位データが不正確であることを示します。

Indication in satellite positioning data
Field sigLevel of struct cxd56_gnss_sv_s
Type

float

Sub fields

none

Unit

dBHz

この値は、ノイズに対する衛星からの信号の強さの比率である C/N0 比(または CN0, CN と表されることもあり)を表しています。 GNSS衛星からの信号はスペクトラム拡散のため、これをS/N比ではなく C/N0 比と呼び、また単位も dBHz となります。 この値が大きいほど、GNSSからの衛星信号の信頼性は高い事を示し、結果としてそれを用いた測位も安定します。 一方、ノイズ源が GNSS アンテナの近くにある、衛星の方向がアンテナの指向性が悪い方向と一致している、あるいは衛星とアンテナの間に障害物がある、さらに衛星信号の追尾が不良であると、この値は小さくなり、測位が不安定になります。 なお衛星信号個々にこれら C/N0比 悪化の要因は異なるため、各衛星によってC/N0比も異なります。 一般的に、5つ以上の衛星から信号の C/N0 が 30 dBHz以上で受信できていると測位結果は安定します。

Multi-GNSS

前出の様に捕捉追尾する衛星数が多いほど測位精度が向上する傾向があります。 GNSS デバイスは複数の衛星システムを同時に利用し、測位演算に供する衛星信号の数を増やすことが出来ます。

  • GLONASS

GPSと同様に全世界をカバーする24機体制のロシアの測位衛星システムです。 GPSだけでも十分衛星数が確保出来ている場合に、GPSシステムの標準精度 20m に比べると劣る精度 70m のGLONASSシステムの信号を混在して測位演算すると、GPS 単独の場合よりも位置精度が落ちる可能性があります。 なおアンテナにはGLONASSの周波数に対応していない物もあるため注意が必要です。

  • QZSS-L1C/A

日本のみちびきから送信される衛星信号です。 この信号はGPS L1C/Aと互換のため、これを利用するとあたかもGPS衛星が増えたかのように見えます。これをみちびきによるGPSの補完機能と呼んでいます。 みちびきは4機体制(2018年時点)で、その軌道は日本を中心に東アジアとオセアニア上空をカバーするため、それ以外の地域では補完効果がありません。

Augmentation

WAAS もしくは みちびきの QZSS-L1S から送信される補強信号を利用することで測位精度を上げることが出来ます。 補強信号はSBASフォーマットをベースとした、数分ごとに更新される測位演算の精度を向上するための計算パラメータです。 補強信号を使う場合、補強情報が無いGLONASSを混在させての測位は出来ません。

  • WAAS

WAASはアメリカ合衆国本土、カナダ、ハワイ及び属州で有効な補強信号です。 GPS衛星の信号から求められる擬似距離 [2]の精度を向上します。

  • QZSS-L1S

QZSS-L1Sは日本の範囲のみで有効です。 GPS衛星信号及びQZSS-L1C/Aから求められる擬似距離 [2]の精度を向上します。 仰角の低い衛星(2018年9月時点で仰角マスクは20度)は補強情報が送信されず、測位に使うことができません。

Select positioning and augmentation satellite systems

本 GNSS デバイスでは、以下の測位衛星システム及び補強信号の組み合わせで測位することを想定しています。 どの衛星システムを使うかは CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM で設定できます。

以下の測位誤差(Accuracy)は一般的な好条件下での参考値です。お使いのシステム及び環境によって変動します。
GPS GLONASS QZSS-L1C/A WAAS QZSS-L1S 95% Accuracy Effective place

x

<5m

under the open sky

x

x

<5m

in East Asia and Oceania

x

x

<7.8m

in the city

x

x

x

<7.8m

in the city of East Asia and Oceania

x

x

x

<2m

in Japan

11.6.6. Short message delivery

GNSS デバイスはQZSSみちびきから送信される災害情報、危機管理情報といった災危(災害・危機)通報を受信できます。

アプリケーションはシグナル通知を GNSS デバイスに設定することで、GNSS デバイスからの災危通報を非同期にシグナルで受けることができるようになります。 災危通報のシグナル通知の設定は、フィールド fd に GNSS デバイスのファイルディスクリプタを, enable には 1 を, gnsssig に任意のシグナル番号を、さらに gnsssig に CXD56_GNSS_SIG_SBAS を設定した cxd56_gnss_signal_setting_s データを、IOCTRLコマンド CXD56_GNSS_IOCTL_SIGNAL_SET の引数として ioctl関数を呼び出してシグナルと災危通報を関連付けして下さい。

GNSS デバイスは SBAS メッセージタイプ の 43 (気象庁防災情報)または 44 (任意情報)を受信すると、関連付けしたシグナルを発行します。 sigwaitinfoでのシグナル処理にて データバッファに doxgen:cxd56_gnss_sbasdata_s[] 、 CXD56_GNSS_READ_OFFSET_SBAS をオフセットとしてGNSSデバイスを read することで通知の要因となった SBAS メッセージを読み出すことが出来ます。

11.6.7. Utilities

NMEA converter

NMEA は GPSアプリケーションで広く使われている位置情報のテキストフォーマットで、gnss ライブラリは NMEA フォーマットの出力もサポートしています。

利用するには、CONFIG_MLIB を 'y' に設定する必要があります。cxd56_gnss_sv_s に格納された GNSS デバイスの内容を NMEA に変換します。

詳細については、gnss_nmea ならびに、NMEA Output を参照してください。

11.6.8. Geofence

Key features

Geofence はあらかじめ指定した領域に近づいたときに通知するためのライブラリです。

  • 領域は Latitude, Longitude, Radius で指定できます

  • 最大 20 領域まで指定できます

geofence notification
図 50. Geofence transition notification

通知は "ENTER", "DWELL", "EXIT" の3種類あります。"DWELL" の場合は、その領域に滞在した時間も通知条件に設定することができます。

Configuration

Geofence を使う場合、GNSS device と Geofence Support を 'y' に指定してください。

[System Type]
  CXD56xx Peripheral Support -->
    [*] GNSS device
    [*]   Geofence Support
Add Region and setup options

Geofence を使うには "/dev/geofence" デバイスファイルを使います。

CXD56_GEOFENCE_IOCTL_ADD

領域を追加するためのコマンドです。

領域は最大20箇所、設定することができます。それぞれの領域は、Latitude, Longitude, Radius で設定できます。

North latitude と East longitude の方向は '+' を与えます。South latitude と West longitude の方向は '-' になります。

CXD56_GEOFENCE_IOCTL_SET_MODE

Geofence が定義された領域の同心円状の領域(Dead Zone)と、その領域に侵入を許す期間 "dwelling period" を指定します。

State transition
Geofence state transition
図 51. Geofence state transition
Dead zone

"Dead Zone" とは定義された領域の半径 (Radius) で定義された同心円状の領域を示します。

  • "ENTER" が定義された場合、その同心円領域に入ると通知します

  • "EXIT" が定義された場合、その同心円領域から出ると通知します

Geofence Dead Zone
図 52. Geofence Dead zone
Read Geofence transition data

状態変化は、poll によって通知されます。 cxd56_geofence_status_s に状態遷移の情報が格納されています。

詳細については、アプリケーションサンプル Geofencing Transitions を参照してください。

11.6.9. PVTLog

Key features

PVTLog は、Position, Velocity, Time の情報のログです。

最大 170 のログを蓄積することができます。ログがあふれた場合は、アプリケーションはシグナルにより通知を受けることができます。 例えば、15分ごとにログを取得した場合、42時間は継続して記録することができます。

ログデータの詳細については、cxd56_pvtlog_s を参照してください。

Configuration

PVTLog を使う場合は、GNSS device Support を 'y' に設定してください。

[System Type]
  CXD56xx Peripheral Support -->
    [*] GNSS device
Start and stop log store

ログを開始するには、ioctl コマンド CXD56_GNSS_IOCTL_PVTLOG_START で行うことができます

記録する間隔についても、このコマンドを使ってください。ログを記録する間隔は測位する間隔よりも大きくする必要があります。

測位を開始するとログは自動的に開始します。ログを停止するには、ioctl コマンド CXD56_GNSS_IOCTL_PVTLOG_STOP を使ってください。

Notification

記録しているログが 170 を超えると、シグナルによりアプリケーションにログが溢れたことが通知されます。 シグナルの設定は、CXD56_GNSS_SIG_PVTLOG で行うことができます。

この通知を受け取ったら、次の記録が行われるまでにログを読み出す必要があります。でなければ、最初のログデータが次の測位データに上書きされることになります。

ログデータは、CXD56_GNSS_READ_OFFSET_PVTLOG でオフセットが指定された位置から読み込むことができます。

ログデータは、バックアップ RAM に記録されます。すでにデータが存在する場合は、消去されることなく上書きされます。 バックアップをクリーンナップする場合は、CXD56_GNSS_IOCTL_PVTLOG_DELETE_LOG を使います。

詳細に関しては、サンプルプログラム PVTLog を参照してください。

11.6.10. Application Examples

Notify Positioning

GNSS 測位の通知は、poll とシグナルによって行われます。どちらを使うかは、CONFIG_EXAMPLES_GNSS_USE_SIGNAL もしくは CONFIG_EXAMPLES_GNSS_USE_POLL を Kconfig で選択できます。

はじめに

gnss_atcmd は Spresense SDK 上で動作する GNSS 機能評価用のサンプルアプリケーションです。 PC 等のホストからシリアルポートを介してコマンドを送信すると、そのシリアルポートに NMEA センテンスの結果が出力されます。具体的なコマンドの仕様とアプリケーションの使用例について後述します。

@コマンド仕様

ホストから送信するコマンドの仕様について説明します。

PC 等のホストから送信されたコマンドを gnss_atcmd アプリケーションが受信し、処理結果をホストに返します。コマンド送信から結果が応答されるまでの期間は、NMEA は出力されません。gnss_atcmd アプリケーションからコマンド完了を示す応答メッセージ (Done または Err ) が返ってくる前に別のコマンドを発行しないようにして下さい。なお、コマンド送信からコマンド応答が返るまでの時間はコマンドの種別およびその時の状態により異なりますが、ワーストケースで約 5 秒かかることがあります。ホストコントローラにてタイムアウトを検出する際は 5 秒にてタイムアウトと判断して下さい。

コマンドフォーマット

コマンドの書式は以下の通りです。"@" (アットマーク)に続いてコマンド文字列や引数を送信し、最後に改行コードを送ります。

@Command [Argument0] [Argument1]...<CR><LF>
Command

4 文字以内の文字列です。詳細は下表 コマンド一覧 を参照してください。

Argument

10 進数で表される数値です。文字列の先頭が "0x" の場合は 16 進数を表します。 コマンドによっては複数の引数をとります。

<CR><LF>

改行コードを表します。コマンド行の終わりには CR (Carriage Return) + LF (Line Feed) を付けてください。

正常応答フォーマット

正常応答結果の書式は以下の通りです。[送信したコマンド文字列]に続いて、"Done"の文字列が返ります。

[Command] Done<CR><LF>
Command

受信したコマンド文字列を表します。

<CR><LF>

改行を表します。応答行の終わりには CR (Carriage Return) + LF (Line Feed) が付加されています。

エラー応答フォーマット

エラー応答結果の書式は以下の通りです。[送信したコマンド文字列]に続いて、"Err"の文字列とエラーコードが返ります。

[Command] Err ErrorCode<CR><LF>
Command

受信したコマンド文字列を表します。

ErrorCode

負値のエラーコードを表します。

<CR><LF>

改行を表します。応答行の終わりには CR (Carriage Return) + LF (Line Feed) が付加されています。

コマンドシーケンス

@GCD のような測位開始のコマンドを発行すると、"Done" の応答を返した後に、定期的に NMEA センテンスが Host へ送られます。

diag 39f656ff7a75cce3fd8105715f5adca1

@VER コマンドを発行すると、バージョン情報が送られた後に、"Done" の応答が返ります。

diag aecaf2c20740a1432f3725e6be277c10
コマンド一覧

gnss_atcmd が処理可能なコマンド一覧を下記に示します。

Command Argument Description

@AEXT

-

アプリケーションを終了します。 本コマンドは測位停止中に実行してください。

@BSSL

NMEAマスク

NMEA 0183 (ver 4.00) 規格で定義されているNMEAセンテンスのうち、 出力するNMEAセンテンスをビットマスク値で引数に指定します。 初期状態ではNMEAマスクには0xefが設定されています。

NMEA Bit Description

$xxGGA

0

時刻、緯度経度、標高、測位状態、DGPS基地局番号などの基本情報

$xxGLL

1

時刻、緯度経度、測位状態などGGAの簡易版

$xxGSA

2

衛星毎の使用不使用、DOP値

$xxGSV

3

可視衛星の衛星番号、仰角、方位角、信号強度

$xxGNS

4

時刻、緯度経度、測位状態

$xxRMC

5

時刻、緯度経度、速度、時期偏差

$xxVTG

6

移動速度に関する詳細情報

$xxZDA

7

年月日を含む時刻情報

$QZQSM

14

災害危機管理通報サービスメッセージ(QZSS独自センテンス)

xx は、以下を表します。

  • GP:GPS衛星のみで測位している場合

  • GL:GLONASS衛星のみで測位している場合

  • QZ:QZS衛星のみで測位している場合

  • GN:複数の衛星システムを利用して測位している場合

コマンド例:

$xxGGAのみ出力を設定

@BSSL 0x1<CR><LF>

$xxRMCと$QZQSMの出力を設定

@BSSL 0x4020<CR><LF>

@BUP

-

受信済みのエフェメリス及び各種パラメータを Flash へセーブします。 セーブされたデータは次回起動時に自動的にリストアされます。 本コマンドは測位停止中に実行して下さい。

@GCD

-

Cold Start による測位を開始し、NMEAセンテンスを周期的に出力します。
出力されるNMEAセンテンスはNMEAマスクに従います。

@GNS

衛星マスク

測位に使用する衛星を引数のビットマスク値で選択します。
例)GPSの場合は 0x1、Hybridの場合は0x3を指定

Bit Satellite

0

GPS

1

GLONASS

2

SBAS(WAAS)補強

3

QZSS L1C/A補完(みちびき)

4

予約

5

QZSS L1S補強(みちびき)

NOTE
補正信号は排他的使用が前提です。使用方法についてはSDKドキュメントをご参照ください。

コマンド例:

GPSを選択

@GNS 0x1<CR><LF>

GPS+GLONASS+QZSS L1C/Aを選択

@GNS 0xb<CR><LF>

@GPOE

<緯度[度]>
<緯度[分]>
<緯度[秒]>
<経度[度]>
<経度[分]>
<経度[秒]>

楕円体座標の受信機現在位置を設定します。

コマンド例:

北緯35°37’09”,東経139°43’51”

@GPOE 35 37 09 139 43 51<CR><LF>

北緯33°07’19”,西経117°19’18”

@GPOE 33 07 19 -117 19 18<CR><LF>

@GSR

-

Hot Start による測位を開始し、NMEAセンテンスを周期的に出力します。
出力されるNMEAセンテンスはNMEAマスクに従います。

@GSTP

-

測位を停止します。

@GSW

-

Warm Start による測位を開始し、NMEAセンテンスを周期的に出力します。
出力されるNMEAセンテンスはNMEAマスクに従います。

@GTIM

<年>
<月>
<日>
<時>
<分>
<秒>

UTC時刻を設定します。

コマンド例:

2018/2/1 13:30'30"

@GTIM 2018 02 01 13 30 30<CR><LF>

2018/7/10 00:00'00”

@GTIM 2018 07 10 00 00 00<CR><LF>

@VER

-

ALLゼロのバージョン番号を返します。

アプリケーション動作例

gnss_atcmd アプリケーションの動作実施例を示します。

Configuration

本アプリケーションを実行するためには、以下の SDK Configuration を有効にしてください。

CONFIG_CXD56_GNSS=y
CONFIG_GPSUTILS_CXD56NMEA_LIB=y
CONFIG_EXAMPLES_GNSS_ATCMD=y

下記のコマンド実行することでこれらの Configuration を自動的に有効にすることができます。

$ ./tools/config.py examples/gnss_atcmd

また、コマンド入出力に使用するポートを、コンフィグレーション GNSS Command IO によって切り替えることができます。

│ Prompt: GNSS Command IO
│   Location:
│     -> Examples
│       -> GNSS CXD5603 @command emulator example (EXAMPLES_GNSS_ATCMD [=y])
  • Example uses USB CDC tty : 拡張ボード上の USB ポートを使用 (デフォルト)

  • Example uses STDINOUT for nsh debug UART : メイン基板上の USB ポート (UART1)

  • Example uses UART ttyS0 : メイン基板上の USB ポート (UART1)

  • Example uses UART ttyS1 : 非サポート

  • Example uses UART ttyS2 : メインボード及び拡張ボード上の UART ポート (UART2)

nsh プロンプトから gnss_atcmd アプリケーションを実行した後に、ターミナルから前述したコマンドを入力します。

例: Cold Start による測位の開始と停止

GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 その後 NMEA センテンスが出力され、適当な期間の後、測位を停止して gnss_atcmd を終了します。

nsh> gnss_atcmd       (アプリケーション開始)
@GNS 0x0b↵         (測位衛星の選択)
@GCD↵             (Cold Start測位開始)

----- <NMEA出力> ----

@GSTP↵            (測位停止)
@AEXT↵           (アプリケーション終了)
nsh>

例: GNSS 終了後の Hot Start 測位

初めに GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 測位された後に、Spresense の電源は保ちつつ GNSS を終了し、再度 Hot Start で測位を開始します。 Hot Start では測位開始から数秒後に測位が FIX します。

nsh> gnss_atcmd       (アプリケーション開始)
@GNS 0x0b↵         (測位衛星の選択)
@GCD↵             (Cold Start測位開始)

----- <NMEA出力> ----

@GSTP↵            (測位停止)
@AEXT↵           (アプリケーション終了)

nsh> gnss_atcmd       (アプリケーション開始)
@GSR↵             (Hot Start測位開始)

----- <NMEA出力> ----

@GSTP↵           (測位停止)
@AEXT↵           (アプリケーション終了)
nsh>

例: Spresense 電源 OFF 後の Hot Start 測位

初めに GPS、Glonass、QZSS L1C/A を測位衛星として選び、Cold Start で測位を開始します。 その後、GNSS を終了した後に Spresense の電源を OFF します。

再度 Spresense の電源を入れた後、UTC 時刻と現在位置を入力して Hot Start で測位を開始します。 Hot Start では測位開始から数秒後に測位が FIX します。

nsh> gnss_atcmd       (アプリケーション開始)
@GNS 0x0b↵         (測位衛星の選択)
@GCD↵             (Cold Start測位開始)

----- <NMEA出力> ----

@GSTP↵            (測位停止)
@BUP↵              (Flashへバックアップ)
@AEXT↵           (アプリケーション終了)

----- <Power OFF> -----

----- <Power ON> -----

nsh> gnss_atcmd       (アプリケーション開始)
@GTIM 2018 11 09 02 45 05↵   (UTC 時刻設定)
@GPOE 35 39 31 139 44 05↵  (現在位置の設定)
@GSR↵             (Hot Start測位開始)

----- <NMEA出力> ----

@GSTP↵           (測位停止)
@AEXT↵           (アプリケーション終了)
nsh>

みちびきQZQSMセンテンスの出力

衛星マスクにQZSS L1/CAを選び、NMEAマスクでQZQSMセンテンスを有効にした後、測位を開始します。 受信条件が良ければ10秒弱で最初のQZQSMセンテンスが出力され、その後4秒毎に出力されます。

nsh> gnss_atcmd

@GNS 0x29↵

@BSSL 0x40ef↵

@GCD↵

$GPGGA,000001.00,,,,,0,00,,,,,,,*49 $GNGLL,,,,,000001.00,V,N*55
…​
$GNZDA,000008.00,06,01,1980,,*77 $QZQSM,56,9AADF260540002C3F2587F8B101962082C41A588ACB1181623500011439023C*7B $GPGGA,000009.00,,,,,0,00,,,,,,,*41
…​

Geofencing Transitions
GNSS Status on e-ink Display

11.7. ASMP Framework

11.7.1. ASMP Framework の概要

ASMP Frameworkはマルチコアプロセッサを簡単に扱えるように用意されたフレームワークです。

このフレームワークには二つのタスクが定義されています。

  • Supervisor タスク (Main CPU task)

  • Worker タスク (Sub CPU task)

diag c4534bd31de8be84c88a5b2bb7d3bfc7
図 53. ASMPフレームワーク関連図

Supervisorタスクは、ASMP Framework API を使用してWorkerタスクの起動、停止などの制御を行います。 詳細は、 MP Task を参照してください。

Workerタスクは、 Main CPUとは完全に独立したタスクで、Sub CPU上で並列処理されるタスクです。したがって、タスク間でデータや状態をやりとりするための通信手段が必要になります。

ASMP Frameworkでは、SupervisorおよびWorkerそれぞれのタスクが通信するための以下の機能を提供しています。

MP message queue は POSIX の message queue に似たメッセージ交換用のインターフェースです。

diag d2717059fdc2bcbb3223b39c19a30144
図 54. MP Message Queue

MP mutex は、pthread mutex に似た排他制御用のメカニズムを提供します。

diag e14bf772ca9c7d753d2e5553217419ec
図 55. MP Mutex

MP shared memory は、それぞれのタスクで共有されるメモリ領域を提供します。

diag bbeb95a67ff807e65635e69b7ab7b9b1
図 56. MP Shared Memory

11.7.2. Configuration

[ASMP] = Y
  [ASMP shared memory size]  = 0x100000

ASMP framework は、 タスク間の共有メモリのために、カーネル管理外のメモリ領域を必要とします。このメモリ領域は、 ASMP shared memory size オプションで変更できます。もし、 ASMP frameworkを必要としないのであれば、カーネルは 1.5MB のメモリを活用することができます。

ASMP Shared memory size 設定は、128KB単位(0x20000)で設定してください。

11.7.3. Workerの起動シーケンス

diag 20db56474b818e42a1da773d4e17869c
図 57. Worker 起動フロー
  1. mptask_init を呼び出してWorkerを生成します

  2. 必要に応じてメッセージキューや共有メモリなどを準備し、Workerに紐付けます

  3. mptask_exec を呼び出してWorkerを実行します

  4. 終了時には mptask_destroy を呼び出してWorkerを停止させます

  5. メッセージキューや共有メモリなどを作成していた場合は破棄させます

詳細は、Supervisor Task example および Worker Task example を参照してください。

11.7.4. Workerのビルド

Workerタスクは、ELFフォーマットのファイルをロードして実行します。ただし、WorkerはサブCPUで動作するため、カーネルやSDKのAPIを直接呼び出すことはできません。

ASMP frameworkがサポートする ELFファイルのレイアウトは以下になります。

diag d1ca866e2680ce3dc99cf576a184d309
図 58. Worker用の ELFファイルのレイアウト

それぞれのプログラムの開始アドレスは 0x00000000 でなくてはならず、それぞれのセクションは連続である必要があります。 SDKでは、Worker用ELFファイルを生成するために必要なコンパイラオプション、リンカオプションおよびリンカスクリプトを提供しています。 これらはそれぞれ CELFFLAGSLDRAWELFFLAGS として sdk/Make.defs 内で定義されています。具体的なビルドルールは ASMP Worker Task 'Hello World' example を参照してください。

さらに、WorkerでASMP Frameworkを使用するためには、Worker用ライブラリが必要です。このライブラリには、Workerを構成するための必要なコード(上図の青色部)が含まれています。ただし、このライブラリはSDKのビルドシーケンス中に用意されないため、ユーザーがWorkerをビルドする際に事前に生成しておく必要があります。

Worker用ライブラリを生成するためのサンプルは、Worker Task Makefile および Worker Task Library Makefile を参照してください。

11.7.5. サンプルコード

11.8. Sensor Control Unit

11.8.1. Overview

Sensor Control Unit (SCU) は、SCU デバイス内の SPI もしくは I2C バスに接続されたセンサーデバイスからのセンシングデータを取得することができます。CPUとは独立して動作するため、センサー取得に関わるCPUの負荷を軽減することができます。

主な特徴
  • シーケンサーによるセンサーデータの自動取得

  • センサーデータ間引き機能(デシメーター)

  • IIR フィルター機能

  • イベント通知機能

これらの機能は、アプリケーションから設定することができます。

SCU は SPI と 2つの I2C バスと 8つのシーケンサーと2つのデシメーターを搭載しています。

diag a66a2aee7a119a9117ae56bdfd03ac90
図 59. SCU block diagram

11.8.2. Configuration

  CXD56xx Configuration  --->
    Sensor Control Unit (SCU)  --->
      Sequencer Sampling Predivider  = 64 (default) (1)
      SCU clock mode                 = RCOSC (default) (2)
      SCU32K clock source            = RTC (default) (3)
      SCU Decimator assignments (4)
        ...
        (Decimator supported drivers)
        ...
      SCU Debug                      = N (default)
      DMAC support                   = Y (default)
1 Sequencer Sampling Predivider は、シーケンサーのサンプリングレートに影響します
2 SCU clock mode はSCUの動作クロックを指定します
3 SCU32K clock source は サンプリング周波数(32768Hz)のクロックソースを選択できます
4 SCU デシメーターは 3つ以上のセンサーに割り当てられますが、デシメーターに割り当てたセンサーの同時使用は2つまでです。

11.8.3. シーケンサー

SCU は2つの種類のシーケンサーがあります。通常のシーケンサーは、センサーデータを定期的に取得し、FIFO に蓄積していきます。デバイスドライバは、このFIFOからデータを取得していきます。

diag c1785ba91bc9f1ad5a61bda8b03d2997
図 60. Sequencer block diagram

それぞれのシーケンサーの FIFO は、SCUIOC_SETFIFO で指定されるサイズに分割されます。FIFOメモリーは全部で 40KB です。アプリケーションは、デバイスドライバを使う前にセットする必要があります。

ret = ioctl(fd, SCUIOC_SETFIFO, sizeof(struct three_axis_s) * 128);

シーケンサーは、サンプリングレートで指定される間隔でセンサーデータを取得していきます。センサーデバイスの仕様で決められたサンプリングレートではないことに注意してください。アプリケーションは、シーケンサーに対し、SCUIOC_SETSAMPLE を使用して、サンプリングレートを使用する前に設定する必要があります。

ret = ioctl(fd, SCUIOC_SETSAMPLE, 2);

SCUIOC_SETSAMPLE は、2 のべき乗でベースクロック(32KHz)を割った数を指定します。

Sequencer sampling rate = 32768 / CONFIG_CXD56_SCU_PREDIV / (2 ^ n)

CONFIG_CXD56_SCU_PREDIV がデフォルト値64の場合に、 SCUIOC_SETSAMPLE で2を指定した場合のサンプリングレートは 128 Hz になります。

アプリケーションは、シーケンサーのサンプリングレートが、センサーの仕様で定められたサンプリングレートと異なることに注意する必要があります。アプリケーションは、センサーデバイスのサンプリングレートとシーケンサーの両方に設定し、その組み合わせがうまく行くことを確認する必要があります。

アプリケーションは SCUIOC_SETWATERMARK で定められたシグナルを受信することができます。シーケンサーのFIFOに watermark に定められた数までセンサーデータが格納されると、SCUドライバはアプリケーションに対してシグナルを発行します。

例えば、アプリケーションがサンプリングレートを 128 Hz に設定し、watermark を 128 に設定したとすると デバイスドライバは1秒ごとにシグナルを発行することになります。

wm.signo = CONFIG_EXAMPLES_MAG_SIGNO;
wm.ts = &ts;
wm.watermark = 128;

ret = ioctl(fd, SCUIOC_SETWATERMARK, (unsigned long)(uintptr_t)&wm);

アプリケーションが、指定した watermark シグナルを受信すると、FIFOの最初のサンプリングデータの取得タイムスタンプがシグナルの siginfo 構造体に格納されます。

11.8.4. デシメーター

デシメーターは、FIFOに取得したデータを間引きする機能でシーケンサーの機能を拡張するために設けられたものです。デシメーターは 3 つの FIFO を持っています。

diag 0b3cd224d7ba24a3341d235eafb78bcc
図 61. Decimator block diagram
デシメーション処理

デシメーターは CICフィルターを適用してシーケンサーが取得したデータを間引きします。アプリケーションは、デシメーターのパラメーターを SCUIOC_SETDECIMATION コマンドを使って、 decimation_s 構造体で指定して変更することができます。

dec.ratio = 1;
dec.leveladj = SCU_LEVELADJ_X1;
dec.forcethrough = 0;

ret = ioctl(d->fd, SCUIOC_SETDECIMATION, (unsigned long)(uintptr_t)&dec);

ratio は、サンプリングレートで指定されたデータを取り出す間隔を2のべき乗数で指定します。例えば、サンプリングレートが 64Hz で、ratio が 1 だった場合、 ( 64 / (2 ^ 1) ), となり実際のサンプリングレートは 32Hz になります。 CIC フィルターはサンプリングされたデータに対して適用されることに注意してください。もし、CIC フィルターを使いたくない場合は、 forcethrough を 1に設定してください。

取得データの増幅

デシメーターは、 decimation_s 構造体の leveladj を使うことで取得データを増幅させることができます。増幅されたデータはそのもとのデータ幅を超過してしまいますので、使用の際は注意が必要です。

leveladj は以下の設定ができます。

デシメーターサポート済みセンサー

デシメーターを使う場合は、センサードライバが対応している必要があります。現在、サポートされているセンサードライバ は以下になります。

  • KX022

  • BMI1422GMV

11.8.5. センサーデータへの信号処理

SCU は、取得したデータに対して信号処理を加えることができるようになっています。 SCUが行える信号処理は、IIRフィルターとイベント検出の2つがあります。 IIRフィルターはデータパス上の3箇所に設定をすることができます。使用するFIFO毎に設定する必要があります。

IIR フィルター
diag ad9db3a7d27d9a0f8bdd7ae0a7ff047d
図 62. IIR filter path
A

FIFO と イベント検出(Event detector)の両方に適用します

F

FIFOにのみ適用します

E

イベント検出(Event detector)にのみ提供します

アプリケーションは二つのIIRフィルターを設定することができます。FIFOは、シーケンサーFIFOかデシメーターFIFO です。イベント検出は特殊な機能であり、後述します。

IIRフィルターの組み合わせ
  • (A)に2つとも適用

  • (A) と (F)に適用

  • (A) と (E)に適用

  • (F) に2つとも適用

  • (F) と (E)に適用

  • (E) に2つとも適用

IIR フィルターの設定箇所は、 filter_pos_e に定義されています IIR フィルターは、係数によって調整することができます。

IIR filter block diagram
図 63. IIR filter block diagram

それぞれの係数は 34 bit の固定小数点で、 s2.31 format です。したがって、IIR フィルターの係数は、32 bit (h) と 8bit (l) で構成されます。

struct_iir_coeff_s
図 64. struct iir_coeff_s h, l

31 bit の h は S(signed bit) です。, 0 = plus, 1 = minus.

30 から 29 bit の h は整数部です。

28 から 0 の h と、 7 から 6 bit の l は、小数部になります。

イベント検出 (Event detector)

イベント検出 (Event detector) は、センサーデータの状態を監視し、その変化を検出します。アプリケーションはどのタイミングでセンサーを取得すべきか判断できるようになります。

イベント検出は、閾値で定められたセンサーデータの幅を超過している数をカウントします。イベント検出に使用できるセンサーデータは 16bitになります。取得したデータが、例えば、XYZ軸それぞれのデータだった場合、normalize 計算を行った後、データが設定値から超過しているか判定します。カウントした数が設定値に達したら、イベント検出器はタイムスタンプ付きの割り込みを発生させます。

normalize 計算は、監視するデータの数(1-3)よって異なります。

  • 1 つだった場合 (例えば、X軸のみ):

  norm = abs(x)
  • 2 つだった場合 (例えば、X軸とY軸 ):

 norm = max(abs(x), abs(y)) * 123 / 128 + min(abs(x), abs(y)) * 51 / 128
  • 3 つだった場合 (例えば、X軸, Y軸, Z軸):

  L1   = max(abs(x), abs(y)) * 120 / 128 + min(abs(x), abs(y)) * 49 / 128
  norm = max(L1, abs(z)) + min(L1, abs(z)) * 44 / 128

イベント検出の設定には scuev_notify_s 構造体を使用します。 risefall の二つの設定値があり、それぞれ threshold, count0 , count1 を持っています。 イベント検出器は カウントしたデータが、 count0 + count1. に達したらアプリケーションに通知を行います。

イベント検出器は IIR フィルターの出力を使うため、IIR フィルターは最初に設定されている必要があります。

scu event
図 65. Event detection
Event detector processes
  • 閾値を超えた値をカウントします

  • カウント数が count0 に達したら、 count1 をスタートします。

  • もし、データ数が count0 に達する前に閾値より小さくなったらカウントをストップしカウント数をリセットします。

  • トータルカウント count0 + count1 に達したらイベントを通知します

  • count1 がゼロだった場合、 count0 の値が閾値に達したら、ただちにイベントを通知します。

  • count0 がゼロだった場合、設定はすべて無視されます

11.8.6. 制限

デシメーター、IIR フィルター、イベント検出器が扱えるデータには、以下の制限があります。

  • 1つのサンプリングデータが16 bit

  • 最大3つのデータ要素

11.8.7. ドライバ開発者のためのガイドライン

SCU機能をサポートしたドライバを開発するには以下の内容を理解する必要があります

  • シーケンサーインストラクションの理解

  • センサーデバイスとの通信方法

  • シーケンサーの初期化(Open) とセンサードライバとの接続方法

  • シーケンサーからサンプルデータを読み出す方法

  • シーケンサーに対して ioctl を介してコマンドを指示する方法

シーケンサーインストラクションの理解

シーケンサーインストラクションは1命令あたり16bitで、センサーデバイスと通信するために、SPI もしくは I2C バスを使います。

ドライバを開発する際は、 SCU_INST_SEND もしくは SCU_INST_RECV マクロを使うことができます。

シーケンサーを通してデータの送受信をする際は、送受信の方法を設定した一連の命令をuinit16_tの配列に格納して設定します。また、送受信の最後には、送信が終了したことを示す SCU_INST_LAST を指定する必要があります。

instruction array の簡単な例
inst[0] = SCU_INST_SEND(0x00);                  // Send register address 0x00
inst[1] = SCU_INST_RECV(2) | SCU_INST_LAST;     // Read 0x00 and 0x01 address data, and indicate the last of instructions
センサーデバイスとの通信方法

最初にドライバはターゲットのセンサーデバイスを初期化しなければなりません。SCU機能をサポートするドライバは、scu_spitransfer もしくは scu_i2ctransfer を使ってセンサーデバイスのレジスタにアクセスする必要があります。

Ex. Register write access function
static void sensor_putreg8(FAR struct sensor_dev_s *priv, uint8_t regaddr, uint8_t regval)
{
  uint16_t inst[2];

  /* Send register address and set the value */

  inst[0] = SCU_INST_SEND(regaddr);
  inst[1] = SCU_INST_SEND(regval) | SCU_INST_LAST;

  scu_i2ctransfer(priv->port, priv->addr, inst, 2, NULL, 0);
}
SCU に直接つながっている SPI と I2C バスは、SCU とセンサードライバが同時にアクセスが発生すると衝突が発生し、誤作動の原因になります。デバイドライバ開発者は、提供される API を通じてのみ、デバイスにアクセスするようにしてください。
シーケンサーの初期化(Open) とセンサードライバとの接続方法

SCU機能をサポートしたドライバはシーケンサーオブジェクトをすべての操作で扱うことになります。それぞれのドライバは、このオブジェクトを保持しておく必要があります。

g_seq = seq_open(MAG_SEQ_TYPE, SCU_BUS_I2C0);
if (!g_seq)
  {
    return -ENOENT;
  }
priv->seq = g_seq;

このサンプルの場合、シーケンサーをOpenし、デバイスデータの中に格納しています。

デシメーターについては、3つのFIFOから読み出すことが可能なので、3つのデバイスファイルを生成しています。

seq_open() は必ず一度だけ呼び出す必要があります。ドライバ開発者は重複して初期化しないように注意する必要があります。

if (g_refcnt == 0)
  {
    int ret;
    ret = sensor_seqinit(priv);
    if (ret < 0)
      {
        return ret;
      }
  }
else
  {
    /* Set existing sequencer */
    priv->seq = g_seq;
  }
g_refcnt++;

SCU はシーケンサーが処理をしていないときにスリープすることができます。 seq_open()seq_close() APIs は SCU のスリープ機能をサポートしています。 ドライバ開発者は、open() もしくは close() を実装するときに、これらの API を呼び出すと同時にセンサーデバイスのパワーモードもコントロールするようにしてください。 それによりシステムは、より省電力を実現することができるようになります。

シーケンサーからサンプルデータを読み出す方法

シーケンサーがセンサーデータを読み出すときは、データを読み出すための一連のシーケンサ命令群を seq_setinstruction で設定します。

以下の例では、 SENSOR_DATA_REGISTER から SENSOR_BYTESPERSAMPLE 数分だけ読みだしています。

static const uint16_t g_sensorinst[] =
{
  SCU_INST_SEND(SENSOR_DATA_REGISTER),
  SCU_INST_RECV(SENSOR_BYTESPERSAMPLE) | SCU_INST_LAST,
};
seq_setinstruction(priv->seq, g_sensorinst, itemsof(g_sensorinst));

シーケンサーは、センサーデータをこの一連のシーケンサ命令群によって定期的に読み出し、FIFO にデータを蓄積します。

蓄積されたセンサーデータをFIFOから読み出す場合は seq_read() 関数を使用してください。

len = seq_read(priv->seq, priv->id, buffer, len);
シーケンサーに対して ioctl を介してコマンドを指示する方法

SCUはデバイスファイルを持たないため、SCUに対して ioctl() を行うために、センサードライバが代わりに仲介する必要があります。 これを行うためには、seq_ioctl() を各ドライバの ioctl() 内で呼ぶようにします。SCUのIOコマンドかどうかを判定するためには、 _SCUIOCVALID() マクロを使用してください。

e.g.
if (_SCUIOCVALID(cmd))
{
  /* Redirect SCU commands */
  ret = seq_ioctl(priv->seq, priv->id, cmd, arg);
}

11.9. Memory Utility Libraries

11.9.1. 概要

メディア処理&センサー処理機能では、データ用に多くのメモリを安全に、フラグメンテーションなどのリークを発生させずに管理する必要があります。このため、Spresenseでは、メモリユーティリティライブラリを提供しています。

ライブラリは、以下の3つのライブラリ、”Memory Manager” 、"Message Library"、"Simple FIFO"で構成されています。

  • ”Memory Manager” は、Multi task 間で、メモリ領域を安全に管理するため、 暗黙的にセグメントエリアを管理する固定長メモリプールライブラリです。

  • "Message Library" は、”Memory Manager” を使うために、クラスオブジェクトをタスク間で送受信するためのライブラリです。

  • "Simple FIFO" は、アプリケーションとフレームワークの間でデータをやりとりするために使用される基本的なFIFOです。

これらのライブラリの利用をメディア処理&センサー処理では、前提としています。 詳細は、以下の各章に記載します。

11.9.2. Memory Manager

”Memory Manager” の説明をします。

概要

”Memory Manager" は、暗黙的な取得と解放を管理する固定長メモリプールです。 用途に応じたメモリ領域をメモリプールとして定義し、その中に必要なセグメントを確保することで、必要に応じたメモリの取得、解放が可能です。

プールの種別、セグメントの数などを決めて、メモリ領域を割り当てることで、メモリ領域のフラグメントなどを避けることができます。 この割り当て情報を "memory_layout" と呼び、このレイアウトをアプリケーションのニーズに合わせて切り替えることで、機能ごとに必要なメモリを確保します。

このメモリLayoutは、Applicationのニーズに従って自由に決めて、作成することが可能です。作成方法は、Configurations and Generateに記載します。

必要な "memory segment"の取得は、"MemHandle" を作成し、セグメントの確保のAPIを呼ぶことで可能です。これによって確保されたセグメントは、"MemHandle" のインスタンスが破棄されるまで、保証されます。
複数のユーザーが非同期に "MemHandle"を確保、解放を行っても、その領域は保証され、すべてのユーザから参照されなくなった時点で解放されます。

セグメント獲得、解放の仕組み

各ユーザオブジェクトは、必要なメモリエリアのセグメントを指し示すMemHandleのインスタンスを生成し、セグメントエリアを取得するAPIを呼ぶことで、それに紐付くメモリセグメントを確保します。

その際、セグメントエリアの参照カウンタを+1します。 これによって、セグメントエリアは使用状態になり、他の要求からは使えないように管理されます。

Get memHandle

この参照カウンタは、"operator=" や、"Copy Constructor" 内でも+1を行います。

このことで、データパイプラインの次に位置するオブジェクトに、この "MemHandle" のインスタンスをコピーし、渡していくことで、 "MemHandle" に紐付いたセグメントを参照することができるとともに、そのエリアを保証できます。

Copy memHandle

逆に、不要になった場合は、"MemHandle" のインスタンスを破棄することで、"Destoractor" 内で、参照カウンタが-1されます。
このことで、参照しているインスタンスがすべてなくなった時点で、自動的にリンクされているセグメントは解放されます。

Use memHandle

この仕組みにより、必要なオブジェクトが各自メモリが、非同期に必要な間インスタンスを確保し、不要になったら各自のタイミングで破棄したとしても、安全にメモリを確保・解放することができ、意識することなく、すべてのユーザがインスタンスを破棄することで、暗黙の裡に参照が外れます。

Release memHandle

Memory Layoutに関しては、Memory Layoutを使うためのヘッダファイル群をあらかじめ用意する必要があります。 これらのヘッダファイルは、Memory Layout定義ファイル(mem_layout.conf)を作成し、専用のツール(mem_layout.rb)を使うことで、生成されます。

APIs

”Memory Manager"のインタフェースは次の通りです。 詳細は、 memutils_memory_manager を参照してください。

Managerクラスの関数
MemMgrLiteライブラリの初期化
関数
static err_t Manager::initFirst(void* lib_area, uint32_t area_size)
引数
void*     lib_area   : ライブラリが使用するデータ領域
uint32_t  area_size  : 領域のサイズ(byte単位)
戻り値
ERR_OK        : 初期化成功
ERR_STS       : 2回以上、本関数を実行している
ERR_DATA_SIZE : area_sizeが、sizeof(MemMgrLite::Manager)未満
ERR_ADR_ALIGN : lib_areaが、4の倍数ではない
説明
ライブラリ全体の初期化を行う。
フェンス機能が有効な場合は、FixedAreaのフェンスの初期化を行う。
本ライブラリの他のAPIを使用する前に、
//事前に取り決めた単一のCPUで一回のみ
本関数を実行すること。

引数lib_areaは、ライブラリ用のデータ領域のアドレスを指定する。
アドレスが、4の倍数でなければ、ERR_ADR_ALIGNを返す。
指定する領域は、永続寿命を持つ領域であること。また性能上、SRAMなどの
高速なメモリが望ましい。

引数area_sizeは、lib_areaのサイズをbyte単位で指定する。
サイズが、sizeof(MemMgrLite::Manager)未満の場合は、ERR_DATA_SIZEを返す。
現在の実装で必要なサイズは、(4 + 4 * NUM_MEM_POOLS) なので、最小で12bytes
最大で1028bytesとなる。
//オプションの動的生成プールを使用する場合は追加で、(8 + 5 * NUM_DYN_POOLS)を4の倍数に切り上げたサイズが必要となる。

//本ライブラリをマルチコア(共有プール)サポートで使用する場合は、この領域は
全てのCPUからアクセスできる必要がある。
//ARMのTCMやMIPSのScratchPadなどは、CPUローカルなメモリなので、マルチコア
サポート時のlib_areaには指定できない。
使用例1

メモリレイアウト定義ファイルで、MemMgrLite用データ領域を定義して使用する例を示します。

//S_ASSERT(MEMMGR_DATA_AREA_SIZE >= sizeof(MemMgrLite::Manager));
void* lib_data_va = MemMgrLite::translatePoolAddrToVa(MEMMGR_DATA_AREA_ADDR);
if (MemMgrLite::Manager::initFirst(lib_data_va, MEMMGR_DATA_AREA_SIZE)) != ERR_OK)
  {
    /* エラー処理 */;
  }
使用例2

静的変数で定義したMemMgrLiteのデータ領域を使用する例を示します。
sizeofで領域を確保できるため、サイズ不足の心配がありません。 なお領域は、4byteアラインを保障するため、uint32_tの配列として定義しています。

static uint32_t s_lib_data[sizeof(MemMgrLite::Manager) / sizeof(uint32_t)];
if (MemMgrLite::Manager::initFirst(s_lib_data, sizeof(s_lib_data)) != ERR_OK)
  {
    /* エラー処理 */;
  }
CPU毎の初期化
関数
static err_t Manager::initPerCpu(void* lib_area)
引数
void*     lib_area  /* ライブラリが使用するデータ領域 */
戻り値
ERR_OK        : 初期化成功
ERR_STS       : 2回以上、本関数を実行している、あるいはinitFirst()の未実行
説明
ライブラリのCPU毎の初期化を行う。
引数lib_areaは、Manager::initFirst()に指定したものと同じアドレスを指定する。

Manager::initFirst()が未実行か、
既に本APIを実行済みのCPUで、再度本APIを実行した場合は、ERR_STSを返す。

//本ライブラリをマルチコア(共有プール)サポートで使用する場合は、全てのCPUはManager::initFirst()の実行完了を(プラットフォーム固有の方法で)待ってから、本関数を実行する必要がある。
使用例1

メモリレイアウト定義ファイルで定義したMemMgrLiteのデータ領域を使用する例を示します。

void* lib_data_va = MemMgrLite::translatePoolAddrToVa(MEMMGR_DATA_AREA_ADDR);
if (MemMgrLite::Manager::initPerCpu(lib_data_va)) != ERR_OK)
  {
    /* エラー処理 */;
  }
使用例2

静的変数で定義したMemMgrLiteのデータ領域を使用する例を示します。

if (MemMgrLite::Manager::initPerCpu(s_lib_data)) != ERR_OK)
  {
    /* エラー処理 */;
  }
静的メモリプールの生成
関数
static err_t Manager::createStaticPools(NumLayout layout_no,
                                        void* work_area,
                                        uint32_t area_size,
                                        const PoolAttr *pool_attr)
引数
NumLayout       layout_no : メモリレイアウト番号 (0 origin)
void*           work_area : 静的メモリプール操作用の作業領域
uint32_t        area_size : 作業領域のサイズ(byte単位)
const PoolAttr *pool_attr : メモリレイアウトのアドレス
戻り値
ERR_OK        : 初期化成功
ERR_STS       : initPerCpu()が未実行、あるいは本関数が実行済み
ERR_ADR_ALIGN : work_areaが、4の倍数ではない
ERR_DATA_SIZE : area_sizeが、最大作業領域サイズ未満
説明
指定されたレイアウト番号のメモリプール郡を生成する。
メモリレイアウトを変更する場合には、いったんManager::destroyStaticPools()で
メモリプール郡を破棄してから、再度本関数を実行すること。

Manager::initPerCpu()が未実行の場合、
既に本関数が実行済みの場合は、ERR_STSを返す。

引数layout_noは、使用するメモリレイアウトの番号を指定する。

引数work_areaは、静的メモリプール操作用の作業領域のアドレスを指定する。
アドレスが、4の倍数でなければ、ERR_ADR_ALIGNを返す。
指定する領域は、Manager::destroyStaticPools()が呼び出されるまで存在する
領域であること。また性能上、SRAMなどの高速なメモリが望ましい。

引数area_sizeは、静的メモリプール操作用の作業領域のサイズを指定する。
レイアウト番号毎に定義されたマクロMEMMGR_Lx_WORK_SIZE(xはレイアウト番号)
以上の値を指定する。
全レイアウト中の最大作業領域サイズは、マクロMEMMGR_MAX_WORK_SIZEで定義される。
作業領域のサイズが不足した場合は、ERR_DATA_SIZEを返す。

//本ライブラリをマルチコア(共有プール)サポートで使用する場合は、この領域は全てのCPUからアクセスできる必要がある。
//ARMのTCMやMIPSのScratchPadなどは、CPUローカルなメモリなので、マルチコアサポート時には指定できない。
使用例1

メモリレイアウト定義ファイルで、MemMgrLite用作業領域を定義して使用する例を示します。 マルチコアサポート時やSRAM配置時は、この方法が使いやすいです。

S_ASSERT(MEMMGR_WORK_AREA_SIZE >= MEMMGR_MAX_WORK_SIZE);
const NumLayout layout_no = 0;
void* work_va = MemMgrLite::translatePoolAddrToVa(MEMMGR_WORK_AREA_ADDR);
if (MemMgrLite::Manager::createStaticPools(layout_no, work_va, MEMMGR_WORK_AREA_SIZE) != ERR_OK)
  {
    /* エラー処理 */;
  }
使用例2

静的変数で定義したMemMgrLiteの作業領域を使用する例を示します。 領域は、4byteアラインを保障するため、uint32_tの配列として定義しています。

static uint32_t s_work_area[MEMMGR_MAX_WORK_SIZE / sizeof(uint32_t)];
const NumLayout layout_no = 0;
if(MemMgrLite::Manager::createStaticPools(layout_no, s_work_area, sizeof(s_work_area) != ERR_OK)
  {
    /* エラー処理 */;
  }
Spresense では、SRAMのみ選択できます。
静的メモリプールの破棄(消去)
関数
static void Manager::destroyStaticPools()
引数
なし
戻り値
なし
説明
Manager::createStaticPools()で生成した静的メモリプールを破棄する。
静的メモリプール未生成時は、何もしない。
Manager::initPerCpu()が未実行の場合は、"debug_assert"する。

メモリプールの破棄時には、セグメント解放漏れのチェックを行う。
解放漏れが検出された場合は、"assert"する。

フェンス機能が有効な場合は、静的メモリプールのフェンスチェックを行い
フェンス破壊が検出された場合は、"assert"する。
使用例
/* 静的メモリプールを破棄する */
MemMgrLite::Manager::destroyStaticPools();
現在のメモリレイアウト番号を取得
関数
static NumLayout Manager::getCurrentLayoutNo()
引数
なし
戻り値
現在設定されているメモリレイアウト番号
未設定の場合は、BadLayoutNo
説明
現在のメモリレイアウト番号を取得する。
メモリレイアウト番号の初期値は、BadLayoutNo。
Manager::createStaticPools()を呼ぶと引数で指定した値が設定される。
Manager::destroyStaticPools()を呼ぶと初期値にリセットされる。
使用例
/* 現在のメモリレイアウト番号を取得する */
MemMgrLite::NumLayout layout_no = MemMgrLite::Manager::getCurrentLayoutNo();
if (layout_no != MemMgrLite::BadLayoutNo)
  {
    printf("現在のメモリレイアウト番号: %d\n", layout_no);
  }
else
  {
    printf("メモリレイアウト番号は未設定\n");
  }
使用中のメモリセグメントの取得
関数
static uint32_t Manager::getStaticPoolsUsedSegs(MemHandle* mhs, uint32_t num_mhs)
//static uint32_t Manager::getUsedSegs(PoolId id, MemHandle* mhs, uint32_t num_mhs)
引数
PoolId       id      : プールID
MemHandle*   mhs     : 使用中のメモリセグメントを格納するメモリハンドル配列
uint32_t     num_mhs : 配列の要素数
戻り値
メモリハンドル配列に格納したセグメント数
説明
メモリプール内で使用中のセグメントをメモリハンドル配列に格納する。
格納されたセグメントの参照カウントは、1増加する。
使用中のセグメント数が、引数num_mhsで指定した値よりも多い時は、num_mhs個の
セグメントを格納した時点で、処理を打ち切る。

getStaticPoolsUsedSegs()は、現在のメモリレイアウトの静的プール全体を対象とする。
//getUsedSegs()は、指定されたIDの静的または動的メモリプールが対象となる。

引数mhsは、メモリセグメントを保持していない空のメモリハンドル配列を指定すること。
引数idが有効なプールIDでなければ、"debug_assert"する。
引数mhsまたはnum_mhsが0の場合は、"debug_assert"する。

これらのAPIは、メモリプールを破棄する前に、解放されていないセグメントの詳細な
情報を取得する用途を想定している。

なお、使用中のセグメント数を知るだけであれば、下記の方が効率が良い。
Manager::getPoolNumSegs(id) - Manager::getPoolNumAvailSegs(id)
使用例
const uint32_t MaxSegInfo = 8;
MemHandle  mhs[MaxSegInfo];

uint32_t num_used = Manager::getStaticPoolsUsedSegs(mhs, MaxSegInfo);
for (uint32_t i = 0; i < num_used; ++i)
  {
        printf("ID=%u SegNo=%u VA=%08x Size=%u RefCnt=%u\n",
                    mhs[i].getPoolId(), mhs[i].getSegNo(), mhs[i].getVa(),
                        mhs[i].getSize(), mhs[i].getRefCnt());
  }
メモリプールの各種情報を取得
関数
static bool     Manager::isPoolAvailable(PoolId id)
static PoolType Manager::getPoolType(PoolId id)
static PoolAddr Manager::getPoolAddr(PoolId id)
static PoolSize Manager::getPoolSize(PoolId id)
static NumSeg   Manager::getPoolNumSegs(PoolId id)
static NumSeg   Manager::getPoolNumAvailSegs(PoolId id)
static bool     Manager::isPoolFenceEnable(PoolId id)
//static LockId   Manager::getPoolLockId(PoolId id)
引数
PoolId   id  /* メモリプールID (1 origin) */
戻り値
説明を参照
説明
isPoolAvailable()は、現在のメモリレイアウトで、指定されたプールIDが有効か否かを返す。

getPoolType(), getPoolAddr(), getPoolSize(), getPoolNumSegs()は、プール
生成時に指定された、プール種別、アドレス、サイズ、セグメント数を返す。

getPoolNumAvailSegs()は、現在の空きセグメント数を返す。

isPoolFenceEnable()は、プール生成時に指定されたフェンス指定を返す。
本関数は、フェンス機能有効時(UseFence = true)のみ定義される。

//getPoolSpinLockId()は、プール生成時に指定されたスピンロックIDを返す。
//本関数は、マルチコアサポート有効時(UseMultiCore = true)のみ定義される。

無効なプールIDを指定するとNULLポインタアクセスを引き起こすので、プールIDの
有効性を確認して使用すること。
使用例
if (MemMgrLite::Manager::isPoolAvailable(my_pool_id))
  {
    printf("type=%d addr=%08x size=%08x num_seg=%u avail_seg=%u",
                        MemMgrLite::Manager::getPoolType(my_pool_id),
                        MemMgrLite::Manager::getPoolAddr(my_pool_id),
                        MemMgrLite::Manager::getPoolSize(my_pool_id),
                        MemMgrLite::Manager::getPoolNumSegs(my_pool_id),
                        MemMgrLite::Manager::getPoolNumAvailSegs(my_pool_id));
#ifdef USE_MEMMGR_FENCE
        printf(" fence=%u", MemMgrLite::Manager::isPoolFenceEnable(my_pool_id));
#endif
//#ifdef USE_MEMMGR_MULTI_CORE
//        printf(" spl_id=%u", MemMgrLite::Manager::getPoolSpinLockId(my_pool_id));
//#endif
  }
MemHandleクラスの関数
コンストラクタ/デストラクタ
関数
MemHandle::MemHandle()                       // default constructor
MemHandle::MemHandle(PoolId id, size_t size) // segment allocate constructor
MemHandle::MemHandle(const MemHandle& mh)    // copy constructor
MemHandle::~MemHandle()                      // destructor
引数
PoolId           id    : プールID
size_t           size  : 要求サイズ(byte単位)
const MemHandle& mh    : コピー元メモリハンドル
戻り値
なし
説明
MemHandleクラスのインスタンスを生成または破棄する。

引数idは、メモリセグメントを取得するプールIDを指定する。
取得結果は、isAvail() or isNull()で判定する。

引数sizeは、要求サイズを指定する。
現状この引数は、セグメントサイズとの比較にのみ使用され、セグメントサイズを
超える値が指定された場合は、"debug_assert"する。

引数mhは、コピー元のメモリハンドルを指定する。
コピー元のメモリハンドルが、メモリセグメントを保持している場合は
メモリセグメントの参照カウントが、1増加する。

メモリセグメントを保持しているインスタンスのデストラクタは、メモリセグメントの
参照カウントを、1減少させる。
使用例
MemMgrLite::MemHandle mh(MY_POOL_ID, sizeof(MyData));
if (mh.isNull())
  {
    /* エラー処理 */;
  }
代入演算子
関数
MemHandle::MemHandle& operator=(const MemHandle& mh)
引数
const MemHandle& mh  : コピー元メモリハンドル
戻り値
自身への参照
説明
自身とコピー元の値が異なる場合にインスタンスの代入を行う。
同じ場合は何もしない。

メモリセグメントを保持している場合は、代入前にメモリセグメントの
参照カウントを、1減少させる。

コピー元のメモリハンドルが、メモリセグメントを保持している場合は
代入後にメモリセグメントの参照カウントを、1増加させる。
使用例
MemMgrLite::MemHandle mh;        /* default constructor */
mh = src_mh;                            /* call operator=() */
メモリセグメント取得
関数
err_t MemHandle::allocSeg(PoolId id, size_t size, MemHandleProxy &proxy)
引数
PoolId           id     : プールID
size_t           size   : 要求サイズ(byte単位)
MemHandleProxy   &proxy : メモリセグメントの参照
戻り値
ERR_OK        : 取得成功
ERR_DATA_SIZE : sizeがセグメントサイズを超えている
ERR_MEM_EMPTY : 取得できるセグメントが無い
説明
指定されたメモリプールからメモリセグメントを取得する。
引数idは、メモリセグメントを取得するプールIDを指定する。

引数sizeは、要求サイズを指定する。
現状この引数は、セグメントサイズとの比較にのみ使用され、セグメントサイズを
超える値が指定された場合は、ERR_DATA_SIZEを返す。

取得できるセグメントが無い場合は、ERR_MEM_EMPTYを返す。
使用例
MemMgrLite::MemHandle mh;
if (mh.allocSeg(MY_POOL_ID, sizeof(MyData)) != ERR_OK)
  {
    /* エラー処理 */;
  }
明示的なメモリセグメント解放
関数
void MemHandle::freeSeg()
引数
なし
戻り値
なし
説明
デストラクタに頼らずに明示的にメモリセグメントを解放する。
メモリセグメントを保持していない場合は、何もしない。
メモリセグメントを保持している場合は、メモリセグメントの参照カウントを
1減少させてから、インスタンスを再初期化する。
メモリセグメントの各種情報を取得
関数
bool        MemHandle::isAvail()
bool        MemHandle::isNull()
bool        MemHandle::isSame(const MemHandle& mh)
PoolId      MemHandle::getPoolId()
NumSeg      MemHandle::getSegNo()
PoolAddr    MemHandle::getAddr()
PoolSize    MemHandle::getSize()
SegRefCnt   MemHandle::getRefCnt()
引数
const MemHandle& mh    : 比較先メモリハンドル
戻り値
説明参照
説明
isAvail()は、インスタンスがメモリセグメントを保持しているか否かを返す。

isNull()は、インスタンスがメモリセグメントを未保持か否かを返す。

isSame()は、インスタンスと引数mhが同じ値か否かを返す。

getPoolId()は、インスタンスがメモリセグメントを保持していれば
セグメントが所属しているプールのIDを返す。
セグメントを保持していなければ、NullPoolIdを返す。

getSegNo()は、インスタンスがメモリセグメントを保持していれば
セグメントが所属しているプール内でのセグメント番号(1 origin)を返す。
セグメントを保持していなければ、NullSegNoを返す。

getSegAddr()は、インスタンスがメモリセグメントを保持していれば
セグメントのアドレスを返す。
セグメントを保持していなければ、"debug_assert"する。

getSegSize()は、インスタンスがメモリセグメントを保持していれば
セグメントのサイズを返す。
セグメントを保持していなければ、"debug_assert"する。

getRefCnt()は、インスタンスがメモリセグメントを保持していれば
セグメントの参照カウントを返す。
セグメントを保持していなければ、"debug_assert"する。
Configurations and Generate

”Memory Manager” のLayoutファイルの記述方法と作成方法を説明します。

Layout情報は、MemoryLayout定義ファイル"mem_layout.conf" (名前は変えられます。) の中に、Rubyで記載され、 "mem_layout.rb" というツールで、C++言語の3つヘッダ、 "mem_layout.h" "fixed_fence.h" "pool_layout.h" を生成します。 ユーザは、このヘッダをインクルードすることで、”Memory Manager” を使えることになります。

How to write a Mamory Layout File

"mem_layout.conf"は、”Memory Manager”のコンフィグレーション、ユーザー定数の定義、デバイスの定義、固定領域の定義、PoolLayoutの定義を行います。それぞれの説明を以下に示します。

”Memory Manager”のコンフィグレーション

”Memory Manager” の各種機能の使用有無を指定できます。指定できる機能と指定方法は下記の通りです。 .

Feature Description

UseFence

フェンスの使用有無をtrue/falseで指定します。 有効にするとUSE_MEMMGR_FENCEマクロが定義され、指定された領域の前後に4byteの 上書き検出用フェンスを配置します。またフェンスチェック用APIが定義されます。

指定の記述例
UseFence = true  # Use of a pool fence
ユーザー定数の定義

MemoryLayout定義ファイル内で使用する定数に、"U_"で開始されるユーザー独自の名称をつける ことができます。また、定義には、Rubyの任意の式を記述することが出来ます。

ユーザー定義定数の記述例
  # スクリプト内定義と重ならないように、"U_"で開始して英大文字、数字と"_"のみとする
  # "U_MEM_"で始まる名称で定義すると、ヘッダファイルに同名のマクロが出力される

  U_STD_ALIGN   = 8     # standard alignment
  U_MSGQ_ALIGN  = 64    # message queue area alignment
Memoryのデバイス定義

各種Memoryデバイスを定義します。これらの定義は、固定領域の定義に使用されます。 ヘッダファイルには、name_ADDRマクロとname_SIZEマクロとして出力されます。

Memoryのデバイス定義の記述例
MemoryDevices.init(
  # name         ram    addr        size
  ["AUD_SRAM",   true,  0x000c0000, 0x00040000],
  nil # end of definition
)

各パラメータの説明は以下の通りです。

パラメータ 説明

name

デバイス名(3文字以上。英大文字で始まり、英大文字, 数字, "_"が使用可能)

ram

デバイスがRAMならば、true。それ以外ならばfalse。

addr

領域のアドレス。0を除く4の倍数の値を指定します。

size

領域のサイズ。0を除く4の倍数の値を指定します。

固定領域の定義

各メモリデバイスに領域を定義します。 各領域の開始アドレスは、デバイス毎の累積サイズ、align、fenceにより決定されます。
ヘッダファイルには、name_ALIGN, name_ADDR, name_SIZEマクロとして出力されます。

固定領域の定義の記述例
FixedAreas.init(
  # name,                  device,    align,        size,         fence
  ["AUDIO_WORK_AREA",     "AUD_SRAM", U_STD_ALIGN,  0x0003e000,   false], # Audio work area
  ["MSG_QUE_AREA",        "AUD_SRAM", U_STD_ALIGN,  0x00001000,   false], # message queue area
  ["MEMMGR_WORK_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000200,   false], # MemMgrLite WORK Area
  ["MEMMGR_DATA_AREA",    "AUD_SRAM", U_STD_ALIGN,  0x00000100,   false], # MemMgrLite DATA Area
  nil # end of definition
)

各パラメータの説明は以下の通りです。

パラメータ 説明

name

領域名(英大文字で始まり、"_AREA"で終わる名称。英大文字, 数字, _が使用可能)

device

領域を確保するMemoryDevicesのデバイス名

align

領域の開始アライメント。0を除くMinAlign(=4)の倍数を指定します。

size

領域のサイズ。0を除く4の倍数の値を指定します。

fence

フェンスの有効・無効を指定します。(この項目は、UseFenceがfalseの場合は無視されます)

PoolLayoutの定義

メモリプールのレイアウトを定義します。 各プール領域の開始アドレスは、固定領域毎の累積サイズ、align、fenceにより決定されます。
ヘッダファイルには、プールIDとNUM_MEM_POOLS, NUM_MEM_LAYOUTSおよび Lx_name_ALIGN, Lx_name_ADDR, Lx_name_SIZE, Lx_name_NUM_SEG, Lx_name_SEG_SIZE マクロとして出力されます。(xはレイアウト番号)
フェンスが有効な場合は、Lx_name_L_FENCE, Lx_name_U_FENCEマクロも出力されます。

PoolLayoutの定義の記述例
# Definition for player
U_MAIN_BUF_SIZE = 1024
U_MAIN_BUF_SEG_NUM = 4
U_MAIN_BUF_POOL_SIZE = U_MAIN_BUF_SIZE * U_MAIN_BUF_SEG_NUM

U_PCM_BUF_SIZE = 1024
U_PCM_BUF_SEG_NUM = 8
U_PCM_BUF_POOL_SIZE = U_PCM_BUF_SIZE * U_PCM_BUF_SEG_NUM

# Definition for recorder
U_REC_BUF_SIZE = 2048
U_REC_BUF_SEG_NUM = 6
U_REC_BUF_POOL_SIZE = U_REC_BUF_SIZE * U_REC_BUF_SEG_NUM

PoolAreas.init(
  [ # layout 0 for Player
    #[ name,            area,              align,        pool-size,            seg,                 fence]
     ["MAIN_BUF_POOL",  "AUDIO_WORK_AREA", U_STD_ALIGN,  U_MAIN_BUF_POOL_SIZE, U_MAIN_BUF_SEG_NUM,  true ],
     ["PCM_BUF_POOL",   "AUDIO_WORK_AREA", U_STD_ALIGN,  U_PCM_BUF_POOL_SIZE,  U_PCM_BUF_SEG_NUM,   true ],
    nil # end of each layout
  ], # end of layout 0

  [ # layout 1 for Recorder
    #[ name,           area,              align,        pool-size,            seg,                fence]
     ["REC_BUF_POOL",  "AUDIO_WORK_AREA", U_STD_ALIGN,  U_REC_BUF_POOL_SIZE,  U_REC_BUF_SEG_NUM,  true ],
     nil # end of each layout
  ], # end of layout 1

  nil # end of definition
)

各パラメータの説明は以下の通りです。

パラメータ 説明

name

プール名(英大文字で始まり、"_POOL"で終わる名称。英大文字, 数字, _が使用可能)

area

プール領域として使用するFixedAreaの領域名。領域はRAMに配置して下さい。

align

プールの開始アライメント。0を除くMinAlign(=4)の倍数を指定します。

pool-size

プールのサイズ。0を除く4の倍数の値。セグメントサイズ * セグメント数。各areaの最終領域には、残りサイズを示すRemainderSizeを指定することができます。

seg

セグメント数。1以上、255以下の値を指定します。

fence

フェンスの有効・無効を指定します。この項目は、UseFenceがfalseの場合は無視されます。

How To Generate

"mem_layout.rb" を使ったLayoutファイルの作成方法は以下の通りです。

ruby -Itool_path mem_layout.conf layout_header fence_header pool_header

Ex) ruby -I../../../sdk/modules/memutils/memory_manager/tool mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

"mem_layout.rb"の各引数の説明は下記の通りです。

表 25. Layoutファイルの作成ツールの引数
Parameter Description

-Itool_path

mem_layout.rbのパス

mem_layout.conf

Memory Layout定義ファイル

layout_header

各種定数値がマクロとして出力されるヘッダファイル

fence_header

FixedAreaのメモリフェンスアドレスが出力されるヘッダファイル。”Memory Manager”が使用するファイルのため、ユーザーは使用しないで下さい。

pool_header

PoolAreaの各種定義が出力されるヘッダファイル。”Memory Manager”が使用するファイルなので、ユーザーは使用しないで下さい。

11.9.3. Message Library

主に、"Memory Manager" のような Task間でClass Instanceの送受信を行う必要がある場合、通常、OSが提供しているシステムコールでは対応できなため、"Message Library" を用いて、これを実現しています。 ここでは、この "Message Library" の説明を行います。

General

"Message Library" は、タスク間でClass Instanceの送受信を行えるタスク間同期ライブラリです。

このライブラリは、送り先をIDとして明示的に指定して送信します。 また、受信側は、送信イベントを待ち受けて、イベントドリブン動作を実現します。

Message Sequence

また、このメッセージにはTypeを持っており、受け取ったインスタンスが、あったかなかったか、あった場合何であったかは、Typeによって判断し取り出します。

ただし、送受信したいクラスは、正しくコピーコンストラクタを実装している必要があります。
Message ID と Type
Message ID

Message ID は、以下 How to write a Message Layout File の Configurationに従って、静的に作成します。 Configuration の詳細はそちらを参照してください。

IDを確定したら、タスクのループの中で、

  MsgQueId id = XX; // Assign the created ID to a variable "id".

  MsgQueBlock *que;
  MsgPacket   *msg;


  err_t err = MsgLib::referMsgQueBlock(id, &que);
  err = que->recv(TIME_FOREVER, &msg);

とすることで、Massageイベント待ちになり、Message ID = XXのイベントドリブン処理が実現できます。

逆に、イベントを送信する場合は、

  MsgQueId send_id = XX; // Assign ID that be sent to a variable "send_id".
  MsgQueId ret_id = XX; // Assign ID that will return to a variable "self_id".

  Object instance; // Class and Instance you want to send.

  instance(); // Construction.

  err_t err = MsgLib::send<Object>(send_id, MsgPriNormal, MSG_TYPE, ret_id, instance);

このように、送信したいIDを send_id、返信してほしいIDを ret_idに代入し、送信したいクラス(Object)のインスタンスを作成し、MsgLib::send で送信します。

ID は、アプリケーションに応じて作成し、明示的に送受信のデータパスを指定しながら使用します。

Message Type

Message ライブラリは、受け取った Message Packet から適切なInstance を取り出すために、 Message Type を用いてどういったオブジェクトが送られたかを判断します。 このため、 Message Packet には、すべて Message Type を付加します。

この Message Type は、"sdk/modules/include/memutils/message/message_type.h"で定義されています。

Message Type は、以下のようなデータ構造を取ります。

diag 788d4c0f09923d010e16c0d729677b6e

各フィールドの説明は以下の通りです。

フィールド名 フィールド 説明

REQ

[15]

メッセージが要求か応答かを示します。0は応答、1は要求です。

MSG_USER

[14-12]

メッセージの使用者情報です。0~7の値でメッセージを使用するシステムを指定することが出来ます。ただし、6は、AudioSubSystem, 7はSensorSubSystemが予約しているため、実際には0~5の値を使用することが出来ます。

MSG_CATEGORY

[11-8]

メッセージのカテゴリ情報です。0~15の値でカテゴリを指定することが出来ます。

MSG_SUB_TYPE

[7-0]

メッセージのサブタイプ情報です。0~255の値でカテゴリ内のメッセージタイプを指定することが出来ます。

定義されているIDは、以下になります。

MSG_TYPE_REQUEST

メッセージの方向を示します。

D15 Description

0

response

1

request

MSG_USER

メッセージを使用するシステムを指定します。 現在、AudioとSensorのIDは予約されています。

D14-D12 Description

0-5

reserved

6

Audio Sub System

7

Sensor Sub System

MSG_CATEGORY

各システム内で自由に定義してください。

例えば、Audioの場合は、
"sdk/modules/include/audio/audio_message_types.h"

Sensorの場合は、
"sdk/modules/include/sensing/sensor_message_types.h"

で定義されています。

MSG_SUB_TYPE

各システム内で自由に定義してください。

例えば、Audioの場合は、
sdk/modules/audio/include/commmon/audio_interanl_message_types.h

Sensorの場合は、
sdk/modules/include/sensing/sensor_message_types.h

で定義されています。

メッセージタイプは、IDが違う場合、同じ値を定義したとしても運用可能ですが、デバッグしやすさと、データパスが変わって、別なIDに送信するような変更などに対しての変更容易性などを鑑みて、すべてをユニークに作るようにしてください。

以下のような実装で、Message Packet からInstanceを取り出します。

  MsgQueBlock *que;
  MsgPacket   *msg;

  err_t err = MsgLib::referMsgQueBlock(id, &que);
  err = que->recv(TIME_FOREVER, &msg);

  if (msg->getType() == MSG_TYPE) { // Check that the message type is as expected or not.

    Object instance = msg->moveParam<Object>(); // get an instance of type Object from Message packet.

  }
APIs

"Message Library"のインタフェースは次の通りです。 詳細は、 memutils_message を参照してください。

MsgLibクラスの関数
メッセージライブラリの初期化
関数
static err_t MsgLib::initFirst()
引数
なし
戻り値
ERR_OK        : 初期化成功
ERR_STS       : 本関数が実行済み
説明
メッセージライブラリ全体の初期化を行う。
本ライブラリの他のAPIを使用する前に、事前に取り決めた単一のCPUで一回だけ本関数を実行すること。
CPU毎の初期化
関数
static err_t MsgLib::initPerCpu()
引数
なし
戻り値
ERR_OK        : 初期化成功
ERR_STS       : MsgLib::initFirst()が未実行
説明
メッセージライブラリのCPU毎の初期化を行う。
CPU毎の各種領域や計数セマフォ(OS環境のみ)の初期化など。

本ライブラリを使用する全てのCPUは、MsgLib::initFirst()の実行完了を
待ってから、本関数を実行する必要がある。

MsgLib::initFirst()が未実行の場合は、ASSERTする。
既に本APIを実行済みのCPUで、再度本APIを実行した場合は、ASSERTする。
メッセージライブラリの終了
関数
static err_t MsgLib::finalize()
引数
なし
戻り値
ERR_OK        : 初期化成功
ERR_STS       : MsgLib::initFirst()が未実行
説明
メッセージライブラリの終了処理を行う。
内部管理情報をクリアする。
メッセージキューの初期化状態の取得
関数
static bool MsgLib::isInitComplete(MsgQueId id)
引数
MsgQueId    id  : メッセージキューID
戻り値
true  :  初期化済み(キューを所有しているCPUで、初期化が完了している)
false : 未初期化
説明
メッセージキューの初期化状態を取得する。
引数idの示すメッセージキューブロックが存在しない場合は、ASSERTする。
MsgLib::initFirst()が未実行の場合は、ASSERTする。
メッセージパケットの送信
関数
static err_t MsgLib::send(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply)

template<typename T>
  static err_t MsgLib::send(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply, const T& param)

static err_t send(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply, const void* param, size_t param_size)

static err_t MsgLib::sendIsr(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply)

template<typename T>
  static err_t MsgLib::sendIsr(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply, const T& param)

static err_t sendIsr(MsgQueId dest, MsgPri pri, MsgType type, MsgQueId reply, const void* param, size_t param_size)
引数
MsgQueId    dest        : 送信先メッセージキューID
MsgPri      pri         : メッセージの優先度
MsgType     type        : メッセージ種別を識別するための値
MsgQueId    reply       : 返信先メッセージキューID
const T&    param       : メッセージのパラメタ
const void* param       : メッセージパラメタへのアドレス
size_t      param_size  : パラメータサイズ
戻り値
ERR_OK       : 送信成功
ERR_QUE_FULL : メッセージキューに空きがない
説明
引数destとpriで示されるキューに、メッセージパケットを格納する。
send()はタスクコンテキスト、sendIsr()は非タスクコンテキストで使用する。
sendIsr()でパラメタを使用する場合、割込み処理の最短化のため、できるだけ
クラスインスタンスは使用せず、パラメタサイズも最小化する事。

引数paramのサイズが大きすぎてキューに格納できない場合は、ASSERTする。
引数destとpriで示されるキューが存在しないか、あるいは初期化が完了して
いない場合は、ASSERTする。
他CPU所有で、自CPUとのスピンロック共有がないキューを指定した場合は、ASSERTする。

sendIsr()で、共有キューを指定した場合は、ASSERTする。
これは、非タスクコンテキストでのスピンロック待ちを防止するためである。
メッセージ受信を通知
関数
static void MsgLib::notifyRecv(MsgQueId dest)
引数
MsgQueId    dest  : 通知先メッセージキューID
戻り値
なし
説明
他CPUからのメッセージの受信を通知する。
本関数は、CPU間通信割込みハンドラから呼び出されることを想定している。
引数destの示すメッセージキューブロックが存在しないか、あるいは初期化が完了していない場合は、ASSERTする。
MsgQueBlockクラスの関数
メッセージキューブロックへの参照を取得
関数
static MsgQueBlock& MsgLib::referMsgQueBlock(MsgQueId id)
引数
MsgQueId    id  : メッセージキューID
戻り値
メッセージキューブロック参照
説明
メッセージキューブロックへの参照を取得する。
引数idの示すメッセージキューブロックが存在しないか、あるいは初期化が完了していない場合は、ASSERTする。
メッセージパケットの受信
関数
MsgPacket* MsgQueBlock::recv(uint32_t ms)
引数
uint32_t  ms : 受信待ち時間(ミリ秒)または、TIME_POLLING or TIME_FOREVER
戻り値
NULL以外: メッセージキュー内のメッセージパケットへのポインタ
NULL    : 受信タイムアウト
説明
指定された時間、メッセージパケットの受信待ちを行う。
MsgLib::send()とは異なり、複数タスクによる同一キューへの同時recv()はサポートしない。
os_wrap.hで、TIME_POLLINGは0、TIME_FOREVERは-1に定義されている。

前回受信したメッセージパケットが、MsgQueBlock::pop()により破棄されていない場合は、ASSERTする。
メッセージキューが他CPU所有の場合は、ASSERTする。
メッセージパケットの破棄
関数
void MsgQueBlock::pop()
引数
なし
戻り値
なし
説明
メッセージキューからメッセージパケットを取り除く。
メッセージパケットにパラメタが存在する場合は、MsgPacket::moveParam()か
MsgPacket::popParam()により、事前にパラメタを破棄すること。
複数タスクによる同一キューの同時pop()はサポートしない。

破棄対象メッセージパケットが存在しない場合は、ASSERTする。
破棄対象メッセージパケットのパラメタ長が、0以外の場合は、ASSERTする。
メッセージキューが他CPU所有の場合は、ASSERTする。
メッセージパケット数の取得
関数
uint16_t MsgQueBlock::getNumMsg(MsgPri pri) const
引数
MsgPri    pri  : メッセージキュー優先度
戻り値
メッセージパケット数
説明
メッセージキュー内のメッセージパケット数を取得する。
引数priの値が不正な場合は、ASSERTする
格納可能なメッセージパケット数の取得
関数
uint16_t MsgQueBlock::getRest(MsgPri pri) const
引数
MsgPri    pri  : メッセージキュー優先度
戻り値
格納可能なメッセージパケット数
説明
メッセージキューに格納可能なメッセージパケット数を取得する。
未使用のキューは、常に0を返す。
引数priの値が不正な場合は、ASSERTする。
MsgPacketクラスの関数
メッセージタイプIDの取得
関数
MsgType MsgPacket::getType() const
引数
なし
戻り値
メッセージタイプID
説明
メッセージパケットのタイプIDを取得する。
メッセージリプライキューIDの取得
関数
MsgQueId MsgPacket::getReply() const
引数
なし
戻り値
リプライキューID
説明
メッセージパケットのリプライキューIDを取得する。
メッセージパラメタ長の取得
関数
uint16_t MsgPacket::getParamSize() const
引数
なし
戻り値
メッセージパラメタ長。パラメタなし時は0が返される。
説明
メッセージパケットのパラメタ長を取得する。
メッセージパラメタの破壊取り出し(移動)
関数
template<typename T>  T MsgPacket::moveParam()
引数
なし
戻り値
メッセージパラメタ
説明
メッセージパケットのパラメタを取り出す(移動)。
sizeof(T) != MsgPacket::getParamSize() の場合、ASSERTする。

本APIは、以下の処理と等価となる。

 T param = MsgPacket::peekParam<T>();  /* 左辺を非参照にして、パラメタのコピーを作成 */
 MsgPacket::popParam<T>();	           /* パラメタを破棄 */
 return param;                         /* パラメタのコピーを返す */


本APIの呼出しにより、メッセージパラメタ長が0に変更される。
メッセージパラメタへの参照やポインタは無効となるので、注意すること。
メッセージパラメタ参照の取得
関数
template<typename T> const T& MsgPacket::peekParam() const

template<typename T> const T& MsgPacket::peekParamOther() const
引数
なし
戻り値
メッセージパラメタのconst参照
説明
メッセージパケットのパラメタへの参照を取得する。
peekParam()は、送信時と同じ型、peekParamOther()は、送信時と異なる型
(例えばパラメタのヘッダの型)での参照に使用する。

peekParam()は
sizeof(T) != MsgPacket::getParamSize()
の場合、ASSERTする。

peekParamOther()は、
sizeof(T) > MsgPacket::getParamSize()
の場合、ASSERTする。

これらのAPIの戻り値を非参照で受け取るとパラメタのコピーが取得できる。
メッセージパラメタの破棄
関数
template<typename T> void MsgPacket::popParam()

void MsgPacket::popParamNoDestruct()
引数
なし
戻り値
なし
説明
メッセージパケットのパラメタを破棄する。
popParam()は、パラメタのデストラクタを呼出す。
popParamNoDestruct()はデストラクタを呼出さないので、パラメタにデストラクタが
存在しないメッセージパケットにのみ使用することができる。
特別な理由がない限り、popParam()を使用すること。

popParam()は、
sizeof(T) != MsgPacket::getParamSize()
の場合、ASSERTする。

これらのAPIの呼出しにより、メッセージパラメタ長が0に変更される。
メッセージパラメタへの参照やポインタは無効となるので、注意すること。
Configurations and Generate

”Message Library” のLayoutファイルの記述方法と作成方法を説明します。

Layout情報は、"msgq_layout.conf" (名前は変えられます。) の中に、Rubyで記載され、 "msgq_layout.rb" というツールで、C++言語の2つヘッダ、 "msgq_id.h" "msgq_pool.h" を生成します。 ユーザは、このヘッダをインクルードすることで、”Message Library” を使えることになります。

How to write a Message Layout File

"msgq_layout.conf"は、”Message Library”のユーザー定数の定義、メッセージキュープールの定義、デバッグ値の指定、メッセージパラメータのチェック指定を行います。それぞれの説明を以下に示します。

ユーザー定数の定義

Message Layout定義ファイル内で使用する定数に、"U_"で開始されるユーザー独自の名称をつける ことができます。また、定義には、Rubyの任意の式を記述することが出来ます。

ユーザー定義定数の記述例
  # ユーザー定義定数は、"U_"で始まる英大文字・数字の名称とすること
  # "U_MSGQ_"で始まる名称で定義すると、msgq_id.hにdefineマクロとしても出力される

  U_HEADER_SIZE	= 8	# Message packet header size
メッセージキュープールの定義

ユーザー定義定数を使って、メッセージキュープールを定義することが出来ます。

メッセージキュープールの定義の記述例
U_MSG_SIZE = 16
U_MSG_NUM  = 8

MsgQuePool = [
 # ID,                        n_size       n_num         h_size           h_nums
  ["MSGQ_USER_APP",           U_MSG_SIZE,  U_MSG_NUM,    0,               0],
  ["MSGQ_DSP_CMD",            256,         10,           U_MSG_SIZE,      U_MSG_NUM],
  nil # end of user definition
] # end of MsgQuePool

各パラメータの説明は以下の通りです。

パラメータ 説明

ID

メッセージキュープールIDの名称を、"MSGQ_"で始まる文字列で指定します。"MSGQ_NULL", "MSGQ_TOP", "MSGQ_END"は予約済みのため使用禁止です。

n_size

通常優先度キューの各要素のバイト数(8以上512以下)。固定ヘッダ長(8byte) + パラメタ長を4の倍数で指定します。

n_num

通常優先度キューの要素数(1以上16384以下)。

h_size

高優先度キューの各要素のバイト数(0または、8以上512以下)。未使用時は0を指定して下さい。

h_num

高優先度キューの要素数(0または、1以上16384以下)。未使用時は0を指定して下さい。

デバッグ値の指定やメッセージパラメータのチェック指定もありますが、使用しない設定としてください。
MsgFillValueAfterPop = 0x00
MsgParamTypeMatchCheck = false
How To Generate

"msgq_layout.rb" を使ったLayoutファイルの作成方法は以下の通りです。

ruby -Itool_path msgq_layout.conf start_addr size id_header pool_header

Ex) ruby -I../../../sdk/modules/memutils/message/tool msgq_layout.conf 0x000fe000 0x1000 msgq_id.h msgq_pool.h

"msgq_layout.rb"の各引数の説明は下記の通りです。

表 26. Layoutファイルの作成ツールの引数
Parameter Description

-Itool_path

msgq_layout.rbのパス

msgq_layout.conf

メッセージキューレイアウト定義ファイル

start_addr

メッセージ領域のアドレス

size

バイト単位の領域サイズ

id_header

メッセージキューIDマクロが出力されるファイル

pool_header

メッセージキュープールの定義が出力されるファイル

Sequence
diag d735426e9a2309e0e10b6bd248632462

11.9.4. Simple FIFO

General

Simple FIFO This library supports one-writer and one-reader access without any exclusive control. Some exclusive access control is required to support multi-writer/reader outside of this library.

This library supports access from multi-processor inserting proper data-sync-barriers and data-memory-barriers. It makes sure the order of update data contents and WP/RP for the purpose.

APIs

詳細は、Doxygenを参照してください。 APIの一覧は下記の通りです。

表 27. SimpleFIFO API一覧
API name Description

CMN_SimpleFifoInitialize

SimpleFIFOの初期化。FIFOに使用するメモリ領域を設定します。

CMN_SimpleFifoOffer

FIFOにデータをpushします。コピー処理はmemcpy()を使用します。

CMN_SimpleFifoOfferWithSpecificCopier

FIFOにデータをpushします。コピー処理はユーザー側で用意します。DMA用いたコピーなどを想定しています。

CMN_SimpleFifoOfferContinuous

FIFOにデータをpushします。指定したサイズ分連続領域にコピーします。指定したサイズ分の連続領域が無い場合は、pushを行いません。コピー処理はmemcpy()を使用します。

CMN_SimpleFifoOfferContinuousWithSpecificCopier

FIFOにデータをpushします。指定したサイズ分連続領域にコピーします。指定したサイズ分の連続領域が無い場合は、pushを行いません。コピー処理はユーザー側で用意します。DMA用いたコピーなどを想定しています。

CMN_SimpleFifoPoll

FIFOからデータをpopします。popしたデータはFIFOから削除されます。コピー処理はmemcpy()を使用します。

CMN_SimpleFifoPollWithSpecificCopier

FIFOからデータをpopします。popしたデータはFIFOから削除されます。コピー処理はユーザー側で用意します。DMA用いたコピーなどを想定しています。

CMN_SimpleFifoPeekWithOffset

FIFOの先頭から指定したOffsetから、指定したサイズのデータのアドレス情報を取得します。FIFOのデータを削除せずに参照したい場合に使用します。

CMN_SimpleFifoPeek

FIFOの先頭から指定したサイズのデータのアドレス情報を取得します。FIFOのデータを削除せずに参照したい場合に使用します。

CMN_SimpleFifoClear

FIFOのRead/Writeポインタをクリアし、空の状態にします。

CMN_SimpleFifoGetVacantSize

FIFOの空きサイズを取得します。

CMN_SimpleFifoGetOccupiedSize

FIFOの使用サイズを取得します。

CMN_SimpleFifoGetExtInfo

CMN_SimpleFifoInitialize()で設定したFIFOの拡張情報を取得します。

CMN_SimpleFifoGetDataSizeOfPeekHandle

CMN_SimpleFifoPeek()で取得したアドレス情報の要素数を取得します。

CMN_SimpleFifoCopyFromPeekHandle

CMN_SimpleFifoPeek()で取得したアドレス情報からデータを取得します。コピー処理はmemcpy()を使用します。

CMN_SimpleFifoCopyFromPeekHandleWithSpecificCopier

CMN_SimpleFifoPeek()で取得したアドレス情報からデータを取得します。コピー処理はユーザー側で用意します。DMA用いたコピーなどを想定しています。

Sequence

SimpleFIFOの簡易シーケンスです。

diag 8b0c5f70d1404ada4911f24179315fc5

11.9.5. Code Examples

These libraries are used with audio features. So, their samples are audio samples.

  • examples/audio_player

  • examples/audio_recorder

11.10. Power Management

11.10.1. Overview

Power Management は、Spresense SDK の特徴的な機能である省電力を実現するために電源管理を行うモジュールです。CXD5602 内部の電源ドメインやクロックの管理、及び、各種スリープモードのサポートを行います。

11.10.2. 電源状態

Spresense SDK は、省電力を実現するために、Deep SleepCold SleepHot Sleep の3つの Sleep モードをサポートしています。

Deep Sleep

CXD5602 は全ての電源ドメインが OFF されていて、CXD5247 PMIC(Power Management IC) のみ通電している状態です。このとき CXD5247 も Sleep 状態に入っており、最も消費電力を低く抑えることができます。

Cold Sleep

CXD5602 内で必要最小限の電源ドメインのみ ON されている状態です。アラームタイマーや、USB 挿抜、GPIO 信号の変化など、Deep Sleep に比べて、多くの起床要因をトリガとして、この Sleep 状態から起床することができます。

Hot Sleep

OS がアイドル状態のときに、この Sleep 状態へと遷移します。Sleep 中も SRAM の状態が保持されているため、起床の際に、SPI-Flash からプログラムを再ロードする必要がなく、高速に Sleep 状態から復帰することができます。

現在のSDKバージョンでは、Hot Sleep はサポートしておりません。
電源状態遷移

主な電源状態の状態遷移図を以下に示します。

Power State Diagram
図 66. Power State Diagram
State Description

PowerOff

CXD5247 PMIC(Power Management IC) も含めて、全ての電源が OFF されている状態です

Battery Check

電源供給の電圧レベルを監視している状態です。電源供給が 3.4 V 以上のときに CXD5602 がブートし、Run 状態に遷移します。

Run

通常の実行状態です。

Idle

OS アイドル状態です。OS アイドルタスクでは WFI (Wait for Interrupt) で割込み待ちをしています。

Hot Sleep

OS アイドル状態が一定の時間以上続くことが予想される場合に、この状態に遷移します。Hot Sleep 状態中は、SRAM のデータは保持されています。

Cold Sleep

CXD5602 の必要最小限な電源のみ ON され、SRAM 含めてそれ以外の電源は OFF 状態です。

Deep Sleep

CXD5602 が電源 OFF されており、CXD5247 PMIC(Power Management IC) だけが ON している状態です。

電源ドメイン階層構造

CXD5602 チップ内部は、階層構造をもったいくつかの電源ドメインに分かれて構成されています。 各種 Sleep モードと電源ドメインとの関係を以下に示します。

Power Domain Hierarchical Structure

11.10.3. 電源状態制御 API

Spresense SDK は、各種電源状態からの起動要因 (以下、boot cause) 、及び、起動要因の許可・禁止を制御するための起動マスク (以下、boot mask) をもっています。

boot cause

各種スリープモードから起床・起動された要因を表します

boot mask

起動要因の許可・禁止を制御します

boot cause、及び、boot mask は共通のビットフラグ構造をしており、それぞれの起動要因が1つのビットで表されます。boot mask の該当ビットに1がセットされると起動要因として許可、0をセットすると禁止になります。Sleep 状態にいるときに、boot mask で許可された起動要因のイベントが発生したときに Sleep 状態から起床します。そのとき、どの起動要因が boot cause に反映されます。

起動要因、起動マスクの定義を以下に示します。

  • Boot Type は、POR (Power-On-Reset) により起動したのか、Reboot による再起動なのか、Deep Sleep, Cold Sleep 状態からの起動なのかを表します。

  • Maskable は、Yes のものだけ起動要因として禁止することが許可されています。No のものは起動要因として禁止することはできません。

boot cause / boot mask Boot Type Maskable Description

PM_BOOT_POR_NORMAL

POR Boot

No

バッテリーもしくは電源が ON された

PM_BOOT_POR_DEADBATT

POR Boot

No

バッテリーもしくは電源が 3.4V 以上になり起動した

PM_BOOT_WDT_REBOOT

Reboot

No

システムウォッチドッグによりリブートした

PM_BOOT_WDT_RESET

Reboot

No

CXD5602 単体のウォッチドッグによりリセットされた

PM_BOOT_DEEP_WKUPL

Deep Boot

Yes

WKUPL 信号を検知した(*2)

PM_BOOT_DEEP_WKUPS

Deep Boot

Yes (*1)

WKUPS 信号を検知した(*2)

PM_BOOT_DEEP_RTC

Deep Boot

Yes (*1)

RTC Alarm が発火した

PM_BOOT_DEEP_USB_ATTACH

Deep Boot

No

USB が接続された(*2)

PM_BOOT_DEEP_OTHERS

Deep Boot

No

未使用

PM_BOOT_COLD_SCU_INT

Cold Boot

Yes

SCU 割り込みを検知した

PM_BOOT_COLD_RTC

Cold Boot

Yes

RTC Alarm が発火した

PM_BOOT_COLD_RTC_ALM0

Cold Boot

Yes

RTC Alarm0 が発火した(SDK は Alarm0 を使用します)

PM_BOOT_COLD_RTC_ALM1

Cold Boot

Yes

RTC Alarm1 が発火した(未使用)

PM_BOOT_COLD_RTC_ALM2

Cold Boot

Yes

RTC Alarm2 が発火した(未使用)

PM_BOOT_COLD_RTC_ALMERR

Cold Boot

Yes

RTC Alarm Error が発生した(未使用)

PM_BOOT_COLD_GPIO

Cold Boot

Yes

GPIO 割り込みを検出した

PM_BOOT_COLD_SEN_INT

Cold Boot

Yes

Sensor 割り込み (SEN_INT) を検出した

PM_BOOT_COLD_PMIC_INT

Cold Boot

Yes

PMIC (CXD5247) 割り込みを検出した

PM_BOOT_COLD_USB_DETACH

Cold Boot

Yes

USB ケーブルが外された(*2)

PM_BOOT_COLD_USB_ATTACH

Cold Boot

Yes

USB ケーブルが接続された(*2)

(*1) PM_BOOT_DEEP_WKUPS と PM_BOOT_DEEP_RTC の両方の起動マスクを禁止にすることはできません。
(*2) Spresenseボードではサポートされていません。

電源状態制御に関連して、次の Power Management API が提供されます。

  • 起動要因の取得

  • 起動マスクの取得

  • 起動マスクの許可・禁止

  • Sleep モードへの遷移

  • リブート

起動要因の取得 API
Function Prototype
uint32_t up_pm_get_bootcause(void);
Description
  • 起動要因を取得します

起動マスクの取得 API
Function Prototype
uint32_t up_pm_get_bootmask(void);
Description
  • 起動要因として何が許可・禁止されているかを表す起動マスクを取得します

    • デフォルトでは、全ての起動要因が許可されています

    • Deep Sleep、もしくは、Power-On-Reset により、この起動マスク値はリセットされます。 Hot Sleep もしくは Cold Sleep 中はこの起動マスク値は保持されています。

起動要因の許可 API
Function Prototype
uint32_t up_pm_set_bootmask(uint32_t mask);
Description
  • 引数で指定した起動要因を有効にします

  • 戻り値は、更新後の起動マスクを返します

起動要因の禁止 API
Function Prototype
uint32_t up_pm_clr_bootmask(uint32_t mask);
Description
  • 引数で指定した起動要因を無効にします

  • 戻り値は、更新後の起動マスクを返します

Example
#include <arch/chip/pm.h>

  uint32_t bootmask;

  bootmask = up_pm_get_bootmask(); // Get the current bootmask
  printf("bootmask=0x%08x/n", bootmask);

  bootmask = up_pm_clr_bootmask(PM_BOOT_COLD_USB_DETACH); // Disable wakeup by USB detached
  printf("bootmask=0x%08x/n", bootmask); // Display the updated bootmask
Sleep 遷移 API
Function Prototype
int up_pm_sleep(enum pm_sleepmode_e mode);
Description
  • Sleep モードに遷移します

  • この関数の呼び出しから戻ってくることはなく、そのまま Sleep 状態に遷移します。

Arguments
引数 mode Description

PM_SLEEP_DEEP

Deep Sleep に移行します

PM_SLEEP_COLD

Cold Sleep に移行します

up_pm_sleep() の発行により、CXD5602 チップ単体として Sleep モードへ遷移します。 Sleep 状態へ遷移するにあたり、チップだけでなく基板に依存した処理を追加で行う場合があります。 BSP の基板依存部に、board_power_off() 関数を実装することで、基板の制御を含めた Sleep モードへの遷移を行います。

BSP 依存部に実装される Sleep 遷移 API を以下に示します。 これは、NuttShell 上の poweroff コマンドからも制御できます。

Function Prototype
int board_power_off(int status)
Arguments
引数 status Description NuttShell command

BOARD_POWEROFF_DEEP

Deep Sleep に移行します

poweroff

BOARD_POWEROFF_COLD

Cold Sleep に移行します

poweroff --cold

リブート
Function Prototype
int up_pm_reboot(void);
Description
  • システムを再起動します

  • この関数の呼び出しから戻ってくることはなく、そのまま再起動します

BSP 基板依存部に、board_reset() 関数を実装することで、基板の制御を含めた再起動を実現することができます。

Function Prototype
int board_reset(int status);

board_reset() は、NuttShell 上の reboot コマンドからも制御できます。

11.10.4. スリープモード

Deep Sleep
特徴

Deep Sleep は次のような特徴をもちます。

  • CXD5602 は、電源 OFF 状態です

  • CXD5247 は、Sleep モードに入り、CXD5602 へ供給されるコア電源、IO電源は OFF されます

    • CXD5247 RTC 時刻は保持されます(システムが RTC XTAL を持っていることが前提です)

    • CXD5247 GPO スイッチは Deep Sleep 中も値が保持されています

      • Deep Sleep 中に GPO を ON にしておく必要がないなら、省電力の観点から Deep Sleep に入る前に OFF することを推奨します

    • CXD5247 Load Switch は OFF されます

    • CXD5602 の IO が OFF になりますので、周辺デバイスから CXD5602 へ電流がリークしないように注意して下さい

消費電力
  • バッテリーの消費電流は、バッテリー端でおよそ 数uA ~ 数+uA程度になります。ただし、この値は基板の設計に依存します。CXD5602 が電源 OFF されるため、周辺デバイスから CXD5602 へのリーク電流が発生しないように注意して基板を設計してください。

Sleep 中の消費電力に関して、拡張ボードに SD カードが挿入されていると SD カードの電源消費分により 約 5 mA ほど消費電流が増加します。
スリープ条件
  • up_pm_sleep(PM_SLEEP_DEEP) や board_poweroff(BOARD_POWEROFF_DEEP) を呼び出すことによって、Deep Sleep 状態に遷移します

  • WKUPL 信号を使用している場合は、WKUPL が 3 秒以上アサートされた場合に、Deep Sleep 状態に遷移します

Spresense 基板では WKUPL 端子が出ていないため、WKUPL 信号による Deep Sleep への遷移機能を使用することはできません
起床条件

起床条件が発生すると、プログラムは SPI-Flash のロードから開始されるため、Power-On-Resetによる起動とほぼ同じだけの時間がかかります。

  • PM_BOOT_DEEP_WKUPL : WKUPL 信号が3秒以上アサートされた場合

  • PM_BOOT_DEEP_WKUPS : WKUPS 信号がアサートされた場合

  • PM_BOOT_DEEP_RTC : RTC Alarm が発火した場合

  • PM_BOOT_DEEP_USB_ATTACH : USB ケーブルが接続された場合

    • 通常、USB ケーブルが接続されていた場合は、Deep Sleep 状態に入ることはできません。 ただし、CONFIG_BOARD_USB_DISABLE_IN_DEEP_SLEEPING=y にすれば、USB 機能を Disable して Deep Sleep 状態に遷移することができます。このとき、USB 接続をトリガにして起床することはできません。

Spresense 基板では WKUPL, WKUPS 端子が出ていないため、WKUPL, WKUPS 信号による Deep Sleep からの起床機能を使用することはできません
Cold Sleep
特徴
  • CXD5602 は、チップ内部の PMU 電源ドメインのみ ON された状態です

    • CXD5602 I/O ピンは有効になっています

    • Backup SRAM の内容は保持されます

  • CXD5247 は通常動作状態です

    • CXD5247 RTC 時刻は保持されます(システムが RTC XTAL を持っていることが前提です)

    • CXD5247 GPO スイッチは Cold Sleep 中も値が保持されます

    • CXD5247 Load Switch は Cold Sleep 中も値が保持されます

消費電力
  • バッテリーの消費電流は、バッテリー端でおおよそ数百 uA です。この電流値は基板の設計に依存します。

Sleep 中の消費電力に関して、拡張ボードに SD カードが挿入されていると SD カードの電源消費分により 約 5 mA ほど消費電流が増加します。
スリープ条件
  • up_pm_sleep(PM_SLEEP_COLD) や board_poweroff(BOARD_POWEROFF_COLD) を呼び出すことによって、Cold Sleep 状態に遷移します

起床条件

起床条件が発生すると、プログラムは SPI-Flash のロードから開始されるため、Power-On-Resetによる起動とほぼ同じだけの時間がかかります。

  • PM_BOOT_COLD_SCU_INT : SCU 割り込みが発火した場合

  • PM_BOOT_COLD_SEN_INT : Sensor 割り込みが発火した場合

  • PM_BOOT_COLD_PMIC_INT : CXD5247 からの割り込みが発火した場合

    • WKUPS 信号がアサートされた場合

    • Low Battery が通知された場合

  • PM_BOOT_COLD_GPIO : GPIO 割り込みがアサートされた場合

  • PM_BOOT_COLD_RTC_ALM0 : RTC Alarm が発火した場合

  • PM_BOOT_COLD_USB_ATTACH : USB ケーブルが接続された場合

  • PM_BOOT_COLD_USB_DETACH : USB ケーブルが外された場合

Spresense 基板では USB 挿抜による Cold Sleep からの起床機能はサポートされていません
Hot Sleep
現在のSDKバージョンでは、Hot Sleep はサポートしておりません。
特徴
  • CXD5602 は、通常動作状態にほぼ等しいですが、NuttX が 動作しているアプリケーション CPU は電源 OFF されます

    • 但し、Hot Sleep 期間中も SRAM の値は保持されています

  • CXD5247 は通常動作状態です

消費電力
  • バッテリーの消費電流は、バッテリー端で最小で数百 uA 以下にまで下げることができますが、アプリケーションとして何を動作させている状態かに強く依存します。

スリープ条件
  • CONFIG_CXD56_HOT_SLEEP=y にすることで、Hot Sleep が有効になります。

    • 以下の CONFIG パラメーターで、Hot Sleep 状態に遷移する条件を変更できます

      • CONFIG_CXD56_HOT_SLEEP_WAIT_COUNT (milliseconds)

      • CONFIG_CXD56_HOT_SLEEP_THRESHOLD (milliseconds)

    • wakelock の取得と解除

      • 後述する wakelock 機構で Hot Sleep 制御を行います。一つでも wakelock が獲得されている限り、Hot Sleep への遷移が禁止されます

Power Manager は、以下に示すアルゴリズムで Hot Sleep 状態へ遷移します。

  1. NuttX OS がアイドル状態の場合、 Power Manager はアイドル状態に滞在する時間をカウントします

    • 何かしらの割り込みが発生した場合は、アイドル状態から抜けて、カウンタはリセットされます

  2. カウンタが、CONFIG_CXD56_HOT_SLEEP_WAIT_COUNT で定義された値を超えた場合、 Power Manager は、この後に続くアイドル時間を予測して計算します

  3. もし、この予測アイドル時間 > CONFIG_CXD56_HOT_SLEEP_THRESHOLD を超えていた場合、システムは Hot Sleep 状態へと遷移します

    • wakelock が獲得されている場合は、システムは Hot Sleep 状態への遷移は禁止されます

起床条件
  • アプリケーション CPU に対する割り込みが発生した場合

    • UART1 受信割り込み

    • UART2 受信割り込み

    • SCU (Sensor Control Unit) Watermark 割り込み

    • USB 挿抜割り込み

    • CXD5247 からの割り込み

    • GPIO 割り込み

    • 他の CPU からの CPU 間通信による割り込み

    • OS Timer 割り込み

11.10.5. 省電力制御

Spresense SDK は、以下のような省電力機能を提供します。

  • CPU システムクロック制御

  • CPU スリープ制御

CPU システムクロック制御

システムクロックは、主に 3 つのモードを提供しています。

Mode CPU Clock CXD5602 Core Voltage

HV (High Voltage) モード

PLL 156MHz

1.0 V

LV (Low Voltage) モード

PLL 32MHz

0.7 V

RCOSC モード

RCOSC 約 8MHz

0.7 V

クロック制御を行わない場合、常に HV モードで動作します。 動的なクロック制御による省電力機能を有効にする場合は、以下のコンフィグレーションを設定してください。

 [CXD56xx Configuration]
   [Power Management]
     [Dynamic clock control] <= Y

Dynamic clock control を有効にすると、システムは HV モード で起動した後に RCOSC モードまでクロックを落とします。定常状態では、RCOSC モードで動作します。

一時的に、高いパフォーマンスが要求される処理を行う場合は、 Frequency Lock 機構を使用して動的にクロックを変更することが可能です。

RCOSC モード、LV モード、HV モードの順番で動作クロックが上がりパフォーマンスも向上しますが、その分だけ消費電力も増加します。Frequency Lock 機構は、LV モードに切り替えたい場合は LV ロックを、HV モードに切り替えたい場合は HV ロックを獲得します。獲得したロックを解放すると、元のクロック状態に戻ります。システム全体のうち、どれか一つでも、より高いクロックモードのロックを獲得している限りは、システムは高いクロックモードで動作します。例として、LV ロック、HV ロックの両方が獲得されている場合は、HV モードになります。HV ロックが解放された場合に、次に高いクロックモードである LV モードへと切り替わります。そこで、LV ロックも解放されると RCOSC モードに戻ります。

  • HV ロック獲得

      struct pm_cpu_freqlock_s lock;
    
      lock.flag = PM_CPUFREQLOCK_FLAG_HV;
      up_pm_acquire_freqlock(&lock);
  • HV ロック解放

      up_pm_release_freqlock(&lock);
  • LV ロック獲得

      struct pm_cpu_freqlock_s lock;
    
      lock.flag = PM_CPUFREQLOCK_FLAG_LV;
      up_pm_acquire_freqlock(&lock);
  • LV ロック解放

      up_pm_release_freqlock(&lock);
CPU スリープ制御

SDK は アプリケーション CPU が アイドル状態のときに自動的に Hot Sleep に遷移する機能を提供します。

現在のSDKバージョンでは、スリープ制御機能はサポートしておりません。

デフォルト設定では、Hot Sleep 機能は無効になっています。この機能を有効にするには以下の設定が必要です。

 [CXD56xx Configuration]
   [Power Management]
     [Hot Sleep] <= Y
       [Hot Sleep wait counter] <= 20
       [Hot Sleep threshold] <= 1000
       [Enable GNSS Hot Sleep] <= Y

CONFIG_CXD56_HOT_SLEEP=y にすると、OS アイドル状態のときに自動的に Hot Sleep 状態に遷移します。 CONFIG_CXD56_GNSS_HOT_SLEEP=y にすると、GNSS CPU の Hot Sleep 機能を有効にすることができます。

アイドル状態で自動的に Hot Sleep 状態に遷移しますが、wakelock 機構により Sleep 状態に遷移するのを抑止することができます。

  • wakelock ロック獲得

    struct pm_cpu_wakelock_s lock;
    
    lock.count = 0;
    up_pm_acquire_wakelock(&lock);
  • wakelock ロック解放

    up_pm_release_wakelock(&lock);

11.11. Sensor Fusion Framework

11.11.1. General

CXD5602 はLow Power 常時センシング機能を備えているとともに、 多くのCoreとメモリによるセンサフュージョン機能が実現可能です。

SDKでは、これらを容易に実現するためのフレームワークを提供しています。

センサフュージョンフレームワークは、"Sensor Manager" と各センサの"Sensor Client"から構成されます。

  • "Sensor Manager" は、Publish-Subscribe Architectureに基づき、複数の"Sensor Client"を制御し、ここからPublishされるSensor Dataを配信します。

  • "Sensor Client"は、各種 "Sensor Device"を制御するドライバを制御する、"Physical Sensor"、 各"Sensor Device"からのデータをFusionして、高機能なセンサを実現する"Logical Sensor"、 Applicationがデータを受け取るための、"Sensor Application"から構成されています。

Sensor Framework のArchitecture図は以下の通りです。

Sensor Framework(Publish/subscribe) Architecture
図 67. Sensor Framework (Publish/subscribe) Architecture

11.11.2. Sensor Manager

"Sensor Manager" は、複数の"Sensor Client"の登録、管理を行い、 適切にセンサデータの配信を行います。

General

"Sensor Manager" に登録された、"Sensor Client"は、取得したデータを"Sensor Manager" に打ち上げることで、"Sensor Manager" が、Subscribeを要求している "Sensor Client" に適切にデータを配信します。

また、Subscribeされていない"Sensor Client"の電源モードを落とせるような枠組みを提供します。

APIs

"Sensor Manager" は、以下のAPIを提供します。 "Sensor Manager" のインターフェースは、パケットと呼ばれるデータ形式のコマンドを を発行すること制御可能です。 "Sensor Client" の登録、削除、データの受け渡しなどを行います。

表 28. Sensor Manager API
APIs Description Corresponding API Corresponding packet

Register

Resister a Sensor Client to Sensor Manager as subscriber.

SS_SendSensorResister

sensor_command_register_t

Release

Unresister the Sensor Client from Sensor Manager.

SS_SendSensorRelease

sensor_command_release_t

SendData

Sender function to Sensor Manager without MemHandle.

SS_SendSensorData

sensor_command_data_t

SendData(MH)

Sender function to Sensor Manager with MemHandle.

SS_SendSensorDataMH

sensor_command_data_mh_t

SendSetPower

Set power status of sensors.

SS_SendSensorSetPower

sensor_command_power_t

Sequence
diag b509d143949476f6504257768861e6ec
図 68. Sensor Manager Sequence
MemHandleについては、Memory Manager Libraryを参照してください。

11.11.3. Logical Sensors

General

"Logical Sensor"とは、各種の物理センサから得られたセンサデータを何らかの信号処理アルゴリズムなどに基づき、高機能なセンサデータを作成するための"Sensor Client"で、ソフトウェアモジュールで構成されています。
実際のアルゴリズムの実装アロケーションは、下記のいくつかの方法があります。

  • NuttX上のタスクとして実装する。

  • asmpフレームワークを使って、DSP上に実装する。

  • 各社ベンダが提供した暗号化されたDSPを用いて実装する。

A logical sensor task on NuttX.

NuttX上のモジュール、もしくはタスクとして実装をします。
特に、重くない処理であったり、頻度の多くない処理の場合、このように実装することで、メモリ、CPUリソースなどを消費せず実装が可能です。

表 29. Samples of Logical Sensors on NuttX
Contents Sample provider

Barometer

From sensor vender

TAP Gesture (Tapping Detector)

From SDK

A logical sensor on DSP by asmp.

ユーザが独自に"Logical Sensor"のアルゴリズムを作成し、その処理をDSP側にオフロードする必要があるような場合(例えば、処理が重いなど)、ASMPフレームワークを用いて、DSP側に実装することが可能です。
このような場合、"Logical Sensor"をスーパーバイザタスクで実装し、そのスーパーバイザタスクからDSP上のWorkerタスクへ処理要求を送って処理をさせることで、マルチコア処理での"Logical Sensor"を実現できます。

表 30. Samples of Logical Sensors on DSP
Contents Sample provider

""

From SDK

SuperVisor and Worker
図 69. SuperVisor and Worker
ASMPフレームワークについては、ASMP Frameworkを参照してください。
A logical sensor on DSP with encryption.

各ソリューションベンダは、さまざまな logical sensor のアルゴリズムを提供します。その場合、各ベンダは、コードを開示せず、それぞれの契約等に基づき、機能を提供することが可能です。
このケースの場合は、ASMPフレームワーク上に、build 及び encryption 済のバイナリをロードすることで、実現が可能です。Encrypted DSPは、各ベンダから提供されます。

表 31. Samples of Logical Sensors on DSP with encryption
Contents Sample provider

AESM (Activity Engine and Step Meter)

From SDK

SuperVisor and Encrypted Worker
図 70. SuperVisor and Encrypted Worker

11.11.4. Logical Sensor API

各 Logical sensorは次のAPIを提供します。

表 32. Logical Sensor API
APIs Description

Create

Create a class instance to communicate with workers.

Open

Load library and boot up as worker task.

Write

Send data to worker task.

Close

Destroy worker task.

これらの要求は、以下のイベントとして定義され、DSP上のWorkerタスクとの送受信に使用されます。
詳細については、各スーパーバイザを参照してください。

Event Description

Init

Initialization event.

Exec

Execution event.

Flush

Terminal event.

11.11.5. Details of each Logical Sensors

11.11.6. Step Counter

"Step Counter" の構成図を以下に示します。

Configuration diagram of Step Counter
図 71. Configuration diagram of Step Counter
Supervisor

スーパーバイザは"Logical Sensor"のためのフレームワークです。 スーパーバイザのDSP上のWorkerを制御するためのいくつかのAPIを提供します。

APIs

"Step Counter"は以下の5つのAPIを提供します。

表 33. Step Counter API
APIs Description Corresponding API

Create

Create StepCounterClass instance.

StepCounterCreate

Open

Load StepCounter library and boot up as worker task.

StepCounterOpen

Write

Send data to StepCounter worker task.

StepCounterWrite

Close

Destory StepCounter worker task.

StepCounterClose

Set

Set setting to StepCounter library .

StepCounterSet

Data format for Step Counter

"Step Counter"には、以下のように指定されたフォーマットで"Accelerometer"のデータが必要です。
これらのデータをWriteのAPIでWorkerに送信します。

Data format of Accelerometer
図 72. Data format for Step Counter
Result of sensing

"Step Counter”は1秒ごとに以下の歩数計情報を出力します。 これらの情報は、StepCounterStepInfo に格納されます。

表 34. Step Counter result
情報 単位 備考

テンポ

Hz

停止状態時も1Hz以上の値となります。

歩幅

cm

歩行と走行でそれぞれ固定値となります。

速度

m/s

累積移動距離

m

歩数

-

行動認識

-

停止/歩行/走行状態を示します。

How to use
Preparation

"Sensor Manager"と呼ばれる複数の"Sensor Client"を制御するために設計されたフレームワークで、 "Step Counter"を制御します。

そのため、"Step Counter"を制御するには、"Sensor Manager"を事前に有効にする必要があります。

Activate Sensor Manager

"Sensor Manager" を有効にするには、SS_ActivateSensorSubSystem(MsgQueId, api_response_callback_t) を呼ぶ必要があります。
MsgQueId は、Message Library Configuration で定義された MsgQueID を指定する必要があります。
api_response_callback_t は、非同期の通知を行うためのコールバック関数を指定します。
NULLを指定した場合は通知は行われません。

static void sensor_manager_api_response(unsigned int code,
                                        unsigned int ercd,
                                        unsigned int self)
{
  ...
}

SS_ActivateSensorSubSystem(MSGQ_SEN_MGR, sensor_manager_api_response);
Register to Sensor Manager

"Sensor Manager"の有効後、"Sensor Manager"に"Step Counter"がSubscribeを要求する"Sensor Client"として、"Accelerometer"を登録します。
この際、Subscribeの処理として、StepCounterWriteを呼び出すコールバック関数を指定します。

また、"Application"が"Step Counter"のセンシング結果を知るために、 "Application"がSubscribeを要求する"Sensor Client"として、"Step Counter"を登録します。
この際、Subscribeの処理を行うコールバック関数を指定します。

bool step_counter_receive_data(sensor_command_data_mh_t& data)
{
  StepCounterWrite(sp_step_counter_ins, &data);

  return true;
}

bool step_counter_recieve_result(sensor_command_data_mh_t& data)
{
  bool ret = true;
  FAR SensorCmdStepCounter *result_data =
    reinterpret_cast<SensorCmdStepCounter *>(data.mh.getVa());
  if (SensorOK == result_data->result.exec_result)
    {
      if (result_data->exec_cmd.cmd_type ==
            STEP_COUNTER_CMD_UPDATE_ACCELERATION)
        {
           ...
        }
    }
    return ret;
}

sensor_command_register_t reg;

reg.header.code   = ResisterClient;
reg.self          = stepcounterID;
reg.subscriptions = (0x01 << accelID);
reg.callback      = NULL;
reg.callback_mh   = &step_counter_receive_data;

SS_SendSensorResister(&reg);

reg.header.code   = ResisterClient;
reg.self          = app0ID;
reg.subscriptions = (0x01 << stepcounterID);
reg.callback      = NULL;
reg.callback_mh   = &step_counter_recieve_result;
SS_SendSensorResister(&reg);
diag 7959450e48d8db3a8cb08898b9087e99
図 73. Register sequence
Create and Open

事前準備の完了後、"Step Counter"の生成、有効化を行います。

"Step Counter"の生成には、StepCounterCreate(PoolId) を呼ぶ必要があります。
PoolIdには、"Memory Manager Configuration"で定義された IDを指定する必要があります。
戻り値として、"Step Counter"のインスタンスへのポインタが返ります。

FAR StepCounterClass *step_counter_instance;
step_counter_instance = StepCounterCreate(SENSOR_DSP_CMD_BUF_POOL);

"Step Counter"の有効化には、StepCounterOpen(FAR StepCounterClass*) を呼ぶ必要があります。
StepCounterClass*には、StepCounterCreateの戻り値である、"Step Counter"のインスタンスへのポインタを指定する必要があります。

StepCounterOpen(step_counter_instance);
diag 92638438e21b2b09bca98b4aded9c7a3
図 74. Create and Open sequence
Set stride

センシングする際の歩幅の初期値は、walking状態で60cm、running状態で80cmです。

この初期値を変更する場合は、StepCounterSet(FAR StepCounterClass*, StepCounterSetting*) を呼ぶ必要があります。
StepCounterClass*には、StepCounterCreateの戻り値である、"Step Counter"のインスタンスへのポインタを指定する必要があります。
StepCounterSetting*には、walking状態とrunning状態のそれぞれの歩幅を step_lengthに単位cmで設定して下さい。歩幅最大値は250cmです。
step_modeは、"STEP_COUNTER_MODE_FIXED_LENGTH"固定です。

StepCounterSetting set;
set.walking.step_length = 70; /* Set stride to 70 cm */
set.walking.step_mode   = STEP_COUNTER_MODE_FIXED_LENGTH;
set.running.step_length = 90; /* Set stride to 90 cm */
set.running.step_mode   = STEP_COUNTER_MODE_FIXED_LENGTH;
StepCounterSet(step_counter_instance, &set);
diag 9fbd33a5bd9ccfe7b9533586feedd6ee
図 75. Set sequence
Start Sensing

"Step Counter"は"Accelerometer"のSubscribeを契機に呼び出される StepCounterWriteで、DSP上のWorkerにデータを送信し、センシング処理を行います。

この際のシーケンスを以下に示します。

diag e3e3d4a2b8659de4f19e336f457ddb09
図 76. Sensing sequence of Accelerometer publish
Close

"Step Counter"の無効化には、StepCounterClose(FAR StepCounterClass*) を呼ぶ必要があります。
StepCounterClass*には、StepCounterCreateの戻り値である、"Step Counter"のインスタンスへのポインタを指定する必要があります。

StepCounterClose(step_counter_instance);
diag 457068923d2998772d6ed9f72e49a249
図 77. Close sequence
Release from Sensor Manager

"Step Counter"の無効後に、"Sensor Manager"への登録を解除します。 この際、"Step Counter"にSubscribeする"Sensor Client"の動作を事前に停止させてください。

sensor_command_register_t reg;

rel.header.code = ReleaseClient;
rel.self        = stepcounterID;
SS_SendSensorRelease(&rel);
Build Configurations

"Step Counter"の機能を使用するためには、

$>cd sdk
$>tools/config.py -m

でconfigurationのmenuを開き、以下のoptionを設定する必要があります。

Select options in below:

[CXD56xx Configuration]
  [I2C0] <= Y
  [Sensor Control Unit] <= Y
[Memory manager] <= Y
  [Memory Utilities]
    [Memory manager] <= Y
    [Message] <= Y
[Drivers]
  [Sensor Drivers] <= Y
    [Bosch BMI160 Sensor support] <= Y
      [SCU Sequencer] <= Y
[Sensing]
  [Sensing manager] <= Y
  [Step counter] <= Y
[ASMP] <= Y
Worker

Workerは他のCore上で動作し、Supervisorから送信されたセンサデータを分析します。
そして、要求されたイベントの処理結果(ステップ数、状態など)を返します。

"Step Counter"のWorkerは、分析のために以下に示すデータを必要とします。

・ Accelerometerデータ(32Hz、32サンプル/1秒)
APIs

"Step Counter"のWorkerは以下の3つのAPIを提供します。

表 35. Step Counter Worker API
APIs Description

Init

Initialize for AESM(Activity Engine and Step Meter) library.

Exec

Execute calculate on sensor data on AESM library.

Flush

End execute process of AESM library.

これらのAPIは、Supervisorから送信されたパケットに含まれるイベントタイプやコマンドタイプによって、 呼び出されます。

関係は下記の通りです。

Init
SensorDspCmd dsp_cmd;
dsp_cmd.header.sensor_type     = StepCounter;
dsp_cmd.header.event_type      = InitEvent;
Exec
SensorDspCmd dsp_cmd;
dsp_cmd.header.sensor_type     = StepCounter;
dsp_cmd.header.event_type      = ExecEvent;
dsp_cmd.exec_aesm_cmd.cmd_type = AESM_CMD_UPDATE_ACCELERATION;
Flush
SensorDspCmd dsp_cmd;
dsp_cmd.header.sensor_type     = StepCounter;
dsp_cmd.header.event_type      = FlushEvent;
Step Counter Example

"Step Counter"のsample applicationとして、"Step Counter" exampleがあります。ここでは、その使い方などを説明します。

Preparation
Build Configurations (kconfig)

"Step Counter"のsample applicationを使うには、configurationのoptionを以下の設定にしてください。

Select options in below:

[Examples]
  [Step counter sensor example] <= Y

または、"Step Counter"のdefault configurationを使用して下さい。

$ ./tools/config.py examples/step_counter
Memory and Message Utility Configurations and Layout

タスク間通信ライブラリ(Message Library)とメモリ管理ライブラリ(Memory Manager)の設定は、以下のように行ってください。

Message Library Configuration

"Step Counter"を使用する際に必要となる"MessageQueue"の定義を行う必要があります。 定義はMessageQueueLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

"Step Counter"のsample applicationでは下記のように行います。

$>cd examples/step_counter/config
$>ruby -I../../../sdk/modules/memutils/message/tool msgq_layout.conf 0x000fe000 0x1000 msgq_id.h msgq_pool.h

MessageQueueLayout定義ファイル(msgq_layout.conf)の記述内容は下記の通りです。

MsgQuePool
 # ID,             n_size  n_num    h_size  h_nums
 ["MSGQ_SEN_MGR",  40,     8,       0,      0],

各パラメータの説明は以下の通りです。

パラメータ 説明

ID

メッセージキュープールIDの名称を、"MSGQ_"で始まる文字列で指定。

n_size

通常優先度キューの各要素のバイト数(8以上512以下)。固定ヘッダ長(8byte) + パラメタ長を4の倍数で指定する。

n_num

通常優先度キューの要素数(1以上16384以下)。

h_size

高優先度キューの各要素のバイト数(0または、8以上512以下)。未使用時は0を指定すること。

h_num

高優先度キューの要素数(0または、1以上16384以下)。未使用時は0を指定すること。

n_sizeは最適値となっているため、変更は行わないでください。

n_numも変更の必要はありませんが、他のapplicationでStep Counterを使う場合は、負荷を考慮して値を増やす必要が出てくる可能性があります。

h_size, h_numsはStep Counterを優先的に処理したい場合に利用して下さい。

それぞれの定義の詳細については、 examples/step_counter/config/msgq_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。
Memory Manager (Intelligent Fix Pool) Configuration

"Step Counter"を使用する際に必要となるMemoryLayout(pool)の定義を行う必要があります。
定義はMemoaryLayout定義ファイルで行い、ツールでコードに組み込むヘッダファイルを生成することが出来ます。

"Step Counter"のsample applicationでは下記のように行います。

$>cd examples/step_counter/config
$>ruby -I../../../sdk/modules/memutils/memory_manager/tool -I. mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定義ファイル(mem_layout.conf)の記述内容は下記の通りです。

FixedAreas
FixedAreas
 # name,                  device,     align,        size,         fence
  ["SENSOR_WORK_AREA",    "SHM_SRAM", U_STD_ALIGN,  0x0001e000,   false],
  ["MSG_QUE_AREA",        "SHM_SRAM", U_STD_ALIGN,  0x00001000,   false],
  ["MEMMGR_WORK_AREA",    "SHM_SRAM", U_STD_ALIGN,  0x00000200,   false],
  ["MEMMGR_DATA_AREA",    "SHM_SRAM", U_STD_ALIGN,  0x00000100,   false],

各パラメータの説明は以下の通りです。

パラメータ 説明

name

領域名(英大文字で始まり、"_AREA"で終わる名称。英大文字, 数字, _が使用可能)

device

領域を確保するMemoryDevicesのデバイス名

align

領域の開始アライメント。0を除くMinAlign(=4)の倍数を指定する

size

領域のサイズ。0を除く4の倍数の値を指定する

fence

フェンスの有効・無効を指定する(この項目は、UseFenceがfalseの場合は無視される)

各nameの用途は以下の通りです。

SENSOR_WORK_AREA

センサフュージョンが利用する

MSG_QUE_AREA

MessageQueueが利用する(固定名)。msgq_id.hの(MSGQ_END_DRM - MSGQ_TOP_DRAM)のサイズを超えないこと。

MEMMGR_WORK_AREA

Memory Managerが利用する作業領域(固定名, 固定サイズ)

MEMMGR_DATA_AREA

Memery Managerが利用するデータ領域(固定名, 固定サイズ)

各nameの合計のサイズがmpshm_init(), mpshm_remap()で確保するシェアメモリのサイズを超えないようにしてください。

PoolAreas
PoolAreas
 # name,                     area,               align,       pool-size,                   seg,                        fence
 ["SENSOR_DSP_CMD_BUF_POOL", "SENSOR_WORK_AREA", U_STD_ALIGN, U_SENSOR_DSP_CMD_POOL_SIZE,  U_SENSOR_DSP_CMD_SEG_NUM,   false],
 ["ACCEL_DATA_BUF_POOL",     "SENSOR_WORK_AREA", U_STD_ALIGN, U_ACCEL_DATA_BUF_POOL_SIZE,  U_ACCEL_DATA_BUF_SEG_NUM,   false],

各パラメータの説明は以下の通りです。

パラメータ 説明

name

プール名(英大文字で始まり、"_POOL"で終わる名称。英大文字, 数字, _が使用可能)

area

プール領域として使用するFixedAreaの領域名。領域はRAMに配置されていること

align

プールの開始アライメント。0を除くMinAlign(=4)の倍数を指定する

pool-size

プールのサイズ。0を除く4の倍数の値。Basicプールでは、セグメントサイズ * セグメント数

seg

セグメント数。1以上、255以下の値を指定する

fence

フェンスの有効・無効を指定する。この項目は、UseFenceがfalseの場合は無視される

各nameの用途は以下の通りです。

SENSOR_DSP_CMD_BUF_POOL

Workerとの送受信用バッファ領域

ACCEL_DATA_BUF_POOL

Accelerometerデータのバッファ領域

それぞれの定義の詳細については、 examples/step_counter/config/mem_layout.confを参照してください。
設定が変わった場合は、ツールを使って新しいヘッダーファイルを生成してください。

11.12. JPEG Decoder

11.12.1. 概要

IJGが開発したlibjpegライブラリをベースにしたJPEGデコード機能を提供します。

概ねオリジナルlibjpegライブラリのAPI仕様に準じておりますが、Spresense向けにカスタマイズしている点がありますので、 このドキュメントで、カスタマイズ内容について詳述します。

以下の説明において、「libjpegインスタンス」とは、libjpeg利用アプリケーションが用意しなければいけないstruct jpeg_decompress_struct型変数を指します。

11.12.2. Spresense向けカスタマイズ内容

出力フォーマット(色空間)

オリジナルlibjpegでサポートしているフォーマットはいずれも24bit/pixel以上ですが、 Spresenseでは16bit/pixelのCb/Y/Cr/Y(YUV4:2:2)フォーマットをサポートすることで、より少ないメモリでデコードできるようにしています。
下記defineがSpresenseで有効な色空間の定義です。 このパラメータをlibjpegインスタンスのメンバ out_color_space に設定してjpeg_start_decompress()を実行することで、 任意のサポート色空間でデコードすることが可能になります。

表 36. 出力フォーマット(色空間)
define名 意味 bits/pixel Spresense オリジナル

JCS_CbYCrY

Cb/Y/Cr/Y(YUV4:2:2)

16

×

JCS_YCbCr

Y/Cb/Cr(YUV)

24

×

JCS_RGB

sRGB

24

×

JCS_CMYK

C/M/Y/K

32

×

JCS_YCCK

Y/Cb/Cr/K

32

×

デコード結果読み出し単位

オリジナルlibjpegでは行単位の読み出しをサポートしていますが、 それに加えてSpresenseでは、より小さなMCU単位での読み出しもサポートしています。

表 37. デコード結果読み出しAPI
API名 用途 Spresense オリジナル

jpeg_read_scanlines

行単位での読み出し

jpeg_read_mcus

MCU単位での読み出し

×

MCUは、JPEGの圧縮単位ブロックで、基本は8×8pixelとなります。 JPEGエンコード時のパラメータ(JPEGヘッダに設定されている)およびデコード時のパラメータ(アプリケーションが設定する)によってサイズが変化します。 アプリケーションとしては、jpeg_start_decompress()実行後にlibjpegインスタンスの情報から以下のように1MCUのサイズを知ることができます。

  • 1MCUの幅 = output_width / MCUs_per_row (トータルの幅 / 幅 方向の総MCU数)

  • 1MCUの高さ = output_height / MCU_rows_in_scan(トータルの高さ / 高さ方向の総MCU数)

MCU単位の場合、1単位あたりのpixel数(データサイズ)が画像サイズに依存しないので、この2種類の単位の差は下記の例のように画像サイズが大きいほど顕著になります。

表 38. 単位pixel数の例:Spresenseカメラで撮影したJPEGファイルを等倍でデコードする場合
単位 QVGAの場合 HDの場合 5Mの場合

行単位

320

1280

2560

MCU単位

128

128

128

JPEGデータ入力方法

オリジナルlibjpegでは、ファイルポインタもしくはバッファでJPEGデータを入力できましたが、 Spresenseでは、それらに加えてファイルディスクリプタにも対応します。

表 39. JPEGデータ入力API
API名 意味 Spresense オリジナル

jpeg_stdio_src

ファイルポインタ

jpeg_fd_src

ファイルディスクリプタ

×

jpeg_mem_src

バッファ

ここでいうファイルディスクリプタとは、read()関数でJPEGデータの読み出しができるファイルディスクリプタであることが条件です。
例えば、通常ファイルをopen()したファイルディスクリプタ以外にも、socket()で作成したソケットディスクリプタも対応可能になります。 (もちろん、ソケットディスクリプタの場合、通信相手からJPEGデータがそのまま送られてくる必要があります。)

エラーハンドリング

オリジナルlibjpegもSpresenseもデフォルトではエラー発生時はexit()によってlibjpeg API実行タスクが終了します。 タスクを終了させない方法として、オリジナルlibjpegでは「setjmp/longjmp」を用いるexampleを提示していますが、 Spresense(NuttX)はsetjmp/longjmpをサポートしていないため、この手法は使えません。 今後、setjmp/longjmp以外の方法でエラーハンドリングできるようサポートする予定です。

libjpegのエラーハンドリングは、「エラーハンドラがreturnしない」前提で実装されており、 仮にエラーハンドラがreturnした場合の動作保証はしておりません。
表 40. エラーハンドラの終了手段
エラーハンドラの
終了手段
意味 Spresense オリジナル

exit

libjpeg API実行タスクの終了

longjmp

setjmpで保存したスタックコンテキストへの
nonlocal jump

×
(NuttX未サポート)


(実装環境依存)

return

エラー検出関数へのreturn

×

×

「エラー」にはプログラム異常によるものの他に、外部要因によるものあります。代表的なエラーについては標準エラー出力への出力参照。

11.12.3. 状態遷移

diag 6e5e8ce3ead6b59b4a2ac2c763e57766

11.12.4. 動作シーケンス

diag 4b1334473a4d030e9f0ff49b1f9497e8
図 78. libjpeg 動作シーケンス

11.12.5. 標準エラー出力への出力

libjpegライブラリは、エラー もしくはWarningを検出した場合に標準エラー出力にメッセージを英文で出力します。 メッセージの意味や出力理由については、オリジナルlibjpegと変わりありません。

ここでは、よく発生するメッセージについて説明します。

表 41. libjpegライブラリによる標準エラー出力メッセージ
出力メッセージ エラー/Warning 出力契機

Improper call to JPEG library in state %d

エラー

API実行順が状態遷移図に従っていない

Unsupported color conversion request

エラー

サポートしていない出力フォーマットを指定した

Not a JPEG file: starts with 0x%02x 0x%02x

エラー

0xFF D8から始まっていない

Corrupt JPEG data: bad Huffman code

Warning

ハフマン符号のデコードエラー

Premature end of JPEG file

Warning

入力されたJPEGデータがEOIマーカーが出てこないままEOFに到達した場合に出力されます。

11.12.6. サンプルコード

このサンプルコードは、オリジナルlibjpegライブラリに添付されているexample.cのデコードプログラムをベースにして、 Spresense版libjpegの以下の特徴を盛り込んだものになります。

  • YUV4:2:2フォーマットで出力する

  • JPEGデータの入力にファイルディスクリプタを利用できる

  • MCU単位のデコードができる

12. NuttXが提供する機能

NuttXが提供する機能については、NuttX.orgを参照してください。


1. 初期位置算出時間 (Time To First Fix)
2. 衛星から受信機間の距離