Developer World Spresense
English 日本語
目录

1. Spresense SDK 概述

Spresense SDK 是用于控制 Sony Semiconductor Solutions Corp. 为 CXD5602 开发的 CXD5602 的软件。 CXD5602 的内部块如下。

CXD5602 blockdiagram
图表 1. CXD5602 内部框图

CXD5602由四个称为域的块组成。

  • Application Domain

    • 该块主要由用户应用程序控制,并安装了六个CPU(ARM制造的ARM Cortex®-M4F)。

  • System IOP Domain

    • 这是用于启动系统和管理 CXD5602 中的电源域的模块,并且配备了ARM Cortex-M0。

  • GNSS Domain

    • 该块使用卫星进行定位,并配备有ARM Cortex-M4F。

  • Sensor Domain

    • 一个模块,可从连接到I2C和SPI总线的传感器获取数据,而无需CPU的干预。

有关 CXD5602 的更多信息,请参考 索尼半导体解决方案有限公司Spresense网站

Spresense SDK 是用于控制上述硬件的软件。 Spresense SDK 使用RTOS之一的 NuttX 作为OS,并提供了详细的功能以基于该OS发挥 CXD5602 的性能。 Spresense 的每个驱动程序都是根据类似于Linux的 NuttX 的驱动程序框架以及 Spresense 的Audio,GNSS,ASMP等中间件层在驱动程序层之上实现的。

sdk overview
图表 2. SDK 概览

每个中间件和特性驱动程序的概述如下。

表格 1. Spresense SDK 中间层概览
模块名 摘要

Audio Middleware

提供 Spresense SDK 的音频功能。对应于各种数据路径,除了以各种格式记录和回放之外,还可以实现语音处理。

Sensor Framework

当输出和处理 Spresense SDK 的各种传感器数据时,它成为一个框架,可以轻松地使用发布/订阅体系结构对传感器的交换或处理数据进行编程。

Memory Utility

Spresense SDK 提供了具有参考计数器的固定大小的内存池功能以及用于异步传输和接收实例的任务同步机制。

ASMP Framework

除了管理 CXD5602 的多核用户程序的加载之外,还管理着12个切片( CXD5602 的存储结构的功能之一)。

Power Management

提供节能功能。

GNSS Driver

CXD5602 具有执行GNSS定位的硬件子系统。该驱动程序与子系统交互,并为用户提供与GNSS相关的功能,就像POSIX I/F字符设备一样的I/F。

有关每个模块的详细信息,请参见“ Spresense SDK 提供的功能” 一章。

2. 许可证

NuttX 一样, Spresense SDK 在BSD 3条款许可下以开源形式发布。详细的许可条款如下。

3. 系统启动顺序

从复位释放 CXD5602 时,BootCPU启动。 与此BootCPU配合使用的是loader.espk。 当loader.espk启动时,控制权转移到loader.espk,后者加载nuttx.spk并启动应用程序CPU。

由于nuttx.spk是使用此SDK构建的二进制文件,因此nuttx.spk的执行内容取决于构建设置和应用程序行为。

如果您的应用程序使用GNSS功能,则在调用初始化API时,loader.espk将加载gnss.espk。

因此,使用 Spresense 板需要loader.espk和gnss.espk二进制代码。 请参考 引导加载程序安装 ,以获取二进制文件。

4. 软件配置管理

本章概述了 Spresense SDK 源代码。

4.1. 知识库

Spresense SDK 由以下两个存储库组成。

仓库名称 子库 説明

spresense

使用 Spresense SDK 主存储库准备开发环境时,请克隆此存储库。它包括 Spresense BSP,受 Spresense 支持的驱动程序,各种示例代码,并将spresense-nuttx作为子模块进行引用。

spresense-nuttx

Spresense NuttX克隆存储库。 Spresense 中的内核由此存储库管理。

4.2. 源树

Spresense SDK 的源树结构如下:

spresense directory structure
图表 3. Spresense SDK 目录结构

每个目录的内容如下:

目录名 説明

spresense

spresense是Clone创建的目录

nuttx

Spresense 包含NuttX内核源代码

examples

包含使用 Spresense SDK 支持的驱动程序和模块的示例代码

sdk

包括 Spresense SDK 支持的驱动程序和模块

bsp

包含带有 Spresense SDK 的BSP

configs

包括Spresense SDK提供的配置

drivers

包括Spresense SDK提供的驱动程序

modules

包含Spresense SDK提供的音频和传感器等模块

system

包括Spresense SDK提供的系统工具

tools

包含使用Spresense SDK开发所需的工具和脚本

5. Spresense SDK 提供的功能

本节介绍 Spresense SDK 提供的每个功能。

5.1. BSP

5.1.1. 简介

BSP(Board Support Package)包括用于板级特定设置和处理的源代码。

NuttX具有以下驱动程序软件体系结构,并且BSP目录包含驱动程序软件,例如: Driver(Lower Half)Board specific codeArchitectural specific code

diag 7b3a8011eb336e2a51fcad7d4f0a6496
图表 4. 设备驱动程序层次结构图
5.1.1.1. 驱动 (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设备驱动程序

5.1.1.2. 框架特定代码

特定于体系结构的驱动程序包括用于使用芯片上功能的驱动程序(例如电源管理)。

5.1.1.3. 板载特定代码

某些特定于板的处理过程可能会根据板的实现方式(引脚设置等)而改变。这些过程分为可以在一定程度上共享的过程和完全取决于董事会的过程。 它们分别存储在 bsp/board/commonbsp/board/<board name> 中,其中 <board name> 是对应的董事会名称。

这还包括 电路板初始化过程

5.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

包括Low Half驱动程序和特定于芯片的设备驱动程序。

5.1.3. 电路板初始化过程

diag 7cab1242a74578faa85099b817db3c64
图表 5. 启动顺序

当主CPU启动时,将初始化NuttX内核,并调用SDK入口点函数。默认情况下,启动 nsh (NuttShell)。

nsh 中,板初始化( boardctl() )被调用。实际的板卡初始化是根据NuttX规则在 board_app_initialize 函数中实现的。该功能执行处理以初始化要使用的板。

初始化过程包括初始化要使用的最低功能 Spresense 和初始化要使用的设备驱动程序。

如果将以 SDK_USER_ENTRYPOINT 开头的任务从 nsh 更改,则用户必须自己调用 boardctl()

5.2. GPIO/Pin 规格

5.2.1. 软件结构

diag 2ccf26c7a02c2ea94fe313d124e620e3

5.2.2. GPIO 驱动接口

gpioif 为应用程序提供以下功能:

  • GPIO引脚设置

    • 功能模式

    • 输入/输出设置

    • 驱动电流/摆率设置

    • 上拉/下拉设置

  • GPIO中断设定

    • 电平/边沿触发设置

    • 噪音过滤器设定

  • GPIO I/O控制

  • GPIO 状态

有关API详细信息,请参考 这里

5.2.2.1. GPIO 应用工具

GPIO命令是在系统工具中准备的, 可以通过设置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

5.2.3. Pin 规格

引脚分配有多种功能,可以通过模式(0-3)更改功能。 将各种引脚分配给引脚组,并通过模式规范按引脚组单位更改功能。

例如,PIN_PWM2,3

boardspec pinmode
  • Mode0 中,PIN_PWM2和PIN_PWM3引脚均设置为GPIO功能

  • Mode1 中,PIN_PWM2和PIN_PWM3引脚均设置为PWM功能

  • Mode2 中,PIN_PWM2和PIN_PWM3引脚均设置为I2C功能

换句话说,由于功能是以组为单位分配的,因此无法将PIN_PWM2设置为GPIO,并且无法将PIN_PWM3单独设置为PWM。

默认情况下,所有引脚都设置为 Mode0(GPIO)

5.2.3.1. Pin 表
  • Pin Name: sdk/bsp/include/arch/chip/pin.hPIN_XXX 形式定义

  • WLCSP: 100引脚封装(CXD5602GF)的定义。。有一些无法使用的PIN。

  • FCBGA: 定义185-pin full package (CXD5602GG)。用于Spresense板上。

  • Mode0-3: 描述每种模式下引脚的功能。

表格 2. 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

5.2.3.2. Pin 配置

使用pinconfig驱动程序配置引脚设置。例如,当使用Mode0(GPIO)以外的I2C和SPI功能时,分别在I2C和SPI驱动器中设置了引脚。 因此,应用程序无需知道模式等的变化。

仅当将其用作Mode0(GPIO)时,请使用上述 gpioif 进行设置。

5.2.3.2.1. 电路板特定的引脚拉力和驱动电流设置

引脚拉动设置和驱动器电流默认设置,定义于 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引脚上的下拉

  • 将SPI4驱动电流从2mA更改为4mA

  • PWM驱动电流从2mA变为4mA

上述。


5.3. Audio 子系统

5.3.1. 常用

CXD5602具有可处理高分辨率的音频功能(音频子系统)。 以下是音频子系统的功能概述。

  • Audio Codec硬件(AD/DA、DNC、DEQ等)控制

  • Aduio Player功能

  • Audio Recorder功能

  • Bluetooth功能(如:BT-A2DP)

  • Sound Effector功能(例如,语音通话的带通滤波器)

本文档介绍了可在CXD5602硬件上实现的用于控制音频功能的软件。有关音频硬件,请参考单独的外部参考: Spresense硬件相关文档

当前固件不支持蓝牙相关功能(用于BT-A2DP)和音效器功能(例如,用于语音通话的带通滤波器)。

5.3.2. 关于层结构

音频子系统堆栈图如下所示。

Audio 子系统堆栈图
图表 6. Audio Sub-system Stack diagram

音频子系统具有三个主要层。

Audio Manager(High Level API)

这是控制最高抽象级别的顶层。 控制整个系统。

Object Layer(ObjectLevel API)

这是一个控制每个功能对象层中每个功能块抽象级别的层。在每个功能中匹配信号处理和DSP处理。

Component Layer(Low Level API)

该层控制每个信号处理组件层中每个信号处理块的抽象级别。通过将处理与信号处理模块组合来配置,可以实现具有高自由度的音频处理。

5.3.3. 顶层 API

顶层API是由 Audio UtilityAudio Manager 提供的。

5.3.3.1. 命令控制发送/接收

顶层API把音频及其子系统作为命令对象进行控制。(High Level API Command System)
命令对象由 AS_SendAudioCommand 向音频及其子系统发送。
被发送的命令对象为 AudioCommand
命令的详细记载于 命令对象

音频及其子系统,根据发送过来的命令进行处理并返回结果。
结果通过 AudioResult 对象返回,可由 AS_ReceiveAudioResult 获取。
结果的详细记载于 结果格式

这个是同步命令。发出命令后,直到返回结果后才能发出下一条命令。
通过 Audio Manager 使用顶层API时,将发送和接收过程编程为以一个命令为单位进行配对。
顶层API命令系统
图表 7. Audio顶层API命令系统
5.3.3.1.1. 控制数据格式(命令格式)

命令对象 AudioCommand 是以1 字(4 字节)的 AudioCommandHeader 开始,并随后根据需要添加尽可能多的参数区域的数据结构。
命令对象是以字单位为基础的,长度为1 字(32 比特、4字节)的整数倍。
命令对象的reserved 区域请设为0 。 命令对象 AudioCommand 是一种数据结构,以 AudioCommandHeader 的一个字(4个字节)开头,然后根据需要添加尽可能多的参数区域。

typedef struct
{
  AudioCommandHeader header;
  union
  {
    Command Parameters (Payload)
    ...
    ...
  };
} AudioCommand;
命令头部

由于命令对象基于字单元,因此它由一个字的整数倍(32位,4字节)组成。这个单词称为命令头( AudioCommandHeader )。

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

表示包含命令头的命令对象长度。
所有的命令对象由整数个字(4字节)构成,
packet_length指定的值为命令包的字长,即命令对象的字节长的1/4。

command_code

命令专用代码。不使用0x00。
命令的类别,请参考 命令一览

sub_code

各命令中用于识别设定及控制对象的代码。

5.3.3.1.2. 通知的数据格式(结果格式)

结果对象由1个字(4字节)的 AudioResultHeader 开始,后跟所需的参数区域。
结果对象是以字单位为基础的,长度为1字(32 比特、4字节)的整数倍。
忽略结果对象中的保留字段。

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指定的值为结果数据包的字长,即结果数据包字节大小的1/4。

result_code

结果数据包种类识别用代码。
结果数据包种类,请参考 结果一览 。 不同的代码,参数区域中的数据内容会变化。

sub_code

里面是和执行命令的sub_code相同的值。

5.3.3.2. 状态迁移

顶层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状态

这是一种状态,可实现压缩从麦克风输入的语音数据并将其写入SD卡等存储设备,或在WiFi / LTE等网络上启动并记录该功能的状态。 状态由RecorderReady状态和RecorderActive状态这两种子状态构成。 RecorderReady是声音记录停止的状态。通过 AUDCMD_STARTREC 迁移到RecorderActive状态,开始声音记录。 RecorderActive状态为声音记录中的状态。通过 AUDCMD_STOPREC 迁移到RecorderReady状态,停止声音记录。

通过 AUDCMD_SETREADYSTATUS 命令,只能迁移到Ready状态。

  • Baseband状态

这种状态实现了内部处理从Mic输入的音频数据并将其输出到AnalogOut或I2S的功能。 状态有BasebandReady状态和BasebandActive状态两个子状态。 BasebandReady状态为声音输出入停止的状态。通过 AUDCMD_STARTBB 迁移到BasebandActive开始声音的输出入动作。 RecorderActive状态为声音输出入时的状态。通过 AUDCMD_STOPBB 迁移到BasebandReady停止声音的输出入动作。

通过 AUDCMD_SETREADYSTATUS 命令,只能迁移到Ready状态。

NOTE:现在的固件未对应Baseband状态。

5.3.3.3. 命令概览

各命令的概览如下。
命令头部 中指定命令ID发送可以使用相关功能。

5.3.3.3.1. 普通或常用命令

任何状态通用的命令。 任何状态都可调用。

表格 3. 普通或常用命令列表
命令名 命令编号 响应结果 描述

GetStatus

0x01

通知状态

取得现在的状态。

详细信息,请参考如下Doxygen文件。

5.3.3.3.2. Baseband 初始化命令

进行Baseband HW初始化的命令。 仅可由Ready状态调用。

表格 4. Baseband 初始化命令表
命令名 命令编号 响应结果 描述

InitMicGain

0x53

InitMicGainCmplt

麦克风增益的设定

InitI2SParam

0x54

InitI2SCmplt

I2S的设定

InitOutputSelect

0x56

InitOutputSelectCmplt

发声器件的设定

InitClearStereo

0x58

InitClearStereoCmplt

清除立体声功能的设定

initRenderClk

0x5c

SetRenderingClkCmplt

HiReso设定的切换

详细请参考如下Doxygen文件。

5.3.3.3.3. Baseband 设置命令

进来Baseband HW设定的命令。 PowerOff以外的状态可以调用。

表格 5. Baseband 设置命令表
命令名 命令编号 响应结果 描述

SetVolume

0x59

SetVolumeCmplt

发声时的音量设定

SetVolumeMute

0x5a

SetVolumeMuteCmplt

发声音量的Mute设定

SetBeep

0x5b

SetBeepCmplt

BEEP音的设定

详细结果,请参考如下Doxygen文件。

5.3.3.3.4. 播放命令

Player的控制命令。 Player状态可以调用。

表格 6. 播放命令表
命令名 命令编号 响应结果 描述

InitPlayer

0x21

InitPlayCmplt

Player播放信息的设定

StartPlayer

0x22

PlayCmplt

从缓存开头解码

StopPlayer

0x23

StopPlayCmplt

不依赖缓存状态,停止Player

ClkRecovery

0x24

ClkRecoveryComplete

发声时间的微调

SetDecoderGain

0x25

SetDecoderGainComplete

L/R分别对发声进行Gain

详细信息,请参考如下Doxygen文件。

5.3.3.3.5. 录制命令

Recorder的控制命令。 Recorder状态可以调用。

表格 7. 录制命令表
命令名 命令编号 响应结果 描述

InitRecorder

0x31

InitRecCmplt

初始化录音功能

StartRecorder

0x32

RecCmplt

开始录音

StopRecorder

0x33

StopRecCmplt

停止录音

详细信息,请参考如下Doxygen文件。

5.3.3.3.6. 状态切换命令
表格 8. 状态切换命令表
命令名 命令编号 响应结果 描述

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文件。

5.3.3.4. 结果概览

音频子系统的结果返回通知。
结果头部 中保存结果ID的方式返回。

5.3.3.4.1. 普通或常用命令
表格 9. 普通或常用命令表
结果名 命令编号 触发命令 描述

NotifyStatus

0x01

GetStatus

通知目前的状态。

5.3.3.4.2. Baseband 初始化结果
表格 10. Baseband 初始化结果列表
结果名 命令编号 触发命令 描述

InitMicGainCmplt

0x53

InitMicGain

通知麦克风增益的设定完成。

InitI2SCmplt

0x54

InitI2SParam

通知I2S的设定完成。

InitOutputSelectCmplt

0x56

InitOutputSelect

通知发声设定的设定完成。

InitClearStereoCmplt

0x58

InitClearStereo

通知清除立体声功能的设定完成。

SetRenderingClkCmplt

0x5c

InitRenderClk

通知HiReso设定的切换完成。

5.3.3.4.3. Baseband 结果设置
表格 11. Baseband 结果设置表
结果名 命令编号 触发命令 描述

SetVolumeCmplt

0x59

SetVolume

通知发声时的音量设定完成。発

SetVolumeMuteCmplt

0x5a

SetVolumeMute

通知发声音量的Mute设定完成。

SetBeepCmplt

0x5b

SetBeep

通知BEEP音的设定完成。

5.3.3.4.4. 播放结果
表格 12. 播放结果表
结果名 命令编号 触发命令 描述

InitPlayCmplt

0x21

InitPlayer

通知Player的播放信息设定完成。

PlayCmplt

0x22

StartPlayer

通知Player已经开始工作。

StopPlayCmplt

0x23

StopPlayer

通知Player已经停止工作。

ClkRecoveryComplete

0x24

ClkRecovery

通知发声时间的微调设定完成。

SetDecoderGainComplete

0x25

SetDecoderGain

通知发声L/R的Gain设定完成。

5.3.3.4.5. 录制结果
表格 13. 录制结果表
结果名 命令编号 触发命令 描述

InitRecCmplt

0x31

nitRecorder

通知录音功能的初始化完成。

RecCmplt

0x32

StartRecorder

通知录音已经开始。

StopRecCmplt

0x33

StopRecorder

通知录音已经结束。

5.3.3.4.6. 状态转换结果
表格 14. 状态转换结果表
结果名 命令编号 触发命令 描述

StatusChanged

0x71

PowerOn SetPowerOffStatus SetBaseBandStatus SetPlayerStatus SetRecorderStatus SetReadyStartus

通知状态迁移已经完成。

5.3.3.4.7. 错误通知
表格 15. 错误通知表
结果名 命令编号 触发命令 描述

ErrorResponse

0xf1

通知有发生错误。

ErrorAttention

0xf2

通知有发生内部处理错误。

5.3.3.5. 命令包详细
5.3.3.5.1. GetStatus

获取AudioSubSystem内的状态。

  • Header

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

无。

5.3.3.5.2. InitMicGain

设定麦克风的输入增益。
可以对各个麦克风的增益分别设定。

  • Header

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

5.3.3.5.3. InitI2SParam

I2S的输出入相关设定。

  • Header

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

5.3.3.5.4. InitOutputSelect

输出端的设定。

  • Header

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

5.3.3.5.5. 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

5.3.3.5.6. initRenderClk

进行HiReso模式的设定。

  • Header

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

5.3.3.5.7. SetVolume
  • Header

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

5.3.3.5.8. SetVolumeMute
  • Header

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

5.3.3.5.9. SetBeep
  • Header

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

5.3.3.5.10. InitPlayer
  • Header

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

5.3.3.5.11. StartPlayer
  • Header

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

5.3.3.5.12. StopPlayer
  • Header

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

5.3.3.5.13. ClkRecovery
  • Header

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

5.3.3.5.14. SetDecoderGain
  • Header

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

5.3.3.5.15. InitRecorder
  • Header

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

5.3.3.5.16. StartRecorder
  • Header

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

无。

5.3.3.5.17. StopRecorder
  • Header

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

无。

5.3.3.5.18. PowerOn
  • Header

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

5.3.3.5.19. SetPowerOffStatus
  • Header

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

无。

5.3.3.5.20. SetBaseBandStatus
  • Header

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

5.3.3.5.21. SetPlayerStatus
  • Header

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

5.3.3.5.22. SetRecorderStatus
  • Header

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

5.3.3.5.23. SetReadyStartus
  • Header

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

无。

5.3.3.5.24. SetThroughStatus
  • Header

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

无。

5.3.3.6. 结果包详细
5.3.3.6.1. 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

包含目前的状态。

5.3.3.6.2. InitMicGainCmplt

InitMicGain 发行后响应。。

  • Header

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

无。

5.3.3.6.3. InitI2SCmplt
  • Header

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

无。

5.3.3.6.4. InitOutputSelectCmplt
  • Header

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

无。

5.3.3.6.5. InitClearStereoCmplt
  • Header

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

无。

5.3.3.6.6. SetRenderingClkCmplt
  • Header

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

无。

5.3.3.6.7. SetVolumeCmplt
  • Header

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

无。

5.3.3.6.8. SetVolumeMuteCmplt
  • Header

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

无。

5.3.3.6.9. SetBeepCmplt
  • Header

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

无。

5.3.3.6.10. InitPlayCmplt
  • Header

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

无。

5.3.3.6.11. PlayCmplt
  • Header

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

无。

5.3.3.6.12. StopPlayCmplt
  • Header

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

无。

5.3.3.6.13. ClkRecoveryComplete
  • Header

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

无。

5.3.3.6.14. SetDecoderGainComplete
  • Header

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

无。

5.3.3.6.15. InitRecCmplt
  • Header

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

无。

5.3.3.6.16. RecCmplt
  • Header

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

无。

5.3.3.6.17. StopRecCmplt
  • Header

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

无。

5.3.3.6.18. 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

包含迁移后的状态。

5.3.3.6.19. 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[]

目前未使用。

5.3.3.6.20. ErrorAttention

内部处理发生错误时被通知。

  • 头部

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

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

错误发生的行被通知。

error_filename

错误发生的文件名(最大32byte)被通知。

5.3.3.7. 存储管理和任务间同步相关
5.3.3.7.1. 管理内存库

AudioSubSystem通过特殊的方法管理使用的数据区域。 MemoryUtility的MemoryManager库,根据Memory Layout定义文件的Layout信息,以固定长度的存储池的方式确保必须的存储区域。 此Layout信息可重复定义,通过切换Layout号的指定,可以确保各功能的必须存储。 Layout信息,可根据Application需求自由指定,但需注意各功能所需的最低限资源。

详细信息,请参考 内存管理 库说明。

另外,各功能合计所需的Layout相关,请参考各example的说明。

AudioSubSystem内的各对象,通过生成指向所需存储空间的MemHandle实例,确保并使用链接到实例的存储片段。

Get memHandle

传递此MemHandle的实例给数据管道的下一个对象,下一个对象也可使用确保的存储区域。不需要时,废弃此实例就看释放存储空间。

实例可拷贝,所需对象可各自确保自己的间实例。不要时根据自己的需要废弃,也可以安全地确保/释放存储空间。

Copy memHandle

片段的使用不需要时,非同步的对象不需要在意存储管理,通过废弃实例,默认引用终止。

Use memHandle

如此,非同步对象间的存储管理变得简单。 所有的引用终止后,存储空间会被释放。

Release memHandle

Layout信息作为Application使用的头文件群,需要预先准备。 这些头文件,通过作成Memory Layout定义文件(mem_layout.conf),使用工具生成。

  使 python3 mem_layout.conf layout_header fence_header pool_header
各参数的说明如下。
mem_layout.conf

Memory Layout定义文件

layout_header

作为C语言的宏输出的各常数的头文件

fence_header

输出FixedArea的存储栏地址的头文件

pool_header

输出PoolArea的各定义的头文件

5.3.3.7.2. 消息库

使用此存储管理机制时,各任务间需要任务对象的收发信。因此,AudioSubSystem使用在任务同步机制中准备的可以在任务实例间进行收发信的message库。

各任务对象通过追加收信端的ID,可以往指定的任务送信。

举例来说,对象送信时发送收信端的ID,收信端的任务仅在自己的ID发生送信要求时才收信。 发生收信前,此任务sleep并等待。

如此,AudioSubSystem以事件驱动进行对象设计。

Message相关,需要事先准备Message使用的头文件群。 这些头文件,通过作成MessageQueueLayout定义文件(msgq_layout.conf),使用工具生成。

  使 python3 msgq_layout.conf area_address area_size id_header pool_header
各参数说明如下。
msgq_layout.conf

Message Layout定义文件

area_address

Message区域的地址

area_size

Message区域的尺寸

id_header

输出MessageQueueID宏的文件

pool_header

输出MessageQueuePool定义的文件

详细请参考消息库 库说明。

5.3.3.7.3. 简化 FIFO 库

AudioSubSystem和用户应用程序间的音频数据的传递,使用Simple FIFO。此FIFO是简化的FIFO,无需特别介绍。

详细请参考 简化 FIFO 库 的库说明。

5.3.3.8. 各功能详细
5.3.3.9. Audio Player 功能

Audio Player 的简单的数据流如下所示。

Audio Player Dataflow
图表 8. Audio Player 数据流

音频及其子系统运行PlayerMode时,User Application往FIFO里输入ES数据。 累积了一定量的数据后,Player启动,根据发声时间,消耗这个ES数据。这个FIFO不发生下溢出时,音频数据不会断续。

Player可以生成2个实例。 2个实例分别可以对解码的音频,通过OutputMixer,Mixing后发声。

数据流内部,通过Message通信。 Message通信,每个客户端持有ID。 Audio Player的场合,根据example中的示例Layout,显示ID如下。

User Application                        : MSGQ_AUD_APP
Audio Manager                           : MSGQ_AUD_MNG
Audio Player0                           : MSGQ_AUD_PLY0
Audio Player1                           : MSGQ_AUD_PLY1           # Set this value when you use player1, in other case, set 0xff.
Output Mixer                            : MSGQ_AUD_OUTPUT_MIX
Audio DSP                               : MSGQ_AUD_DSP
Rendering Component(Audio Player0)      : MSGQ_AUD_RND_PLY0
Rendering Component(Audio Player1)      : MSGQ_AUD_RND_PLY1       # Set this value when you use player1, in other case, set 0xff.
Rendering Component Sync(Audio Player0) : MSGQ_AUD_RND_PLY0_SYNC
Rendering Component Sync(Audio Player1) : MSGQ_AUD_RND_PLY1_SYNC  # Set this value when you use player1, in other case, set 0xff.
Post Filter (Channel0)                  : MSGQ_AUD_PFDSP0
Post Filter (Channel1)                  : MSGQ_AUD_PFDSP1
将来MSGQ_AUD_RND_PLY0/PLY1_SYNC可能会被删除,变为API。
Audio Player Message ID
图表 9. Audio Player Message ID

另外,各数据的数据区域如下。

ES Data (Audio Player0)                           : S0_DEC_ES_MAIN_BUF_POOL
ES Data (Audio Player1)                           : S0_DEC_ES_SUB_BUF_POOL    # Set this value when you use player1, in other case, set S0_NULL_POOL.
PCM Data (Audio Player0)                          : S0_REND_PCM_BUF_POOL
PCM Data (Audio Player1)                          : S0_REND_PCM_SUB_BUF_POOL  # Set this value when you use player1, in other case, set S0_NULL_POOL.
Audio Decoder DSP Command                         : S0_DEC_APU_CMD_POOL
SamplingRateConverter Work Buffer (Audio Player0) : S0_SRC_WORK_BUF_POOL
SamplingRateConverter Work Buffer (Audio Player1) : S0_SRC_WORK_SUB_BUF_POOL  # Set this value when you use player1, in other case, set S0_NULL_POOL.
Post Filter PCM Data (Channel0)                   : S0_PF0_PCM_BUF_POOL
Post Filter PCM Data (Channel1)                   : S0_PF1_PCM_BUF_POOL
Post Filter DSP Command (Channel0)                : S0_PF0_APU_CMD_POOL
Post Filter DSP Command (Channel1)                : S0_PF1_APU_CMD_POOL
Audio Player Pool ID
图表 10. Audio Player Pool ID

这些ID需要在生成时指定。

5.3.3.9.1. 使用方法
准备

通过"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_PLY0;
ids.player_sub  = MSGQ_AUD_PLY1;
ids.mixer       = MSGQ_AUD_OUTPUT_MIX;
ids.recorder    = 0xFF;
ids.effector    = 0xFF;
ids.recognizer  = 0xFF;

AS_CreateAudioManager(ids, attention_callback);
创建MediaPlayerObject

为了使 MediaPlayerObject 有效,需要调用 AS_CreatePlayerMulti(AsPlayerId, AsCreatePlayerParams_t, AudioAttentionCb)
AsPlayerId 指定为2个既存Player (AsPlayerIdAS_PLAYER_ID_0, AS_PLAYER_ID_1) 中的一个。使用这2个Player时,请分别Create。
AsCreatePlayerParams_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)
{
  ...
}

AsCreatePlayerParams_t cparam;

cparam.msgq_id.player = MSGQ_AUD_PLY0;
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     = S0_DEC_ES_MAIN_BUF_POOL;
cparam.pool_id.pcm    = S0_REND_PCM_BUF_POOL;
cparam.pool_id.dsp    = S0_DEC_APU_CMD_POOL;
cparam.pool_id.src_work = S0_SRC_WORK_BUF_POOL;

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

cparam.msgq_id.player = MSGQ_AUD_PLY1;
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     = S0_DEC_ES_SUB_BUF_POOL;
cparam.pool_id.pcm    = S0_REND_PCM_SUB_BUF_POOL;
cparam.pool_id.dsp    = S0_DEC_APU_CMD_POOL;
cparam.pool_id.src_work = S0_SRC_WORK_SUB_BUF_POOL;

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

为了使 OutputMixerObject 有效,需要调用 AS_CreateOutputMixer(AsCreateOutputMixParams_t)
AsCreateOutputMixParams_t 中,需要指定由 AMessage Library Configuration 定义的 MsgQueID 和由 Memory Manager Configuration 定义的 PoolId 。
AudioAttentionCb 为异步通知,需要设定回调函数。不使用AudioManager时设定。使用AS_CreateAudioManager登录回调函数的场合,指定为NULL时不发生通知。

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

AsCreateOutputMixParams_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 = S0_PF0_PCM_BUF_POOL;
cparam.pool_id.render_path1_filter_pcm = S0_PF1_PCM_BUF_POOL;
cparam.pool_id.render_path0_filter_dsp = S0_PF0_APU_CMD_POOL;
cparam.pool_id.render_path1_filter_dsp = S0_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。
如果应用程序仅使用1个Player时,第3第4个参数(dev1_req, dev1_sync)需要设定为0xFF。

AsCreateRendererParam_t renderer_act_param;
cparam.msgq_id.dev0_req  = MSGQ_AUD_RND_PLY0;
cparam.msgq_id.dev0_sync = MSGQ_AUD_RND_PLY0_SYNC;
cparam.msgq_id.dev1_req  = MSGQ_AUD_RND_PLY1;
cparam.msgq_id.dev1_sync = MSGQ_AUD_RND_PLY1_SYNC;

result = AS_CreateRenderer(&renderer_act_param);
将来,High Level API的生成函数有可能统合到AudioManager的生成函数里。
初始化及状态变化

必要的对象生成后,为了使Player工作,进行Audio的HW设定,电源On,工作模式变更等初始化处理。

可以按顺序发行以下命令来实现。

Audio SubSystem 上电

为了给Audio功能块上电,通过发行 AUDCMD_POWERONPowerOnParam 命令,上电并迁移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);
初始化输出设备

执行PowerOn并迁移到Ready状态后,通过 AUDCMD_INITOUTPUTSELECTInitOutputSelectParam 命令选择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来实现。
设置扬声器驱动模式

驱动扬声器的数字放大器的驱动能力,可以通过 AUDCMD_SETSPDRVMODESetSpDrvModeParam 命令来设定。

表示驱动能力的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);
变换到播放状态

通过 AUDCMD_SETPLAYERSTATUSSetPlayerStsParam 命令迁移AudioSubSystem的状态至Player状态。

各参数设定如下。

active_player
  AS_ACTPLAYER_MAIN : 仅player0播放
  AS_ACTPLAYER_SUB  : 仅player1播放
  AS_ACTPLAYER_BOTH : player0和player1Mix后播放
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读取时都会通知。

命令设定示例

如下,Player0, Player1同时播放的设定示例。 Player0, Player1各自使用自己的SimpleFIFO输入数据的设定。

  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, AsCreatePlayerParams_t, AudioAttentionCb) 置_AS_PLAYER_ID_1_ 为有效。
Set volume

输出设定为扬声器时,可以用 AUDCMD_SETVOLUMESetVolumeParam 设定音量。 各参数设定如下。

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。

命令设定示例

如下,设定Player0为0dB,Player1为0dB,Master音量为-20dB的示例。

  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 e2eb67f141f989814817e686cbf83d2e
图表 11. Initial sequence
初始化和启动播放器

表示音乐播放的初始化及开始顺序。  

初始化播放器

通过AUDCMD_INITPLAYERPlayerCommandAsInitPlayerParam 进行播放的初始化设定。

player_id

AsPlayerId的实例的ID设定。有2个实例,请设定为其中1个。

实例编号 设定值

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 的场合,由于DPS使用DualCore,Working区域也需要更大, 打算进行Dual Decode时,仅DSP区域就需要384kB。请根据需要,通过改变SDK的Configuration确保DSP区域。
dsp_path

指定保存Decoder的DSP二进制映像文件的绝对路径。最大24字符。

命令设定示例

如下,设定由Player0播放mp3/16bit/Stereo/48kHz的内容的初始化示例。 另外,播放使用的解码器配置路径指定为SD卡的BIN目录。

  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);
启动播放

通过 AUDCMD_PLAYPLAYER, PlayerCommand 开始播放。 音乐播放开始后,即开始从FIFO读出压缩音频数据。
因此,音乐播放开始前,请在FIFO中存入足够的压缩音频数据。

开始时,如果FIFO中没有存入足够的数据,开始后就会发生Underflow,音频播放会被停止。
player_id

设定 AsPlayerId 的实例的ID。请设定由 AUDCMD_INITPLAYER 初始设定完成的 实例ID。

实例编号 设定值

0

AS_PLAYER_ID_0

1

AS_PLAYER_ID_1

命令设定示例

如下,由Player0开始播放的设定示例。

  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 05054694fe75344e389f0bf22e1d6b52
图表 12. 播放状态切换序列
停止播放

描述音频播放停止的顺序。

关闭播放器
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

命令设定示例

如下为Player0一般停止的设定示例。

  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 5ee87f4cb8c449f2e533e3e88579c0b0
图表 13. 停止过程
5.3.3.9.2. 编译配置

为了使用 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
5.3.3.9.3. 注意事项及方法

音乐播放时的警告一览和对应方法如下。详细请参考 关于音频子系统错误

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。否则会产生噪音。
5.3.3.9.4. DSP 安装
DSP binary image install

请将DSP二进制映像放入Kconfig设定的路径下。二进制映像在 sdk/modules/audio/dsp 里。

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

MP3DEC

61kbyte

WAVDEC

32kbyte

进行高分辨率的采样率播放时,DSP请使用 2 Core(1Core使用192kB)。
※2Core的话,384kB。
请注意资源使用。

5.3.3.9.5. Audio Player 示例

Audio Player example是音乐播放的简单的示例程序。在此说明用法。

准备
编译配置(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)。

配置消息库

需要定义使用AudioPlayer功能时必须的MessageQueue。 定义通过MessageQueueLayout定义文件,可以使用工具生成包含代码的头文件。

Audio Player 的example中如下进行。

cd examples/audio_player/config
python3 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,     30,    0,      0],
  ["MSGQ_AUD_APP",            64,      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_PLY0",           48,      5,    0,      0],
  ["MSGQ_AUD_PLY1",           48,      5,    0,      0],
  ["MSGQ_AUD_OUTPUT_MIX",     48,      8,    0,      0],
  ["MSGQ_AUD_RND_PLY0",       32,     16,    0,      0],
  ["MSGQ_AUD_RND_PLY0_SYNC",  16,      8,    0,      0],
  ["MSGQ_AUD_RND_PLY1",       32,     16,    0,      0],
  ["MSGQ_AUD_RND_PLY1_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
python3 mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定义文件(mem_layout.conf)的内容如下。

固定区域说明
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()确保的共享存储的大小。

请勿变更FixedAreas。
动态区域
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
设定变更后,请使用工具生成新的头文件。
表格 17. 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 及声音文件
Music file

请在SD卡的根目录下作成 "AUDIO/" 目录, 拷贝音乐文件到此。

Playlist

管理需要播放的音乐文件。由 csv 文件生成数据可。文件名为 "TRACK_DB.CSV" 。

在SD卡根目录下作成 "PLAYLIST/" 目录, 拷贝 "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为前提。仅播放列表的第一行。
Using SPI-Flash instead of SD Card

文件系统要用SPI-Flash的话,请将example的播放文件,Playlist,DSP二进制映像的指定路径改为"/mnt/spif/*"。 然后,拷贝播放文件,Playlist,DSP二进制映像到此路径下。

执行方法

由 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
5.3.3.10. Audio Recorder 功能

Audio Recorder的简单数据流如下所示。

Audio Recorder 数据流
图表 14. Audio Recorder数据流

当音频子系统在RecorderMode下运行时,用户应用程序将 必须准备一个FIFO来存储ES数据。 当开始记录音频数据时,在操作一定时间后,音频数据将累积在此FIFO中。该音频数据以指定的压缩格式编码, 可以通过从FIFO中适当地读取音频数据并且不使FIFO溢出来获取连续音频数据。

记录器可以捕获两行作为硬件,但目前不支持生成两个实例并记录两行的功能。

用户应用程序通过根据每个系统的要求处理此音频(例如,将其写入Strage并进行记录,将其发送到Connectivity模块进行云处理等)来实现Recorder应用程序。

数据流内部与Message通信。 消息通信具有每个客户端的ID。 对于Audio Recorder,根据示例示例中的布局,下面显示了ID。

User Application           : MSGQ_AUD_APP
Audio Manager              : MSGQ_AUD_MNG
Audio Frontend             : MSGQ_AUD_FRONTEND
Audio Recorder             : MSGQ_AUD_RECORDER
Audio Capture Component    : MSGQ_AUD_CAP
Audio DSP                  : MSGQ_AUD_DSP

※MSGQ_AUD_CAP_SYNC将被删除。

Audio Recorder 消息编号
图表 15. Audio Recorder Message ID

每个数据的数据区域如下。

PCM (输入) 数据缓存      : 数据缓存
ES Data Buffer (for DSP)   : ES_BUF_POOL
PreProcess DSP Command     : PRE_APU_CMD_POOL
Audio Encoder DSP Command  : ENC_APU_CMD_POOL
Audio Recorder 池塘编号
图表 16. Audio Recorder Pool ID

这些ID必须在生成时指定。

5.3.3.10.1. 使用方法
准备

“AudioManager”,“MicFrontendObject”,“MediaRecorderObject”,被设计来控制音频子系统称为“CaptureComponent”,实现了录音机的软件组件。

创建AudioManager

要启用AudioManager,您需要调用 AS_CreateAudioManager(AudioSubSystemIDs) 。 必须在 AudioSubSystemIDs 中指定在“消息库配置”中定义的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 = 0xFF;
ids.player_sub  = 0xFF;
ids.micfrontend = MSGQ_AUD_FRONTEND
ids.mixer       = 0xFF;
ids.recorder    = MSGQ_AUD_RECORDER;
ids.effector    = 0xFF;
ids.recognizer  = 0xFF;

AS_CreateAudioManager(ids, attention_callback);
创建 MicFrontendObject

要启用MicFrontendObject,您需要调用 AS_CreateMicFrontend(AsCreateMicFrontendParams_t 。 必须指定在消息库配置中定义的MsgQueID和在内存管理器配置中定义的PoolId。MsgQueID的Dsp,PoolId的输出和dspcmd是 Preprocess仅 有效。否则,您可以指定NULL_POOL。
AudioAttentionCb 指定用于异步通知的回调函数。请在不使用AudioManager时指定。如果回调函数已在AS_CreateAudioManager中注册,则如果指定NULL,则不会发出通知。

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

AsCreateMicFrontendParams_t cparam;

cparam.msgq_id.micfrontend = MSGQ_AUD_FRONTEND;
cparam.msgq_id.mng         = MSGQ_AUD_MNG;
cparam.msgq_id.dsp         = MSGQ_AUD_PREDSP;
cparam.pool_id.capin       = S0_INPUT_BUF_POOL;
cparam.pool_id.output      = S0_PREPROC_BUF_POOL; /* When preprocess will not work, can be set to NULL_POOL */
cparam.pool_id.dspcmd      = S0_PRE_APU_CMD_POOL; /* When preprocess will not work, can be set to NULL_POOL */

result = AS_CreateMicFrontend(&cparam, attention_callback_from_frontend);
创建 MediaRecorderObject

要启用MediaRecorderObject,您需要调用 AS_CreateMediaRecorder(AsCreateRecorderParams_t) 。 必须指定在消息库配置中定义的MsgQueID和在内存管理器配置中定义的PoolId。
AudioAttentionCb 指定用于执行异步通知的回调函数。 请在不使用AudioManager时指定。如果回调函数已在AS_CreateAudioManager中注册,则如果指定NULL,则不会发出通知。

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

AsCreateRecorderParams_t cparam;

cparam.msgq_id.recorder      = MSGQ_AUD_RECORDER;
cparam.msgq_id.mng           = MSGQ_AUD_MNG;
cparam.msgq_id.dsp           = MSGQ_AUD_DSP;
cparam.pool_id.input         = S0_INPUT_BUF_POOL;
cparam.pool_id.output        = S0_ES_BUF_POOL;
cparam.pool_id.dsp           = S0_ENC_APU_CMD_POOL;

result = AS_CreateMediaRecorder(&cparam, attention_callback_from_recorder);
激活 CaptureComponent

启用CaptureComponent,您需要调用 AS_CreateCapture(AsActCaptureParam_t) 。 必须指定在消息库配置中定义的MsgQueID和在内存管理器配置中定义的PoolId。 如果您的应用程序不使用第二个通道,则必须将第三个和第四个参数设置为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);
初始化及改变状态

生成必要的对象后,将执行诸如音频硬件设置,开机和操作模式更改之类的初始化处理,以执行记录器操作。

这可以通过按顺序发出以下命令来实现。

音频子系统上电

要打开音频模块,请发出 AUDCMD_POWERONPowerOnParam 命令以打开电源,并将AudioSubSystem状态更改为Ready状态。

enable_sound_effect

enable_sound_effect固定为AS_DISABLE_SOUNDEFFECT。

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);
初始化麦克风增益

AUDCMD_INITMICGAIN 设置麦克风增益。

init_mic_gain_param[]

对于模拟麦克风,可以将dB值乘以10得到的值可以在0(0.0dB)到210(21.0dB)的范围内设置,以5的倍数表示。 默认值为0.0dB。 对于数字麦克风,可以在-7850(-78.50dB)到0(0.00dB)的范围内设置将dB值乘以100得到的值。默认值为-78.50dB。
如果不想更改增益值,请指定 AS_MICGAIN_HOLD

命令设置示例

以下是将21 dB的增益应用于1ch至4ch输入的设置示例。 5ch到8ch的原因是设置不变。

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通道选择图”的值设置。 默认设置为模拟麦克风1/2/3/4。

配置信息如下所述。

MIC频道选择图设置
[CXD56xx Configuration]
  [Audio]
    [Audio baseband config settings]
      [CXD5247 settings]
        (0xFFFF4321) MIC channel select map

“MIC channel select map”的值每4位指示MIC ID。
mic_gain元素与“MIC channel select map”的位字段之间的关系如下。

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

位域

31-28

27-24

23-20

19-16

15-12

11-8

7-4

3-0

“MIC channel slect 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开始按顺序设置要使用的麦克风。不能通过跳过来设置元素编号。 不支持模拟和数字麦克风的混合。 设置模拟麦克风时设置元素0-3。 如果元素为偶数,则选择L通道;如果元素为奇数,则选择R通道。

进入录音状态

使用 AUDCMD_SETRECORDERSTATUS 将AudioSubSystem状态更改为Recorder状态。

输入设备

指定要记录的输入设备。必须将设置的麦克风类型与 AUDCMD_INITMICGAIN

AS_SETRECDR_STS_INPUTDEVICE_MIC_A  : CXD5247模拟麦克风
AS_SETRECDR_STS_INPUTDEVICE_MIC_D  : CXD5247数字麦克风
输入设备句柄

目前固定为0。

输出设备

指定编码的ES数据的输出设备。
当前仅支持RAM设备输出。

AS_SETRECDR_STS_OUTPUTDEVICE_RAM : 输出到RAM设备
输出设备句柄

指定用于存储输出(编码的ES数据)的SimpleFIFO的处理程序。
simple_fifo_handler由CMN_SimpleFifoInitialize ()获得。

命令设置示例

以下是录制麦克风输入到SimpleFIFO的设置示例。

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);
开始录音

表示录音开始的顺序。

初始化麦克风前端

使用 AUDCMD_INIT_MICFRONTENDMicFrontendCommandAsInitMicFrontEnd 来设置前端操作(例如音频捕获)。

ch_num
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
samples
/* 指定每帧的样本数。 */
out_fs

指定从MicFrontend输出的音频的采样率。
仅在 preproc_typeAsMicFrontendPreProcSrc 时有效。

AS_SAMPLINGRATE_8000  : 8kHz
AS_SAMPLINGRATE_16000 : 16kHz
AS_SAMPLINGRATE_44100 : 44.1kHz
AS_SAMPLINGRATE_48000 : 48kHz
...
...
AS_SAMPLINGRATE_192000 : 192kHz
preproc_type

设置预处理类型。

AsMicFrontendPreProcThrough       : Through
AsMicFrontendPreProcSrc           : Sampling Rate Converter
AsMicFrontendPreProcUserCustom    : User Custom Process
如果您指定 AsMicFrontendPreProcSrc ,则需要在 sdk /modules/audio/DSP/ 中使用 SRC
preprocess_dsp_path

使用完整路径(包括文件名)为预处理指定DSP二进制文件。
当preproc_type为AsMicFrontendPreProcThrough时不使用。

"/mnt/sd0/BIN/PREPROC" : 将名为PREPROC的二进制文件放入SD卡的BIN文件夹中时
"/mnt/spif/SRC"        : 当直接在SPI-FLASH下放置一个称为SRC的二进制文件时
data_dest

从MicFrontendObject指定音频数据的输出目的地。

AsMicFrontendDataToRecorder   : 
AsMicFrontendDataToRecognizer : 

下图显示了在音频识别器功能中使用PreprocessDSP处理信号的位置。

在突出显示的区域中使用Customproc和UserCustomDSP执行信号处理。
用户创建信号处理并将其合并到此UserCustomDSP中。

Audio recorder preprocess
图表 17. Audio Recognizer Preprocess
命令设置示例

以下是以每帧Mono/16bit/768sample per frame捕获音频时的设置示例。
预处理由UserCustom的DSP执行,DSP的二进制文件位于SD卡的BIN文件夹中。
捕获的音频被设置为用于录音机。

AudioCommand command;
command.header.packet_length = LENGTH_INIT_MICFRONTEND;
command.header.command_code  = AUDCMD_INIT_MICFRONTEND;
command.header.sub_code      = 0x00;
command.init_micfrontend_param.ch_num       = AS_CHANNEL_MONO
command.init_micfrontend_param.bit_length   = AS_BITLENGTH_16;
command.init_micfrontend_param.sample       = 768; /* 根据编解码器设置此值。 */
command.init_micfrontend_param.outfs        = AS_SAMPLINGRATE_16000;
command.init_micfrontend_param.preproc_type = AsMicFrontendPreProcUserCustom;
snprintf(command.init_micfrontend_param.preprocess_dsp_path,
         AS_RECOGNIZER_FILE_PATH_LEN,
         "%s", "/mnt/sd0/BIN/PREPROC");
command.init_micfrontend_param.data_dest = AsMicFrontendDataToRecorder;
初始化预处理 DSP

使用AUDCMD_INIT_PREPROCESS_DSPAsInitRecorderParam 初始化DSP以进行预处理。 为ereProcess指定DSP二进制文件,其完整路径包括文件名。 AsMicFrontendPreProcThrough时不使用type。 当preproc_type为AsMicFrontendPreProcThrough时不使用。 当preproc_type为AsMicFrontendPreProcThrough时不使用。

如果在 AUDCMD_INIT_MICFRONTEND 中将 preproc_type 设置为 AsMicFrontendPreProcThrough ,则无需执行此步骤。
packet_addr

初始化命令包的地址。命令格式取决于DSP的预处理。
在此API响应之前,必须保留设置的地址区域。

packet_size

初始化命令包的大小。

命令设置示例

以下是将s_initparam数据作为DSP初始化命令发送的示例。

static uint8_t s_initparam = 0;

AudioCommand command;
command.header.packet_length = LENGTH_INIT_PREPROCESS_DSP;
command.header.command_code  = AUDCMD_INIT_PREPROCESS_DSP;
command.header.sub_code      = 0x00;
command.init_preproc_param.packet_addr = reinterpret_cast<uint8_t *>(&s_initparam);
command.init_preproc_param.packet_size = sizeof(s_initparam);
AS_SendAudioCommand(&command);
初始化录音器

使用 AUDCMD_INITRECRecorderCommanddoxygen: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 : LinearPCM
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

指定存储编码器或滤波器DSP映像的绝对路径。最多24个字符。

输入设备和通道数量的组合受到限制。
输入 通道数

Mic

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

  • (*1. 仅LPCM)

  • (*2. 仅在使用LPCM和DigitalMic时)

编解码器,位长,采样频率和位速率的组合受到限制。
编码名 位长 采样频率 比特率

MP3

16bit

16kHz

8000(*1), 16000 ~ 32000

48kHz

32000 ~ 2560000

LPCM

16bit

16kHz, 48kHz

-

24bit(*2)

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

-

  • (*1. 指定1ch时)

  • (*2. 需要高分辨率模式)

命令设置示例

以下是以16kHz/Mono/LPCM录制时的设置示例。 用于编码的DSP二进制文件放置在SD卡的BIN文件夹中。

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  = AS_SAMPLINGRATE_16000;
command.recorder.init_param.channel_number = AS_CHANNEL_MONO;
command.recorder.init_param.bit_length     = AS_BITLENGTH_16;
command.recorder.init_param.codec_type     = AS_CODECTYPE_LPCM;
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 cf49f33fa5ca6db7e508e7fc57cce311
图表 18. 记录初始化顺序
开始录音

开始用 AUDCMD_STARTREC 录音。

开始录制后不久,音频系统会将ES数据写入FIFO。 为了正确记录音频数据,必须在FIFO溢出之前读取写入的数据。
您将收到有关写入数据的通知,因此请根据此事件适当阅读。

如果FIFO已满,则音频系统无法写入并丢弃无法写入的音频数据。因此,直接记录会导致音频数据不连续。
命令设置示例
AudioCommand command;
command.header.packet_length = LENGTH_START_RECORDER;
command.header.command_code  = AUDCMD_STARTREC;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag 32a7123dc4b2f56ae58f932ee770d149
图表 19. 记录顺序
停止录音
Stop Recorder.

停止使用 AUDCMD_STOPREC 录音。 当接收到停止指令时,记录器会在编码点停止,直到捕获的音频数据为止。

命令设置示例
AudioCommand command;
command.header.packet_length = LENGTH_STOP_RECORDER;
command.header.command_code  = AUDCMD_STOPREC;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag b074920aba8aa65cd9098c358350c661
图表 20. 记录停止顺序
5.3.3.10.2. 编译配置

使用AudioRecorder功能

cd sdk/
tools/config.py -m

打开配置菜单并设置以下配置。

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
5.3.3.10.3. 注意事项及方法

以下是音频录制过程中的警告列表以及如何处理它们。有关详细信息,请参见 关于音频子系统错误

编号 事件代码 事件级别 Approach

0x06

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW

WARNING

这是因为AudioSubSystem无法将记录数据输出到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二进制版本不同。使用 "sdk/modules/audio/dsp” 文件更新DSP二进制映像。

5.3.3.10.4. 安装 DSP
DSP binary image install

将DSP二进制映像存储在Kconfig设置的路径中。 二进制映像位于 sdk /modules/audio/dsp 中。

表格 18. 根据配置,选择有关音频录制的二进制镜像文件
镜像 大小

MP3ENC

111kbyte

SRC(采样率转换器)

21kbyte

LPCM不需要压缩处理,但是需要频率转换处理,因此需要SRC(采样率转换器)DSP负载。
5.3.3.10.5. 音频录制示例

有一个简单的Recorder Example,您可以检查Recorder的操作。

准备
编译配置(kconfig)

要使用Audio Recorder示例程序,请进行以下设置。

加载audio_recorder配置。

cd sdk/
tools/config.py examples/audio_recorder

确保启用了录音机。

tools/config.py -m
(audio recorder:)
[Examples]
  [Audio recorder example] <= Y
无法同时选择音频和逻辑传感器示例以及其他示例。如果选择多个,将发生编译错误。
只支持以下格式

有关详细信息,请参考 开始录制

内存实用程序配置和布局
消息库配置

必须定义使用AudioRecorder函数时所需的MessageQueue。 该定义在MessageQueueLayout定义文件中完成,并且可以使用该工具生成要包含在代码中的头文件。

音频录制示例 中,执行以下操作。

cd examples/audio_recorder/config
python3 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_MGR",               88,     30,    0,      0],
  ["MSGQ_AUD_APP",               64,      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],
  ["MSGQ_AUD_FRONTEND",          48,     10,    0,      0],
  ["MSGQ_AUD_PREDSP",            20,      5,    0,      0],

每个参数的说明如下。

参数 说明

ID

用以“MSGQ”开头的字符串指定消息队列ID的名称。

n_size

正常优先级队列的每个元素中的字节数(8到512)。指定固定的标头长度(8个字节)+参数长度(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

应用程序用于接收命令响应

MSGQ_AUD_DSP

用于接收来自DSP的响应(解码器)

MSGQ_AUD_RECORDER

用于接收MediaRecorderObject命令

MSGQ_AUD_CAP

用于接收CaptureComponent命令

MSGQ_AUD_CAP_SYNC

用于CaptureComponent的内部同步处理

有关每个定义的详细信息, 参见链接:https://github.com/sonydevworld/spresense/tree/master/examples /audio_recorder/config/msgq_layout.conf[examples/audio_recorder/config/msgq_layout.conf^] 。
如果设置更改,请使用该工具生成一个新的头文件。
内存管理器(智能修订池)配置

必须定义使用AudioRecorder函数时所需的MemoryLayout(池)。
定义在MemoaryLayout定义文件中进行,并且可以使用该工具生成要包含在代码中的头文件。

音频录制示例 中,执行以下操作。

cd examples/audio_recorder/config
python3 mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定义文件(mem_layout.conf)的内容如下。

固定空间
FixedAreas
 # name,                  device,     align,        size,         fence
  ["AUDIO_WORK_AREA",     "AUD_SRAM", U_STD_ALIGN,  0x0003d000,   False],
  ["MSG_QUE_AREA",        "AUD_SRAM", U_STD_ALIGN,  0x00002000,   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

该区域的起始对齐方式。 指定MinAlign的倍数(= 4),不包括0

size

区域的大小。 指定的值是0以外的4的倍数

fence

启用/禁用围栏(如果UseFence为False,则忽略此项目)

每个名称的用法如下。

AUDIO_WORK_AREA

由AudioSubSystem使用

MSG_QUE_AREA

由MessageQueue使用(固定名称)。不要超过msgq_id.h中的(MSGQ_END_DRM-MSGQ_TOP_DRAM)的大小。

MEMMGR_WORK_AREA

内存管理器使用的工作区(固定名称,固定大小)

MEMMGR_DATA_AREA

Memery Manager使用的数据区域(固定名称,固定大小)

确保每个名称的总大小不超过由 mpshm_init() 、 doxygen:mpshm_remap [mpshm_remap()] 保护的共享内存的大小。

固定区域无法定制
动态空间
PoolAreas
 # name,                    area,              align,        pool-size,  seg, fence
  ["ES_BUF_POOL",           "AUDIO_WORK_AREA", U_STD_ALIGN,  0x0000F000, 5,   True ],
  ["PREPROC_BUF_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x0000F000, 5,   True ],
  ["INPUT_BUF_POOL",        "AUDIO_WORK_AREA", U_STD_ALIGN,  0x0000F000, 5,   True ],
  ["ENC_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x00000114, 3,   True ],
  ["SRC_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x00000114, 3,   True ],
  ["PRE_APU_CMD_POOL",      "AUDIO_WORK_AREA", U_STD_ALIGN,  0x00000114, 3,   True ],

每个参数的说明如下。

参数 说明

name

池名称(以大写字母开头,以“POOL”结尾。可以使用大写字母,数字和

area

FixedArea区域名称用作池区域。 该区域必须位于RAM中

align

池的起始对齐方式。 指定MinAlign的倍数(= 4),不包括0。

pool-size

游泳池的大小。 该值是4的整数倍,但0除外。 对于基本池,段大小*段数

seg

段数。指定一个介于1到255之间的值

fence

指定围栏有效还是无效。 如果UseFence为False,则忽略此项目

每个名称的用法如下。

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
如果设置更改,请使用该工具生成一个新的头文件。
执行方法

从NuttShell启动Recorder应用程序。

nsh>recorder

Audio Recorder程序启动,录音开始。
记录文件将为“/mnt/sd0/REC/YYMMDD_HHMMSS.mp3” 。

Start AudioRecorder example

录制10秒钟后,AudioRecorder应用程序将退出。

Exit AudioRecorder example
5.3.3.11. Audio Recognizer 功能

Audio Recognizer 的简单数据流如下所示。

Audio Recognizer Dataflow
图表 21. Audio Recognizer Dataflow.

Audio Recognizer Function 提供用于实现语音识别功能的框架。

识别动作开始后,开始抓取音频数据,经过Pre处理后往识别库输入音频数据。
Pre处理对音频数据根据语音识别库要求的输入格式作必要的处理(采样率变换及噪音抑制等)。
如果可以将抓取的音频原样输入语音识别库的话,Pre处理设定为“通过”也没问题。
抓取并采取Pre处理后的音频数据会输入到语音识别库。
是否有结果输出,由库决定。它有一个可以每次输入都通知识别结果的框架。请配合应用程序使用。

+ Audio SubSystem在RecognizerMode工作时,可以在不关心音频数据(PCM数据)的情况下实现应用层。

数据流内部,使用Message通信。
Message通信,每个客户端都有ID。
Audio Recognizer的场合,根据example中的示例显示ID如下。

User Application           : MSGQ_AUD_APP
Audio Manager              : MSGQ_AUD_MNG
Audio Frontend             : MSGQ_AUD_FRONTEND
Audio Recognizer           : MSGQ_AUD_RECOGNIZER
Audio Capture Component    : MSGQ_AUD_CAP
Audio DSP                  : MSGQ_AUD_DSP
Audio Recognizer Message ID
图表 22. Audio Recognizer Message ID

另外,各数据的数据区域如下。

PCM (Input) Data Buffer    : INPUT_BUF_POOL
PreProcess Data Buffer     : PREPROC_BUF_POOL
PreProcess DSP Command     : PRE_APU_CMD_POOL
Recognizer DSP Command     : RCG_APU_CMD_POOL
Audio Recognizer Pool ID
图表 23. Audio Recognizer Pool ID

这些ID需要在生成时指定。

5.3.3.11.1. 使用方法
准备

通过被称为"AudioManager"、"MicFrontendObject"、"RecognizerObject"、"CaptureComponent" 的用于控制音频子系统而设计的软件组件,来实现Audio识别。

创建 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_MNG;
ids.player_main = 0xFF;
ids.player_sub  = 0xFF;
ids.micfrontend = MSGQ_AUD_FRONTEND
ids.mixer       = 0xFF;
ids.recorder    = 0xFF;
ids.effector    = 0xFF;
ids.recognizer  = MSGQ_AUD_RECOGNIZER;

AS_CreateAudioManager(ids, attention_callback);
创建 MicFrontendObject

使MicFrontendObject有效,需要调用 AS_CreateMicFrontend(AsCreateMicFrontendParam_t)
需要指定由Message Library Configuration定义的MsgQueID和由Memory Manager Configuration定义的 PoolId。
MsgQueID 里的 dsp,PoolId里的 output 和 dspcmd 请仅在 执行Preprocess 时有效。其他场合可以指定为NULL_POOL 。
AudioAttentionCb为异步通知,所以需要指定回调函数。请在不使用AudioManager的场合指定。
由AS_CreateAudioManager登录回调函数的情况或者指定为 NULL 时为不通知。

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

AsCreateMicFrontendParams_t cparam;

cparam.msgq_id.micfrontend = MSGQ_AUD_FRONTEND;
cparam.msgq_id.mng         = MSGQ_AUD_MNG;
cparam.msgq_id.dsp         = MSGQ_AUD_PREDSP;
cparam.pool_id.capin       = INPUT_BUF_POOL;
cparam.pool_id.output      = PREPROC_BUF_POOL; /* When you don't use preprocess, set to NULL_POOL */
cparam.pool_id.dspcmd      = PRE_APU_CMD_POOL; /* When you don't use preprocess, set to NULL_POOL */

result = AS_CreateMicFrontend(&cparam, attention_callback_from_frontend);
创建 RecognizerObject

使 RecognizerObject 有效,需要调用 AS_CreateRecognizer(AsCreateRecognizerParam_t) 。 需要指定由 Message Library Configuration 定义的 MsgQueID 和由 Memory Manager Configuration 定义的 PoolId 。
AudioAttentionCb 为异步通知,所以需要指定回调函数。请在不使用AudioManager的场合指定。
由AS_CreateAudioManager登录回调函数的情况或者指定为 NULL 时为不通知。

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

AsCreateRecognizerParam_t cparam;

cparam.msgq_id.recognizer = MSGQ_AUD_RECOGNIZER;
cparam.msgq_id.parent     = MSGQ_AUD_MNG;
cparam.msgq_id.dsp        = MSGQ_AUD_RCGDSP;
cparam.pool_id.output     = S0_OUTPUT_BUF_POOL;
cparam.pool_id.dsp        = S0_RCG_APU_CMD_POOL;

result = AS_CreateRecognizer(&cparam, attention_callback_from_recognizer);
创建 CaptureComponent

使 CaptureComponent 有效, 需要调用 AS_CreateCapture(AsActCaptureParam_t)。 需要指定由 Message Library Configuration 定义的 MsgQueID 和由 Memory Manager Configuration 定义的 PoolId 。
如果应用程序不使用第二通道的话,第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);
初始化及改变状态

必要的对象生成后,为了让Recognizer动作,进行Audio的HW的设定,电源On,动作模式变更等初始化处理。

可以按顺序发出以下命令来实现。

Audio 子系统上电

为了给Audio功能块上电,通过发出AUDCMD_POWERONPowerOnParam 命令,上电使Audio子系统的状态迁移至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);
初始化麦克风

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

init_mic_gain_param[]

对于模拟麦克风,dB值乘以10获得的值可以在0(0.0dB)到210(21.0dB)的范围内以5的倍数设定。缺省值为0.0dB。
对于数字麦克风,dB值乘以100获得的值可以在-7850(-78.50dB)~0(0.00dB)的范围内设定。缺省值为-78.50dB。
不想变更Gain值使,请指定’AS_MICGAIN_HOLD'。

命令设定示例

如下,1ch~4ch的输出加上21dB增益时的设定示例。 设定5ch~8ch的增益不变。

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的信息。

麦克通道设定
[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声道。

切到识别状态

使用AUDCMD_SETRECOGNIZERSTATUS迁移AudioSubSystem的状态至Recognizer状态。

初始化设备

指定要记录对象的输入设备。

可以仅指定麦克风。
AsMicFrontendDeviceMic : 
命令设定示例

以下是使用麦克风输入进行识别的设置示例。

AudioCommand command;
command.header.packet_length = LENGTH_SET_RECOGNIZER_STATUS;
command.header.command_code  = AUDCMD_SETRECOGNIZERSTATUS;
command.header.sub_code      = 0x00;
command.set_recorder_status_param.input_device = AsMicFrontendDeviceMic;
AS_SendAudioCommand(&command);
开始识别

语音识别开始顺序。

Init mic frontend

通过AUDCMD_INIT_MICFRONTEND, MicFrontendCommand, AsInitMicFrontEnd设置前端动作(音频抓取等)。

ch_num
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
samples
/* 指定1帧的采样数。请根据识别库的规格设定。 */
out_fs

指定由MicFrontend输出的音频的采样率。
preproc_type 仅在 AsMicFrontendPreProcSrc 时有效。

AS_SAMPLINGRATE_8000  : 8kHz
AS_SAMPLINGRATE_16000 : 16kHz
AS_SAMPLINGRATE_44100 : 44.1kHz
AS_SAMPLINGRATE_48000 : 48kHz
...
...
AS_SAMPLINGRATE_192000 : 192kHz
preproc_type

设定PreProcess的类别。

AsMicFrontendPreProcThrough       : Through
AsMicFrontendPreProcSrc           : Sampling Rate Converter
AsMicFrontendPreProcUserCustom    : User Custom Process
指定’AsMicFrontendPreProcSrc' 的话,sdk/modules/audio/DSP/ 里的 SRC 是必须的。
preprocess_dsp_path

PreProcess用的DSP二进制用包含全路径的文件名指定。

"/mnt/sd0/BIN/PREPROC" : PREPROC 这个二进制放入SD卡的Bin目录下
"/mnt/spif/SRC"        : SRC 这个二进制放入SPI-FLASH的一级目录下
data_dest

指定从MicFrontendObject输出Audio数据的目的地。

AsMicFrontendDataToRecorder   : Send to Recorder
AsMicFrontendDataToRecognizer : Send to Recognizer

下图展示了使用PreprocessDSP的信号处理模块处于Audio Recognizer Function中的位置。

信号处理由高亮部分的CustomprocComp(Pre), UserCustomDSP(Pre)进行。
用户创建信号处理并嵌入到UserCustomDSP。

Audio recognizer preprocess
图表 24. Audio 识别预处理

Preprocess可以根据识别库的输入格式,使用DPS进行用户自己的信号处理。
比如,识别库的输入与Baseband的输入(48kHz or 192kHz)不同时,执行采样率变换,噪音抑制滤波器等预处理。

命令设定示例

如下,使用Mono/16bit/768sample per frame抓取音频时的设定示例。
Pre处理由UserCustom的DSP进行。这个DSP用的二进制文件在SD卡的BIN目录下。
另外,抓取的音频设定为Recognizer用。

AudioCommand command;
command.header.packet_length = LENGTH_INIT_MICFRONTEND;
command.header.command_code  = AUDCMD_INIT_MICFRONTEND;
command.header.sub_code      = 0x00;
command.init_micfrontend_param.ch_num       = AS_CHANNEL_MONO
command.init_micfrontend_param.bit_length   = AS_BITLENGTH_16;
command.init_micfrontend_param.sample       = 768; /* 请根据识别库的规格设置此值。 */
command.init_micfrontend_param.outfs        = AS_SAMPLINGRATE_16000;
command.init_micfrontend_param.preproc_type = AsMicFrontendPreProcUserCustom;
snprintf(command.init_micfrontend_param.preprocess_dsp_path,
         AS_RECOGNIZER_FILE_PATH_LEN,
         "%s", "/mnt/sd0/BIN/PREPROC");
command.init_micfrontend_param.data_dest = AsMicFrontendDataToRecognizer;
DSP 初始化预处理

通过AUDCMD_INIT_PREPROCESS_DSP, AsInitPreProcParam初始化Pre处理用的DSP。

通过AUDCMD_INIT_MICFRONTENDpreproc_typeAsMicFrontendPreProcThrough 时无需执行此步骤。
packet_addr

初始化命令包的地址。命令格式依赖于Pre处理用的DSP。
在此API响应之前,需保留设置的地址区域。

packet_size

初始化命令包的大小。

命令设定示例
static uint8_t s_initparam = 0;

AudioCommand command;
command.header.packet_length = LENGTH_INIT_PREPROCESS_DSP;
command.header.command_code  = AUDCMD_INIT_PREPROCESS_DSP;
command.header.sub_code      = 0x00;
command.init_preproc_param.packet_addr = reinterpret_cast<uint8_t *>(&s_initparam);
command.init_preproc_param.packet_size = sizeof(s_initparam);
AS_SendAudioCommand(&command);
初始化识别器
fcb

注册回调函数以获取AudioSusSystem的识别函数。
识别结果为纯数据通知,数据构成取决于识别库。

static void recognizer_find_callback(AsRecognitionInfo)
type

设定识别引擎类别。

SDK v1.4.0仅可指定如下的设定值。
AsRecognizerTypeUserCustom
recognizer_dsp_path

以包含文件名的全目录名指定识别用DSP二进制文件。

"/mnt/sd0/BIN/RCGPROC" : RCGPROC二进制文件放在SD卡的BIN目录下时

下图中高亮部分为此处指定的识别用DSP二进制文件
CustomprocComp(Recogniton), UserCustomDSP(Recognition)相关位置进行识别处理。

Audio recognizer recognizerprocess
图表 25. Audio Recognizer Process
命令设定示例

如下,由recognizer_find_callback()获取识别结果的设定示例。 识别用DSP放在SD卡的BIN目录下。

static void recognizer_find_callback(AsRecognitionInfo info)
{
  ...
}

AudioCommand command;
command.header.packet_length = LENGTH_INIT_RECOGNIZER;
command.header.command_code  = AUDCMD_INIT_RECOGNIZER;
command.header.sub_code      = 0x00;
command.init_recognizer.fcb             = recognizer_find_callback;
command.init_recognizer.recognizer_type = AsRecognizerTypeUserCustom;
snprintf(command.init_recognizer.recognizer_dsp_path,
         AS_RECOGNIZER_FILE_PATH_LEN,
         "%s", "/mnt/sd0/BIN/RCGPROC");
初始化识别 DSP

通过AUDCMD_INIT_RECOGNIZER_DSP, AsInitRecognizerProcParam初始化识别用DSP。

packet_addr

初始化命令包的地址。命令格式取决于识别处理用DSP。
此API响应前,需保留设置的地址区域。

packet_size

初始化命令包的大小。

命令设定示例
static uint8_t s_initparam = 0;

AudioCommand command;
command.header.packet_length = LENGTH_INIT_RECOGNIZER_DSP;
command.header.command_code  = AUDCMD_INIT_RECOGNIZER_DSP;
command.header.sub_code      = 0x00;
command.init_rcg_param.packet_addr = reinterpret_cast<uint8_t *>(&s_initparam);
command.init_rcg_param.packet_size = sizeof(s_initparam);
AS_SendAudioCommand(&command);

语音识别功能初始化为止的顺序如下图所示。

diag bfe5a19ce55db623a0aeda2a9767d413
图表 26. 语音识别初始化顺序
开始识别

通过AUDCMD_START_RECOGNIZER开始识别动作。
开始后AudioSubSystem对抓取的音频数据预处理后送入识别库。
识别结果由Init Recognizer设定的回调函数通知。

命令设定示例
AudioCommand command;
command.header.packet_length = LENGTH_START_RECOGNIZER;
command.header.command_code  = AUDCMD_START_RECOGNIZER;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag 8a7244f567478db4cba6e237df0c0fb4
图表 27. 识别动作顺序
停止识别

通过 AUDCMD_STOP_RECOGNIZER 停止识别动作。
停止后AudioSubSystem停止抓取数据,同时停止送入识别库。

命令设定示例
AudioCommand command;
command.header.packet_length = LENGTH_STOP_RECOGNIZER;
command.header.command_code  = AUDCMD_STOP_RECOGNIZER;
command.header.sub_code      = 0x00;
AS_SendAudioCommand(&command)
diag 8fb62e6e2c23d8dc57df71c010b6818a
图表 28. 识别停止顺序
5.3.3.11.2. 编译配置

为了使用AudioRecognizer的功能

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

[SDK audio]                      <= Y
  [Audio Utilities]
    [Sound Recognizer]           <= Y
    [Mic Front End]              <= Y

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

[ASMP]                           <= Y
5.3.3.11.3. 注意事项

语音识别的警告一览及对应方法如下。详细请参考 关于音频子系统错误

ID Attention Code Attention Level Approach

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二进制的版本不一致。请用"sdk/modules/audio/dsp"的文件更新DSP二进制映像。

5.3.3.11.4. DSP 安装

将用于语音识别的DSP二进制映像存储到Kconfig设置的路径中。

[TBD]SDK提供的二进制映像,在 sdk/modules/audio/dsp 下。
5.3.3.12. Audio Through 功能

Audio Through 的简单数据流如下所示。

Audio Through 数据流
图表 29. Audio Through 数据流

Audio SubSystem工作在ThroughMode时,用户程序可以设定不经过CPU的数据流。

数据的输入端可以指定为I2S或MIC。 数据的输出端可以指定为扬声器或I2S。

此外,User Application可以设定2个数据流。 使用MIXER可以MIX 2个数据流为1个。

User Application要求的设定会通过Message发出命令。 Message通信在每个客户端用于ID。 Audio Through的场合,ID如下所示。

User Application           : MSGQ_AUD_APP
Audio Manager              : MSGQ_AUD_MNG
Audio Through Message ID
图表 30. Audio Through 消息编号

此ID需要在生成时指定。

5.3.3.12.1. Audio HW 内部数据流

Audio Through时,Audio HW的内部为 Audio HW 内部数据流 中显示的数据流。
数据流的输入端有I2S In、MIC In、Mixer Out。
数据流的输出端有Mixer In1、 Mixer In2、I2SOut。输出端设定为Mixer In1或者Mixer In2时,输出由Mixer Out到扬声器。

diag 65e983773cddcc639db0941b79e4fdb8
图表 31. Audio Through 内部数据流

可以设定的输入端和输出端的关系如下。

表格 19. Audio Through dataflow combination
输入端 输出端

I2S In

Mixer In1, Mixer In2

MIC In

Mixer In1, Mixer In2, I2S Out

Mixer Out

I2S Out,
Speaker Out(始终输出)

5.3.3.12.2. 使用方法
准备

称为“AudioManager”
通过为控制音频子系统而设计的软件组件实现Audio Through。

因此,为了实现Audio Through需要事先调用以下对象生成函数。

Activate AudioManager

需要调用 AS_CreateAudioManager(AudioSubSystemIDs) 使 AudioManager 有效。
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);
初始化及状态改变

生成了必要的对象后,进行Audio的HW的设定,电源On,工作模式变更等初始化处理,以执行Audio Through动作。

按顺序发出以下命令可以实现。

Audio 子系统上电

为了让Audio功能块上电,通过发出 AUDCMD_POWERONPowerOnParam 命令,上电并将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);
初始化输出设备

PowerOn并迁移到Ready状态后,通过 AUDCMD_INITOUTPUTSELECTInitOutputSelectParam 命令来选择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);
更改通道状态

使用 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);
设置音量

输出为扬声器时,可以用 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

Mix MIXER1和MIXER2後的音量。の音量。设定范围同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);
初始化麦克风

请参考 Recorder Init Mic Gain

可以使用的麦克风为,CXD5247模拟麦克风1,CXD5247ア模拟麦克风2的组合, 或者CXD5247数字麦克风1,CXD5247数字麦克风2的组合中的一组。

打算变更麦克风的话,如 Recorder Init Mic Gain ,可以变更Layout来实现。
diag 58655d46ad555e08e00e0de46af35622
图表 32. 初始化顺序
启动 Audio Through

设定数据流的路径,开始数据的输入和输出。

设置 Through Path

通过 AUDCMD_SETTHROUGHPATHAsSetThroughPathParamAsThroughPath 可以同时设定两路数据路径。 各路数据路径的参数设定如下。

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
图表 33. 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
图表 34. 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
图表 35. 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
图表 36. command example 4 dataflow
diag 8ff3456753187077134a0b21e7a8bde2
图表 37. Player State sequence
5.3.3.12.3. 编译配置

使用AudioThrough 的功能前

cd sdk
tools/config.py -m

需要使用以上命令打开Config menu ,设定如下的Config。

Select options in below:

[CXD65xx Configuration]
  [Audio]                        <= Y

[SDK audio]                      <= Y
5.3.3.12.4. 注意事项及解决方案

播放音乐时的警告一览及对应方法如下。详细请参考 关于音频子系统错误

编号 代码 级别 解决方案

0x0F

AS_ATTENTION_SUB_CODE_TASK_CREATE_ERROR

ERROR

堆区域不足。请扩大堆区域。

AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW 发生时,音频播放将停止,状态变为播放错误。 发生此状态时,请立即发行 AsStopPlayerParam 命令,迁移至播放停止状态。
迁移到播放停止后,请一定清空FIFO。否则会产生噪音。

5.3.4. 对象级 API

音频功能以比顶层API更好的单位提供API。
通过在调用高级API时使用内部使用的对象的组合,可以创建更多的免费应用程序。
您可以使用创建更多免费的应用程序。

这称为 Object Level API

5.3.4.1. 有关用例

这是使用Object LevelAPI的用例示例。
(这只是一个示例,因为组合和用法是免费的。)

5.3.4.1.1. 用例1

在这种情况下,音频数据将使用MediaPlayerObject和OutputMixerObject进行解码并输出。
从MediaPlayerObject返回的PCM数据可以在由Application处理之后发送到OutputMixerObject。

diag ab93aa2802beb8c61e03e7c1143ecd69
5.3.4.1.2. 用例 2

在这种情况下,不使用MediaPlayerObject,将放置在RAM中的PCM数据发送到OutputMixerObject。
因为它不解码,所以它适合于播放需要快速响应的声源,例如声音效果。

diag bf1fe0222522853b96ba7b3104ae3997
5.3.4.1.3. 用例 3

MediaRecorderObjectを使い記録したMIC入力をApplicationで加工して
OutputMixer経由でスピーカーやI2S出力に送出するケースです。 在这种情况下,使用MediaRecorderObject记录的MIC输入由应用程序处理,并通过OutputMixer发送到扬声器或I2S输出。

diag f4e757af5d5bed88f7fbea6f4033e170
5.3.4.2. MediaPlayerObject

MediaPlayerObject执行音频数据解码管理和解码结果PCM输出。
可以同时使用两个Player,并且每个API中的PlayerID参数分别对其进行控制。

应用程序通过称为SimpleFIFO的缓冲区将ES数据传递给MediaplayerObject。
缓冲区下溢时播放停止。 在设计应用程序时应考虑到这一点。
解码完成后,MediaPlayerObject将把PCM数据通知MemoryHandle。

diag f4b4ec84d21ebaf098aadeca6c6e0294

也可以将PCM数据发送到OutputMixerObject。在这种情况下,对应用程序无响应。
但是,当然,必须创建并启动OutputMixerObject。
(默认是对应用程序的回调响应,如上所示。)

diag bcaf7c36bef0baccb48dd3e7ffb724d4
5.3.4.2.1. 功能
创建

使用MediaPlayerObject时必须调用。
执行任务生成,实例生成以及过渡到MsqQueue等待。

接口
bool AS_CreatePlayer(AsPlayerId id, FAR AsCreatePlayerParam_t *param);
激活

激活MediaPlayerObject。必须被调用。
此处设置了用于将音频数据从Application传递到MediaPlayerObject的缓冲区句柄。

接口
bool AS_ActivatePlayer(AsPlayerId id, FAR AsActivatePlayer &actparam);
初始化

设置要播放的内容的信息并初始化MediaPlayerObject。
每当内容信息_(※)变化时,都必须进行呼叫。
_(※编解码器类型,位长,采样频率)

接口
bool AS_InitPlayer(AsPlayerId id, FAR AsInitPlayerParam &initparam);
播放

开始播放。
播放开始后,继续回答解码结果(PCM数据)。
应用程序需要将音频数据提供给激活时指定的缓冲区。
如果电源无法跟上,缓冲区将下溢并且播放将停止。

您可以选择是将解码的PCM数据发送到Application,还是直接将其发送到OutputMixerObject。

接口
bool AS_PlayPlayer(AsPlayerId id, FAR AsPlayPlayerParam &playparam);
停止

停止。
调用此API时,您可以选择在播放保留在音频数据缓冲区中的数据之后立即停止还是停止。
在前一种情况下,可能需要一些时间才能停止。

根据通话的时间,由于错误,您可能会在通话后收到解码完成的通知。

接口
bool AS_StopPlayer(AsPlayerId id, FAR AsStopPlayerParam &stopparam);
设定增益

将播放音量增益分别设置为L/R。
不通话时为100%(默认音量)。(BaseBand卷设置没有依赖性)

接口
bool AS_SetPlayerGain(AsPlayerId id, FAR AsSetGainParam &gainparam);
下一请求

请求下一个解码过程(播放继续过程)。
解码结果数据缓冲区为空等时,连续调用。
如果未调用此API,则将不执行后续的解码处理,并且声音将停止或被中断。

(※如果PCM数据的目标直接是OutputMixerObject,则不需要调用。)

接口
bool AS_RequestNextPlayerProcess(AsPlayerId id, FAR AsRequestNextParam &nextparam);
停用

停用MediaPlayerObject。 要再次使用MediaPlayerObject,您需要从Acitvate重新开始。

接口
bool AS_DeactivatePlayer(AsPlayerId id, FAR AsDeactivatePlayer &deactparam);
删除

删除MediaPlayerObject任务或实例。
要再次使用MediaPlayerObject,您需要从Create重新开始。

接口
bool AS_DeletePlayer(AsPlayerId id);
5.3.4.2.2. 顺序

MediaPlayerObject的简单序列。

diag b6cefcb9577de8b5b442e21834522a3d
5.3.4.3. OutputMixerObject

OutputMixerObject管理PCM数据的发送(呈现)。
应用程序通过MemoryHandle将PCM数据发送到OutputMixerObject。
渲染完成后,将从OutputMixerObject返回回调。

diag bfaf0f6425a975302f975fae14b46c76
5.3.4.3.1. 功能
创建

使用OutputMixerObject时必须调用。
执行任务生成,实例生成以及过渡到MsqQueue等待。

接口
bool AS_CreateOutputMixer(FAR AsCreateOutputMixParam_t *param);
激活

执行OutputMixerObject的激活。必须调用。
此时选择输出目的地(扬声器或I2S)。

接口
bool AS_ActivateOutputMixer(uint8_t handle, FAR AsActivateOutputMixer &actparam);
发送数据

发送PCM数据。发送完成后,将回叫响应。

在通过此API发送的数据发送完成之前,请传递以下数据。
如果不及时,DMA传输将下溢并停止。

当多次调用此API时,实际上会发送PCM数据。

diag 08e8411efd34ac6919d61bed27938fee
接口
bool AS_SendDataOutputMixer(FAR AsSendDataOutputMixer &sendparam);
帧项控制

调整PCM数据传输时间。
可以进行比实际PCM数据发音时间更长或更短的微调。
它主要用于调整PCM数据的缓冲区剩余量(在/上溢抑制下)。
(※调整过程中可能会进入小的噪音。)

接口
bool AS_FrameTermFineControlOutputMixer(uint8_t handle, FAR AsFrameTermFineControl &ftermparam);
停用

停用OutputMixerObject。

接口
bool AS_DeactivateOutputMixer(uint8_t handle, FAR AsDeactivateOutputMixer &deactparam);
删除

删除任务和OutputMixerObject实例。
要再次使用OutputMixerObject,您需要从Create重新开始。

接口
bool AS_DeleteOutputMix(void);
5.3.4.3.2. 顺序

OutputMixerObject的简单序列。

diag 555016bd2e38d78db91630612bd722d4
5.3.4.4. MediaRecorderObject

MediaRecorderObject执行音频数据的编码管理和编码结果ES的输出。

对捕获的MIC或IS2输入(PCM数据)进行编码,并将其顺序存储在SimpleFIFO缓冲区中。
应用程序可以通过提取来检索ES数据。 当由于提取不足而导致缓冲区溢出时,记录将停止,因此应在设计应用程序时考虑到这一点。

diag 75593d76f238c730ff85bb837905911b
5.3.4.4.1. 功能
创建

使用MediaRecorderObject时必须调用。
执行任务生成,实例生成以及过渡到MsqQueue等待。

接口
bool AS_CreateMediaRecorder(FAR AsActRecorderParam_t *param);
激活

激活MediaRecorderObject。
传递此时用于传递编码音频数据的缓冲区的句柄。

接口
bool AS_ActivateMediaRecorder(FAR AsActivateRecorder *actparam);
初始化

设置要记录的内容信息并初始化MediaRecorderObject。
录制期间无法动态更改。

接口
bool AS_InitMediaRecorder(FAR AsInitRecorderParam *initparam);
启动

根据Init中设置的信息开始记录。
编码的ES数据按顺序存储在激活时指定的音频缓冲区中。
应用程序需要从音频缓冲区中提取ES数据。

接口
bool AS_StartMediaRecorder(void);
Stop

停止录音。
仅支持立即停止。

接口
bool AS_StopMediaRecorder(void);
停用

停用MediaRecorderObject。

接口
bool AS_DeactivateMediaRecorder(void);
删除

删除MediaRecorderObject。

接口
bool AS_DeleteMediaRecorder(void);
5.3.4.4.2. 顺序
diag d3c4a849772a3eab645846899a9bfc56

5.3.5. 底层 API

Now Under construction. mOm

5.3.6. UserCustomDSP 架构

UserCustomDSP是一种机制,允许将特定于用户的信号处理应用于音频信号。
信号处理由DSP执行。 这是它如何工作的详细说明。

5.3.6.1. 框架代码

要添加信号处理,您必须首先创建一个UserCustomDSP。
SDK至少提供了所需的源代码作为框架。
通过将这些内容与用户创建的DSP代码一起构建来创建UserCustomDSP。

有关创建UserCustomDSP的过程,请参考 Audio Recorder 教程
diag 25a03e75844acdce8cd8a80f2463a143
图表 38. 框架放置
5.3.6.2. 框架代码和用户代码之间的关系

SDK提供的框架与用户代码之间的关系必须如下图所示。
用户在图中编辑与“User Edit DSP Codes”相对应的部分。
(无需编辑框架代码。)

diag 0b46c0dab991ebadf39516a6f62223f2
图表 39. 框架代码和用户代码之间的关系

创建用户代码时要记住的要点如下:

  1. 可以自由创建与UserCustomDSP的通信命令定义,但是必须使用继承框架的 CustomprocCommand::CmdBase 的结构,并遵循 数据格式如下所示

    diag 0251762412ae0cac3ba46f77045cb413
    图表 40. 通讯指令格式

    例如:

    struct InitPram : public CustomprocCommand::CmdBase
    {
      uint8_t ch_num;
      ...
    }
  2. 编写用户处理的类(在 以上)继承了框架 CustomprocDspUserProcIf (抽象类)并通过覆盖其方法来实现它,如下所示。

    class UserProc : public CustomprocDspUserProcIf
    {
      void init(CustomprocCommand::CmdBase*);
      ...
    }
5.3.6.3. UserCustomDSP 操作
5.3.6.3.1. DSP内部状态转换

UserCustomDSP对 InitExecFlushSet 命令执行 状态转换 ,如下所示。

diag 08e6f503b014bb37cd4f99f0886ae829
图表 41. UserCustomDSP状态转换
5.3.6.3.2. DSP操作顺序

在上述框架上创建的UserCustomDSP按照下图所示的顺序在每个Audio功能中运行。
有关UserCutstomDSP在Audio Recorer功能中的位置,请参考 初始化麦克风前端(录音) ,对于音频识别器,请参考 初始化麦克风前端(识别器)

从下图中可以看到, InitSet 命令是由用户代码中的API调用触发的。
ExecFlush 命令在AudioSubSystem内部发送(每次捕获音频时)。 (※ 不需要从用户代码发送 ExecFlush 命令。)

AudioRecorder功能及UserCustomDSP操作顺序

总体流程如下。

  1. AUDCMD_INIT_MICFRONTEND 指定的二进制文件中启动。

  2. AUDCMD_INIT_PREPROCESS_DSP 将向UserCustomDSP发送一个 Init 命令。 用于发送处理所需的参数,例如通道数和位长。

  3. AUDCMD_STARTREC 开始音频捕获,并使用 Exec 命令顺序发送它们。这由UserCustomDSP处理。

  4. AUDCMD_SET_PREPROCESS_DSPSet 命令将发送。 由于即使在记录操作期间也可以发送,因此可用于设置滤波器系数。

  5. 音频捕获使用强力停止 AUDCMD_STOPREC,并且在最后一帧中的 Exec 之后发送 Flush 。 用于清除延迟等。

diag 1a34003c6e2a67a420c158fd8b1d560b
图表 42. AudioRecorder函数HighLevelAPI命令和UserCustomDSP操作顺序
AudioRecognizer功能和UserCustomDSP操作顺序

总体流程如下:

  1. DSP由 AUDCMD_INIT_RECOGNIZER 指定的二进制文件启动。

  2. 带有 AUDCMD_INIT_RECOGNIZER_DSPInit 命令发送到UserCustomDSP。 用于发送识别处理所需的参数,例如通道数和位长。

  3. AUDCMD_START_RECOGNIZER 开始音频捕获,并使用 Exec 命令顺序发送它们。 这是UserCustomDSP识别的。

  4. AUDCMD_SET_RECOGNIZER_DSPSet 命令将发送。 由于即使在识别操作期间也可以发送,因此可用于设置识别参数。

  5. 使用 AUDCMD_STOP_RECOGNIZER 停止音频捕获,并且在最后一帧的 Exec 之后发送 Flush 。 用于清除延迟。

  6. AudioRecognizer函数HighLevelAPI命令和UserCustomDSP操作顺序

diag 251ef3e2521fa76aab040bc063ac7173

5.3.7. 关于音频子系统错误

5.3.7.1. 概要

Audio SubSystem 的High Level API 拥有命令~结果的收发信界面。

发向Audio SubSystem的命令出现问题时,作为结果返回 AUDRLT_ERRORRESPONSE , 错误内容保存在 ErrorResponse 的参数中。 这个错误称为 应答错误

另外,Audio SubSystem的内部处理发现错误时,内部事件启动,通过由 AS_CreateAudioManager 登录的 回调函数 通知错误,错误内容保存在 ErrorAttention 的参数中。 这个被称为 状态错误

对于应答错误,状态错误,对应于各个错误请执行故障对应和错误处理等。

5.3.7.2. 应答错误

Audio 子系统发出的命令,如果按照式样执行了控制,对各条命令会应答命令结束的结果。
但是,由于违反状态或者参数错误等导致执行了和式样不一致的控制,将返回 AUDRLT_ERRORRESPONSE 的结果, 错误内容包含在 ErrorResponse 的参数中。

diag 674ed13aec6d69686c4146073f628e6a

结果的应答错误的数据形式,请参考 结果格式ErrorResponse

 "ErrorResponse" 里附加有"Error Code",
通过"Error Code",可以知道错误发生的原因。

以下为"Error Code" 的一览。

表格 20. 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

DSP解码器初始化失败

AS_ECODE_ENCODER_LIB_INITIALIZE_ERROR

0x0E

DSP编码器初始化失败

AS_ECODE_FILTER_LIB_INITIALIZE_ERROR

0x0F

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_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"的详细信息,请参考 此处

5.3.7.3. 状态错误

Audio 子系统内部处理中(非命令处理)发现错误的时候,发生通知用的事件。 获取这个事件,需要事先通过 AS_CreateAudioManager 登录回调函数。

diag 61e7ac2732cc09448530338bdfa8a75d

状态错误数据形式 请参考 ErrorAttention

状态错误包含,播放动作时ES(Elementary Stream)断流(下溢出),记录动作时ES写入缓存的溢出(上溢出)等流程控制错误,存储资源枯竭,实时处理延迟等系统错误, HW发生的错误等,修复需要重启系统的致命错误。

这些错误,可以通过"ErrorAttention"附加的"Attention Code"来判断。 请根据发生的"Attention Code"修改。 另外,变更实装方法也可改进错误。

以下为"ErrorAttention" 附加的 "Attention Code" 一览。

表格 21. 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 级别

Attention通知有级别指定,指明错误严重性的同时恢复的处理方式也会不同。

表格 22. Attention 级别
级别 描述

致命

0x03

系统调用错误等,无法修复,恢复需要重启系统。

错误

0x02

内部错误(队列Full/Empty,DSP加载/卸载等)导致Audio系统动作无法继续的错误。回归系统初期状态(Ready状态)可以恢复。

警告

0x01

可能发生解码/编码错误,数据的上溢出/下溢出,动作异常,声音数据异常等,但动作可以继续。

5.3.7.4. 错误码列表

"Error Code"详细如下。

5.3.7.4.1. AS_ECODE_STATE_VIOLATION
code

0x01

description

Audio子系统内部发生违反状态。
要求命令和AudioSubSystem内部状态不一致导致命令无法受理。
使用状态迁移命令迁移到正确状态后,请再次发送命令。

AudioSubSystem内部状态迁移请参考下面文档。

状态迁移相关

5.3.7.4.2. AS_ECODE_PACKET_LENGTH_ERROR
code

0x02

description

命令包的长度参数有误。
包长度以Word(4byte)单位指定。不是byte单位。
请确认是否设定了正确的值。

5.3.7.4.3. AS_ECODE_COMMAND_CODE_ERROR
code

0x03

description

接收到未知命令。
请再次确认命令ID。

5.3.7.4.4. AS_ECODE_COMMAND_NOT_SUPPOT
code

0x04

description

发送的命令无效。
需要通过配置使命令对应功能有效。

有关Audio Player和Audio Recorder的配置,请参考下面文档。

Audio Player
Audio Recorder

5.3.7.4.5. AS_ECODE_AUDIO_POWER_ON_ERROR
code

0x05

description

Audio电源无法打开。电源可能已经打开。

5.3.7.4.6. AS_ECODE_AUDIO_POWER_OFF_ERROR
code

0x06

description

Audio电源无法关闭。电源可能已经关闭。

5.3.7.4.7. AS_ECODE_DSP_LOAD_ERROR
code

0x07

description

DSP无法加载/启动。

请确认DSP的配置路径被正确设定了。
有关配置路径的设定,请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

另外,配置路径中可能未放入需要的DSP。
AudioPlayer(对应播放文件的类别)需要 MP3DEC, AACDEC, WAVDEC, OPUSDEC
AudioRecorder(对应记录文件的类别)需要 MP3ENC, OPUSENC, SRC
以上由 sdk/modules/audio/dsp/ 提供。

5.3.7.4.8. AS_ECODE_DSP_UNLOAD_ERROR
code

0x08

description

DSP无法结束/卸载。
可能已经卸载或者未加载。

5.3.7.4.9. AS_ECODE_DSP_VERSION_ERROR
code

0x09

description

DSP的版本和AudioSubSytem预计不一致,无法使用。
请使用和SDK包一起的DSP sdk/modules/audio/dsp/

5.3.7.4.10. AS_ECODE_SET_AUDIO_DATA_PATH_ERROR
code

0x0a

description

Audio数据路径设定(输入/输出)错误。
请确认以下参数是否正确设定。

AudioRecorder 是 初始化录音器
BaseBand 是 SetBaseBandStatusParam
Through mode 是 AsSetThroughPathParam

5.3.7.4.11. AS_ECODE_CLEAR_AUDIO_DATA_PATH_ERROR
code

0x0b

description

Audio数据路径设定无法清除。

5.3.7.4.12. AS_ECODE_NOT_AUDIO_DATA_PATH
code

0x0c

description

输入设备或输出设备无效。
需要迁移到BaseBandStatus或者ThroughStatus 。

迁移到BasebandStatus是 SetBasebandStatus
迁移到ThroughStatus是 SetThroughStatus

5.3.7.4.13. AS_ECODE_DECODER_LIB_INITIALIZE_ERROR
code

0x0d

description

DSP解码器应答为初始化错误。

5.3.7.4.14. AS_ECODE_ENCODER_LIB_INITIALIZE_ERROR
code

0x0e

description

DSP编码器应答为初始化错误。

5.3.7.4.15. AS_ECODE_FILTER_LIB_INITIALIZE_ERROR
code

0x0f

description

DSP过滤器应答为初始化错误。

5.3.7.4.16. AS_ECODE_COMMAND_PARAM_CODEC_TYPE
code

0x11

description

Audio Codec的类别指定错误。

AudioSubSystem对应Codec请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

5.3.7.4.17. AS_ECODE_COMMAND_PARAM_CHANNEL_NUMBER
code

0x13

description

指定ch数错误或者组合其他参数时出错。
AudioPlayer和AudioRecorder都对其他参数(例如编解码器类型和通道数)的组合有限制。

有关限制的详细信息,请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

5.3.7.4.18. AS_ECODE_COMMAND_PARAM_SAMPLING_RATE
code

0x14

description

指定的采样频率有误,或者组合其它参数时出错。
AudioPlayer和AudioRecorder都对其他参数(例如编解码器类型和采样频率)的组合有限制。

在AudioPlayer的情况下,如果音频数据的标头中包含的采样频率信息与指定的采样频率不同,也会发生此错误。

有关限制的详细信息,请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

5.3.7.4.19. AS_ECODE_COMMAND_PARAM_BIT_RATE
code

0x15

description

指定的比特率有误,或者组合其它参数时出错。
AudioRecorder时,Codec类型等参数和比特率的组合有限制。

有关限制的详细信息,请参考如下文件。

初始化录音器

5.3.7.4.20. AS_ECODE_COMMAND_PARAM_BIT_LENGTH
code

0x16

description

指定的比特长度有误,或者组合其它参数时出错。

有关限制的详细信息,请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

另外,Recorder状态指定为24bit记录时,需要切换到HiReso模式。

模式切换请参考 Init Rendering Clock

5.3.7.4.21. AS_ECODE_COMMAND_PARAM_COMPLEXITY
code

0x17

description

指定的OPUS编码压缩率有误。

参数请参考以下文件。

初始化录音器

5.3.7.4.22. AS_ECODE_COMMAND_PARAM_ACTIVE_PLAYER
code

0x18

description

启用Player指定错误。
无法迁移到Player状态。

参数请参考以下文件。

变换到播放状态

5.3.7.4.23. AS_ECODE_COMMAND_PARAM_INPUT_DEVICE
code

0x19

description

指定的输入设备有误。

参数请参考以下文件。

变换到播放状态
进入录音状态

5.3.7.4.24. AS_ECODE_COMMAND_PARAM_OUTPUT_DEVICE
code

0x1A

description

指定的输出设备有误。

参数请参考以下文件。

变换到播放状态
进入录音状态

5.3.7.4.25. AS_ECODE_COMMAND_PARAM_INPUT_HANDLER
code

0x1B

description

指定的输入设备句柄有误。
请确认SimpleFIFO的句柄或者回调函数已被正确设定。

参数请参考以下文件。

变换到播放状态

5.3.7.4.26. AS_ECODE_COMMAND_PARAM_CONFIG_TABLE
code

0x1F

description

MFE或MPP滤波器的系数表地址无效。 (※不支持MFE和MPP。)

5.3.7.4.27. AS_ECODE_COMMAND_PARAM_WITH_MFE
code

0x20

description

MFE的活动指定参数有误。
(※MFE未支持。)

5.3.7.4.28. AS_ECODE_COMMAND_PARAM_WITH_MPP
code

0x21

description

MPP的活动指定参数有误。
(※MPP未支持。)

5.3.7.4.29. AS_ECODE_COMMAND_PARAM_INPUT_DB
cod

0x28

description

静音指定参数有误。

参数请参考以下文件。

Set Volume Mute

5.3.7.4.30. AS_ECODE_DMAC_INITIALIZE_ERROR
code

0x2B

description

声音抓取~渲染的初始设定失败。

5.3.7.4.31. AS_ECODE_DMAC_READ_ERROR
code

0x2C

description

Audio数据读取失败。

5.3.7.4.32. 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设定

5.3.7.4.33. AS_ECODE_SIMPLE_FIFO_UNDERFLOW
code

0x2F

description

Audio播放开始时,作为ES缓存使用的SimpleFIFO下溢出。
播放开始后AudioSubSystem会立即从SimpleFIFO读取ES数据,开始解码
应用程序需要在播放开始前放入ES数据。

diag cff12f4d33aaa04dc7fd94c53ebcf0c1
5.3.7.4.34. AS_ECODE_SET_MIC_GAIN_ERROR
code

0x30

description

麦克风输入的增益设定值有误。
模拟麦克风和数字麦克风设定的值域时不同的。

参数相关请参考以下文件。

Initialize Mic Gain

5.3.7.4.35. AS_ECODE_SET_OUTPUT_SELECT_ERROR
code

0x32

description

指定的输出端设定有误。

InitOutputSelect

5.3.7.4.36. AS_ECODE_INIT_CLEAR_STEREO_ERROR
code

0x33

description

发生Clear Stereo的设定错误。

5.3.7.4.37. AS_ECODE_SET_VOLUME_ERROR
code

0x34

description

指定的播放音量有误。
音量的设定值有限制的。参数的细节请参考如下文件。

Set Volume

5.3.7.4.38. AS_ECODE_SET_VOLUME_MUTE_ERROR
code

0x35

description

AudioDriver的音量设定失败。

5.3.7.4.39. AS_ECODE_SET_BEEP_ERROR
code

0x36

description

指定的蜂鸣音参数有误。
音量→频率的设定值有限制的,参数的细节请参考如下文件。

5.3.7.4.40. AS_ECODE_QUEUE_OPERATION_ERROR
code

0x37

description

AudioSubSystem内部队列操作(push, pop)发生错误。

5.3.7.4.41. AS_ECODE_COMMAND_PARAM_RENDERINGCLK
code

0x39

description

HiReso模式设定的参数错误。
可以设定的参数请参考如下文件。

SetRenderingClock

5.3.7.4.42. 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
5.3.7.5. Attention Code List

"Attention Code" 的详细如下。

5.3.7.5.1. AS_ATTENTION_SUB_CODE_DMA_UNDERFLOW
Code

0x01

Attention Level

ERROR

Description

DMA传输发生下溢出。
发往DMA的传输要求可能迟于DMA的数据传输速度。 或者DMA传输已经被停止。
DMA的传输速度,一般模式下为48000帧/秒、HiReso模式下为192000帧/秒。

Error Handling

此错误发生时,应用程序任务处理可能比实时处理优先。
请试着重新考虑各任务的优先度。

5.3.7.5.2. AS_ATTENTION_SUB_CODE_DMA_OVERFLOW
Code

0x02

Attention Level

ERROR

Description

DMA传输发生上溢出。
发往DMA的传输要求可能快于DMA的数据传输速度。
或者DMA传输未开始。

DMA的传输速度,一般模式下为48000帧/秒、HiReso模式下为192000帧/秒。

Error Handling

另外,记录动作时,HW提供的Audio的主时钟可能停止了。请确认时钟是否正确提供了? 播放动作时发生的话,请确认时钟是否正确发送了。

5.3.7.5.3. AS_ATTENTION_SUB_CODE_DMA_ERROR
Code

0x03

Attention Level

FATAL, ERROR

Description

DMA硬件应答为错误。
可能在发送DMA传输要求前要求了传输开始。

Error Handling

一般不会发生的错误。
可能SDK内部有故障。。

5.3.7.5.4. AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_UNDERFLOW
Code

0x05

Attention Level

WARNING

Description

AudioPlayer动作中SimpleFIFO发生下溢出。
SimpleFIFO用于应用程序向AudioSubSystem传输ES数据的缓存。
应用程序跟不上AudioSubSystem读取数据的速度。

Error Handling

请调整任务优先度使应用程序来得及提供数据给缓存,
增加缓存尺寸使数据来得及放入等。

5.3.7.5.5. AS_ATTENTION_SUB_CODE_SIMPLE_FIFO_OVERFLOW
Code

0x06

Attention Level

WARNING

Description

AudioRecorder动作中SimpleFIFO发生上溢出。
SimpleFIFO用于AudioSubSystem向应用程序传输EncodedES数据的缓存。
应用程序跟不上AudioSubSystem放入数据的速度。

Error Handling

请调整任务优先度使应用程序来得及读出数据,
增加缓存尺寸使数据来得及读出等。

5.3.7.5.6. AS_ATTENTION_SUB_CODE_ILLEGAL_REQUEST
Code

0x07

Attention Level

ERROR

Description

AudioSubSystem的内部接收到不正确的事件。
控制流程可能异常。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.7. AS_ATTENTION_SUB_CODE_INTERNAL_STATE_ERROR
Code

0x08

Attention Level

ERROR

Description

MediaPlayer内部发生状态异常。

error handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.8. AS_ATTENTION_SUB_CODE_UNEXPECTED_PARAM
Code

0x09

Attention Level

ERROR

Description

命令参数错误。

Error Handling

请重新考虑命令参数。

5.3.7.5.9. AS_ATTENTION_SUB_CODE_QUEUE_POP_ERROR
Code

0x0A

Attention Level

ERROR

Description

内部队列发生POP错误。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.10. AS_ATTENTION_SUB_CODE_QUEUE_PUSH_ERROR
Code

0x0B

Attention Level

ERROR

Description

内部队列发生PUSH错误。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.11. AS_ATTENTION_SUB_CODE_QUEUE_MISSING_ERROR
Code

0x0C

Attention Level

ERROR

Description

内部队列无意中被清空。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.12. AS_ATTENTION_SUB_CODE_MEMHANDLE_ALLOC_ERROR
Code

0x0D

Attention Level

ERROR

Description

存储句柄获取失败。
全部的存储句柄被用掉了,或者句柄的ID有错。

Error Handling

存储句柄的段数不够的场合请重新考虑存储池的设定。
设定方法请参考以下文件。(以AudioPlayer为例)+
Player的MemoryPool概要
Player的MemoyPool概要

5.3.7.5.13. AS_ATTENTION_SUB_CODE_MEMHANDLE_FREE_ERROR
Code

0x0E

Attention Level

ERROR

Description

存储句柄释放失败。
打算释放的句柄可能已经被释放了。

Error Dandling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.14. 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.
5.3.7.5.15. AS_ATTENTION_SUB_CODE_RESOURCE_ERROR
Code

0x10

Attention Level

ERROR

Description

AudioSubSystem内使用的实例的生成/删除失败。
Object/Component的CreateAPI, DeleteAPI可能发生了2重调用。
或者有可能Head区域不足。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.16. AS_ATTENTION_SUB_CODE_DSP_LOAD_ERROR
Code

0x12

Attention Level

ERROR

Description

DSP二进制加载失败。
指定DSP二进制文件的目录路径可能不存在。

Error Handling

请确认文件是否存在,或者重新指定目录路径。
目录路径的指定请参考如下文件。

AudioPlayer 为 初始化播放器
AudioRecorder 为 初始化录音器

5.3.7.5.17. AS_ATTENTION_SUB_CODE_DSP_UNLOAD_ERROR
Code

0x13

Attention Level

ERROR

Description

DSP卸载失败。 可能已经卸载了,或者原先就未被加载。

Error handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.18. AS_ATTENTION_SUB_CODE_DSP_EXEC_ERROR
Code

0x14

Attention Level

ERROR, WARNING

Description

DSP处理执行时发生错误。
虽然不会立即影响AudioSubSystem的动作,
可能会导致解码/编码/过滤器结果不正常。
(可能导致短时的声音紊乱,数据丢失。)

Error Handling

播放时的话,有可能是Audio数据是坏的。
请确认Audio数据。

5.3.7.5.19. AS_ATTENTION_SUB_CODE_DSP_ILLEGAL_REPLY
code

0x16

Attention Level

ERROR

Description

DSP发出的应答命令包坏了。

Error handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.20. AS_ATTENTION_SUB_CODE_DSP_VERSION_ERROR
Code

0x18

Attention Level

ERROR

Description

DSP发生版本错误。DSP无法加载。

Error Handling

请使用SDK包中的DSP二进制。
DSP二进制在 sdk/modules/audio/dsp 里面。

5.3.7.5.21. AS_ATTENTION_SUB_CODE_BASEBAND_ERROR
Code

0x19

Attention Level

ERROR

Description

Audio Driver发生寄存器设定错误。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.5.22. AS_ATTENTION_SUB_CODE_STREAM_PARSER_ERROR
Code

0x1A

Attention Level

ERROR

Description

AudioPlayer发生ES数据的解析错误。
初始化播放器 中设定的参数和ES数据解析结果不一致。

Error Handling

请确认传输到AudioSubSystem的ES数据是否有错,是否坏了。

5.3.7.5.23. AS_ATTENTION_SUB_CODE_DSP_LOG_ALLOC_ERROR
Code

0x1E

Attention Level

ERROR

Description

DSP日志用缓存获取失败。
启动复数各DSP时可能会发生日志用缓存容量不够。

Error Handling

DSP日志用区域可以通过应用程序或者配置文件设定。
另外,DSP日志不需要的话可以通过配置文件关闭日志功能。

cd sdk
cd tools/config.py -k -m
[Audio Utilities]
  [Audio component menu]
    [dsp debug dump] <- Set to "No".
5.3.7.5.24. AS_ATTENTION_SUB_CODE_DSP_ASSETION_FAIL
Code

0x1F

Attention Level

ERROR

Description

DSP内部发生错误处理无法继续。

Error Handling

需要系统重置。

5.3.7.5.25. AS_ATTENTION_SUB_CODE_DSP_SEND_ERROR
Code

0x20

Attention Level

ERROR

Description

向DSP发送命令出错。

Error Handling

一般不会发生的错误。
SDK内部可能有故障。

5.3.7.6. Module ID List

AudioSubSystem内部使用模块的ID一览。
和状态码一起由Attention回调通知,可以据此判断哪个模块发生了错误。

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.

5.3.8. 图书馆

音频子系统需要以下库:


5.4. Camera

5.4.1. 简介

CXD5602 具有一个8位并行Camera I/F,并且可以连接具有该I/F的相机模块。目前,Spresense 通过Sony ISX012支持相机模块。 除了数据接口之外,相机模块通常还具有用于控制模块的接口。在ISX012中,I2C用于控制I/F。 以下是硬件配置的概述。

camera hw overview
图表 43. Camra HW Overview

在 CXD5602 中,有一个名为CISIF的Camera I/F模块,该模块桥接8位并行信号和 CXD5602 内部总线。除了用于ISX012摄像机模块之外,还使用I2C总线进行控制。

本章概述了如何使用 Spresense SDK 控制连接到此相机I/F的相机模块。

Spresense SDK Camera控件提供的驱动程序I/F与Linux熟悉的V4L2非常相似,因此可以轻松地从V4L2代码转移。此I/F称为V4S(视频显示)。V4S提供了一个API,该API无需使用设备(例如ISX012),通过设备文件使用打开,关闭和ioctl之类的标准I/F,即可抽象为照相机的功能。

camera v4s overview
图表 44. V4S 软件浏览

V4S提供了两个用于摄像机控制的虚拟视频流。 在这两个虚拟流中,一个充当用于处理电影(例如“摄像机预览”图像)的流,另一个充当用于获取静止图像的流。

camera v4s dataflow
图表 45. V4S 数据流

要从应用程序获取这两个流的数据,可以通过使用VIDIOC_QBUF在驱动程序中设置应用程序准备的缓冲区,并使用VIDIOC_DQBUF设置VIDIOC_QBUF设置的缓冲区来检索图像数据。

应用程序提供的缓冲区必须是使用memalign()获得的32位对齐方式。

每个流由 v4l2_buf_typeV4L2_BUF_TYPE_VIDEO_CAPTURE 处理视频,而 V4L2_BUF_TYPE_STILL_CAPTURE 支持静态图像流。

V4L2_BUF_TYPE_STILL_CAPTURE 是V4S特定的参数。

从初始化V4S到捕获图像数据的一般流程如下:

diag a00acb00cc4c9d6fe1c833146e10468b
图表 46. V4S 序列图概览

5.4.2. 状态转移

状态是为每个流管理的,可以从应用程序并行控制。 但是,V4L2_BUF_TYPE_STILL_CAPTURE控件被赋予用于图像获取的优先级,并且V4L2_BUF_TYPE_VIDEO_CAPTURE侧的图像获取在VIDIOC_TAKEPICT_START和VIDIOC_TAKEPICT_STOP之间停止(状态转换图中不是“dma”状态)。

diag 399c5422633c90d9f58f3becf41bd00d

5.4.3. V4S支持ioctl命令

表格 23. V4S支持ioctl命令
类别 命令 功能 Spresense定制

缓冲区控制

VIDIOC_REQBUFS

执行驱动程序缓冲区管理区域的初始设置。

添加参数“ v4l2_buf_mode模式 ” 缓冲区组设计为具有RING结构。

VIDIOC_QBUF

排队应用程序提供的缓冲区。

符合V4L2

VIDIOC_DQBUF

使包含图像数据的缓冲区出队。

符合V4L2

VIDIOC_CANCEL_DQBUF

取消VIDIOC_DQBUF。

Spresense原始命令已添加到左侧。

流控制

VIDIOC_STREAMON

开始直播。

符合V4L2

VIDIOC_STREAMOFF

停止播放。

符合V4L2

VIDIOC_TAKEPICT_START

开始拍摄静态影像

Spresense原始命令已添加到左侧。

VIDIOC_TAKEPICT_STOP

静止画撮影停止

Spresense原始命令已添加到左侧。

检查框架设置范围

VIDIOC_ENUM_FMT

检查摄像头设备支持的像素格式

符合V4L2

VIDIOC_ENUM_FRAMESIZES

检查相机设备支持的图像尺寸

将V4l2_buf_type添加到该参数,以便可以为每个流确认该参数。

VIDIOC_ENUM_FRAMEINTERVALS

检查摄像头设备支持的帧间隔

将V4l2_buf_type添加到该参数,以便可以为每个流确认该参数。

VIDIOC_TRY_FMT

检查是否可以设置IN参数中指定的像素格式和图像尺寸的组合。

符合V4L2

更改框架设置

VIDIOC_S_FMT

设置像素格式和图像尺寸。

符合V4L2

VIDIOC_S_PARM

设置帧间隔(可以指定小数分子和分母)。

符合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原始命令以简化应用程序中的半按控制。

5.4.4. ISX012原始规格

5.4.4.1. JPEG + YUV4:2:2格式

在ioctl(VIDIOC_S_FMT)中

  • 将参数pixelformat设置为V4L2_PIX_FMT_JPEG_WITH_SUBIMG

  • 参数subimg_pixelformat中的V4L2_PIX_FMT_UYVY

通过设置,可以同时以JPEG和YUV4:2:2两种数据格式获取一帧图像。

例如,您可以实现一个应用程序,在不使用JPEG解码器的情况下拍摄照片并将其保存为JPEG时显示与保存的图像相同的图像。

但是,与单独获取每种格式相比,对图像大小和帧速率的限制更加严格。

diag c25f72fe2a2fa4e91246c472be29732e
图表 47. JPEG + YUV4:2:2格式

5.4.5. 图像尺寸和帧速率的限制

可以通过VIDIOC_S_FMT设置的图像大小与可以通过VIDIOC_S_PARM设置的帧间隔(帧速率的倒数)之间存在关系。
(如果增加图像尺寸,则不能设置较大的帧速率。)

下面显示了每种像素格式对Spresense + ISX012的支持范围。 在ISX012中可以设置的帧速率采用离散值,并且可以设置七种类型的120 / 60 / 30 / 15 / 7.5 / 6 / 5。
在下图中,例如,对于YUV 4:2:2格式

  • QVGA及以下:最大FPS=120,因此可以设置7种120FPS至5FPS

  • 大于QVGA:最大FPS=60,因此可以设置从60FPS到5FPS的6种类型

という制約になります。

diag e20be42c17fe936f4b3ca31aee2cb114
图表 48. YUV4:2:可设置的2种格式的图像尺寸和最大帧速率
diag 2d164fbd359fa17a6c4988de576bdaef
图表 49. JPEG格式的图像尺寸和最大可配置帧率
diag 1415c4a641b352130a344b6b54cad2cc
图表 50. JPEG + YUV4:2:2格式JPEG图像大小和最大可配置帧率

在JPEG + YUV4; 2; 2格式中,YUV422图像大小支持从96x64到WQVGA(400x240) 在此范围内,帧速率约束将不受影响。

5.4.6. 示例代码


5.5. DNN 运行态

5.5.1. DNN 运行态简介

DNN运行时库(dnnrt)可以使用从索尼提供的神经网络库或神经网络控制台(NNC)学习的模型,使用深度神经网络(DNN)执行识别处理。

为了使用DNN运行时执行识别处理,必须预先使用NNC创建训练后的模型(nnb文件格式)。 有关如何创建训练模型的信息,请参见外部 网络模型的准备

dnnrt overview cn
图表 51. DNN 运行态简介

有关神经网络库和神经网络控制台的信息,请参见下面的官方网站。

DNN运行时库使用NNabla C运行态。

5.5.2. 示例代码

该示例代码是一个示例代码,用于通过执行使用 网络模型的准备 中的 image_recognition.MNIST.LeNet 创建的学习模型来执行手写字符识别。

image_recognition.MNIST.LeNet 创建的学习模型将28x28大小的图像作为输入并输出10个数组。这10个数组表示由索引识别的数字,并且输出该数组中每个数字的概率。例如,在阵列的顶部(索引0)输出输入图像为数字“0”的概率。

有关详细细腻,请参考 DNNRT 示例 README

diag 5d6a115741cc83949996cdb8e91e35aa
图表 52. DNNRT操作顺序

5.6. GNSS

GNSS库提供了接收GPS/GLONASS卫星信号并计算当前位置的功能。 要使用此功能,您需要为GNSS安装天线。 Spresense 板上有一个芯片天线,因此不需要其他天线。

5.6.1. 主要特点

  • 除GPS/GLONASS外,还支持可以从QZSS(Michibiki)卫星系统接收信号的Multi GNSS

  • 可用SBAS(WAAS)和QZSS L1S进行定位加固

  • 由于应用程序核心和GNSS核心是分开的,因此可以独立执行定位和通知。

  • 支持Geofence

这些功能是POSIX兼容的设备文件,可以从应用程序进行操作。 设备文件为 “/dev/gps”,可以使用open(),close(),read(),seek(),ioctl()进行操作。

NuttX RTOS ioctl具有三个参数。 对于GNSS设备文件,第二个参数“req”是GNSS命令,第三个参数“arg”是in/out data传递。

5.6.2. 配置

要使用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”。 根据测试环境设置EXAMPLE_GNSS_FACTORY_SVID。 如果要直接运行工厂测试,请将[Application entry point]更改为“gnss_factory_test”。 测试结果(cn和多普勒)是数值的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'

有关详细信息,请参见以下自述文件。 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轮询或信号将定位结果通知应用程序。 可以通过以下配置设置可以轮询的号码。默认情况下,轮询数为4,信号数为3。 有关更多详细信息,请参考 定位计算通知

[System Type]
  [CXD56xx Peripheral Support]
    [GNSS setting]
      [GNSS max poll waiters] = 4
      [GNSS max signal receivers] = 3

5.6.3. 设备控制

GNSS库通过ioctl()控制。

ioctl命令使用IOCTL_前缀定义。 GNSS设备文件可以同时从多个应用程序open()。 但是,GNSS设备一次仅接受一个IOCTL命令。换句话说,这并不意味着哪个应用程序具有优先权,它会按照被接受的顺序进行处理。

5.6.3.1. 启动

您可以使用 CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM 设置在启动时使用哪个卫星系统。定位间隔用 CXD56_GNSS_IOCTL_SET_OPE_MODE 设置。

对于“热启动”(“Hot Start”),您需要设置最新的位置和时间。有关详细信息,请参阅 GNSS 备份数据 中的 “Warm Start和Hot Start”设置。

5.6.3.2. 开始定位

您可以使用 CXD56_GNSS_IOCTL_START 指定“启动模式”。

接下来的初始位置计算时间TTFF是参考值。这取决于您的系统和环境。
启动模式 IOCTL 命令参数 TTFF (*1) 备注

Cold Start

CXD56_GNSS_STMOD_COLD

> 45 sec

所有定位数据,时间和卫星轨道信息将被删除,下一次启动将从卫星采集开始。

Warm Start

CXD56_GNSS_STMOD_WARM

> 20 sec

开始使用最新的定位数据,时间和年历(卫星的粗轨道信息)。不使用星历(详细的卫星轨道信息)。

Hot Start

CXD56_GNSS_STMOD_HOT

>= 1 sec

开始使用最新的定位数据,时间和年历(卫星的粗轨道信息)。不使用星历(详细的卫星轨道信息)。

(*1) 初始位置计算时间 (Time To First Fix)

即使是“Warm Start”或“Hot Start”,如果自上一次操作以来已经过去了很长时间,并且卫星轨道信息已过期且已过期,则GNSS设备将以与“Cold Start”相同的方式获取卫星。

5.6.3.3. 停止定位

使用 CXD56_GNSS_IOCTL_STOP 停止定位。停止需要200到300毫秒。

5.6.3.4. 定位计算通知

通知有两种类型:poll和信号。

使用轮询时,可以使用 CONFIG_CXD56_GNSS_NPOLLWAITERS 设置poll次数。

如果使用信号,则将 cxd56_gnss_signal_setting_s 数据(字段描述符设置为GNSS设备文件描述符),enable设置为1,signo设置为任何信号编号,并将gnsssig设置为 CXD56_GNSS_SIG_GNSS , 调用ioctl函数作为IOCTRL命令 CXD56_GNSS_IOCTL_SIGNAL_SET 的参数,以将信号与定位通知相关联。

应用程序可以使用sigwaitinfo接收通知作为信号。 如果不再需要该信号,则可以通过在CXD56_GNSS_IOCTL_SIGNAL_SET启用字段中将 cxd56_gnss_signal_setting_s 数据设置为0来清除关联。 可以通过配置中的CONFIG_CXD56_GNSS_NSIGNALRECEIVERS更改最大信号关联数。

可以在 gnss应用程序示例程序 中找到设置了CONFIG_EXAMPLES_GNSS_USE_SIGNAL的示例。

5.6.4. 关于快速定位

为了通过“Hot Start”缩短TTFF,最快的方法是使用卫星轨道信息和备份数据中包含的其他信息。 使用ioctl命令显示使用备份数据的标准“Hot Start”过程。

diag 0859fec2f1f6d08bd01409199cd4b183
图表 53. Standard flow for hot start using backupdata
5.6.4.1. GNSS 备份数据

当通过“Hot Start”开始定位时,将使用备份数据中包含的最终定位位置,星历表,历书和TCXO时钟偏移值。 可以使用ioctl命令将备份数据存储在闪存中。在这种情况下,即使电源关闭,在下次启动时也会从闪存扩展到SRAM,并可用于“Hot Start”。

5.6.4.1.1. 电源状况和备份数据

随着系统的运行,GNSS定位正在工作,并且所有相关信息都已存储。当系统处于“Hot Sleep”状态时,SRAM数据将保留并且RTC保持运行,因此可以通过“Hot Start”开始定位。在“Deep Sleep”状态下,RTC继续运行,但是SRAM已关闭,因此有必要恢复和使用闪存中保存的备份数据进行“Hot Start”。

5.6.4.1.2. 保存备份数据

使用ioctl命令 CXD56_GNSS_IOCTL_SAVE_BACKUP_DATA 将备份数据保存到闪存等。备份数据以CONFIG_CXD56_GNSS_BACKUP_FILENAME中指定的文件名保存。   但是,如果您频繁写入闪存,则可能会导致内存故障。例如,在系统关闭时保存它。

5.6.4.1.3. 无效备份数据

在极少数情况下,保存的备份数据可能会损坏。在这种情况下,数据恢复将失败,并显示校验和错误,并且定位将从“Cold Start”开始。

5.6.4.1.4. 过期数据

如果星历或年历已过期,这些数据将被忽略。在这种情况下,这将等同于“Cold Start”,因此TTFF将更长。开始定位后,在接收到来自卫星的最新星历和年历时进行备份数据卫星轨道信息也将被覆盖。

5.6.4.2. GPS 时间

要执行“Hot Start”,GNSS设备的当前时间必须在60秒内。如果之前进行过定位并且未关闭系统,则将RTC_GPS设置为上次定位时设置的时间。接通电源后,RTC_GPS的值立即未定义,因此有必要使用应用程序中的ioctl命令设置时间。

5.6.4.2.1. RTC_GPS 精度

当定位停止时,GNSS设备会将LSI中的RTC时钟精度计时器RTC_GPS更新为GPS时间。 停止定位后,GNSS设备的时钟停止,并且该RTC_GPS保持时间。 RTC_GPS时间与实时时间之间的误差取决于外部RTC Xtal的时钟精度。 GNSS设备在恢复定位时会根据RTC_GPS时间执行定位计算,因此停止时间越长,RTC_GPS时间相对于实时的误差就越大,这会影响TTFF和初始定位位置的准确性。 从定位停止位置超过15分钟后,对于后续的“Hot Start”定位结果,RTC_GPS时间错误将无法忽略。 如果即使在较长的定位停止时间后仍需要较短的TTFF或较高的初始位置精度,则可以考虑使用ioctl命令设置时间。

打开系统后,RTC_GPS会立即显示“ 0h 6 - Jan - 1980”。RTC_GPS设置为GPS时间,因为在完成定位后可以获取GPS时间。除非指定时间,否则定位计算基于RTC_GPS。

5.6.4.2.2. 通过命令设置时间

使用ioctl命令 CXD56_GNSS_IOCTL_SET_TIME 指定应用程序从网络获取的时间。

5.6.4.3. 当前位置

对于“Hot Start”,需要最新的位置数据。如果应用程序没有位置数据,则GNSS设备将基于先前测量的位置信息执行“Hot Start”。

5.6.4.3.1. 通过命令设置位置

当指定应用程序从网络获取的位置信息时,请使用ioctl命令 CXD56_GNSS_IOCTL_SET_RECEIVER_POSITION_ELLIPSOIDALCXD56_GNSS_IOCTL_SET_RECEIVER_POSITION_ORTHOGONAL

5.6.5. 位置准确性

为了进行准确的定位,需要在适当的接收条件下进行定位。从定位数据可以在某种程度上估计定位环境是否不影响高精度定位,例如建筑物中卫星的不可见性,大型建筑物的反射波的影响以及WIFI的噪声。

5.6.5.1. 接收器定位数据中的含义
5.6.5.1.1. Field numsv, numsv_tracking, numsv_calcpos, numsv_calcvel
Type

uint8_t

Unit

none

字段numsv,numsv_tracking,numsv_calcpos和numsv_calcvel分别是可见卫星数,跟踪卫星数,用于位置计算的卫星数和用于速度计算的卫星数。 可见卫星包括根据卫星轨道信息预计会存在于当前天空中的卫星,但实际上它们被遮挡了并且没有接收到信号。 在跟踪卫星中,接收到的信号较弱且精度不高的信号未用于定位或速度计算。 位置精度取决于信号强度和后述的卫星配置,因此不能无条件地进行说明,但是,通常,如果将numsv_calcpos的数量保持在6以上,则通常会发生几米的误差而继续进行定位。

5.6.5.1.2. 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(精度稀释),DOP是根据卫星的几何排列计算得出的位置精度的下降速率。 'p’是整体精度下降率,'h’是水平精度下降率,'v’是垂直精度下降率,'ew’是东西方精度下降率,'ns’是南北精度指示下降率。

DOP越小,位置越好。例如,在城市之类的狭窄天空中,几乎无法接收到卫星,并且DOP变得更糟。 如果pDOP超过5,则表示该条件不适合定位。另一方面,如果pDOP为2或更小,则该条件足以用于定位。

5.6.5.1.3. 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的恶化等都会给定位结果带来误差。该值越大,定位数据越不准确。

5.6.5.2. 卫星定位数据的含义
5.6.5.2.1. Field sigLevel of struct cxd56_gnss_sv_s
Type

float

Sub fields

none

Unit

dBHz

该值表示C/N0比率(或有时称为CN0,CN),它是来自卫星的信号强度与噪声的比率。 由于来自GNSS卫星的信号是扩频信号,因此称为C/N0比,而不是S/N比,单位为dBHz。 该值越大,来自GNSS的卫星信号的可靠性越高,结果,使用它的定位将是稳定的。 另一方面,噪声源在GNSS天线附近,卫星方向与天线方向性差的方向一致,或者卫星与天线之间存在障碍物,卫星信号的跟踪性差。 该值变小并且定位变得不稳定。

5.6.5.3. 多 GNSS

如上所述,存在随着捕获和跟踪的卫星数量的增加而提高定位精度的趋势。 GNSS设备可以同时使用多个卫星系统,以增加用于定位计算的卫星信号数量。

  • GLONASS

    俄罗斯定位卫星系统,有24架飞机像GPS一样覆盖全世界。 当GPS足够时,如果使用70m GLONASS系统信号执行定位计算,则定位精度可能会低于单独的GPS,这低于GPS系统标准精度20m。 请注意,某些天线不支持GLONASS频率。

  • QZSS-L1C/A

    日本发送的卫星信号。 由于此信号与GPS L1C/A兼容,因此使用它似乎使GPS卫星的数量增加了。这被Michibiki称为GPS补充功能。 Michibiki有4架飞机(截至2018年),其航迹涵盖了东亚和大洋洲,主要在日本,因此在其他地区没有补充作用。

5.6.5.4. 增强

使用WAAS或Michibiki的QZSS-L1S发送的增强信号可以提高定位精度。 加固信号是基于SBAS格式的计算参数,可提高每隔几分钟更新一次的定位计算的准确性。 使用增强信号时,无法使用没有增强信息的GLONASS进行定位。

  • WAAS

    WAAS是美国大陆、加拿大、夏威夷和各省的有效加固信号。 提高了GPS卫星信号所需的伪距离(卫星与接收器之间的距离)的精度。

  • QZSS-L1S

    QZSS-L1S仅在日本有效。 提高GPS卫星信号和QZSS-L1C/A所需的伪距精度(卫星与接收器之间的距离)。 低仰角卫星(截至2018年9月,仰角屏蔽为20度)将不会接收到增强信息,也无法用于定位。

5.6.5.5. 选择定位和增强卫星系统

在该GNSS设备中,假定使用以下定位卫星系统和增强信号的组合来执行定位。 您可以设置与 CXD56_GNSS_IOCTL_SELECT_SATELLITE_SYSTEM 一起使用的卫星系统。

以下定位误差(精度)是一般条件下的参考值。它取决于您的系统和环境。
GPS GLONASS QZSS-L1C/A WAAS QZSS-L1S 95% 准确率 有效区域

x

<5m

天空下

x

x

<5m

东亚和大洋洲

x

x

<7.8m

城市

x

x

x

<7.8m

东亚和大洋洲的城市

x

x

x

<2m

日本

5.6.6. 发送短信

GNSS设备可以接收灾难(灾难/危机)报告,例如从QZSS Michibiki发送的灾难信息和危机管理信息。

通过将信号通知设置为GNSS设备,应用程序可以异步接收来自GNSS设备的灾难通知。 灾难通知信号通知设置为 cxd56_gnss_signal_setting_s ,在字段fd中具有GNSS设备文件描述符,enable为1,gnsssig中为任意信号号, 对于灾难通知信号通知设置,cxd56_gnss_signal_setting_s 会在字段fd中设置GNSS设备的文件描述符,将1设置为启用,将gnsssig设置为任意信号号,将 CXD56_GNSS_SIG_SBAS 设置为gnsssig时,请将ioctl函数作为一个函数调用IOCTRL命令 CXD56_GNSS_IOCTL_SIGNAL_SET 的自变量,将信号与灾难报告相关联。

GNSS设备收到SBAS消息类型43(气象局防灾信息)或44(可选信息)时,它会发出关联的信号。 在sigwaitinfo信号处理中,可以通过读取 cxd56_gnss_sbasdata_sCXD56_GNSS_READ_OFFSET_SBAS 作为数据缓冲区中的偏移量来读取引起通知的SBAS消息。

5.6.7. 功能使用

5.6.7.1. NMEA 转换器

NMEA是广泛用于GPS应用程序中的位置信息文本格式,并且gnss库还支持NMEA格式输出。

要使用它,必须将CONFIG_MLIB设置为 'y' 。 将存储在 cxd56_gnss_sv_s 中的GNSS设备的内容转换为NMEA。

有关详细信息,请参见 gnss_nmeaNMEA 输出

5.6.8. 地理围栏

5.6.8.1. 重要特性

Geofence是一个图书馆,可在您靠近指定区域时通知您。

  • 可以通过纬度、经度、半径指定区域

  • 您最多可以指定20个区域

geofence notification
图表 54. Geofence transition notification

通知共有三种类型:“ENTER”、“DWELL”和“EXIT”。在“DWELL”的情况下,您还可以设置停留时间的通知条件。

5.6.8.2. 配置

使用Geofence时,将GNSS设备和Geofence支持指定为 'y' 。

[System Type]
  CXD56xx Peripheral Support -->
    [*] GNSS device
    [*]   Geofence Support
5.6.8.3. 添加区域和设置选项

要使用Geofence,请使用“/dev/geofence”设备文件。

5.6.8.3.1. CXD56_GEOFENCE_IOCTL_ADD

添加区域的命令。

最多可以设置20个区域。每个区域均可设置纬度、经度和半径。

北纬和东经方向为 '+' 。南纬和西经方向是 '-' 。

5.6.8.3.2. CXD56_GEOFENCE_IOCTL_SET_MODE

必须将CONFIG_CXD56_GNSS设置为“y”才能使用S函数。

5.6.8.4. 状态转换
Geofence 状态转换
图表 55. Geofence 状态转换
5.6.8.5. 盲区

盲区是指由定义的区域半径(半径)定义的同心区域。

  • 如果定义了“ENTER”,则进入同心区域时将通知您

  • 如果定义了“EXIT”,当您退出同心区域时,它将通知您

Geofence 盲区
图表 56. Geofence 盲区
5.6.8.6. 读取地理围栏传送的数据

状态更改通过投票通知。 状态转换信息存储在 cxd56_geofence_status_s 中。

有关更多信息,请参见应用程序样本 Geofencing 迁移

5.6.9. PVTLog 打印输出

5.6.9.1. 主要特性

PVTLog是有关位置,速度和时间的信息的日志。

最多可以累积170个日志。如果日志溢出,可以通过信号通知应用程序。 例如,如果每15分钟获取一次日志,则可以连续记录42个小时。

有关日志数据的详细信息,请参考 cxd56_pvtlog_s

5.6.9.2. 配置

要使用PVTLog,请将GNSS设备支持设置为 'y' 。

[System Type]
  CXD56xx Peripheral Support -->
    [*] GNSS device
5.6.9.3. 开始和停止存储日志

要开始记录,可以使用ioctl命令 CXD56_GNSS_IOCTL_PVTLOG_START 也可以使用此命令记录间隔。

日志记录间隔必须大于定位间隔。

定位开始时,日志自动开始。要停止记录,请使用ioctl命令 CXD56_GNSS_IOCTL_PVTLOG_STOP

5.6.9.4. 通知

如果您记录的日志超过170条,则会有一个信号通知应用程序该日志已溢出。 信号配置可以用 CXD56_GNSS_SIG_PVTLOG 完成。

收到此通知时,必须先阅读日志,然后再进行下一次记录。否则,第一个日志数据将被下一个定位数据覆盖。

可以从由 CXD56_GNSS_READ_OFFSET_PVTLOG 指定偏移量的位置读取日志数据。

日志数据记录在备份RAM中。 如果数据已经存在,将被覆盖而不会被擦除。 使用 CXD56_GNSS_IOCTL_PVTLOG_DELETE_LOG 清理备份。

有关详细信息,请参见示例程序 PVTLog 打印输出

5.6.10. 应用程序示例

5.6.10.1. 定位通知

GNSS定位的通知通过轮询和信号完成。您可以在Kconfig中选择CONFIG_EXAMPLES_GNSS_USE_SIGNAL或CONFIG_EXAMPLES_GNSS_USE_POLL。

5.6.10.3. 引言

gnss_atcmd是在Spresense SDK上运行的GNSS功能评估的示例应用程序。 当从主机(例如PC)通过串行端口发送命令时,NMEA语句结果将输出到该串行端口。后面将描述特定的命令规范和应用程序使用示例。

5.6.10.4. @Command规范

描述从主机发送的命令的规范。

s_atcmd应用程序接收从主机(例如PC)发送的命令,并将处理结果返回给主机。从命令发送到响应的期间,不输出NMEA。nss_atcmd应用程序响应消息,指示命令完成返回消息(“Done”或“Err”)之前,请勿发出其他命令。 从命令发送到返回命令响应的时间取决于命令类型和当时的状态,但是在最坏的情况下可能需要5秒钟。当主机控制器检测到超时时,请确定超时为5秒。

5.6.10.4.1. 命令格式

命令格式如下。在“@”(符号后)后发送命令字符串或参数,并在末尾发送换行代码。

@Command [Argument0] [Argument1]...<CR><LF>
Command

字符串,最多4个字符。 有关详细信息,请参见下表 命令清单

Argument

以十进制表示的数字值。 如果字符串以“0x”开头,则表示一个十六进制数。 有些命令带有多个参数。

<CR><LF>

表示换行代码。以CR(回车)+ LF(换行)结束命令行。

5.6.10.4.2. 普通回复格式

正常响应结果的格式如下。在[发送命令字符串]之后,返回“Done”字符串。

[Command] Done<CR><LF>
Command

代表收到的命令字符串。

<CR><LF>

代表换行。在响应行的末尾添加了CR(回车)+ LF(换行)。

5.6.10.4.3. 错误响应格式

错误响应结果的格式如下。在[发送命令字符串]之后,返回“Err”字符串和错误代码。

[Command] Err ErrorCode<CR><LF>
Command

代表收到的命令字符串。

ErrorCode

代表负错误代码。

<CR><LF>

代表换行。在响应行的末尾添加了CR(回车)+ LF(换行)。

5.6.10.4.4. 命令顺序

当发出定位开始命令(例如@GCD)时,在返回“Done”响应之后,会定期向主机发送NMEA语句。

diag e7b6c6dbd2cce5b431b8535ccdf4e672

发出@VER命令时,将发送版本信息,并返回“Done”响应。

diag aecaf2c20740a1432f3725e6be277c10
5.6.10.4.5. 命令清单

gnss_atcmd可以处理的命令列表如下所示。

命令 参数 描述

@AEXT

-

退出申请。 定位停止时执行此命令。

@BSSL

NMEA输出掩码

在NMEA 0183(版本4.00)标准中定义的NMEA语句中, 要输出的NMEA语句被指定为具有位掩码值的自变量。 最初,NMEA掩码设置为0xef。

NMEA 描述

$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

卫星

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

-

返回所有零的版本号。

5.6.10.5. 应用程序操作示例

gnss_atcmd应用程序的操作示例如下所示。

5.6.10.5.1. 配置

要运行此应用程序,请启用以下SDK配置。

CONFIG_CXD56_GNSS=y
CONFIG_GPSUTILS_CXD56NMEA_LIB=y
CONFIG_EXAMPLES_GNSS_ATCMD=y

您可以通过执行以下命令来自动启用这些配置。

./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应用程序后,从终端输入以上命令。

5.6.10.5.2. 示例:通过Cold Start开始和停止定位

选择GPS、Glonass和QZSS L1C/A作为定位卫星,然后从Cold Start开始定位。 之后,输出NMEA语句,经过一段适当的时间后,停止定位并终止gnss_atcmd。

nsh> gnss_atcmd       (开始申请)
@GNS 0x0b↵         (定位卫星选择)
@GCD↵             (Cold Start开始定位)

----- <NMEA输出> ----

@GSTP↵            (停止定位)
@AEXT↵           (申请终止)
nsh>

5.6.10.5.3. 示例:GNSS结束后的热启动定位

首先,选择GPS,Glonass和QZSS L1C/A作为定位卫星,然后使用Cold Start开始定位。 定位后,在保持Spresense功率的同时终止GNSS,并通过Hot Start再次启动定位。 在Hot Start中,定位将在开始定位后几秒钟固定。

nsh> gnss_atcmd       (开始申请)
@GNS 0x0b↵         (选择定位卫星)
@GCD↵             (Cold Start开始定位)

----- <NMEA输出> ----

@GSTP↵            (停止定位)
@AEXT↵           (申请终止)

nsh> gnss_atcmd       (开始申请)
@GSR↵             (Hot Start开始定位)

----- <NMEA出力> ----

@GSTP↵           (停止定位)
@AEXT↵           (终止申请)
nsh>

5.6.10.5.4. 示例:Spresense电源关闭后的Hot Start定位

首先,选择GPS、Glonass和QZSS L1C/A作为定位卫星,然后使用冷启动开始定位。 之后,退出GNSS后关闭Spresense电源。

再次打开Spresense后,输入UTC时间和当前位置,并通过Hot Start开始定位。 在Hot Start中,定位将在开始定位后几秒钟固定。

nsh> gnss_atcmd       (开始申请)
@GNS 0x0b↵         (选择定位卫星)
@GCD↵             (Cold Start定位开始)

----- <NMEA输出> ----

@GSTP↵            (停止定位)
@BUP↵              (备份到闪存)
@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>

5.6.10.5.5. 准天顶卫星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
…​

5.6.10.6. Geofencing 迁移
5.6.10.7. PVTLog 日志输出

5.7. ASMP 框架

5.7.1. ASMP 框架简介

ASMP是准备好轻松处理多核处理器的框架。

此框架中定义了两个任务。

  • Supervisor任务 (主CPU任务)

  • Worker任务 (副CPU任务)

diag c4534bd31de8be84c88a5b2bb7d3bfc7
图表 57. ASMP框架图

主管任务使用ASMP框架API来控制辅助任务的启动和停止。 详细信息,请参考 多核任务

Worker任务是完全独立于主CPU并在副CPU上并行处理的任务。因此,需要一种通信方法来在任务之间交换数据和状态。

ASMP框架为Supervisor任务和Worker任务的通信任务提供以下功能。

多核消息队列 是类似于POSIX消息队列的消息交换接口。

diag d2717059fdc2bcbb3223b39c19a30144
图表 58. 多核消息队列

多核互斥锁 提供了类似于pthread互斥锁的独占控制机制。

diag e14bf772ca9c7d753d2e5553217419ec
图表 59. 多核互斥锁

多核共享内存 提供了每个任务共享的存储区域。

diag bbeb95a67ff807e65635e69b7ab7b9b1
图表 60. 多核共享内存

5.7.2. 配置

[ASMP] = Y
  [ASMP shared memory size]  = 0x100000

ASMP框架要求内核管理之外的内存区域用于任务之间的共享内存。可以使用 ASMP shared memory size 选项进行更改。如果您不需要ASMP框架,则内核可以利用1.5MB的内存。

以128KB为单位设置 ASMP Shared memory size 设置(0x20000)。

5.7.3. Worker 启动顺序

diag 23ec4d8e910d986725caaa06adbbc73f
图表 61. Worker 启动顺序
  1. 调用 mptask_init 创建一个Worker程序

  2. 根据需要准备消息队列,共享内存等,并将其链接到Worker程序

  3. 调用 mptask_exec 运行Worker程序

  4. 完成后,调用 mptask_destroy 停止Worker程序

  5. 如果已创建消息队列或共享内存,则将其丢弃

有关详细信息,请参考 Supervisor任务示例Worker Task示例

5.7.4. 创建 Worker

Worker任务加载并执行ELF格式文件。但是,由于Worker在副CPU上运行,因此无法直接调用内核和SDK API。

ASMP框架支持的ELF文件布局如下。

diag d1ca866e2680ce3dc99cf576a184d309
图表 62. Worker的ELF文件布局

每个程序的起始地址必须为 0x00000000 ,并且每个部分都必须是连续的。 SDK提供了为Worker生成ELF文件所需的编译器选项,链接器选项和链接器脚本。 这些在 sdk/Make.defs 中分别定义为 CELFFLAGSLDRAWELFFLAGS 。有关特定的构建规则,请参考 ASMP Worker任务 'Hello World' 示例

此外,需要一个Worker程序库才能将ASMP框架与Worker一起使用。该库包含配置工作程序所需的代码(上图中的蓝色部分)。但是,由于未在SDK生成序列中准备此库,因此用户必须在生成工作程序之前先生成它。

有关如何生成Worker程序库的示例,请参考 Worker Task MakefileWorker Task Library Makefile

5.7.5. 示例代码


5.8. 传感器控制单元

5.8.1. 概览

传感器控制单元(SCU)可以从连接到SCU设备中SPI或I2C总线的传感器设备获取传感数据。

主要特点
  • 通过定序器自动获取传感器数据

  • 传感器数据稀疏功能(抽取器)

  • IIR滤波器功能

  • 事件通知功能

可以从应用程序中设置这些功能。

SCU具有SPI,两个I2C总线,八个定序器和两个抽取器。

diag a66a2aee7a119a9117ae56bdfd03ac90
图表 63. SCU 块图

5.8.2. 配置

  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 音序器采样预分频器会影响音序器采样率
2 SCU时钟模式指定SCU工作时钟
3 SCU32K时钟源可以选择采样频率(32768Hz)时钟源
4 可以将一个SCU抽取器分配给两个以上的传感器,但是最多可以将两个传感器分配给抽取器。

5.8.3. 音序器

SCU有两种类型的音序器。普通定序器定期获取传感器数据并将其存储在FIFO中。设备驱动程序从此FIFO获取数据。

diag c1785ba91bc9f1ad5a61bda8b03d2997
图表 64. 音序器块图

每个定序器的FIFO被划分为 SCUIOC_SETFIFO 指定的大小。FIFO内存总计40KB。在使用设备驱动程序之前,必须先设置应用程序。

ret = ioctl(fd, SCUIOC_SETFIFO, sizeof(struct three_axis_s) * 128);

定序器以采样率指定的间隔获取传感器数据。请注意,采样率不是由传感器设备规格决定的。应用程序将`doxygen:SCUIOC_SETSA发送给定序器必须在使用MPLE []使用采样率之前进行设置。 在使用采样率之前,必须使用 SCUIOC_SETSAMPLE 为音序器配置应用程序。

ret = ioctl(fd, SCUIOC_SETSAMPLE, 2);

SCUIOC_SETSAMPLE 指定基本时钟(32KHz)除以2的幂。

Sequencer sampling rate = 32768 / CONFIG_CXD56_SCU_PREDIV / (2 ^ n)

如果 CONFIG_CXD56_SCU_PREDIV 是默认值64,并且在 SCUIOC_SETSAMPLE 中指定了2,则采样率为128Hz。

应用程序应注意,定序器采样率与传感器规格中指定的采样率不同。该应用程序设置传感器设备的采样率和音序器,您需要确保比赛顺利进行。

该应用程序可以接收由 SCUIOC_SETWATERMARK 定义的信号。当传感器数据存储到定序器FIFO中,直到达到 watermark 中指定的数量时,SCU驱动程序就会向应用程序发出信号。

例如,如果应用程序将采样率设置为128 Hz,而 watermark 设置为128,则设备驱动程序将每秒发出一个信号。

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 结构中。

5.8.4. 抽取器

提供抽取器以通过稀疏FIFO中获取的数据来扩展定序器功能。抽取器具有三个FIFO。

diag 0b3cd224d7ba24a3341d235eafb78bcc
图表 65. 抽取器块图
5.8.4.1. 抽取处理

抽取器应用CIC滤波器来稀疏音序器获取的数据。 应用程序可以使用 doxygen: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的幂以提取采样率指定的数据。 例如,如果采样率为64 Hz,并且_ratio_为1,(64 /(2 ^ 1)),则实际采样率为32 Hz。 注意,CIC过滤器应用于采样数据。 如果您不想使用CIC筛选器,请将_forcethrough_设置为1。

5.8.4.2. 采集数据的放大

抽取器可以使用 decimation_s 结构中的_leveladj_放大获取的数据。 放大后的数据将超过原始数据的宽度,因此使用时必须小心。

_leveladj_可以如下设置。

5.8.4.3. 抽取器支持的传感器

使用抽取器时,传感器驱动器必须兼容。当前支持的传感器驱动程序是:

  • KX022

  • BMI1422GMV

5.8.5. 传感器数据的信号处理

SCU可以将信号处理添加到采集的数据中。 SCU可以执行两种类型的信号处理:IIR滤波器和事件检测。 IIR滤波器可以在数据路径上的三个位置设置。 必须为要使用的每个FIFO进行设置。

5.8.5.1. IIR 滤波器
diag ad9db3a7d27d9a0f8bdd7ae0a7ff047d
图表 66. IIR 过滤路径
A

适用于FIFO和事件检测器

F

仅适用于FIFO

E

仅提供给事件检测器(Event Detector)

该应用程序可以设置两个IIR滤波器。FIFO是定序器FIFO或抽取器FIFO。事件检测是一项特殊功能,如下所述:

IIR滤波器的组合
  • 两者都适用(A)

  • (A)并适用于(F)

  • (A)并适用于(E)

  • 两者都适用(F)

  • 适用于(F)和(E)

  • 两者都适用(E)

IIR过滤器设置在 filter_pos_e 中定义。 IIR滤波器可以调整一个因子。

IIR 过滤器块图
图表 67. IIR filter block diagram

每个系数均为34位固定点,s2.31格式。因此,IIR滤波器的系数由32位(h)和8位(l)组成。

struct_iir_coeff_s
图表 68. struct iir_coeff_s h, l

31位_h_为S(带符号位)。,0 =加号,1 =减号。

30至29位_h_是整数部分。

十进制部分是从28到0的_H_和7到6位的_l_。

5.8.5.2. 事件检测(Event detector)

事件检测器(Event detector)监视传感器数据的状态并检测其中的变化。该应用程序将能够确定何时应采集传感器。

事件检测对超过阈值定义的传感器数据宽度的数量进行计数。可用于事件检测的传感器数据为16位。例如,如果获取的数据是每个XYZ轴的数据,则在进行归一化计算后,确定数据是否超过设定值。 当计数达到设定值时,事件检测器将生成一个带时间戳的中断。

归一化计算取决于要监视的数据数(1-3)。

  • 如果是一个(例如,仅X轴):

  norm = abs(x)
  • 如果有两个(例如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 结构配置事件检测。 有两个设置_rise_和_fall_,分别具有_threshold_、_ count0_和_count1_。 当计数的数据达到_count0_ + _count1_时,事件检测器会通知应用程序。

事件检测器使用IIR滤波器的输出,因此必须首先设置IIR滤波器。

scu event
图表 69. Event detection
事件检测过程
  • 计数值超过阈值

  • 当计数达到_count0_时,启动_count1_。

  • 如果数据数量在达到_count0_之前降至阈值以下,则停止计数并重置计数。

  • 达到总数_count0_ + _count1_时通知事件

  • 如果_count1_为零,则一旦_count0_的值达到阈值,便会通知一个事件。

  • 如果_count0_为零,则忽略所有设置

5.8.6. 限制条件

以下限制适用于抽取器,IIR滤波器和事件检测器可以处理的数据。

  • 一个采样数据是16位

  • 多达3个数据元素

5.8.7. 驱动程序开发人员指南

要开发支持SCU功能的驱动程序,您需要了解以下内容:

  • 了解音序器指令

  • 与传感器装置的通信方法

  • 如何连接定序器初始化(Open)和传感器驱动程序

  • 从定序器中读取样本数据

  • 如何通过ioctl命令音序器

5.8.7.1. 了解音序器指令

定序器指令为每条指令16位,并使用SPI或I2C总线与传感器设备进行通信。

开发驱动程序时,可以使用 doxygen:SCU_INST_SEND[]doxygen:SCU_INST_RECV[] 宏。

通过定序器发送和接收数据时,存储并设置一系列指令,这些指令在uinit16_t数组中设置发送和接收方法。在发送和接收结束时,您需要指定 SCU_INST_LAST 以指示发送已完成。

指令数组的简单示例
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
5.8.7.2. 与传感器装置的通信方法

首先,驾驶员必须初始化目标传感器设备。支持SCU功能的驱动程序需要使用 scu_spitransferscu_i2ctransfer 来访问传感器设备寄存器。

比如: 注册写权限函数
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和传感器驱动程序,则直接连接到SCU的SPI和I2C总线可能会导致冲突。设备驱动程序开发人员应仅通过提供的API访问设备。
5.8.7.3. 如何连接定序器初始化(Open)和传感器驱动程序

支持SCU的驱动程序将在所有操作中处理定序器对象。每个驱动程序必须保留此对象。

g_seq = seq_open(MAG_SEQ_TYPE, SCU_BUS_I2C0);
if (!g_seq)
  {
    return -ENOENT;
  }
priv->seq = g_seq;

在此示例中,打开定序器并将其存储在设备数据中。

可以从三个FIFO中读取抽取器,因此会生成三个设备文件。

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() API支持SCU睡眠功能。 在实现 open()close() 时,驱动程序开发人员应在调用这些API的同时控制传感器设备的电源模式。 结果,该系统可以实现更多的节能。

5.8.7.4. 从定序器中读取样本数据

当定序器读取传感器数据时,设置一系列定序器指令以使用 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中。

使用 seq_read() 函数从FIFO读取累积的传感器数据。

len = seq_read(priv->seq, priv->id, buffer, len);
5.8.7.5. 如何通过ioctl命令音序器

由于SCU没有设备文件,因此传感器驱动程序必须进行中介,才能在SCU上执行 ioctl() 。 为此,请在每个驱动程序的 ioctl() 中调用 seq_ioctl() 。 使用 _SCUIOCVALID() 宏来确定它是否为SCU IO命令。

e.g.
if (_SCUIOCVALID(cmd))
{
  /* Redirect SCU commands */
  ret = seq_ioctl(priv->seq, priv->id, cmd, arg);
}

5.9. 内存使用库

5.9.1. 概要

媒体处理和传感器处理功能中,需要对数据用的大量存储空间进行安全的,没有碎片泄露之类的管理。因此,在Spresense中提供了内存实用程序库。

程序库包含”Memory Manager” 、"Message Library"、"Simple FIFO"三个库。

  • ”Memory Manager” 是为了在 Multi task 间安全地管理存储空间, 隐含地进行段区间管理的固定长度内存池库。

  • "Message Library" 是为了使用 ”Memory Manager” ,使类对象在任务间通信用的库。

  • "Simple FIFO" 是为了应用程序和框架间进行数据传输用的最基本的FIFO。

这些库的使用是媒体出来和传感器处理的前提。 详细请参考以下各章。

5.9.2. 内存管理

”Memory Manager” 的说明。

5.9.2.1. 概要

”Memory Manager" 为隐含地对获取和释放进行管理的固定长度内存库。 根据用途定义内存空间为内存池,并在其中确保需要的段,来完成需要使用内存的获取和释放。

确定池的种类,段数等进行内存空间的分配,可以防止内存空间的碎片化。 这个分配信息称作 "memory_layout" ,根据应用程序的需求切换这个布局,来确保功能所需的内存。

这个内存布局可以根据应用程序自由确定及生成。生成方法记录在 配置及生成 里。

可以通过生成 "MemHandle" 并调用段分配API取得所需的 "memory segment" 。此方法分配的段,在 "MemHandle" 的实例被废弃前一直有效。
多用户异步分别的 "MemHandle",即使有用户释放,此空间还将保持,直到所有用户不用时才被释放。

5.9.2.2. 段的获取和释放机制

各用户对象通过生成指向所需内存空间段的MemHandle,调用段区间获取API,确保相关的内存段。

此时,段空间参考计数器+1。 由此,该段空间为使用状态,确保不会被其他要求使用。

Get memHandle

该引用计数器,在 "operator=" 及 "Copy Constructor" 中也做+1操作。

由此,拷贝并传递此 "MemHandle" 的实例给数据管道中的下一个对象, 对象可以引用 "MemHandle" 绑定的段,确保这个空间。

Copy memHandle

相反,不需要空间时,废弃 "MemHandle" 的实例,在析构函数中参考计数器-1。
由此,所有的引用实例废弃后,链接的段会被自动释放。

Use memHandle

这种机制使得所需的对象对各自的内存进行异步确保所需的对象间实例,不用时即使根据各自的时间废弃,也可以安全地分配和释放内存。无需特别关注,在所有的用户废弃实例后,将默认断开所有引用。

Release memHandle

关于Memory Layout,使用前需要事先准备相关头文件群。 这些头文件由Memory Layout定义文件(mem_layout.conf)作成,通过专用工具(mem_layout.py)生成。

5.9.2.3. APIs

”Memory Manager"的界面如下。 详细请参考 memutils_memory_manager

5.9.2.3.1. 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,用来以byte单位指定lib_area的大小。
尺寸小于sizeof(MemMgrLite::Manager)时,返回ERR_DATA_SIZE。
当前的实装所需的尺寸为 (4 + 4 * NUM_MEM_POOLS) ,所有最小12bytes,
最大1028bytes。
//可选项中使用动态创建池的场合,作为追加要求,(8 + 5 * NUM_DYN_POOLS)需要四舍五入为4的倍数。

//此库支持多核(共享池)时,该空间
必须是所有CPU都可访问。
//ARM的TCM,MPS的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时,返回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个来源)*/
返回值
参考说明
说明
isPoolAvailable()返回当下的内存布局指定的池ID是否有效。

getPoolType(), getPoolAddr(), getPoolSize(), getPoolNumSegs()分别返回
在创建时指定的池类别,地址,大小,段数。

getPoolNumAvailSegs()返回目前的空段数。

isPoolFenceEnable()返回创建池的时候指定的围栏设定。
本函数仅在围栏功能有效时(UseFence = True)被定义。

//getPoolSpinLockId()返回创建池的时候指定的旋转锁ID。
//本函数仅在多核支持有效时(UseMultiCore = True)被定义。

指定为无效的池会发生访问空指针的问题,
请确认池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
  }
5.9.2.3.2. 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"。
5.9.2.4. 配置及生成

介绍如何编写和创建 ”Memory Manager” 的Layout文件。

Layout信息,通过MemoryLayout定义文件 "mem_layout.conf" (文件名可变。) 中由Python编写的 "mem_layout.py" 工具,从C++言語的3个头文件, "mem_layout.h" "fixed_fence.h" "pool_layout.h" 创建而成。 用户程序只要包含此头文件,就可以使用 ”Memory Manager” 。

5.9.2.4.1. 如何编写内存布局文件

"mem_layout.conf"用来进行”Memory Manager”配置,用户常量的定义,设备的定义,PoolLayout的定义。各功能如下说明。

”Memory Manager”的配置

指定是否使用 ”Memory Manager” 各种功能。可以指定的功能和指定方法如下。 .

特性 描述

UseFence

使用True/False指定是否使用围栏。 启用后,将定义USE_MEMMGR_FENCE宏,并在指定区域之前和之后4个字节 配置栅栏以进行覆写检测。 另外,定义了围栏检查API。

规格示例
UseFence = True  # Use of a pool fence
用户常量的定义

MemoryLayout定义文件中使用的常量,可以定义为以"U_"开头的用户自定义名称。 另外,定义可以是任意的Python表达式。

用户定义常量的描述示例
  # 为了和脚本内的定义不重复,以"U_"开头,并仅使用英文大写字母,数字和"_"
  # 如果定义以“ U_MEM_”开头的名称,则具有相同名称的宏将输出到头文件中

  U_STD_ALIGN   = 8     # standard alignment
  U_MSGQ_ALIGN  = 64    # message queue area alignment
Memory设备定义

定义各种存储设备。这些定义用于定义固定区域。 它作为name_ADDR宏和name_SIZE宏输出到头文件。

存储设备定义描述示例
MemoryDevices.init(
  # name         ram    addr        size
  ["AUD_SRAM",   True,  0x000c0000, 0x00040000],
  None # end of definition
)

每个参数的说明如下。

参数 说明

name

设备名称(3个或更多字符。以大写字母开头,并且可以使用大写字母,数字和“ _”)

ram

如果设备是RAM,则为True。 否则为False。

addr

该区域的地址。 指定的值是4的整数倍,但0除外。

size

区域的大小。 指定的值是4的整数倍,但0除外。

定义固定区域

为每个存储设备定义一个区域。 每个区域的起始地址由每个设备的累积大小,对齐和围墙确定。
它作为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
  None # end of definition
)

每个参数的说明如下。

参数 说明

name

区域名称(名称以大写字母开头,以“ AREA”结尾。可以使用大写字母,数字和

device

用于保护区域的MemoryDevices的设备名称

align

该区域的起始对齐方式。指定MinAlign的倍数(= 4),不包括0。

size

区域的大小。 指定的值是4的整数倍,但0除外。

fence

指定是启用还是禁用围栏。(如果UseFence为False,则忽略此项目)

PoolLayout的定义

定义内存池的布局。 每个池区域的起始地址由每个固定区域的累积大小,对齐和围墙确定。
在头文件中,输出池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 ],
    None # 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 ],
    None # end of each layout
  ], # end of layout 1

  None # end of definition
)

在单独的区域中最多可以定义3个内存池。

为音频定义PoolLayout和为Sensor定义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

# Sensor
U_SENSOR_DSP_CMD_SIZE       = 0x300
U_SENSOR_DSP_CMD_SEG_NUM    = 8
U_SENSOR_DSP_CMD_POOL_SIZE  = U_SENSOR_DSP_CMD_SIZE  * U_SENSOR_DSP_CMD_SEG_NUM

U_SENSOR_DATA_BUF_SIZE      = 0x300
U_SENSOR_DATA_BUF_SEG_NUM   = 8
U_SENSOR_DATA_BUF_POOL_SIZE = U_SENSOR_DATA_BUF_SIZE * U_SENSOR_DATA_BUF_SEG_NUM

# section 0
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 ],
    None # 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 ],
    None # end of each layout
  ], # end of layout 1

  None # end of definition
)

# section 1
PoolAreas.init(
  [ # layout 0 for Sensor
    #[ name,                    area,               align,       pool-size,                   seg,                        fence]
    ["SENSOR_DSP_CMD_BUF_POOL", "COMMON_WORK_AREA", U_STD_ALIGN, U_SENSOR_DSP_CMD_POOL_SIZE,  U_SENSOR_DSP_CMD_SEG_NUM,   False],
    ["SENSOR_DATA_BUF_POOL",    "COMMON_WORK_AREA", U_STD_ALIGN, U_SENSOR_DATA_BUF_POOL_SIZE, U_SENSOR_DATA_BUF_SEG_NUM,  False],
    None # end of each layout
  ], # end of layout 0

  None # end of definition
)

每个参数的说明如下。

参数名 说明

name

池名称(以大写字母开头,以“POOL”结尾。可以使用大写字母,数字和

area

FixedArea区域名称用作池区域。将区域放在RAM中。

align

池的起始对齐方式。指定MinAlign的倍数(= 4),不包括0。

pool-size

游泳池的大小。该值是4的整数倍,但0除外。段大小*段数。

seg

段数。指定一个介于1和255之间的值。

fence

指定是启用还是禁用围栏。如果UseFence为False,则忽略此项目。

5.9.2.4.2. 生成方式

使用“mem_layout.py”创建布局文件的方法如下。

python3 mem_layout.conf layout_header fence_header pool_header

Ex) python3 mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

“mem_layout.py”的每个参数的说明如下。

表格 24. 布局文件创建工具参数
参数 描述

mem_layout.conf

内存布局定义文件

layout_header

头文件,其中各种常量值作为宏输出。为了调整内存大小,将以注释格式输出每个布局的剩余可用大小(/*剩余XXXX_AREA = 0xXXXXXXXX */)。

fence_header

输出FixedArea的内存防护地址的头文件。该文件由“内存管理器”使用,用户不应使用。

pool_header

输出PoolArea的各种定义的头文件。该文件由“内存管理器”使用,用户不应使用。

5.9.3. 消息库

主要是,当需要在任务之间(例如“Memory Manager”)发送和接收类实例时,通常无法处理OS提供的系统调用,因此可以使用“Message Library”来实现。 本节介绍此“Message Library”。

5.9.3.1. 常用

“Message Library”是一个任务同步库,可以在任务之间发送和接收类实例。

该库发送显式指定为ID的目的地。 接收器还等待传输事件并执行事件驱动的操作。

Message Sequence

另外,该消息具有类型,并且由类型来判断以确定接收到的实例是否存在。

但是,您要发送和接收的类必须正确实现复制构造函数。
5.9.3.2. 消息编号及类型
5.9.3.2.1. 消息编号

Message ID是根据下面的 如何编写消息内存布局文件 的配置静态创建的。 有关配置的详细信息,请参阅该内容。

确认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和要回复的ret_id ID,创建要发送的类(对象)的实例,然后使用MsgLib::send发送它。

该ID是根据应用程序创建的,并且在显式指定用于发送和接收的数据路径时使用。

5.9.3.2.2. 消息类型

消息库使用Message Type来确定发送了什么对象,以便从接收到的Message Packet中检索适当的实例。 因此,消息类型被添加到所有消息包。

此Message Type在“sdk/modules/include/memutils/message/message_type.h”中定义。

Message Type采用以下数据结构。

diag 788d4c0f09923d010e16c0d729677b6e

每个字段的说明如下。

参数名 值域 说明

REQ

[15]

指示消息是请求还是响应。0是响应,1是请求。

MSG_USER

[14-12]

消息的用户信息。您可以指定一个使用消息的系统,该消息的值介于0到7之间。但是,由于AudioSubSystem保留了6个,SensorSubSystem保留了7个,因此实际上可以使用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

指定使用该消息的系统。 当前,音频和传感器ID被保留。

D14-D12 描述

0-5

保留

6

Audio 子系统

7

Sensor 子系统

MSG_CATEGORY

请在每个系统中自由定义。

例如,对于音频,
"sdk/modules/include/audio/audio_message_types.h"

对于传感器
"sdk/modules/include/sensing/sensor_message_types.h"

定义于。

MSG_SUB_TYPE

请在每个系统中自由定义。

例如,对于音频
sdk/modules/audio/include/commmon/audio_interanl_message_types.h

对于传感器
sdk/modules/include/sensing/sensor_message_types.h

定义于。

如果消息类型是不同的ID,则即使定义了相同的值,也可以对其进行操作,但是它易于调试,可更改性(例如更改数据路径和发送到另一个ID)等。确保所有内容都是唯一的。

使用以下实现从Message Packet中提取实例。

  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.

  }
5.9.3.3. 接口

“Message Library”的界面如下。 有关详细信息,请参考 memutils_message

5.9.3.3.1. 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。

endIsr()指定了共享队列,则执行ASSERT。
这是为了防止自旋锁在非任务上下文中等待。
消息接收通知
函数
static void MsgLib::notifyRecv(MsgQueId dest)
参数
MsgQueId    dest  : 通知目标消息队列ID
返回值
说明
通知收到其他CPU的消息。
假定此函数是从CPU中断处理程序调用的。
如果参数dest指示的消息队列块不存在,或者初始化尚未完成,则执行ASSERT。
5.9.3.3.2. MsgQueBlock类函数
获取对消息队列块的引用
函数
static MsgQueBlock& MsgLib::referMsgQueBlock(MsgQueId id)
参数
MsgQueId    id  : 消息队列ID
返回值
消息队列块参考
说明
获取对消息队列块的引用。
如果参数id指示的消息队列块不存在,或者初始化尚未完成,则执行ASSERT。
消息包接收
函数
MsgPacket* MsgQueBlock::recv(uint32_t ms)
参数
uint32_t  ms : 接收等待时间(毫秒)或TIME_POLLING或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。
5.9.3.3.3. MsgPacket类函数
获取消息类型ID
函数
MsgType MsgPacket::getType() const
参数
返回值
消息编号
说明
获取消息包的类型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()用于与传输时具有相同类型的引用,而peepkParamOther()
用于与传输时具有不同类型的引用(例如,参数标头类型)。

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,消息参数长度将更改为零。
请注意,消息参数的引用和指针无效。
5.9.3.4. 配置及生成

本节介绍如何创建和创建“Message Library”布局文件。

布局信息用Python编写在“ msgq_layout.conf”中(可以更改名称) 带有两个C++标头的名为“ msgq_layout.py”的工具。 生成“msgq_id.h” 、 “msgq_pool.h”。 用户可以通过包含此标头来使用“Message Library”。

5.9.3.4.1. 如何编写消息内存布局文件

“msgq_layout.conf”定义“Message Library”的用户常数,消息队列池,调试值和消息参数检查。每个说明如下所示。

定义用户常数

可以将以“ U_”开头的用户定义名称分配给消息布局定义文件中使用的常量。该定义可以是任何Python表达式。

用户定义的常量描述示例
  # 用户定义的常数必须具有以“ U_”开头的大写字母和数字名称
  # 如果使用以“U_MSGQ_”开头的名称进行定义,则该名称也将作为定义宏在msgq_id.h中输出。

  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],
  None # end of user definition
] # end of MsgQuePool

每个参数的说明如下。

参数 说明

ID

使用以“ MSGQ_”开头的字符串指定消息队列池ID的名称。“MSGQ_NULL”、“MSGQ_TOP”、“MSGQ_END”已保留,无法使用。

n_size

正常优先级队列的每个元素中的字节数(8到512)。 指定固定的标头长度(8个字节)+参数长度(4的倍数)。

n_num

正常优先级队列中的元素数(1到16384)。

h_size

高优先级队列的每个元素中的字节数(0或8到512)。不使用时,请指定0。

h_num

高优先级队列中的元素数(0或1到16384)。不使用时指定0。

尽管有调试值和消息参数检查规范,但不要使用它们。
MsgFillValueAfterPop = 0x00
MsgParamTypeMatchCheck = False
5.9.3.4.2. 生成方式

使用“msgq_layout.py”创建布局文件的方法如下。

python3 msgq_layout.conf start_addr size id_header pool_header

Ex) python3 msgq_layout.conf 0x000fe000 0x1000 msgq_id.h msgq_pool.h

“msgq_layout.py”的每个参数的说明如下。

表格 25. Layout文件创建工具参数
参数 描述

msgq_layout.conf

消息队列布局定义文件

start_addr

留言区地址

size

区域大小(以字节为单位)

id_header

消息队列ID宏输出到的文件

pool_header

输出消息队列池定义的文件

5.9.3.4.3. 顺序
diag 1184ee41e1f6914d2f42275e8bcdd35f

5.9.4. 简单 FIFO

5.9.4.1. 常用

Simple FIFO 该库支持单写和单读访问,无需任何独占控制。 需要某些独占访问控制才能支持此库之外的多写入器/读取器。

该库支持从多处理器进行的访问,插入适当的数据同步屏障和数据内存屏障。 为此,请确保更新数据内容和WP/RP的顺序。

5.9.4.2. 接口

有关详细信息,请参见Doxygen。 API列表如下。

表格 26. SimpleFIFO API 概览
API 名称 描述

CMN_SimpleFifoInitialize

SimpleFIFO初始化。设置用于FIFO的存储区。

CMN_SimpleFifoOffer

将数据推入FIFO。使用memcpy()进行复制处理。

CMN_SimpleFifoOfferWithSpecificCopier

将数据推入FIFO。复制过程由用户准备。假定使用DMA复制。

CMN_SimpleFifoOfferContinuous

将数据推入FIFO。将指定的尺寸复制到连续区域。如果没有连续的区域用于指定的大小,则不执行推送。使用memcpy()进行复制处理。

CMN_SimpleFifoOfferContinuousWithSpecificCopier

将数据推入FIFO。将指定的尺寸复制到连续区域。如果没有连续的区域用于指定的大小,则不执行推送。复制过程由用户准备。假定使用DMA复制。

CMN_SimpleFifoPoll

从FIFO弹出数据。弹出的数据从FIFO中删除。使用memcpy()进行复制处理。

CMN_SimpleFifoPollWithSpecificCopier

从FIFO弹出数据。弹出的数据从FIFO中删除。复制过程由用户准备。假定使用DMA复制。

CMN_SimpleFifoPeekWithOffset

从FIFO的开头从指定的偏移量获取指定大小的数据的地址信息。当您想引用FIFO数据而不删除它时,请使用它。

CMN_SimpleFifoPeek

从FIFO的开头获取指定大小数据的地址信息。当您想引用FIFO数据而不删除它时,请使用它。

CMN_SimpleFifoClear

清除FIFO读/写指针,使其为空。

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复制。

5.9.4.3. 顺序

简单FIFO简单序列。

diag c1eba8e7bc91e90d7bc69dfcf3e9a774

5.9.5. 代码示例

这些库与音频功能一起使用。 因此,他们的样本是音频样本。

  • examples/audio_player

  • examples/audio_recorder


5.10. 电源管理

5.10.1. 概览

Power Management 是执行电源管理以实现节能的模块,这是 Spresense SDK 的功能。 CXD5602 管理内部电源域和时钟,并支持各种睡眠模式。

5.10.2. 电源状态

Spresense SDK支持三种睡眠模式: Deep SleepCold SleepHot Sleep 以节省电量。

Deep Sleep

在CXD5602中,所有电源域都被关闭,只有CXD5247 PMIC(电源管理IC)通电。 此时,CXD5247也处于休眠状态,并且可以将功耗降至最低。

Cold Sleep

仅CXD5602中的最小必需电源域为上电。与 Deep Sleep 相比,例如警报计时器、USB插入/提取、GPIO信号更改等。

Hot Sleep

当OS处于空闲状态时,过渡到此睡眠状态。由于在休眠期间保持SRAM状态,因此唤醒时无需从SPI-Flash重新加载程序,因此您可以快速从休眠状态返回。

当前的SDK版本不支持热睡眠。
5.10.2.1. 电源状态转换

主要电源状态的状态转换图如下所示。

电源状态图
图表 70. Power State Diagram
状态 描述

PowerOff

包括CXD5247 PMIC(电源管理IC)在内的所有电源都已关闭

Battery Check

正在监视电源电压电平。 CXD5602 在电源为3.4V或更高时启动,并转换为“运行”状态。

Run

正常执行状态。

Idle

操作系统空闲。OS空闲任务等待WFI的中断(等待中断)。

Hot Sleep

当OS空闲状态预计将持续一定时间时,将进入此状态。 在Hot Sleep期间,SRAM数据将保留。

Cold Sleep

仅打开CXD5602的最低必需电源,并且关闭其他电源(包括SRAM)。

Deep Sleep

CXD5602断电,只有CXD5247 PMIC(电源管理IC)上电。

5.10.2.2. 电源域层次结构

CXD5602芯片分为具有分层结构的几个电源域。 各种休眠模式与电源域之间的关系如下所示。

电源域层次图

5.10.3. 电源状态控制 API

Spresense SDK具有来自各种电源状态的启动因子(以下称为 boot cause )和用于控制许可/禁止启动因子的启动掩码( boot mask )。

boot cause

代表起床和从各种睡眠模式开始的因素

boot mask

控制启用/禁用激活因子

boot causeboot mask 具有通用的位标志结构,并且每个引导原因都由一位表示。当 boot mask 的相应位设置为1时,将其作为引导因子使能;而当设置为0时,将其禁用。 当 boot mask 允许的激活因子事件发生在Sleep状态时,从Sleep唤醒。那时,哪个引导因素反映在 boot cause 中。

激活因子和激活掩码的定义如下所示。

  • 引导类型指示系统是通过POR(上电复位)启动,通过Reboot重新启动还是从Deep Sleep或Cold Sleep状态启动。

  • 仅当是时才允许将Maskable用作激活因子。 没有人不能被禁止作为激活因素。

boot cause / boot mask Boot Type Maskable Description

PM_BOOT_POR_NORMAL

POR Boot

No

电池或电源已打开

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

(*2) 当检测到WKUPL信号时

PM_BOOT_DEEP_WKUPS

Deep Boot

Yes (*1)

检测到WKUPS信号 (*2)

PM_BOOT_DEEP_RTC

Deep Boot

Yes (*1)

发出RTC警报

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警报

PM_BOOT_COLD_RTC_ALM0

Cold Boot

Yes

RTC警报0(SDK使用警报0)

PM_BOOT_COLD_RTC_ALM1

Cold Boot

Yes

已触及RTC警告1(未使用)

PM_BOOT_COLD_RTC_ALM2

Cold Boot

Yes

触发了RTC Alarm2(未使用)

PM_BOOT_COLD_RTC_ALMERR

Cold Boot

Yes

发生RTC警报错误(未使用)

PM_BOOT_COLD_GPIO

Cold Boot

Yes

检测到GPIO中断

PM_BOOT_COLD_SEN_INT

Cold Boot

Yes

检测到传感器中断(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板上不支持。

提供以下与电源状态控制有关的电源管理API:

  • 获取激活因子

  • 获取激活掩码

  • 激活掩码启用/禁止

  • 过渡到Sleep模式

  • 重新开机

5.10.3.1. 激活因子 API
Function Prototype
uint32_t up_pm_get_bootcause(void);
Description
  • 获取激活因子

5.10.3.2. 启动掩码 API
Function Prototype
uint32_t up_pm_get_bootmask(void);
Description
  • 获取激活掩码,指示允许/禁止的激活因子

    • 默认情况下,允许所有激活因子

    • 该激活掩码值通过Deep Sleep或Power-On-Reset进行复位。 在Hot Sleep或Cold Sleep期间将保留该激活掩码值。

5.10.3.3. 激活因子权限 API
Function Prototype
uint32_t up_pm_set_bootmask(uint32_t mask);
Description
  • 启用参数中指定的激活因子

  • 返回值返回更新的激活掩码

5.10.3.4. 禁止激活因子 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
5.10.3.5. Sleep 迁移 API
Function Prototype
int up_pm_sleep(enum pm_sleepmode_e mode);
Description
  • 过渡到Sleep模式

  • 调用此函数没有任何回报,并且状态转换为休眠状态。

Arguments
模式枚举 描述

PM_SLEEP_DEEP

进入Deep Sleep

PM_SLEEP_COLD

进入Cold Sleep

通过发出up_pm_sleep(),仅CXD5602芯片就转换为睡眠模式。 当转换到Sleep状态时,可能会添加不仅取决于芯片而且取决于板子的处理。 通过在BSP的板相关部分中实现board_power_off()函数,可以转换到包括板控制在内的休眠模式。

在BSP相关部分中实现的睡眠过渡API如下所示。 也可以从NuttShell上的poweroff命令控制它。

Function Prototype
int board_power_off(int status)
Arguments
状态枚举 描述 NuttShell 命令

BOARD_POWEROFF_DEEP

将移至Deep Sleep

poweroff

BOARD_POWEROFF_COLD

将移至Cold Sleep

poweroff --cold

5.10.3.6. 重新开机
Function Prototype
int up_pm_reboot(void);
Description
  • 重新启动系统

  • 它不会从此函数调用中返回,它将重新启动

通过在BSP板相关部分中实现board_reset()函数,可以实现包括板控制在内的重启。

Function Prototype
int board_reset(int status);

board_reset()也可以通过NuttShell上的reboot命令来控制。

5.10.4. 睡眠模式

5.10.4.1. Deep Sleep
5.10.4.1.1. 特性

Deep Sleep具有以下功能。

  • CXD5602断电

  • CXD5247进入睡眠模式,并且关闭了提供给CXD5602的内核电源和IO电源

    • CXD5247保留了RTC时间(假设系统具有RTC XTAL)

    • CXD5247 GPO开关在Deep Sleep期间保持值

      • 如果在深度睡眠期间不必保持GPO处于打开状态,则从节电的角度出发,建议在进入深度睡眠之前将其关闭

    • CXD5247负载开关已关闭

    • 由于CXD5602 IO已关闭,请注意不要使电流从外围设备泄漏到CXD5602

5.10.4.1.2. 电源消耗
  • 电池末端的电池电流消耗约为uA至几uA。由于CXD5602的电源已关闭,请仔细设计电路板,以确保从外围设备到CXD5602的电流不会泄漏。

关于Sleep 的功耗,如果将SD卡插入扩展板,则电流消耗将增加约5 mA,具体取决于SD卡的功耗。
5.10.4.1.3. 睡眠状况
  • 通过调用up_pm_sleep(PM_SLEEP_DEEP)或board_poweroff(BOARD_POWEROFF_DEEP)转换为深度睡眠状态

  • 当使用WKUPL信号时,在声明WKUPL 3秒以上时转换到Deep Sleep状态

由于WKUPL引脚没有出现在Spresense板上,因此无法使用WKUPL信号将功能转换为深度睡眠
5.10.4.1.4. 唤醒条件

发生唤醒条件时,程序将以SPI-Flash加载的方式启动,因此大约需要与Power-On-Reset启动相同的时间。

  • PM_BOOT_DEEP_WKUPL : 当WKUPL信号有效3秒以上时

  • PM_BOOT_DEEP_WKUPS : 当WKUPS信号有效时

  • PM_BOOT_DEEP_RTC : 当RTC警报触发时

  • PM_BOOT_DEEP_USB_ATTACH : 连接USB电缆时

    • 通常,连接USB电缆后,您将无法进入深度睡眠状态。 但是,如果CONFIG_BOARD_USB_DISABLE_IN_DEEP_SLEEPING=y,则可以禁用USB功能并转换为Deep Sleep状态。 目前,您无法使用USB连接作为触发器来唤醒。

由于WKUPL和WKUPS端子没有出现在Spresense板上,因此无法通过WKUPL和WKUPS信号使用深度睡眠中的唤醒功能
5.10.4.2. Cold Sleep
5.10.4.2.1. 特性
  • 对于CXD5602,仅打开芯片内部的PMU电源域

    • CXD5602 I/O引脚使能

    • 备份SRAM内容将保留

  • CXD5247正常运行

    • CXD5247保留了RTC时间(假设系统具有RTC XTAL)

    • CXD5247 GPO开关在Cold Sleep期间保持其值

    • CXD5247负载开关即使在Cold Sleep期间也能保持数值

5.10.4.2.2. 电力消耗
  • 电池末端的电池电流消耗约为几百uA。

关于睡眠期间的功耗,如果将SD卡插入扩展板,则电流消耗将增加约5 mA,具体取决于SD卡的功耗。
5.10.4.2.3. 睡眠状况
  • 通过调用up_pm_sleep(PM_SLEEP_COLD)或board_poweroff(BOARD_POWEROFF_COLD)转换为冷睡眠状态

5.10.4.2.4. 唤醒条件

发生唤醒条件时,程序将以SPI-Flash加载的方式启动,因此大约需要与Power-On-Reset启动相同的时间。

  • PM_BOOT_COLD_SCU_INT : 触发SCU中断时

  • PM_BOOT_COLD_SEN_INT : 当传感器中断触发时

  • PM_BOOT_COLD_PMIC_INT : 当CXD5247的中断触发时

    • 当WKUPS信号有效时

    • 通知电池电量不足时

  • PM_BOOT_COLD_GPIO : 当GPIO中断有效时

  • PM_BOOT_COLD_RTC_ALM0 : 当RTC警报触发时

  • PM_BOOT_COLD_USB_ATTACH : 连接USB电缆时

  • PM_BOOT_COLD_USB_DETACH : 断开USB连接线时

IMPROTANT: Spresense板不支持通过USB插入/拔出从Cold Sleep中唤醒的功能

5.10.4.3. Hot Sleep
当前的SDK版本不支持Hot Sleep。
5.10.4.3.1. 特性
  • CXD5602几乎等于正常操作状态,但是运行NuttX的应用CPU已关闭电源

    • 但是,SRAM值在Hot Sleep期间会保留。

  • CXD5247正常运行

5.10.4.3.2. 电力消耗
  • 电池末端的电池电流消耗可以低至几百uA,但这在很大程度上取决于应用程序的运行情况。

5.10.4.3.3. 睡眠状况
  • 通过设置CONFIG_CXD56_HOT_SLEEP=y启用热睡眠。

    • 以下CONFIG参数可用于更改转换为热睡眠状态的条件。

      • CONFIG_CXD56_HOT_SLEEP_WAIT_COUNT(毫秒)

      • CONFIG_CXD56_HOT_SLEEP_THRESHOLD(毫秒)

    • 获取和释放唤醒锁

      • Hot Sleep控制由稍后描述的wakelock机制执行。只要获得至少一个wakelock,就禁止过渡到Hot Sleep。

电源管理器使用以下算法转换为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,则不允许系统转换为热睡眠状态

5.10.4.3.4. 唤醒条件
  • 当应用CPU发生中断时

    • UART1接收中断

    • UART2接收中断

    • SCU(传感器控制单元)水印中断

    • USB插入/提取中断

    • 来自CXD5247的中断

    • GPIO中断

    • 由于来自其他CPU的CPU间通信而中断

    • 操作系统计时器中断

5.10.5. 节电控制

Spresense SDK 提供以下节电功能。

  • CPU系统时钟控制

  • CPU睡眠控制

5.10.5.1. CPU 系统时钟控制

系统时钟提供三种主要模式。

模式 CPU 时钟 CXD5602 核电压

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

启用动态时钟控制后,以HV模式启动后,系统将时钟降至RCOSC模式。在稳定状态下,以RCOSC模式运行。

为了临时执行高性能处理,可以使用Frequency Lock动态更改时钟。

RCOSC模式,LV模式和HV模式可增加工作时钟并提高性能,但是功耗会相应增加。Frequency Lock机制在切换到LV模式时使用LV锁定,在切换到HV模式时使用HV锁定。释放获得的锁定后,将恢复原始时钟状态。 例如,如果同时获取了LV锁定和HV锁定,则会设置HV模式。 释放HV锁定后,它将切换到下一个更高的时钟模式,即LV模式。 释放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);
5.10.5.2. 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);

5.11. 传感器融合框架

5.11.1. 常见

CXD5602具有低功率恒定感测功能和具有许多内核和存储器的传感器融合功能。

SDK提供了一个框架来简化这一过程。

传感器融合框架由每个传感器的“Sensor Manager”和“Sensor Client”组成。

  • “Sensor Manager”基于Publish-Subscribe Architecture控制多个“Sensor Client”,并分发从此处发布的Sensor Data。

  • “Sensor Client”是一个“Logical Sensor”,它控制着控制各种“Sensor Device”的驱动程序,“Logical Sensro”,通过融合每个“Sensor Device”中的数据来实现高性能传感器的应用程序 包含用于接收数据的“Sensor Application”。

Sensor Framework的体系结构图如下。

Sensor Framework(Publish/subscribe) Architecture
图表 71. 传感器框架(Publish/subscribe)结构

5.11.2. 传感器管理

“传感器管理器”注册并管理多个“传感器客户端”正确分发传感器数据。 正确分发传感器数据。

5.11.2.1. 常见

在“Sensor Manager”中注册的“Sensor Client”将获取的数据启动到“Sensor Manager”,以便“Sensor Manager”将数据正确分发给“Sensor Client”并请求订阅。

它还提供了一个框架,可以关闭未订阅的“传感器客户端”的电源模式。

5.11.2.2. API 接口

“Sensor Manager”提供以下API。 “Sensor Manager”界面可控制,以称为数据包的数据格式发布命令。 注册并删除“Sensor Client”并传输数据。

表格 27. 传感器管理API
APIs 描述 对应 API 对应数据包

Register

注册传感器客户到管理者,作为订阅者。

SS_SendSensorResister

sensor_command_register_t

Release

在管理者注销传感器客户。

SS_SendSensorRelease

sensor_command_release_t

SendData

不通过MemHandle发送函数到管理者。

SS_SendSensorData

sensor_command_data_t

SendData(MH)

通过MemHandler发送函数到管理者。

SS_SendSensorDataMH

sensor_command_data_mh_t

SendSetPower

设置传感器供电状态。

SS_SendSensorSetPower

sensor_command_power_t

5.11.2.3. 顺序
diag 264c0793d5fa3663ecc483af74414779
图表 72. 传感器管理者顺序
对于MemHandle,请参阅 管理内存库

5.11.3. 逻辑传感器

5.11.3.1. 常见

“Logical Sensor”是用于基于从各种物理传感器获得的传感器数据的某种信号处理算法来创建功能强大的传感器数据的“Sensor Client”,它由软件模块组成。
实际的算法实现分配可以通过以下方式完成。

  1. 在NuttX上实现为任务。

  2. 使用asmp框架在DSP上实现。

  3. 使用供应商提供的加密DSP实施。

5.11.3.1.1. Nuttx中逻辑传感器任务

在NuttX上实现为模块或任务。
特别地,在不繁重的处理或不频繁执行的处理的情况下,通过以这种方式实现,可以在不消耗存储器和CPU资源的情况下实现。

表格 28. NuttX中逻辑传感器示例
内容 示例来源

Barometer

传感器供应商

TAP Gesture (Tapping Detector)

SDK

5.11.3.1.2. DSP在asmp上的逻辑传感器

当用户创建自己的“Logical Sensor”算法并需要将处理任务转移到DSP端(例如繁重的处理)时,请使用ASMP框架在DSP端有可能实现它。
在这种情况下,可以通过将“Logical Sensor”实现为管理任务并将处理请求从管理任务发送到DSP上的工作任务来实现多核处理中的“Logical Sensor”。

表格 29. DSP中逻辑传感器示例
内容 示例来源

""

SDK

SuperVisor and Worker
图表 73. 监视及工人角色
有关ASMP框架,请参考 ASMP 框架
DSP逻辑传感器加密

每个解决方案供应商都提供不同的logical sensor算法。在这种情况下,每个供应商都可以根据其合同等提供功能,而无需透露代码。
在这种情况下,可以通过在ASMP框架上加载构建文件和加密的二进制文件来实现。每个供应商都提供加密的DSP。

表格 30. DSP逻辑传感器加密示例
内容 示例来源

AESM (Activity Engine and Step Meter)

SDK

SuperVisor and Encrypted Worker
图表 74. 监视及加密工人角色

5.11.4. 逻辑传感器API

每个逻辑传感器都提供以下API:

表格 31. Logical Sensor API
APIs 描述

Create

创建对象来跟worker通信。

Open

加载和启动worker。

Write

发送数据到worker。

Close

销毁worker任务。

这些请求被定义为以下事件,并用于发送和接收DSP上的工作任务。
有关详细信息,请参见每个主管。

事件 描述

Init

初始化事件。

Exec

执行事件。

Flush

终止事件。

5.11.5. 各个逻辑传感器细节

5.11.6. 计步器

Step Counter 的框图如下所示。

Configuration diagram of Step Counter
图表 75. Step Counter配置图
5.11.6.1. 监视

主管是“Logical Sensor”的框架。 提供多个API来控制主管的DSP上的Worker。

5.11.6.1.1. 接口 API

Step Counter 提供以下五个API。

表格 32. Step Counter API
接口 描述 对应接口

Create

创建StepCounterClass对象。

StepCounterCreate

Open

加载StepCounter库并启动worker。

StepCounterOpen

Write

发送数据到StepCounter worker任务。

StepCounterWrite

Close

销毁StepCounter的worker任务。

StepCounterClose

Set

设置StepCounter库。

StepCounterSet

5.11.6.1.2. 计步器数据格式

“Step Counter”要求使用以下指定格式的“Accelerometer”数据。
使用Write API将这些数据发送给工作人员。

加速器数据格式
图表 76. Step Counter数据格式
5.11.6.1.3. 感应数据

“Step Counter”每秒输出以下Step Counter信息。 此信息存储在 StepCounterStepInfo

表格 33. Step Counter结果
数据 单位 备注

频率

Hz

取值范围为1到3Hz。 即使停止,该值仍为1 Hz或更高。

歩幅

cm

步行和跑步的固定值。

速度

m/s

累积移动距离

m

歩数

-

行走模式

-

指示停止/步行/跑步状态。

5.11.6.2. 使用方法
5.11.6.2.1. 准备

用于控制多个“Sensor Client”的框架称为"Sensor Manager” 控制“Step Counter”。

因此,要控制“Step Counter”,必须事先启用“Sensor Manager”。

激活传感器管理

要启用“Sensor Manager”,您需要调用 SS_ActivateSensorSubSystem(MsgQueId,api_response_callback_t)
MsgQueId必须是在消息库配置中定义的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);
注册到传感器管理

启用“Sensor Manager”后,将“Accelerometer”注册为“Step Counter”请求订阅“Sensor Manager”的“Sensor Client”。
这时,指定调用回调函数 StepCounterWrite 作为Subscribe的过程。

另外,为了使“Application”了解“Step Counter”的检测结果 将“Application”请求订阅的“Step Counter”注册为“Step Client”。
此时,请指定回调函数来处理订阅。

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 ed4255411bdcaca75955e24be60f6fae
图表 77. 注册顺序
5.11.6.2.2. 创建及打开

完成准备后,生成并启用“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*中,您需要指定一个指向“Step Counter”实例的指针,该实例是 StepCounterCreate

StepCounterOpen(step_counter_instance);
diag c4781ad5b42780790d1d378c6b75f43d
图表 78. Create and Open sequence
5.11.6.2.3. 设置步长

感测时的步幅的初始值在步行状态下为60cm,在跑步状态下为80cm。

要更改此初始值,您需要调用 StepCounterSet(FAR StepCounterClass *,StepCounterSetting *)
在StepCounterClass *中,您需要指定一个指向“Step Counter”实例的指针,该实例是 StepCounterCreate
对于StepCounterSetting *,将在步行状态和跑步状态下的步幅设置为以cm为单位的step_length。最大步幅为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 6d4244f82815bb2f67d4a11a52fd9da7
图表 79. 设置顺序
开始感应

“Step Counter”是 StepCounterWrite ,由“ Accelerometer” Subscribe调用,将数据发送到DSP上的Worker并执行传感处理。

此时的顺序如下所示。

diag d2e295d53f5bc56412ddb18bef05f264
图表 80. 加速度器发布感应数据
5.11.6.2.4. 关闭

要禁用“Step Counter”,您需要调用 StepCounterClose(FAR StepCounterClass *)
在StepCounterClass *中,您需要指定一个指向“Step Counter”实例的指针,该实例是 StepCounterCreate

StepCounterClose(step_counter_instance);
diag 457068923d2998772d6ed9f72e49a249
图表 81. 关闭顺序
5.11.6.2.5. 传感器管理释放

使“Step Counter”无效后,取消向“Sensor Manager”的注册。 在这种情况下,请先停止订阅“Step Counter”的“Sensor Client”的操作。

sensor_command_register_t reg;

rel.header.code = ReleaseClient;
rel.self        = stepcounterID;
SS_SendSensorRelease(&rel);
5.11.6.3. 编译配置

要使用“Step Counter”功能,

cd sdk
tools/config.py -m

打开配置菜单并设置以下选项。

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
5.11.6.4. 工作任务

Worker在其他内核上运行,并分析从Supervisor发送的传感器数据。
它返回所请求事件的处理结果(步骤数,状态等)。

“Step Counter”的Worker需要下面显示的数据进行分析。

・ Accelerometer数据(32Hz、32样本/1秒)
5.11.6.4.1. 接口 API

“Step Counter”的worker提供以下三个API:

表格 34. Step Counter Worker API
接口 描述

Init

为AESM(活动引擎和步数表)库初始化。

Exec

对AESM库中的传感器数据执行计算。

Flush

结束AESM库的执行过程。

根据从Supervisor发送的数据包中包含的事件类型和命令类型来调用这些API。

关系如下。

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;
5.11.6.5. 计步器示例

有一个“Step Counter”示例作为“Step Counter”的示例应用程序。 本节说明如何使用它。

5.11.6.5.1. 准备
编译配置(Kconfig)

要使用“ Step Counter”示例应用程序,请按如下所示设置配置选项。

按以下方式选择:

[Examples]
  [Step counter sensor example] <= Y

或使用“Step Counter”的默认配置。

./tools/config.py examples/step_counter
内存和消息实用程序配置和布局

如下设置任务间通信库(Message Library)和内存管理库(Memory Manager)。

消息库配置

有必要定义“MessageQueue”,这在使用“Step Counter”时是必需的。 该定义在MessageQueueLayout定义文件中完成,并且可以使用该工具生成要包含在代码中的头文件。

在“Step Counter”示例应用程序中,执行以下操作:

cd examples/step_counter/config
python3 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

使用以“ MSGQ_”开头的字符串指定消息队列池标识的名称。

n_size

正常优先级队列的每个元素中的字节数(8到512)。 指定固定的标头长度(8个字节)+参数长度(4的倍数)。

n_num

正常优先级队列中的元素数(1到16384)。

h_size

高优先级队列的每个元素中的字节数(0或8到512)。不使用时指定0。

h_num

高优先级队列中的元素数(0或1到16384)。不使用时指定0。

n_size是最佳值,不应更改。

n_num不需要更改,但是在其他应用程序中使用Step Counter时,可能需要考虑负载而增加该值。

要优先处理步骤计数器时,请使用h_size和h_nums。

有关每个定义的详细信息,请参考 examples/step_counter/config/msgq_layout.conf
如果设置更改,请使用该工具生成一个新的头文件。
内存管理器(智能修订池)配置

必须定义使用“Step Counter”时所需的MemoryLayout(pool)。
定义在MemoaryLayout定义文件中进行,并且可以使用该工具生成要包含在代码中的头文件。

在“Step Counter”示例应用程序中,执行以下操作:

cd examples/step_counter/config
python3 mem_layout.conf mem_layout.h fixed_fence.h pool_layout.h

MemoaryLayout定义文件(mem_layout.conf)的内容如下。

固定区域
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

该区域的起始对齐方式。 指定MinAlign的倍数(= 4),不包括0

size

区域的大小。 指定的值是0以外的4的倍数

fence

指定启用/禁用围栏(如果UseFence为false,则忽略此项目)

每个名称的用法如下。

SENSOR_WORK_AREA

用于传感器融合

MSG_QUE_AREA

由MessageQueue使用(固定名称)。不要超过msgq_id.h中的(MSGQ_END_DRM-MSGQ_TOP_DRAM)的大小。

MEMMGR_WORK_AREA

内存管理器使用的工作区(固定名称,固定大小)

MEMMGR_DATA_AREA

Memery Manager使用的数据区域(固定名称,固定大小)

确保每个名称的总大小不超过由mpshm_init() 、 doxygen:mpshm_remap [mpshm_remap()] 保护的共享内存的大小。

动态区域
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],
 ["GNSS_DATA_BUF_POOL",      "SENSOR_WORK_AREA", U_STD_ALIGN, U_GNSS_DATA_BUF_POOL_SIZE,   U_GNSS_DATA_BUF_SEG_NUM,    False],

每个参数的说明如下。

参数 说明

name

池名称(以大写字母开头,以“ POOL”结尾。可以使用大写字母,数字和

area

FixedArea区域名称用作池区域。 该区域必须位于RAM中

align

池的起始对齐方式。 指定MinAlign的倍数(= 4),不包括0

pool-size

游泳池的大小。 该值是4的整数倍,但0除外。 对于基本池,段大小*段数

seg

段数。 指定一个介于1到255之间的值

fence

指定围栏有效还是无效。 如果UseFence为false,则忽略此项目

每个名称的用法如下。

SENSOR_DSP_CMD_BUF_POOL

与Worker发送和接收的缓冲区

ACCEL_DATA_BUF_POOL

Accelerometer数据缓冲区

如果设置更改,请使用该工具生成一个新的头文件。 NOTE: 有关每个定义的详细信息,请参考 examples/step_counter/config/mem_layout.conf 。 如果设置更改,请使用该工具生成一个新的头文件。


5.12. JPEG 解码

5.12.1. 简介

提供基于IJG开发的libjpeg库的JPEG解码功能。

尽管它总体上遵循原始libjpeg库的API规范,但仍有针对Spresense定制的要点,因此本文档详细介绍了定制。

在以下说明中,“libjpeg实例”指的是struct jpeg_decompress_struct类型变量,该变量必须由使用libjpeg的应用程序准备。

5.12.2. Spresense 定制

输出格式(色彩空间)

原始libjpeg支持的所有格式均为24位/像素或更高,但Spresense支持16位/像素Cb/Y/Cr/Y(YUV4:2:2)格式,因此可以用更少的内存进行解码。
以下定义是Spresense中的有效色彩空间定义。 通过将此参数设置为libjpeg实例的成员out_color_space并执行jpeg_start_decompress(), 允许在任何支持的色彩空间中进行解码。

表格 35. 输出格式(色彩空间)
宏名 含义 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单元读取。

表格 36. 解码结果读取API
API名 功能 Spresense 原生

jpeg_read_scanlines

逐行读取

jpeg_read_mcus

通过MCU读取

×

MCU是JPEG压缩单元块,基本上是8x8像素。 大小根据JPEG编码参数(在JPEG标头中设置)和解码参数(由应用程序设置)而有所不同。 作为应用程序,在执行jpeg_start_decompress()之后,您可以从libjpeg实例信息中了解1MCU的大小,如下所示: * 1MCU宽度 = output_width / MCUs_per_row (总宽度/宽度方向上的MCU总数) * 1MCU高度 = output_height / MCU_rows_in_scan(总高度/高度方向上的MCU总数)

对于MCU单元,每个单元的像素数(数据大小)不取决于图像大小,因此,随着图像大小的增加,这两种类型的单元之间的差异变得更加明显,如下例所示。

表格 37. 单位像素数示例:当以相同放大倍数对使用Spresense相机拍摄的JPEG文件进行解码时
単位 QVGA分辨率 HD分辨率 5M分辨率

行単位

320

1280

2560

MCU単位

128

128

128

JPEG数据输入方式

在原始的libjpeg中,可以使用文件指针或缓冲区输入JPEG数据,但是在Spresense中,除了这些以外,还支持文件描述符。

表格 38. JPEG数据输入API
API名 含义 Spresense 原生

jpeg_stdio_src

文件指针

jpeg_fd_src

文件描述符

×

jpeg_mem_src

缓冲液

这里的文件描述符是一个条件,该条件是可以使用read()函数读取JPEG数据的文件描述符。
例如,除了open()常规文件的文件描述符外,还可以支持使用socket()创建的套接字描述符。 (当然,在使用套接字描述符的情况下,必须按原样从通信伙伴发送JPEG数据。)

错误处理

默认情况下,当原始libjpeg和Spresense中均发生错误时,libjpeg API执行任务将由exit()终止。 原始的libjpeg提供了一个示例,该示例使用“setjmp/longjmp”作为不结束任务的方法, 但是由于Spresense(NuttX)不支持setjmp/longjmp,因此无法使用此方法。 将来,我们计划使用setjmp/longjmp以外的方法来支持错误处理。

libjpeg的错误处理是在“错误处理程序不返回”的前提下实现的,如果错误处理程序返回,则不能保证操作。
表格 39. 错误处理程序的终止方法
错误处理程序
终止方式
目的 Spresense 原生

exit

libjpeg API执行任务结束

longjmp

到使用setjmp保存的堆栈上下文
nonlocal jump

×
(不支持NuttX)


(取决于实施环境)

return

返回错误检测功能

×

×

除程序错误外,“错误”还可能由外部原因引起。 有关典型错误,请参考 输出到标准错误输出

5.12.3. 状态转移

diag 4924849ab3532a8c0f240f9da59d52dc

5.12.4. 操作顺序

diag 5bf6831b0a740be8cd23cb2ed38a79d5
图表 82. libjpeg操作顺序

5.12.5. 输出到标准错误输出

当检测到错误或警告时,libjpeg库会将消息输出到英语标准错误输出。 消息的含义和输出原因与原始libjpeg相同。

以下是一些常见的消息。

表格 40. libjpeg库的标准错误输出消息
输出信息 错误/警告 输出时机

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

警告

霍夫曼代码解码错误

Premature end of JPEG file

警告

当输入的JPEG数据到达EOF而没有EOI标记出现时输出

5.12.6. 示例代码

此示例代码基于原始libjpeg库附带的example.c解码程序,并结合了Spresense版本的libjpeg的以下功能:

  • YUV4输出:2:2格式

  • 文件描述符可用于输入JPEG数据

  • 可以通过MCU解码

6. NuttX提供的功能

请参考 NuttX.org ,了解NuttX提供的功能。

7. 调试方法

本节介绍调试用户应用程序时有用的信息和工具。

7.1. Eclipse IDE 调试方法

7.1.1. 硬件

  • 兼容CMSIS-DAP的调试适配器(ICE)

    • Keil ULINK2(http://www.keil.com/arm/ulink2/)

    • NXP LPC-Link2(https://www.nxp.com/jp/support/developer-resources/software-development-tools/lpc-developer-resources-/lpc-microcontroller-utilities/lpc-link2:OM13054?lang=jp&lang_cd=jp&)

  • SWD 连接器

7.1.1.1. 安装SWD连接器

有关如何安装SWD连接器的信息,请参考外部 硬件文档

7.1.2. OpenOCD 设置

设置开发工具 将自动安装GNU MCU Eclipse项目( https://gnu-mcu-eclipse.github.io/ )提供的OpenOCD 为了与 Spresense SDK 一起使用,需要执行以下操作。

将下载的 Spresense SDK 存储库的 sdk/tools 目录下的 cxd5602.cfg 配置文件复制到OpenOCD引用的目录中。

cp spresense/sdk/tools/cxd5602.cfg ~/spresenseenv/usr/scripts/target/

对于Ubuntu,必须使用以下命令授予连接到ICE的权限。 请先连接ICE。

sudo cp ~/spresenseenv/usr/contrib/60-openocd.rules /etc/udev/rules.d/
sudo udevadm control --reload

7.1.3. 安装Eclipse

对于Ubuntu,请单独安装JRE以使用Eclipse。

sudo apt install default-jre

对于Windows/Mac,请从Oracle网站获得Eclipse推荐的JRE并进行安装。有关详细信息,请访问Eclipse官方网站(https://www.eclipse.org/)。

从Eclipse官方站点(https://www.eclipse.org/downloads/)下载最新版本。运行安装程序时,将显示以下菜单:单击 Eclipse IDE for C/C++ Developers

Install CDT
图表 83. 为C/C++ 开发人员安装Eclipse IDE

安装Eclipse之后,请安装其他插件。

  1. 点击 HelpEclipse Markeplace…​

  2. 搜素 gnu mcu 并点击 Go

  3. 安装 GNU MCU Eclipse

Install GNU MCU

7.1.4. Spresense 主板设置

Spresense 板将自动启动名为 nuttx 的文件(如果已安装)。 如果未安装该文件,请进入调试模式。 在使用Eclipse进行调试之前,Spresense 板必须处于调试模式。

  1. 打开串行终端

  2. 按住终端上的 r 键,重置主板

  3. 终端上出现 updater# 提示

  4. 使用以下命令删除名为 nuttx 的文件

updater# rm nuttx

进入调试模式时,按复位键后,终端上将显示以下消息。

Waiting for debugger connection..

要返回正常模式,请使用 tools/flash.sh 重新加载 nuttx.spk

7.1.5. 调试(GNU MCU Eclipse plugin)

7.1.5.1. 设置
  1. 点击 RunDebug Configurations…​

  2. 选择 GDB OpenOCD Debugging

  3. New 按钮创建新的OpenOCD调试配置

  4. 设置以下

OpenOCD调试设置
  • Main

    • C/C++ Application → nuttx

eclipse debug gnu mcu main
图表 84. Main标签页
  • Debugger

    • OpenOCD Setup

      • Executable pathopenocd 路径

      • Start GDB Session → 激活

    • GDB Client Setup

      • Executable namearm-none-eabi-gdb 路径

    • OpenOCD Setup

      • Config options → 设定如下

-f interface/cmsis-dap.cfg -f target/cxd5602.cfg
eclipse debug gnu mcu debugger
图表 85. Debugger标签页
  • Startup

    • Load Symbols and Executable

      • Load symbols → 激活

      • Load executable → 激活

    • Runtime Options

      • Debug in RAM → 激活

eclipse debug gnu mcu startup
图表 86. Startup标签页
7.1.5.2. 执行调试

通过以下步骤开始调试。

  1. 按下Spresense板上的重置开关

  2. 在OpenOCD调试设置中按 Debug 按钮。