VOI611 SDK 開發(fā)接入指南

本文主要描述了基于SDK方案的開發(fā)流程,適用于嵌入式開發(fā)工程師及個(gè)人開發(fā)者快速入門,了解使用 VOI611 內(nèi)置 MCU 開發(fā)。


1.方案概述


VOI611 是一顆針對(duì)嵌入式產(chǎn)品的深度學(xué)習(xí)語音識(shí)別芯片,內(nèi)置神經(jīng)網(wǎng)絡(luò)硬件加速模塊NPU,標(biāo)準(zhǔn)ARM處理器Cortex-M3,集成多種控制和通信接口。

VOI611 不僅可以運(yùn)行多種神經(jīng)網(wǎng)絡(luò),在有噪聲干擾的近場(chǎng)和遠(yuǎn)場(chǎng)情況下,支持離線語音命令識(shí)別,還可以在設(shè)備不聯(lián)網(wǎng)的情況下,通過說出簡(jiǎn)單命令詞方式,有效控制目標(biāo)電器設(shè)備,執(zhí)行既定的操作行為。

voi611_func.png

圖 - VOI611芯片功能示例

VOI611 智能語音處理解決方案是基于深度學(xué)習(xí)語音識(shí)別芯片設(shè)計(jì)的全套智能語音解決方案,探境科技提供SDK可以對(duì)芯片上的各硬件進(jìn)行開發(fā)、定制,例如:

  • 定制外圍設(shè)備
  • 定制語音識(shí)別反饋處理和定制反饋語音
  • 定制MCU和ASR通信的串口碼


2.開發(fā)環(huán)境


2.1 Windows 開發(fā)環(huán)境

由探境提供的IET_ENV軟件編譯環(huán)境,解壓即可使用,目錄如下

├── sdk?
├── tools
├── start-編譯環(huán)境-iet-env.bat
└── ?使用說明.md

2.2 如何進(jìn)入編譯環(huán)境

雙擊運(yùn)行 start-編譯環(huán)境-iet-env.bat 腳本,進(jìn)入相應(yīng)SDK版本

cd VOI611_SDK_2.1

2.3 編譯和打包

進(jìn)入SDK的根目錄,執(zhí)行清除和編譯指令

make clean
make

生成的升級(jí)文件位于當(dāng)前目錄的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
主要用于批量生產(chǎn)階段,在Flash備料環(huán)節(jié)進(jìn)行批量的燒錄。(生產(chǎn)流程為:預(yù)燒錄Flash芯片-->貼片加工-->產(chǎn)測(cè)驗(yàn)證)

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
主要用于標(biāo)識(shí) flash layout 信息,記錄了:app_iet_upgrade.bin 、 wav_iet_upgrade.bin 、 weight_iet_upgrade.bin 等文件地址。

boot_iet_upgrade.bin
VOI611芯片上電后,首先運(yùn)行這部分的軟件,并且載入 para_iet_upgrade.bin 的設(shè)定。

查看固件升級(jí)方法


3. SDK 介紹


3.1 SDK 目錄結(jié)構(gòu)說明

├── bootloader
├── demo
│?? ├── include  所有依賴的Lib文件的頭文件聲明
│?? ├── lib      依賴的Lib文件
│?? ├── obj      依賴的.o文件
│?? ├── source   demo APP 以及 Makefile
│?? └── tool     鏈接器
├── document     文檔說明
├── Makefile     編譯腳本
├── output-package 
│?? ├── conf            配置文件
│?? ├── upgrade-package 升級(jí)包目錄
│?? ├── wav             語音反饋文件
│?? └── weight          訓(xùn)練模型文件
└── tool
    ├── package
    └── tts             語音合成腳本

3.2 IC類型設(shè)置

VOI611有兩種類型IC分別是1CA和1CC,軟件需要根據(jù)不同的型號(hào)配置。
SDK默認(rèn)編譯出來的固件是1CC,如果需要編譯1CA固件,需要修改如下兩個(gè)文件。

  • demo/source/main.c
#define IC_TYPE_1CC      (1)      //1CC設(shè)置 
#define IC_TYPE_1CC      (0)      //1CA設(shè)置   
  • output-package/conf/upgrade_conf.json
"hw_ver": "1CC"      //1CC設(shè)置 
"hw_ver": "1CA"      //1CA設(shè)置   

3.3 GPIO配置使用

VOI611 SDK 允許用戶根據(jù)不同的硬件環(huán)境來配置Pinmux

共16個(gè)GPIO,全部為復(fù)用管腳,具體描述如下表:

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口對(duì)應(yīng)的IO是復(fù)用的,使用PWM功能時(shí)需要將對(duì)應(yīng)的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,默認(rèn)UART0用于升級(jí),通訊,調(diào)試功能

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        //接收超時(shí)
#define SAMPLE_UART_FRAME_LENGTH               11        //接收長(zhǎng)度

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個(gè)定時(shí)器,實(shí)現(xiàn)定時(shí)功能

  • 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 反饋音定制

反饋音是語音反饋處理的一部分,為了產(chǎn)品獲得更好的用戶體驗(yàn),通常在用戶發(fā)出指令之后產(chǎn)品會(huì)反饋語音;

探境提供了語音合成的工具longyin_tts,可以試聽和批量生成TTS

voi611_func.png

圖2 - longyin 語音合成工具

試聽設(shè)置

  • 場(chǎng)景設(shè)置,共有6個(gè)場(chǎng)景可選擇
  • 發(fā)聲人設(shè)置,可選擇男性,女性,兒童等不同音色
  • 音量,語速,語調(diào)設(shè)置
  • 添加試聽文字,點(diǎn)擊 試聽 即可

批量生成設(shè)置

  • 設(shè)置轉(zhuǎn)換起始ID(程序根據(jù)這個(gè)ID播放提示音)
  • 添加生成列表,每條反饋音一行
  • 點(diǎn)擊 批量轉(zhuǎn)換 等待完成,點(diǎn)擊 結(jié)果目錄 就可以看到生成的反饋音

反饋音如何加入固件中

  • 把批量生成的反饋音文件加入到 ./output-package/wav/ 目錄下即可

如何播放反饋音

  • 調(diào)用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 權(quán)重文件

  • 權(quán)重文件位于 output-package/weight 目錄下的二進(jìn)制文件,是以.bin為后綴名。
  • 權(quán)重文件bin文件主要存放探境科技為該產(chǎn)品ASR定制的神經(jīng)網(wǎng)絡(luò)訓(xùn)練模型和ASR權(quán)重
  • 新的權(quán)重文件,用戶只需要替換這個(gè).bin文件即可

注意:weight 目錄下只能有一個(gè)bin文件


4. APP 開發(fā)


4.1 SDK常用的路徑和文件

  • 外設(shè)接口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 系統(tǒng)設(shè)置

文件bach_app_cfg.c主要配置ROM,RAM分區(qū),硬件設(shè)定等,通常修改較多的地方

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 應(yīng)用開發(fā)

文件 asr_sample.c 識(shí)別結(jié)果功能邏輯都這里實(shí)現(xiàn),重點(diǎn)部分

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;      //識(shí)別結(jié)果回調(diào)函數(shù)
    r_config.kws_notify_callback = com_common_kws_notify;  //事件通知回調(diào)函數(shù)
    ...

    #if (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_REG)        //探境標(biāo)準(zhǔn)寄存器
        com_reg_app();
    #elif (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_CUSTOMER) //客制化協(xié)議
        com_customer_app();
    #elif (SAMPLE_COMM_CONFIG_TYPE == SAMPLE_COMM_CONFIG_NONE)     //串口源數(shù)據(jù)
        com_raw_app();
    #endif
}