sp2cw3 bare SDK快速开发指南

本文介绍珠海普林芯驰sp2cw3平台芯片bare的SDK使用,包括编译环境搭建、下载、驱动及应用开发等,使用SDK进行开发之前,请阅读本文。

1、SOC简介

sp2cw3系列是珠海普林芯驰(www.spacetouch.co)推出的通用音频处理SOC,采用CPU+NPU+uDSP三核异构框架。CPU使用RISC-V架构,支持单精度浮点运算,uDSP能够完成音频信号的特征提取及计算,通过NPU实现神经网络训练和学习,能够实现AI降噪、AEC、语音识别等音频算法应用。 同时内置高性能音频专用 codec,丰富的外设资源,能够应用于各种音频应用领域。

spv40

2、bare SDK框架说明

bare SDK提供了AI降噪、传统(MMSE)降噪、回声消除、啸叫抑制等工程模版,工程模版已经集成最新的算法库。开发人员只需要根据自己的需求,完成业务逻辑部分即可。

2.1、文件夹目录结构

SDK根目录主控包括如下文件夹及内容:

文件夹描述
oss链接脚本、启动文件、寄存器封装等公共文件用,用户一般不需要改动,如需要改动,请联系原厂技术支持
project该文件下放置多个demo工程,用以不同的需求开发

spv40

 

 

project是SDK源码目录,开发需要进入该目录进行:

文件夹描述
sp2cw3_release_for_a2a_ai_aec_v1.0回声消除(AEC)A2A标准参考工程
sp2cw3_release_for_a2a_ai_denoise_v1.0AI降噪A2A标准参考工程
sp2cw3_release_for_a2a_stationary_denoise_v1.0稳态噪声降噪A2A标准参考工程
sp2cw3_demo_for_iis_ai_denoise_v1.0AI降噪IIS标准参考工程
sp2cw3_release_algo_for_a2a_ai_howling_suppression_v1.0AI啸叫抑制A2A标准参考工程

 

工程文件夹目录结构:

文件夹描述
algo算法静态库和算法接口调用逻辑代码
board硬件平台、系统状态机
codecaudio adc(录音),audio dac(播放) ,src(采样率转换)、 IIS等等相关配置代码
image算法模型(.mod)、参数配置文件(.a)、提示音文件(.dat)
src用户业务逻辑代码相关
system系统运行、算法执行调用文件,udsp、npu、DMA等
debug编译过程中间文件
output编译后输出的烧录文件(.bin)
makefile编译构建脚本,负责文件的依赖关系等等

1722505678538

2.2、应用工程配置说明

2.2.1AI 降噪工程配置

导入AI降噪工程(工程名:sp2cw3_release_for_a2a_ai_denoise_v1.0)后,打开makefile文件,可以对降噪模型的延时和MIC通道做配置,如下:

配置值功能说明
DENOISE_DELAY_TIME_MS24对应ADC采样率为8k,降噪模型延时为24ms
DENOISE_DELAY_TIME_MS37对应ADC采样率为16k,降噪模型延时为37.5ms
DENOISE_DELAY_TIME_MS 48对应ADC采样率为16k,降噪模型延时为48ms

 

配置值功能说明
DENOISE_MIC_NUMBER1单麦降噪
DENOISE_MIC_NUMBER2双麦降噪

 

2.2.2稳态降噪工程配置

导入稳态降噪工程(工程名:sp2cw3_release_for_a2a_stationary_denoise_v1.0)后,打开makefile文件,可以对降噪库的采样率、延时、声道数做修改,如下:

配置值功能说明
DENOISE_TYPEmono_16k_48ms对应ADC采样率为16k,降噪库延时为24ms,单声道
DENOISE_TYPEmono_48k_32ms对应ADC采样率为48k,降噪库延时为32ms,单声道
DENOISE_TYPEmono_8k_48ms对应ADC采样率为8k,降噪库延时为48ms,单声道
DENOISE_TYPEstereo_16k_48ms对应ADC采样率为16k,降噪库延时为48ms,立体声
DENOISE_TYPEstereo_48k_32ms对应ADC采样率为48k,降噪库延时为32ms,立体声
DENOISE_TYPEstereo_8k_48ms对应ADC采样率为8k,降噪库延时为48ms,立体声

 

2.2.3回声消除(AEC)工程配置

导入AEC工程(工程名:sp2cw3_release_for_a2a_ai_aec_v1.0)后,打开makefile文件,可以对AEC库的采样率、延时做修改,如下:

配置值功能说明
AEC_TYPEAEC_8K_48MS对应ADC采样率为8k,AEC库延时为48ms
AEC_TYPEAEC_16K_48MS对应ADC采样率为16k,AEC库延时为48ms
AEC_TYPEAEC_DENOISE_8K_48MS对应ADC采样率为8k,降噪和AEC库延时为48ms

 

2.2.4啸叫抑制(AHS)工程配置

导入啸叫抑制工程(工程名:sp2cw3_release_algo_for_a2a_ai_howling_suppression_v1.0)后,打开makefile文件,可以对啸叫抑制库的采样率、延时做修改,如下:

配置值功能说明
AHS_TYPEAHS_16K_18MS对应ADC采样率为16k,啸叫抑制库延时为18ms

2.3、系统状态机说明

函数名位置描述
void user_init(void)main.c用于上电后的外设初始化
void user_2ms_handler(void)mainc2ms执行周期的状态机回调函数,用户可以根据需求在这里调用业务逻辑代码
void user_10ms_handler(void)main.c10ms执行周期的状态机回调函数,用户可以根据需求在这里调用业务逻辑代码
void user_100ms_handler(void)main.c100ms执行周期的状态机回调函数,用户可以根据需求在这里调用业务逻辑代码
__IRAM void tick_user_handler(void)main.c500us执行周期的状态机回调函数,用户可以根据需求在这里调用业务逻辑代码

注释:在增加业务逻辑代码时候,应该评估其执行周期,尽可能不要频繁执行,为CPU跑语音算法预留足够的CPU算力。

2.4核心代码解析

2.4.1 audio adc

void audio_adc_init(void)
{
    audio_adc_ch_cfg_typedef   cfg;
    cfg.sample_rate  = SAMPLE_RATE_16K;            /*配置采样率*/
    cfg.digit_volume = VOLUME_01X;                 /*数字音量*/
    cfg.hw_pin = AMIC_CH0;                         /*模拟通道*/
    cfg.amic.mode = different;                     /*差分模式*/
    cfg.amic.mic_gain = denoise_param.mic_gain;    /*从配置文件获取MIC增益*/
    cfg.amic.mix_gain = MADC_MIX_GAIN_N0D0B;       /*设置MIX增益*/
    cfg.amic.vmic = VOLT_2o59;                     /*设置VMIC电压*/
    hal_audio_adc_ch_cfg(&audio_adc, cfg);
    cfg.hw_pin = AMIC_CH1;
    hal_audio_adc_ch_cfg(&audio_adc, cfg);
    audio_adc.init.data_width = WIDTH_16BIT;       /*数据宽度*/
#ifndef    ADC_USE_SRC1
    audio_adc.init.src_sel = AHB;
#else
    audio_adc.init.src_sel = SRC;
    debug("in audio_adc_init, src take effect \n\r");
#endif
    audio_adc.init.channel_id = CHN0 | CHN1;
    audio_adc.dma_handle = &audio_dma;/*注册DMA句柄*/
    hal_audio_init(&audio_adc);
#ifndef    ADC_USE_SRC1
        adc_dma_init();
#endif
    //adc_mic0_AGC_init();
    audio_adc_cmd(&audio_adc, ENABLE);
}

主要通过2个结构体传入参数,结构体的赋值通过结构体枚举变量成员传入:

typedef struct _audio_adc_ch_cfg_typedef
{
    sample_rate_type_def     sample_rate;  /*采样率*/
    volume_type_def          digit_volume; /*数字音量*/
    microphone_type_def      hw_pin;       /*pin脚选择*/
    audio_adc_dmic_typedef   dmic;         /*DMIC配置*/
    audio_adc_amic_typedef   amic;         /*AMIC配置*/
} audio_adc_ch_cfg_typedef;

typedef struct _audio_adc_amic_typedef
{
    amic_mode_type_def       mode;             /*输入方式*/
    amic_mic_gain_type_def   mic_gain;         /*mic增益*/
    amic_mix_gain_type_def   mix_gain;         /*mix增益*/
    vmic_vol_type_def        vmic;             /*VMIC电压*/
} audio_adc_amic_typedef;

 

2.4.1 audio dac

void audio_dac_init(void)
{
    volatile __ALIGNED(4) static uint16_t dac_buff[2][DAC_FRAM_SIZE * 2];
    audio_dac_buff[0].addr = (uint8_t *)dac_buff[0];
    audio_dac_buff[0].status = BUFF_FREE;
    audio_dac_buff[1].addr = (uint8_t *)dac_buff[1];
    audio_dac_buff[1].status = BUFF_FREE;
    audio_dac.init.track = DAC_STEREO;
    audio_dac.init.sample_rate = DAC_SAMPLE_RATE_16K;
    audio_dac.init.outfrom = HEADPHONE;
#ifndef    DAC_USE_SRC0
    audio_dac.init.src_sel = AHB;
    audio_dac.init.data_format = width_16bit_useful_16bit;
#else
    audio_dac.init.src_sel = SRC;
    audio_dac.init.data_format = width_32bit_useful_low_16bit;
#endif
    audio_dac.init.mix_source = MIX_SOURCE_DAC_DETACHED;
    audio_dac.init.vol = denoise_param.hp_volume;
    audio_dac.init.eq_type = EQ_NORMAL_TYPE;
    audio_dac.init.inverse = denoise_param.dac_output_inverse;
    audio_dac.dma_handle = &dac_dma;
    hal_audio_dac_init(&audio_dac);
    audio_dac_EQ_init();
    audio_dac_drc_init();
    dac_dma_cfg();
    audio_dac_cmd(&audio_dac, ENABLE);
}

主要通过结构体传入参数,结构体的赋值通过结构体枚举变量成员传入:

typedef struct  dac_init_typedef
{
    adc_track_typedef               track;           /*声道数*/
    dac_sample_rate_typedef         sample_rate;     /*采样率*/
    dac_outfrom_typedef             outfrom;         /*输出类型*/
    src_sel_type_def                src_sel;         /*AHB或SRC*/
    dac_data_format_typedef         data_format;     /*数据对齐格式*/
    dac_mix_sorce_def               mix_source;      /*mix设置*/
    uint32_t                        vol;             /*音量设置*/
    eq_param_class_type             eq_type;         /*EQ类型*/
    dac_param_inverse_type          inverse;         /*输出为差分或正常*/
} dac_init_typedef;

2.5音频算法接口说明

1722512619376

/**
 * 音频算法初始化
 * @param: none
 * @return: none.
 */
void denoise_init(void)
{
    plxc_set_model_addr((uint32_t)(FW_HEADER->BIN[1].ADDR + 0x4000000));// set ai denoise mod addr
	plxc_algo_init();//init ai denoise algo
	plxc_set_denoise_level(250); // set ai denoise level
	plxc_set_audio_callback(getaudio);// set callback function
}


/**
 * 向算法输入原始音频数据
 *
 * @param: audio:原始音频数据的缓存地址
 *         num_samples:音频数据的点数
           (uint32_t)audio_buffer[0]:主通道
           (uint32_t)audio_buffer[1]:参考通道
 * @return: none.
 */
void push_primitive_audio_data(int16_t *audio, uint32_t num_samples)
{
	...
    if ((gAudioPrimitive != (void *)0) && (gAudioPrimitive->audioListener != (void *)0))
    {
        gAudioPrimitive->audioListener(0, (uint32_t)audio_buffer[0], (uint32_t)audio_buffer[1]);
    }
    ...
}

/**
 * 音频算法计算完成后回调函数,从该函数获取数据
 * @param: audio0:音频数据0buff地址
 *         audio1:音频数据1buff地址
 *         num_samples:音频数据的点数
 * @return: none.
 */
void get_audio(int16_t *audio0, int16_t *audio1, uint32_t num_samples)
{
    uint16_t temp_buff[AUDIO_CALLBACK_LEN * 2];
    ...
    for (uint16_t i = 0; i < num_samples; i++)/*输出1路降噪前,1路降噪后的数据*/
    {
        temp_buff[2 * i + 0] = audio1[i];
        temp_buff[2 * i + 1] = audio0[i];
    }
    ...
    src1_write_data((uint8_t *)temp_buff, AUDIO_CALLBACK_LEN);//将降噪后的数据,通过SRC后由DAC播出
}