VOI611 SDK 开发接入指南
本文主要描述了基于SDK方案的开发流程,适用于嵌入式开发工程师及个人开发者快速入门,了解使用 VOI611 内置 MCU 开发。
1.方案概述
VOI611 是一颗针对嵌入式产品的深度学习语音识别芯片,内置神经网络硬件加速模块NPU,标准ARM处理器Cortex-M3,集成多种控制和通信接口。
VOI611 不仅可以运行多种神经网络,在有噪声干扰的近场和远场情况下,支持离线语音命令识别,还可以在设备不联网的情况下,通过说出简单命令词方式,有效控制目标电器设备,执行既定的操作行为。
VOI611 智能语音处理解决方案是基于深度学习语音识别芯片设计的全套智能语音解决方案,探境科技提供SDK可以对芯片上的各硬件进行开发、定制,例如:
- 定制外围设备
- 定制语音识别反馈处理和定制反馈语音
- 定制MCU和ASR通信的串口码
2.开发环境
2.1 Windows 开发环境
由探境提供的IET_ENV软件编译环境,解压即可使用,目录如下
├── sdk
├── tools
├── start-编译环境-iet-env.bat
└── 使用说明.md
2.2 如何进入编译环境
双击运行 start-编译环境-iet-env.bat 脚本,进入相应SDK版本
cd VOI611_SDK_2.1
2.3 编译和打包
进入SDK的根目录,执行清除和编译指令
make clean
make
生成的升级文件位于当前目录的output-package/upgrade-package/package下
app_iet_upgrade.bin iet_upgrade_01.bin wav_iet_upgrade.bin
boot_iet_upgrade.bin iet_upgrade.bin weight_iet_upgrade_01.bin
iet_flash_xMB_checksum.bin para_iet_upgrade.bin weight_iet_upgrade.bin
iet_flash_xMB_checksum.bin
主要用于批量生产阶段,在Flash备料环节进行批量的烧录。(生产流程为:预烧录Flash芯片-->贴片加工-->产测验证)
iet_upgrade.bin
该文件系列包含(iet_upgrade.bin / iet_upgrade_01.bin / iet_upgrade_02.bin / ...)
iet_upgrade.bin = boot_iet_upgrade.bin + para_iet_upgrade.bin + app_iet_upgrade.bin + wav_iet_upgrade.bin + weight_iet_upgrade.bin
para_iet_upgrade.bin
主要用于标识 flash layout 信息,记录了:app_iet_upgrade.bin 、 wav_iet_upgrade.bin 、 weight_iet_upgrade.bin 等文件地址。
boot_iet_upgrade.bin
VOI611芯片上电后,首先运行这部分的软件,并且载入 para_iet_upgrade.bin 的设定。
3. SDK 介绍
3.1 SDK 目录结构说明
├── bootloader
├── demo
│ ├── include 所有依赖的Lib文件的头文件声明
│ ├── lib 依赖的Lib文件
│ ├── obj 依赖的.o文件
│ ├── source demo APP 以及 Makefile
│ └── tool 链接器
├── document 文档说明
├── Makefile 编译脚本
├── output-package
│ ├── conf 配置文件
│ ├── upgrade-package 升级包目录
│ ├── wav 语音反馈文件
│ └── weight 训练模型文件
└── tool
├── package
└── tts 语音合成脚本
3.2 IC类型设置
VOI611有两种类型IC分别是1CA和1CC,软件需要根据不同的型号配置。
SDK默认编译出来的固件是1CC,如果需要编译1CA固件,需要修改如下两个文件。
- demo/source/main.c
#define IC_TYPE_1CC (1) //1CC设置
#define IC_TYPE_1CC (0) //1CA设置
- output-package/conf/upgrade_conf.json
"hw_ver": "1CC" //1CC设置
"hw_ver": "1CA" //1CA设置
3.3 GPIO配置使用
VOI611 SDK 允许用户根据不同的硬件环境来配置Pinmux
共16个GPIO,全部为复用管脚,具体描述如下表:
Pin num | Function0 | Function1 | Function2 |
---|---|---|---|
19 | PDM_CLK | GPIOC2 | |
20 | I2S_SDI | GPIOD2 | |
38 | MSPI_SCK | GPIOA3 | |
39 | MSPI_SDO | GPIOC3 | |
40 | MSPI_SDI | GPIOD3 | |
41 | MSPI_CSN | GPIOB3 | |
54 | UART1_RX | GPIOD1 | |
55 | UART1_TX | GPIOC1 | |
56 | UART0_TX | GPIOA1 | |
57 | UART0_RX | GPIOB1 | |
60 | JTAG_TDO | PWM3_O | GPIOD0 |
61 | JTAG_TDI | PWM2_O | GPIOC0 |
62 | JTAG_TMS | PWM1_O | GPIOB0 |
63 | JTAG_TCK | PWM0_O | GPIOA0 |
64 | I2C_SDA | GPIOB2 | |
65 | I2C_SCL | GPIOA2 |
- GPIO 读写操作例程
#include "asr_gpio.h"
void main(void)
{
uint8_t ui1_group = 0,ui1_pin = 0; //GPIOA0 group = 0 ,pin = 0;
uint32_t ui4_data = 0,ui4_value = 0
uint32_t ui4_source_contrl = 0; //0 software control 1 hardware control
uint32_t ui4_direction = 1; //1 output, 0 input
i4_ret = asr_gpio_open(ui1_group, ui1_pin, ui4_direction, ui4_data, ui4_source_contrl)
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_write(ui1_group, ui1_pin, ui4_value);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_read(ui1_group, ui1_pin, &ui4_value);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_close(ui1_group, ui1_pin);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
}
- GPIO 中断操作例程 ( 只有GPIOA0/GPIOB0/GPIOC0/GPIOD0具有中断功能 )
#include "asr_gpio.h"
static void goio_interrupt_callback(void)
{
APP_MSG("do what you want here.\n");
}
void main(void)
{
uint8_t ui1_group = 0,ui1_pin = 0;
uint32_t ui4_data = 0,ui4_value = 0
uint32_t ui4_source_contrl = 0; //0 software control 1 hardware control
uint32_t ui4_direction = 0; //1 output, 0 input
uint8_t ui1_int_polarity = 0; //0 low volage trigger,1 high volage trigger
uint8_t ui1_int_flag = 1,ui1_int_level = 0,ui1_int_bothedge = 0;
i4_ret = asr_gpio_open(ui1_group, ui1_pin, ui4_direction, ui4_data, ui4_source_contrl);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_interrupt_config(ui1_group, ui1_pin, ui1_int_flag, ui1_int_level,
ui1_int_polarity,ui1_int_bothedge,goio_interrupt_callback);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_interrupt_enable(ui1_group, ui1_pin, ui1_int_flag,
ui1_int_level, ui1_int_polarity,ui1_int_bothedge,goio_interrupt_callback);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
ui1_int_flag = 0;
i4_ret = asr_gpio_interrupt_disable(ui1_group, ui1_pin, ui1_int_flag,
ui1_int_level, ui1_int_polarity,ui1_int_bothedge,goio_interrupt_callback);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_gpio_interrupt_clear(ui1_group, ui1_pin, ui1_int_flag,
ui1_int_level, ui1_int_polarity,ui1_int_bothedge,goio_interrupt_callback);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
}
3.4 PWM配置使用
VOI611 硬件有4路PWM,如下表:
Pin num | Function0 | Function1 | Function2 |
---|---|---|---|
60 | JTAG_TDO | PWM3_O | GPIOD0 |
61 | JTAG_TDI | PWM2_O | GPIOC0 |
62 | JTAG_TMS | PWM1_O | GPIOB0 |
63 | JTAG_TCK | PWM0_O | GPIOA0 |
PWM口对应的IO是复用的,使用PWM功能时需要将对应的IO配置为PWM功能
- PWM操作例程
#include "asr_pwm.h"
#define HS_BACH_PWM_GROUP 0 //group A
#define HS_BACH_PWM_PIN 0 //pin 0
#define HS_BACH_PWM_NUM 0
#define HS_BACH_PWM_20KHZ (20)
#define HS_BACH_PWM_50_PERCENT (50)
#define HS_BACH_PWM_0_PERCENT (0)
#define HS_BACH_PWM_100_PERCENT (100)
void main(void)
{
int32_t i4_ret;
i4_ret = asr_pinmux_function_select(HS_BACH_PWM_GROUP,HS_BACH_PWM_PIN,E_FUNC_PWM);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_pwm_init(HS_BACH_PWM_NUM, HS_BACH_PWM_20KHZ, HS_BACH_PWM_100_PERCENT);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_pwm_start(HS_BACH_PWM_NUM);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_pwm_reset_config(HS_BACH_PWM_NUM, BACH_PWM_20KHZ, HS_BACH_PWM_0_PERCENT);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
asr_pwm_stop(uint32_t ui4_num);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_pwm_start(HS_BACH_PWM_NUM);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_pwm_close(HS_BACH_PWM_NUM);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
}
3.5 UART配置使用
VOI611 硬件提供2路UART,默认UART0用于升级,通讯,调试功能
Pin num | Function0 | Function1 | Function2 |
---|---|---|---|
54 | UART1_RX | GPIOD1 | |
55 | UART1_TX | GPIOC1 | |
56 | UART0_TX | GPIOA1 | |
57 | UART0_RX | GPIOB1 |
- UART 操作例程
#define BACH_UART 0
#define BAUD_RATE (115200)
#define COM_CUSTOMER_UART_FRAME_RX_TIMEOUT_MS 50 //接收超时
#define SAMPLE_UART_FRAME_LENGTH 11 //接收长度
static void com_customer_uart_frame_rx_callback(void *asr_uart, uint8_t* pui1_data, uint16_t ui2_len)
{
//do something
}
void main(void)
{
asr_uart_customer.port_num = BACH_UART;
asr_uart_customer.baudrate = BAUD_RATE;
asr_uart_open(&asr_uart_customer, com_customer_uart_frame_rx_callback,
COM_CUSTOMER_UART_FRAME_RX_TIMEOUT_MS, SAMPLE_UART_FRAME_LENGTH, 1, 0);
}
3.6 Timer配置说明
VOI611 硬件提供4个定时器,实现定时功能
- Timer 使用例程
#include "asr_timer.h"
#define TIME_300MS (300)
static void asr_timer_callback()
{
APP_MSG("do what you want.\n");
}
int main()
{
int32_t i4_ret;
i4_ret = asr_timer_setup(TIMER_3, TIME_300MS, asr_timer_callback);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_timer_start(ui4_timer_id);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_timer_stop(ui4_timer_id);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
i4_ret = asr_timer_close(ui4_timer_id);
ASR_CHECK_FAIL_VALUE(i4_ret, E_OK);
return i4_ret;
}
3.7 反馈音定制
反馈音是语音反馈处理的一部分,为了产品获得更好的用户体验,通常在用户发出指令之后产品会反馈语音;
探境提供了语音合成的工具longyin_tts,可以试听和批量生成TTS
试听设置
- 场景设置,共有6个场景可选择
- 发声人设置,可选择男性,女性,儿童等不同音色
- 音量,语速,语调设置
- 添加试听文字,点击 试听 即可
批量生成设置
- 设置转换起始ID(程序根据这个ID播放提示音)
- 添加生成列表,每条反馈音一行
- 点击 批量转换 等待完成,点击 结果目录 就可以看到生成的反馈音
反馈音如何加入固件中
- 把批量生成的反馈音文件加入到 ./output-package/wav/ 目录下即可
如何播放反馈音
- 调用SDK的API接口 com_common_play_voice
void com_common_play_voice(uint8_t ui1_idx)
{
ASR_RET e_ret;
asr_play_param r_play_param;
r_play_param.i2_play_index = (int16_t)ui1_idx;
if ((ui1_idx <= ui1_wav_count) && (ui1_is_mute == 0))
{
e_ret = asr_audio_play(&r_play_param);
ASR_CHECK_FAIL(e_ret);
}
}
3.8 权重文件
- 权重文件位于 output-package/weight 目录下的二进制文件,是以.bin为后缀名。
- 权重文件bin文件主要存放探境科技为该产品ASR定制的神经网络训练模型和ASR权重
- 新的权重文件,用户只需要替换这个.bin文件即可
注意:weight 目录下只能有一个bin文件
4. APP 开发
4.1 SDK常用的路径和文件
- 外设接口API文件路径 demo/include/peripheral
- 常用文件
demo/source/asr_sample.c
demo/source/app_cfg/bach_app_cfg.c
demo/source/app_cfg/com_common.c
demo/source/app_cfg/com_raw.c
demo/source/app_cfg/com_reg.c
4.2 系统设置
文件bach_app_cfg.c主要配置ROM,RAM分区,硬件设定等,通常修改较多的地方
const uint8_t ui1_cfg_release = 1; //0 debug 1 release
const uint8_t ui1_cfg_comm_uart = 0; // app comunicatoin port
const uint32_t ui4_cfg_comm_baudrate = 9600;//app com port buadrate
4.3 应用开发
文件 asr_sample.c 识别结果功能逻辑都这里实现,重点部分
static void sample_kws_result(uint16_t ui2_word_index, uint8_t ui1_cmd_idx, uint8_t ui1_voice)
{
sample_customization_result(ui2_word_index, &ui1_cmd_idx, &ui1_voice);
#if (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_REG)
com_reg_kws_result(ui2_word_index, ui1_cmd_idx, ui1_voice);
#else
com_customer_kws_result(ui2_word_index, ui1_cmd_idx, ui1_voice);
#endif
}
void sample_app(void)
{
...
KWS_CONFIG r_config;
r_config.kws_result_callback = sample_kws_result; //识别结果回调函数
r_config.kws_notify_callback = com_common_kws_notify; //事件通知回调函数
...
#if (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_REG) //探境标准寄存器
com_reg_app();
#elif (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_CUSTOMER) //客制化协议
com_customer_app();
#elif (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_NONE) //串口源数据
com_raw_app();
#endif
}