海思hi3518ev300说明书_海思3516dv300方案开发

大家好,又见面了,我是你们的朋友全栈君。

1.硬件

Hi3516支持内置AudioCodec/外置音频解码芯片; 由于这里硬件上外接FM1288,故走的是外置,通过I2S接入, 通过MIC单端/差分输入音频.
由于之前一直调试内置Codec,这里任然保留内置相关代码;

2.重要概念

2.1. I2S相关概念

(1)LRCLK (帧时钟,也称为WS)
	当LRCLK为低电平时表示传输左声道,高电平时表示传输右声道,
	LRCLK的频率 = 采样频率

(2)SCLK(串行时钟) ,也叫BCLK(位时钟);方波形式存在
	对应数字音频的每一位数据,SCLK都有一个脉冲.
	SCLK的频率 = 2 * 采样频率 * 采样位数;

 (3) SDATA 串行数据,就是二进制补码表示的音频数据.

(4) MCLK(主时钟,也叫系统时钟)
	一般采样频率的256倍或384倍,它并不是必须的,可有可无,具体看要求.

(5)
	I2S是一种比较简单的数字接口协议,没有地址或设备选择机制;
	在I2S总线上,只能同时存在一个主设备和发送设备;
	主设备可以是发送设备,也可以是接收设备,或是协调发送设备和接收设备的其他控制设备;

2.2 关键点

(1)  底层时序不需要我们自己实现,如i2s如何控制FM1288等.
(2) i2c用的连在主芯片(hi3516dv300)上,就可以直接用底层的驱动.
(3) FM1288的i2s,应该已经封装到mpp里面,只需通过i2c配置好codec,然后通过mpp库操作ai/ao接口即可.
(4) 通过i2c配置下寄存器,一般codec都是配置i2s的模式(主/从,采样率等参数),i2s的bclk,ws等;
(5) 主时钟(MCLK)要看看是有海思做主(master)还是由codec()做主 (slave);
(6) 一般都是由主设备提供MCLK,帧时钟和位时钟都是通过这个MLCK计算出来的.

3.音频上行(ai->aenc)

软件设计上参考: 对应SDK/mpp/sample/audio/sample_audio.c

先配置i2c.通过引脚图及hdmi命令配置:
如:system("himm 0x114F004C 0x103");

据手册: 在 AI/AO 设备主模式下,建议用户先配置好AI/AO,在配置codec;

3.1. 输入初始化

	HI_S32 rc ,i;
AIO_ATTR_S stAioAttr;
AUDIO_DEV   AiDev = 0;
stAioAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
stAioAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
stAioAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
stAioAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
stAioAttr.u32EXFlag      = 1;
stAioAttr.u32FrmNum      = 30;
stAioAttr.u32PtNumPerFrm = 320;
stAioAttr.u32ChnCnt      = 2; //最大只能支持2个
stAioAttr.u32ClkSel      = 1;
//stAioAttr.enI2sType = AIO_I2STYPE_INNERCODEC; 选择内置Codec解码
stAioAttr.enI2sType      = AIO_I2STYPE_EXTERN;//若外部单独有解码芯片,需要选择外部,另需要确认是否支持;
rc = HI_MPI_AI_SetPubAttr(AiDev, &stAioAttr);
//rc错误处理,以下均省略...
rc = HI_MPI_AI_Enable(AiDev);
AI_CHN_PARAM_S pstChnParam;
for(int j = 0; j < stAioAttr.u32ChnCnt; j++)
{ 

rc = HI_MPI_AI_GetChnParam(AiDev, j, &pstChnParam);
pstChnParam.u32UsrFrmDepth = 30;
rc = HI_MPI_AI_SetChnParam(AiDev, j,&pstChnParam);
rc = HI_MPI_AI_EnableChn(AiDev, j);
}  
#if 1 //这部分据实际情况慢慢调
//3516dv300输入不支持 HI_MPI_AI_SetVqeAttr,可用HI_MPI_AI_SetTalkVqeAttr
//声音质量增强功能(Talk)相关属性
AUDIO_DEV AiDevId = 0;
AI_CHN AiChn = 0;
AUDIO_DEV AoDevId = 0;
AO_CHN AoChn = 0;
AI_TALKVQE_CONFIG_S pstVqeConfig;
memset(&pstVqeConfig, 0, sizeof(AI_TALKVQE_CONFIG_S));
pstVqeConfig.u32OpenMask = AI_TALKVQE_MASK_HPF | AI_TALKVQE_MASK_ANR ;//| AI_TALKVQE_MASK_AGC ;
pstVqeConfig.s32WorkSampleRate = AUDIO_SAMPLE_RATE_8000;
pstVqeConfig.s32FrameSample = 320;
pstVqeConfig.enWorkstate = VQE_WORKSTATE_MUSIC ;
//去低频,表现为轰轰不舒适声音
pstVqeConfig.stHpfCfg.bUsrMode = HI_TRUE;
pstVqeConfig.stHpfCfg.enHpfFreq = AUDIO_HPF_FREQ_150;//建议120或150
//回声抵消
pstVqeConfig.stAecCfg.bUsrMode = HI_FALSE;
// pstVqeConfig.stAecCfg.s8CngMode = 1;//舒适噪音模式
// pstVqeConfig.stAecCfg.s8NearAllPassEnergy = 1;//判断是否无光泽传输的远端能量阈值:
// pstVqeConfig.stAecCfg.s8NearCleanSupEnergy = 2;//近端信号强制复位的能量门限:
// pstVqeConfig.stAecCfg.s16DTHnlSortQTh = 16384;
// pstVqeConfig.stAecCfg.s16EchoBandLow = 10;//语音处理band1,低频参数,
// pstVqeConfig.stAecCfg.s16EchoBandHigh = 25;//41;//语音处理band1,高频参数,
// pstVqeConfig.stAecCfg.s16EchoBandLow2 = 28;//47;
// pstVqeConfig.stAecCfg.s16EchoBandHigh2 = 35;//63;
// HI_S16 s16ERLBand[6] = {4, 6, 36, 49, 50, 51};
// HI_S16 s16ERL[7] = {7, 10, 16, 10, 18, 18, 18};
// memcpy(pstVqeConfig.stAecCfg.s16ERLBand,s16ERLBand,sizeof(s16ERLBand));
// memcpy(pstVqeConfig.stAecCfg.s16ERL,s16ERL,sizeof(s16ERL));
// pstVqeConfig.stAecCfg.s16VioceProtectFreqL = 3;
// pstVqeConfig.stAecCfg.s16VioceProtectFreqL1 = 6;
//去除外界噪音
pstVqeConfig.stAnrCfg.bUsrMode = HI_TRUE;
pstVqeConfig.stAnrCfg.s16NrIntensity = 15;//[0~25]越大降噪力度越高,损伤越高.
pstVqeConfig.stAnrCfg.s16NoiseDbThr = 60;//[30~60]越大,检测力度越弱,声音更平滑
pstVqeConfig.stAnrCfg.s8SpProSwitch = 1;//[0/1]是否开启对音乐细节检测,喧闹场景不建议开
//AGC 更多是放大输入源的声音
pstVqeConfig.stAgcCfg.bUsrMode    = HI_FALSE;
#if 0
pstVqeConfig.stAgcCfg.s8TargetLevel = -2;
pstVqeConfig.stAgcCfg.s8NoiseFloor = -40;
pstVqeConfig.stAgcCfg.s8MaxGain = 30;
pstVqeConfig.stAgcCfg.s8AdjustSpeed = 10;
pstVqeConfig.stAgcCfg.s8ImproveSNR = 2;//上限6db
pstVqeConfig.stAgcCfg.s8UseHighPassFilt = 3;
pstVqeConfig.stAgcCfg.s8OutputMode = 0;
pstVqeConfig.stAgcCfg.s16NoiseSupSwitch = 1;//开启噪声抑制
#endif
//遇到库找不到请看下面
rc = HI_MPI_AI_SetTalkVqeAttr(AiDevId, AiChn, AoDevId, AoChn,&pstVqeConfig);
rc = HI_MPI_AI_EnableVqe(AiDevId, AiChn);
#endif

3.2. 输出初始化

	HI_S32 rc ,i;
HI_S32 s32AoChnCnt; 
AIO_ATTR_S stAioAttr;
AUDIO_DEV   AoDev = 0;
rc = HI_MPI_AO_Disable(AoDev );//先禁用AO设备
stAioAttr.enSamplerate   = AUDIO_SAMPLE_RATE_8000;
stAioAttr.enBitwidth     = AUDIO_BIT_WIDTH_16;
stAioAttr.enWorkmode     = AIO_MODE_I2S_MASTER;
stAioAttr.enSoundmode    = AUDIO_SOUND_MODE_MONO;
stAioAttr.u32EXFlag      = 1;
stAioAttr.u32FrmNum      = 30;
stAioAttr.u32PtNumPerFrm = 320;
stAioAttr.u32ChnCnt      = 2;
stAioAttr.u32ClkSel      = 1;
//stAioAttr.enI2sType = AIO_I2STYPE_INNERCODEC;
stAioAttr.enI2sType      = AIO_I2STYPE_EXTERN;//若外部单独有解码芯片,需要选择外部,另需要确认是否支持;
rc = HI_MPI_AO_SetPubAttr(AoDev , &stAioAttr);
rc = HI_MPI_AO_Enable(AoDev );
/* enable AO channle */
s32AoChnCnt = stAioAttr.u32ChnCnt;
for (i = 0; i < s32AoChnCnt >> stAioAttr.enSoundmode; i++)
{ 

rc = HI_MPI_AO_EnableChn(AoDev , i);
}
#if 0 //没用到
AUDIO_DEV AoDevId = 0;
AO_CHN AoChn = 0;
AO_VQE_CONFIG_S pstVqeConfig;
memset(&pstVqeConfig, 0, sizeof(AO_VQE_CONFIG_S));
pstVqeConfig.u32OpenMask = AO_VQE_MASK_HPF | AO_VQE_MASK_ANR | AO_VQE_MASK_AGC;
pstVqeConfig.s32WorkSampleRate = AUDIO_SAMPLE_RATE_8000;
pstVqeConfig.s32FrameSample = 320;
pstVqeConfig.enWorkstate = VQE_WORKSTATE_COMMON ;
//高通滤波功能相关配置
pstVqeConfig.stHpfCfg.bUsrMode = HI_TRUE;
pstVqeConfig.stHpfCfg.enHpfFreq = AUDIO_HPF_FREQ_150;
//去噪
pstVqeConfig.stAnrCfg.bUsrMode = HI_TRUE;//用户模式
pstVqeConfig.stAnrCfg.s16NrIntensity = 15;//[0~25]越大降噪力度越高,损伤越高.
pstVqeConfig.stAnrCfg.s16NoiseDbThr = 60;//[30~60]越大,检测力度越弱,声音更平滑
pstVqeConfig.stAnrCfg.s8SpProSwitch = 1;//[0/1]是否开启对音乐细节检测,喧闹场景不建议开
//自动增益控制
pstVqeConfig.stAgcCfg.bUsrMode    = HI_TRUE;
pstVqeConfig.stAgcCfg.s8TargetLevel = -2;
pstVqeConfig.stAgcCfg.s8NoiseFloor = -20;
pstVqeConfig.stAgcCfg.s8MaxGain = 30;
pstVqeConfig.stAgcCfg.s8AdjustSpeed = 10;
pstVqeConfig.stAgcCfg.s8ImproveSNR = 0;//上限6db
pstVqeConfig.stAgcCfg.s8UseHighPassFilt = 0;
pstVqeConfig.stAgcCfg.s8OutputMode = 0;
pstVqeConfig.stAgcCfg.s16NoiseSupSwitch = 1;//开启噪声抑制
rc = HI_MPI_AO_SetVqeAttr(AoDevId, AoChn, &pstVqeConfig);
rc = HI_MPI_AO_EnableVqe(AoDevId, AoChn);
printf("HI_MPI_AO_EnableVqe AoDevId[%d] rc[%d] \n",AoDevId,rc);
#endif

3.3. codec配置

如果是外置解码芯片,这里不需要配置内部Codec; 外置解码芯片就相当于codec;
应该不需要配置这么多,视情况而定!
	//func(enSamplerate) enSamplerate传进来
HI_S32 fdAcodec= -1;
HI_S32 ret = HI_SUCCESS;
ACODEC_FS_E i2s_fs_sel;   
switch (enSamplerate)
{ 

case AUDIO_SAMPLE_RATE_8000:
i2s_fs_sel = ACODEC_FS_8000;
break;
case AUDIO_SAMPLE_RATE_16000:
i2s_fs_sel = ACODEC_FS_16000;
break;
case AUDIO_SAMPLE_RATE_32000:
i2s_fs_sel = ACODEC_FS_32000;
break;
case AUDIO_SAMPLE_RATE_48000:
i2s_fs_sel = ACODEC_FS_48000;
break;
default:
i2s_fs_sel = ACODEC_FS_8000;
break;
}
fdAcodec = open("/dev/acodec",O_RDWR);
if(fdAcodec < 0)
{ 

printf("[%s %d] open dev/acodec failed!\n",__FUNCTION__,__LINE__);
return HI_FALSE;
}
//将内置Codec恢复为默认设置
if(ioctl(fdAcodec, ACODEC_SOFT_RESET_CTRL))
{ 

printf("reset the audio code to the default config error\n");
}
//设置I2s1采样率
if(ioctl(fdAcodec, ACODEC_SET_I2S1_FS, &i2s_fs_sel))
{ 

printf("[%s %d] set i2s1 fs failed!\n",__FUNCTION__,__LINE__);
return HI_FALSE;
}
//输入方式选择
ACODEC_MIXER_E input_mode = ACODEC_MIXER_IN1;//单端输入 ACODEC_MIXER_IN_D;//:差分
if (ioctl(fdAcodec, ACODEC_SET_MIXER_MIC, &input_mode))
{ 

printf("%s: select acodec input_mode failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
int iVol = 50;//[-78-80] 建议[19-50]
#if 1
//输入音量之PGA模块
if (ioctl(fdAcodec, ACODEC_SET_INPUT_VOL, &iVol))
{ 

printf("%s: ioctl ACODEC_SET_INPUT_VOL failed\n", __FUNCTION__);
return HI_FALSE;
}
unsigned int gain_mac;
gain_mac = 15;//15为最大增益30db 16:-1.5db
if (ioctl(fdAcodec, ACODEC_SET_GAIN_MICL, &gain_mac))
{ 

printf("%s: ioctl ACODEC_SET_GAIN_MICL failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
if (ioctl(fdAcodec, ACODEC_SET_GAIN_MICR, &gain_mac))
{ 

printf("%s: ioctl ACODEC_SET_GAIN_MICR failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
//输入音量之BOOST模块
if (ioctl(fdAcodec, ACODEC_SET_INPUT_VOL, &iVol))
{ 

printf("%s: ioctl ACODEC_SET_INPUT_VOL failed\n", __FUNCTION__);
return HI_FALSE;
}
unsigned int enable_boostl;
enable_boostl = 0x1;//取1时模拟增益增加20db
if (ioctl(fdAcodec, ACODEC_ENABLE_BOOSTL, &enable_boostl))
{ 

printf("%s: ioctl ACODEC_ENABLE_BOOSTL failed\n", __FUNCTION__);
return HI_FALSE;
}
unsigned int enable_boostr;
enable_boostr = 0x1;//取1时模拟增益增加20db
if (ioctl(fdAcodec, ACODEC_ENABLE_BOOSTR, &enable_boostr))
{ 

printf("%s: ioctl ACODEC_ENABLE_BOOSTR failed\n", __FUNCTION__);
return HI_FALSE;
}
//#else
//输入音量之ADC模块
if (ioctl(fdAcodec, ACODEC_SET_INPUT_VOL, &iVol))
{ 

printf("%s: ioctl ACODEC_SET_INPUT_VOL failed\n", __FUNCTION__);
return HI_FALSE;
}
ACODEC_VOL_CTRL vol_ctrl;
vol_ctrl.vol_ctrl_mute = 0;//不静音
vol_ctrl.vol_ctrl = 0;//[0~127] 0音量最大
//左声道输入音量控制
if(ioctl(fdAcodec, ACODEC_SET_ADCL_VOL, &vol_ctrl))
{ 

printf("%s: acodec set adcl vol failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
if(ioctl(fdAcodec, ACODEC_SET_ADCR_VOL, &vol_ctrl))
{ 

printf("%s: acodec set adcr vol failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
#endif
//输出总音量控制
iVol = 4; //[-126~6]
if (ioctl(fdAcodec, ACODEC_SET_OUTPUT_VOL, &iVol))
{ 

printf("[%s %d] set output vol fs failed!\n",__FUNCTION__,__LINE__);
}
//把MICIN静音(MUTE)功能关闭
#if 1
HI_U32 u32MuteCtrl = 0;
if(ioctl(fdAcodec, ACODEC_SET_MICL_MUTE, &u32MuteCtrl))
{ 

printf("%s: select acodec mute_l failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
if(ioctl(fdAcodec, ACODEC_SET_MICR_MUTE, &u32MuteCtrl))
{ 

printf("%s: select acodec mute_r failed\n", __FUNCTION__);
ret = HI_FAILURE;
}
#endif
close(fdAcodec);

4.音频下行 (adec->ao)

一般情况上行没问题,下行只是方向相反而已! 伪代码:

	HI_MPI_ADEC_CreateChn(chn,&解码参数);
HI_MPI_SYS_Bind(HI_ID_ADEC,..HI_ID_AO);
while(获取流)
{ 

HI_MPI_ADEC_SendStream(chn,&码流结构体,阻塞否?);
}

5.遇到的问题

问题1:
HI3516DV300 HI_MPI_AI_EnableVqe调节音频使能Vqe时出现.
dlopen libhive_common.so/libsecurec.so or libhive_AEC.so failed
解决方案: 
在sdk中找到对应的.so文件,放到 usr/lib 下并记得改权限(重要).
问题2:
下行过程遇到的问题:HI_MPI_ADEC_SendStream 0xA0188040(码流错误);
排查过程:
1> 初步怀疑解码参数问题,检查后排除;可以在send_stream前面将下行码流保存成对应格式,如.g711a格式,在pc上播放;首先确保码流到这里能播放;
2> 第一步能通过,那么试试自编自解是否可行(首先确保上行ok,音频功放ok),在上行前先创建解码通道并绑定ao,在HI_MPI_AENC_GetStream获取流后立马又发给ao;
3> 第二步基本都没问题,记录下发送成功的字节长度;最终将问题定位到海思头(一定确保上行码流长度和下行码流长度一致)
如上行324字节(320+4字节海思头),下行也要保证一样,多了少了可能就有问题!!!

6.fm1288芯片

  1. 首先,向厂家要一份linux的驱动参考代码,方便参考配置;
  2. fm1288芯片使能的标志是MIC_BIAS引脚输出高电平;
  3. PWD# 引脚需要上电, RST#引脚需要复位在拉高,且需要在其后的90ms的软件初始化;
  4. I2S类型需选择AIO_I2STYPE_EXTERN才能通过I2C配置成功,不然一直显示超时;
  5. 参考 https://blog.csdn.net/qq_37565330/article/details/79460692

7.总结

多看手册,一般手册上都能找到答案.
结合sdk示例.
若软件上没啥问题,可适当排查硬件.硬件时钟,与示波器结合.分析时序等等一步步排查;

参考:https://baike.baidu.com/item/I2S/3443390?fr=aladdin

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190250.html原文链接:https://javaforall.cn

原文地址:https://cloud.tencent.com/developer/article/2157340

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340