AC63_BT_SDK/cpu/br34/audio_mic_capless.c

420 lines
13 KiB
C
Raw Normal View History

2025-02-18 15:40:42 +08:00
/*
****************************************************************************
* Audio Mic_Capless Module
*mic模块
*mic的信号输出接到芯片的MICIN引脚(PA1)
****************************************************************************
*/
#include "system/includes.h"
#include "media/includes.h"
#include "app_config.h"
#include "app_action.h"
#include "app_main.h"
#include "audio_config.h"
#define LOG_TAG "[APP_AUDIO]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#define TCFG_AUDIO_MC_ENABLE 1 //mic_capless_enable
//#define MC_LOG_ENABLE
#ifdef MC_LOG_ENABLE
#define MC_LOG_I g_printf
#define MC_LOG_E r_printf
#else
#define MC_LOG_E(...)
#define MC_LOG_I(...)
#endif/*MC_LOG_ENABLE*/
const int const_mic_capless_dtb = TCFG_MC_DTB_FIXED;
#if TCFG_AUDIO_MC_ENABLE
extern struct adc_platform_data adc_data;
extern void delay_2ms(int cnt);
extern void wdt_clear(void);
typedef struct {
u8 save_bias_res; /*trim结果是否保存*/
u8 trim; /*trim状态*/
u8 cur_bias_res;
OS_SEM sem;
} MicCapless_trim_t;
MicCapless_trim_t *mc_trim = NULL;
#define MC_TRIM_P BIT(0)
#define MC_TRIM_N BIT(1)
#define LADC_CAPLESS_ADJUST_SAVE
#ifdef LADC_CAPLESS_ADJUST_SAVE
#define DIFF_RANGE 50
#define CFG_DIFF_RANGE 100
#define CHECK_INTERVAL 10
#endif/*LADC_CAPLESS_ADJUST_SAVE*/
#define DACDTB_RANGE_MAX 8100
#define DACDTB_RANGE_MIN 6600
#define MIC_CAPLESS_ADJUST_BUD_DEFAULT 0
#define MIC_CAPLESS_ADJUST_BUD 100
#define MC_TRIM_SUCC 0
#define MC_TRIM_ERR 1
#define MC_TRIM_TIMEOUT 300
static const u8 mic_bias_tab[] = {0, 20, 12, 28, 4, 18, 10, 26, 2, 22, 14, 30, 17, 21, 6, 25, 29, 27, 31, 5, 3, 7};
#define MIC_BIAS_RSEL(x) SFR(JL_ADDA->ADA_CON0, 17, 5, x)
/*不支持自动校准,使用快速收敛*/
#if TCFG_MC_BIAS_AUTO_ADJUST
u8 mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD_DEFAULT;
#else
u8 mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD;
#endif/*TCFG_MC_BIAS_AUTO_ADJUST*/
u32 read_capless_DTB(void)
{
u32 dacr32 = 0;
int ret = syscfg_read(CFG_DAC_DTB, &dacr32, sizeof(dacr32));
if (ret != sizeof(dacr32)) {
/*
*,使
*使
*/
log_info("DAC_DTB NULL,use fast feedback");
mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD;
return DACR32_DEFAULT;
}
log_info("cfg DTB0:%d,ret = %d\n", dacr32, ret);
return dacr32;
}
static u32 read_vm_capless_DTB(void)
{
u32 vm_dacr32 = 0;
int ret = syscfg_read(CFG_DAC_DTB, &vm_dacr32, sizeof(vm_dacr32));
if (ret != sizeof(vm_dacr32)) {
log_info("vm DTB read err\n");
return DACR32_DEFAULT;
}
log_info("vm DTB0:%d,ret = %d\n", vm_dacr32, ret);
return vm_dacr32;
}
typedef struct {
u8 adjust_complete;
u8 dtb_step_limit; //限制dtb收敛步进
u16 save_dtb;
} mc_var_t;
mc_var_t mc_var = {
.save_dtb = DACR32_DEFAULT,
.adjust_complete = 0,
.dtb_step_limit = 0,
};
#if TCFG_MC_DTB_STEP_LIMIT
/*获取省电容mic收敛信息配置*/
int get_mc_dtb_step_limit(void)
{
return mc_var.dtb_step_limit;
}
#endif /*TCFG_MC_DTB_STEP_LIMIT*/
void save_capless_DTB()
{
s16 diff;
u32 save_dac_dtb = 0;
MC_LOG_I("save_capless_DTB\n");
/*
*(1)dtb0或者dtb1有一个不是默认值
*(2)
*/
if ((mc_var.save_dtb != DACR32_DEFAULT) && mc_var.adjust_complete) {
/*读取记忆值,比较是否需要更新配置*/
u32 cfg_dacr32 = read_vm_capless_DTB();
/*分离dtb0和dtb1*/
u16 cfg_dtb0 = (cfg_dacr32 & 0xFFFF);
mc_var.adjust_complete = 0;
log_info("save_dtb0:%d,\n", mc_var.save_dtb);
log_info("cfg_dtb:0x%x,cfg_dtb0:%d\n", cfg_dacr32, cfg_dtb0);
diff = mc_var.save_dtb - cfg_dtb0;
if ((mc_var.save_dtb != DACR32_DEFAULT) && ((cfg_dtb0 == DACR32_DEFAULT) || ((diff < -CFG_DIFF_RANGE) || (diff > CFG_DIFF_RANGE)))) {
save_dac_dtb = mc_var.save_dtb;
log_info("dtb0 update:%d,0x%x,save_dac_dtb:%x\n", mc_var.save_dtb, mc_var.save_dtb, save_dac_dtb);
} else {
save_dac_dtb = cfg_dtb0;
log_info("dtb0 need't update:%d,diff:%d\n", mc_var.save_dtb, diff);
}
if (save_dac_dtb != cfg_dacr32) {
MC_LOG_I("store mc dtb:%x\n", save_dac_dtb);
syscfg_write(CFG_DAC_DTB, &save_dac_dtb, 4);
/* u32 tmp_dacr32 = 0;
syscfg_read(CFG_DAC_DTB,&tmp_dacr32,4);
MC_LOG_I("read mc dtb:%x\n",tmp_dacr32); */
}
} else {
log_info("dacr32 adjust uncomplete:%d,complete:%d\n", mc_var.save_dtb, mc_var.adjust_complete);
}
}
/*
*
*/
u16 get_ladc_capless_bud(void)
{
//printf("mc_bud:%d",mic_capless_adjust_bud);
return mic_capless_adjust_bud;
}
extern void audio_adc_mic_trim_open(u8 mic_idx, u8 gain);
extern void audio_adc_mic_trim_close(u8 mic_idx);
static u8 audio_mc_idle_query(void)
{
return (mc_trim ? 0 : 1);
}
REGISTER_LP_TARGET(audio_mc_device_lp_target) = {
.name = "audio_mc_device",
.is_idle = audio_mc_idle_query,
};
void mic_capless_trim_init(u8 mic_idx)
{
log_info("mic_capless_trim_init:%d\n", mic_idx);
mc_trim = zalloc(sizeof(MicCapless_trim_t));
if (mc_trim) {
if (mic_idx == LADC_CH_MIC_L) {
mc_trim->cur_bias_res = adc_data.mic_bias_res;
}
os_sem_create(&mc_trim->sem, 0);
mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD;
audio_adc_mic_trim_open(TCFG_AUDIO_ADC_MIC_CHA, app_var.aec_mic_gain);
log_info("mic_capless_trim_init succ\n");
} else {
log_info("mic_capless_trim_init err\n");
}
}
void mic_capless_trim_exit(u8 trim_result)
{
audio_adc_mic_trim_close(TCFG_AUDIO_ADC_MIC_CHA);
if (trim_result) {
log_info("save trim value,bias_res:%d,dtb0:%d\n", adc_data.mic_bias_res, mc_var.save_dtb);
log_info("save trim value,save_bias:%d,complete:%d\n", mc_trim->save_bias_res, mc_var.adjust_complete);
if (mc_trim->save_bias_res) {
int ret = syscfg_write(CFG_MC_BIAS, &adc_data.mic_bias_res, 1);
}
if (mc_var.adjust_complete) {
save_capless_DTB();
}
mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD_DEFAULT;
MC_LOG_E("mc_trim succ,use default adjust bud:%d\n", mic_capless_adjust_bud);
} else {
mic_capless_adjust_bud = MIC_CAPLESS_ADJUST_BUD;
MC_LOG_E("mc_trim err,use fast adjust bud:%d\n", mic_capless_adjust_bud);
}
free(mc_trim);
mc_trim = NULL;
log_info("mic_capless_bias_adjust_exit\n");
}
void mic_capless_trim_result(u8 result)
{
if (mc_trim) {
/*预收敛*/
log_info("mc_pre_auto_adjust_result:%d\n", result);
if (mc_trim->trim && (mc_trim->trim < (MC_TRIM_P | MC_TRIM_N))) {
mc_trim->save_bias_res = 1;
adc_data.mic_bias_res = mc_trim->cur_bias_res;
}
os_sem_post(&mc_trim->sem);
} else {
/*运行过程收敛*/
log_info("mc_run_auto_adjust_result:%d\n", result);
}
}
#define POWER_RESET_VDDIO_POR BIT(0) /*上电reset*/
#define POWER_RESET_PPINR BIT(3) /*长按reset*/
extern u8 power_reset_flag;
/*
*mic偏置是否需要校准,
*1power on reset
*2vm被擦除
*/
u8 mc_bias_adjust_check(void)
{
u8 por_flag = 0;
#if (TCFG_MC_BIAS_AUTO_ADJUST == MC_BIAS_ADJUST_ALWAYS)
return 1;
#endif
int ret = syscfg_read(CFG_POR_FLAG, &por_flag, 1);
if (ret == 1) {
if (por_flag == 0xA5) {
log_info("power on reset 1");
por_flag = 0;
ret = syscfg_write(CFG_POR_FLAG, &por_flag, 1);
return 1;
}
}
if (power_reset_flag & POWER_RESET_VDDIO_POR) {
log_info("power on reset 2");
return 1;
}
if (read_vm_capless_DTB() == DACR32_DEFAULT) {
log_info("vm format");
return 1;
}
return 0;
}
void mc_trim_init(int update)
{
u8 por_flag = 0;
u8 cur_por_flag = 0;
if (adc_data.mic_capless == 0) {
return;
}
/*
*1.update
*2.power_on_reset
*3.pin reset
*/
if (update || (power_reset_flag & POWER_RESET_VDDIO_POR) || (power_reset_flag & POWER_RESET_PPINR)) {
log_info("reset_flag:0x%x", power_reset_flag);
cur_por_flag = 0xA5;
}
int ret = syscfg_read(CFG_POR_FLAG, &por_flag, 1);
log_info("POR flag:%x-%x", cur_por_flag, por_flag);
if ((cur_por_flag == 0xA5) && (por_flag != cur_por_flag)) {
//log_info("update POR flag");
/*需要保存上电状态时因为开机有可能进入soft poweroff下次开机的时候需要知道上次的开机状态*/
ret = syscfg_write(CFG_POR_FLAG, &cur_por_flag, 1);
}
}
/*
* mic预收敛
*/
void mic_trim_run()
{
int ret = 0;
#if (!(TCFG_AUDIO_ADC_MIC_CHA & (LADC_CH_MIC_L | LADC_CH_MIC_R)))
return;
#endif
if (adc_data.mic_capless == 0) {
return;
}
log_info("mic_trim_run\n");
#if TCFG_MC_BIAS_AUTO_ADJUST
if (mc_bias_adjust_check()) {
//printf("MC_BIAS_ADJUST...");
/*
*
*1mic的偏置非法,mic头的情况
*2vm被擦除()
*/
mc_var.dtb_step_limit = 0;
mic_capless_trim_init(TCFG_AUDIO_ADC_MIC_CHA);
ret = os_sem_pend(&mc_trim->sem, MC_TRIM_TIMEOUT);
if (ret == OS_TIMEOUT) {
log_info("mc_trim timeout!\n");
mic_capless_trim_exit(0);
} else {
log_info("mc_trim ok\n");
mic_capless_trim_exit(1);
mc_var.dtb_step_limit = TCFG_MC_DTB_STEP_LIMIT;
}
} else {
log_info("mc_need't trim");
mc_var.dtb_step_limit = TCFG_MC_DTB_STEP_LIMIT;
}
#endif/*TCFG_MC_BIAS_AUTO_ADJUST*/
}
void ladc_capless_adjust_post(s32 dacr32, u8 begin)
{
static s32 last_dacr32 = 0;
static u8 check_cnt = 0;
u8 bias_rsel;
s32 dacr32_diff;
/*adjust_begin,clear*/
if (begin) {
last_dacr32 = 0;
check_cnt = 0;
mc_var.adjust_complete = 0;
mc_var.save_dtb = DACR32_DEFAULT;
return;
}
#if TCFG_MC_CONVERGE_TRACE
printf("<%d>", dacr32);
#endif/*TCFG_MC_CONVERGE_TRACE*/
if (mc_var.adjust_complete == 0) {
if (++check_cnt > CHECK_INTERVAL) {
check_cnt = 0;
#if TCFG_MC_BIAS_AUTO_ADJUST
if (mc_trim) {
if (dacr32 > DACDTB_RANGE_MAX) {
if (mc_trim->cur_bias_res < 21) {
mc_trim->cur_bias_res++;
} else {
printf("[Assert]mic_bias_rsel err 1!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
ASSERT(0, "mic_bias_rsel err 1\n");
}
bias_rsel = mic_bias_tab[mc_trim->cur_bias_res];
y_printf("[-]mic_bias_rsel:%d = %d", mc_trim->cur_bias_res, bias_rsel);
MIC_BIAS_RSEL(bias_rsel);
mc_trim->trim |= MC_TRIM_P;
return;
} else if (dacr32 < DACDTB_RANGE_MIN) {
if (mc_trim->cur_bias_res > 1) {
mc_trim->cur_bias_res--;
} else {
printf("[Assert]mic_bias_rsel err 2!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
ASSERT(0, "mic_bias_rsel err 2\n");
}
bias_rsel = mic_bias_tab[mc_trim->cur_bias_res];
y_printf("[+]mic_bias_rsel:%d = %d", mc_trim->cur_bias_res, bias_rsel);
MIC_BIAS_RSEL(bias_rsel);
mc_trim->trim |= MC_TRIM_N;
return;
}
if (mc_trim->trim == (MC_TRIM_P | MC_TRIM_N)) {
mic_capless_trim_result(MC_TRIM_ERR);
}
}
#endif/*TCFG_MC_BIAS_AUTO_ADJUST*/
dacr32_diff = dacr32 - last_dacr32;
//printf("[capless:%d-%d-%d]",dacr32,last_dacr32,dacr32_diff);
last_dacr32 = dacr32;
if (mc_var.adjust_complete == 0) {
mc_var.save_dtb = dacr32;
}
/*调整稳定*/
if ((dacr32_diff > -DIFF_RANGE) && (dacr32_diff < DIFF_RANGE)) {
log_info("adjust_OK:%d\n", dacr32);
mc_var.adjust_complete = 1;
#if TCFG_MC_BIAS_AUTO_ADJUST
mic_capless_trim_result(MC_TRIM_SUCC);
#endif/*TCFG_MC_BIAS_AUTO_ADJUST*/
}
}
}
}
#endif/*TCFG_AUDIO_MC_ENABLE*/