LINEIN_AUX相关应用
📎 原始文档:https://www.kdocs.cn/l/cmKrARYMyX1A LINEIN/AUX相关应用
本文档旨在指导用户快速使用杰理方案调试linein/AUX相关的应用,进行快速初步了解。
注:LINEIN和AUX名称现已无明显区分,都是指音频输入接口
硬件:
AC695N/AC696N:aux信号进主控信号幅度 vpp不能超过1.2V,因此需要增加电阻分压。检测电阻不能省。
AC700N:一般情况下做头戴耳机,AUX不进主控,完全是作为有线耳机使用,接法如下,AUX检测电阻不能省。
AC700N:如果aux要进主控,可以选mic作为输入引脚,注意需要选择两路不同的AMUX 才可以做立体声输入
aux信号进主控信号幅度 vpp不能超过1.2V
概述:
LINEI/AUX 功能相应的代码配置,在各板级头文件件中,如apps\soundbox\board\br23\board_ac695x_demo\board_ac695x_demo_cfg.h
// linein配置 //
//*********************************************************************************//
#define TCFG_LINEIN_ENABLE TCFG_APP_LINEIN_EN // linein使能
// #define TCFG_LINEIN_LADC_IDX 0 // linein使用的ladc通道,对应ladc_list
#define TCFG_LINEIN_LR_CH AUDIO_LIN0_LR
#define TCFG_LINEIN_CHECK_PORT IO_PORTB_03 // linein检测IO
#define TCFG_LINEIN_PORT_UP_ENABLE 1 // 检测IO上拉使能
#define TCFG_LINEIN_PORT_DOWN_ENABLE 0 // 检测IO下拉使能
#define TCFG_LINEIN_AD_CHANNEL NO_CONFIG_PORT // 检测IO是否使用AD检测
#define TCFG_LINEIN_VOLTAGE 0 // AD检测时的阀值
#define TCFG_LINEIN_INPUT_WAY LINEIN_INPUT_WAY
#define TCFG_LINEIN_MULTIPLEX_WITH_SD DISABLE // linein 检测与 SD cmd 复用
#define TCFG_LINEIN_SD_PORT 0// 0:sd0 1:sd1 //选择复用的sd口
LINEIN/AUX进来的信号源分为数字通道和模拟通道两种方式,数字通道经过AD采集,模拟通道可以将信号源直接输出到DAC模块。
模拟通道:
信号源会通过linein的引脚或DAC某单个声道,经过芯片内部增益放大电路后(默认会放大2dB)输出到DAC。
内部增益放大电路的开关在
include_lib\media\media_develop\media\cpu\br23\asm\audio_linein.h
/*
*linein输入级增益控制,只有0或者1两级
*0:正常增益
*1:增益X2
*/
void audio_linein_gain(u8 gain);
数字通道:
信号源会通过linein的引脚,经过芯片内部增益放大电路后()输出到DAC。
内部增益大小可以从include_lib\media\media_develop\media\cpu\br23\asm\audio_adc.h中获取。int audio_adc_linein_set_gain(struct audio_adc_ch *ch, int gain);接口描述上有。
以下是AC695N的示例:
/*
*********************************************************************
* Audio ADC Linein Gain
* Description: 设置linein增益
* Arguments : ch linein采样通道操作句柄
* sample_rate 采样率
* Return : 0 成功 其他 失败
* Note(s) : (1)linein adc的增益范围:0(-8dB)~15(7dB),8(0dB),step:1dB
* (2)增益设置规则:
* A:默认linein两个通道的增益一致:
* audio_adc_linein_set_gain(ch,gain);
* B:如果要分开设置,可以把参数gain分成高低16bit来设置:
* audio_adc_linein_set_gain(ch,(gain_l | (gain_r << 16)));
*********************************************************************
*/
int audio_adc_linein_set_gain(struct audio_adc_ch *ch, int gain);
LINEIN或MIC的电压输入范围:
AC692N:MIC和AUX走数字通道均支持3.0Vpp(高压);
AC696N/AC695N:AUX走数字通道支持1.2Vpp(低压),MIC支持0.6Vpp;
JL701N:MIC和AUX走数字通道均支持1.2Vpp(SDK默认开的低压,如果K歌音箱等应用不在意些许功耗的增加,需要软件修改SDK,改成2.0Vpp高压)
代码:
在app_main.c中会进入到app_linein_task();,该模式用于linein功能
应用端开发重点关注 ..\apps\soundbox\task_manager\linein文件夹下的源文件,
其中
linein.c是主要用于接收按键消息,设备消息,公共消息,根据相应的消息进行处理
linein_api.c提供了音量加减,模拟增益设置等api接口
linein_dev.c提供linein插入检测功能的api接口
在路径..\cpu\br23\audio_dec中audio_dec_linein.c和audio_dec_linein.h用于开启linein的数字通道的解码模块
常见问题以及功能示例:
1、AC695 LINEIN LADC底噪问题
JL_AUDIO->ADC_CON |= (BIT(25)|BIT(26)|BIT(27));
JL_AUDIO->ADC_CON |= (BIT(29)|BIT(30)|BIT(31));
需要更多的ram和mips
2、AC695的动态切换LINEIN AMUXN通道的问题
记得#define TCFG_DEC_PCM_ENABLE ENABLE的PCM解码要打开!
//////////////////////////20210603////////////////////////////////////////
void APP_switch_linein_ch(int ch)
{
SFR(JL_ANA->DAA_CON2, 1, 1, 0);//LIN0L_EN
SFR(JL_ANA->DAA_CON2, 5, 1, 0);//LIN1L_EN
SFR(JL_ANA->DAA_CON2, 3, 1, 0);//LIN0R_EN
SFR(JL_ANA->DAA_CON2, 7, 1, 0);//LIN1R_EN
switch (ch) {
case AUDIO_ADC_LINE0_LR:
JL_PORTA->DIR |= BIT(0) | BIT(1);
JL_PORTA->DIE &= ~(BIT(0) | BIT(1));
/* linein_open_chs = 2; */
/*
*ADC0 USE LINL ADC
*ADC1 USE LINR ADC
*/
/* JL_ANA->DAA_CON3 &= ~(BIT(3) | BIT(4)); */
/* SFR(JL_ANA->DAA_CON2, 1, 1, 1);//LIN0L_EN */
/* SFR(JL_ANA->DAA_CON2, 3, 1, 1);//LIN0R_EN */
break;
case AUDIO_ADC_LINE0_L:
JL_PORTA->DIR |= BIT(0);
JL_PORTA->DIE &= ~BIT(0);
/* JL_ANA->DAA_CON3 &= ~(BIT(3));// ADC0 USE LINL ADC */
break;
case AUDIO_ADC_LINE0_R:
JL_PORTA->DIR |= BIT(1);
JL_PORTA->DIE &= ~BIT(1);
/* JL_ANA->DAA_CON3 &= ~(BIT(4));// ADC1 USE LINR ADC */
break;
case AUDIO_ADC_LINE1_LR:
JL_PORTB->DIR |= BIT(7) | BIT(8);
JL_PORTB->DIE &= ~(BIT(7) | BIT(8));
/* linein_open_chs = 2; */
/* JL_ANA->DAA_CON3 &= ~(BIT(3) | BIT(4)); // ADC1 USE LINR ADC */
SFR(JL_ANA->DAA_CON2, 1, 1, 1);//LIN0L_EN
SFR(JL_ANA->DAA_CON2, 3, 1, 1);//LIN0R_EN
break;
case AUDIO_ADC_LINE1_L:
JL_PORTB->DIR |= BIT(7);
JL_PORTB->DIE &= ~BIT(7);
/* JL_ANA->DAA_CON3 &= ~(BIT(3));// ADC0 USE LINL ADC */
SFR(JL_ANA->DAA_CON2, 1, 1, 1);//LIN0L_EN
break;
case AUDIO_ADC_LINE1_R:
JL_PORTB->DIR |= BIT(8);
JL_PORTB->DIE &= ~BIT(8);
/* JL_ANA->DAA_CON3 &= ~(BIT(4));// ADC1 USE LINR ADC */
SFR(JL_ANA->DAA_CON2, 3, 1, 1);//LIN0R_EN
break;
case AUDIO_ADC_LINE2_LR:
JL_PORTB->DIR |= BIT(9) | BIT(10);
JL_PORTB->DIE &= ~(BIT(9) | BIT(10));
/* linein_open_chs = 2; */
/*
*ADC0 USE LINL ADC
*ADC1 USE LINR ADC
*/
/* JL_ANA->DAA_CON3 &= ~(BIT(3) | BIT(4)); */
SFR(JL_ANA->DAA_CON2, 5, 1, 1);//LIN1L_EN
SFR(JL_ANA->DAA_CON2, 7, 1, 1);//LIN1R_EN
break;
case AUDIO_ADC_LINE2_L:
JL_PORTB->DIR |= BIT(9);
JL_PORTB->DIE &= ~BIT(9);
/* JL_ANA->DAA_CON3 &= ~(BIT(3));// ADC0 USE LINL ADC */
SFR(JL_ANA->DAA_CON2, 5, 1, 1);//LIN1L_EN
break;
case AUDIO_ADC_LINE2_R:
JL_PORTB->DIR |= BIT(10);
JL_PORTB->DIE &= ~BIT(10);
/* JL_ANA->DAA_CON3 &= ~(BIT(4));// ADC1 USE LINR ADC */
SFR(JL_ANA->DAA_CON2, 7, 1, 1);//LIN1R_EN
break;
default:
break;
/* ladc_log("audio_adc_linein_open:ch err\n"); */
/* return -EINVAL; */
}
}
if(ladc_var.linein_ch.ch != linein->ch){
printf("\APP_switch_linein_ch------ \n");
APP_switch_linein_ch(linein->ch);
ladc_var.linein_ch.ch = linein->ch;
}


3、AC696linein使用限制
AC696只有一路ADC,所以不能同时使用linein双声道ADC输入,需要立体声时只能走模拟通道,但模拟调不了EQ;
FM 与 LINEIN 复用未使能,不可选择AUDIO_LIN1R_CH,同时也是不能使用AUDIO_LIN1_LR,当fm和linein复用时,linein接在fm引脚;
以上两点如果不注意,就会导致程序复位。
关于FM 与 LINEIN 复用 功能注意点:
- FM 与 LINEIN 复用 必须使用ADC 数字输入的方式。
- FM 与 LINEIN 复用,并且在蓝牙模式下,同时开启linein功能混合输出,打开linein的动作需要在蓝牙初始化完成后调用,不然会导致没有声音。
PS1:同时开启linein功能混合输出衍生注意点:BT 和 linein混合输出,走的ADC数字输入的时候,默认会出现linein 有声BT无声的情况,原因是两个解码默认并没有做叠加使能。
PS2:同时开启linein功能混合输出衍生问题点:BT 和 linein混合输出,走的ADC数字输入的时候,在music 模式下同时播放320Kwav 格式音频时,会出现卡顿声,并且有异常"w" 字符打印现象。
处理办法:提供一种处理思路就是,走mic_effect 的方式,直接将adc 的声音推到dac中去,并将原有的mic 通路更换为linein 通道,这里提供修改方式:与公版程序对比替换即可测试(需要自行将所有的不需要的mic音效节点都去掉):
ac696n_soundbox_sdk_v1.7.0_linein复用FM_mic_effect_使用linein通道(FM).rar
4、linein使用注意点
- 当要使用频谱,频响或者其他算法功能时需要注意程序是否配置为数字输入,模拟输入无法获得数据去处理,特别是AC696一定要注意上文第三点去使用;
- linein尽可能不要与其他功能做IO口复用,能避免各类检测概率出错问题
5、AC700N蓝牙和linein同时输出到dac
【金山文档】 AC700N_earphone_release_V1.3.5_linein_mix
https://kdocs.cn/l/cj1zeIED4lZU
将下面的代码替换到audio_linein_demo.c文件,linein IO是PA1和PB8
/*
****************************************************************************
* Audio ADC Demo
*
*Description : Audio ADC使用范例
*Notes : (1)本demo为开发测试范例,请不要修改该demo, 如有需求,请自行
* 复制再修改
* (2)linein工作模式说明
* A.单端隔直(cap_mode)
* 可以选择linein供电方式:外部供电还是内部供电(linein_bias_inside = 1)
* B.单端省电容(capless_mode)
* C.差分模式(cap_diff_mode)
****************************************************************************
*/
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "app_main.h"
#include "audio_config.h"
#include "audio_demo.h"
#include "audio_dvol.h"
#include "audio_codec_clock.h"
#if 1
#define ADC_DEMO_LOG printf
#else
#define ADC_DEMO_LOG(...)
#endif
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
static struct audio_dac_channel mic_ch = {0};
static u8 audio_adc_linein_vol = LINEIN_DVOL_MAX;
s16 mono_to_dual[ADC_DEMO_IRQ_POINTS * 2 + 4];
#define ADC_DEMO_CH_NUM 2 /*支持的最大采样通道(max = 2)*/
#define ADC_DEMO_BUF_NUM 2 /*采样buf数*/
#define ADC_DEMO_IRQ_POINTS 256 /*采样中断点数*/
#define ADC_DEMO_BUFS_SIZE (ADC_DEMO_CH_NUM * ADC_DEMO_BUF_NUM * ADC_DEMO_IRQ_POINTS)
struct adc_demo {
u8 adc_2_dac;
u8 linein_idx;
struct audio_adc_output_hdl adc_output;
struct adc_linein_ch linein_ch;
s16 adc_buf[ADC_DEMO_BUFS_SIZE];
OS_SEM sem;
u8 release;
u8 *buf;
u16 len;
};
static struct adc_demo *linein_demo = NULL;
int sound_pcm_dev_write(void *private_data, void *data, int len);
/*
*********************************************************************
* AUDIO linein OUTPUT
* Description: linein采样数据回调
* Arguments : pric 私有参数
* data linein数据
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 单声道数据格式
* L0 L1 L2 L3 L4 ...
* 双声道数据格式()
* L0 R0 L1 R1 L2 R2...
*********************************************************************
*/
static void adc_linein_demo_output(void *priv, s16 *data, int len)
{
/* putchar('O'); */
// printf("> %d %d\n", data[0], data[1]);
int wlen = 0;
if (linein_demo && linein_demo->adc_2_dac) {
linein_demo->len = len;
if (linein_demo->linein_idx == (LADC_CH_LINEIN_L | LADC_CH_LINEIN_R)) {
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
/*输出两个linein的数据到DAC两个通道*/
// putchar('a');
// wlen = audio_dac_write(&dac_hdl, data, len * 2);
// wlen = sound_pcm_dev_write(&mic_ch, data, len * 2);
linein_demo->len = len * 2;
#else
/*输出其中一个linein的数据到DAC一个通道*/
// putchar('b');
s16 *mono_data = data;
for (int i = 0; i < (len / 2); i++) {
mono_data[i] = data[i * 2]; /*linein_L*/
//mono_data[i] = data[i * 2 + 1]; /*linein_R*/
}
// wlen = audio_dac_write(&dac_hdl, mono_data, len);
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
} else {
/*输出一个linein的数据到DAC一个通道*/
// putchar('c');
// wlen = audio_dac_write(&dac_hdl, data, len);
// wlen = sound_pcm_dev_write(&mic_ch, data, len);
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
s16 *mono_data = data;
for (u16 i = 0; i < (len >> 1); i++) {
mono_to_dual[2 * i] = mono_data[i];
mono_to_dual[2 * i + 1] = mono_data[i];
}
data = mono_to_dual;
linein_demo->len = len * 2;
#endif
}
linein_demo->buf = data;
os_sem_set(&linein_demo->sem, 0);
os_sem_post(&linein_demo->sem);
}
}
void linein_demo_run(void *p)
{
struct adc_demo *stream = (struct adc_demo *)p;
stream->release = 0;
while(1){
int res = os_sem_pend(&stream->sem, 0);
if(res){
continue;
}
if (stream->release) {
while (1) {
os_time_dly(10000);
return;
}
}else{
int offset = 0;
int cnt = 0;
int wlen;
//可在此处添加自己的数据处理
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(LINEIN_DVOL, linein_demo->buf, linein_demo->len);
#endif
do {
wlen = sound_pcm_dev_write(&mic_ch, linein_demo->buf + (offset >> 1), linein_demo->len - offset);
offset = offset + wlen;
cnt ++;
} while ((offset != linein_demo->len) && (cnt < 1000));
if (offset != linein_demo->len) {
/* putchar('D'); */
printf("dac write err :%d %d\n", linein_demo->len, offset);
}
}
}
}
void audio_adc_linein_demo_close(void);
/*
*********************************************************************
* AUDIO ADC linein OPEN
* Description: 打开linein通道
* Arguments : linein_idx linein通道
* gain linein增益
* sr linein采样率
* linein_2_dac linein数据(通过DAC)监听
* Return : None.
* Note(s) : (1)打开一个linein通道示例:
* audio_adc_linein_demo_open(LADC_CH_LINEIN_L,10,16000,1);
* 或者
* audio_adc_linein_demo_open(LADC_CH_LINEIN_R,10,16000,1);
* (2)打开两个linein通道示例:
* audio_adc_linein_demo_open(LADC_CH_LINEIN_R|LADC_CH_LINEIN_L,10,16000,1);
*********************************************************************
*/
void audio_adc_linein_demo_open(u8 linein_idx, u8 gain, u16 sr, u8 linein_2_dac)
{
if(linein_demo){
return;
}
#if TCFG_AUDIO_MUSIC_SAMPLE_RATE
sr = TCFG_AUDIO_MUSIC_SAMPLE_RATE;
#endif
if(audio_dac_is_working(&dac_hdl)){
sr = audio_dac_get_sample_rate(&dac_hdl);
}
ADC_DEMO_LOG("audio_adc_linein_demo open:%d,gain:%d,sr:%d,linein_2_dac:%d\n", linein_idx, gain, sr, linein_2_dac);
linein_demo = zalloc(sizeof(struct adc_demo));
if (linein_demo) {
//step0:打开linein通道,并设置增益
audio_adc_linein_open(&linein_demo->linein_ch, linein_idx, &adc_hdl);
audio_adc_linein_set_gain(&linein_demo->linein_ch, linein_idx, gain);
//step1:设置linein通道采样率
audio_adc_linein_set_sample_rate(&linein_demo->linein_ch, sr);
//step2:设置linein采样buf
audio_adc_linein_set_buffs(&linein_demo->linein_ch, \
linein_demo->adc_buf, \
ADC_DEMO_IRQ_POINTS * 2, \
ADC_DEMO_BUF_NUM);
//step3:设置linein采样输出回调函数
linein_demo->adc_output.handler = adc_linein_demo_output;
audio_adc_linein_add_output_handler(&linein_demo->linein_ch, &linein_demo->adc_output);
/*监听配置(可选)*/
linein_demo->adc_2_dac = linein_2_dac;
linein_demo->linein_idx = linein_idx;
if (linein_2_dac) {
audio_codec_clock_set(AUDIO_PCM_MODE, AUDIO_CODING_PCM, 0);
extern int sound_pcm_dev_start(void *private_data, int sample_rate, s16 volume);
audio_dac_new_channel(&dac_hdl, &mic_ch);
struct audio_dac_channel_attr attr;
attr.delay_time = 50;
attr.protect_time = 8;
attr.write_mode = WRITE_MODE_FORCE;
audio_dac_channel_set_attr(&mic_ch, &attr);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(LINEIN_DVOL, audio_adc_linein_vol, LINEIN_DVOL_MAX, LINEIN_DVOL_FS, -1);
#endif
sound_pcm_dev_start(&mic_ch, sr, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
// ADC_DEMO_LOG("max_sys_vol:%d\n", get_max_sys_vol());
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
linein_demo->release = 1;
os_sem_create(&linein_demo->sem, 0);
os_task_create(linein_demo_run, linein_demo, 5, 128, 0, "linein_demo");
// ADC_DEMO_LOG("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
// audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
// audio_dac_set_sample_rate(&dac_hdl, sr);
// audio_dac_start(&dac_hdl);
}
//step4:启动linein通道采样
audio_adc_linein_start(&linein_demo->linein_ch);
}
ADC_DEMO_LOG("audio_adc_linein_demo start succ\n");
}
int audio_adc_get_current_sr(void)
{
if(linein_demo){
return linein_demo->linein_ch.sample_rate;
}
return 0;
}
void audio_adc_linein_demo_set_vol(u8 vol)
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if(vol > LINEIN_DVOL_MAX){
vol = LINEIN_DVOL_MAX;
}
audio_adc_linein_vol = vol;
audio_digital_vol_set(LINEIN_DVOL, audio_adc_linein_vol);
#endif
}
void audio_adc_linein_demo_vol_up(void)
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if(audio_adc_linein_vol < LINEIN_DVOL_MAX){
audio_adc_linein_vol++;
}
audio_digital_vol_set(LINEIN_DVOL, audio_adc_linein_vol);
#endif
}
void audio_adc_linein_demo_vol_down(void)
{
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
if(audio_adc_linein_vol){
audio_adc_linein_vol--;
}
audio_digital_vol_set(LINEIN_DVOL, audio_adc_linein_vol);
#endif
}
/*
*********************************************************************
* AUDIO ADC linein CLOSE
* Description: 关闭linein采样模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_adc_linein_demo_close(void)
{
ADC_DEMO_LOG("audio_adc_linein_demo_close\n");
if (linein_demo) {
audio_adc_linein_del_output_handler(&linein_demo->linein_ch, &linein_demo->adc_output);
audio_adc_linein_close(&linein_demo->linein_ch);
linein_demo->release = 1;
os_task_del("linein_demo");
os_sem_del(&linein_demo->sem, 0);
sound_pcm_dev_stop(&mic_ch);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(LINEIN_DVOL);
#endif
OS_ENTER_CRITICAL();
free(linein_demo);
linein_demo = NULL;
OS_EXIT_CRITICAL();
audio_codec_clock_del(AUDIO_PCM_MODE);
}
}
#if AUDIO_DEMO_LP_REG_ENABLE
static u8 linein_demo_idle_query()
{
return linein_demo ? 0 : 1;
}
REGISTER_LP_TARGET(linein_demo_lp_target) = {
.name = "linein_demo",
.is_idle = linein_demo_idle_query,
};
#endif/*AUDIO_DEMO_LP_REG_ENABLE*/
修改图:


打开调用
audio_adc_linein_demo_open(LADC_CH_LINEIN_L | LADC_CH_LINEIN_R, 5, 48000, 1);
关闭调用
audio_adc_linein_demo_close();