first
This commit is contained in:
2871
cpu/br28/a2dp_dec.c
Normal file
2871
cpu/br28/a2dp_dec.c
Normal file
File diff suppressed because it is too large
Load Diff
680
cpu/br28/adc_api.c
Normal file
680
cpu/br28/adc_api.c
Normal file
@ -0,0 +1,680 @@
|
||||
#include "typedef.h"
|
||||
#include "asm/clock.h"
|
||||
#include "asm/adc_api.h"
|
||||
#include "timer.h"
|
||||
#include "init.h"
|
||||
#include "asm/efuse.h"
|
||||
#include "irq.h"
|
||||
#include "asm/power/p33.h"
|
||||
#include "asm/power/p11.h"
|
||||
#include "asm/power_interface.h"
|
||||
#include "jiffies.h"
|
||||
|
||||
u32 adc_sample(u32 ch);
|
||||
static volatile u16 _adc_res;
|
||||
static volatile u16 cur_ch_value;
|
||||
static u8 cur_ch = 0;
|
||||
struct adc_info_t {
|
||||
u32 ch;
|
||||
u16 value;
|
||||
u32 jiffies;
|
||||
u32 sample_period;
|
||||
};
|
||||
|
||||
#define ENABLE_OCCUPY_MODE 1
|
||||
|
||||
static struct adc_info_t adc_queue[ADC_MAX_CH + ENABLE_OCCUPY_MODE];
|
||||
|
||||
|
||||
static u8 adc_sample_flag = 0;
|
||||
|
||||
static u16 dtemp_voltage = 0;
|
||||
|
||||
|
||||
#define ADC_SRC_CLK clk_get("adc")
|
||||
|
||||
/*config adc clk according to sys_clk*/
|
||||
static const u32 sys2adc_clk_info[] = {
|
||||
128000000L,
|
||||
96000000L,
|
||||
72000000L,
|
||||
48000000L,
|
||||
24000000L,
|
||||
12000000L,
|
||||
6000000L,
|
||||
1000000L,
|
||||
};
|
||||
|
||||
u32 adc_add_sample_ch(u32 ch)
|
||||
{
|
||||
u32 i = 0;
|
||||
for (i = 0; i < ADC_MAX_CH; i++) {
|
||||
/* printf("%s() %d %x %x\n", __func__, i, ch, adc_queue[i].ch); */
|
||||
if (adc_queue[i].ch == ch) {
|
||||
break;
|
||||
} else if (adc_queue[i].ch == -1) {
|
||||
adc_queue[i].ch = ch;
|
||||
adc_queue[i].value = 1;
|
||||
adc_queue[i].jiffies = 0;
|
||||
adc_queue[i].sample_period = msecs_to_jiffies(0);
|
||||
printf("add sample ch %x\n", ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
u32 adc_set_sample_freq(u32 ch, u32 ms)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0; i < ADC_MAX_CH; i++) {
|
||||
if (adc_queue[i].ch == ch) {
|
||||
adc_queue[i].sample_period = msecs_to_jiffies(ms);
|
||||
adc_queue[i].jiffies = msecs_to_jiffies(ms) + jiffies;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
u32 adc_remove_sample_ch(u32 ch)
|
||||
{
|
||||
u32 i = 0;
|
||||
for (i = 0; i < ADC_MAX_CH; i++) {
|
||||
if (adc_queue[i].ch == ch) {
|
||||
adc_queue[i].ch = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
static u32 adc_get_next_ch(u32 cur_ch)
|
||||
{
|
||||
for (int i = cur_ch + 1; i < ADC_MAX_CH; i++) {
|
||||
if (adc_queue[i].ch != -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define PMU_CH_SAMPLE_FREQ 500 //ms
|
||||
|
||||
#define PMU_CH_VALUE_ARRAY_SIZE (16 + 1)
|
||||
|
||||
static u16 vbat_value_array[PMU_CH_VALUE_ARRAY_SIZE];
|
||||
static u16 vbg_value_array[PMU_CH_VALUE_ARRAY_SIZE];
|
||||
|
||||
static void adc_value_push(u16 *array, u16 adc_value)
|
||||
{
|
||||
u16 pos = array[0];
|
||||
pos++;
|
||||
if (pos >= PMU_CH_VALUE_ARRAY_SIZE) {
|
||||
pos = 1;
|
||||
}
|
||||
array[pos] = adc_value;
|
||||
array[0] = pos;
|
||||
}
|
||||
|
||||
static u16 adc_value_avg(u16 *array)
|
||||
{
|
||||
u32 i, j, sum = 0;
|
||||
for (i = 1, j = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
|
||||
if (array[i]) {
|
||||
sum += array[i];
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
if (sum) {
|
||||
return (sum / j);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void adc_value_array_reset(u16 *array)
|
||||
{
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
|
||||
array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 adc_get_value(u32 ch)
|
||||
{
|
||||
if (ch == AD_CH_VBAT) {
|
||||
return adc_value_avg(vbat_value_array);
|
||||
} else if (ch == AD_CH_LDOREF) {
|
||||
return adc_value_avg(vbg_value_array);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ADC_MAX_CH; i++) {
|
||||
if (adc_queue[i].ch == ch) {
|
||||
return adc_queue[i].value;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#define VBG_CENTER 801
|
||||
#define VBG_RES 3
|
||||
u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
|
||||
{
|
||||
u32 adc_res = adc_ch_val;
|
||||
u32 adc_trim = get_vbg_trim();
|
||||
u32 tmp, tmp1;
|
||||
|
||||
tmp1 = adc_trim & 0x0f;
|
||||
tmp = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
|
||||
/* printf("adc_res %d mv vbg:%d adc:%d adc_trim:%x\n", adc_res, adc_vbg, adc_ch_val, adc_trim); */
|
||||
|
||||
if (adc_vbg == 0) {
|
||||
adc_vbg = 1; //防止div0异常
|
||||
}
|
||||
adc_res = adc_res * tmp / adc_vbg;
|
||||
return adc_res;
|
||||
}
|
||||
|
||||
u32 adc_get_voltage(u32 ch)
|
||||
{
|
||||
#ifdef CONFIG_FPGA_ENABLE
|
||||
return 1000;
|
||||
#endif
|
||||
|
||||
if (ch == AD_CH_DTEMP) {
|
||||
return dtemp_voltage;
|
||||
}
|
||||
|
||||
u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
|
||||
u32 adc_res = adc_get_value(ch);
|
||||
return adc_value_to_voltage(adc_vbg, adc_res);
|
||||
}
|
||||
u32 adc_check_vbat_lowpower()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void adc_audio_ch_select(u32 ch)
|
||||
{
|
||||
SFR(JL_ADDA->ADDA_CON1, 1, 1, 1);
|
||||
SFR(JL_ADDA->ADDA_CON0, 0, 12, 0);
|
||||
|
||||
switch (ch << 16) {
|
||||
case AD_AUDIO_VADADC:
|
||||
SFR(JL_ADDA->ADDA_CON0, 12, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_VCM:
|
||||
SFR(JL_ADDA->ADDA_CON0, 11, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_VBGLDO:
|
||||
SFR(JL_ADDA->ADDA_CON0, 10, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_HPVDD:
|
||||
SFR(JL_ADDA->ADDA_CON0, 9, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_RN:
|
||||
SFR(JL_ADDA->ADDA_CON0, 4, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_RP:
|
||||
SFR(JL_ADDA->ADDA_CON0, 3, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_LN:
|
||||
SFR(JL_ADDA->ADDA_CON0, 2, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_LP:
|
||||
SFR(JL_ADDA->ADDA_CON0, 1, 1, 1);
|
||||
break;
|
||||
case AD_AUDIO_DACVDD:
|
||||
SFR(JL_ADDA->ADDA_CON0, 0, 1, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void adc_close()
|
||||
{
|
||||
JL_ADC->CON = 0;
|
||||
JL_ADC->CON = 0;
|
||||
}
|
||||
void adc_suspend()
|
||||
{
|
||||
JL_ADC->CON &= ~BIT(4);
|
||||
}
|
||||
void adc_resume()
|
||||
{
|
||||
JL_ADC->CON |= BIT(4);
|
||||
}
|
||||
|
||||
void adc_enter_occupy_mode(u32 ch)
|
||||
{
|
||||
if (JL_ADC->CON & BIT(4)) {
|
||||
return;
|
||||
}
|
||||
adc_queue[ADC_MAX_CH].ch = ch;
|
||||
cur_ch_value = adc_sample(ch);
|
||||
}
|
||||
void adc_exit_occupy_mode()
|
||||
{
|
||||
adc_queue[ADC_MAX_CH].ch = -1;
|
||||
}
|
||||
u32 adc_occupy_run()
|
||||
{
|
||||
if (adc_queue[ADC_MAX_CH].ch != -1) {
|
||||
while (1) {
|
||||
asm volatile("idle");//wait isr
|
||||
if (_adc_res != (u16) - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_adc_res == 0) {
|
||||
_adc_res ++;
|
||||
}
|
||||
adc_queue[ADC_MAX_CH].value = _adc_res;
|
||||
_adc_res = cur_ch_value;
|
||||
return adc_queue[ADC_MAX_CH].value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
u32 adc_get_occupy_value()
|
||||
{
|
||||
if (adc_queue[ADC_MAX_CH].ch != -1) {
|
||||
return adc_queue[ADC_MAX_CH].value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
u32 get_adc_div(u32 src_clk)
|
||||
{
|
||||
u32 adc_clk;
|
||||
u32 adc_clk_idx;
|
||||
u32 cnt;
|
||||
adc_clk = src_clk;
|
||||
cnt = ARRAY_SIZE(sys2adc_clk_info);
|
||||
for (adc_clk_idx = 0; adc_clk_idx < cnt; adc_clk_idx ++) {
|
||||
if (adc_clk > sys2adc_clk_info[adc_clk_idx]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (adc_clk_idx < cnt) {
|
||||
adc_clk_idx = cnt - adc_clk_idx;
|
||||
} else {
|
||||
adc_clk_idx = cnt - 1;
|
||||
}
|
||||
return adc_clk_idx;
|
||||
}
|
||||
|
||||
___interrupt
|
||||
static void adc_isr()
|
||||
{
|
||||
_adc_res = JL_ADC->RES;
|
||||
|
||||
local_irq_disable();
|
||||
JL_ADC->CON = BIT(6);
|
||||
local_irq_enable();
|
||||
|
||||
#if 1
|
||||
if (adc_sample_flag > 1) {
|
||||
extern void adc_scan(void *priv);
|
||||
adc_scan((void *)&adc_sample_flag);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 adc_sample(u32 ch)
|
||||
{
|
||||
const u32 tmp_adc_res = _adc_res;
|
||||
_adc_res = (u16) - 1;
|
||||
|
||||
u32 adc_con = 0;
|
||||
SFR(adc_con, 0, 3, 0b110);//div 96
|
||||
|
||||
|
||||
adc_con |= (0xf << 12); //启动延时控制,实际启动延时为此数值*8个ADC时钟
|
||||
adc_con |= BIT(3); //ana en
|
||||
adc_con |= BIT(6); //clr pend
|
||||
adc_con |= BIT(5);//ie
|
||||
adc_con |= BIT(17);//clk en
|
||||
/* adc_con |= BIT(18)|BIT(19);//clk en */
|
||||
|
||||
SFR(adc_con, 21, 3, 0b010);
|
||||
switch (ch & 0xff) {
|
||||
case AD_CH_BT:
|
||||
SFR(adc_con, 18, 3, AD_CH_BT & 0xf);
|
||||
break;
|
||||
case AD_CH_PMU:
|
||||
if (adc_sample_flag > 1) {
|
||||
SFR(adc_con, 0, 3, 0b011);//div 24
|
||||
adc_con &= ~(0xf << 12);
|
||||
}
|
||||
SFR(adc_con, 18, 3, AD_CH_PMU & 0xf);
|
||||
adc_pmu_ch_select(ch >> 16);
|
||||
break;
|
||||
|
||||
case AD_CH_AUDIO:
|
||||
SFR(adc_con, 18, 3, AD_CH_AUDIO & 0xf);
|
||||
adc_audio_ch_select(ch >> 16);
|
||||
break;
|
||||
|
||||
case AD_CH_LPCTM:
|
||||
SFR(adc_con, 18, 3, AD_CH_LPCTM & 0xf);
|
||||
break;
|
||||
|
||||
case AD_CH_X32K:
|
||||
SFR(adc_con, 18, 3, AD_CH_X32K & 0xf);
|
||||
break;
|
||||
case AD_CH_PLL1:
|
||||
SFR(adc_con, 18, 3, AD_CH_PLL1 & 0xf);
|
||||
break;
|
||||
default:
|
||||
SFR(adc_con, 21, 3, 0b001);
|
||||
SFR(adc_con, 8, 4, ch & 0xf);
|
||||
break;
|
||||
}
|
||||
|
||||
JL_ADC->CON = adc_con;
|
||||
JL_ADC->CON |= BIT(4);//en
|
||||
|
||||
/* printf("ch %x %x %x %x",ch,ch >> 16,JL_ADC->CON,P3_ANA_CON4); */
|
||||
|
||||
JL_ADC->CON |= BIT(6);//kistart
|
||||
|
||||
return tmp_adc_res;
|
||||
}
|
||||
|
||||
void adc_scan(void *priv)
|
||||
{
|
||||
static u16 vbg_adc_res = 0;
|
||||
static u16 dtemp_adc_res = 0;
|
||||
|
||||
if ((priv == NULL) && (adc_sample_flag > 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (adc_queue[ADC_MAX_CH].ch != -1) { //occupy mode
|
||||
return;
|
||||
}
|
||||
|
||||
if (JL_ADC->CON & BIT(4)) {
|
||||
adc_sample_flag = 0;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (_adc_res == 0xffff) {
|
||||
adc_sample_flag = 0;
|
||||
}
|
||||
|
||||
if (adc_sample_flag) {
|
||||
if (adc_sample_flag == 2) {
|
||||
dtemp_adc_res = _adc_res;
|
||||
adc_sample_flag = 3;
|
||||
adc_sample(AD_CH_LDOREF);
|
||||
return;
|
||||
} else if (adc_sample_flag == 3) {
|
||||
vbg_adc_res = _adc_res;
|
||||
dtemp_voltage = adc_value_to_voltage(vbg_adc_res, dtemp_adc_res);
|
||||
/* printf("vbg:%d dtemp:%d vol:%dmv\n", vbg_adc_res, dtemp_adc_res, dtemp_voltage); */
|
||||
} else {
|
||||
adc_queue[cur_ch].value = _adc_res;
|
||||
if (adc_queue[cur_ch].ch == AD_CH_VBAT) {
|
||||
adc_value_push(vbat_value_array, _adc_res);
|
||||
/* printf("vbat %d",_adc_res); */
|
||||
} else if (adc_queue[cur_ch].ch == AD_CH_LDOREF) {
|
||||
adc_value_push(vbg_value_array, _adc_res);
|
||||
/* printf("vbg %d",_adc_res); */
|
||||
}
|
||||
}
|
||||
adc_sample_flag = 0;
|
||||
}
|
||||
|
||||
u8 next_ch = adc_get_next_ch(cur_ch);
|
||||
|
||||
if (adc_queue[next_ch].sample_period) {
|
||||
if (time_before(adc_queue[next_ch].jiffies, jiffies)) {
|
||||
if (adc_queue[next_ch].ch == AD_CH_DTEMP) {
|
||||
adc_sample_flag = 2;
|
||||
} else {
|
||||
adc_sample_flag = 1;
|
||||
}
|
||||
adc_sample(adc_queue[next_ch].ch);
|
||||
adc_queue[next_ch].jiffies += adc_queue[next_ch].sample_period;
|
||||
}
|
||||
} else {
|
||||
adc_sample(adc_queue[next_ch].ch);
|
||||
adc_sample_flag = 1;
|
||||
}
|
||||
|
||||
cur_ch = next_ch;
|
||||
}
|
||||
|
||||
static u16 adc_wait_pnd()
|
||||
{
|
||||
while (!(JL_ADC->CON & BIT(7)));
|
||||
u32 adc_res = JL_ADC->RES;
|
||||
/* printf("adc_res =%d\n",adc_res); */
|
||||
asm("nop");
|
||||
JL_ADC->CON |= BIT(6);
|
||||
return adc_res;
|
||||
}
|
||||
|
||||
static int hpvdd_voltage = 0;
|
||||
static void read_hpvdd_voltage(void)
|
||||
{
|
||||
int hpvdd_adc_value = 0;
|
||||
int tvalue = 0;
|
||||
adc_sample(AD_CH_AUDIO_HPVDD);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
tvalue = adc_wait_pnd();
|
||||
hpvdd_adc_value += tvalue;
|
||||
}
|
||||
hpvdd_adc_value /= 10;
|
||||
|
||||
u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
|
||||
hpvdd_voltage = adc_value_to_voltage(adc_vbg, hpvdd_adc_value);
|
||||
printf("hpvdd = %d mV\n", hpvdd_voltage);
|
||||
SFR(JL_ADDA->ADDA_CON0, 9, 1, 0);
|
||||
}
|
||||
|
||||
int get_hpvdd_voltage(void)
|
||||
{
|
||||
return hpvdd_voltage;
|
||||
}
|
||||
|
||||
void adc_reset(void)
|
||||
{
|
||||
int i, j;
|
||||
local_irq_disable();
|
||||
JL_ADC->CON = 0;
|
||||
|
||||
memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
|
||||
memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
|
||||
|
||||
u32 sum_ad = 0;
|
||||
adc_sample(AD_CH_LDOREF);
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
|
||||
sum_ad += adc_wait_pnd();
|
||||
}
|
||||
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
|
||||
adc_value_push(vbg_value_array, sum_ad);
|
||||
printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
|
||||
|
||||
sum_ad = 0;
|
||||
adc_sample(AD_CH_VBAT);
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
|
||||
sum_ad += adc_wait_pnd();
|
||||
}
|
||||
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
|
||||
adc_value_push(vbat_value_array, sum_ad);
|
||||
printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
|
||||
printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
|
||||
|
||||
JL_ADC->CON = BIT(6);
|
||||
cur_ch = 0;
|
||||
adc_sample_flag = 0;
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
void _adc_init(u32 sys_lvd_en)
|
||||
{
|
||||
memset(adc_queue, 0xff, sizeof(adc_queue));
|
||||
memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
|
||||
memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
|
||||
|
||||
JL_ADC->CON = 0;
|
||||
JL_ADC->CON = 0;
|
||||
|
||||
adc_add_sample_ch(AD_CH_LDOREF);
|
||||
adc_set_sample_freq(AD_CH_LDOREF, PMU_CH_SAMPLE_FREQ);
|
||||
|
||||
adc_add_sample_ch(AD_CH_VBAT);
|
||||
adc_set_sample_freq(AD_CH_VBAT, PMU_CH_SAMPLE_FREQ);
|
||||
|
||||
adc_add_sample_ch(AD_CH_DTEMP);
|
||||
adc_set_sample_freq(AD_CH_DTEMP, PMU_CH_SAMPLE_FREQ);
|
||||
|
||||
u32 sum_ad = 0;
|
||||
adc_sample(AD_CH_LDOREF);
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
|
||||
sum_ad += adc_wait_pnd();
|
||||
}
|
||||
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
|
||||
adc_value_push(vbg_value_array, sum_ad);
|
||||
printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
|
||||
|
||||
sum_ad = 0;
|
||||
adc_sample(AD_CH_VBAT);
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
|
||||
sum_ad += adc_wait_pnd();
|
||||
}
|
||||
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
|
||||
adc_value_push(vbat_value_array, sum_ad);
|
||||
printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
|
||||
printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
|
||||
|
||||
sum_ad = 0;
|
||||
adc_sample(AD_CH_DTEMP);
|
||||
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
|
||||
sum_ad += adc_wait_pnd();
|
||||
}
|
||||
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
|
||||
dtemp_voltage = adc_value_to_voltage(adc_value_avg(vbg_value_array), sum_ad);
|
||||
printf("dtemp_adc_value = %d\n", sum_ad);
|
||||
printf("dtemp = %d mv\n", dtemp_voltage);
|
||||
|
||||
read_hpvdd_voltage();
|
||||
|
||||
request_irq(IRQ_GPADC_IDX, 0, adc_isr, 0);
|
||||
|
||||
usr_timer_add(NULL, adc_scan, 5, 0); //2ms
|
||||
|
||||
/* void btosc_fast_boot_test(void); */
|
||||
/* btosc_fast_boot_test(); */
|
||||
/* sys_timer_add(NULL, adc_scan, 10); //2ms */
|
||||
|
||||
/* void adc_test(); */
|
||||
/* usr_timer_add(NULL, adc_test, 1000, 0); //2ms */
|
||||
|
||||
/* extern void wdt_close(); */
|
||||
/* wdt_close(); */
|
||||
/* */
|
||||
/* while(1); */
|
||||
}
|
||||
u32 get_vdd_voltage(u32 ch)
|
||||
{
|
||||
u32 vbg_value = 0;
|
||||
u32 wvdd_value = 0;
|
||||
|
||||
adc_sample(AD_CH_LDOREF);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
vbg_value += adc_wait_pnd();
|
||||
}
|
||||
|
||||
adc_sample(ch);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
wvdd_value += adc_wait_pnd();
|
||||
}
|
||||
|
||||
u32 adc_vbg = vbg_value / 10;
|
||||
u32 adc_res = wvdd_value / 10;
|
||||
|
||||
return adc_value_to_voltage(adc_vbg, adc_res);
|
||||
}
|
||||
|
||||
|
||||
#define ADC_SCAN_NUM 16
|
||||
__attribute__((noinline))
|
||||
AT(.volatile_ram_code)
|
||||
u32 get_vddio_voltage()
|
||||
{
|
||||
|
||||
u32 vbg_value = 0;
|
||||
u32 vddio_value = 0;
|
||||
u32 min = -1;
|
||||
u32 max = 0;
|
||||
adc_pmu_detect_en(0);
|
||||
adc_sample(AD_CH_LDOREF);
|
||||
for (int i = 0; i < ADC_SCAN_NUM; i++) {
|
||||
while (!(JL_ADC->CON & BIT(7))) { //wait pending
|
||||
}
|
||||
|
||||
u32 adc_res = JL_ADC->RES;
|
||||
vbg_value += adc_res;
|
||||
JL_ADC->CON |= BIT(6);
|
||||
if (max < adc_res) {
|
||||
max = adc_res;
|
||||
}
|
||||
if (min > adc_res) {
|
||||
min = adc_res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 adc_vbg = (vbg_value - max - min) / (ADC_SCAN_NUM - 2);
|
||||
|
||||
u32 adc_trim = get_vbg_trim();
|
||||
|
||||
u32 vbg_voltage, tmp1;
|
||||
|
||||
tmp1 = adc_trim & 0x0f;
|
||||
vbg_voltage = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
|
||||
u32 vddio_voltage = vbg_voltage * 1023 / adc_vbg;
|
||||
return vddio_voltage;
|
||||
}
|
||||
|
||||
void adc_init()
|
||||
{
|
||||
adc_pmu_detect_en(1);
|
||||
|
||||
volatage_trim_init();
|
||||
|
||||
_adc_init(1);
|
||||
}
|
||||
//late_initcall(adc_init);
|
||||
|
||||
void adc_test()
|
||||
{
|
||||
/* void efuse_test(); */
|
||||
/* efuse_test(); */
|
||||
/* printf("\n\n%s() chip_id :%x\n", __func__, get_chip_id()); */
|
||||
/* printf("%s() vbg trim:%x\n", __func__, get_vbg_trim()); */
|
||||
/* printf("%s() vbat trim:%x\n", __func__, get_vbat_trim()); */
|
||||
|
||||
/* printf("\n\nWLA_CON0 %x\n", JL_ANA->WLA_CON0); */
|
||||
/* printf("WLA_CON9 %x\n", JL_ANA->WLA_CON9); */
|
||||
/* printf("WLA_CON10 %x\n", JL_ANA->WLA_CON10); */
|
||||
/* printf("WLA_CON21 %x\n", JL_ANA->WLA_CON21); */
|
||||
|
||||
/* printf("ADA_CON %x\n", JL_ANA->ADA_CON3); */
|
||||
/* printf("PLL_CON1 %x\n", JL_CLOCK->PLL_CON1); */
|
||||
|
||||
printf("\n%s() VBAT:%d %d mv\n\n", __func__,
|
||||
adc_get_value(AD_CH_VBAT), adc_get_voltage(AD_CH_VBAT) * 4);
|
||||
|
||||
/* printf("\n%s() pa3:%d %d mv\n\n", __func__, */
|
||||
/* adc_get_value(AD_CH_PA3), adc_get_voltage(AD_CH_PA3)); */
|
||||
|
||||
|
||||
}
|
||||
void adc_vbg_init()
|
||||
{
|
||||
return ;
|
||||
}
|
||||
//__initcall(adc_vbg_init);
|
||||
456
cpu/br28/aec_tool.c
Normal file
456
cpu/br28/aec_tool.c
Normal file
@ -0,0 +1,456 @@
|
||||
#include "system/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "app_online_cfg.h"
|
||||
#include "online_db_deal.h"
|
||||
#include "math.h"
|
||||
#include "config/config_target.h"
|
||||
#include "config/config_interface.h"
|
||||
#include "aec_user.h"
|
||||
|
||||
extern int aec_cfg_online_init();
|
||||
extern int aec_cfg_online_update(int root_cmd, void *cfg);
|
||||
extern int get_aec_config(u8 *buf, int version);
|
||||
|
||||
#if TCFG_AEC_TOOL_ONLINE_ENABLE
|
||||
|
||||
/* #define LOG_TAG_CONST AEC_TOOL */
|
||||
#define LOG_TAG "[AEC-TOOL]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_DUMP_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
const u8 audio_sdk_name[16] = "AC701N";
|
||||
/* const u8 audio_aec_ver[4] = {1, 7, 1, 1}; */
|
||||
const u8 audio_aec_ver[4] = {1, 7, 1, 2};
|
||||
|
||||
#define audio_eq_password "000"
|
||||
#define password_en 0
|
||||
|
||||
enum {
|
||||
AEC_ONLINE_CMD_GETVER = 0x5,
|
||||
AEC_ONLINE_CMD_GET_SOFT_SECTION,//br22专用
|
||||
AEC_ONLINE_CMD_GET_SECTION_NUM = 0x7,//工具查询 小机需要的eq段数
|
||||
AEC_ONLINE_CMD_GLOBAL_GAIN_SUPPORT_FLOAT = 0x8,
|
||||
|
||||
|
||||
AEC_ONLINE_CMD_PASSWORD = 0x9,
|
||||
AEC_ONLINE_CMD_VERIFY_PASSWORD = 0xA,
|
||||
AEC_ONLINE_CMD_FILE_SIZE = 0xB,
|
||||
AEC_ONLINE_CMD_FILE = 0xC,
|
||||
AEC_ONLINE_CMD_GET_SECTION_NUM_NEW = 0xD,//该命令新加与 0x7功能一样
|
||||
AEC_ONLINE_CMD_CHANGE_MODE = 0xE,//切模式
|
||||
|
||||
AEC_ONLINE_CMD_MODE_COUNT = 0x100,//模式个数a 1
|
||||
AEC_ONLINE_CMD_MODE_NAME = 0x101,//模式的名字a eq
|
||||
AEC_ONLINE_CMD_MODE_GROUP_COUNT = 0x102,//模式下组的个数,4个字节 1
|
||||
AEC_ONLINE_CMD_MODE_GROUP_RANGE = 0x103,//模式下组的id内容 0x11
|
||||
AEC_ONLINE_CMD_EQ_GROUP_COUNT = 0x104,//eq组的id个数 1
|
||||
AEC_ONLINE_CMD_EQ_GROUP_RANGE = 0x105,//eq组的id内容 0x11
|
||||
AEC_ONLINE_CMD_MODE_SEQ_NUMBER = 0x106,//mode的编号 magic num
|
||||
|
||||
|
||||
AEC_ONLINE_CMD_MAX,//最后一个
|
||||
};
|
||||
|
||||
typedef struct _aec_tool_cfg {
|
||||
u8 mode_index; //模式序号
|
||||
u8 *mode_name; //模式名
|
||||
u32 mode_seq; //模式的seq,用于识别离线文件功能类型
|
||||
u8 fun_num; //模式下有多少种功能
|
||||
u16 fun_type[6]; //模式下拥有哪些功能
|
||||
} aec_tool_cfg;
|
||||
|
||||
typedef struct _aec_parm {
|
||||
u8 app: 1; //是否手机app在线调试
|
||||
u8 online_en: 1;
|
||||
aec_tool_cfg *aec_tool_tab;
|
||||
} aec_adjust_parm;
|
||||
|
||||
typedef struct {
|
||||
u32 aec_updata;
|
||||
spinlock_t lock;
|
||||
|
||||
u8 app: 1;
|
||||
u8 online_en: 1;
|
||||
u8 password_ok: 1;
|
||||
u8 parse_seq;
|
||||
aec_tool_cfg *aec_tool_tab;
|
||||
} AEC_CFG;
|
||||
|
||||
static AEC_CFG *p_aec_cfg = NULL;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 在线调试,应答接口
|
||||
@param *packet
|
||||
@param
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static void ci_send_packet_new(AEC_CFG *aec_cfg, u32 id, u8 *packet, int size)
|
||||
{
|
||||
ASSERT(aec_cfg);
|
||||
if (aec_cfg->app) {
|
||||
if (AEC_CONFIG_ID == id) {
|
||||
app_online_db_ack(aec_cfg->parse_seq, packet, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if TCFG_ONLINE_ENABLE
|
||||
ci_send_packet(id, packet, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*aec 在线调试,系数解析函数
|
||||
* */
|
||||
static s32 aec_online_update(AEC_CFG *aec_cfg, void *_packet)
|
||||
{
|
||||
typedef struct {
|
||||
int cmd; ///<AEC_ONLINE_CMD
|
||||
int data[45]; ///<data
|
||||
} AEC_ONLINE_PACKET;
|
||||
|
||||
AEC_ONLINE_PACKET *packet = _packet;
|
||||
int ret = -1;
|
||||
|
||||
log_d("aec_cmd:0x%x ", packet->cmd);
|
||||
spin_lock(&aec_cfg->lock);
|
||||
ret = aec_cfg_online_update(packet->cmd, packet->data);
|
||||
spin_unlock(&aec_cfg->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 打开工具时,相关的命令通讯
|
||||
* */
|
||||
static int aec_online_nor_cmd(AEC_CFG *aec_cfg, void *_packet)
|
||||
{
|
||||
typedef struct {
|
||||
int cmd; ///<AEC_ONLINE_CMD
|
||||
int data[45]; ///<data
|
||||
} AEC_ONLINE_PACKET;
|
||||
|
||||
AEC_ONLINE_PACKET *packet = _packet;
|
||||
|
||||
aec_tool_cfg *aec_tool_tab = aec_cfg->aec_tool_tab;
|
||||
u32 id = AEC_CONFIG_ID;
|
||||
if (packet->cmd == AEC_ONLINE_CMD_GETVER) {
|
||||
struct eq_ver_info {
|
||||
char sdkname[16];
|
||||
u8 eqver[4];
|
||||
};
|
||||
struct eq_ver_info eq_ver_info = {0};
|
||||
memcpy(eq_ver_info.sdkname, audio_sdk_name, sizeof(audio_sdk_name));
|
||||
memcpy(eq_ver_info.eqver, audio_aec_ver, sizeof(audio_aec_ver));
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&eq_ver_info, sizeof(struct eq_ver_info));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_GET_SECTION_NUM || (packet->cmd == AEC_ONLINE_CMD_GET_SECTION_NUM_NEW)) {
|
||||
struct _cmd {
|
||||
int id;
|
||||
int groupId;
|
||||
};
|
||||
struct _cmd cmd = {0};
|
||||
|
||||
memcpy(&cmd, packet->data, sizeof(struct _cmd));
|
||||
uint8_t hw_section = 0;
|
||||
log_d("hw_section %d cmd.id:%x\n", hw_section, cmd.id);
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&hw_section, sizeof(uint8_t));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_GLOBAL_GAIN_SUPPORT_FLOAT) {
|
||||
uint8_t support_float = 1;
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&support_float, sizeof(uint8_t));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_PASSWORD) {
|
||||
uint8_t password = 0;
|
||||
if (password_en) {
|
||||
password = 1;
|
||||
}
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&password, sizeof(uint8_t));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_VERIFY_PASSWORD) {
|
||||
//check password
|
||||
int len = 0;
|
||||
char pass[64];
|
||||
typedef struct password {
|
||||
int len;
|
||||
char pass[45];
|
||||
} PASSWORD;
|
||||
|
||||
PASSWORD ps = {0};
|
||||
spin_lock(&aec_cfg->lock);
|
||||
memcpy(&ps, packet->data, sizeof(PASSWORD));
|
||||
memcpy(&ps, packet->data, sizeof(int) + ps.len);
|
||||
spin_unlock(&aec_cfg->lock);
|
||||
|
||||
uint8_t password_ok = 0;
|
||||
if (!strcmp(ps.pass, audio_eq_password)) {
|
||||
password_ok = 1;
|
||||
} else {
|
||||
log_error("password verify failxx \n");
|
||||
}
|
||||
aec_cfg->password_ok = password_ok;
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&password_ok, sizeof(uint8_t));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_FILE_SIZE) {
|
||||
y_printf("get aec file_size");
|
||||
#if TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
|
||||
u32 cfg_file_size = sizeof(AEC_DMS_CONFIG);
|
||||
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
|
||||
u32 cfg_file_size = sizeof(DMS_FLEXIBLE_CONFIG);
|
||||
#endif/*TCFG_AUDIO_DMS_SEL*/
|
||||
#else/*SINGLE MIC*/
|
||||
u32 cfg_file_size = sizeof(AEC_CONFIG);
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&cfg_file_size, sizeof(u32));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_FILE) {
|
||||
y_printf("get aec file");
|
||||
put_buf(packet, 64);
|
||||
#if TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
|
||||
AEC_DMS_CONFIG cfg_file;
|
||||
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
|
||||
DMS_FLEXIBLE_CONFIG cfg_file;
|
||||
#endif/*TCFG_AUDIO_DMS_SEL*/
|
||||
#else/*SINGLE MIC*/
|
||||
AEC_CONFIG cfg_file;
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
int version = 0;
|
||||
memcpy(&version, packet->data, 4);
|
||||
printf("version %x", version);
|
||||
int cfg_file_len = get_aec_config(&cfg_file, version);
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&cfg_file, cfg_file_len);
|
||||
return 0;//-EINVAL;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_COUNT) {
|
||||
//模式个数
|
||||
int mode_cnt = 1;//aec_cfg->mode_num;
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&mode_cnt, sizeof(int));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_NAME) {
|
||||
//utf8编码得名字
|
||||
struct cmd {
|
||||
int id;
|
||||
int modeId;
|
||||
};
|
||||
struct cmd cmd;
|
||||
memcpy(&cmd, packet, sizeof(struct cmd));
|
||||
|
||||
u8 tmp[32] = {0};
|
||||
u8 name_len = strlen(aec_tool_tab[cmd.modeId].mode_name);
|
||||
memcpy(tmp, aec_tool_tab[cmd.modeId].mode_name, name_len);
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)tmp, name_len);
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_GROUP_COUNT) {
|
||||
struct cmd {
|
||||
int id;
|
||||
int modeId;
|
||||
};
|
||||
struct cmd cmd;
|
||||
memcpy(&cmd, packet, sizeof(struct cmd));
|
||||
int groups_num = aec_tool_tab[cmd.modeId].fun_num;
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&groups_num, sizeof(int));
|
||||
return 0;
|
||||
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_GROUP_RANGE) { //摸下是组的id
|
||||
struct cmd {
|
||||
int id;
|
||||
int modeId;
|
||||
int offset;
|
||||
int count;
|
||||
};
|
||||
struct cmd cmd;
|
||||
memcpy(&cmd, packet, sizeof(struct cmd));
|
||||
|
||||
u16 *group_tmp = aec_tool_tab[cmd.modeId].fun_type;//groups[cmd.modeId];
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&group_tmp[cmd.offset], cmd.count * sizeof(u16));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_EQ_GROUP_COUNT) {
|
||||
u32 eq_group_num = 0;
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&eq_group_num, sizeof(u32));
|
||||
return 0;
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_EQ_GROUP_RANGE) {
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_CHANGE_MODE) {
|
||||
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_SEQ_NUMBER) {
|
||||
struct cmd {
|
||||
int id;
|
||||
int modeId;
|
||||
};
|
||||
struct cmd cmd;
|
||||
memcpy(&cmd, packet, sizeof(struct cmd));
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)&aec_tool_tab[cmd.modeId].mode_seq, sizeof(u32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
*注册到协议端的,数据回调接口
|
||||
* */
|
||||
static void aec_online_callback(uint8_t *packet, uint16_t size)
|
||||
{
|
||||
s32 res = 0;
|
||||
AEC_CFG *aec_cfg = p_aec_cfg;
|
||||
if (!aec_cfg) {
|
||||
return ;
|
||||
}
|
||||
//u8 *tmp_packet = malloc(size);
|
||||
//memcpy(tmp_packet, packet, size);
|
||||
u8 *tmp_packet = packet;
|
||||
ASSERT(((int)tmp_packet & 0x3) == 0, "buf %x size %d\n", tmp_packet, size);
|
||||
res = aec_online_update(aec_cfg, (void *)tmp_packet);
|
||||
|
||||
u32 id = AEC_CONFIG_ID;
|
||||
|
||||
if (res == 0) {
|
||||
log_d("Ack");
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)"OK", 2);
|
||||
} else {
|
||||
res = aec_online_nor_cmd(aec_cfg, (void *)tmp_packet);
|
||||
if (res == 0) {
|
||||
//free(tmp_packet);
|
||||
return ;
|
||||
}
|
||||
log_d("Nack");
|
||||
ci_send_packet_new(aec_cfg, id, (u8 *)"ER", 2);
|
||||
}
|
||||
//free(tmp_packet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
REGISTER_CONFIG_TARGET(aec_config_target) = {
|
||||
.id = AEC_CONFIG_ID,
|
||||
.callback = aec_online_callback,
|
||||
};
|
||||
|
||||
//AEC在线调试不进power down
|
||||
static u8 aec_online_idle_query(void)
|
||||
{
|
||||
AEC_CFG *cfg = p_aec_cfg;
|
||||
if (!cfg) {
|
||||
return 1;
|
||||
}
|
||||
if (cfg->online_en) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(aec_online_lp_target) = {
|
||||
.name = "aec_online",
|
||||
.is_idle = aec_online_idle_query,
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 手机app 在线调时,数据解析的回调
|
||||
@param *packet
|
||||
@param
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int aec_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
|
||||
{
|
||||
AEC_CFG *aec_cfg = p_aec_cfg;
|
||||
ASSERT(aec_cfg);
|
||||
if (aec_cfg->online_en) {
|
||||
aec_cfg->parse_seq = ext_data[1];
|
||||
aec_online_callback(packet, size);
|
||||
} else {
|
||||
printf("AEC_ONLINE,not enable!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *aec_cfg_open(aec_adjust_parm *parm)
|
||||
{
|
||||
AEC_CFG *aec_cfg = NULL;
|
||||
if (aec_cfg == NULL) {
|
||||
aec_cfg = zalloc(sizeof(AEC_CFG));
|
||||
ASSERT(aec_cfg);
|
||||
}
|
||||
|
||||
aec_cfg->aec_tool_tab = parm->aec_tool_tab;
|
||||
aec_cfg->app = parm->app;
|
||||
aec_cfg->online_en = parm->online_en;
|
||||
|
||||
spin_lock_init(&aec_cfg->lock);
|
||||
p_aec_cfg = aec_cfg;
|
||||
return aec_cfg;
|
||||
|
||||
}
|
||||
|
||||
void aec_cfg_close(AEC_CFG *aec_cfg)
|
||||
{
|
||||
if (!aec_cfg) {
|
||||
return ;
|
||||
}
|
||||
|
||||
free(aec_cfg);
|
||||
aec_cfg = NULL;
|
||||
}
|
||||
|
||||
aec_tool_cfg aec_tool_tab[] = {
|
||||
{0, (u8 *)"AEC tool", AEC_CONFIG_ID, 1, {0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500}},
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 设置CVP算法类型
|
||||
@param cvp_mode 配置的算法类型
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void cvp_mode_set(u16 cvp_mode)
|
||||
{
|
||||
printf("cvp_mode_set:0x%x\n", cvp_mode);
|
||||
aec_tool_tab[0].fun_type[0] = cvp_mode;
|
||||
}
|
||||
|
||||
int aec_cfg_init(void)
|
||||
{
|
||||
#if TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
|
||||
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
|
||||
cvp_mode_set(0x3100);
|
||||
#else/*CVP_DNS_MODE*/
|
||||
cvp_mode_set(0x3300);
|
||||
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
|
||||
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
|
||||
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
|
||||
cvp_mode_set(0x3400);
|
||||
#else/*CVP_DNS_MODE*/
|
||||
cvp_mode_set(0x3500);
|
||||
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
|
||||
#endif/*TCFG_AUDIO_DMS_SEL*/
|
||||
#else/*SINGLE MIC*/
|
||||
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
|
||||
cvp_mode_set(0x3000);
|
||||
#else/*CVP_DNS_MODE*/
|
||||
cvp_mode_set(0x3200);
|
||||
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
aec_adjust_parm parm = {0};
|
||||
parm.online_en = 1;
|
||||
#if APP_ONLINE_DEBUG
|
||||
parm.app = 1;
|
||||
#endif
|
||||
parm.aec_tool_tab = aec_tool_tab;
|
||||
AEC_CFG *aec_cfg = aec_cfg_open(&parm);
|
||||
if (aec_cfg->app) {
|
||||
app_online_db_register_handle(DB_PKT_TYPE_AEC, aec_app_online_parse);
|
||||
}
|
||||
aec_cfg_online_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(aec_cfg_init);
|
||||
#endif
|
||||
1029
cpu/br28/app_audio.c
Normal file
1029
cpu/br28/app_audio.c
Normal file
File diff suppressed because it is too large
Load Diff
3528
cpu/br28/audio_anc.c
Normal file
3528
cpu/br28/audio_anc.c
Normal file
File diff suppressed because it is too large
Load Diff
405
cpu/br28/audio_anc.h
Normal file
405
cpu/br28/audio_anc.h
Normal file
@ -0,0 +1,405 @@
|
||||
#ifndef AUDIO_ANC_H
|
||||
#define AUDIO_ANC_H
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "asm/anc.h"
|
||||
#include "anc_btspp.h"
|
||||
#include "anc_uart.h"
|
||||
#include "app_config.h"
|
||||
#include "in_ear_detect/in_ear_manage.h"
|
||||
#include "audio_anc_mult_scene.h"
|
||||
#include "icsd_anc_app.h"
|
||||
#include "audio_anc_fade_ctr.h"
|
||||
|
||||
/*******************ANC User Config***********************/
|
||||
#define ANC_COEFF_SAVE_ENABLE 1 /*ANC滤波器表保存使能*/
|
||||
#define ANC_INFO_SAVE_ENABLE 0 /*ANC信息记忆:保存上一次关机时所处的降噪模式等等*/
|
||||
#define ANC_TONE_PREEMPTION 0 /*ANC提示音打断播放(1)还是叠加播放(0)*/
|
||||
#define ANC_BOX_READ_COEFF 1 /*支持通过工具读取ANC训练系数*/
|
||||
#define ANC_FADE_EN 1 /*ANC淡入淡出使能*/
|
||||
#define ANC_MODE_SYSVDD_EN 0 /*ANC模式提高SYSVDD,避免某些IC电压太低导致ADC模块工作不正常*/
|
||||
#define ANC_TONE_END_MODE_SW 1 /*ANC提示音结束进行模式切换*/
|
||||
#define ANC_MODE_EN_MODE_NEXT_SW 1 /*ANC提示音结束后才允许下一次模式切换*/
|
||||
#define ANC_MODE_FADE_LVL 1 /*降噪模式淡入步进 * 53ms*/
|
||||
|
||||
/*
|
||||
ANC多场景滤波器配置
|
||||
*/
|
||||
#define ANC_MULT_ORDER_ENABLE 0 /*ANC多滤波器使能*/
|
||||
#define ANC_MULT_ORDER_CMP_ONLY_USE_ID1 1 /*ANC多滤波器-CMP音乐补偿仅使用场景ID1的参数*/
|
||||
#define ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 0 /*ANC多滤波器-通透模式仅使用场景ID1的参数*/
|
||||
|
||||
#define ANC_MULT_ORDER_NORMAL_ID 1 /*ANC多滤波器-开机默认场景ID*/
|
||||
|
||||
//ANC多滤波器-耳道自适应ID匹配,选择0则跟随当前场景
|
||||
#define ANC_MULT_ADPTIVE_TRAIN_USE_ID 1 /*耳道自适应-训练使用的场景ID*/
|
||||
#define ANC_MULT_ADPTIVE_MATCH_USE_ID 1 /*耳道自适应-匹配使用的场景ID*/
|
||||
|
||||
/*-------------------耳道自适应开发者模式说明------------------
|
||||
开发者模式(支持工具在线修改)
|
||||
权限:
|
||||
1、MIC/SPK数据获取,采样率跟随ANC
|
||||
2、支持工具自适应数据读取,会占用3-4K ram
|
||||
3、TWS区分左右参数
|
||||
4、进入后不支持产测,关机自动退出开发者模式
|
||||
|
||||
ANC_DEVELOPER_MODE_EN
|
||||
开发者强制模式(不支持工具修改, 开机默认开发者模式)
|
||||
新增权限:
|
||||
5、每次自适应都保存数据,保存前会校验数据,确保开机转换数据正常,不会死机
|
||||
6、自适应失败播放提示音
|
||||
-------------------------------------------------------------*/
|
||||
#define ANC_DEVELOPER_MODE_EN 0 /*开发者强制模式强制使能,启动后不支持产测, 优先级最高, 不受工具控制*/
|
||||
|
||||
#define ANC_EAR_ADAPTIVE_EN TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN /*ANC耳道自适应使能, 耳道是变量*/
|
||||
#define ANC_POWEOFF_SAVE_ADAPTIVE_DATA 1 /*保存耳道自适应数据 0 每次保存;1 关机保存*/
|
||||
#define ANC_EAR_ADAPTIVE_CMP_EN ANC_ADAPTIVE_CMP_EN /*ANC耳道自适应音乐补偿使能*/
|
||||
#define ANC_EAR_ADAPTIVE_EVERY_TIME 0 /*每次切ANC_ON都进行自适应*/
|
||||
|
||||
/*
|
||||
ANC场景增益自适应配置
|
||||
(场景是变量,与耳道自适应功能相互独立)
|
||||
*/
|
||||
#define ANC_ADAPTIVE_EN 0 /*ANC增益自适应使能*/
|
||||
#define ANC_ADAPTIVE_MODE ANC_ADAPTIVE_GAIN_MODE /*ANC增益自适应模式*/
|
||||
#define ANC_ADAPTIVE_TONE_EN 0 /*ANC增益自适应提示音使能*/
|
||||
|
||||
/*
|
||||
音乐响度ANC动态增益调节, 随着音乐响度增大而减小ANC增益, 开此功能可关闭AUDIO_DRC
|
||||
*/
|
||||
#define ANC_MUSIC_DYNAMIC_GAIN_EN 0 /*音乐动态ANC增益使能*/
|
||||
#define ANC_MUSIC_DYNAMIC_GAIN_THR -12 /*音乐动态ANC增益触发阈值(单位dB), range: (-30 ~ 0]*/
|
||||
#define ANC_MUSIC_DYNAMIC_GAIN_SINGLE_FB 1 /*动态增益单独调FB增益使能*/
|
||||
|
||||
#if ANC_TRAIN_MODE == ANC_FB_EN
|
||||
#define ANC_MODE_ENABLE ANC_OFF_BIT | ANC_ON_BIT
|
||||
#else
|
||||
#define ANC_MODE_ENABLE ANC_OFF_BIT | ANC_ON_BIT | ANC_TRANS_BIT
|
||||
#endif/*ANC_TRAIN_MODE*/
|
||||
|
||||
//************************************************************************//
|
||||
// ICSD ADT 相关功能配置 //
|
||||
//************************************************************************//
|
||||
#define AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC 0//广域点击左右耳同步使能
|
||||
|
||||
/*支持开免摘的anc模式*/
|
||||
#define SPEAK_TO_CHAT_ANC_MODE_ENABLE (ANC_ON_BIT)
|
||||
|
||||
//****************** ICSD ADT 相关功能配置 end ************************//
|
||||
|
||||
/*ANC工具配对码使能*/
|
||||
#define ANCTOOL_NEED_PAIR_KEY 1
|
||||
#define ANCTOOL_PAIR_KEY "123456" /*ANC工具默认配对码*/
|
||||
|
||||
/*******************ANC User Config End*******************/
|
||||
|
||||
/*ANC模式调试信息*/
|
||||
static const char *anc_mode_str[] = {
|
||||
"NULL", /*无效/非法*/
|
||||
"ANC_OFF", /*关闭模式*/
|
||||
"ANC_ON", /*降噪模式*/
|
||||
"Transparency", /*通透模式*/
|
||||
"ANC_BYPASS", /*BYPASS模式*/
|
||||
"ANC_TRAIN", /*训练模式*/
|
||||
"ANC_TRANS_TRAIN", /*通透训练模式*/
|
||||
};
|
||||
|
||||
/*ANC状态调试信息*/
|
||||
static const char *anc_state_str[] = {
|
||||
"anc_close", /*关闭状态*/
|
||||
"anc_init", /*初始化状态*/
|
||||
"anc_open", /*打开状态*/
|
||||
};
|
||||
|
||||
/*ANC MSG List*/
|
||||
enum {
|
||||
ANC_MSG_TRAIN_OPEN = 0xA1,
|
||||
ANC_MSG_TRAIN_CLOSE,
|
||||
ANC_MSG_RUN,
|
||||
ANC_MSG_FADE_END,
|
||||
ANC_MSG_MODE_SYNC,
|
||||
ANC_MSG_TONE_SYNC,
|
||||
ANC_MSG_DRC_TIMER,
|
||||
ANC_MSG_DEBUG_OUTPUT,
|
||||
ANC_MSG_ADAPTIVE_SYNC,
|
||||
ANC_MSG_MUSIC_DYN_GAIN,
|
||||
ANC_MSG_ICSD_ANC_CMD,
|
||||
ANC_MSG_USER_TRAIN_INIT,
|
||||
ANC_MSG_USER_TRAIN_RUN,
|
||||
ANC_MSG_USER_TRAIN_SETPARAM,
|
||||
ANC_MSG_USER_TRAIN_TIMEOUT,
|
||||
ANC_MSG_ADT,
|
||||
ANC_MSG_USER_TRAIN_END,
|
||||
ANC_MSG_MIC_DATA_GET,
|
||||
ANC_MSG_RESET,
|
||||
ANC_MSG_SZ_FFT_OPEN,
|
||||
ANC_MSG_SZ_FFT_RUN,
|
||||
ANC_MSG_SZ_FFT_CLOSE,
|
||||
ANC_MSG_MODE_SWITCH_IN_ANCTASK,
|
||||
};
|
||||
|
||||
/*ANC MIC动态增益调整状态*/
|
||||
enum {
|
||||
ANC_MIC_DY_STA_INIT = 0, /*准备状态*/
|
||||
ANC_MIC_DY_STA_START, /*进行状态*/
|
||||
ANC_MIC_DY_STA_STOP, /*停止状态*/
|
||||
};
|
||||
|
||||
#define ANC_CONFIG_LFF_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FF_EN)) && (ANC_CH & ANC_L_CH))
|
||||
#define ANC_CONFIG_LFB_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FB_EN)) && (ANC_CH & ANC_L_CH))
|
||||
#define ANC_CONFIG_RFF_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FF_EN)) && (ANC_CH & ANC_R_CH))
|
||||
#define ANC_CONFIG_RFB_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FB_EN)) && (ANC_CH & ANC_R_CH))
|
||||
|
||||
/*ANC记忆信息*/
|
||||
typedef struct {
|
||||
u8 mode; /*当前模式*/
|
||||
u8 mode_enable; /*使能的模式*/
|
||||
#if INEAR_ANC_UI
|
||||
u8 inear_tws_mode;
|
||||
#endif/*INEAR_ANC_UI*/
|
||||
//s32 coeff[488];
|
||||
} anc_info_t;
|
||||
|
||||
|
||||
#if ANC_EAR_ADAPTIVE_EN
|
||||
|
||||
typedef struct {
|
||||
#if ANC_EAR_RECORD_EN
|
||||
float record_FL[EAR_RECORD_MAX][ANC_VMDATA_FF_RECORD_SIZE];
|
||||
float record_FR[EAR_RECORD_MAX][ANC_VMDATA_FF_RECORD_SIZE];
|
||||
int record_num;
|
||||
// u8 record_num;
|
||||
#endif/*ANC_EAR_RECORD_EN*/
|
||||
u8 result;
|
||||
#if ANC_CONFIG_LFF_EN
|
||||
float lff_gain;
|
||||
anc_fr_t lff[ANC_ADAPTIVE_FF_ORDER];
|
||||
#endif/*ANC_CONFIG_LFF_EN*/
|
||||
#if ANC_CONFIG_LFB_EN
|
||||
float lfb_gain;
|
||||
anc_fr_t lfb[ANC_ADAPTIVE_FB_ORDER];
|
||||
#if ANC_EAR_ADAPTIVE_CMP_EN
|
||||
float lcmp_gain;
|
||||
anc_fr_t lcmp[ANC_ADAPTIVE_CMP_ORDER];
|
||||
#endif/*ANC_EAR_ADAPTIVE_CMP_EN*/
|
||||
#endif/*ANC_CONFIG_LFB_EN*/
|
||||
#if ANC_CONFIG_RFF_EN
|
||||
float rff_gain;
|
||||
anc_fr_t rff[ANC_ADAPTIVE_FF_ORDER];
|
||||
#endif/*ANC_CONFIG_RFF_EN*/
|
||||
#if ANC_CONFIG_RFB_EN
|
||||
float rfb_gain;
|
||||
anc_fr_t rfb[ANC_ADAPTIVE_FB_ORDER];
|
||||
#if ANC_EAR_ADAPTIVE_CMP_EN
|
||||
float rcmp_gain;
|
||||
anc_fr_t rcmp[ANC_ADAPTIVE_CMP_ORDER];
|
||||
#endif/*ANC_EAR_ADAPTIVE_CMP_EN*/
|
||||
#endif/*ANC_CONFIG_RFB_EN*/
|
||||
} _PACKED anc_adaptive_iir_t;
|
||||
|
||||
#endif/*ANC_EAR_ADAPTIVE_EN */
|
||||
|
||||
|
||||
/*ANC初始化*/
|
||||
void anc_init(void);
|
||||
|
||||
/*ANC训练模式*/
|
||||
void anc_train_open(u8 mode, u8 debug_sel);
|
||||
|
||||
/*ANC关闭训练*/
|
||||
void anc_train_close(void);
|
||||
|
||||
/*
|
||||
*ANC状态获取
|
||||
*return 0: idle(初始化)
|
||||
*return 1: busy(ANC/通透/训练)
|
||||
*/
|
||||
u8 anc_status_get(void);
|
||||
|
||||
/*获取anc当前模式*/
|
||||
u8 anc_mode_get(void);
|
||||
|
||||
/*获取anc记录的最新的目标ANC模式*/
|
||||
u8 anc_new_target_mode_get(void);
|
||||
|
||||
#define ANC_DAC_CH_L 0
|
||||
#define ANC_DAC_CH_R 1
|
||||
/*获取anc模式,dac左右声道的增益*/
|
||||
u8 anc_dac_gain_get(u8 ch);
|
||||
|
||||
/*获取anc模式,ff_mic的增益*/
|
||||
u8 audio_anc_ffmic_gain_get(void);
|
||||
|
||||
/*获取anc模式,fb_mic的增益*/
|
||||
u8 audio_anc_fbmic_gain_get(void);
|
||||
|
||||
/*获取anc模式,指定mic的增益, mic_sel:目标MIC通道*/
|
||||
u8 audio_anc_mic_gain_get(u8 mic_sel);
|
||||
|
||||
/*ANC模式切换(切换到指定模式),并配置是否播放提示音*/
|
||||
void anc_mode_switch(u8 mode, u8 tone_play);
|
||||
|
||||
/*在anc任务里面切换anc模式,
|
||||
*避免上一次切换没有完成,这次切换被忽略的情况*/
|
||||
void anc_mode_switch_in_anctask(u8 mode, u8 tone_play);
|
||||
|
||||
/*ANC模式同步(tws模式)*/
|
||||
void anc_mode_sync(u8 *data);
|
||||
|
||||
void anc_poweron(void);
|
||||
|
||||
/*ANC poweroff*/
|
||||
void anc_poweroff(void);
|
||||
|
||||
/*ANC模式切换(下一个模式)*/
|
||||
void anc_mode_next(void);
|
||||
|
||||
/*ANC通过ui菜单选择anc模式,处理快速切换的情景*/
|
||||
void anc_ui_mode_sel(u8 mode, u8 tone_play);
|
||||
|
||||
/*设置ANC支持切换的模式*/
|
||||
void anc_mode_enable_set(u8 mode_enable);
|
||||
|
||||
/*anc coeff 长度大小获取*/
|
||||
int anc_coeff_size_get(u8 mode);
|
||||
|
||||
void anc_coeff_size_set(u8 mode, int len);
|
||||
|
||||
int *anc_debug_ctr(u8 free_en);
|
||||
/*
|
||||
*查询当前ANC是否处于训练状态
|
||||
*@return 1:处于训练状态
|
||||
*@return 0:其他状态
|
||||
*/
|
||||
int anc_train_open_query(void);
|
||||
|
||||
/*ANC在线调试繁忙标志设置*/
|
||||
void anc_online_busy_set(u8 en);
|
||||
|
||||
/*ANC在线调试繁忙标志获取*/
|
||||
u8 anc_online_busy_get(void);
|
||||
|
||||
/*tws同步播放模式提示音,并且同步进入anc模式*/
|
||||
void anc_tone_sync_play(int tone_name);
|
||||
|
||||
/*anc coeff读接口*/
|
||||
int *anc_coeff_read(void);
|
||||
|
||||
/*anc coeff写接口*/
|
||||
int anc_coeff_write(int *coeff, u16 len);
|
||||
|
||||
/*ANC挂起*/
|
||||
void anc_suspend(void);
|
||||
|
||||
/*ANC恢复*/
|
||||
void anc_resume(void);
|
||||
|
||||
/*通话动态MIC增益开始函数*/
|
||||
void anc_dynamic_micgain_start(u8 audio_mic_gain);
|
||||
|
||||
/*通话动态MIC增益结束函数*/
|
||||
void anc_dynamic_micgain_stop(void);
|
||||
|
||||
/*anc_gains参数读写接口*/
|
||||
void anc_param_fill(u8 cmd, anc_gain_t *cfg);
|
||||
|
||||
/*ANC_DUT audio模块使能函数,用于分离功耗*/
|
||||
void audio_anc_dut_enable_set(u8 enablebit);
|
||||
|
||||
/*ANC自适应TWS同步信息处理*/
|
||||
void audio_anc_adap_sync(int ref_num, int err_num, int err);
|
||||
void audio_anc_adap_num_compare(int ref_num, int err_num);
|
||||
|
||||
/*设置fb mic为复用mic*/
|
||||
void audio_anc_mic_mana_fb_mult_set(u8 mult_flag);
|
||||
|
||||
//ANC MIC信息管理
|
||||
void audio_anc_mic_management(audio_anc_t *param);
|
||||
|
||||
/*切换ANC自适应模式*/
|
||||
void audio_anc_adaptive_mode_set(u8 mode, u8 lvl);
|
||||
|
||||
/*ANC增益调节 音乐响度检测*/
|
||||
void audio_anc_music_dynamic_gain_det(s16 *data, int len);
|
||||
|
||||
/*ANC增益调节 音乐响度初始化*/
|
||||
void audio_anc_music_dynamic_gain_init(int sr);
|
||||
|
||||
/*ANC增益调节 音乐响度复位*/
|
||||
void audio_anc_music_dynamic_gain_reset(u8 effect_reset_en);
|
||||
|
||||
/*
|
||||
自适应模式-重新检测
|
||||
param: tws_sync_en 1 TWS同步自适应,支持TWS降噪平衡,需左右耳一起调用此接口
|
||||
0 单耳自适应, 不支持TWS降噪平衡,可TWS状态下单耳自适应
|
||||
*/
|
||||
int audio_anc_mode_ear_adaptive(u8 tws_sync_en);
|
||||
|
||||
/*
|
||||
自适应/普通参数切换
|
||||
param: mode 0 使用普通参数; 1 使用自适应参数
|
||||
tone_play 0 不播放提示音;1 播放提示音
|
||||
update_flag 0 不更新效果; 1 即时更新效果
|
||||
*/
|
||||
int audio_anc_coeff_adaptive_set(u32 mode, u8 tone_play, u8 update_flag);
|
||||
|
||||
/*ANC滤波器模式循环切换*/
|
||||
int audio_anc_coeff_adaptive_switch();
|
||||
|
||||
/*判断当前是否处于训练中*/
|
||||
u8 audio_anc_adaptive_busy_get(void);
|
||||
|
||||
/*当前ANC滤波器模式获取 0:普通参数 1:自适应参数*/
|
||||
int audio_anc_coeff_mode_get(void);
|
||||
|
||||
/*强制停止ANC训练 - 并用回默认参数*/
|
||||
void anc_ear_adaptive_forced_exit(void);
|
||||
|
||||
/*自适应训练失败处理回调函数*/
|
||||
void audio_anc_adaptive_fail_callback(u8 anc_err);
|
||||
|
||||
void audio_anc_develop_set(u8 mode);
|
||||
|
||||
u8 audio_anc_develop_get(void);
|
||||
|
||||
/*自适应主从序号*/
|
||||
u8 anc_ear_adaptive_seq_get(void);
|
||||
|
||||
void audio_anc_param_map(u8 coeff_en, u8 gain_en);
|
||||
|
||||
/*
|
||||
多滤波器-场景切换
|
||||
param: scene 场景ID
|
||||
update_flag 非ANC_OFF时,即时更新效果: 0 不更新;1 更新
|
||||
Note: ID 从1 开始
|
||||
*/
|
||||
void audio_anc_mult_scene_set(u16 scene_id, u8 update_flag);
|
||||
|
||||
/*多滤波器-获取当前场景的滤波器*/
|
||||
u8 audio_anc_mult_scene_get(void);
|
||||
|
||||
/*多滤波器-最大场景个数设置*/
|
||||
void audio_anc_mult_scene_max_set(u8 scene_cnt);
|
||||
|
||||
/*多滤波器-最大场景个数获取*/
|
||||
u8 audio_anc_mult_scene_max_get(void);
|
||||
|
||||
/*多滤波器-场景循环切换*/
|
||||
void audio_anc_mult_scene_switch(u8 tone_flag);
|
||||
|
||||
/*
|
||||
ANC结构设置, 下一次切模式或复位ANC时生效
|
||||
param: enablebit ANC结构配置,如(ANC_FF_EN/ANC_FB_EN/ANC_HYBRID_EN)
|
||||
update_flag 非ANC_OFF时,即时更新效果: 0 不更新;1 更新
|
||||
*/
|
||||
void audio_anc_enable_set(u8 enablebit, u8 update_flag);
|
||||
|
||||
//ANC产测/调试模式设置
|
||||
void audio_anc_prodution_mode_set(u8 mode);
|
||||
|
||||
extern int anc_uart_write(u8 *buf, u8 len);
|
||||
extern void ci_send_packet(u32 id, u8 *packet, int size);
|
||||
extern void sys_auto_shut_down_enable(void);
|
||||
extern void sys_auto_shut_down_disable(void);
|
||||
|
||||
#endif/*AUDIO_ANC_H*/
|
||||
270
cpu/br28/audio_anc_coeff.h
Normal file
270
cpu/br28/audio_anc_coeff.h
Normal file
@ -0,0 +1,270 @@
|
||||
#ifndef _AUDIO_ANC_COEFF_H_
|
||||
#define _AUDIO_ANC_COEFF_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
//46K
|
||||
// const double trans_coeff_test[10] = {
|
||||
// 1.000000e+00,
|
||||
// -2.000000e+00,
|
||||
// 1.000000e+00,
|
||||
// -1.626608e+00,
|
||||
// 6.662413e-01,
|
||||
|
||||
// 1.000000e+00,
|
||||
// -2.000000e+00,
|
||||
// 1.000000e+00,
|
||||
// -1.802846e+00,
|
||||
// 8.467739e-01
|
||||
// };
|
||||
|
||||
//93k
|
||||
const double trans_coeff_test[15] = {
|
||||
1.000000e+00,
|
||||
-2.000000e+00,
|
||||
1.000000e+00,
|
||||
-1.878287e+00,
|
||||
8.825817e-01,
|
||||
|
||||
1.000000e+00,
|
||||
-2.000000e+00,
|
||||
1.000000e+00,
|
||||
-1.945184e+00,
|
||||
9.496315e-01,
|
||||
|
||||
5.154418e-02,
|
||||
1.030884e-01,
|
||||
5.154418e-02,
|
||||
-1.263093e+00,
|
||||
4.692696e-01
|
||||
|
||||
};
|
||||
|
||||
static const s32 fz_coef_test[100] = {
|
||||
-15,
|
||||
-27,
|
||||
-10,
|
||||
-14,
|
||||
-38,
|
||||
-8,
|
||||
-22,
|
||||
-40,
|
||||
-29,
|
||||
14,
|
||||
28,
|
||||
26,
|
||||
-28,
|
||||
-21,
|
||||
2,
|
||||
-52,
|
||||
-95,
|
||||
-99,
|
||||
-25,
|
||||
103,
|
||||
62,
|
||||
-58,
|
||||
-116,
|
||||
-137,
|
||||
-27,
|
||||
77,
|
||||
25,
|
||||
-138,
|
||||
-250,
|
||||
-174,
|
||||
11,
|
||||
147,
|
||||
80,
|
||||
-52,
|
||||
-108,
|
||||
7,
|
||||
146,
|
||||
217,
|
||||
122,
|
||||
3,
|
||||
-49,
|
||||
35,
|
||||
93,
|
||||
93,
|
||||
20,
|
||||
-43,
|
||||
-84,
|
||||
-46,
|
||||
-4,
|
||||
3,
|
||||
-50,
|
||||
-71,
|
||||
-64,
|
||||
-25,
|
||||
30,
|
||||
3,
|
||||
-54,
|
||||
-56,
|
||||
-65,
|
||||
-15,
|
||||
17,
|
||||
-36,
|
||||
-55,
|
||||
-50,
|
||||
-21,
|
||||
33,
|
||||
41,
|
||||
4,
|
||||
-33,
|
||||
-49,
|
||||
-13,
|
||||
23,
|
||||
25,
|
||||
5,
|
||||
-26,
|
||||
-37,
|
||||
-13,
|
||||
17,
|
||||
22,
|
||||
28,
|
||||
6,
|
||||
-1,
|
||||
10,
|
||||
28,
|
||||
29,
|
||||
7,
|
||||
-16,
|
||||
-21,
|
||||
1,
|
||||
17,
|
||||
5,
|
||||
-13,
|
||||
-24,
|
||||
-11,
|
||||
3,
|
||||
10,
|
||||
-2,
|
||||
-22,
|
||||
-9,
|
||||
-9
|
||||
};
|
||||
|
||||
#if 1
|
||||
const double ancl_fb_coef_test[100] = {
|
||||
1.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00,
|
||||
0.000000e+00
|
||||
};
|
||||
|
||||
const double ancl_ff_coef_test[100] = {
|
||||
|
||||
};
|
||||
|
||||
const double ancl_sz_coef_test[100] = {
|
||||
|
||||
};
|
||||
|
||||
const double ancr_fb_coef_test[100] = {
|
||||
|
||||
};
|
||||
|
||||
const double ancr_ff_coef_test[100] = {
|
||||
|
||||
};
|
||||
|
||||
const double ancr_sz_coef_test[100] = {
|
||||
|
||||
};
|
||||
#endif
|
||||
#endif/*_AUDIO_ANC_COEFF_H_*/
|
||||
138
cpu/br28/audio_anc_fade_ctr.c
Normal file
138
cpu/br28/audio_anc_fade_ctr.c
Normal file
@ -0,0 +1,138 @@
|
||||
#include "audio_anc_fade_ctr.h"
|
||||
#include "anc.h"
|
||||
#include "audio_anc.h"
|
||||
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO ANC
|
||||
* File : audio_anc_fade_ctr.c
|
||||
* By : Junhao
|
||||
* Notes : ANC fade gain管理,支持多场景并行使用
|
||||
*
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define anc_fade_log printf
|
||||
#else
|
||||
#define anc_fade_log(...)
|
||||
#endif/*log_en*/
|
||||
|
||||
//默认淡入增益,dB换算公式 fade_gain = 10^(dB/20) * 16384;
|
||||
#define AUDIO_ANC_FADE_GAIN_DEFAULT 16384 //(0dB)
|
||||
|
||||
struct anc_fade_context {
|
||||
struct list_head entry;
|
||||
enum anc_fade_mode_t mode;
|
||||
u8 ch;
|
||||
u16 fade_gain;
|
||||
};
|
||||
|
||||
static LIST_HEAD(anc_fade_head);
|
||||
|
||||
static OS_MUTEX fade_mutex;
|
||||
|
||||
static void anc_fade_ctr_list_del(enum anc_fade_mode_t mode)
|
||||
{
|
||||
struct anc_fade_context *ctx;
|
||||
if (list_empty(&anc_fade_head)) {
|
||||
return;
|
||||
}
|
||||
list_for_each_entry(ctx, &anc_fade_head, entry) {
|
||||
if (!strcmp(ctx->mode, mode)) {
|
||||
goto __fade_del;
|
||||
}
|
||||
}
|
||||
return;
|
||||
__fade_del:
|
||||
list_del(&ctx->entry);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void anc_fade_ctr_list_add(enum anc_fade_mode_t mode, u8 ch, u16 gain)
|
||||
{
|
||||
struct anc_fade_context *new_ctx = malloc(sizeof(struct anc_fade_context));
|
||||
new_ctx->mode = mode;
|
||||
//通道检测,有些芯片 fade_gain 不区分通道
|
||||
new_ctx->ch = anc_fade_ctr_ch_check(ch);
|
||||
new_ctx->fade_gain = gain;
|
||||
list_add_tail(&new_ctx->entry, &anc_fade_head);
|
||||
}
|
||||
|
||||
static int anc_fade_ctr_update(enum anc_fade_mode_t mode, u8 ch, u16 gain)
|
||||
{
|
||||
struct anc_fade_context *ctx;
|
||||
if (list_empty(&anc_fade_head)) {
|
||||
return 1;
|
||||
}
|
||||
list_for_each_entry(ctx, &anc_fade_head, entry) {
|
||||
if (ctx->mode == mode) {
|
||||
if (ctx->ch != ch) {
|
||||
printf("ERR!!!anc_fade_gain mode&ch is no \"one to one\" \n");
|
||||
}
|
||||
ctx->fade_gain = gain;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void audio_anc_fade_ctr_init(void)
|
||||
{
|
||||
os_mutex_create(&fade_mutex);
|
||||
}
|
||||
|
||||
void audio_anc_fade_ctr_set(enum anc_fade_mode_t mode, u8 ch, u16 gain)
|
||||
{
|
||||
os_mutex_pend(&fade_mutex, 0);
|
||||
u16 lff_gain, lfb_gain, rff_gain, rfb_gain;
|
||||
struct anc_fade_context *ctx;
|
||||
u8 fade_en = anc_api_get_fade_en();
|
||||
/* anc_fade_log("fade in mode %d, gain %d\n", mode, gain); */
|
||||
|
||||
lff_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
|
||||
lfb_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
|
||||
rff_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
|
||||
rfb_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
|
||||
|
||||
if (gain == AUDIO_ANC_FADE_GAIN_DEFAULT) {
|
||||
anc_fade_ctr_list_del(mode); //删除
|
||||
} else {
|
||||
if (anc_fade_ctr_update(mode, ch, gain)) { //更新
|
||||
anc_fade_ctr_list_add(mode, ch, gain); //新增
|
||||
}
|
||||
}
|
||||
|
||||
//遍历链表
|
||||
if (!list_empty(&anc_fade_head)) {
|
||||
list_for_each_entry(ctx, &anc_fade_head, entry) {
|
||||
/* anc_fade_log("fade list : mode %d, gain %d\n", ctx->mode, ctx->fade_gain); */
|
||||
if ((ctx->ch & AUDIO_ANC_FADE_CH_LFF) && (ctx->fade_gain < lff_gain)) {
|
||||
lff_gain = ctx->fade_gain;
|
||||
}
|
||||
if ((ctx->ch & AUDIO_ANC_FADE_CH_LFB) && (ctx->fade_gain < lfb_gain)) {
|
||||
lfb_gain = ctx->fade_gain;
|
||||
}
|
||||
if ((ctx->ch & AUDIO_ANC_FADE_CH_RFF) && (ctx->fade_gain < rff_gain)) {
|
||||
rff_gain = ctx->fade_gain;
|
||||
}
|
||||
if ((ctx->ch & AUDIO_ANC_FADE_CH_RFB) && (ctx->fade_gain < rfb_gain)) {
|
||||
rfb_gain = ctx->fade_gain;
|
||||
}
|
||||
}
|
||||
}
|
||||
anc_fade_log("fade lff %d, lfb %d, rff %d, rfb %d\n", lff_gain, lfb_gain, rff_gain, rfb_gain);
|
||||
audio_anc_fade_cfg_set(fade_en, 1, 0);
|
||||
audio_anc_fade(AUDIO_ANC_FADE_CH_LFF, lff_gain);
|
||||
audio_anc_fade(AUDIO_ANC_FADE_CH_LFB, lfb_gain);
|
||||
audio_anc_fade(AUDIO_ANC_FADE_CH_RFF, rff_gain);
|
||||
audio_anc_fade(AUDIO_ANC_FADE_CH_RFB, rfb_gain);
|
||||
os_mutex_post(&fade_mutex);
|
||||
}
|
||||
|
||||
void audio_anc_fade_ctr_del(enum anc_fade_mode_t mode)
|
||||
{
|
||||
audio_anc_fade_ctr_set(mode, 0, AUDIO_ANC_FADE_GAIN_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
39
cpu/br28/audio_anc_fade_ctr.h
Normal file
39
cpu/br28/audio_anc_fade_ctr.h
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
#ifndef _AUDIO_ANC_FADE_CTR_H_
|
||||
#define _AUDIO_ANC_FADE_CTR_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
//ANC全部通道
|
||||
#define AUDIO_ANC_FDAE_CH_ALL AUDIO_ANC_FADE_CH_LFF | AUDIO_ANC_FADE_CH_LFB | AUDIO_ANC_FADE_CH_RFF | AUDIO_ANC_FADE_CH_RFB
|
||||
|
||||
enum anc_fade_mode_t {
|
||||
ANC_FADE_MODE_RESET = 0, //复位
|
||||
ANC_FADE_MODE_SWITCH, //ANC模式切换
|
||||
ANC_FADE_MODE_MUSIC_DYNAMIC, //音乐动态增益
|
||||
ANC_FADE_MODE_SCENE_ADAPTIVE, //ANC场景噪声自适应
|
||||
ANC_FADE_MODE_WIND_NOISE, //ANC风噪检测
|
||||
ANC_FADE_MODE_SUSPEND, //ANC挂起
|
||||
//可再此继续添加模式
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
ANC淡入淡出增益设置
|
||||
param: mode 场景模式
|
||||
ch 设置目标通道(支持多通道)
|
||||
gain 设置增益
|
||||
notes: ch 支持配置多个通道,但mode 必须与 ch配置一一对应;
|
||||
当设置gain = 16384, 会自动删除对应模式
|
||||
*/
|
||||
void audio_anc_fade_ctr_set(enum anc_fade_mode_t mode, u8 ch, u16 gain);
|
||||
|
||||
//删除fade mode
|
||||
void audio_anc_fade_ctr_del(enum anc_fade_mode_t mode);
|
||||
|
||||
//fade ctr 初始化
|
||||
void audio_anc_fade_ctr_init(void);
|
||||
|
||||
|
||||
#endif/*_AUDIO_ANC_FADE_CTR_H_*/
|
||||
|
||||
972
cpu/br28/audio_anc_mult_scene.c
Normal file
972
cpu/br28/audio_anc_mult_scene.c
Normal file
@ -0,0 +1,972 @@
|
||||
|
||||
/*******************************************************************
|
||||
ANC 多滤波器场景
|
||||
*******************************************************************/
|
||||
#include "audio_anc.h"
|
||||
#include "audio_anc_mult_scene.h"
|
||||
|
||||
|
||||
#if ANC_MULT_ORDER_ENABLE
|
||||
|
||||
#if 0
|
||||
#define anc_mult_log printf
|
||||
#else
|
||||
#define anc_mult_log(...)
|
||||
#endif/*log_en*/
|
||||
|
||||
//ANC重组数据流程测试
|
||||
#define ANC_MULT_DATA_TEST 0 //1 测试读取 ;2 测试重组
|
||||
|
||||
typedef struct {
|
||||
u8 yorder;
|
||||
anc_mult_gain_t *gains; //gains, 复用flash位置
|
||||
anc_fr_t *fr; //滤波器,复用flash位置
|
||||
} anc_mult_param_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head entry;
|
||||
u16 scene_id; //场景号
|
||||
anc_mult_param_t lff;
|
||||
anc_mult_param_t lfb;
|
||||
anc_mult_param_t ltrans;
|
||||
anc_mult_param_t lcmp;
|
||||
anc_mult_param_t rff;
|
||||
anc_mult_param_t rfb;
|
||||
anc_mult_param_t rtrans;
|
||||
anc_mult_param_t rcmp;
|
||||
} anc_mult_bulk_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head head;
|
||||
audio_anc_t *param;
|
||||
u16 cur_scene;
|
||||
double *lff_coeff;
|
||||
double *lfb_coeff;
|
||||
double *lcmp_coeff;
|
||||
double *ltrans_coeff;
|
||||
double *rff_coeff;
|
||||
double *rfb_coeff;
|
||||
double *rcmp_coeff;
|
||||
double *rtrans_coeff;
|
||||
} anc_mult_hdl_t;
|
||||
|
||||
//场景数据子结构;
|
||||
typedef struct {
|
||||
u16 scene_id;
|
||||
u16 cnt;
|
||||
u8 dat[0]; //小心访问非对齐异常
|
||||
} anc_mult_scene_file_t;
|
||||
|
||||
/*
|
||||
包含关系
|
||||
anc_coeff_t
|
||||
->anc_mult_scene_file_t
|
||||
->struct anc_param_head_t
|
||||
->data;
|
||||
*/
|
||||
anc_mult_hdl_t *mult_hdl = NULL;
|
||||
|
||||
static anc_coeff_t *anc_mult_cfg_test(int *db_len);
|
||||
static anc_coeff_t *anc_mult_cfg_part_test(int *db_len);
|
||||
|
||||
|
||||
//多滤波器数据填充
|
||||
static int anc_mult_scene_param_read(struct list_head *list, u8 *dat)
|
||||
{
|
||||
int i = 0;
|
||||
int file_offset = 0;
|
||||
u8 *temp_dat;
|
||||
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)dat;
|
||||
anc_mult_scene_file_t file_align;
|
||||
memcpy((u8 *)&file_align, (u8 *)file, sizeof(anc_mult_scene_file_t));
|
||||
struct anc_param_head_t id_head[file_align.cnt];
|
||||
|
||||
anc_mult_bulk_t *bulk = zalloc(sizeof(anc_mult_bulk_t));
|
||||
|
||||
bulk->scene_id = file_align.scene_id;
|
||||
|
||||
/* put_buf(db_coeff->dat, db_coeff->cnt * 6); */
|
||||
anc_mult_log("anc_mult_scene_id %d\n", file_align.scene_id);
|
||||
temp_dat = file->dat + (file_align.cnt * 6);
|
||||
for (i = 0; i < file_align.cnt; i++) {
|
||||
memcpy(&id_head[i], file->dat + (i * 6), 6); //结构体为8字节,这里只有6字节
|
||||
anc_mult_log("id:0X%x, offset:%d,len:%d\n", id_head[i].id, id_head[i].offset, id_head[i].len);
|
||||
switch (id_head[i].id) {
|
||||
case ANC_L_FF_FGQ:
|
||||
anc_mult_log("ANC_L_FF_FGQ\n");
|
||||
bulk->lff.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->lff.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_L_FB_FGQ:
|
||||
anc_mult_log("ANC_L_FB_FGQ\n");
|
||||
bulk->lfb.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->lfb.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_L_CMP_FGQ:
|
||||
anc_mult_log("ANC_L_CMP_FGQ\n");
|
||||
bulk->lcmp.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->lcmp.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_L_TRANS_FGQ:
|
||||
anc_mult_log("ANC_L_TRANS_FGQ\n");
|
||||
bulk->ltrans.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->ltrans.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
|
||||
case ANC_L_FF_PARM:
|
||||
anc_mult_log("ANC_L_FF_PARM\n");
|
||||
bulk->lff.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_L_FB_PARM:
|
||||
anc_mult_log("ANC_L_FB_PARM\n");
|
||||
bulk->lfb.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_L_CMP_PARM:
|
||||
anc_mult_log("ANC_L_CMP_PARM\n");
|
||||
bulk->lcmp.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_L_TRANS_PARM:
|
||||
anc_mult_log("ANC_L_TRANS_PARM\n");
|
||||
bulk->ltrans.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
|
||||
case ANC_R_FF_FGQ:
|
||||
anc_mult_log("ANC_R_FF_FGQ\n");
|
||||
bulk->rff.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->rff.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_R_FB_FGQ:
|
||||
anc_mult_log("ANC_R_FB_FGQ\n");
|
||||
bulk->rfb.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->rfb.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_R_CMP_FGQ:
|
||||
anc_mult_log("ANC_R_CMP_FGQ\n");
|
||||
bulk->rcmp.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->rcmp.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
case ANC_R_TRANS_FGQ:
|
||||
anc_mult_log("ANC_R_TRANS_FGQ\n");
|
||||
bulk->rtrans.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
|
||||
bulk->rtrans.yorder = id_head[i].len / 13;
|
||||
break;
|
||||
|
||||
case ANC_R_FF_PARM:
|
||||
anc_mult_log("ANC_R_FF_PARM\n");
|
||||
bulk->rff.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_R_FB_PARM:
|
||||
anc_mult_log("ANC_R_FB_PARM\n");
|
||||
bulk->rfb.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_R_CMP_PARM:
|
||||
anc_mult_log("ANC_R_CMP_PARM\n");
|
||||
bulk->rcmp.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_R_TRANS_PARM:
|
||||
anc_mult_log("ANC_R_TRANS_PARM\n");
|
||||
bulk->rtrans.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
|
||||
break;
|
||||
case ANC_L_ADAP_GOLD_CURVE:
|
||||
case ANC_R_ADAP_GOLD_CURVE:
|
||||
if (mult_hdl->param->adaptive) {
|
||||
anc_mult_log("ANC_L/R_ADAP_GOLD_CURVE\n");
|
||||
mult_hdl->param->adaptive->ref_ff_curve = temp_dat + id_head[i].offset;
|
||||
mult_hdl->param->adaptive->ref_ff_curve_len = id_head[i].len;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* put_buf((u8 *)(temp_dat + id_head[i].offset), id_head[i].len); */
|
||||
}
|
||||
|
||||
//加入链表
|
||||
list_add_tail(&bulk->entry, list);
|
||||
//下一个场景的数据偏移量
|
||||
file_offset = ((u32)temp_dat - (u32)dat) + id_head[file_align.cnt - 1].offset + id_head[file_align.cnt - 1].len;
|
||||
anc_mult_log("next scene offset %d\n", file_offset);
|
||||
return file_offset;
|
||||
}
|
||||
|
||||
static int anc_mult_scene_list_del(struct list_head *list)
|
||||
{
|
||||
anc_mult_bulk_t *bulk;
|
||||
anc_mult_bulk_t *temp;
|
||||
list_for_each_entry_safe(bulk, temp, list, entry) {
|
||||
list_del(&bulk->entry);
|
||||
free(bulk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//多滤波器文件读取
|
||||
int anc_mult_coeff_file_fill(anc_coeff_t *db_coeff)
|
||||
{
|
||||
int offset = 0;
|
||||
u8 *temp_dat;
|
||||
#if ANC_MULT_DATA_TEST == 1
|
||||
int len;
|
||||
db_coeff = anc_mult_cfg_test(&len);
|
||||
#endif/*ANC_MULT_DATA_TEST*/
|
||||
if (mult_hdl && db_coeff) {
|
||||
if ((db_coeff->version & 0xF0) == 0xA0) {
|
||||
anc_mult_log("%s scene_cnt %d\n", __func__, db_coeff->cnt);
|
||||
anc_mult_scene_list_del(&mult_hdl->head); //先卸载所有链表
|
||||
audio_anc_mult_scene_max_set(db_coeff->cnt);
|
||||
temp_dat = db_coeff->dat;
|
||||
for (int i = 0; i < db_coeff->cnt; i++) {
|
||||
//temp_dat表示当前场景数据指针,以下函数会返回 下一个场景相对当前temp_dat的偏移量
|
||||
temp_dat += anc_mult_scene_param_read(&mult_hdl->head, temp_dat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//多滤波器初始化API
|
||||
void anc_mult_init(audio_anc_t *param)
|
||||
{
|
||||
mult_hdl = zalloc(sizeof(anc_mult_hdl_t));
|
||||
mult_hdl->param = param;
|
||||
|
||||
//链表初始化
|
||||
INIT_LIST_HEAD(&mult_hdl->head);
|
||||
}
|
||||
|
||||
extern void audio_anc_biquad2ab_double(anc_fr_t *iir, double *out_coeff, u8 order, int alogm);
|
||||
static int anc_mult_cfg_analsis(anc_mult_param_t *p, double **coeff, float *gain, int alogm)
|
||||
{
|
||||
if (*coeff) {
|
||||
free(*coeff);
|
||||
*coeff = NULL;
|
||||
}
|
||||
if (!p->yorder) {
|
||||
//没有滤波器, 退出
|
||||
return -1;
|
||||
}
|
||||
*coeff = (double *)malloc(p->yorder * 40);
|
||||
/* g_printf("coeff %x\n", (u32)*coeff); */
|
||||
audio_anc_biquad2ab_double(p->fr, *coeff, p->yorder, alogm);
|
||||
float temp;
|
||||
memcpy((u8 *)&temp, (u8 *)&p->gains->iir_gain, 4);
|
||||
if (temp < 0) {
|
||||
*gain = 0 - temp;
|
||||
return 1; //返回符号位
|
||||
} else {
|
||||
*gain = temp;
|
||||
return 0; //返回符号位
|
||||
}
|
||||
}
|
||||
|
||||
//场景ID校验
|
||||
int audio_anc_mult_scene_id_check(u16 scene_id)
|
||||
{
|
||||
if (!mult_hdl) {
|
||||
return 1;
|
||||
}
|
||||
anc_mult_bulk_t *bulk;
|
||||
list_for_each_entry(bulk, &mult_hdl->head, entry) {
|
||||
if (bulk->scene_id == scene_id) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//目标场景, 转成IIR滤波器,并设置到lib coeff/gain变量
|
||||
int anc_mult_scene_set(u16 scene_id)
|
||||
{
|
||||
int ret = 1;
|
||||
if (!mult_hdl) {
|
||||
return 1;
|
||||
}
|
||||
anc_mult_log("anc_mult_scene_set cur scene_id %d\n", scene_id);
|
||||
u8 gain_sign = 0;
|
||||
audio_anc_t *param = mult_hdl->param;
|
||||
mult_hdl->cur_scene = scene_id;
|
||||
anc_mult_bulk_t *bulk;
|
||||
anc_mult_bulk_t *cmp_bulk;
|
||||
anc_mult_bulk_t *trans_bulk;
|
||||
list_for_each_entry(bulk, &mult_hdl->head, entry) {
|
||||
if (bulk->scene_id == scene_id) {
|
||||
if (anc_mult_cfg_analsis(&bulk->lff, &mult_hdl->lff_coeff, ¶m->gains.l_ffgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCL_FF_SIGN;
|
||||
}
|
||||
param->lff_coeff = mult_hdl->lff_coeff;
|
||||
param->lff_yorder = bulk->lff.yorder;
|
||||
/* g_printf("param->lff_yorder %d\n", param->lff_yorder); */
|
||||
/* put_buf((u8 *)mult_hdl->lff_coeff, bulk->lff.yorder * 40); */
|
||||
/* g_printf("gain %d/100, gain_sign %x\n", (int)(param->gains.l_ffgain * 100.0f), gain_sign); */
|
||||
|
||||
if (anc_mult_cfg_analsis(&bulk->lfb, &mult_hdl->lfb_coeff, ¶m->gains.l_fbgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCL_FB_SIGN;
|
||||
}
|
||||
param->lfb_coeff = mult_hdl->lfb_coeff;
|
||||
param->lfb_yorder = bulk->lfb.yorder;
|
||||
|
||||
if (anc_mult_cfg_analsis(&bulk->rff, &mult_hdl->rff_coeff, ¶m->gains.r_ffgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCR_FF_SIGN;
|
||||
}
|
||||
param->rff_coeff = mult_hdl->rff_coeff;
|
||||
param->rff_yorder = bulk->rff.yorder;
|
||||
|
||||
if (anc_mult_cfg_analsis(&bulk->rfb, &mult_hdl->rfb_coeff, ¶m->gains.r_fbgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCR_FB_SIGN;
|
||||
}
|
||||
param->rfb_coeff = mult_hdl->rfb_coeff;
|
||||
param->rfb_yorder = bulk->rfb.yorder;
|
||||
|
||||
#if !ANC_MULT_ORDER_CMP_ONLY_USE_ID1 //CMP支持多场景
|
||||
cmp_bulk = bulk;
|
||||
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
|
||||
#if !ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 //通透支持多场景
|
||||
trans_bulk = bulk;
|
||||
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
|
||||
ret = 0;
|
||||
}
|
||||
if (bulk->scene_id == 1) {
|
||||
#if ANC_MULT_ORDER_CMP_ONLY_USE_ID1 //CMP固定使用场景1的参数
|
||||
cmp_bulk = bulk;
|
||||
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
|
||||
#if ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 //通透固定使用场景1的参数
|
||||
trans_bulk = bulk;
|
||||
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
|
||||
}
|
||||
}
|
||||
|
||||
if (anc_mult_cfg_analsis(&cmp_bulk->lcmp, &mult_hdl->lcmp_coeff, ¶m->gains.l_cmpgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCL_CMP_SIGN;
|
||||
}
|
||||
param->lcmp_coeff = mult_hdl->lcmp_coeff;
|
||||
param->lcmp_yorder = cmp_bulk->lcmp.yorder;
|
||||
|
||||
if (anc_mult_cfg_analsis(&cmp_bulk->rcmp, &mult_hdl->rcmp_coeff, ¶m->gains.r_cmpgain, param->gains.alogm) > 0) {
|
||||
gain_sign |= ANCR_CMP_SIGN;
|
||||
}
|
||||
param->rcmp_coeff = mult_hdl->rcmp_coeff;
|
||||
param->rcmp_yorder = cmp_bulk->rcmp.yorder;
|
||||
|
||||
if (anc_mult_cfg_analsis(&trans_bulk->ltrans, &mult_hdl->ltrans_coeff, ¶m->gains.l_transgain, param->gains.trans_alogm) > 0) {
|
||||
gain_sign |= ANCL_TRANS_SIGN;
|
||||
}
|
||||
param->ltrans_coeff = mult_hdl->ltrans_coeff;
|
||||
param->ltrans_yorder = trans_bulk->ltrans.yorder;
|
||||
|
||||
if (anc_mult_cfg_analsis(&trans_bulk->rtrans, &mult_hdl->rtrans_coeff, ¶m->gains.r_transgain, param->gains.trans_alogm) > 0) {
|
||||
gain_sign |= ANCR_TRANS_SIGN;
|
||||
}
|
||||
param->rtrans_coeff = mult_hdl->rtrans_coeff;
|
||||
param->rtrans_yorder = trans_bulk->rtrans.yorder;
|
||||
|
||||
param->gains.gain_sign = gain_sign;
|
||||
audio_anc_max_yorder_verify(param);
|
||||
#if ANC_EAR_ADAPTIVE_EN
|
||||
//ANC自适应开发者模式,映射左右参数
|
||||
audio_anc_param_map(1, 1);
|
||||
#endif/*ANC_EAR_ADAPTIVE_EN*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
//释放IIR滤波器空间
|
||||
void audio_anc_mult_scene_coeff_free(void)
|
||||
{
|
||||
/*
|
||||
空间暂不释放:
|
||||
频繁切场景时或与自适应交叉使用时,set 和 free的动作可能不是一一对应的,
|
||||
导致最后一个信号量响应时,滤波器已经被提前释放了。
|
||||
*/
|
||||
return;
|
||||
if (!mult_hdl) {
|
||||
return;
|
||||
}
|
||||
if (mult_hdl->lff_coeff) {
|
||||
free(mult_hdl->lff_coeff);
|
||||
mult_hdl->param->lff_coeff = NULL;
|
||||
mult_hdl->lff_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->lfb_coeff) {
|
||||
free(mult_hdl->lfb_coeff);
|
||||
mult_hdl->param->lfb_coeff = NULL;
|
||||
mult_hdl->lfb_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->ltrans_coeff) {
|
||||
free(mult_hdl->ltrans_coeff);
|
||||
mult_hdl->param->ltrans_coeff = NULL;
|
||||
mult_hdl->ltrans_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->lcmp_coeff) {
|
||||
free(mult_hdl->lcmp_coeff);
|
||||
mult_hdl->param->lcmp_coeff = NULL;
|
||||
mult_hdl->lcmp_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->rff_coeff) {
|
||||
free(mult_hdl->rff_coeff);
|
||||
mult_hdl->param->rff_coeff = NULL;
|
||||
mult_hdl->rff_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->rfb_coeff) {
|
||||
free(mult_hdl->rfb_coeff);
|
||||
mult_hdl->param->rfb_coeff = NULL;
|
||||
mult_hdl->rfb_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->rtrans_coeff) {
|
||||
free(mult_hdl->rtrans_coeff);
|
||||
mult_hdl->param->rtrans_coeff = NULL;
|
||||
mult_hdl->rtrans_coeff = NULL;
|
||||
}
|
||||
if (mult_hdl->rcmp_coeff) {
|
||||
free(mult_hdl->rcmp_coeff);
|
||||
mult_hdl->param->rcmp_coeff = NULL;
|
||||
mult_hdl->rcmp_coeff = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*ANC滤波器格式校验*/
|
||||
static int anc_mult_coeff_check(anc_coeff_t *db_coeff, u16 len)
|
||||
{
|
||||
u32 coeff_len = 0;
|
||||
int i;
|
||||
|
||||
if ((db_coeff->version & 0xF0) != 0xA0) {
|
||||
return 1;
|
||||
}
|
||||
if (db_coeff->cnt > 5) { //理论上最大ID个数
|
||||
return 1;
|
||||
}
|
||||
|
||||
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)db_coeff->dat;
|
||||
struct anc_param_head_t coeff_head[file->cnt];
|
||||
|
||||
for (i = 0; i < file->cnt; i++) {
|
||||
memcpy(&coeff_head[i], file->dat + (i * 6), 6); //结构体为8字节,这里只有6字节
|
||||
if (coeff_len != coeff_head[i].offset) {
|
||||
return 1;
|
||||
}
|
||||
coeff_len += coeff_head[i].len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const static u8 anc_mult_part_id[8][2] = {
|
||||
{ANC_L_FF_PARM, ANC_L_FF_FGQ},
|
||||
{ANC_L_FB_PARM, ANC_L_FB_FGQ},
|
||||
{ANC_L_CMP_PARM, ANC_L_CMP_FGQ},
|
||||
{ANC_L_TRANS_PARM, ANC_L_TRANS_FGQ},
|
||||
|
||||
{ANC_R_FF_PARM, ANC_R_FF_FGQ},
|
||||
{ANC_R_FB_PARM, ANC_R_FB_FGQ},
|
||||
{ANC_R_CMP_PARM, ANC_R_CMP_FGQ},
|
||||
{ANC_R_TRANS_PARM, ANC_R_TRANS_FGQ}
|
||||
};
|
||||
|
||||
//部分数据文件-头部信息重组
|
||||
static void anc_mult_part_head_recombination(u16 *cnt, struct anc_param_head_t *id_head, anc_mult_param_t *p, anc_mult_param_t *new_p, u8 type)
|
||||
{
|
||||
u8 order = (new_p->fr) ? new_p->yorder : p->yorder;
|
||||
|
||||
if ((p->gains != NULL) || (new_p->gains != NULL)) {
|
||||
id_head[*cnt].id = anc_mult_part_id[type][0];
|
||||
id_head[*cnt].len = sizeof(anc_mult_gain_t);
|
||||
if (*cnt) {
|
||||
id_head[*cnt].offset = id_head[(*cnt) - 1].len + id_head[(*cnt) - 1].offset;
|
||||
}
|
||||
(*cnt)++;
|
||||
}
|
||||
if (order) {
|
||||
id_head[*cnt].id = anc_mult_part_id[type][1];
|
||||
id_head[*cnt].len = order * sizeof(anc_fr_t);
|
||||
if (*cnt) {
|
||||
id_head[*cnt].offset = id_head[(*cnt) - 1].len + id_head[(*cnt) - 1].offset;
|
||||
}
|
||||
(*cnt)++;
|
||||
}
|
||||
}
|
||||
|
||||
//部分数据文件-数据信息重组
|
||||
static void anc_mult_part_data_recombination(anc_mult_param_t *new_p, anc_mult_param_t *p, anc_mult_param_t *t_p, u8 type)
|
||||
{
|
||||
if (t_p->gains != NULL) {
|
||||
memcpy((u8 *)new_p->gains, (u8 *)t_p->gains, sizeof(anc_mult_gain_t));
|
||||
} else if (p->gains != NULL) {
|
||||
memcpy((u8 *)new_p->gains, (u8 *)p->gains, sizeof(anc_mult_gain_t));
|
||||
}
|
||||
if (t_p->fr != NULL) {
|
||||
memcpy((u8 *)new_p->fr, (u8 *)t_p->fr, t_p->yorder * sizeof(anc_fr_t));
|
||||
} else if (p->fr != NULL) {
|
||||
memcpy((u8 *)new_p->fr, (u8 *)p->fr, p->yorder * sizeof(anc_fr_t));
|
||||
}
|
||||
}
|
||||
|
||||
//部分数据文件-写,不支持新增场景
|
||||
static int anc_mult_part_coeff_write(anc_coeff_t *target_coeff, u16 len)
|
||||
{
|
||||
u16 head_cnt, i, new_id_flag;
|
||||
u16 scene_cnt = 0;
|
||||
int ret = 0;
|
||||
int new_len = sizeof(anc_coeff_t);
|
||||
anc_coeff_t *old_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, &mult_hdl->param->coeff_size);
|
||||
u8 *temp_dat;
|
||||
|
||||
anc_mult_bulk_t *new_bulk;
|
||||
anc_mult_bulk_t *target_bulk;
|
||||
anc_mult_bulk_t *old_bulk;
|
||||
anc_mult_bulk_t *t_bulk;
|
||||
|
||||
if ((old_coeff->version & 0xF0) != 0xA0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
anc_mult_scene_file_t *file[old_coeff->cnt];
|
||||
|
||||
//1、解析目标数据信息
|
||||
struct list_head target_list;
|
||||
INIT_LIST_HEAD(&target_list);
|
||||
|
||||
if ((target_coeff->version & 0xF0) != 0xA0) {
|
||||
return -1;
|
||||
}
|
||||
temp_dat = target_coeff->dat;
|
||||
for (i = 0; i < target_coeff->cnt; i++) {
|
||||
//temp_dat表示当前场景数据指针,以下函数会返回 下一个场景相对当前temp_dat的偏移量
|
||||
temp_dat += anc_mult_scene_param_read(&target_list, temp_dat);
|
||||
}
|
||||
|
||||
//检查是否属于新场景(目前不支持新加场景重组)
|
||||
list_for_each_entry(target_bulk, &target_list, entry) {
|
||||
new_id_flag = 1;
|
||||
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
|
||||
if (target_bulk->scene_id == old_bulk->scene_id) {
|
||||
new_id_flag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_id_flag) {
|
||||
ret = -2;
|
||||
goto __free2;
|
||||
}
|
||||
}
|
||||
|
||||
//2、重组新数据头信息
|
||||
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
|
||||
t_bulk = old_bulk;
|
||||
list_for_each_entry(target_bulk, &target_list, entry) {
|
||||
if (target_bulk->scene_id == old_bulk->scene_id) {
|
||||
t_bulk = target_bulk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
file[scene_cnt] = zalloc(sizeof(struct anc_param_head_t) * 16 + sizeof(anc_mult_scene_file_t));
|
||||
struct anc_param_head_t *id_head = (struct anc_param_head_t *)file[scene_cnt]->dat;
|
||||
head_cnt = 0;
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lff, &t_bulk->lff, 0);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lfb, &t_bulk->lfb, 1);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lcmp, &t_bulk->lcmp, 2);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->ltrans, &t_bulk->ltrans, 3);
|
||||
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rff, &t_bulk->rff, 4);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rfb, &t_bulk->rfb, 5);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rcmp, &t_bulk->rcmp, 6);
|
||||
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rtrans, &t_bulk->rtrans, 7);
|
||||
file[scene_cnt]->scene_id = old_bulk->scene_id;
|
||||
file[scene_cnt]->cnt = head_cnt;
|
||||
scene_cnt++;
|
||||
//file+id_head+data(len+offset)
|
||||
new_len += sizeof(anc_mult_scene_file_t) + (sizeof(struct anc_param_head_t) * head_cnt) + \
|
||||
id_head[head_cnt - 1].len + id_head[head_cnt - 1].offset;
|
||||
/* printf("last len%d, cnt%d, offset%d, len%d\n", new_len, head_cnt, id_head[head_cnt - 1].len, id_head[head_cnt - 1].offset); */
|
||||
}
|
||||
//重组后数据长度
|
||||
anc_mult_log("PART FILE new_file_len %d\n", new_len);
|
||||
|
||||
//3、申请新数据空间
|
||||
anc_coeff_t *new_coeff = (anc_coeff_t *)zalloc(new_len);
|
||||
struct list_head new_list;
|
||||
INIT_LIST_HEAD(&new_list);
|
||||
|
||||
int new_offset = 0;
|
||||
if (!new_coeff) {
|
||||
ret = -1;
|
||||
goto __free1;
|
||||
}
|
||||
memcpy((u8 *)new_coeff, (u8 *)old_coeff, sizeof(anc_coeff_t));
|
||||
temp_dat = new_coeff->dat;
|
||||
//4、拷贝数据头至新数据空间
|
||||
for (i = 0; i < new_coeff->cnt; i++) {
|
||||
memcpy(temp_dat, (u8 *)file[i], sizeof(anc_mult_scene_file_t));
|
||||
memcpy(temp_dat + sizeof(anc_mult_scene_file_t), file[i]->dat, \
|
||||
sizeof(struct anc_param_head_t) * file[i]->cnt);
|
||||
|
||||
/* put_buf((u8*)new_coeff, new_len); */
|
||||
new_offset = anc_mult_scene_param_read(&new_list, temp_dat);
|
||||
temp_dat += new_offset;
|
||||
}
|
||||
//5、重组新数据
|
||||
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
|
||||
t_bulk = old_bulk;
|
||||
list_for_each_entry(target_bulk, &target_list, entry) {
|
||||
if (target_bulk->scene_id == old_bulk->scene_id) {
|
||||
t_bulk = target_bulk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list_for_each_entry(new_bulk, &new_list, entry) {
|
||||
if (new_bulk->scene_id == old_bulk->scene_id) {
|
||||
anc_mult_part_data_recombination(&new_bulk->lff, &old_bulk->lff, &t_bulk->lff, 0);
|
||||
anc_mult_part_data_recombination(&new_bulk->lfb, &old_bulk->lfb, &t_bulk->lfb, 1);
|
||||
anc_mult_part_data_recombination(&new_bulk->lcmp, &old_bulk->lcmp, &t_bulk->lcmp, 2);
|
||||
anc_mult_part_data_recombination(&new_bulk->ltrans, &old_bulk->ltrans, &t_bulk->ltrans, 3);
|
||||
|
||||
anc_mult_part_data_recombination(&new_bulk->rff, &old_bulk->rff, &t_bulk->rff, 4);
|
||||
anc_mult_part_data_recombination(&new_bulk->rfb, &old_bulk->rfb, &t_bulk->rfb, 5);
|
||||
anc_mult_part_data_recombination(&new_bulk->rcmp, &old_bulk->rcmp, &t_bulk->rcmp, 6);
|
||||
anc_mult_part_data_recombination(&new_bulk->rtrans, &old_bulk->rtrans, &t_bulk->rtrans, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
//重组后数据内容
|
||||
/* put_buf((u8*)new_coeff, new_len); */
|
||||
|
||||
//6、写入flash
|
||||
mult_hdl->param->write_coeff_size = new_len; //更新滤波器长度
|
||||
ret = anc_db_put(mult_hdl->param, NULL, new_coeff);
|
||||
|
||||
//7、释放新数据链表、ram
|
||||
anc_mult_scene_list_del(&new_list);
|
||||
free(new_coeff);
|
||||
|
||||
__free1:
|
||||
//8、释放重组临时ram
|
||||
for (i = 0; i < old_coeff->cnt; i++) {
|
||||
free(file[i]);
|
||||
}
|
||||
__free2:
|
||||
//9、释放目标数据解析链表
|
||||
anc_mult_scene_list_del(&target_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//单独增益ID设置-兼容之前的命令
|
||||
void audio_anc_mult_gains_id_set(u8 gain_id, int data)
|
||||
{
|
||||
if (!mult_hdl) {
|
||||
return;
|
||||
}
|
||||
anc_mult_bulk_t *bulk;
|
||||
u8 *temp_dat;
|
||||
float fgain = *((float *)&data);
|
||||
int i;
|
||||
|
||||
struct list_head list;
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
||||
anc_coeff_t *db_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, &mult_hdl->param->coeff_size);
|
||||
|
||||
if ((db_coeff->version & 0xF0) != 0xA0) {
|
||||
return;
|
||||
}
|
||||
anc_coeff_t *coeff = malloc(mult_hdl->param->coeff_size);
|
||||
memcpy((u8 *)coeff, (u8 *)db_coeff, mult_hdl->param->coeff_size);
|
||||
|
||||
temp_dat = coeff->dat;
|
||||
for (i = 0; i < coeff->cnt; i++) {
|
||||
temp_dat += anc_mult_scene_param_read(&list, temp_dat);
|
||||
}
|
||||
list_for_each_entry(bulk, &list, entry) {
|
||||
if (bulk->scene_id == audio_anc_mult_scene_get()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (gain_id) {
|
||||
case ANC_FFGAIN_SET:
|
||||
if (bulk->lff.gains) {
|
||||
bulk->lff.gains->iir_gain = (bulk->lff.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_FBGAIN_SET:
|
||||
if (bulk->lfb.gains) {
|
||||
bulk->lfb.gains->iir_gain = (bulk->lfb.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_TRANS_GAIN_SET:
|
||||
if (bulk->ltrans.gains) {
|
||||
bulk->ltrans.gains->iir_gain = (bulk->ltrans.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_CMP_GAIN_SET:
|
||||
if (bulk->lcmp.gains) {
|
||||
bulk->lcmp.gains->iir_gain = (bulk->lcmp.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_RFF_GAIN_SET:
|
||||
if (bulk->rff.gains) {
|
||||
bulk->rff.gains->iir_gain = (bulk->rff.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_RFB_GAIN_SET:
|
||||
if (bulk->rfb.gains) {
|
||||
bulk->rfb.gains->iir_gain = (bulk->rfb.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_RTRANS_GAIN_SET:
|
||||
if (bulk->rtrans.gains) {
|
||||
bulk->rtrans.gains->iir_gain = (bulk->rtrans.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_RCMP_GAIN_SET:
|
||||
if (bulk->rcmp.gains) {
|
||||
bulk->rcmp.gains->iir_gain = (bulk->rcmp.gains->iir_gain > 0) ? fgain : 0 - fgain;
|
||||
}
|
||||
break;
|
||||
case ANC_GAIN_SIGN_SET:
|
||||
anc_mult_param_t *p;
|
||||
for (i = 0; i < 8; i++) {
|
||||
p = &bulk->lff + i;
|
||||
if (!p->gains) {
|
||||
continue;
|
||||
}
|
||||
if (((data & BIT(i)) && (p->gains->iir_gain > 0)) || \
|
||||
((!(data & BIT(i))) && (p->gains->iir_gain < 0))) {
|
||||
p->gains->iir_gain = 0 - p->gains->iir_gain;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
mult_hdl->param->write_coeff_size = mult_hdl->param->coeff_size;
|
||||
if (anc_db_put(mult_hdl->param, NULL, (anc_coeff_t *)coeff)) {
|
||||
anc_mult_log("anc_coeff_write err!");
|
||||
}
|
||||
audio_anc_mult_coeff_file_read();
|
||||
|
||||
free(coeff);
|
||||
}
|
||||
|
||||
//获取并解析flash anc_coeff.bin,实时更新参数效果
|
||||
int audio_anc_mult_coeff_file_read(void)
|
||||
{
|
||||
if (!mult_hdl) {
|
||||
return 1;
|
||||
}
|
||||
audio_anc_t *param = mult_hdl->param;
|
||||
//读flash
|
||||
anc_coeff_t *db_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, ¶m->coeff_size);
|
||||
anc_mult_log("anc_db coeff_size %d\n", param->coeff_size);
|
||||
//更新参数链表
|
||||
int ret = anc_mult_coeff_file_fill(db_coeff);
|
||||
|
||||
//更新效果
|
||||
if (param->mode != ANC_OFF) {
|
||||
/* g_printf("read cur scene_id %d\n",mult_hdl->cur_scene); */
|
||||
anc_mult_scene_set(mult_hdl->cur_scene);
|
||||
audio_anc_reset(param, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//anc_coeff.bin在线更新,支持全部数据文件写、部分数据文件写
|
||||
int audio_anc_mult_coeff_write(ANC_coeff_fill_t type, int *coeff, u16 len)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 single_type = 0;
|
||||
#if ANC_MULT_DATA_TEST == 2 //流程测试,确认重组数据正常
|
||||
int test_len;
|
||||
if (type == ANC_MULT_COEFF_FILL_PART) {
|
||||
coeff = (int *)anc_mult_cfg_part_test((int)&test_len);
|
||||
} else {
|
||||
coeff = (int *)anc_mult_cfg_test((int)&test_len);
|
||||
}
|
||||
len = test_len;
|
||||
mult_hdl->param->write_coeff_size = len;
|
||||
#endif/*ANC_MULT_DATA_TEST*/
|
||||
|
||||
anc_coeff_t *db_coeff = (anc_coeff_t *)coeff;
|
||||
|
||||
anc_coeff_t *tmp_coeff = NULL;
|
||||
if (!mult_hdl) {
|
||||
return -1;
|
||||
}
|
||||
anc_mult_log("anc_coeff_write:0x%x, len:%d", (u32)coeff, len);
|
||||
ret = anc_mult_coeff_check(db_coeff, len);
|
||||
if (ret) {
|
||||
r_printf("err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (type == ANC_MULT_COEFF_FILL_PART) {
|
||||
ret = anc_mult_part_coeff_write(db_coeff, len);
|
||||
} else if (type == ANC_MULT_COEFF_FILL_ALL) {
|
||||
ret = anc_db_put(mult_hdl->param, NULL, (anc_coeff_t *)coeff);
|
||||
}
|
||||
if (ret) {
|
||||
anc_mult_log("anc_coeff_write err:%d", ret);
|
||||
return -1;
|
||||
}
|
||||
ret = audio_anc_mult_coeff_file_read();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if ANC_MULT_DATA_TEST
|
||||
|
||||
static anc_coeff_t *anc_mult_cfg_test(int *db_len)
|
||||
{
|
||||
int i, j;
|
||||
int offset = 0;
|
||||
int len = 4 + 2 * (4 + 6 + 6) + 4 + 4 + 26 + 39;
|
||||
anc_coeff_t *db = (anc_coeff_t *)zalloc(len);
|
||||
anc_mult_log("test_db_len %d\n", len);
|
||||
db->version = ANC_VERSION_BR28_MULT;
|
||||
db->cnt = 2;
|
||||
u8 *scene_temp = db->dat;
|
||||
u8 *temp_dat;
|
||||
struct anc_param_head_t *id_head;
|
||||
anc_fr_t fr;
|
||||
anc_mult_gain_t *gain;
|
||||
|
||||
for (j = 0; j < db->cnt; j++) {
|
||||
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)scene_temp;
|
||||
|
||||
switch (j) {
|
||||
case 0:
|
||||
file->cnt = 2;
|
||||
file->scene_id = 1;
|
||||
temp_dat = file->dat + (file->cnt * 6);
|
||||
id_head = (struct anc_param_head_t *)file->dat;
|
||||
id_head[0].id = ANC_L_FF_PARM;
|
||||
id_head[0].offset = 0;
|
||||
id_head[0].len = 4;
|
||||
gain = (anc_mult_gain_t *)temp_dat;
|
||||
gain->iir_gain = 2.0f;
|
||||
|
||||
id_head[1].id = ANC_L_FF_FGQ;
|
||||
id_head[1].offset = 4;
|
||||
id_head[1].len = 26;
|
||||
fr.type = ANC_IIR_BAND_PASS;
|
||||
fr.a[0] = 500.0f;
|
||||
fr.a[1] = 10.0f;
|
||||
fr.a[2] = 3.0f;
|
||||
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
|
||||
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
|
||||
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[1].offset + id_head[1].len;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
file->cnt = 2;
|
||||
file->scene_id = 2;
|
||||
temp_dat = file->dat + (file->cnt * 6);
|
||||
id_head = (struct anc_param_head_t *)file->dat;
|
||||
id_head[0].id = ANC_L_FF_PARM;
|
||||
id_head[0].offset = 0;
|
||||
id_head[0].len = 4;
|
||||
gain = (anc_mult_gain_t *)temp_dat;
|
||||
gain->iir_gain = -3.0f;
|
||||
|
||||
id_head[1].id = ANC_L_FF_FGQ;
|
||||
id_head[1].offset = 4;
|
||||
id_head[1].len = 39;
|
||||
fr.type = ANC_IIR_BAND_PASS;
|
||||
fr.a[0] = 5000.0f;
|
||||
fr.a[1] = 10.0f;
|
||||
fr.a[2] = 3.0f;
|
||||
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
|
||||
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
|
||||
memcpy(temp_dat + id_head[1].offset + 26, (u8 *)&fr, 13);
|
||||
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[1].offset + id_head[1].len;
|
||||
break;
|
||||
}
|
||||
scene_temp += offset;
|
||||
}
|
||||
*db_len = len;
|
||||
put_buf((u8 *)db, *db_len);
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
anc_coeff_t *anc_mult_cfg_part_test(int *db_len)
|
||||
{
|
||||
int i, j;
|
||||
int offset = 0;
|
||||
/* int len = 4 + 2 * (4 + 6 ) + 4 + 4 + 26 + 39; */
|
||||
int len = 4 + 2 * (4 + 6) + 6 + 4 + 4 + 39;
|
||||
anc_coeff_t *db = (anc_coeff_t *)zalloc(len);
|
||||
anc_mult_log("test_db_len %d\n", len);
|
||||
db->version = ANC_VERSION_BR28_MULT;
|
||||
db->cnt = 2;
|
||||
u8 *scene_temp = db->dat;
|
||||
u8 *temp_dat;
|
||||
struct anc_param_head_t *id_head;
|
||||
anc_fr_t fr;
|
||||
anc_mult_gain_t *gain;
|
||||
|
||||
for (j = 0; j < db->cnt; j++) {
|
||||
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)scene_temp;
|
||||
|
||||
switch (j) {
|
||||
case 0:
|
||||
file->cnt = 1;
|
||||
file->scene_id = 1;
|
||||
temp_dat = file->dat + (file->cnt * 6);
|
||||
id_head = (struct anc_param_head_t *)file->dat;
|
||||
id_head[0].id = ANC_L_FF_PARM;
|
||||
id_head[0].offset = 0;
|
||||
id_head[0].len = 4;
|
||||
gain = (anc_mult_gain_t *)temp_dat;
|
||||
gain->iir_gain = 1.0f;
|
||||
|
||||
/* id_head[1].id = ANC_L_FF_FGQ; */
|
||||
/* id_head[1].offset = 4; */
|
||||
/* id_head[1].len = 26; */
|
||||
/* fr.type = ANC_IIR_BAND_PASS; */
|
||||
/* fr.a[0] = 500.0f; */
|
||||
/* fr.a[1] = 10.0f; */
|
||||
/* fr.a[2] = 3.0f; */
|
||||
/* memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13); */
|
||||
/* memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13); */
|
||||
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[0].offset + id_head[0].len;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
file->cnt = 2;
|
||||
file->scene_id = 2;
|
||||
temp_dat = file->dat + (file->cnt * 6);
|
||||
id_head = (struct anc_param_head_t *)file->dat;
|
||||
id_head[0].id = ANC_L_FF_PARM;
|
||||
id_head[0].offset = 0;
|
||||
id_head[0].len = 4;
|
||||
gain = (anc_mult_gain_t *)temp_dat;
|
||||
gain->iir_gain = 1.0f;
|
||||
|
||||
id_head[1].id = ANC_L_FF_FGQ;
|
||||
id_head[1].offset = 4;
|
||||
/* id_head[1].len = 39; */
|
||||
id_head[1].len = 26;
|
||||
fr.type = ANC_IIR_BAND_PASS;
|
||||
fr.a[0] = 1.0f;
|
||||
fr.a[1] = 1.0f;
|
||||
fr.a[2] = 1.0f;
|
||||
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
|
||||
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
|
||||
/* memcpy(temp_dat + id_head[1].offset + 26, (u8 *)&fr, 13); */
|
||||
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[0].offset + id_head[0].len;
|
||||
break;
|
||||
}
|
||||
scene_temp += offset;
|
||||
}
|
||||
*db_len = len;
|
||||
put_buf((u8 *)db, *db_len);
|
||||
return db;
|
||||
}
|
||||
|
||||
#endif/*ANC_MULT_DATA_TEST*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif/*ANC_MULT_ORDER_ENABLE*/
|
||||
27
cpu/br28/audio_anc_mult_scene.h
Normal file
27
cpu/br28/audio_anc_mult_scene.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef AUDIO_ANC_MULT_SCENE_H
|
||||
#define AUDIO_ANC_MULT_SCENE_H
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "asm/anc.h"
|
||||
|
||||
typedef enum {
|
||||
ANC_MULT_COEFF_FILL_ALL = 0, //滤波器全部填充
|
||||
ANC_MULT_COEFF_FILL_PART, //滤波器部分填充
|
||||
} ANC_coeff_fill_t;
|
||||
|
||||
int audio_anc_mult_coeff_file_read(void);
|
||||
|
||||
void anc_mult_init(audio_anc_t *param);
|
||||
|
||||
int anc_mult_scene_set(u16 scene_id);
|
||||
|
||||
int audio_anc_mult_coeff_write(ANC_coeff_fill_t type, int *coeff, u16 len);
|
||||
|
||||
void audio_anc_mult_scene_coeff_free(void);
|
||||
|
||||
void audio_anc_mult_gains_id_set(u8 gain_id, int data);
|
||||
|
||||
int audio_anc_mult_scene_id_check(u16 scene_id);
|
||||
|
||||
#endif/*AUDIO_ANC_MULT_SCENE_H*/
|
||||
1080
cpu/br28/audio_capture.c
Normal file
1080
cpu/br28/audio_capture.c
Normal file
File diff suppressed because it is too large
Load Diff
9
cpu/br28/audio_capture.h
Normal file
9
cpu/br28/audio_capture.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef _AUDIO_CAPTURE_H_
|
||||
#define _AUDIO_CAPTURE_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
int audio_capture_init(void);
|
||||
int audio_capture_exit(void);
|
||||
|
||||
#endif/*_AUDIO_CAPTURE_H_*/
|
||||
374
cpu/br28/audio_codec_clock.c
Normal file
374
cpu/br28/audio_codec_clock.c
Normal file
@ -0,0 +1,374 @@
|
||||
/*****************************************************************
|
||||
>file name : audio_codec_clock.c
|
||||
>create time : Thu 03 Jun 2021 09:36:12 AM CST
|
||||
>History :
|
||||
2021-11-19 : 增加后台叠加时钟的配置,用于满足一些后台运行的
|
||||
音频处理
|
||||
*****************************************************************/
|
||||
#define LOG_TAG "[CODEC_CLK]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_DUMP_ENABLE
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_WARN_ENABLE
|
||||
#include "debug.h"
|
||||
#include "app_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "audio_dec_eff.h"
|
||||
#include "asm/dac.h"
|
||||
#include "avctp_user.h"
|
||||
|
||||
#define AUDIO_CODING_ALL (0xffffffff)
|
||||
#define MAX_CODING_TYPE_NUM 4 //可根据模式的解码格式需求扩展
|
||||
#define AUDIO_CODEC_BASE_CLK SYS_24M
|
||||
|
||||
static LIST_HEAD(codec_clock_head);
|
||||
|
||||
struct audio_codec_clock {
|
||||
u32 coding_type;
|
||||
u32 clk;
|
||||
u8 background; //后台运行的时钟
|
||||
};
|
||||
|
||||
struct audio_codec_clk_context {
|
||||
u8 mode;
|
||||
struct audio_codec_clock params;
|
||||
struct list_head entry;
|
||||
};
|
||||
|
||||
#define SYS_60M SYS_64M
|
||||
const struct audio_codec_clock audio_clock[AUDIO_MAX_MODE][MAX_CODING_TYPE_NUM] = {
|
||||
{
|
||||
//A2DP_MODE
|
||||
{
|
||||
AUDIO_CODING_SBC,
|
||||
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
|
||||
SYS_76M,
|
||||
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)) || (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
|
||||
SYS_76M,
|
||||
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) && AUDIO_OUT_EFFECT_ENABLE)) || (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG)
|
||||
SYS_60M,
|
||||
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE) || TCFG_DRC_ENABLE || TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
SYS_48M,
|
||||
#else
|
||||
SYS_32M,
|
||||
#endif
|
||||
},
|
||||
{
|
||||
AUDIO_CODING_AAC,
|
||||
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
SYS_96M,
|
||||
#else
|
||||
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || AUDIO_VBASS_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
|
||||
SYS_76M,
|
||||
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
|
||||
SYS_64M,
|
||||
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) || AUDIO_SURROUND_CONFIG || TCFG_DRC_ENABLE
|
||||
#if (TCFG_AUDIO_ANC_ENABLE)
|
||||
SYS_64M,
|
||||
#else
|
||||
SYS_60M,
|
||||
#endif /*TCFG_AUDIO_ANC_ENABLE*/
|
||||
#else
|
||||
SYS_48M,
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
{
|
||||
AUDIO_CODING_LDAC,
|
||||
#if (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
|
||||
SYS_128M,
|
||||
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) | (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG) || TCFG_DRC_ENABLE
|
||||
#if (TCFG_AUDIO_ANC_ENABLE)
|
||||
SYS_128M,
|
||||
#else
|
||||
SYS_128M,
|
||||
#endif /*TCFG_AUDIO_ANC_ENABLE*/
|
||||
#else
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
SYS_128M,
|
||||
#else
|
||||
SYS_128M,
|
||||
#endif /*TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR*/
|
||||
#endif
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
//ESCO MODE
|
||||
{
|
||||
AUDIO_CODING_MSBC,
|
||||
#if TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR
|
||||
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
|
||||
SYS_76M,
|
||||
#else /*TCFG_AUDIO_CVP_NS_MODE == CVP_DNS_MODE*/
|
||||
SYS_96M,
|
||||
#endif /*TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE*/
|
||||
#else
|
||||
/* SYS_48M, */
|
||||
0,
|
||||
#endif
|
||||
},
|
||||
{AUDIO_CODING_CVSD, 0},
|
||||
},
|
||||
|
||||
{
|
||||
//TONE MODE
|
||||
{AUDIO_CODING_AAC | AUDIO_CODING_WAV | AUDIO_CODING_WTGV2 | AUDIO_CODING_MP3, SYS_64M},
|
||||
{AUDIO_CODING_ALL, 0},
|
||||
},
|
||||
|
||||
{
|
||||
//FILE MODE
|
||||
{AUDIO_CODING_ALL, 120 * 1000000L},
|
||||
},
|
||||
|
||||
{
|
||||
//PC MODE
|
||||
{AUDIO_CODING_ALL, 96 * 1000000L},
|
||||
},
|
||||
|
||||
{
|
||||
//USB MIC MODE
|
||||
#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
|
||||
{AUDIO_CODING_ALL, 128 * 1000000L},
|
||||
#else
|
||||
{AUDIO_CODING_ALL, 96 * 1000000L},
|
||||
#endif
|
||||
},
|
||||
|
||||
{
|
||||
//VAD MODE
|
||||
{AUDIO_CODING_ALL, SYS_32M, 1},
|
||||
},
|
||||
|
||||
{
|
||||
//SPATIAL EFFECT MODE
|
||||
#if ((defined TCFG_AUDIO_EFFECT_TASK_EBABLE) && TCFG_AUDIO_EFFECT_TASK_EBABLE)
|
||||
{AUDIO_CODING_ALL, SYS_32M, 1},
|
||||
#else
|
||||
{AUDIO_CODING_ALL, SYS_120M, 1},
|
||||
#endif /*TCFG_AUDIO_EFFECT_TASK_EBABLE*/
|
||||
},
|
||||
{
|
||||
// SPEAK_TO_CHAT_MODE
|
||||
{AUDIO_CODING_ALL, 48 * 1000000L}
|
||||
},
|
||||
|
||||
{
|
||||
// ANC_EAR_ADAPTIVE_MODE
|
||||
{AUDIO_CODING_ALL, SYS_160M, 0}
|
||||
},
|
||||
|
||||
{
|
||||
// ANC_DUT_SZ_FFT_MODE
|
||||
{AUDIO_CODING_ALL, SYS_120M, 0}
|
||||
},
|
||||
//TODO
|
||||
};
|
||||
|
||||
static u32 audio_codec_background_clock(void)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
u32 clk = 0;
|
||||
|
||||
if (list_empty(&codec_clock_head)) {
|
||||
return 0;
|
||||
}
|
||||
list_for_each_entry(ctx, &codec_clock_head, entry) {
|
||||
if (ctx->params.background) {
|
||||
clk += ctx->params.clk;
|
||||
}
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void audio_codec_background_clock_add(u32 clk)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
|
||||
if (list_empty(&codec_clock_head)) {
|
||||
return;
|
||||
}
|
||||
list_for_each_entry(ctx, &codec_clock_head, entry) {
|
||||
ctx->params.clk += clk;
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_codec_background_clock_del(u32 clk)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
|
||||
if (list_empty(&codec_clock_head)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_for_each_entry(ctx, &codec_clock_head, entry) {
|
||||
ctx->params.clk -= clk;
|
||||
}
|
||||
}
|
||||
|
||||
static bool audio_codec_mode_exist(u8 mode)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
|
||||
if (list_empty(&codec_clock_head)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list_for_each_entry(ctx, &codec_clock_head, entry) {
|
||||
if (ctx->mode == mode) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption)
|
||||
{
|
||||
u32 new_clk = 0;
|
||||
u32 background_clk = 0;
|
||||
|
||||
if (mode >= AUDIO_MAX_MODE) {
|
||||
log_error("Not support this mode : %d", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (audio_codec_mode_exist(mode)) {
|
||||
return 0;
|
||||
}
|
||||
const struct audio_codec_clock *params = audio_clock[mode];
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_CODING_TYPE_NUM; i++) {
|
||||
if (params[i].coding_type & coding_type) {
|
||||
goto match_clock;
|
||||
}
|
||||
}
|
||||
|
||||
log_error("Not found right coding type : %d", coding_type);
|
||||
return -EINVAL;
|
||||
|
||||
match_clock:
|
||||
if (params[i].background) {
|
||||
/*如果是后台运行的,则需要处理最终时钟为前台+后台时钟总和*/
|
||||
audio_codec_background_clock_add(params[i].clk);
|
||||
new_clk = params[i].clk;
|
||||
struct audio_codec_clk_context *first = list_empty(&codec_clock_head) ? NULL : list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
|
||||
if (first) {
|
||||
new_clk = first->params.clk;
|
||||
} else {
|
||||
/*后台运行时钟比较接近负载极限,容易导致其他跑不过来,因此多加12M*/
|
||||
new_clk += 12 * 1000000L;
|
||||
}
|
||||
goto clock_set;
|
||||
}
|
||||
|
||||
background_clk = audio_codec_background_clock();
|
||||
new_clk = (params[i].clk ? params[i].clk : clk_get("sys")) + background_clk;
|
||||
if (!preemption) {
|
||||
struct audio_codec_clk_context *ctx1;
|
||||
if (!list_empty(&codec_clock_head)) {
|
||||
ctx1 = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
|
||||
if (ctx1 && !ctx1->params.background) {
|
||||
if (new_clk <= ctx1->params.clk) {
|
||||
/*叠加解码的时钟不可小于在播放的音频时钟*/
|
||||
new_clk = ctx1->params.clk + 12 * 1000000;
|
||||
} else {
|
||||
new_clk += 32 * 1000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clock_set:
|
||||
struct audio_codec_clk_context *ctx = (struct audio_codec_clk_context *)zalloc(sizeof(struct audio_codec_clk_context));
|
||||
ctx->mode = mode;
|
||||
ctx->params.coding_type = coding_type;
|
||||
ctx->params.background = params[i].background;
|
||||
ctx->params.clk = ctx->params.background ? params[i].clk : new_clk;
|
||||
clk_set("sys", new_clk);
|
||||
if (ctx->params.background) {
|
||||
list_add_tail(&ctx->entry, &codec_clock_head);
|
||||
} else {
|
||||
list_add(&ctx->entry, &codec_clock_head);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_codec_clock_del(u8 mode)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
int next_clk = 0;
|
||||
u32 remove_clk = 0;
|
||||
|
||||
list_for_each_entry(ctx, &codec_clock_head, entry) {
|
||||
if (ctx->mode == mode) {
|
||||
goto clock_del;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
clock_del:
|
||||
list_del(&ctx->entry);
|
||||
if (ctx->params.background) {
|
||||
audio_codec_background_clock_del(ctx->params.clk);
|
||||
remove_clk = ctx->params.clk;
|
||||
}
|
||||
free(ctx);
|
||||
|
||||
if (!list_empty(&codec_clock_head)) {
|
||||
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
|
||||
if (ctx) {
|
||||
next_clk = ctx->params.clk;
|
||||
}
|
||||
} else {
|
||||
u32 current_clk = clk_get("sys");
|
||||
#if (TCFG_BD_NUM == 2)&&(TCFG_BT_SUPPORT_AAC==1)
|
||||
if ((mode == AUDIO_A2DP_MODE) && (get_total_connect_dev() > 1)) {
|
||||
next_clk = current_clk - remove_clk;
|
||||
} else {
|
||||
if (remove_clk) {
|
||||
next_clk = current_clk - remove_clk;
|
||||
} else {
|
||||
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (remove_clk) {
|
||||
next_clk = current_clk - remove_clk;
|
||||
} else {
|
||||
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!next_clk || next_clk < AUDIO_CODEC_BASE_CLK) {
|
||||
next_clk = list_empty(&codec_clock_head) ? clk_get("sys") : AUDIO_CODEC_BASE_CLK;
|
||||
}
|
||||
clk_set("sys", next_clk);
|
||||
}
|
||||
|
||||
void audio_codec_clock_check(void)
|
||||
{
|
||||
struct audio_codec_clk_context *ctx;
|
||||
|
||||
if (!list_empty(&codec_clock_head)) {
|
||||
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 current_clk = clk_get("sys");
|
||||
u32 expect_clk = ctx->params.background ? (ctx->params.clk + 12 * 1000000L) : ctx->params.clk;
|
||||
if ((current_clk < 192 * 1000000L) && current_clk < expect_clk) {
|
||||
log_error("Audio codec clock error : %dM, %dM.", current_clk / 1000000, expect_clk / 1000000);
|
||||
clk_set("sys", expect_clk);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
cpu/br28/audio_codec_clock.h
Normal file
55
cpu/br28/audio_codec_clock.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*****************************************************************
|
||||
>file name : audio_codec_clock.h
|
||||
>create time : Thu 03 Jun 2021 09:36:25 AM CST
|
||||
*****************************************************************/
|
||||
#ifndef _AUDIO_CODEC_CLOCK_H_
|
||||
#define _AUDIO_CODEC_CLOCK_H_
|
||||
#include "audio_base.h"
|
||||
|
||||
enum {
|
||||
AUDIO_A2DP_MODE = 0,
|
||||
AUDIO_ESCO_MODE,
|
||||
AUDIO_TONE_MODE,
|
||||
AUDIO_FILE_MODE,
|
||||
AUDIO_PC_MODE,
|
||||
AUDIO_USB_MIC_MODE,
|
||||
SMART_VOICE_MODE,
|
||||
SPATIAL_EFFECT_MODE,
|
||||
SPEAK_TO_CHAT_MODE,
|
||||
ANC_EAR_ADAPTIVE_MODE,
|
||||
ANC_DUT_SZ_FFT_MODE,
|
||||
AUDIO_MAX_MODE,
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* 音频编解码时钟设置
|
||||
*
|
||||
* Input : mode - 音频模式,coding_type - 模式下的解码格式
|
||||
* preemption - 打断/叠加.
|
||||
* Output : 0 - 成功, 非0 - 出错.
|
||||
* Notes : 目前在耳机SDK用于A2DP/ESCO/TONE三个模式的时钟切换.
|
||||
* History : 2021/06/03 初始版本
|
||||
*=======================================================================*/
|
||||
int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption);
|
||||
|
||||
/*************************************************************************
|
||||
* 音频编解码时钟删除
|
||||
*
|
||||
* Input : mode - 音频模式
|
||||
* Output : 无.
|
||||
* Notes : 需和audio_codec_clock_set结对使用.
|
||||
* History : 2021/06/03 初始版本
|
||||
*=======================================================================*/
|
||||
void audio_codec_clock_del(u8 mode);
|
||||
|
||||
/*************************************************************************
|
||||
* 音频编解码时钟检查
|
||||
*
|
||||
* Input : 无
|
||||
* Output : 无.
|
||||
* Notes : 检查音频使用中是否有时钟被修改的情况并报错
|
||||
* History : 2021/11/18
|
||||
*=======================================================================*/
|
||||
void audio_codec_clock_check(void);
|
||||
#endif
|
||||
304
cpu/br28/audio_common/audio_mic_codec.c
Normal file
304
cpu/br28/audio_common/audio_mic_codec.c
Normal file
@ -0,0 +1,304 @@
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "classic/hci_lmp.h"
|
||||
#include "aec_user.h"
|
||||
#include "asm/audio_src.h"
|
||||
#include "audio_enc.h"
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
#include "audio_anc.h"
|
||||
#endif
|
||||
#include "app_main.h"
|
||||
#include "btstack/avctp_user.h"
|
||||
|
||||
#if 1//(TCFG_ENC_OPUS_ENABLE) || (TCFG_ENC_SPEEX_ENABLE)
|
||||
|
||||
extern struct audio_encoder_task *encode_task;
|
||||
//static struct audio_encoder_task *encode_task = NULL;
|
||||
|
||||
#define ENC_ADC_BUF_NUM (2)
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
//JL701N打开ANC,ADC需要使用相同buffer和中断点数
|
||||
#define ENC_ADC_IRQ_POINTS (256)
|
||||
#else
|
||||
#define ENC_ADC_IRQ_POINTS (320)
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
#define ENC_ADC_BUFS_SIZE (ENC_ADC_BUF_NUM * ENC_ADC_IRQ_POINTS)
|
||||
|
||||
#define MIC_USE_MIC_CHANNEL (1)
|
||||
#define MIC_ENC_IN_SIZE (ENC_ADC_IRQ_POINTS * 2)
|
||||
#define MIC_ENC_OUT_SIZE (ENC_ADC_IRQ_POINTS)
|
||||
|
||||
struct mic_enc_hdl {
|
||||
struct audio_encoder encoder;
|
||||
OS_SEM pcm_frame_sem;
|
||||
u8 output_frame[MIC_ENC_OUT_SIZE];
|
||||
u8 pcm_frame[MIC_ENC_IN_SIZE];
|
||||
u8 frame_size;
|
||||
u8 in_cbuf_buf[MIC_ENC_IN_SIZE * 4];
|
||||
cbuffer_t pcm_in_cbuf;
|
||||
int (*mic_output)(void *priv, void *buf, int len);
|
||||
#if mic_ENC_PACK_ENABLE
|
||||
u16 cp_type;
|
||||
u16 packet_head_sn;
|
||||
#endif
|
||||
#if MIC_USE_MIC_CHANNEL
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
struct adc_mic_ch mic_ch;
|
||||
s16 adc_buf[ENC_ADC_BUFS_SIZE]; //align 4Bytes
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct mic_enc_hdl *mic_enc = NULL;
|
||||
|
||||
static void mic_enc_output_func_register(int (*output_func)(void *priv, void *buf, int len))
|
||||
{
|
||||
if (mic_enc) {
|
||||
mic_enc->mic_output = output_func;
|
||||
}
|
||||
}
|
||||
|
||||
void mic_enc_resume(void)
|
||||
{
|
||||
if (mic_enc) {
|
||||
os_sem_post(&mic_enc->pcm_frame_sem);
|
||||
}
|
||||
}
|
||||
|
||||
static int mic_enc_pcm_get(struct audio_encoder *encoder, s16 **frame, u16 frame_len)
|
||||
{
|
||||
int pcm_len = 0;
|
||||
if (mic_enc == NULL) {
|
||||
r_printf("mic_enc NULL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* putchar('!'); */
|
||||
if ((&mic_enc->pcm_in_cbuf)->data_len < frame_len) {
|
||||
/* putchar('#'); */
|
||||
os_sem_set(&mic_enc->pcm_frame_sem, 0);
|
||||
os_sem_pend(&mic_enc->pcm_frame_sem, 5);
|
||||
if (mic_enc == NULL) {
|
||||
printf("mic_enc is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
pcm_len = cbuf_read(&mic_enc->pcm_in_cbuf, mic_enc->pcm_frame, frame_len);
|
||||
if (pcm_len != frame_len) {
|
||||
putchar('L');
|
||||
}
|
||||
/* putchar('D'); */
|
||||
|
||||
*frame = mic_enc->pcm_frame;
|
||||
return pcm_len;
|
||||
}
|
||||
|
||||
static void mic_enc_pcm_put(struct audio_encoder *encoder, s16 *frame)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct audio_enc_input mic_enc_input = {
|
||||
.fget = mic_enc_pcm_get,
|
||||
.fput = mic_enc_pcm_put,
|
||||
};
|
||||
|
||||
static int mic_enc_probe_handler(struct audio_encoder *encoder)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int mic_enc_output_handler(struct audio_encoder *encoder, u8 *frame, int len)
|
||||
{
|
||||
if (encoder == NULL) {
|
||||
r_printf("encoder NULL");
|
||||
}
|
||||
wdt_clear();
|
||||
/* printf("mic frame len:%d \n",len); */
|
||||
if (mic_enc && mic_enc->mic_output) {
|
||||
mic_enc->mic_output(NULL, frame, len);
|
||||
}
|
||||
/* put_buf(frame, 16); */
|
||||
return len;
|
||||
}
|
||||
|
||||
const static struct audio_enc_handler mic_enc_handler = {
|
||||
.enc_probe = mic_enc_probe_handler,
|
||||
.enc_output = mic_enc_output_handler,
|
||||
};
|
||||
|
||||
static void mic_enc_event_handler(struct audio_decoder *decoder, int argc, int *argv)
|
||||
{
|
||||
printf("mic_enc_event_handler:0x%x,%d\n", argv[0], argv[0]);
|
||||
switch (argv[0]) {
|
||||
case AUDIO_ENC_EVENT_END:
|
||||
puts("AUDIO_ENC_EVENT_END\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void adc_mic_output_handler(void *priv, s16 *data, int len)
|
||||
{
|
||||
if (mic_enc) {
|
||||
u16 wlen = cbuf_write(&mic_enc->pcm_in_cbuf, data, len);
|
||||
if (wlen != len) {
|
||||
putchar('@');
|
||||
}
|
||||
audio_encoder_resume(&mic_enc->encoder);
|
||||
mic_enc_resume();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define HIGHT_COMPLEX 0
|
||||
#define LOW_COMPLEX (BIT(4))
|
||||
|
||||
|
||||
extern struct audio_adc_hdl adc_hdl;
|
||||
int audio_mic_enc_open(int (*mic_output)(void *priv, void *buf, int len), u32 code_type, u8 ai_type)
|
||||
{
|
||||
int err;
|
||||
struct audio_fmt fmt;
|
||||
|
||||
switch (code_type) {
|
||||
case AUDIO_CODING_OPUS:
|
||||
//1. quality:bitrate 0:16kbps 1:32kbps 2:64kbps
|
||||
// quality: MSB_2:(bit7_bit6) format_mode //0:百度_无头. 1:酷狗_eng+range.
|
||||
// quality:LMSB_2:(bit5_bit4) low_complexity //0:高复杂度,高质量.兼容之前库. 1:低复杂度,低质量.
|
||||
//2. sample_rate sample_rate=16k ignore
|
||||
fmt.quality = 0 | ai_type/*| LOW_COMPLEX*/;
|
||||
fmt.sample_rate = 16000;
|
||||
fmt.coding_type = AUDIO_CODING_OPUS;
|
||||
break;
|
||||
case AUDIO_CODING_SPEEX:
|
||||
fmt.quality = 5;
|
||||
fmt.complexity = 2;
|
||||
fmt.sample_rate = 16000;
|
||||
fmt.coding_type = AUDIO_CODING_SPEEX;
|
||||
break;
|
||||
default:
|
||||
printf("do not support this type !!!\n");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!encode_task) {
|
||||
encode_task = zalloc(sizeof(*encode_task));
|
||||
if (!encode_task) {
|
||||
printf("encode_task NULL !!!\n");
|
||||
}
|
||||
audio_encoder_task_create(encode_task, "audio_enc");
|
||||
}
|
||||
if (!mic_enc) {
|
||||
mic_enc = zalloc(sizeof(*mic_enc));
|
||||
if (!mic_enc) {
|
||||
printf("mic_enc NULL !!!\n");
|
||||
}
|
||||
memset(mic_enc, 0x00, sizeof(*mic_enc));
|
||||
}
|
||||
|
||||
mic_enc_output_func_register(mic_output);
|
||||
cbuf_init(&mic_enc->pcm_in_cbuf, mic_enc->in_cbuf_buf, MIC_ENC_IN_SIZE * 4);
|
||||
os_sem_create(&mic_enc->pcm_frame_sem, 0);
|
||||
audio_encoder_open(&mic_enc->encoder, &mic_enc_input, encode_task);
|
||||
audio_encoder_set_handler(&mic_enc->encoder, &mic_enc_handler);
|
||||
audio_encoder_set_fmt(&mic_enc->encoder, &fmt);
|
||||
audio_encoder_set_event_handler(&mic_enc->encoder, mic_enc_event_handler, 0);
|
||||
audio_encoder_set_output_buffs(&mic_enc->encoder, mic_enc->output_frame,
|
||||
sizeof(mic_enc->output_frame), 1);
|
||||
if (!mic_enc->encoder.enc_priv) {
|
||||
log_e("encoder err, maybe coding(0x%x) disable \n", fmt.coding_type);
|
||||
err = -EINVAL;
|
||||
goto __err;
|
||||
}
|
||||
|
||||
int start_err = audio_encoder_start(&mic_enc->encoder);
|
||||
|
||||
#if MIC_USE_MIC_CHANNEL
|
||||
fmt.sample_rate = 16000;
|
||||
audio_mic_pwr_ctl(MIC_PWR_ON);
|
||||
audio_adc_mic_open(&mic_enc->mic_ch, BIT(0), &adc_hdl);
|
||||
audio_adc_mic_set_sample_rate(&mic_enc->mic_ch, fmt.sample_rate);
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
app_var.aec_mic_gain = audio_anc_ffmic_gain_get();
|
||||
#endif
|
||||
printf(">>>>>>>>>mic gain:%d \n", app_var.aec_mic_gain);
|
||||
audio_adc_mic_set_gain(&mic_enc->mic_ch, app_var.aec_mic_gain);
|
||||
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
//JL701N打开ANC,ADC需要使用相同buffer和中断点数
|
||||
extern s16 esco_adc_buf[];
|
||||
audio_adc_mic_set_buffs(&mic_enc->mic_ch, esco_adc_buf,
|
||||
ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
|
||||
#else
|
||||
audio_adc_mic_set_buffs(&mic_enc->mic_ch, mic_enc->adc_buf,
|
||||
ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
mic_enc->adc_output.handler = adc_mic_output_handler;
|
||||
audio_adc_add_output_handler(&adc_hdl, &mic_enc->adc_output);
|
||||
|
||||
|
||||
//app_audio_output_samplerate_set(44100);
|
||||
//app_audio_output_start();
|
||||
audio_adc_mic_start(&mic_enc->mic_ch);
|
||||
#endif
|
||||
|
||||
printf("mic_enc_open ok %d\n", start_err);
|
||||
|
||||
|
||||
return 0;
|
||||
__err:
|
||||
audio_encoder_close(&mic_enc->encoder);
|
||||
|
||||
local_irq_disable();
|
||||
free(mic_enc);
|
||||
mic_enc = NULL;
|
||||
local_irq_enable();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int audio_mic_enc_close()
|
||||
{
|
||||
if (!mic_enc) {
|
||||
return -1;
|
||||
}
|
||||
printf("audio_mic_enc_close\n");
|
||||
#if MIC_USE_MIC_CHANNEL
|
||||
audio_adc_mic_close(&mic_enc->mic_ch);
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
if (anc_status_get() == 0) {
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
}
|
||||
#else
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
#endif
|
||||
audio_adc_del_output_handler(&adc_hdl, &mic_enc->adc_output);
|
||||
#endif
|
||||
mic_enc_resume();
|
||||
audio_encoder_close(&mic_enc->encoder);
|
||||
|
||||
/* if (encode_task) { */
|
||||
/* audio_encoder_task_del(encode_task); */
|
||||
/* free(encode_task); */
|
||||
/* encode_task = NULL; */
|
||||
/* } */
|
||||
|
||||
free(mic_enc);
|
||||
mic_enc = NULL;
|
||||
|
||||
printf("audio_mic_enc_close end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
208
cpu/br28/audio_config.h
Normal file
208
cpu/br28/audio_config.h
Normal file
@ -0,0 +1,208 @@
|
||||
#ifndef _APP_AUDIO_H_
|
||||
#define _APP_AUDIO_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "board_config.h"
|
||||
|
||||
#if BT_SUPPORT_MUSIC_VOL_SYNC
|
||||
#define TCFG_MAX_VOL_PROMPT 0
|
||||
#else
|
||||
#define TCFG_MAX_VOL_PROMPT 1
|
||||
#endif
|
||||
|
||||
//*********************************************************************************//
|
||||
// USB Audio配置 //
|
||||
//*********************************************************************************//
|
||||
/*usb mic的数据是否经过CVP,包括里面的回音消除(AEC)、非线性回音压制(NLP)、降噪(ANS)模块*/
|
||||
#define TCFG_USB_MIC_CVP_ENABLE DISABLE_THIS_MOUDLE
|
||||
#define TCFG_USB_MIC_CVP_MODE (ANS_EN | NLP_EN)
|
||||
|
||||
//*********************************************************************************//
|
||||
// CVP配置 //
|
||||
//*********************************************************************************//
|
||||
//麦克风阵列校准使能
|
||||
#define TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE 0
|
||||
|
||||
//上行同步使能
|
||||
#define TCFG_AUDIO_CVP_SYNC 0
|
||||
|
||||
/*
|
||||
*该配置适用于没有音量按键的产品,防止打开音量同步之后
|
||||
*连接支持音量同步的设备,将音量调小过后,连接不支持音
|
||||
*量同步的设备,音量没有恢复,导致音量小的问题
|
||||
*/
|
||||
#define TCFG_VOL_RESET_WHEN_NO_SUPPORT_VOL_SYNC 0 //不支持音量同步的设备默认最大音量
|
||||
|
||||
#define MC_BIAS_ADJUST_DISABLE 0 //省电容mic偏置校准关闭
|
||||
#define MC_BIAS_ADJUST_ONE 1 //省电容mic偏置只校准一次(跟dac trim一样)
|
||||
#define MC_BIAS_ADJUST_POWER_ON 2 //省电容mic偏置每次上电复位都校准(Power_On_Reset)
|
||||
#define MC_BIAS_ADJUST_ALWAYS 3 //省电容mic偏置每次开机都校准(包括上电复位和其他复位)
|
||||
/*
|
||||
*省电容mic偏置电压自动调整(因为校准需要时间,所以有不同的方式)
|
||||
*1、烧完程序(完全更新,包括配置区)开机校准一次
|
||||
*2、上电复位的时候都校准,即断电重新上电就会校准是否有偏差(默认)
|
||||
*3、每次开机都校准,不管有没有断过电,即校准流程每次都跑
|
||||
*/
|
||||
#define TCFG_MC_BIAS_AUTO_ADJUST MC_BIAS_ADJUST_DISABLE
|
||||
|
||||
#define TCFG_ESCO_PLC 1 //通话丢包修复
|
||||
#define TCFG_AEC_ENABLE 1 //通话回音消除使能
|
||||
#define TCFG_AUDIO_CONFIG_TRACE 0 //音频模块配置跟踪查看
|
||||
#define TCFG_DIG_PHASE_INVERTER_EN 0 //数字反相器,用来矫正DAC的输出相位(AC701N输出正相,默认关)
|
||||
|
||||
|
||||
#define MAX_ANA_VOL (3) //系统最大模拟音量 (0-3)
|
||||
#define MAX_COM_VOL (16) // 具体数值应小于联合音量等级的数组大小 (combined_vol_list)
|
||||
#define MAX_DIG_VOL (16)
|
||||
|
||||
/*
|
||||
数字音量等级表生成参数(软件数字音量和硬件数字音量共用两个参数)
|
||||
修改 DIG_VOL_MAX_VALUE 也要留意一下 DIG_VOL_STEP 参数,避免在小音量等级时候音量太小。
|
||||
*/
|
||||
#if TCFG_AUDIO_HEARING_AID_ENABLE
|
||||
#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
|
||||
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_L_DIFF)
|
||||
#define DIG_VOL_MAX_VALUE (-5.0f) // 数字音量最大值(单位:dB)
|
||||
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF)
|
||||
#define DIG_VOL_MAX_VALUE (-8.0f) // 数字音量最大值(单位:dB)
|
||||
#else
|
||||
#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
|
||||
#endif
|
||||
#define DIG_VOL_STEP (3.0f) // 逐级递减差值(单位:dB)
|
||||
|
||||
/*
|
||||
*ANC下,当数字音量大于-6dB时,会导致播歌失真,以下任意一种方式都可解决, SDK默认第一种
|
||||
*1、数字音量限制在-6dB以下
|
||||
*2、开启音乐动态增益ANC_MUSIC_DYNAMIC_GAIN_EN
|
||||
*/
|
||||
#if (TCFG_AUDIO_ANC_ENABLE)
|
||||
#define ANC_MODE_DIG_VOL_LIMIT (-6.0f)
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
|
||||
/*
|
||||
*软件数字音量表自定义
|
||||
* 0:使用软件数字音量文件中的默认数组
|
||||
* 1:按上面设置的参数重新生成
|
||||
*/
|
||||
#define SW_DIG_VOL_TAB_USER_DEFINED 0
|
||||
|
||||
#if ((SYS_VOL_TYPE == VOL_TYPE_DIGITAL) || (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW))
|
||||
#define SYS_MAX_VOL MAX_DIG_VOL
|
||||
#define SYS_DEFAULT_VOL 0//SYS_MAX_VOL
|
||||
#define SYS_DEFAULT_TONE_VOL 8
|
||||
#define SYS_DEFAULT_SIN_VOL 6
|
||||
|
||||
#elif (SYS_VOL_TYPE == VOL_TYPE_AD)
|
||||
#define SYS_MAX_VOL MAX_COM_VOL
|
||||
#define SYS_DEFAULT_VOL SYS_MAX_VOL
|
||||
#define SYS_DEFAULT_TONE_VOL 14
|
||||
#define SYS_DEFAULT_SIN_VOL 8
|
||||
#else
|
||||
#error "SYS_VOL_TYPE define error"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*数字音量最大值定义*/
|
||||
#define DEFAULT_DIGITAL_VOLUME 16384
|
||||
|
||||
|
||||
#define BT_MUSIC_VOL_LEAVE_MAX 16 /*高级音频音量等级*/
|
||||
#define BT_MUSIC_VOL_STEP (-3.0f) /*高级音频音量等级衰减步进*/
|
||||
#define BT_CALL_VOL_LEAVE_MAX 15 /*通话音量等级*/
|
||||
#define BT_CALL_VOL_STEP (-2.0f) /*通话音量等级衰减步进*/
|
||||
|
||||
|
||||
/*
|
||||
*audio state define
|
||||
*/
|
||||
#define APP_AUDIO_STATE_IDLE 0
|
||||
#define APP_AUDIO_STATE_MUSIC 1
|
||||
#define APP_AUDIO_STATE_CALL 2
|
||||
#define APP_AUDIO_STATE_WTONE 3
|
||||
#define APP_AUDIO_STATE_LINEIN 4
|
||||
#define APP_AUDIO_CURRENT_STATE 5
|
||||
|
||||
#define APP_AUDIO_MAX_STATE (APP_AUDIO_CURRENT_STATE + 1)
|
||||
|
||||
|
||||
#define AUDIO_OUTPUT_INCLUDE_BT ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)) \
|
||||
|| ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_BT))
|
||||
|
||||
|
||||
#define AUDIO_OUTPUT_INCLUDE_FM ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)) \
|
||||
|| ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_FM))
|
||||
|
||||
|
||||
#if TCFG_MIC_EFFECT_ENABLE
|
||||
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
|
||||
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_REVERB_SAMPLERATE_DEFUAL)
|
||||
#elif (TCFG_AD2DA_LOW_LATENCY_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
|
||||
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
|
||||
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE)
|
||||
#elif TCFG_SIDETONE_ENABLE
|
||||
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
|
||||
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
|
||||
#else
|
||||
#define TCFG_AUDIO_DAC_MIX_ENABLE (0)
|
||||
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
|
||||
#endif
|
||||
|
||||
u8 get_max_sys_vol(void);
|
||||
u8 get_tone_vol(void);
|
||||
|
||||
s8 app_audio_get_volume(u8 state);
|
||||
s8 app_audio_get_volume_r(u8 state);
|
||||
void app_audio_set_volume(u8 state, s8 volume, u8 fade);
|
||||
void app_audio_set_volume_each_channel(u8 state, s8 volume_l, s8 volume_r, u8 fade);
|
||||
void app_audio_volume_up(u8 value);
|
||||
void app_audio_volume_down(u8 value);
|
||||
void app_audio_volume_set(u8 value);
|
||||
void app_audio_state_switch(u8 state, s16 max_volume);
|
||||
void app_audio_mute(u8 value);
|
||||
s16 app_audio_get_max_volume(void);
|
||||
void app_audio_state_switch(u8 state, s16 max_volume);
|
||||
void app_audio_state_exit(u8 state);
|
||||
void app_audio_set_max_volume(u8 state, s16 max_volume);
|
||||
u8 app_audio_get_state(void);
|
||||
void volume_up_down_direct(s8 value);
|
||||
void app_audio_set_mix_volume(u8 front_volume, u8 back_volume);
|
||||
void app_audio_set_digital_volume(s16 volume);
|
||||
|
||||
void app_set_sys_vol(s16 vol_l, s16 vol_r);
|
||||
void app_set_max_vol(s16 vol);
|
||||
void audio_volume_list_init(u8 cfg_en);
|
||||
|
||||
u32 phone_call_eq_open();
|
||||
int eq_mode_sw();
|
||||
int mic_test_start();
|
||||
int mic_test_stop();
|
||||
|
||||
void dac_power_on(void);
|
||||
void dac_power_off(void);
|
||||
|
||||
/*打印audio模块的数字模拟增益:DAC/ADC*/
|
||||
void audio_gain_dump();
|
||||
void audio_adda_dump(void); //打印所有的dac,adc寄存器
|
||||
|
||||
void app_audio_volume_init(void);
|
||||
void app_audio_output_init(void);
|
||||
int app_audio_output_mode_set(u8 output);
|
||||
int app_audio_output_mode_get(void);
|
||||
int app_audio_output_channel_get(void);
|
||||
int app_audio_output_channel_set(u8 channel);
|
||||
int app_audio_output_write(void *buf, int len);
|
||||
int app_audio_output_samplerate_select(u32 sample_rate, u8 high);
|
||||
int app_audio_output_samplerate_set(int sample_rate);
|
||||
int app_audio_output_samplerate_get(void);
|
||||
int app_audio_output_start(void);
|
||||
int app_audio_output_stop(void);
|
||||
int audio_dac_trim_value_check(struct audio_dac_trim *dac_trim);
|
||||
|
||||
int esco_enc_reset(void);
|
||||
u8 bt_phone_dec_is_running();
|
||||
u8 bt_media_is_running(void);
|
||||
void a2dp_dec_dut_enable(u8 dut_enable);
|
||||
|
||||
|
||||
#endif/*_APP_AUDIO_H_*/
|
||||
652
cpu/br28/audio_cvp_dut.c
Normal file
652
cpu/br28/audio_cvp_dut.c
Normal file
@ -0,0 +1,652 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Audio CVP DUT
|
||||
*
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
#include "audio_cvp_dut.h"
|
||||
#include "online_db_deal.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_adc.h"
|
||||
#include "anc.h"
|
||||
#include "aec_user.h"
|
||||
#include "app_main.h"
|
||||
#include "user_cfg_id.h"
|
||||
#include "audio_config.h"
|
||||
#include "math.h"
|
||||
|
||||
#if 0
|
||||
#define cvp_dut_log printf
|
||||
#define cvp_dut_put_float put_float
|
||||
#else
|
||||
#define cvp_dut_log(...)
|
||||
#define cvp_dut_put_float(...)
|
||||
#endif
|
||||
|
||||
#define CVP_DUT_BIG_ENDDIAN 1 //大端数据输出
|
||||
#define CVP_DUT_LITTLE_ENDDIAN 2 //小端数据输出
|
||||
#define CVP_DUT_OUTPUT_WAY CVP_DUT_LITTLE_ENDDIAN
|
||||
|
||||
#if TCFG_AUDIO_CVP_DUT_ENABLE
|
||||
static cvp_dut_t *cvp_dut_hdl = NULL;
|
||||
static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
|
||||
int cvp_dut_new_rx_packet(u8 *dat, u8 len);
|
||||
int cvp_dut_spp_rx_packet(u8 *dat, u8 len);
|
||||
|
||||
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
extern void audio_aec_output_sel(u8 sel, u8 agc);
|
||||
#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
|
||||
|
||||
extern void put_float(double fv);
|
||||
extern void sys_enter_soft_poweroff(void *priv);
|
||||
extern int audio_aec_toggle_set(u8 toggle);
|
||||
|
||||
/*未经过算法处理,主要用于分析ANC MIC的频响*/
|
||||
int cvp_dut_bypass_mic_ch_sel(u8 mic_num)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
switch (mic_num) {
|
||||
case A_MIC0:
|
||||
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_0;
|
||||
break;
|
||||
case A_MIC1:
|
||||
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_1;
|
||||
break;
|
||||
case A_MIC2:
|
||||
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_2;
|
||||
break;
|
||||
case A_MIC3:
|
||||
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 cvp_dut_mic_ch_get(void)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
return cvp_dut_hdl->mic_ch_sel;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 cvp_dut_mode_get(void)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
return cvp_dut_hdl->mode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cvp_dut_mode_set(u8 mode)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
cvp_dut_hdl->mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
int cvp_dut_event_deal(u8 *dat)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
switch (dat[3]) {
|
||||
#if TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
//双麦ENC DUT 事件处理
|
||||
case CVP_DUT_DMS_MASTER_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
|
||||
break;
|
||||
case CVP_DUT_DMS_SLAVE_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
|
||||
break;
|
||||
case CVP_DUT_DMS_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
|
||||
break;
|
||||
#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
case CVP_DUT_3MIC_MASTER_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(1, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_SLAVE_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(2, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_FB_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(3, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(0, 0);
|
||||
break;
|
||||
#else
|
||||
//单麦SMS/DNS DUT 事件处理
|
||||
case CVP_DUT_DMS_MASTER_MIC:
|
||||
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(0);
|
||||
break;
|
||||
case CVP_DUT_DMS_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(1);
|
||||
break;
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH & ANC_L_CH) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
|
||||
} else {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
|
||||
}
|
||||
break;
|
||||
case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH & ANC_L_CH) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
|
||||
} else {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
|
||||
}
|
||||
break;
|
||||
case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
|
||||
}
|
||||
break;
|
||||
case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
|
||||
}
|
||||
break;
|
||||
case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
|
||||
cvp_dut_log("CMD:CVP_DUT_RESUME\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
break;
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
|
||||
//JL自研算法指令API
|
||||
#if !TCFG_CVP_DEVELOP_ENABLE
|
||||
case CVP_DUT_NS_OPEN:
|
||||
cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
|
||||
break;
|
||||
case CVP_DUT_NS_CLOSE:
|
||||
cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
|
||||
break;
|
||||
#endif/*TCFG_CVP_DEVELOP_ENABLE*/
|
||||
|
||||
case CVP_DUT_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(1);
|
||||
break;
|
||||
case CVP_DUT_CLOSE_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(0);
|
||||
break;
|
||||
case CVP_DUT_POWEROFF:
|
||||
cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
|
||||
sys_enter_soft_poweroff(NULL);
|
||||
break;
|
||||
default:
|
||||
cvp_dut_log("CMD:UNKNOW CMD!!!\n");
|
||||
return CVP_DUT_ACK_ERR_UNKNOW;
|
||||
}
|
||||
return CVP_DUT_ACK_SUCCESS;
|
||||
}
|
||||
return CVP_DUT_ACK_ERR_UNKNOW;
|
||||
}
|
||||
|
||||
void cvp_dut_init(void)
|
||||
{
|
||||
cvp_dut_log("tx dat");
|
||||
if (cvp_dut_hdl == NULL) {
|
||||
cvp_dut_hdl = zalloc(sizeof(cvp_dut_t));
|
||||
}
|
||||
//开机默认设置成算法模式
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
app_online_db_register_handle(DB_PKT_TYPE_DMS, cvp_dut_app_online_parse);
|
||||
}
|
||||
|
||||
void cvp_dut_unit(void)
|
||||
{
|
||||
free(cvp_dut_hdl);
|
||||
cvp_dut_hdl = NULL;
|
||||
}
|
||||
|
||||
int cvp_dut_spp_tx_packet(u8 command)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
cvp_dut_hdl->tx_buf.magic = CVP_DUT_SPP_MAGIC;
|
||||
cvp_dut_hdl->tx_buf.dat[0] = 0;
|
||||
cvp_dut_hdl->tx_buf.dat[1] = 0;
|
||||
cvp_dut_hdl->tx_buf.dat[2] = 0;
|
||||
cvp_dut_hdl->tx_buf.dat[3] = command;
|
||||
cvp_dut_log("tx dat");
|
||||
#if CVP_DUT_OUTPUT_WAY == CVP_DUT_LITTLE_ENDDIAN // 小端格式
|
||||
cvp_dut_hdl->tx_buf.crc = CRC16((&cvp_dut_hdl->tx_buf.dat), CVP_DUT_PACK_NUM - 4);
|
||||
put_buf((u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
|
||||
app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
|
||||
#else
|
||||
u16 crc_temp;
|
||||
int i;
|
||||
u8 dat[CVP_DUT_PACK_NUM];
|
||||
u8 dat_temp;
|
||||
memcpy(dat, &(cvp_dut_hdl->tx_buf), CVP_DUT_PACK_NUM);
|
||||
crc_temp = CRC16(dat + 4, 6);
|
||||
printf("crc0x%x,0x%x", crc_temp, cvp_dut_hdl->tx_buf.crc);
|
||||
for (i = 0; i < 6; i += 2) { //小端数据转大端
|
||||
dat_temp = dat[i];
|
||||
dat[i] = dat[i + 1];
|
||||
dat[i + 1] = dat_temp;
|
||||
}
|
||||
crc_temp = CRC16(dat + 4, CVP_DUT_PACK_NUM - 4);
|
||||
dat[2] = crc_temp >> 8;
|
||||
dat[3] = crc_temp & 0xff;
|
||||
put_buf(dat, CVP_DUT_PACK_NUM);
|
||||
app_online_db_send(DB_PKT_TYPE_DMS, dat, CVP_DUT_PACK_NUM);
|
||||
#endif
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
cvp_dut_hdl->parse_seq = ext_data[1];
|
||||
int ret = cvp_dut_spp_rx_packet(packet, size);
|
||||
if (ret) {
|
||||
cvp_dut_new_rx_packet(packet, size);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cvp_dut_spp_rx_packet(u8 *dat, u8 len)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
u8 dat_temp;
|
||||
u16 crc = 0;
|
||||
int ret = 0;
|
||||
u8 dat_packet[CVP_DUT_PACK_NUM];
|
||||
if (len > CVP_DUT_PACK_NUM) {
|
||||
return 1;
|
||||
}
|
||||
/* cvp_dut_log("rx dat,%d\n", CVP_DUT_PACK_NUM); */
|
||||
put_buf(dat, len);
|
||||
memcpy(dat_packet, dat, len);
|
||||
crc = CRC16(dat + 4, len - 4);
|
||||
#if CVP_DUT_OUTPUT_WAY == CVP_DUT_BIG_ENDDIAN // 大端格式
|
||||
for (int i = 0; i < 6; i += 2) { // 大端数据转小端
|
||||
dat_temp = dat_packet[i];
|
||||
dat_packet[i] = dat_packet[i + 1];
|
||||
dat_packet[i + 1] = dat_temp;
|
||||
}
|
||||
#endif
|
||||
cvp_dut_log("rx dat_packet");
|
||||
memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, 4);
|
||||
if (cvp_dut_hdl->rx_buf.magic == CVP_DUT_SPP_MAGIC) {
|
||||
cvp_dut_log("crc %x,cvp_dut_hdl->rx_buf.crc %x\n", crc, cvp_dut_hdl->rx_buf.crc);
|
||||
if (cvp_dut_hdl->rx_buf.crc == crc || cvp_dut_hdl->rx_buf.crc == 0x1) {
|
||||
memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, len);
|
||||
ret = cvp_dut_event_deal(cvp_dut_hdl->rx_buf.dat);
|
||||
cvp_dut_spp_tx_packet(ret); //反馈收到命令
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CVP SPP产测 NEW STRUCT
|
||||
***************************************************************************/
|
||||
|
||||
struct cvp_dut_packet_t {
|
||||
u8 cmd; //命令
|
||||
u16 len; //参数长度
|
||||
u8 dat[0]; //参数
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cvp_dut_head_t {
|
||||
u16 magic; //标识符
|
||||
u16 crc; //CRC, 从packet开始计算
|
||||
struct cvp_dut_packet_t packet;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
CVP 命令处理函数
|
||||
param: struct cvp_dut_head_t 类型的数据
|
||||
return 执行结果
|
||||
*/
|
||||
int cvp_dut_new_event_deal(void *packet)
|
||||
{
|
||||
struct cvp_dut_packet_t *hdl = (struct cvp_dut_packet_t *)packet;
|
||||
u16 len = hdl->len;
|
||||
int wlen = 0;
|
||||
int ret = -1;
|
||||
u8 last_mode, reset_flag;
|
||||
cvp_dut_log("CVP_DUT CMD:0X%x,LEN:%d\n", hdl->cmd, len);
|
||||
put_buf((u8 *)packet, hdl->len + sizeof(struct cvp_dut_packet_t));
|
||||
if (cvp_dut_hdl) {
|
||||
reset_flag = 0;
|
||||
last_mode = cvp_dut_hdl->mode;
|
||||
switch (hdl->cmd) {
|
||||
#if TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
//双麦ENC DUT 事件处理
|
||||
case CVP_DUT_DMS_MASTER_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
|
||||
break;
|
||||
case CVP_DUT_DMS_SLAVE_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
|
||||
break;
|
||||
case CVP_DUT_DMS_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
|
||||
break;
|
||||
#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
case CVP_DUT_3MIC_MASTER_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(1, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_SLAVE_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(2, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_FB_MIC:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(3, 0);
|
||||
break;
|
||||
case CVP_DUT_3MIC_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_output_sel(0, 0);
|
||||
break;
|
||||
#else
|
||||
//单麦SMS/DNS DUT 事件处理
|
||||
case CVP_DUT_DMS_MASTER_MIC:
|
||||
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(0);
|
||||
break;
|
||||
case CVP_DUT_DMS_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(1);
|
||||
break;
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH & ANC_L_CH) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
|
||||
} else {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
|
||||
}
|
||||
reset_flag = 1;
|
||||
break;
|
||||
case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH & ANC_L_CH) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
|
||||
} else {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
|
||||
}
|
||||
reset_flag = 1;
|
||||
break;
|
||||
case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
|
||||
}
|
||||
reset_flag = 1;
|
||||
break;
|
||||
case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
|
||||
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
|
||||
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
|
||||
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
|
||||
}
|
||||
reset_flag = 1;
|
||||
break;
|
||||
case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
|
||||
cvp_dut_log("CMD:CVP_DUT_RESUME\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
break;
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
|
||||
//JL自研算法指令API
|
||||
#if !TCFG_CVP_DEVELOP_ENABLE
|
||||
case CVP_DUT_NS_OPEN:
|
||||
cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
|
||||
break;
|
||||
case CVP_DUT_NS_CLOSE:
|
||||
cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
|
||||
break;
|
||||
#endif/*TCFG_CVP_DEVELOP_ENABLE*/
|
||||
|
||||
case CVP_DUT_OPEN_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(1);
|
||||
break;
|
||||
case CVP_DUT_CLOSE_ALGORITHM:
|
||||
cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_aec_toggle_set(0);
|
||||
break;
|
||||
case CVP_DUT_POWEROFF:
|
||||
cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
|
||||
sys_enter_soft_poweroff(NULL);
|
||||
break;
|
||||
|
||||
/*enc麦克风校准补偿*/
|
||||
#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
|
||||
case CVP_ENC_MIC_DIFF_CMP_SET: //主MIC - 副MIC
|
||||
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_SET\n");
|
||||
float diff;
|
||||
memcpy((u8 *)&diff, hdl->dat, len);
|
||||
cvp_dut_log("diff:");
|
||||
cvp_dut_put_float(diff);
|
||||
float dms_mic_diff = log10(app_var.enc_degradation) * 20;
|
||||
app_var.audio_mic_array_diff_cmp = pow(10, (diff + dms_mic_diff) / 20);
|
||||
wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
|
||||
if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
|
||||
printf("mic array diff cap vm write fail !!!");
|
||||
ret = CVP_DUT_ACK_VM_WRITE_ERR;
|
||||
}
|
||||
cvp_dut_log("mic_array_diff_cmp:");
|
||||
cvp_dut_put_float(app_var.audio_mic_array_diff_cmp);
|
||||
break;
|
||||
case CVP_ENC_MIC_DIFF_CMP_EN:
|
||||
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_EN\n");
|
||||
u8 en;
|
||||
memcpy(&en, hdl->dat, len);
|
||||
app_var.audio_mic_array_trim_en = en;
|
||||
wlen = syscfg_write(CFG_MIC_ARRAY_TRIM_EN, (u8 *)(&app_var.audio_mic_array_trim_en), sizeof(app_var.audio_mic_array_trim_en));
|
||||
if (wlen != sizeof(app_var.audio_mic_array_trim_en)) {
|
||||
cvp_dut_log("mic array trim en vm write fail !!!");
|
||||
ret = CVP_DUT_ACK_VM_WRITE_ERR;
|
||||
}
|
||||
cvp_dut_log("mic array trim en: %d\n", app_var.audio_mic_array_trim_en);
|
||||
break;
|
||||
case CVP_ENC_MIC_DIFF_CMP_CLEAN:
|
||||
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
|
||||
app_var.audio_mic_array_diff_cmp = 1.0f;
|
||||
app_var.audio_mic_cmp.talk = 1.0f;
|
||||
app_var.audio_mic_cmp.ff = 1.0f;
|
||||
app_var.audio_mic_cmp.fb = 1.0f;
|
||||
|
||||
wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
|
||||
if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
|
||||
cvp_dut_log("mic array diff cap vm write fail !!!");
|
||||
ret = CVP_DUT_ACK_VM_WRITE_ERR;
|
||||
}
|
||||
wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
|
||||
if (wlen != sizeof(audio_mic_cmp_t)) {
|
||||
printf("mic array diff cap vm write fail !!!");
|
||||
ret = CVP_DUT_ACK_VM_WRITE_ERR;
|
||||
}
|
||||
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
|
||||
break;
|
||||
case CVP_ENC_TARGET_MIC_DIFF_SET:
|
||||
cvp_dut_log("CMD:CVP_ENC_TARGET_MIC_DIFF_SET\n");
|
||||
float talk_diff, ff_diff, fb_diff;
|
||||
memcpy((u8 *)&talk_diff, hdl->dat, 4);
|
||||
memcpy((u8 *)&ff_diff, hdl->dat + 4, 4);
|
||||
memcpy((u8 *)&fb_diff, hdl->dat + 8, 4);
|
||||
cvp_dut_log("talk_diff:");
|
||||
cvp_dut_put_float(talk_diff);
|
||||
cvp_dut_log("ff_diff:");
|
||||
cvp_dut_put_float(ff_diff);
|
||||
cvp_dut_log("fb_diff:");
|
||||
cvp_dut_put_float(fb_diff);
|
||||
app_var.audio_mic_cmp.talk = pow(10, (talk_diff) / 20);
|
||||
app_var.audio_mic_cmp.ff = pow(10, (ff_diff) / 20);
|
||||
app_var.audio_mic_cmp.fb = pow(10, (fb_diff) / 20);
|
||||
wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
|
||||
if (wlen != sizeof(audio_mic_cmp_t)) {
|
||||
printf("mic array diff cap vm write fail !!!");
|
||||
ret = CVP_DUT_ACK_VM_WRITE_ERR;
|
||||
}
|
||||
break;
|
||||
#endif /*TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE*/
|
||||
|
||||
/*通话算法模块开关*/
|
||||
case CVP_DUT_CVP_IOCTL:
|
||||
cvp_dut_log("CMD:CVP_DUT_CVP_IOCTL\n");
|
||||
u8 ioctl_cmd = hdl->dat[0];
|
||||
u8 toggle = hdl->dat[1];
|
||||
cvp_dut_log(" io ctl cmd %d, toggle %d", ioctl_cmd, toggle);
|
||||
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
|
||||
audio_cvp_ioctl(ioctl_cmd, toggle, NULL);
|
||||
break;
|
||||
case CVP_DUT_DEC_DUT_SET:
|
||||
cvp_dut_log("CVP_DUT_DEC_DUT_SET: %d\n", hdl->dat[0]);
|
||||
cvp_dut_hdl->dec_dut_enable = hdl->dat[0];
|
||||
a2dp_dec_dut_enable(cvp_dut_hdl->dec_dut_enable);
|
||||
break;
|
||||
default:
|
||||
cvp_dut_log("CMD:UNKNOW CMD!!!\n");
|
||||
ret = CVP_DUT_ACK_ERR_UNKNOW;
|
||||
}
|
||||
if (last_mode != cvp_dut_hdl->mode) {
|
||||
reset_flag = 1; //模式被修改,则复位通话
|
||||
}
|
||||
if (reset_flag) {
|
||||
if (bt_phone_dec_is_running()) {
|
||||
esco_enc_reset();
|
||||
}
|
||||
}
|
||||
ret = (ret == -1) ? CVP_DUT_ACK_SUCCESS : ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//len = 参数数据长度(不包括cmd)
|
||||
int cvp_dut_new_tx_packet(u8 cmd, u8 *data, int len)
|
||||
{
|
||||
if (cvp_dut_hdl) {
|
||||
int packet_len = sizeof(struct cvp_dut_head_t) + len;
|
||||
struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)malloc(packet_len);
|
||||
head->magic = CVP_DUT_NEW_SPP_MAGIC;
|
||||
head->packet.cmd = cmd;
|
||||
head->packet.len = len;
|
||||
head->crc = CRC16(&head->packet, packet_len - 4);
|
||||
if (len) {
|
||||
memcpy(head->packet.dat, data, len);
|
||||
}
|
||||
cvp_dut_log("tx new_dat_packet %d\n", packet_len);
|
||||
//put_buf((u8 *)head, packet_len);
|
||||
app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)head, packet_len);
|
||||
free(head);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cvp_dut_new_rx_packet(u8 *dat, u8 len)
|
||||
{
|
||||
u16 crc = 0;
|
||||
int ret = 0;
|
||||
struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)dat;
|
||||
if (cvp_dut_hdl) {
|
||||
cvp_dut_log("rx new_dat_packet");
|
||||
//put_buf(dat, len);
|
||||
crc = CRC16(&head->packet, len - 4);
|
||||
if (head->magic == CVP_DUT_NEW_SPP_MAGIC) {
|
||||
if (head->crc == crc || head->crc == 0x1) {
|
||||
ret = cvp_dut_new_event_deal(&head->packet);
|
||||
cvp_dut_new_tx_packet(ret, NULL, 0); //反馈收到命令
|
||||
if (ret == CVP_DUT_ACK_SUCCESS) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
cvp_dut_log("ERR head->crc %x != %x\n", head->crc, crc);
|
||||
cvp_dut_new_tx_packet(CVP_DUT_ACK_CRC_ERR, NULL, 0); //反馈收到命令
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
DEC产测状态获取
|
||||
param: music_decide 1 需判断播歌状态; 0 不需判断
|
||||
*/
|
||||
u8 audio_dec_dut_en_get(u8 music_decide)
|
||||
{
|
||||
if (!cvp_dut_hdl) {
|
||||
return 0;
|
||||
}
|
||||
if (music_decide && !bt_media_is_running()) {
|
||||
//当前非播歌状态
|
||||
return 0;
|
||||
}
|
||||
return cvp_dut_hdl->dec_dut_enable;
|
||||
}
|
||||
|
||||
#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/
|
||||
|
||||
121
cpu/br28/audio_cvp_dut.h
Normal file
121
cpu/br28/audio_cvp_dut.h
Normal file
@ -0,0 +1,121 @@
|
||||
#ifndef _AUDIO_CVP_DUT_H_
|
||||
#define _AUDIO_CVP_DUT_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
/*******************CVP测试命令集*********************/
|
||||
#define CVP_DUT_DMS_MASTER_MIC 0x01 //DMS-测试主MIC SMS-关闭CVP算法
|
||||
#define CVP_DUT_DMS_SLAVE_MIC 0x02 //DMS-测试副MIC
|
||||
#define CVP_DUT_DMS_OPEN_ALGORITHM 0x03 //DMS-测试dms算法 SMS-打开CVP算法
|
||||
|
||||
#define CVP_DUT_NS_OPEN 0x04 //打开NS模块
|
||||
#define CVP_DUT_NS_CLOSE 0x05 //关闭NS模块
|
||||
|
||||
//ANC MIC 频响测试指令,且需切换到CVP_DUT_MODE_BYPASS,在通话HFP前设置
|
||||
#define CVP_DUT_FF_MIC 0x06 //测试TWS FF MIC/头戴式左耳FF_MIC
|
||||
#define CVP_DUT_FB_MIC 0x07 //测试TWS FB MIC/头戴式左耳FB_MIC
|
||||
#define CVP_DUT_HEAD_PHONE_R_FF_MIC 0x08 //测试头戴式右耳FF_MIC
|
||||
#define CVP_DUT_HEAD_PHONE_R_FB_MIC 0x09 //测试头戴式右耳FB_MIC
|
||||
|
||||
#define CVP_DUT_OPEN_ALGORITHM 0x0a //CVP算法开启
|
||||
#define CVP_DUT_CLOSE_ALGORITHM 0x0b //CVP算法关闭
|
||||
#define CVP_DUT_MODE_ALGORITHM_SET 0x0c //CVP_DUT 开关算法模式
|
||||
#define CVP_DUT_POWEROFF 0x0d //耳机关机指令
|
||||
|
||||
#define CVP_ENC_MIC_DIFF_CMP_SET 0x0f //设置补偿值(主MIC - 副MIC)
|
||||
#define CVP_ENC_MIC_DIFF_CMP_EN 0x10 //补偿使能
|
||||
#define CVP_ENC_MIC_DIFF_CMP_CLEAN 0x11 //清除补偿
|
||||
|
||||
//三麦通话测试指令
|
||||
#define CVP_DUT_3MIC_MASTER_MIC CVP_DUT_DMS_MASTER_MIC //测试三麦算法主麦频响
|
||||
#define CVP_DUT_3MIC_SLAVE_MIC CVP_DUT_DMS_SLAVE_MIC //测试三麦算法副麦频响
|
||||
#define CVP_DUT_3MIC_FB_MIC 0x0e //测试三麦算法FBmic频响
|
||||
#define CVP_DUT_3MIC_OPEN_ALGORITHM CVP_DUT_DMS_OPEN_ALGORITHM //测试三麦算法副麦频响
|
||||
|
||||
#define CVP_DUT_CVP_IOCTL 0x12 //CVP算法单元独立控制
|
||||
|
||||
#define CVP_DUT_DEC_DUT_SET 0x13 //DEC 产测模式设置 (bypass数据处理)
|
||||
#define CVP_ENC_TARGET_MIC_DIFF_SET 0x14 //设置MIC与目标金机MIC的差值(主-副-FB)
|
||||
|
||||
//命令回复
|
||||
#define CVP_DUT_ACK_SUCCESS 0x01 //命令接收成功
|
||||
//错误回复
|
||||
#define CVP_DUT_ACK_ERR_UNKNOW 0xA1 //未知命令
|
||||
#define CVP_DUT_ACK_CRC_ERR 0xA2 //CRC错误
|
||||
#define CVP_DUT_ACK_VM_WRITE_ERR 0xA3 //VM写入错误
|
||||
/*******************CVP测试命令集END*********************/
|
||||
|
||||
#define CVP_DUT_SPP_MAGIC 0x55BB
|
||||
#define CVP_DUT_PACK_NUM sizeof(cvp_dut_data_t) //数据包总长度
|
||||
|
||||
#define CVP_DUT_NEW_SPP_MAGIC 0x55CC
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
CVP_DUT 算法模式
|
||||
通话中设置命令,可自由开关每个算法,测试性能指标
|
||||
*/
|
||||
CVP_DUT_MODE_ALGORITHM = 1,
|
||||
|
||||
/*
|
||||
CVP_DUT BYPASS模式
|
||||
通话前设置命令,不经过算法,可自由选择需要测试的MIC
|
||||
每次通话结束默认恢复成 CVP_DUT算法模式
|
||||
*/
|
||||
CVP_DUT_MODE_BYPASS = 2,
|
||||
|
||||
} CVP_DUT_mode_t;
|
||||
|
||||
typedef enum {
|
||||
CVP_3MIC_OUTPUT_SEL_DEFAULT = 0, /*默认输出*/
|
||||
CVP_3MIC_OUTPUT_SEL_MASTER, /*Talk mic原始数据*/
|
||||
CVP_3MIC_OUTPUT_SEL_SLAVE, /*FF mic原始数据*/
|
||||
CVP_3MIC_OUTPUT_SEL_FBMIC, /*FB mic原始数据*/
|
||||
} CVP_3MIC_OUTPUT_ENUM;
|
||||
|
||||
//DEC 产测模式
|
||||
typedef enum {
|
||||
AUDIO_DEC_DUT_MODE_CLOSE = 0, /*DEC_DUT 关闭*/
|
||||
AUDIO_DEC_DUT_MODE_BYPASS, /*DEC_DUT 开启:bypass所有数据处理*/
|
||||
AUDIO_DEC_DUT_MODE_SPK_EQ, /*DEC_DUT 开启:仅保留SPK_EQ*/
|
||||
} audio_dec_dut_mode_t;
|
||||
|
||||
typedef struct {
|
||||
u16 magic;
|
||||
u16 crc;
|
||||
u8 dat[4];
|
||||
} cvp_dut_data_t;
|
||||
|
||||
typedef struct {
|
||||
u8 parse_seq;
|
||||
u8 mic_ch_sel; //bypass模式下,MIC通道号
|
||||
u8 mode; //CVP DUT MODE
|
||||
u8 dec_dut_enable; //DEC DUT 模式
|
||||
cvp_dut_data_t rx_buf; //spp接收buf
|
||||
cvp_dut_data_t tx_buf; //spp发送buf
|
||||
} cvp_dut_t;
|
||||
//cvp_dut 测试初始化接口
|
||||
void cvp_dut_init(void);
|
||||
|
||||
//cvp_dut 卸载接口
|
||||
void cvp_dut_unit(void);
|
||||
|
||||
//cvp_dut MIC 通道 获取接口
|
||||
u8 cvp_dut_mic_ch_get(void);
|
||||
|
||||
//cvp_dut 模式获取
|
||||
u8 cvp_dut_mode_get(void);
|
||||
|
||||
//cvp_dut 模式设置
|
||||
void cvp_dut_mode_set(u8 mode);
|
||||
|
||||
/*
|
||||
DEC产测状态获取
|
||||
param: music_decide 1 需判断播歌状态; 0 不需判断
|
||||
*/
|
||||
u8 audio_dec_dut_en_get(u8 music_decide);
|
||||
|
||||
//cvp_dut 数据解析函数
|
||||
int cvp_dut_new_rx_packet(u8 *dat, u8 len);
|
||||
|
||||
#endif/*_AUDIO_CVP_DUT_*/
|
||||
161
cpu/br28/audio_cvp_sync.c
Normal file
161
cpu/br28/audio_cvp_sync.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include "system/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
|
||||
#if TCFG_AUDIO_CVP_SYNC
|
||||
|
||||
#if 0
|
||||
#define cvp_sync_log printf
|
||||
#else
|
||||
#define cvp_sync_log(...)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CVP_SYNC_STA_NORMAL = 0, //普通状态
|
||||
CVP_SYNC_STA_DOWNSAMPLING, //下采样状态
|
||||
CVP_SYNC_STA_UPSAMPLING, //上采样状态
|
||||
};
|
||||
|
||||
#define AUDIO_CVP_SRCBUF_SIZE 672 //输入输出BUFFER长度
|
||||
#define AUDIO_CVP_CATCH_LEN AUDIO_CVP_SRCBUF_SIZE //SRC 拼包BUF 长度, 注意每帧不能超过此长度
|
||||
#define AUDIO_CVP_DETECT_TIME 1000 //定时检测周期
|
||||
|
||||
typedef struct {
|
||||
u8 ch_num;
|
||||
u8 src_break;
|
||||
u8 state;
|
||||
u8 det_flag;
|
||||
u8 cnt;
|
||||
u16 offset;
|
||||
u16 det_time_id;
|
||||
u32 target_sample_rate; //目标采样率
|
||||
u32 sample_rate; //采样率
|
||||
s16 src_inbuf[AUDIO_CVP_SRCBUF_SIZE / 2];
|
||||
s16 src_outbuf[AUDIO_CVP_SRCBUF_SIZE / 2];
|
||||
u8 frame_catch[AUDIO_CVP_CATCH_LEN];
|
||||
struct audio_src_handle *hw_src; //SRC句柄
|
||||
} audio_cvp_sync_t;
|
||||
|
||||
static audio_cvp_sync_t *hdl = NULL;
|
||||
|
||||
extern int lmp_private_get_esco_send_packet_len();
|
||||
extern int audio_aec_sync_buffer_set(s16 *data, int len);
|
||||
static int audio_cvp_sync_output_handler(void *priv, void *data, int len)
|
||||
{
|
||||
if ((hdl->offset + len) > AUDIO_CVP_CATCH_LEN) {
|
||||
printf("cvp sync output buf full\n");
|
||||
hdl->src_break = 1;
|
||||
}
|
||||
//回调仅做拼包
|
||||
memcpy(hdl->frame_catch + hdl->offset, (u8 *)data, len);
|
||||
hdl->offset += len;
|
||||
/* if (hdl->cnt > 5) { */
|
||||
/* cvp_sync_log("sync len %d, offset %d\n", len, hdl->offset); */
|
||||
/* } */
|
||||
return len;
|
||||
}
|
||||
|
||||
static void audio_cvp_sync_det_set(void *priv)
|
||||
{
|
||||
if (hdl) {
|
||||
hdl->det_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int audio_cvp_sync_open(u16 sr)
|
||||
{
|
||||
if (!hdl) {
|
||||
hdl = zalloc(sizeof(audio_cvp_sync_t));
|
||||
}
|
||||
if (!hdl) {
|
||||
return 1;
|
||||
}
|
||||
hdl->hw_src = zalloc(sizeof(struct audio_src_handle));
|
||||
if (!hdl->hw_src) {
|
||||
return 1;
|
||||
}
|
||||
hdl->ch_num = 1;
|
||||
hdl->sample_rate = sr;
|
||||
hdl->target_sample_rate = sr;
|
||||
audio_hw_src_open(hdl->hw_src, hdl->ch_num, SRC_TYPE_RESAMPLE);
|
||||
audio_hw_src_set_output_buffer(hdl->hw_src, hdl->src_outbuf, AUDIO_CVP_SRCBUF_SIZE);
|
||||
audio_hw_src_set_input_buffer(hdl->hw_src, hdl->src_inbuf, AUDIO_CVP_SRCBUF_SIZE);
|
||||
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate);
|
||||
audio_src_set_output_handler(hdl->hw_src, NULL, audio_cvp_sync_output_handler);
|
||||
hdl->det_time_id = sys_timer_add(NULL, audio_cvp_sync_det_set, AUDIO_CVP_DETECT_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_cvp_sync_run(s16 *data, int len)
|
||||
{
|
||||
int wlen = 0;
|
||||
int btlen = lmp_private_get_esco_send_packet_len();
|
||||
|
||||
if (!hdl) {
|
||||
return 0;
|
||||
}
|
||||
if (hdl->det_flag) {
|
||||
if (btlen > 360) {
|
||||
if (hdl->state != CVP_SYNC_STA_UPSAMPLING) {
|
||||
hdl->state = CVP_SYNC_STA_UPSAMPLING;
|
||||
hdl->cnt = 0;
|
||||
}
|
||||
if (++hdl->cnt > 5) {
|
||||
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate - 1);
|
||||
cvp_sync_log("cvp_src_upsr btlen %d, cnt %d, len %d\n", btlen, hdl->cnt, len);
|
||||
}
|
||||
} else if (btlen < 120) {
|
||||
if (hdl->state != CVP_SYNC_STA_DOWNSAMPLING) {
|
||||
hdl->state = CVP_SYNC_STA_DOWNSAMPLING;
|
||||
hdl->cnt = 0;
|
||||
}
|
||||
if (++hdl->cnt > 5) {
|
||||
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate + 1);
|
||||
cvp_sync_log("cvp_src_downsr btlen %d, cnt %d, len %d\n", btlen, hdl->cnt, len);
|
||||
}
|
||||
} else {
|
||||
hdl->state = CVP_SYNC_STA_NORMAL;
|
||||
hdl->det_flag = 0;
|
||||
hdl->cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 //测试模块
|
||||
hdl->cnt = 6;
|
||||
static int max_btlen = 0;
|
||||
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate + 10);
|
||||
if (btlen > max_btlen) {
|
||||
max_btlen = btlen;
|
||||
cvp_sync_log("btlen %d, len %d \n", max_btlen, len);
|
||||
}
|
||||
#endif/*测试模块*/
|
||||
if (hdl->hw_src) {
|
||||
while (len) {
|
||||
hdl->offset = 0;
|
||||
wlen = audio_src_resample_write(hdl->hw_src, data, len);
|
||||
audio_resample_hw_push_data_out(hdl->hw_src); //执行完则表示当前帧的数据全部输出完毕
|
||||
audio_aec_sync_buffer_set((s16 *)hdl->frame_catch, hdl->offset); //输出到CVP
|
||||
data += wlen / 2;
|
||||
len -= wlen;
|
||||
if (hdl->src_break) {
|
||||
hdl->src_break = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int audio_cvp_sync_close()
|
||||
{
|
||||
if (hdl->hw_src) {
|
||||
audio_hw_src_stop(hdl->hw_src);
|
||||
audio_hw_src_close(hdl->hw_src);
|
||||
sys_timer_del(hdl->det_time_id);
|
||||
free(hdl->hw_src);
|
||||
free(hdl);
|
||||
hdl = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif/*TCFG_AUDIO_CVP_SYNC*/
|
||||
37
cpu/br28/audio_cvp_sync.h
Normal file
37
cpu/br28/audio_cvp_sync.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef AUDIO_CVP_SYNC_H
|
||||
#define AUDIO_CVP_SYNC_H
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio CVP Sync Open
|
||||
* Description: 通话上行同步打开
|
||||
* Arguments : sr 采样率
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : null
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_cvp_sync_open(u16 sr);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio CVP Sync Run
|
||||
* Description: 通话上行同步处理
|
||||
* Arguments : data 数据指针, len 数据长度(byte)
|
||||
* Return : len 写入的数据长度,0 写入失败
|
||||
* Note(s) : null
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_cvp_sync_run(s16 *data, int len);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio CVP Sync Close
|
||||
* Description: 通话上行同步关闭
|
||||
* Arguments : null
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : null
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_cvp_sync_close();
|
||||
|
||||
#endif/*AUDIO_CVP_SYNC_H*/
|
||||
1841
cpu/br28/audio_dec.c
Normal file
1841
cpu/br28/audio_dec.c
Normal file
File diff suppressed because it is too large
Load Diff
99
cpu/br28/audio_dec/audio_dec.h
Normal file
99
cpu/br28/audio_dec/audio_dec.h
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
#ifndef _AUDIO_DEC_H_
|
||||
#define _AUDIO_DEC_H_
|
||||
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "asm/audio_src.h"
|
||||
// #include "audio_digital_vol.h"
|
||||
/*#include "application/audio_eq_drc_apply.h"*/
|
||||
|
||||
|
||||
#ifndef RB16
|
||||
#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
|
||||
#endif
|
||||
|
||||
extern struct audio_decoder_task decode_task;
|
||||
extern struct audio_mixer mixer;
|
||||
extern struct audio_mixer recorder_mixer;
|
||||
|
||||
u32 audio_output_rate(int input_rate);
|
||||
u32 audio_output_channel_num(void);
|
||||
int audio_output_set_start_volume(u8 state);
|
||||
|
||||
int audio_output_start(u32 sample_rate, u8 reset_rate);
|
||||
void audio_output_stop(void);
|
||||
|
||||
struct audio_src_handle *audio_hw_resample_open(void *priv, int (*output_handler)(void *, void *, int),
|
||||
u8 channel, u16 input_sample_rate, u16 output_sample_rate);
|
||||
void audio_hw_resample_close(struct audio_src_handle *hdl);
|
||||
|
||||
void audio_resume_all_decoder(void);
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
void audio_sbc_enc_inbuf_resume(void);
|
||||
|
||||
int audio_dec_init();
|
||||
|
||||
void set_source_sample_rate(u16 sample_rate);
|
||||
u16 get_source_sample_rate();
|
||||
#if USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0
|
||||
void a2dp_user_digital_volume_set(u8 vol);
|
||||
u8 a2dp_user_audio_digital_volume_get();
|
||||
void a2dp_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void linein_user_digital_volume_set(u8 vol);
|
||||
u8 linein_user_audio_digital_volume_get();
|
||||
void linein_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void fm_user_digital_volume_set(u8 vol);
|
||||
u8 fm_user_audio_digital_volume_get();
|
||||
void fm_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void file_user_digital_volume_set(u8 vol);
|
||||
u8 file_user_audio_digital_volume_get();
|
||||
void file_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void pc_user_digital_volume_set(u8 vol);
|
||||
u8 pc_user_audio_digital_volume_get();
|
||||
void pc_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
void spdif_user_digital_volume_set(u8 vol);
|
||||
u8 spdif_user_audio_digital_volume_get();
|
||||
void spdif_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
|
||||
|
||||
void reverb_user_digital_volume_set(u8 vol);
|
||||
u8 reverb_user_audio_digital_volume_get();
|
||||
void reverb_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
|
||||
#endif
|
||||
void reverb_set_dodge_threshold(int threshold_in, int threshold_out, u8 fade_tar, u8 dodge_en);
|
||||
|
||||
|
||||
void a2dp_dec_output_set_start_bt_time(u32 bt_tmr);
|
||||
/*void mix_out_high_bass(u32 cmd, struct high_bass *hb);
|
||||
void mix_out_high_bass_dis(u32 cmd, u8 dis);*/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
|
||||
{
|
||||
s16 *mono = mono_pcm;
|
||||
int i = 0;
|
||||
u8 j = 0;
|
||||
|
||||
for (i = 0; i < points; i++, mono++) {
|
||||
*dual_pcm++ = *mono;
|
||||
*dual_pcm++ = *mono;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#include "audio_dec_file.h"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1305
cpu/br28/audio_dec/audio_dec_file.c
Normal file
1305
cpu/br28/audio_dec/audio_dec_file.c
Normal file
File diff suppressed because it is too large
Load Diff
127
cpu/br28/audio_dec/audio_dec_file.h
Normal file
127
cpu/br28/audio_dec/audio_dec_file.h
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
#ifndef _AUDIO_DEC_FILE_H_
|
||||
#define _AUDIO_DEC_FILE_H_
|
||||
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "media/file_decoder.h"
|
||||
#include "system/includes.h"
|
||||
#include "media/audio_decoder.h"
|
||||
#include "app_config.h"
|
||||
#include "music/music_decrypt.h"
|
||||
#include "music/music_id3.h"
|
||||
|
||||
#include "audio_dec_eff.h"
|
||||
|
||||
|
||||
#define FILE_DEC_REPEAT_EN 0 // 无缝循环播放
|
||||
|
||||
enum {
|
||||
FILE_DEC_STREAM_CLOSE = 0,
|
||||
FILE_DEC_STREAM_OPEN,
|
||||
};
|
||||
|
||||
struct file_dec_hdl {
|
||||
//struct audio_stream *stream; // 音频流
|
||||
struct file_decoder file_dec; // file解码句柄
|
||||
struct audio_res_wait wait; // 资源等待句柄
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
struct file_decoder trans_dec; // 解码句柄
|
||||
u8 *frame;
|
||||
u16 frame_len;
|
||||
u16 frame_remain_len;
|
||||
u8 trans_dec_end;
|
||||
u8 wait_tws_confirm;
|
||||
u8 tws_channel;
|
||||
u16 seqn;
|
||||
u16 tx_seqn;
|
||||
u32 wait_tws_timeout;
|
||||
void *ts_handle;
|
||||
void *syncts;
|
||||
u32 pcm_num;
|
||||
u32 mix_ch_event_params[3];
|
||||
#endif
|
||||
struct audio_mixer_ch mix_ch; // 叠加句柄
|
||||
|
||||
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
|
||||
struct dec_eq_drc *eq_drc;
|
||||
#endif//TCFG_MUSIC_MODE_EQ_ENABLE
|
||||
|
||||
u8 remain;
|
||||
|
||||
struct audio_dec_breakpoint *dec_bp; // 断点
|
||||
u32 id; // 唯一标识符,随机值
|
||||
void *file; // 文件句柄
|
||||
u32 pick_flag : 1; // 挑出数据帧发送(如MP3等)。不是输出pcm,后级不能接任何音效处理等
|
||||
u32 pcm_enc_flag : 1; // pcm压缩成数据帧发送(如WAV等)
|
||||
u32 read_err : 2; // 读数出错 0:no err, 1:fat err, 2:disk err
|
||||
u32 wait_add : 1; // 是否马上得到执行
|
||||
|
||||
#if TCFG_DEC_DECRYPT_ENABLE
|
||||
CIPHER mply_cipher; // 解密播放
|
||||
#endif
|
||||
#if TCFG_DEC_ID3_V1_ENABLE
|
||||
MP3_ID3_OBJ *p_mp3_id3_v1; // id3_v1信息
|
||||
#endif
|
||||
#if TCFG_DEC_ID3_V2_ENABLE
|
||||
MP3_ID3_OBJ *p_mp3_id3_v2; // id3_v2信息
|
||||
#endif
|
||||
|
||||
#if FILE_DEC_REPEAT_EN
|
||||
u8 repeat_num; // 无缝循环次数
|
||||
struct fixphase_repair_obj repair_buf; // 无缝循环句柄
|
||||
#endif
|
||||
|
||||
struct audio_dec_breakpoint *bp; // 断点信息
|
||||
|
||||
void *evt_priv; // 事件回调私有参数
|
||||
void (*evt_cb)(void *, int argc, int *argv); // 事件回调句柄
|
||||
|
||||
void (*stream_handler)(void *priv, int event, struct file_dec_hdl *); // 数据流设置回调
|
||||
void *stream_priv; // 数据流设置回调私有句柄
|
||||
};
|
||||
|
||||
enum {
|
||||
FILE_FROM_LOCAL,
|
||||
FILE_FROM_TWS,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct file_decoder *file_dec_get_file_decoder_hdl(void);
|
||||
|
||||
#define file_dec_is_stop() file_decoder_is_stop(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_is_play() file_decoder_is_play(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_is_pause() file_decoder_is_pause(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_pp() file_decoder_pp(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_FF(x) file_decoder_FF(file_dec_get_file_decoder_hdl(),x)
|
||||
#define file_dec_FR(x) file_decoder_FR(file_dec_get_file_decoder_hdl(),x)
|
||||
#define file_dec_get_breakpoint(x) file_decoder_get_breakpoint(file_dec_get_file_decoder_hdl(),x)
|
||||
#define file_dec_get_total_time() file_decoder_get_total_time(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_get_cur_time() file_decoder_get_cur_time(file_dec_get_file_decoder_hdl())
|
||||
#define file_dec_get_decoder_type() file_decoder_get_decoder_type(file_dec_get_file_decoder_hdl())
|
||||
|
||||
int file_dec_create(void *priv, void (*handler)(void *, int argc, int *argv));
|
||||
int file_dec_open(void *file, struct audio_dec_breakpoint *bp);
|
||||
void file_dec_close();
|
||||
int file_dec_restart(int id);
|
||||
int file_dec_push_restart(void);
|
||||
int file_dec_get_status(void);
|
||||
|
||||
void file_dec_set_stream_set_hdl(struct file_dec_hdl *dec,
|
||||
void (*stream_handler)(void *priv, int event, struct file_dec_hdl *),
|
||||
void *stream_priv);
|
||||
void *get_file_dec_hdl();
|
||||
|
||||
int tws_local_media_dec_open(u8 channel, u8 *arg);
|
||||
|
||||
void tws_local_media_dec_close(u8 channel);
|
||||
|
||||
int tws_local_media_dec_state();
|
||||
|
||||
void send_local_media_dec_open_cmd();
|
||||
|
||||
int file_dec_get_source();
|
||||
|
||||
#endif /*TCFG_APP_MUSIC_EN*/
|
||||
|
||||
391
cpu/br28/audio_dec/audio_dec_iis.c
Normal file
391
cpu/br28/audio_dec/audio_dec_iis.c
Normal file
@ -0,0 +1,391 @@
|
||||
#include "audio_dec_iis.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_decoder.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "audio_enc.h"
|
||||
#include "application/audio_eq.h"
|
||||
#include "application/audio_drc.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "audio_dec.h"
|
||||
#include "app_main.h"
|
||||
#include "clock_cfg.h"
|
||||
#include "audio_dec_eff.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "audio_dvol.h"
|
||||
#include "audio_link.h"
|
||||
#include "circular_buf.h"
|
||||
#include "sound_device.h"
|
||||
|
||||
|
||||
#if (TCFG_AUDIO_INPUT_IIS)
|
||||
|
||||
extern ALINK_PARM alink0_platform_data;
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
extern struct audio_decoder_task decode_task;
|
||||
extern struct audio_mixer mixer;
|
||||
/* extern void *hw_alink; //alink初始化句柄 */
|
||||
#define IIS_IN_STORE_PCM_SIZE (4 * 1024)
|
||||
|
||||
//iis 驱动结构体
|
||||
struct iis_in_sample_hdl {
|
||||
OS_SEM sem;
|
||||
s16 *store_pcm_buf;
|
||||
cbuffer_t cbuf;
|
||||
int sample_rate;
|
||||
void *hw_alink;
|
||||
void *alink_ch;
|
||||
};
|
||||
|
||||
// iis 输入解码结构体
|
||||
struct iis_in_dec_hdl {
|
||||
struct audio_decoder decoder;
|
||||
struct audio_res_wait wait;
|
||||
struct audio_mixer_ch mix_ch;
|
||||
u8 channel;
|
||||
u8 start;
|
||||
u8 need_resume;
|
||||
u8 remain;
|
||||
u8 output_ch;
|
||||
int sample_rate;
|
||||
void *iis_in; //驱动句柄
|
||||
};
|
||||
static struct iis_in_dec_hdl *iis_in_dec = NULL;
|
||||
|
||||
// ********************** iis in 驱动 ************************* //
|
||||
static void iis_in_dec_resume(void)
|
||||
{
|
||||
if (iis_in_dec) {
|
||||
audio_decoder_resume(&iis_in_dec->decoder);
|
||||
}
|
||||
}
|
||||
|
||||
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
|
||||
{
|
||||
s16 pcm_L;
|
||||
s16 pcm_R;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < points_len; i++, pcm_lr += 2) {
|
||||
pcm_L = *pcm_lr;
|
||||
pcm_R = *(pcm_lr + 1);
|
||||
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void iis_in_data_handler(void *priv, void *_data, int len)
|
||||
{
|
||||
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)priv;
|
||||
s16 *data = (s16 *)_data;
|
||||
u16 temp_len = len;
|
||||
int wlen = 0;
|
||||
|
||||
if (iis_in_dec->start == 0) {
|
||||
goto __exit;
|
||||
}
|
||||
//iis 默认输入的是双声道数据
|
||||
if (iis_in_dec->output_ch == 1) {
|
||||
s16 *mono_data = data;
|
||||
for (int i = 0; i < len / 4; i++) {
|
||||
mono_data[i] = mono_data[i * 2];
|
||||
}
|
||||
len = len / 2;
|
||||
wlen = cbuf_write(&iis_in->cbuf, mono_data, len);
|
||||
if (wlen != len) {
|
||||
putchar('w');
|
||||
}
|
||||
} else if (iis_in_dec->output_ch == 2) {
|
||||
wlen = cbuf_write(&iis_in->cbuf, data, len);
|
||||
/* os_sem_post(&iis_in->sem); */
|
||||
if (wlen != len) {
|
||||
putchar('W');
|
||||
}
|
||||
} else {
|
||||
putchar('e');
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
if (iis_in_dec && iis_in_dec->need_resume) {
|
||||
iis_in_dec->need_resume = 0;
|
||||
iis_in_dec_resume();
|
||||
}
|
||||
__exit:
|
||||
alink_set_shn(&alink0_platform_data.ch_cfg[1], temp_len / 4);
|
||||
}
|
||||
|
||||
static void *iis_in_open(int sr)
|
||||
{
|
||||
struct iis_in_sample_hdl *iis_in = NULL;
|
||||
iis_in = zalloc(sizeof(struct iis_in_sample_hdl));
|
||||
if (!iis_in) {
|
||||
return NULL;
|
||||
}
|
||||
iis_in->store_pcm_buf = malloc(IIS_IN_STORE_PCM_SIZE);
|
||||
if (!iis_in->store_pcm_buf) {
|
||||
free(iis_in);
|
||||
return NULL;
|
||||
}
|
||||
cbuf_init(&iis_in->cbuf, iis_in->store_pcm_buf, IIS_IN_STORE_PCM_SIZE);
|
||||
iis_in->hw_alink = (ALINK_PARM *)get_iis_alink_param();
|
||||
if (iis_in->hw_alink == NULL) {
|
||||
iis_in->hw_alink = alink_init(&alink0_platform_data);
|
||||
}
|
||||
iis_in->alink_ch = alink_channel_init(iis_in->hw_alink, 1, ALINK_DIR_RX, (void *)iis_in, iis_in_data_handler);
|
||||
alink_start(iis_in->hw_alink);
|
||||
iis_in->sample_rate = sr;
|
||||
return iis_in;
|
||||
}
|
||||
|
||||
|
||||
// *********************** iis in dec 解码 ***************************//
|
||||
static int iis_in_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
|
||||
{
|
||||
int rlen = 0;
|
||||
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
|
||||
if (!iis_in || iis_in_dec->start == 0) {
|
||||
goto __exit;
|
||||
}
|
||||
if (!iis_in->store_pcm_buf) {
|
||||
goto __exit;
|
||||
}
|
||||
int read_len = cbuf_get_data_size(&iis_in->cbuf);
|
||||
if (read_len) {
|
||||
read_len = read_len > len ? len : read_len;
|
||||
rlen = cbuf_read(&iis_in->cbuf, buf, read_len);
|
||||
/* printf("--- rlen : %d\n", rlen); */
|
||||
}
|
||||
__exit:
|
||||
if (!rlen) {
|
||||
iis_in_dec->need_resume = 1;
|
||||
return -1;
|
||||
}
|
||||
/* y_printf("--- rlen = %d\n",rlen); */
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static int iis_in_dec_probe_handler(struct audio_decoder *decoder)
|
||||
{
|
||||
/* struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder); */
|
||||
struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iis_in_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
|
||||
{
|
||||
struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
|
||||
|
||||
if (!dec) {
|
||||
return 0;
|
||||
}
|
||||
int rlen = len;
|
||||
int wlen = 0;
|
||||
|
||||
if (!dec->remain) {
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_run(MUSIC_DVOL, data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
|
||||
if (!wlen) {
|
||||
putchar('w');
|
||||
}
|
||||
rlen -= wlen;
|
||||
|
||||
if (rlen == 0) {
|
||||
dec->remain = 0;
|
||||
} else {
|
||||
dec->remain = 1;
|
||||
}
|
||||
return len - rlen;
|
||||
}
|
||||
|
||||
static const struct audio_dec_handler iis_in_dec_handler = {
|
||||
.dec_probe = iis_in_dec_probe_handler,
|
||||
.dec_output = iis_in_dec_output_handler,
|
||||
};
|
||||
|
||||
static const struct audio_dec_input iis_input = {
|
||||
.coding_type = AUDIO_CODING_PCM,
|
||||
.data_type = AUDIO_INPUT_FILE,
|
||||
.ops = {
|
||||
.file = {
|
||||
.fread = iis_in_stream_read,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static void iis_in_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
|
||||
{
|
||||
switch (argv[0]) {
|
||||
case AUDIO_DEC_EVENT_END:
|
||||
/*pcm_audio_close();*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//开始 iis dec 解码
|
||||
static int iis_in_dec_start(void)
|
||||
{
|
||||
int err;
|
||||
y_printf(">>>>>>>> Enter Func: %s \n", __func__);
|
||||
struct audio_fmt f = {0};
|
||||
struct iis_in_dec_hdl *dec = iis_in_dec;
|
||||
|
||||
if (!iis_in_dec && iis_in_dec->start == 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = audio_decoder_open(&dec->decoder, &iis_input, &decode_task);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
if (dec->iis_in == NULL) {
|
||||
y_printf("--> %s, %d, Init iis_in!\n", __func__, __LINE__);
|
||||
dec->iis_in = iis_in_open(dec->sample_rate);
|
||||
if (!dec->iis_in) {
|
||||
goto __err;
|
||||
}
|
||||
}
|
||||
|
||||
audio_decoder_set_handler(&dec->decoder, &iis_in_dec_handler);
|
||||
audio_decoder_set_event_handler(&dec->decoder, iis_in_dec_event_handler, 0);
|
||||
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
|
||||
if (dac_conn == DAC_OUTPUT_LR) {
|
||||
dec->output_ch = 2;
|
||||
} else {
|
||||
dec->output_ch = 1;
|
||||
}
|
||||
|
||||
f.coding_type = AUDIO_CODING_PCM;
|
||||
f.sample_rate = dec->sample_rate;
|
||||
f.channel = dec->output_ch;
|
||||
|
||||
sound_pcm_dev_channel_mapping(dec->output_ch);
|
||||
|
||||
err = audio_decoder_set_fmt(&dec->decoder, &f);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
|
||||
#endif
|
||||
|
||||
// 设置叠加功能
|
||||
audio_mixer_ch_open(&dec->mix_ch, &mixer);
|
||||
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
|
||||
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||||
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 1);
|
||||
|
||||
err = audio_decoder_start(&dec->decoder);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
/* audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption); */
|
||||
dec->start = 1;
|
||||
return 0;
|
||||
|
||||
__err:
|
||||
return err;
|
||||
}
|
||||
|
||||
// iis in 解码资源等待
|
||||
void iis_in_dec_stop(void);
|
||||
|
||||
static int iis_in_wait_res_handler(struct audio_res_wait *wait, int event)
|
||||
{
|
||||
int err = 0;
|
||||
if (event == AUDIO_RES_GET) {
|
||||
// 启动解码
|
||||
err = iis_in_dec_start();
|
||||
} else if (event == AUDIO_RES_PUT) {
|
||||
// 被打断
|
||||
iis_in_dec_stop();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int iis_in_dec_open(void)
|
||||
{
|
||||
int err;
|
||||
struct iis_in_dec_hdl *dec = NULL;;
|
||||
dec = zalloc(sizeof(*dec));
|
||||
if (!dec) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
iis_in_dec = dec;
|
||||
dec->sample_rate = TCFG_IIS_SR;
|
||||
dec->channel = 2; //iis 是双声道数据
|
||||
dec->wait.priority = 2;
|
||||
dec->wait.preemption = 1;
|
||||
dec->wait.handler = iis_in_wait_res_handler;
|
||||
|
||||
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
|
||||
clock_add(DEC_PCM_CLK);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void iis_in_dec_stop(void)
|
||||
{
|
||||
if (iis_in_dec && iis_in_dec->start == 1) {
|
||||
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
|
||||
iis_in_dec->start = 0;
|
||||
audio_decoder_close(&iis_in_dec->decoder);
|
||||
audio_mixer_ch_close(&iis_in_dec->mix_ch);
|
||||
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_close(MUSIC_DVOL);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
|
||||
local_irq_disable();
|
||||
#if 1
|
||||
if (iis_in) {
|
||||
void *alink_p = (ALINK_PARM *)get_iis_alink_param();
|
||||
if (iis_in->hw_alink && !alink_p) {
|
||||
alink_uninit(iis_in->hw_alink);
|
||||
iis_in->hw_alink = NULL;
|
||||
} else {
|
||||
/* alink_uninit(iis_in->hw_alink); */
|
||||
alink_channel_close(iis_in->alink_ch);
|
||||
}
|
||||
if (iis_in->store_pcm_buf) {
|
||||
free(iis_in->store_pcm_buf);
|
||||
iis_in->store_pcm_buf = NULL;
|
||||
}
|
||||
free(iis_in);
|
||||
iis_in = NULL;
|
||||
iis_in_dec->iis_in = NULL;
|
||||
}
|
||||
#endif
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
void iis_in_dec_close(void)
|
||||
{
|
||||
if (!iis_in_dec) {
|
||||
return;
|
||||
}
|
||||
iis_in_dec_stop();
|
||||
audio_decoder_task_del_wait(&decode_task, &iis_in_dec->wait);
|
||||
clock_remove(DEC_PCM_CLK);
|
||||
local_irq_disable();
|
||||
free(iis_in_dec);
|
||||
iis_in_dec = NULL;
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
9
cpu/br28/audio_dec/audio_dec_iis.h
Normal file
9
cpu/br28/audio_dec/audio_dec_iis.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __AUDIO_DEC_IIS_H
|
||||
#define __AUDIO_DEC_IIS_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
921
cpu/br28/audio_dec/audio_dec_pc.c
Normal file
921
cpu/br28/audio_dec/audio_dec_pc.c
Normal file
@ -0,0 +1,921 @@
|
||||
#include "uac_stream.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_decoder.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "audio_enc.h"
|
||||
#include "application/audio_eq.h"
|
||||
#include "application/audio_drc.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "audio_dec.h"
|
||||
#include "app_main.h"
|
||||
#include "clock_cfg.h"
|
||||
#include "audio_dec_eff.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "audio_dvol.h"
|
||||
#include "sound_device.h"
|
||||
|
||||
#if TCFG_UI_ENABLE
|
||||
#include "ui/ui_api.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_PC_ENABLE//TCFG_APP_PC_EN
|
||||
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
|
||||
#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_SBC
|
||||
#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
|
||||
#else
|
||||
#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_MP3
|
||||
#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
|
||||
#endif
|
||||
|
||||
struct usb_audio_handle {
|
||||
int top_size;
|
||||
int bottom_size;
|
||||
int begin_size;
|
||||
};
|
||||
|
||||
#define RATE_INC_STEP 2
|
||||
#define RATE_DEC_STEP 2
|
||||
|
||||
|
||||
struct uac_dec_hdl {
|
||||
struct audio_decoder decoder;
|
||||
struct audio_res_wait wait;
|
||||
struct audio_mixer_ch mix_ch;
|
||||
int begin_size;
|
||||
int top_size;
|
||||
int bottom_size;
|
||||
u8 start;
|
||||
u8 channel;
|
||||
u8 output_ch;
|
||||
u8 sync_start;
|
||||
u32 src_out_sr;
|
||||
u32 dec_no_out_sound : 1; // 解码不直接输出声音(用于TWS转发)
|
||||
u32 sample_rate;
|
||||
u32 audio_new_rate;
|
||||
u32 usb_audio_max_speed;
|
||||
u32 usb_audio_min_speed;
|
||||
struct audio_src_handle *src_sync;
|
||||
u8 remain;
|
||||
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
|
||||
struct dec_eq_drc *eq_drc;
|
||||
#endif
|
||||
|
||||
|
||||
struct user_audio_parm *user_hdl;
|
||||
|
||||
|
||||
u32 cnt: 8;
|
||||
|
||||
u32 state: 1;
|
||||
|
||||
int check_data_timer;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
extern struct audio_decoder_task decode_task;
|
||||
extern struct audio_mixer mixer;
|
||||
|
||||
static u16 sys_event_id = 0;
|
||||
static struct uac_dec_hdl *uac_dec = NULL;
|
||||
|
||||
static u8 uac_dec_maigc = 0;
|
||||
|
||||
|
||||
extern void uac_get_cur_vol(const u8 id, u16 *l_vol, u16 *r_vol);
|
||||
extern u8 uac_get_mute(void);
|
||||
extern void bt_tws_sync_volume();
|
||||
|
||||
void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt);
|
||||
void pc_eq_drc_close(struct uac_dec_hdl *dec);
|
||||
|
||||
int uac_vol_switch(int vol)
|
||||
{
|
||||
u16 valsum = vol * (SYS_MAX_VOL + 1) / 100;
|
||||
|
||||
if (valsum > SYS_MAX_VOL) {
|
||||
valsum = SYS_MAX_VOL;
|
||||
}
|
||||
return valsum;
|
||||
}
|
||||
|
||||
static void uac_dec_set_output_channel(struct uac_dec_hdl *dec)
|
||||
{
|
||||
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
|
||||
|
||||
if (dac_conn == DAC_OUTPUT_LR) {
|
||||
dec->output_ch = 2;
|
||||
} else {
|
||||
|
||||
dec->output_ch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int uac_sync_output_handler(void *priv, void *buf, int len)
|
||||
{
|
||||
struct uac_dec_hdl *dec = (struct uac_dec_hdl *)priv;
|
||||
int remain_len = len;
|
||||
int wlen = 0;
|
||||
s16 *data = (s16 *)buf;
|
||||
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
if (dec->dec_no_out_sound) {
|
||||
return pcm2tws_enc_output(NULL, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
|
||||
return wlen;
|
||||
}
|
||||
|
||||
|
||||
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
|
||||
{
|
||||
s16 pcm_L;
|
||||
s16 pcm_R;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < points_len; i++, pcm_lr += 2) {
|
||||
pcm_L = *pcm_lr;
|
||||
pcm_R = *(pcm_lr + 1);
|
||||
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uac_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
|
||||
{
|
||||
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
|
||||
int rlen = len;
|
||||
int wlen = 0;
|
||||
|
||||
|
||||
/* if (dec->channel == 2 && dec->output_ch == 1) { //这里 */
|
||||
|
||||
/* pcm_LR_to_mono((s16 *)data, (s16 *)data, len >> 2); //这里有双声道转单声道 */
|
||||
/* len >>= 1; */
|
||||
/* } */
|
||||
|
||||
|
||||
if (!dec->remain) {
|
||||
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
|
||||
if (dec->user_hdl) {
|
||||
u8 ch_num = dec->output_ch;
|
||||
user_audio_process_handler_run(dec->user_hdl, data, len, ch_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_run(MUSIC_DVOL, data, len);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
}
|
||||
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
|
||||
if (dec->eq_drc && dec->eq_drc->async) {
|
||||
int eqlen = eq_drc_run(dec->eq_drc, data, len);
|
||||
len -= eqlen;
|
||||
if (len == 0) {
|
||||
dec->remain = 0;
|
||||
} else {
|
||||
dec->remain = 1;
|
||||
}
|
||||
return eqlen;
|
||||
}
|
||||
|
||||
if (!dec->remain) {
|
||||
eq_drc_run(dec->eq_drc, data, len);
|
||||
}
|
||||
#endif//TCFG_PC_MODE_EQ_ENABLE
|
||||
|
||||
if (dec->src_sync) {
|
||||
wlen = audio_src_resample_write(dec->src_sync, data, rlen);
|
||||
/*printf("%d - %d\n", len, wlen);*/
|
||||
/* return wlen; */
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
} else if (dec->dec_no_out_sound) {
|
||||
wlen = pcm2tws_enc_output(NULL, data, rlen);
|
||||
#endif
|
||||
} else {
|
||||
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
|
||||
}
|
||||
|
||||
rlen -= wlen;
|
||||
|
||||
if (rlen == 0) {
|
||||
dec->remain = 0;
|
||||
} else {
|
||||
dec->remain = 1;
|
||||
}
|
||||
|
||||
|
||||
return len - rlen;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 检测uac是否收到数据,没数据时暂停mix_ch
|
||||
@param *priv: 私有参数
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static void audio_pc_check_timer(void *priv)
|
||||
{
|
||||
#if 1
|
||||
u8 alive = uac_speaker_get_alive();
|
||||
if (alive) {
|
||||
uac_dec->cnt++;
|
||||
if (uac_dec->cnt > 5) {
|
||||
if (!uac_dec->state) {
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
if (uac_dec->pcm_dec.dec_no_out_sound) {
|
||||
localtws_decoder_pause(1);
|
||||
}
|
||||
#endif
|
||||
audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
|
||||
audio_decoder_resume_all(&decode_task);
|
||||
uac_dec->state = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (uac_dec->cnt) {
|
||||
uac_dec->cnt--;
|
||||
}
|
||||
if (uac_dec->state) {
|
||||
uac_dec->state = 0;
|
||||
uac_dec->cnt = 0;
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
if (uac_dec->pcm_dec.dec_no_out_sound) {
|
||||
localtws_decoder_pause(0);
|
||||
}
|
||||
#endif
|
||||
audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
|
||||
audio_decoder_resume_all(&decode_task);
|
||||
}
|
||||
}
|
||||
uac_speaker_set_alive(1);
|
||||
#else
|
||||
static u8 cnt = 0;
|
||||
if (uac_speaker_stream_size(NULL) == 0) {
|
||||
if (cnt < 20) {
|
||||
cnt++;
|
||||
}
|
||||
if (cnt == 15) {
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
if (uac_dec->pcm_dec.dec_no_out_sound) {
|
||||
localtws_decoder_pause(1);
|
||||
}
|
||||
#endif
|
||||
audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
|
||||
audio_decoder_resume_all(&decode_task);
|
||||
}
|
||||
} else {
|
||||
if (cnt > 14) {
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
if (uac_dec->pcm_dec.dec_no_out_sound) {
|
||||
localtws_decoder_pause(0);
|
||||
}
|
||||
#endif
|
||||
audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
|
||||
audio_decoder_resume_all(&decode_task);
|
||||
}
|
||||
cnt = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int uac_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
|
||||
{
|
||||
int rlen = 0;
|
||||
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
|
||||
|
||||
if (!dec->sync_start) {
|
||||
if (uac_speaker_stream_size() < dec->begin_size) {
|
||||
return -1;
|
||||
}
|
||||
dec->sync_start = 1;
|
||||
}
|
||||
|
||||
|
||||
rlen = uac_speaker_read(NULL, (void *)buf, len);
|
||||
|
||||
if (dec->channel == 2 && dec->output_ch == 1) {
|
||||
pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2);
|
||||
rlen >>= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!rlen) {
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static const struct audio_dec_input uac_input = {
|
||||
.coding_type = AUDIO_CODING_PCM,
|
||||
.data_type = AUDIO_INPUT_FILE,
|
||||
.ops = {
|
||||
.file = {
|
||||
.fread = uac_stream_read,
|
||||
/*.fseek = uac_stream_seek,*/
|
||||
/*.flen = uac_stream_len,*/
|
||||
}
|
||||
}
|
||||
};
|
||||
int uac_speaker_stream_sample_rate(void);
|
||||
static int usb_audio_stream_sync(struct uac_dec_hdl *dec, int data_size)
|
||||
{
|
||||
if (!dec->src_sync) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
//优化下行播放同步得调节步进
|
||||
|
||||
u32 in_sr = uac_speaker_stream_sample_rate();
|
||||
|
||||
u32 out_sr = (long long)dec->audio_new_rate * (long long)in_sr / dec->sample_rate; //统计得输入采样率,转换成输出采样率
|
||||
|
||||
|
||||
if (data_size < dec->bottom_size) {
|
||||
out_sr += out_sr * 5 / 10000;
|
||||
/* putchar('+'); */
|
||||
}
|
||||
|
||||
if (data_size > dec->top_size) {
|
||||
out_sr -= out_sr * 5 / 10000;
|
||||
/* putchar('-'); */
|
||||
}
|
||||
|
||||
if (out_sr != dec->audio_new_rate) {
|
||||
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, out_sr);
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
u32 sr = dec->audio_new_rate;
|
||||
|
||||
if (data_size < dec->bottom_size) {
|
||||
dec->audio_new_rate += RATE_INC_STEP;
|
||||
/*printf("rate inc\n");*/
|
||||
}
|
||||
|
||||
if (data_size > dec->top_size) {
|
||||
dec->audio_new_rate -= RATE_DEC_STEP;
|
||||
/*printf("rate dec : %d\n", __this->audio_new_rate);*/
|
||||
}
|
||||
|
||||
if (dec->audio_new_rate < dec->usb_audio_min_speed) {
|
||||
dec->audio_new_rate = dec->usb_audio_min_speed;
|
||||
} else if (dec->audio_new_rate > dec->usb_audio_max_speed) {
|
||||
dec->audio_new_rate = dec->usb_audio_max_speed;
|
||||
}
|
||||
|
||||
if (sr != dec->audio_new_rate) {
|
||||
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uac_dec_probe_handler(struct audio_decoder *decoder)
|
||||
{
|
||||
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
|
||||
int err = 0;
|
||||
|
||||
#if 0
|
||||
if (!dec->sync_start) {
|
||||
if (uac_speaker_stream_size() > dec->begin_size) {
|
||||
dec->sync_start = 1;
|
||||
return 0;
|
||||
} else {
|
||||
os_time_dly(2);
|
||||
audio_decoder_suspend(&dec->decoder, 0);
|
||||
/* audio_decoder_resume(&dec->decoder); */
|
||||
/* return 0;//临时 */
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!dec->sync_start) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
if (dec->dec_no_out_sound) {
|
||||
// localtws同步有微调处理
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
usb_audio_stream_sync(dec, uac_speaker_stream_size());
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct audio_dec_handler uac_dec_handler = {
|
||||
.dec_probe = uac_dec_probe_handler,
|
||||
.dec_output = uac_dec_output_handler,
|
||||
};
|
||||
|
||||
static int uac_audio_sync_init(struct uac_dec_hdl *dec)
|
||||
{
|
||||
dec->sync_start = 0;
|
||||
dec->begin_size = uac_speaker_stream_length() * 60 / 100;
|
||||
dec->top_size = uac_speaker_stream_length() * 70 / 100;
|
||||
dec->bottom_size = uac_speaker_stream_length() * 40 / 100;
|
||||
|
||||
dec->audio_new_rate = dec->src_out_sr;//audio_output_rate(dec->sample_rate);
|
||||
printf("out_sr:%d, dsr:%d, \n", dec->audio_new_rate, dec->sample_rate);
|
||||
dec->usb_audio_max_speed = dec->audio_new_rate + 50;
|
||||
dec->usb_audio_min_speed = dec->audio_new_rate - 50;
|
||||
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
if (dec->dec_no_out_sound) {
|
||||
if (dec->audio_new_rate == dec->sample_rate) {
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
dec->src_sync = zalloc(sizeof(struct audio_src_handle));
|
||||
if (!dec->src_sync) {
|
||||
return -ENODEV;
|
||||
}
|
||||
audio_hw_src_open(dec->src_sync, dec->output_ch, SRC_TYPE_RESAMPLE);
|
||||
|
||||
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
|
||||
|
||||
audio_src_set_output_handler(dec->src_sync, dec, uac_sync_output_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uac_audio_sync_release(struct uac_dec_hdl *dec)
|
||||
{
|
||||
if (dec->src_sync) {
|
||||
audio_hw_src_stop(dec->src_sync);
|
||||
audio_hw_src_close(dec->src_sync);
|
||||
local_irq_disable();
|
||||
free(dec->src_sync);
|
||||
dec->src_sync = NULL;
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uac_audio_close(void)
|
||||
{
|
||||
if (!uac_dec || !uac_dec->start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uac_dec->start = 0;
|
||||
uac_dec->sync_start = 0;
|
||||
|
||||
if (uac_dec->check_data_timer) {
|
||||
sys_hi_timer_del(uac_dec->check_data_timer);
|
||||
}
|
||||
|
||||
audio_decoder_close(&uac_dec->decoder);
|
||||
uac_audio_sync_release(uac_dec);
|
||||
if (!uac_dec->dec_no_out_sound) {
|
||||
audio_mixer_ch_close(&uac_dec->mix_ch);
|
||||
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
|
||||
}
|
||||
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
if (uac_dec->dec_no_out_sound) {
|
||||
uac_dec->dec_no_out_sound = 0;
|
||||
pcm2tws_enc_close();
|
||||
encfile_tws_dec_close();
|
||||
local_tws_stop();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
pc_eq_drc_close(uac_dec);
|
||||
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
|
||||
if (uac_dec->user_hdl) {
|
||||
user_audio_process_close(uac_dec->user_hdl);
|
||||
uac_dec->user_hdl = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_close(MUSIC_DVOL);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
|
||||
|
||||
/* 此处不进行clock_del,改为在usb_audio_demo_exit后 */
|
||||
/* 由于usb_audio_mic_close前adc中断还会不断唤醒usb_audio_mic_write_task */
|
||||
/* 降低时钟会导致系统跑不过来 */
|
||||
/* audio_codec_clock_del(AUDIO_PC_MODE); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uac_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
|
||||
{
|
||||
switch (argv[0]) {
|
||||
case AUDIO_DEC_EVENT_END:
|
||||
puts("USB AUDIO_DEC_EVENT_END\n");
|
||||
if ((u8)argv[1] != (u8)(uac_dec_maigc - 1)) {
|
||||
log_i("maigc err, %s\n", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
/*uac_audio_close();*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uac_audio_start(void)
|
||||
{
|
||||
int err;
|
||||
struct audio_fmt f = {0};
|
||||
struct uac_dec_hdl *dec = uac_dec;
|
||||
|
||||
if (!uac_dec) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = audio_decoder_open(&dec->decoder, &uac_input, &decode_task);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
audio_decoder_set_handler(&dec->decoder, &uac_dec_handler);
|
||||
audio_decoder_set_event_handler(&dec->decoder, uac_dec_event_handler, uac_dec_maigc++);
|
||||
|
||||
|
||||
uac_dec_set_output_channel(dec);
|
||||
|
||||
f.coding_type = AUDIO_CODING_PCM;
|
||||
f.sample_rate = dec->sample_rate;
|
||||
f.channel = dec->output_ch;
|
||||
|
||||
sound_pcm_dev_channel_mapping(dec->output_ch);
|
||||
|
||||
err = audio_decoder_set_fmt(&dec->decoder, &f);
|
||||
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
dec->dec_no_out_sound = 0;
|
||||
if (dec2tws_check_enable() == true) {
|
||||
audio_decoder_set_output_channel(&dec->decoder, UAC_DEC_PCM_ENC_CHANNEL);
|
||||
dec->output_ch = AUDIO_CH_IS_MONO(UAC_DEC_PCM_ENC_CHANNEL) ? 1 : 2;;
|
||||
struct audio_fmt enc_fmt = {0};
|
||||
enc_fmt.coding_type = UAC_DEC_PCM_ENC_TYPE;
|
||||
enc_fmt.bit_rate = 128;
|
||||
enc_fmt.channel = dec->output_ch;
|
||||
enc_fmt.sample_rate = audio_output_rate(dec->sample_rate);//dec->decoder.fmt.sample_rate;
|
||||
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
|
||||
#endif
|
||||
|
||||
int ret = pcm2tws_enc_open(&enc_fmt);
|
||||
if (ret == 0) {
|
||||
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
|
||||
pcm2tws_enc_set_output_handler(local_tws_output);
|
||||
#else
|
||||
pcm2tws_enc_set_output_handler(encfile_tws_wfile);
|
||||
ret = encfile_tws_dec_open(&enc_fmt);
|
||||
#endif
|
||||
if (ret == 0) {
|
||||
dec->dec_no_out_sound = 1;
|
||||
pcm2tws_enc_set_resume_handler(uac_dec_resume);
|
||||
audio_decoder_task_del_wait(&decode_task, &dec->wait);
|
||||
local_tws_start(&enc_fmt);
|
||||
audio_decoder_set_run_max(&dec->decoder, 20);
|
||||
dec->src_out_sr = enc_fmt.sample_rate;
|
||||
goto __dec_start;
|
||||
} else {
|
||||
pcm2tws_enc_close();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
|
||||
// 设置叠加功能
|
||||
audio_mixer_ch_open(&dec->mix_ch, &mixer);
|
||||
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
|
||||
|
||||
|
||||
dec->src_out_sr = audio_output_rate(f.sample_rate);
|
||||
|
||||
__dec_start:
|
||||
uac_audio_sync_init(dec);
|
||||
pc_eq_drc_open(dec, &f);
|
||||
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
|
||||
|
||||
u16 l_volume, r_volume;
|
||||
|
||||
uac_get_cur_vol(0, &l_volume, &r_volume);
|
||||
u8 vol = uac_vol_switch(l_volume);
|
||||
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
|
||||
|
||||
|
||||
|
||||
#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
|
||||
bt_tws_sync_volume();
|
||||
#endif
|
||||
|
||||
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
|
||||
struct user_audio_digital_parm vol_parm = {0};
|
||||
#if (defined(USER_DIGITAL_VOLUME_ADJUST_ENABLE) && (USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0))
|
||||
vol_parm.en = true;
|
||||
vol_parm.vol = app_audio_get_volume(APP_AUDIO_CURRENT_STATE);
|
||||
vol_parm.vol_max = app_audio_get_max_volume();
|
||||
vol_parm.fade_step = 2;
|
||||
#endif
|
||||
dec->user_hdl = user_audio_process_open((void *)&vol_parm, NULL, NULL);
|
||||
#endif
|
||||
|
||||
err = audio_decoder_start(&dec->decoder);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
dec->state = 0;
|
||||
dec->cnt = 0;
|
||||
dec->check_data_timer = sys_hi_timer_add(NULL, audio_pc_check_timer, 10);
|
||||
audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
|
||||
dec->start = 1;
|
||||
return 0;
|
||||
|
||||
__err:
|
||||
|
||||
pc_eq_drc_close(dec);
|
||||
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
|
||||
if (dec->user_hdl) {
|
||||
user_audio_process_close(dec->user_hdl);
|
||||
dec->user_hdl = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int uac_wait_res_handler(struct audio_res_wait *wait, int event)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (event == AUDIO_RES_GET) {
|
||||
err = uac_audio_start();
|
||||
} else if (event == AUDIO_RES_PUT) {
|
||||
uac_audio_close();
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void uac_speaker_stream_rx_handler(int event, void *data, int len)
|
||||
{
|
||||
if (uac_dec) {
|
||||
audio_decoder_resume(&uac_dec->decoder);
|
||||
}
|
||||
}
|
||||
|
||||
extern struct uac_stream_info *puac_speaker_info;
|
||||
static int usb_audio_play_open(void *_info)
|
||||
{
|
||||
struct uac_dec_hdl *dec;
|
||||
|
||||
if (uac_dec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dec = zalloc(sizeof(*dec));
|
||||
if (!dec) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
uac_dec = dec;
|
||||
|
||||
dec->sample_rate = (u32)_info & 0xFFFFFF;
|
||||
dec->channel = (u32)_info >> 24;
|
||||
printf("usb_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
|
||||
set_uac_speaker_rx_handler(dec, uac_speaker_stream_rx_handler);
|
||||
dec->wait.priority = 2;
|
||||
dec->wait.preemption = 1;
|
||||
dec->wait.handler = uac_wait_res_handler;
|
||||
audio_decoder_task_add_wait(&decode_task, &dec->wait);
|
||||
|
||||
clock_add(DEC_PCM_CLK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_audio_play_close(void *arg)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!uac_dec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uac_dec->start) {
|
||||
uac_audio_close();
|
||||
}
|
||||
|
||||
|
||||
audio_decoder_task_del_wait(&decode_task, &uac_dec->wait);
|
||||
|
||||
clock_remove(DEC_PCM_CLK);
|
||||
|
||||
local_irq_disable();
|
||||
free(uac_dec);
|
||||
uac_dec = NULL;
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uac_dec_restart(int magic)
|
||||
{
|
||||
if ((!uac_dec) || (magic != uac_dec_maigc)) {
|
||||
return -1;
|
||||
}
|
||||
int _info = (uac_dec->channel << 24) | uac_dec->sample_rate;
|
||||
usb_audio_play_close(NULL);
|
||||
int err = usb_audio_play_open((void *)_info);
|
||||
return err;
|
||||
}
|
||||
|
||||
int uac_dec_push_restart(void)
|
||||
{
|
||||
if (!uac_dec) {
|
||||
return false;
|
||||
}
|
||||
int argv[3];
|
||||
argv[0] = (int)uac_dec_restart;
|
||||
argv[1] = 1;
|
||||
argv[2] = (int)uac_dec_maigc;
|
||||
os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
|
||||
return true;
|
||||
}
|
||||
|
||||
void uac_dec_resume(void)
|
||||
{
|
||||
if (uac_dec && (uac_dec->start)) {
|
||||
audio_decoder_resume(&uac_dec->decoder);
|
||||
}
|
||||
}
|
||||
int uac_dec_no_out_sound(void)
|
||||
{
|
||||
if (uac_dec && uac_dec->dec_no_out_sound) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
extern int usb_audio_mic_open(void *_info);
|
||||
extern int usb_audio_mic_close(void *arg);
|
||||
extern void usb_audio_mic_set_gain(int gain);
|
||||
|
||||
static int usb_device_event_handler(u8 event, int value)
|
||||
{
|
||||
switch (event) {
|
||||
case USB_AUDIO_PLAY_OPEN:
|
||||
/*tone_play_stop();*/
|
||||
usb_audio_play_open((void *)value);
|
||||
break;
|
||||
case USB_AUDIO_PLAY_CLOSE:
|
||||
usb_audio_play_close((void *)value);
|
||||
break;
|
||||
case USB_AUDIO_MIC_OPEN:
|
||||
usb_audio_mic_open((void *)value);
|
||||
break;
|
||||
case USB_AUDIO_MIC_CLOSE:
|
||||
usb_audio_mic_close((void *)value);
|
||||
break;
|
||||
case USB_AUDIO_SET_MIC_VOL:
|
||||
usb_audio_mic_set_gain(value);
|
||||
break;
|
||||
case USB_AUDIO_SET_PLAY_VOL:
|
||||
|
||||
value = uac_vol_switch(value & 0xffff); //left ch volume
|
||||
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, value, 1);
|
||||
#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
|
||||
bt_tws_sync_volume();
|
||||
#endif
|
||||
|
||||
#if TCFG_UI_ENABLE
|
||||
u8 vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||||
ui_set_tmp_menu(MENU_MAIN_VOL, 1000, vol, NULL);
|
||||
#endif //TCFG_UI_ENABLE
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_audio_event_handler(struct sys_event *event, void *priv)
|
||||
{
|
||||
switch (event->type) {
|
||||
case SYS_DEVICE_EVENT:
|
||||
if ((u32)event->arg == DEVICE_EVENT_FROM_UAC) {
|
||||
log_d("usb device event : %d %x\n", event->u.dev.event, event->u.dev.value);
|
||||
usb_device_event_handler(event->u.dev.event, event->u.dev.value);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
__attribute__((weak))int audio_dev_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_audio_demo_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
audio_dev_init();
|
||||
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_UAC, 2,
|
||||
usb_audio_event_handler);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usb_audio_demo_exit(void)
|
||||
{
|
||||
unregister_sys_event_handler(usb_audio_event_handler);
|
||||
usb_audio_play_close(NULL);
|
||||
usb_audio_mic_close(NULL);
|
||||
audio_codec_clock_del(AUDIO_PC_MODE);
|
||||
}
|
||||
int audio_pc_src_resample_write(void *priv, s16 *data, u32 len)
|
||||
{
|
||||
if (uac_dec && uac_dec->start) { //避免src已经关闭,异步eq 还在输出写src,导致异常
|
||||
return audio_src_resample_write(priv, data, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt)
|
||||
{
|
||||
if (!dec) {
|
||||
return;
|
||||
}
|
||||
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
|
||||
u8 drc_en = 0;
|
||||
#if TCFG_DRC_ENABLE&&TCFG_PC_MODE_DRC_ENABLE
|
||||
drc_en = 1;
|
||||
#endif//TCFG_PC_MODE_DRC_ENABLE
|
||||
|
||||
if (dec->src_sync) {
|
||||
dec->eq_drc = dec_eq_drc_setup(dec->src_sync, (eq_output_cb)audio_pc_src_resample_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
|
||||
} else if (dec->dec_no_out_sound) {
|
||||
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
|
||||
dec->eq_drc = dec_eq_drc_setup(dec->dec_no_out_sound, (eq_output_cb)pcm2tws_enc_output, fmt->sample_rate, dec->output_ch, 1, drc_en);
|
||||
#endif
|
||||
} else {
|
||||
dec->eq_drc = dec_eq_drc_setup(&dec->mix_ch, (eq_output_cb)audio_mixer_ch_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
|
||||
}
|
||||
#endif//TCFG_PC_MODE_EQ_ENABLE
|
||||
|
||||
}
|
||||
|
||||
|
||||
void pc_eq_drc_close(struct uac_dec_hdl *dec)
|
||||
{
|
||||
if (!dec) {
|
||||
return;
|
||||
}
|
||||
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
|
||||
if (dec->eq_drc) {
|
||||
dec_eq_drc_free(dec->eq_drc);
|
||||
dec->eq_drc = NULL;
|
||||
}
|
||||
#endif//TCFG_PC_MODE_EQ_ENABLE
|
||||
|
||||
}
|
||||
#endif /* TCFG_APP_PC_EN */
|
||||
|
||||
286
cpu/br28/audio_dec/audio_dec_pcm.c
Normal file
286
cpu/br28/audio_dec/audio_dec_pcm.c
Normal file
@ -0,0 +1,286 @@
|
||||
#include "app_config.h"
|
||||
#include "audio_decoder.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "audio_enc.h"
|
||||
#include "application/audio_eq.h"
|
||||
#include "application/audio_drc.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "audio_dec.h"
|
||||
#include "app_main.h"
|
||||
#include "clock_cfg.h"
|
||||
#include "audio_dec_eff.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "audio_dvol.h"
|
||||
#include "audio_dec_pcm.h"
|
||||
|
||||
struct pcm_dec_hdl {
|
||||
struct audio_decoder decoder;
|
||||
struct audio_res_wait wait;
|
||||
struct audio_mixer_ch mix_ch;
|
||||
u8 start;
|
||||
u8 remain;
|
||||
u8 channel;
|
||||
u8 output_ch;
|
||||
int sample_rate;
|
||||
int (*pcm_read_cb)(void *, void *, int);
|
||||
};
|
||||
static struct pcm_dec_hdl *pcm_dec = NULL;
|
||||
extern struct audio_decoder_task decode_task;
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
|
||||
|
||||
void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int))
|
||||
{
|
||||
local_irq_disable();
|
||||
if (pcm_dec && pcm_dec->start == 1) {
|
||||
pcm_dec->pcm_read_cb = pcm_read_func;
|
||||
} else {
|
||||
y_printf(">>> %s, %d, pcm_dec set read cb failed!\n", __func__, __LINE__);
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
|
||||
{
|
||||
s16 pcm_L;
|
||||
s16 pcm_R;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < points_len; i++, pcm_lr += 2) {
|
||||
pcm_L = *pcm_lr;
|
||||
pcm_R = *(pcm_lr + 1);
|
||||
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int pcm_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
|
||||
{
|
||||
int rlen = 0;
|
||||
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
|
||||
|
||||
local_irq_disable();
|
||||
if (dec) {
|
||||
if (dec->pcm_read_cb) {
|
||||
rlen = dec->pcm_read_cb(NULL, (void *)buf, len);
|
||||
}
|
||||
if (dec->channel == 2 && dec->output_ch == 1) {
|
||||
/* pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2); */
|
||||
/* rlen >>= 1; */
|
||||
}
|
||||
}
|
||||
local_irq_enable();
|
||||
if (!rlen) {
|
||||
return -1;
|
||||
}
|
||||
return rlen;
|
||||
}
|
||||
|
||||
static const struct audio_dec_input pcm_input = {
|
||||
.coding_type = AUDIO_CODING_PCM,
|
||||
.data_type = AUDIO_INPUT_FILE,
|
||||
.ops = {
|
||||
.file = {
|
||||
.fread = pcm_stream_read,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static int pcm_dec_probe_handler(struct audio_decoder *decoder)
|
||||
{
|
||||
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
|
||||
{
|
||||
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
|
||||
|
||||
if (!dec) {
|
||||
return 0;
|
||||
}
|
||||
int rlen = len;
|
||||
int wlen = 0;
|
||||
|
||||
if (!dec->remain) {
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_run(MUSIC_DVOL, data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
|
||||
if (!wlen) {
|
||||
putchar('w');
|
||||
}
|
||||
rlen -= wlen;
|
||||
|
||||
if (rlen == 0) {
|
||||
dec->remain = 0;
|
||||
} else {
|
||||
dec->remain = 1;
|
||||
}
|
||||
return len - rlen;
|
||||
}
|
||||
|
||||
static const struct audio_dec_handler pcm_dec_handler = {
|
||||
.dec_probe = pcm_dec_probe_handler,
|
||||
.dec_output = pcm_dec_output_handler,
|
||||
};
|
||||
|
||||
static void pcm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
|
||||
{
|
||||
switch (argv[0]) {
|
||||
case AUDIO_DEC_EVENT_END:
|
||||
/*pcm_audio_close();*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void pcm_dec_resume(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
if (pcm_dec && pcm_dec->start) {
|
||||
audio_decoder_resume(&pcm_dec->decoder);
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static int pcm_audio_play_start(void)
|
||||
{
|
||||
int err;
|
||||
y_printf(">>>>>>>> Enter Func: %s \n", __func__);
|
||||
struct audio_fmt f = {0};
|
||||
struct pcm_dec_hdl *dec = pcm_dec;
|
||||
|
||||
if (!pcm_dec) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = audio_decoder_open(&dec->decoder, &pcm_input, &decode_task);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
audio_decoder_set_handler(&dec->decoder, &pcm_dec_handler);
|
||||
audio_decoder_set_event_handler(&dec->decoder, pcm_dec_event_handler, 0);
|
||||
|
||||
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
|
||||
if (dac_conn == DAC_OUTPUT_LR) {
|
||||
dec->output_ch = 2;
|
||||
} else {
|
||||
dec->output_ch = 1;
|
||||
}
|
||||
|
||||
f.coding_type = AUDIO_CODING_PCM;
|
||||
f.sample_rate = dec->sample_rate;
|
||||
f.channel = dec->output_ch;
|
||||
|
||||
err = audio_decoder_set_fmt(&dec->decoder, &f);
|
||||
|
||||
printf(">>>>>>>> %s, dec->output_ch : %d\n", __func__, dec->output_ch);
|
||||
|
||||
#if TCFG_AUDIO_OUTPUT_IIS
|
||||
sound_pcm_dev_channel_mapping(dec->output_ch);
|
||||
#endif
|
||||
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
|
||||
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
|
||||
// 设置叠加功能
|
||||
audio_mixer_ch_open(&dec->mix_ch, &mixer);
|
||||
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
|
||||
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||||
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
|
||||
|
||||
err = audio_decoder_start(&dec->decoder);
|
||||
if (err) {
|
||||
goto __err;
|
||||
}
|
||||
audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
|
||||
dec->start = 1;
|
||||
return 0;
|
||||
|
||||
__err:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pcm_audio_play_stop(void)
|
||||
{
|
||||
if (!pcm_dec || !pcm_dec->start) {
|
||||
return 0;
|
||||
}
|
||||
pcm_dec->start = 0;
|
||||
audio_decoder_close(&pcm_dec->decoder);
|
||||
audio_mixer_ch_close(&pcm_dec->mix_ch);
|
||||
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
|
||||
audio_digital_vol_close(MUSIC_DVOL);
|
||||
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcm_wait_res_handler(struct audio_res_wait *wait, int event)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (event == AUDIO_RES_GET) {
|
||||
err = pcm_audio_play_start();
|
||||
} else if (event == AUDIO_RES_PUT) {
|
||||
/* pcm_audio_play_stop(); */
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int pcm_audio_play_open(int sr, u8 ch)
|
||||
{
|
||||
struct pcm_dec_hdl *dec;
|
||||
|
||||
if (pcm_dec) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dec = zalloc(sizeof(*dec));
|
||||
if (!dec) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pcm_dec = dec;
|
||||
|
||||
dec->sample_rate = sr;
|
||||
dec->channel = ch;
|
||||
y_printf(">>> pcm_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
|
||||
dec->wait.priority = 2;
|
||||
dec->wait.preemption = 1;
|
||||
dec->wait.handler = pcm_wait_res_handler;
|
||||
audio_decoder_task_add_wait(&decode_task, &dec->wait);
|
||||
|
||||
clock_add(DEC_PCM_CLK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pcm_audio_play_close(void)
|
||||
{
|
||||
if (!pcm_dec) {
|
||||
return;
|
||||
}
|
||||
pcm_audio_play_stop();
|
||||
audio_decoder_task_del_wait(&decode_task, &pcm_dec->wait);
|
||||
clock_remove(DEC_PCM_CLK);
|
||||
local_irq_disable();
|
||||
free(pcm_dec);
|
||||
pcm_dec = NULL;
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
16
cpu/br28/audio_dec/audio_dec_pcm.h
Normal file
16
cpu/br28/audio_dec/audio_dec_pcm.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __AUDIO_DEC_PCM_H
|
||||
#define __AUDIO_DEC_PCM_H
|
||||
|
||||
#include "asm/cpu.h"
|
||||
|
||||
|
||||
void pcm_dec_resume(void);
|
||||
void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int));
|
||||
int pcm_audio_play_open(int sr, u8 ch);
|
||||
void pcm_audio_play_close(void);
|
||||
|
||||
|
||||
extern int sound_pcm_dev_channel_mapping(int ch_num);
|
||||
|
||||
#endif
|
||||
|
||||
920
cpu/br28/audio_dec/audio_usb_mic.c
Normal file
920
cpu/br28/audio_dec/audio_usb_mic.c
Normal file
@ -0,0 +1,920 @@
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "device/uac_stream.h"
|
||||
#include "audio_enc.h"
|
||||
#include "app_main.h"
|
||||
#include "user_cfg_id.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "audio_config.h"
|
||||
/* #include "application/audio_echo_reverb.h" */
|
||||
|
||||
/*USB MIC上行数据同步及变采样模块使能*/
|
||||
#define USB_MIC_SRC_ENABLE 1
|
||||
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
#include "aec_user.h"
|
||||
#include "overlay_code.h"
|
||||
#endif/*TCFG_USB_MIC_CVP_ENABLE*/
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
#include "audio_track.h"
|
||||
#include "Resample_api.h"
|
||||
#endif/*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
#define USB_AUDIO_MIC_WRITE_TASK_NAME "usbmic_write"
|
||||
|
||||
#define PCM_ENC2USB_OUTBUF_LEN (6 * 1024)
|
||||
|
||||
#define USB_MIC_BUF_NUM 3
|
||||
|
||||
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
#define USB_MIC_CH_NUM 3 /* 3mic通话 */
|
||||
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
#define USB_MIC_CH_NUM 2 /* 双mic通话 */
|
||||
#else
|
||||
#define USB_MIC_CH_NUM 1 /* 单mic通话 */
|
||||
#endif
|
||||
|
||||
#define USB_MIC_IRQ_POINTS 256
|
||||
#define USB_MIC_BUFS_SIZE (USB_MIC_CH_NUM * USB_MIC_BUF_NUM * USB_MIC_IRQ_POINTS)
|
||||
|
||||
#define USB_MIC_STOP 0x00
|
||||
#define USB_MIC_START 0x01
|
||||
|
||||
#ifndef VM_USB_MIC_GAIN
|
||||
#define VM_USB_MIC_GAIN 5
|
||||
#endif
|
||||
|
||||
#define USB_PLNK_MIC_GAIN_ENABLE 1 //PLNK_MIC数字增益放大使能
|
||||
#define USB_PLNK_MIC_DIG_GAIN 60.f //PLNK_MIC数字增益(Gain = 10^(dB_diff/20))
|
||||
|
||||
extern struct audio_adc_hdl adc_hdl;
|
||||
extern u16 uac_get_mic_vol(const u8 usb_id);
|
||||
extern int usb_output_sample_rate();
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
typedef struct {
|
||||
u8 start;
|
||||
u8 busy;
|
||||
u16 in_sample_rate;
|
||||
u16 out_sample_rate;
|
||||
u32 *runbuf;
|
||||
s16 output[320 * 3 + 16];
|
||||
RS_STUCT_API *ops;
|
||||
void *audio_track;
|
||||
} usb_mic_sw_src_t;
|
||||
static usb_mic_sw_src_t *usb_mic_src = NULL;
|
||||
#endif/*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
|
||||
|
||||
struct _usb_mic_hdl {
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
struct adc_mic_ch mic_ch;
|
||||
s16 adc_buf[USB_MIC_BUFS_SIZE];
|
||||
enum enc_source source;
|
||||
OS_SEM sem;
|
||||
|
||||
cbuffer_t output_cbuf;
|
||||
u8 *output_buf;//[PCM_ENC2USB_OUTBUF_LEN];
|
||||
u8 rec_tx_channels;
|
||||
u8 mic_data_ok;/*mic数据等到一定长度再开始发送*/
|
||||
u8 status;
|
||||
u8 drop_data; //用来丢掉刚开mic的前几帧数据
|
||||
#if TCFG_USB_MIC_ECHO_ENABLE
|
||||
ECHO_API_STRUCT *p_echo_hdl;
|
||||
#endif
|
||||
#if (USB_MIC_CH_NUM > 1)
|
||||
s16 tmp_buf[USB_MIC_IRQ_POINTS];
|
||||
#endif/*USB_MIC_CH_NUM*/
|
||||
#if (USB_MIC_CH_NUM > 2)
|
||||
s16 tmp_buf_1[USB_MIC_IRQ_POINTS];
|
||||
#endif/*USB_MIC_CH_NUM*/
|
||||
s16 *usb_mic_data;
|
||||
u16 data_len;
|
||||
float dig_gain;
|
||||
};
|
||||
|
||||
struct audio_sample_track_context {
|
||||
u32 in_sr;
|
||||
volatile u8 track_step;
|
||||
volatile int samples;
|
||||
volatile u32 sample_rate;
|
||||
volatile u32 adc_points;
|
||||
volatile u32 next_period;
|
||||
volatile int period;
|
||||
};
|
||||
static u32 adc_hwp = 0;
|
||||
static u32 adc_points = 0;
|
||||
static void *user_audio_local_sample_track_open(int in_sr, int sample_rate, int period)
|
||||
{
|
||||
struct audio_sample_track_context *ctx;
|
||||
ctx = (struct audio_sample_track_context *)zalloc(sizeof(struct audio_sample_track_context));
|
||||
if (!ctx) {
|
||||
return NULL;
|
||||
}
|
||||
ctx->in_sr = in_sr;
|
||||
ctx->sample_rate = sample_rate;
|
||||
ctx->period = period * sample_rate / 1000;
|
||||
adc_points = 0;
|
||||
return ctx;
|
||||
}
|
||||
int get_audio_adc_points_time()//获取总的采样周期
|
||||
{
|
||||
return adc_points + ((JL_AUDIO->ADC_HWP > adc_hwp) ? (JL_AUDIO->ADC_HWP - adc_hwp) : (JL_AUDIO->ADC_HWP + JL_AUDIO->ADC_LEN - adc_hwp));
|
||||
}
|
||||
static int user_audio_local_sample_track_in_period(void *c, int samples)
|
||||
{
|
||||
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
|
||||
if (ctx->track_step == 0) {
|
||||
ctx->track_step = 1;
|
||||
goto __exit;
|
||||
}
|
||||
if (ctx->track_step == 1) {
|
||||
ctx->track_step = 2;
|
||||
ctx->next_period = ctx->period;
|
||||
ctx->samples = 0;
|
||||
goto __exit;
|
||||
}
|
||||
ctx->samples += samples;
|
||||
if (time_after(ctx->samples, ctx->next_period)) {
|
||||
int adc_points = get_audio_adc_points_time();
|
||||
int points_diff = (adc_points - ctx->adc_points);
|
||||
if (points_diff > 0) {
|
||||
int sample_rate = ((u64)((u64)ctx->in_sr * (u64)ctx->samples)) / points_diff;
|
||||
/* printf("> track : %d %d %d %d< \n", sample_rate, ctx->samples, ctx->in_sr, points_diff); */
|
||||
/* printf("> track : %d < \n", sample_rate); */
|
||||
ctx->sample_rate = sample_rate;
|
||||
}
|
||||
ctx->adc_points = adc_points;
|
||||
ctx->next_period = ctx->period;
|
||||
ctx->samples = 0;
|
||||
}
|
||||
__exit:
|
||||
return ctx->sample_rate;
|
||||
}
|
||||
static int user_audio_local_sample_track_rate(void *c)
|
||||
{
|
||||
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
|
||||
return ctx->sample_rate;
|
||||
}
|
||||
static void user_audio_local_sample_track_close(void *c)
|
||||
{
|
||||
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
|
||||
if (!ctx) {
|
||||
return;
|
||||
}
|
||||
ctx->track_step = 0;
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static struct _usb_mic_hdl *usb_mic_hdl = NULL;
|
||||
#if TCFG_USB_MIC_ECHO_ENABLE
|
||||
ECHO_PARM_SET usbmic_echo_parm_default = {
|
||||
.delay = 200, //回声的延时时间 0-300ms
|
||||
.decayval = 50, // 0-70%
|
||||
.direct_sound_enable = 1, //直达声使能 0/1
|
||||
.filt_enable = 1, //发散滤波器使能
|
||||
};
|
||||
EF_REVERB_FIX_PARM usbmic_echo_fix_parm_default = {
|
||||
.wetgain = 2048, ////湿声增益:[0:4096]
|
||||
.drygain = 4096, ////干声增益: [0:4096]
|
||||
.sr = MIC_EFFECT_SAMPLERATE, ////采样率
|
||||
.max_ms = 200, ////所需要的最大延时,影响 need_buf 大小
|
||||
};
|
||||
#endif
|
||||
static int usb_audio_mic_sync(u32 data_size)
|
||||
{
|
||||
#if 0
|
||||
int change_point = 0;
|
||||
|
||||
if (data_size > __this->rec_top_size) {
|
||||
change_point = -1;
|
||||
} else if (data_size < __this->rec_bottom_size) {
|
||||
change_point = 1;
|
||||
}
|
||||
|
||||
if (change_point) {
|
||||
struct audio_pcm_src src;
|
||||
src.resample = 0;
|
||||
src.ratio_i = (1024) * 2;
|
||||
src.ratio_o = (1024 + change_point) * 2;
|
||||
src.convert = 1;
|
||||
dev_ioctl(__this->rec_dev, AUDIOC_PCM_RATE_CTL, (u32)&src);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_audio_mic_tx_handler(int event, void *data, int len)
|
||||
{
|
||||
if (usb_mic_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (usb_mic_hdl->status == USB_MIC_STOP) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int r_len = 0;
|
||||
u8 ch = 0;
|
||||
u8 double_read = 0;
|
||||
|
||||
/* int rlen = 0; */
|
||||
|
||||
if (usb_mic_hdl->mic_data_ok == 0) {
|
||||
if (usb_mic_hdl->output_cbuf.data_len > (PCM_ENC2USB_OUTBUF_LEN / 4)) {
|
||||
usb_mic_hdl->mic_data_ok = 1;
|
||||
}
|
||||
//y_printf("mic_tx NULL\n");
|
||||
memset(data, 0, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
if (usb_mic_src && usb_mic_src->audio_track) {
|
||||
user_audio_local_sample_track_in_period(usb_mic_src->audio_track, (len >> 1) / usb_mic_hdl->rec_tx_channels);
|
||||
}
|
||||
#endif/*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
/* usb_audio_mic_sync(size); */
|
||||
if (usb_mic_hdl->rec_tx_channels == 2) {
|
||||
len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len / 2);
|
||||
s16 *tx_pcm = (s16 *)data;
|
||||
int cnt = len / 2;
|
||||
for (cnt = len / 2; cnt >= 2;) {
|
||||
tx_pcm[cnt - 1] = tx_pcm[cnt / 2 - 1];
|
||||
tx_pcm[cnt - 2] = tx_pcm[cnt / 2 - 1];
|
||||
cnt -= 2;
|
||||
}
|
||||
len *= 2;
|
||||
} else {
|
||||
len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len);
|
||||
}
|
||||
if (!len) {
|
||||
putchar('M');
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int usb_audio_mic_write(void *data, u16 len)
|
||||
{
|
||||
int wlen = len;
|
||||
if (usb_mic_hdl) {
|
||||
if (usb_mic_hdl->status == USB_MIC_STOP) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int outlen = len;
|
||||
s16 *obuf = data;
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
if (usb_mic_src && usb_mic_src->start) {
|
||||
usb_mic_src->busy = 1;
|
||||
u32 sr = usb_output_sample_rate();
|
||||
usb_mic_src->ops->set_sr(usb_mic_src->runbuf, sr);
|
||||
outlen = usb_mic_src->ops->run(usb_mic_src->runbuf, data, len >> 1, usb_mic_src->output);
|
||||
usb_mic_src->busy = 0;
|
||||
ASSERT(outlen <= (sizeof(usb_mic_src->output) >> 1));
|
||||
//printf("16->48k:%d,%d,%d\n",len >> 1,outlen,sizeof(usb_mic_src->output));
|
||||
obuf = usb_mic_src->output;
|
||||
outlen = outlen << 1;
|
||||
}
|
||||
#endif/*USB_MIC_SRC_ENABLE*/
|
||||
wlen = cbuf_write(&usb_mic_hdl->output_cbuf, obuf, outlen);
|
||||
if (wlen != outlen) {
|
||||
r_printf("usb_mic write full:%d-%d\n", wlen, outlen);
|
||||
}
|
||||
}
|
||||
return wlen;
|
||||
}
|
||||
|
||||
static void adc_output_to_cbuf(void *priv, s16 *data, int len)
|
||||
{
|
||||
if (usb_mic_hdl == NULL) {
|
||||
return ;
|
||||
}
|
||||
if (usb_mic_hdl->status == USB_MIC_STOP) {
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch (usb_mic_hdl->source) {
|
||||
case ENCODE_SOURCE_MIC:
|
||||
case ENCODE_SOURCE_LINE0_LR:
|
||||
case ENCODE_SOURCE_LINE1_LR:
|
||||
case ENCODE_SOURCE_LINE2_LR: {
|
||||
|
||||
adc_hwp = JL_AUDIO->ADC_HWP;
|
||||
adc_points += len / 2;
|
||||
|
||||
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
#if (USB_MIC_CH_NUM == 3)/*3 Mic*/
|
||||
s16 *mic0_data = data;
|
||||
s16 *mic1_data = usb_mic_hdl->tmp_buf;
|
||||
s16 *mic1_data_pos = usb_mic_hdl->tmp_buf_1;
|
||||
//printf("mic_data: %x, %x, %d\n",data, mic1_data_pos, len);
|
||||
for (u16 i = 0; i < (len >> 1); i++) {
|
||||
mic0_data[i] = data[i * 3];
|
||||
mic1_data[i] = data[i * 3 + 1];
|
||||
mic1_data_pos[i] = data[i * 3 + 2];
|
||||
}
|
||||
audio_aec_inbuf_ref(mic1_data, len);
|
||||
audio_aec_inbuf_ref_1(mic1_data_pos, len);
|
||||
audio_aec_inbuf(data, len);
|
||||
return;
|
||||
|
||||
#elif (USB_MIC_CH_NUM == 2)/*DualMic*/
|
||||
s16 *mic0_data = data;
|
||||
s16 *mic1_data = usb_mic_hdl->tmp_buf;
|
||||
s16 *mic1_data_pos = data + (len / 2);
|
||||
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
|
||||
for (u16 i = 0; i < (len >> 1); i++) {
|
||||
mic0_data[i] = data[i * 2];
|
||||
mic1_data[i] = data[i * 2 + 1];
|
||||
}
|
||||
memcpy(mic1_data_pos, mic1_data, len);
|
||||
|
||||
#if 0 /*debug*/
|
||||
static u16 mic_cnt = 0;
|
||||
if (mic_cnt++ > 300) {
|
||||
putchar('1');
|
||||
audio_aec_inbuf(mic1_data_pos, len);
|
||||
if (mic_cnt > 600) {
|
||||
mic_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
putchar('0');
|
||||
audio_aec_inbuf(mic0_data, len);
|
||||
}
|
||||
return;
|
||||
#endif/*debug end*/
|
||||
#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
|
||||
audio_aec_inbuf_ref(mic1_data_pos, len);
|
||||
audio_aec_inbuf(data, len);
|
||||
#else
|
||||
audio_aec_inbuf_ref(data, len);
|
||||
audio_aec_inbuf(mic1_data_pos, len);
|
||||
#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
|
||||
#else/*SingleMic*/
|
||||
audio_aec_inbuf(data, len);
|
||||
#endif/*USB_MIC_CH_NUM*/
|
||||
|
||||
#else /* TCFG_USB_MIC_CVP_ENABLE == 0 */
|
||||
if (usb_mic_hdl->drop_data != 0) {
|
||||
usb_mic_hdl-> drop_data--;
|
||||
memset(data, 0, len);
|
||||
}
|
||||
#if TCFG_USB_MIC_ECHO_ENABLE
|
||||
if (usb_mic_hdl->p_echo_hdl) {
|
||||
run_echo(usb_mic_hdl->p_echo_hdl, data, data, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 由于usb_audio_mic_write中SRC执行时间较长在adc中断中写数据会影响usb中断 */
|
||||
/* 改为在usb_audio_mic_write_task中向usb写数据 */
|
||||
/* adc输入一帧数据,唤醒一次运行任务处理数据 */
|
||||
usb_mic_hdl->usb_mic_data = data;
|
||||
usb_mic_hdl->data_len = len;
|
||||
os_sem_set(&usb_mic_hdl->sem, 0);
|
||||
os_sem_post(&usb_mic_hdl->sem);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
static int sw_src_init(u32 in_sr, u32 out_sr)
|
||||
{
|
||||
usb_mic_src = zalloc(sizeof(usb_mic_sw_src_t));
|
||||
ASSERT(usb_mic_src);
|
||||
|
||||
usb_mic_src->in_sample_rate = in_sr;
|
||||
usb_mic_src->out_sample_rate = out_sr;
|
||||
|
||||
usb_mic_src->ops = get_rs16_context();
|
||||
/* usb_mic_src->ops = get_rsfast_context(); */
|
||||
g_printf("ops:0x%x\n", usb_mic_src->ops);
|
||||
ASSERT(usb_mic_src->ops);
|
||||
u32 need_buf = usb_mic_src->ops->need_buf();
|
||||
g_printf("runbuf:%d\n", need_buf);
|
||||
usb_mic_src->runbuf = malloc(need_buf);
|
||||
ASSERT(usb_mic_src->runbuf);
|
||||
RS_PARA_STRUCT rs_para_obj;
|
||||
rs_para_obj.nch = 1;
|
||||
|
||||
rs_para_obj.new_insample = in_sr;
|
||||
rs_para_obj.new_outsample = out_sr;
|
||||
printf("sw src,in = %d,out = %d\n", rs_para_obj.new_insample, rs_para_obj.new_outsample);
|
||||
usb_mic_src->ops->open(usb_mic_src->runbuf, &rs_para_obj);
|
||||
|
||||
usb_mic_src->audio_track = user_audio_local_sample_track_open(in_sr, out_sr, 2000);
|
||||
usb_mic_src->start = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sw_src_exit(void)
|
||||
{
|
||||
if (usb_mic_src) {
|
||||
usb_mic_src->start = 0;
|
||||
while (usb_mic_src->busy) {
|
||||
putchar('w');
|
||||
os_time_dly(2);
|
||||
}
|
||||
|
||||
user_audio_local_sample_track_close(usb_mic_src->audio_track);
|
||||
usb_mic_src->audio_track = NULL;
|
||||
|
||||
local_irq_disable();
|
||||
if (usb_mic_src->runbuf) {
|
||||
free(usb_mic_src->runbuf);
|
||||
usb_mic_src->runbuf = 0;
|
||||
}
|
||||
free(usb_mic_src);
|
||||
usb_mic_src = NULL;
|
||||
local_irq_enable();
|
||||
printf("sw_src_exit\n");
|
||||
}
|
||||
printf("sw_src_exit ok\n");
|
||||
return 0;
|
||||
}
|
||||
#endif/*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
|
||||
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
static int usb_mic_aec_output(s16 *data, u16 len)
|
||||
{
|
||||
//putchar('k');
|
||||
if (usb_mic_hdl == NULL) {
|
||||
return len ;
|
||||
}
|
||||
if (usb_mic_hdl->status == USB_MIC_STOP) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int outlen = len;
|
||||
s16 *outdat = data;
|
||||
/* if (aec_hdl->dump_packet) { */
|
||||
/* aec_hdl->dump_packet--; */
|
||||
/* //memset(outdat, 0, outlen); */
|
||||
/* } */
|
||||
u16 wlen = usb_audio_mic_write(outdat, outlen);
|
||||
return len;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
int uac_mic_vol_switch(int vol)
|
||||
{
|
||||
return vol * 14 / 100;
|
||||
}
|
||||
|
||||
float uac_mic_dig_gain_switch(int vol)
|
||||
{
|
||||
float gain = vol / 10.f;
|
||||
return gain;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* USB Audio MIC Write Task
|
||||
* Description: USB MIC 写数据任务
|
||||
* Arguments : priv 私用参数
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
static void usb_audio_mic_write_task(void *priv)
|
||||
{
|
||||
printf("==Audio Usb Mic Write Task==\n");
|
||||
|
||||
while (1) {
|
||||
os_sem_pend(&usb_mic_hdl->sem, 0);
|
||||
|
||||
putchar('.');
|
||||
if (usb_mic_hdl->status) {
|
||||
usb_audio_mic_write(usb_mic_hdl->usb_mic_data, usb_mic_hdl->data_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* PDM MIC API
|
||||
* Description: PDM mic操作接口
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
|
||||
/* #define USB_PLNK_SR 16000#<{(|16000/44100/48000|)}># */
|
||||
#define USB_PLNK_SCLK 2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
|
||||
#define USB_PLNK_CH_NUM 1 /*支持的最大通道(max = 2)*/
|
||||
#define USB_PLNK_IRQ_POINTS 256 /*采样中断点数*/
|
||||
#include "pdm_link.h"
|
||||
#include "media/audio_gain_process.h"
|
||||
static audio_plnk_t *audio_plnk_mic = NULL;
|
||||
static void audio_plnk_mic_output(void *buf, u16 len)
|
||||
{
|
||||
s16 *mic0 = (s16 *)buf;
|
||||
if (audio_plnk_mic) {
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
audio_aec_inbuf(mic0, len << 1);
|
||||
#else
|
||||
#if USB_PLNK_MIC_GAIN_ENABLE
|
||||
GainProcess_16Bit(mic0, mic0, USB_PLNK_MIC_DIG_GAIN, 1, 1, 1, len);
|
||||
#endif
|
||||
usb_mic_hdl->usb_mic_data = mic0;
|
||||
usb_mic_hdl->data_len = len << 1;
|
||||
os_sem_set(&usb_mic_hdl->sem, 0);
|
||||
os_sem_post(&usb_mic_hdl->sem);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_pdm_mic_en(u8 en, u16 sr, u16 gain)
|
||||
{
|
||||
printf("usb_pdm_mic_en:%d\n", en);
|
||||
if (en) {
|
||||
if (audio_plnk_mic) {
|
||||
printf("audio_plnk_mic re-malloc error\n");
|
||||
return -1;
|
||||
}
|
||||
audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
|
||||
if (audio_plnk_mic == NULL) {
|
||||
printf("audio_plnk_mic zalloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
audio_mic_pwr_ctl(MIC_PWR_ON);
|
||||
audio_plnk_mic->ch_num = USB_PLNK_CH_NUM;
|
||||
audio_plnk_mic->sr = sr;
|
||||
audio_plnk_mic->buf_len = USB_PLNK_IRQ_POINTS;
|
||||
#if (PLNK_CH_EN == PLNK_CH0_EN)
|
||||
audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
|
||||
audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
|
||||
#elif (PLNK_CH_EN == PLNK_CH1_EN)
|
||||
audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
|
||||
audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
|
||||
#else
|
||||
audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
|
||||
audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
|
||||
#endif
|
||||
audio_plnk_mic->buf = zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
|
||||
ASSERT(audio_plnk_mic->buf);
|
||||
audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
|
||||
audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
|
||||
audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
|
||||
audio_plnk_mic->output = audio_plnk_mic_output;
|
||||
audio_plnk_open(audio_plnk_mic);
|
||||
audio_plnk_start(audio_plnk_mic);
|
||||
SFR(JL_ASS->CLK_CON, 0, 2, 3);
|
||||
} else {
|
||||
audio_plnk_close();
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
//printf("anc_status:%d\n",anc_status_get());
|
||||
if (anc_status_get() == 0) {
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
}
|
||||
#else
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
if (audio_plnk_mic->buf) {
|
||||
free(audio_plnk_mic->buf);
|
||||
}
|
||||
if (audio_plnk_mic) {
|
||||
free(audio_plnk_mic);
|
||||
audio_plnk_mic = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif/* #if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC) */
|
||||
|
||||
int usb_audio_mic_open(void *_info)
|
||||
{
|
||||
int err = 0;
|
||||
if (usb_mic_hdl) {
|
||||
return 0;
|
||||
}
|
||||
usb_mic_hdl = zalloc(sizeof(*usb_mic_hdl));
|
||||
if (!usb_mic_hdl) {
|
||||
return -EFAULT;
|
||||
}
|
||||
usb_mic_hdl->status = USB_MIC_STOP;
|
||||
|
||||
usb_mic_hdl->output_buf = zalloc(PCM_ENC2USB_OUTBUF_LEN);
|
||||
if (!usb_mic_hdl->output_buf) {
|
||||
printf("usb_mic_hdl->output_buf NULL\n");
|
||||
|
||||
if (usb_mic_hdl) {
|
||||
free(usb_mic_hdl);
|
||||
usb_mic_hdl = NULL;
|
||||
}
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
u32 sample_rate = (u32)_info & 0xFFFFFF;
|
||||
usb_mic_hdl->rec_tx_channels = (u32)_info >> 24;
|
||||
usb_mic_hdl->source = ENCODE_SOURCE_MIC;
|
||||
printf("usb mic sr:%d ch:%d\n", sample_rate, usb_mic_hdl->rec_tx_channels);
|
||||
|
||||
|
||||
usb_mic_hdl->drop_data = 10; //用来丢掉前几帧数据
|
||||
usb_mic_hdl->dig_gain = 1.f; // 用来初始化数字增益
|
||||
u32 out_sample_rate = sample_rate;
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
sample_rate = 16000;
|
||||
printf("usb mic sr[aec]:%d\n", sample_rate);
|
||||
/*加载清晰语音处理代码*/
|
||||
audio_cvp_code_load();
|
||||
audio_aec_open(sample_rate, TCFG_USB_MIC_CVP_MODE, usb_mic_aec_output);
|
||||
#else
|
||||
os_sem_create(&usb_mic_hdl->sem, 0);
|
||||
err = task_create(usb_audio_mic_write_task, NULL, USB_AUDIO_MIC_WRITE_TASK_NAME);
|
||||
#endif
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
sw_src_init(sample_rate, out_sample_rate);
|
||||
#endif /*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
|
||||
cbuf_init(&usb_mic_hdl->output_cbuf, usb_mic_hdl->output_buf, PCM_ENC2USB_OUTBUF_LEN);
|
||||
|
||||
#if TCFG_MIC_EFFECT_ENABLE
|
||||
app_var.usb_mic_gain = mic_effect_get_micgain();
|
||||
#else
|
||||
app_var.usb_mic_gain = uac_mic_vol_switch(uac_get_mic_vol(0));
|
||||
#endif//TCFG_MIC_EFFECT_ENABLE
|
||||
|
||||
#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
|
||||
mic_effect_to_usbmic_onoff(1);
|
||||
#else
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
|
||||
usb_pdm_mic_en(1, sample_rate, app_var.usb_mic_gain);
|
||||
#else
|
||||
audio_mic_pwr_ctl(MIC_PWR_ON);
|
||||
#if 1
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0)
|
||||
printf("adc_mic0 open\n");
|
||||
audio_adc_mic_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
|
||||
#ifndef TALK_MIC0_GAIN
|
||||
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
|
||||
#else
|
||||
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, TALK_MIC0_GAIN);
|
||||
#endif
|
||||
#endif/*TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0*/
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)
|
||||
printf("adc_mic1 open\n");
|
||||
audio_adc_mic1_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl);
|
||||
#ifndef FF_MIC1_GAIN
|
||||
audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
|
||||
#else
|
||||
audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, FF_MIC1_GAIN);
|
||||
#endif
|
||||
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)*/
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)
|
||||
printf("adc_mic2 open\n");
|
||||
audio_adc_mic2_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl);
|
||||
#ifndef FB_MIC2_GAIN
|
||||
audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
|
||||
#else
|
||||
audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, FB_MIC2_GAIN);
|
||||
#endif
|
||||
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)*/
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)
|
||||
printf("adc_mic3 open\n");
|
||||
audio_adc_mic3_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl);
|
||||
#ifndef OTHER_MIC3_GAIN
|
||||
audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
|
||||
#else
|
||||
audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, OTHER_MIC3_GAIN);
|
||||
#endif
|
||||
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)*/
|
||||
audio_adc_mic_set_sample_rate(&usb_mic_hdl->mic_ch, sample_rate);
|
||||
audio_adc_mic_set_buffs(&usb_mic_hdl->mic_ch, usb_mic_hdl->adc_buf, USB_MIC_IRQ_POINTS * 2, USB_MIC_BUF_NUM);
|
||||
usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
|
||||
audio_adc_add_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
|
||||
audio_adc_mic_start(&usb_mic_hdl->mic_ch);
|
||||
#else
|
||||
audio_mic_open(&usb_mic_hdl->mic_ch, sample_rate, app_var.usb_mic_gain);
|
||||
usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
|
||||
audio_mic_add_output(&usb_mic_hdl->adc_output);
|
||||
audio_mic_start(&usb_mic_hdl->mic_ch);
|
||||
#endif
|
||||
#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
|
||||
#if TCFG_USB_MIC_ECHO_ENABLE
|
||||
usb_mic_hdl->p_echo_hdl = open_echo(&usbmic_echo_parm_default, &usbmic_echo_fix_parm_default);
|
||||
if (usb_mic_hdl->p_echo_hdl) {
|
||||
update_echo_gain(usb_mic_hdl->p_echo_hdl, usbmic_echo_fix_parm_default.wetgain, usbmic_echo_fix_parm_default.drygain);
|
||||
}
|
||||
#endif
|
||||
#endif//TCFG_USB_MIC_DATA_FROM_MICEFFECT
|
||||
set_uac_mic_tx_handler(NULL, usb_audio_mic_tx_handler);
|
||||
|
||||
/* 需要用时钟管理,防止其他操作降低USB_MIC时钟 */
|
||||
audio_codec_clock_set(AUDIO_USB_MIC_MODE, AUDIO_CODING_PCM, 0);
|
||||
|
||||
usb_mic_hdl->status = USB_MIC_START;
|
||||
/* __this->rec_begin = 0; */
|
||||
return 0;
|
||||
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
u32 usb_mic_is_running()
|
||||
{
|
||||
if (usb_mic_hdl) {
|
||||
return SPK_AUDIO_RATE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*************************************************************
|
||||
*
|
||||
* usb mic gain save
|
||||
*
|
||||
*************************************************************
|
||||
*/
|
||||
static int usb_mic_gain_save_timer;
|
||||
static u8 usb_mic_gain_save_cnt;
|
||||
static void usb_audio_mic_gain_save_do(void *priv)
|
||||
{
|
||||
//printf(" usb_audio_mic_gain_save_do %d\n", usb_mic_gain_save_cnt);
|
||||
local_irq_disable();
|
||||
if (++usb_mic_gain_save_cnt >= 5) {
|
||||
sys_timer_del(usb_mic_gain_save_timer);
|
||||
usb_mic_gain_save_timer = 0;
|
||||
usb_mic_gain_save_cnt = 0;
|
||||
local_irq_enable();
|
||||
printf("USB_GAIN_SAVE\n");
|
||||
syscfg_write(VM_USB_MIC_GAIN, &app_var.usb_mic_gain, 1);
|
||||
return;
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static void usb_audio_mic_gain_change(u8 gain)
|
||||
{
|
||||
local_irq_disable();
|
||||
app_var.usb_mic_gain = gain;
|
||||
usb_mic_gain_save_cnt = 0;
|
||||
if (usb_mic_gain_save_timer == 0) {
|
||||
usb_mic_gain_save_timer = sys_timer_add(NULL, usb_audio_mic_gain_save_do, 1000);
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
int usb_audio_mic_get_gain(void)
|
||||
{
|
||||
return app_var.usb_mic_gain;
|
||||
}
|
||||
|
||||
void usb_audio_mic_set_gain(int gain)
|
||||
{
|
||||
if (usb_mic_hdl == NULL) {
|
||||
r_printf("usb_mic_hdl NULL gain");
|
||||
return;
|
||||
}
|
||||
#ifndef CONFIG_BOARD_AISPEECH_NR_GAIN
|
||||
gain = uac_mic_vol_switch(gain);
|
||||
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, gain);
|
||||
usb_audio_mic_gain_change(gain);
|
||||
#else
|
||||
printf("AIS 3MIC set digital gain");
|
||||
usb_mic_hdl->dig_gain = uac_mic_dig_gain_switch(gain);
|
||||
#endif /*CONFIG_BOARD_AISPEECH_NR_GAIN*/
|
||||
}
|
||||
|
||||
float usb_audio_mic_get_dig_gain(void)
|
||||
{
|
||||
if (usb_mic_hdl == NULL) {
|
||||
r_printf("usb_mic_hdl NULL gain");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return usb_mic_hdl->dig_gain;
|
||||
}
|
||||
|
||||
int usb_audio_mic_close(void *arg)
|
||||
{
|
||||
if (usb_mic_hdl == NULL) {
|
||||
r_printf("usb_mic_hdl NULL close");
|
||||
return 0;
|
||||
}
|
||||
printf("usb_mic_hdl->status %x\n", usb_mic_hdl->status);
|
||||
if (usb_mic_hdl && usb_mic_hdl->status == USB_MIC_START) {
|
||||
printf("usb_audio_mic_close in\n");
|
||||
usb_mic_hdl->status = USB_MIC_STOP;
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
audio_aec_close();
|
||||
#else
|
||||
task_kill(USB_AUDIO_MIC_WRITE_TASK_NAME);
|
||||
#endif
|
||||
#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
|
||||
mic_effect_to_usbmic_onoff(0);
|
||||
#else
|
||||
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
|
||||
usb_pdm_mic_en(0, 0, 0);
|
||||
#else
|
||||
#if 1
|
||||
audio_adc_mic_close(&usb_mic_hdl->mic_ch);
|
||||
audio_adc_del_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
|
||||
#else
|
||||
audio_mic_close(&usb_mic_hdl->mic_ch, &usb_mic_hdl->adc_output);
|
||||
#endif
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
|
||||
#if TCFG_USB_MIC_ECHO_ENABLE
|
||||
if (usb_mic_hdl->p_echo_hdl) {
|
||||
close_echo(usb_mic_hdl->p_echo_hdl);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
sw_src_exit();
|
||||
#endif /*USB_MIC_SRC_ENABLE*/
|
||||
cbuf_clear(&usb_mic_hdl->output_cbuf);
|
||||
if (usb_mic_hdl) {
|
||||
|
||||
if (usb_mic_hdl->output_buf) {
|
||||
free(usb_mic_hdl->output_buf);
|
||||
usb_mic_hdl->output_buf = NULL;
|
||||
}
|
||||
free(usb_mic_hdl);
|
||||
usb_mic_hdl = NULL;
|
||||
}
|
||||
#if TCFG_USB_MIC_CVP_ENABLE
|
||||
audio_codec_clock_del(AUDIO_USB_MIC_MODE);
|
||||
#endif /*TCFG_USB_MIC_CVP_ENABLE*/
|
||||
}
|
||||
printf("usb_audio_mic_close out\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usb_mic_stream_sample_rate(void)
|
||||
{
|
||||
#if USB_MIC_SRC_ENABLE
|
||||
if (usb_mic_src && usb_mic_src->audio_track) {
|
||||
int sr = user_audio_local_sample_track_rate(usb_mic_src->audio_track);
|
||||
if ((sr < (usb_mic_src->out_sample_rate + 50)) && (sr > (usb_mic_src->out_sample_rate - 50))) {
|
||||
return sr;
|
||||
}
|
||||
return usb_mic_src->out_sample_rate;
|
||||
}
|
||||
#endif /*USB_MIC_SRC_ENABLE*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 usb_mic_stream_size()
|
||||
{
|
||||
if (!usb_mic_hdl) {
|
||||
return 0;
|
||||
}
|
||||
if (usb_mic_hdl->status == USB_MIC_START) {
|
||||
if (usb_mic_hdl) {
|
||||
return cbuf_get_data_size(&usb_mic_hdl->output_cbuf);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 usb_mic_stream_length()
|
||||
{
|
||||
return PCM_ENC2USB_OUTBUF_LEN;
|
||||
}
|
||||
|
||||
int usb_output_sample_rate()
|
||||
{
|
||||
int sample_rate = usb_mic_stream_sample_rate();
|
||||
int buf_size = usb_mic_stream_size();
|
||||
|
||||
sample_rate = (u32)(usb_mic_src->in_sample_rate * sample_rate) / usb_mic_src->out_sample_rate;/*统计输出采样率,重新转换成输入采样率调输入*/
|
||||
if (buf_size >= (usb_mic_stream_length() * 1 / 2)) {
|
||||
sample_rate += (sample_rate * 5 / 10000);
|
||||
//putchar('+');
|
||||
}
|
||||
if (buf_size <= (usb_mic_stream_length() / 3)) {
|
||||
sample_rate -= (sample_rate * 5 / 10000);
|
||||
//putchar('-');
|
||||
}
|
||||
|
||||
return sample_rate;
|
||||
}
|
||||
|
||||
1860
cpu/br28/audio_dec_eff.c
Normal file
1860
cpu/br28/audio_dec_eff.c
Normal file
File diff suppressed because it is too large
Load Diff
134
cpu/br28/audio_dec_eff.h
Normal file
134
cpu/br28/audio_dec_eff.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef _AUD_DEC_EFF_H
|
||||
#define _AUD_DEC_EFF_H
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "classic/tws_api.h"
|
||||
#include "classic/hci_lmp.h"
|
||||
#include "media/eq_config.h"
|
||||
#include "media/audio_surround.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "app_main.h"
|
||||
#include "media/audio_vbass.h"
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
#include "audio_anc.h"
|
||||
#endif/*TCFG_AUDIO_ANC_ENABLE*/
|
||||
|
||||
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
|
||||
#include "online_db_deal.h"
|
||||
#endif
|
||||
|
||||
struct dec_sur {
|
||||
#if AUDIO_SURROUND_CONFIG
|
||||
surround_hdl *surround; //环绕音效句柄
|
||||
u8 surround_eff; //音效模式记录
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#if (defined(TCFG_AUDIO_OUT_EQ_ENABLE) && (TCFG_AUDIO_OUT_EQ_ENABLE != 0))
|
||||
#define AUDIO_OUT_EQ_USE_SPEC_NUM 2 // 使用特定的eq段
|
||||
#else
|
||||
#define AUDIO_OUT_EQ_USE_SPEC_NUM 0
|
||||
#endif
|
||||
#define AUDIO_EQ_FADE_EN 1
|
||||
#define HIGH_BASS_EQ_FADE_STEP (1)
|
||||
|
||||
#if TCFG_EQ_ENABLE&&TCFG_AUDIO_OUT_EQ_ENABLE
|
||||
#define AUDIO_OUT_EFFECT_ENABLE 1 // 音频输出时的音效处理
|
||||
#else
|
||||
#define AUDIO_OUT_EFFECT_ENABLE 0
|
||||
#endif//TCFG_AUDIO_OUT_EQ_ENABLE
|
||||
extern struct audio_mixer mixer;
|
||||
|
||||
typedef int (*eq_output_cb)(void *, void *, int);
|
||||
|
||||
struct eq_filter_fade {
|
||||
u16 tmr;
|
||||
int cur_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
|
||||
int use_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
|
||||
};
|
||||
struct dec_eq_drc {
|
||||
s16 *eq_out_buf;
|
||||
int eq_out_buf_len;
|
||||
int eq_out_points;
|
||||
int eq_out_total;
|
||||
|
||||
void *priv;
|
||||
eq_output_cb out_cb;
|
||||
void *drc_prev;
|
||||
void *eq;
|
||||
void *spk_eq;
|
||||
void *drc;
|
||||
u8 async;
|
||||
u8 drc_bef_eq;
|
||||
struct eq_filter_fade fade;
|
||||
u8 remain;
|
||||
};
|
||||
|
||||
struct eq_parm_new {
|
||||
u8 in_mode: 2;
|
||||
u8 run_mode: 2;
|
||||
u8 data_in_mode: 2;
|
||||
u8 data_out_mode: 2;
|
||||
};
|
||||
void *audio_surround_setup(u8 channel, u8 eff);
|
||||
void audio_surround_free(void *sur);
|
||||
void audio_surround_set_ch(void *sur, u8 channel);
|
||||
void audio_surround_voice(void *sur, u8 en);
|
||||
|
||||
|
||||
vbass_hdl *audio_vbass_setup(u32 sample_rate, u8 channel);
|
||||
void audio_vbass_free(vbass_hdl *vbass);
|
||||
|
||||
|
||||
void *dec_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
|
||||
void dec_eq_drc_free(void *eff);
|
||||
|
||||
|
||||
void *esco_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
|
||||
void esco_eq_drc_free(void *eff);
|
||||
|
||||
|
||||
void *audio_out_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
|
||||
void audio_out_eq_drc_free(void *eff);
|
||||
int audio_out_eq_set_gain(void *eff, u8 idx, int gain);
|
||||
|
||||
int eq_drc_run(void *priv, void *data, u32 len);
|
||||
|
||||
void mix_out_drc_open(u16 sample_rate);
|
||||
void mix_out_drc_close();
|
||||
void mix_out_drc_run(s16 *data, u32 len);
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief mix_out后限幅器系数更新
|
||||
@param threadhold限幅器阈值,-60~0,单位db
|
||||
@return
|
||||
@note
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void mix_out_drc_threadhold_update(float threadhold);
|
||||
|
||||
struct audio_drc *esco_limiter_open(u16 sample_rate, u16 ch_num);
|
||||
void esco_limiter_run(struct audio_drc *limiter, s16 *data, u32 len);
|
||||
void esco_limiter_close(struct audio_drc *limiter);
|
||||
|
||||
void spk_eq_seg_update(struct eq_seg_info *seg);
|
||||
void spk_eq_global_gain_udapte(float global_gain);
|
||||
void *spk_eq_open(u32 sample_rate, u8 ch_num, u8 bitwide);
|
||||
void spk_eq_close(void *eq);
|
||||
void spk_eq_run(void *eq, void *in, void *out, u16 len);
|
||||
int spk_eq_save_to_vm();
|
||||
void spk_eq_read_from_vm();
|
||||
void spk_eq_set_send_data_handler(void (*handler)(u8 seq, u8 *packet, u8 size));
|
||||
int spk_eq_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
|
||||
int spk_eq_spp_rx_packet(u8 *packet, u8 len);
|
||||
int spk_eq_read_seg_l(u8 **buf);
|
||||
int spk_eq_read_seg_r(u8 **buf);
|
||||
|
||||
void *audio_bass_boost_open(u32 sample_rate, u8 ch_num);
|
||||
void audio_bass_boost_run(void *hdl, s16 *data, int len);
|
||||
void audio_bass_boost_close(void *hdl);
|
||||
|
||||
extern struct virtual_bass_tool_set *get_vbass_parm();
|
||||
#endif
|
||||
447
cpu/br28/audio_demo/audio_adc_demo.c
Normal file
447
cpu/br28/audio_demo/audio_adc_demo.c
Normal file
@ -0,0 +1,447 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Audio ADC Demo
|
||||
*
|
||||
*Description : Audio ADC使用范例
|
||||
*Notes : (1)本demo为开发测试范例,请不要修改该demo, 如有需求,请自行
|
||||
* 复制再修改
|
||||
* (2)mic工作模式说明
|
||||
* A.单端隔直(cap_mode)
|
||||
* 可以选择mic供电方式:外部供电还是内部供电(mic_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 "asm/audio_adc.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;
|
||||
|
||||
#define ADC_DEMO_CH_NUM 4 /*支持的最大采样通道(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 mic_idx;
|
||||
u8 linein_idx;
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
struct adc_mic_ch mic_ch;
|
||||
struct adc_linein_ch linein_ch;
|
||||
s16 adc_buf[ADC_DEMO_BUFS_SIZE];
|
||||
u8 linein_ch_num;
|
||||
u8 linein_ch_sel;
|
||||
};
|
||||
static struct adc_demo *mic_demo = NULL;
|
||||
static struct adc_demo *linein_demo = NULL;
|
||||
|
||||
/* 选择输出哪路 linein采样的数据,可通过按键调用此函数实现每按一下按键切一下输出的linein通路 */
|
||||
void linein_output_channel_sel()
|
||||
{
|
||||
if (linein_demo) {
|
||||
linein_demo->linein_ch_sel += 1;
|
||||
if (linein_demo->linein_ch_sel > linein_demo->linein_ch_num - 1) {
|
||||
linein_demo->linein_ch_sel = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO MIC OUTPUT
|
||||
* Description: mic采样数据回调
|
||||
* Arguments : pric 私有参数
|
||||
* data mic数据
|
||||
* len 数据长度
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : 单声道数据格式
|
||||
* L0 L1 L2 L3 L4 ...
|
||||
* 双声道数据格式()
|
||||
* L0 R0 L1 R1 L2 R2...
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#define ADC_DEBUG_BUF (0)
|
||||
#define ADC_DEBUF_SIZE (32000)
|
||||
|
||||
#if ADC_DEBUG_BUF
|
||||
u32 d_skip_cnt = 100;
|
||||
s16 d_buf[ADC_DEBUF_SIZE / 2] = {0};
|
||||
u8 *d_ptr = d_buf;
|
||||
u32 d_buf_cnt = 0;
|
||||
#endif
|
||||
|
||||
static void adc_mic_demo_output(void *priv, s16 *data, int len)
|
||||
{
|
||||
//printf("> %d %d %d %d\n", data[0], data[1], data[2], data[3]);
|
||||
|
||||
int wlen = 0;
|
||||
if (mic_demo && mic_demo->adc_2_dac) {
|
||||
if (mic_demo->mic_idx == (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1)) {
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
/*输出两个mic的数据到DAC两个通道*/
|
||||
putchar('a');
|
||||
wlen = audio_dac_write(&dac_hdl, data, len * 2);
|
||||
#else
|
||||
/*输出其中一个mic的数据到DAC一个通道*/
|
||||
putchar('b');
|
||||
s16 *mono_data = data;
|
||||
for (int i = 0; i < (len / 2); i++) {
|
||||
mono_data[i] = data[i * 2]; /*MIC_L*/
|
||||
//mono_data[i] = data[i * 2 + 1]; /*MIC_R*/
|
||||
}
|
||||
wlen = audio_dac_write(&dac_hdl, mono_data, len);
|
||||
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
|
||||
} else {
|
||||
/*输出一个mic的数据到DAC一个通道*/
|
||||
putchar('c');
|
||||
wlen = audio_dac_write(&dac_hdl, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
#if ADC_DEBUG_BUF
|
||||
|
||||
wdt_close();
|
||||
if (d_skip_cnt) {
|
||||
d_skip_cnt--;
|
||||
return;
|
||||
}
|
||||
|
||||
d_buf_cnt += len * ADC_DEMO_CH_NUM;
|
||||
if (d_buf_cnt >= ADC_DEBUF_SIZE) {
|
||||
wdt_close();
|
||||
local_irq_disable();
|
||||
printf(">>> hex\n\n");
|
||||
put_buf(d_buf, ADC_DEBUF_SIZE);
|
||||
printf(">>> hex end\n\n");
|
||||
u32 i;
|
||||
for (i = 0; i < ADC_DEBUF_SIZE / 2; i++) {
|
||||
/* printf("%d\n", d_buf[i]); */
|
||||
}
|
||||
printf(">>> printf end\n\n");
|
||||
while (1);
|
||||
}
|
||||
memcpy(d_ptr, data, len * ADC_DEMO_CH_NUM);
|
||||
d_ptr += len * ADC_DEMO_CH_NUM;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO Linein OUTPUT
|
||||
* Description: linein采样数据回调
|
||||
* Arguments : pric 私有参数
|
||||
* data mic数据
|
||||
* len 数据长度
|
||||
* Return : 0 成功 其他 失败
|
||||
* Note(s) : 单声道数据格式
|
||||
* L0 L1 L2 L3 L4 ...
|
||||
* 双声道数据格式()
|
||||
* L0 R0 L1 R1 L2 R2...
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#define LINEIN_DEBUG_BUF (0)
|
||||
#define LINEIN_DEBUF_SIZE (32000)
|
||||
|
||||
#if LINEIN_DEBUG_BUF
|
||||
u32 l_skip_cnt = 100;
|
||||
s16 l_buf[LINEIN_DEBUF_SIZE / 2] = {0};
|
||||
u8 *l_ptr = l_buf;
|
||||
u32 l_buf_cnt = 0;
|
||||
#endif
|
||||
|
||||
|
||||
static void adc_linein_demo_output(void *priv, s16 *data, int len)
|
||||
{
|
||||
/* printf("> %d %d %d %d\n", data[0], data[1], data[2], data[3]); */
|
||||
int wlen = 0;
|
||||
if (linein_demo && linein_demo->adc_2_dac) {
|
||||
if (linein_demo->linein_ch_num >= 2) {
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
/*输出两个linein的数据到DAC两个通道,默认输出第一个和第二个采样通道的数据*/
|
||||
putchar('a');
|
||||
s16 temp[len * 2];
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
temp[2 * i] = data[linein_demo->linein_ch_num * i];
|
||||
temp[2 * i + 1] = data[linein_demo->linein_ch_num * i + 1];
|
||||
}
|
||||
wlen = audio_dac_write(&dac_hdl, temp, len * 2);
|
||||
#else
|
||||
/*输出其中一个linein的数据到DAC一个通道*/
|
||||
putchar('b');
|
||||
s16 *mono_data = data;
|
||||
for (int i = 0; i < (len / 2); i++) {
|
||||
switch (linein_demo->linein_ch_sel) {
|
||||
case 0:
|
||||
mono_data[i] = data[i * linein_demo->linein_ch_num]; /*第一路 linein采样的数据*/
|
||||
break;
|
||||
case 1:
|
||||
mono_data[i] = data[i * linein_demo->linein_ch_num + 1]; /*第一路 linein采样的数据*/
|
||||
break;
|
||||
case 2:
|
||||
mono_data[i] = data[i * linein_demo->linein_ch_num + 2]; /*第三路 linein采样的数据*/
|
||||
break;
|
||||
case 3:
|
||||
mono_data[i] = data[i * linein_demo->linein_ch_num + 3]; /*第四路 linein采样的数据*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#if LINEIN_DEBUG_BUF
|
||||
wdt_close();
|
||||
if (l_skip_cnt) {
|
||||
l_skip_cnt--;
|
||||
return;
|
||||
}
|
||||
|
||||
l_buf_cnt += len * ADC_DEMO_CH_NUM;
|
||||
if (l_buf_cnt >= LINEIN_DEBUF_SIZE) {
|
||||
wdt_close();
|
||||
local_irq_disable();
|
||||
printf(">>> hex\n\n");
|
||||
put_buf(l_buf, LINEIN_DEBUF_SIZE);
|
||||
printf(">>> hex end\n\n");
|
||||
u32 i;
|
||||
for (i = 0; i < LINEIN_DEBUF_SIZE / 2; i++) {
|
||||
/* printf("%d\n", l_buf[i]); */
|
||||
}
|
||||
printf(">>> printf end\n\n");
|
||||
while (1);
|
||||
}
|
||||
memcpy(l_ptr, data, len * ADC_DEMO_CH_NUM);
|
||||
l_ptr += len * ADC_DEMO_CH_NUM;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO ADC MIC OPEN
|
||||
* Description: 打开mic通道
|
||||
* Arguments : mic_idx mic通道
|
||||
* gain mic增益
|
||||
* sr mic采样率
|
||||
* mic_2_dac mic数据(通过DAC)监听
|
||||
* Return : None.
|
||||
* Note(s) : (1)打开一个mic通道示例:
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_0,10,16000,1);
|
||||
* 或者
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1,10,16000,1);
|
||||
* (2)打开两个mic通道示例:
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1|AUDIO_ADC_MIC_0,10,16000,1);
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac)
|
||||
{
|
||||
ADC_DEMO_LOG("audio_adc_mic_demo open:%d,gain:%d,sr:%d,mic_2_dac:%d\n", mic_idx, gain, sr, mic_2_dac);
|
||||
mic_demo = zalloc(sizeof(struct adc_demo));
|
||||
if (mic_demo) {
|
||||
//step0:打开mic通道,并设置增益
|
||||
audio_adc_mic_open(&mic_demo->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
|
||||
audio_adc_mic_set_gain(&mic_demo->mic_ch, gain);
|
||||
audio_adc_mic_0dB_en(1);
|
||||
|
||||
//step1:设置mic通道采样率
|
||||
audio_adc_mic_set_sample_rate(&mic_demo->mic_ch, sr);
|
||||
//step2:设置mic采样buf
|
||||
audio_adc_mic_set_buffs(&mic_demo->mic_ch, mic_demo->adc_buf, ADC_DEMO_IRQ_POINTS * 2, ADC_DEMO_BUF_NUM);
|
||||
//step3:设置mic采样输出回调函数
|
||||
mic_demo->adc_output.handler = adc_mic_demo_output;
|
||||
audio_adc_add_output_handler(&adc_hdl, &mic_demo->adc_output);
|
||||
//step4:启动mic通道采样
|
||||
audio_adc_mic_start(&mic_demo->mic_ch);
|
||||
|
||||
/*监听配置(可选)*/
|
||||
mic_demo->adc_2_dac = mic_2_dac;
|
||||
mic_demo->mic_idx = mic_idx;
|
||||
if (mic_2_dac) {
|
||||
ADC_DEMO_LOG("max_sys_vol:%d\n", get_max_sys_vol());
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
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);
|
||||
}
|
||||
}
|
||||
ADC_DEMO_LOG("audio_adc_mic_demo start succ\n");
|
||||
|
||||
int res = 0;
|
||||
int msg[16];
|
||||
// 循环一直往dac写数据
|
||||
#ifdef BT_DUT_ADC_INTERFERE
|
||||
while (0) {
|
||||
#else
|
||||
while (1) {
|
||||
#endif/*BT_DUT_ADC_INTERFERE*/
|
||||
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
|
||||
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
|
||||
os_time_dly(500);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO ADC MIC CLOSE
|
||||
* Description: 关闭mic采样模块
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_adc_mic_demo_close(void)
|
||||
{
|
||||
ADC_DEMO_LOG("audio_adc_mic_demo_close\n");
|
||||
if (mic_demo) {
|
||||
audio_adc_del_output_handler(&adc_hdl, &mic_demo->adc_output);
|
||||
audio_adc_mic_close(&mic_demo->mic_ch);
|
||||
free(mic_demo);
|
||||
mic_demo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* 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(AUDIO_ADC_LINE0,10,16000,1);
|
||||
* 或者
|
||||
* audio_adc_linein_demo_open(AUDIO_ADC_LINE1,10,16000,1);
|
||||
* (2)打开两个linein通道示例:
|
||||
* audio_adc_linein_demo_open(AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
|
||||
* (3)打开四个linein通道示例:
|
||||
* audio_adc_linein_demo_open(AUDIO_ADC_LINE3|AUDIO_ADC_LINE2|AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_adc_linein_demo_open(u8 linein_idx, u8 gain, u16 sr, u8 linein_2_dac)
|
||||
{
|
||||
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通道,并设置增益
|
||||
if (linein_idx & AUDIO_ADC_LINE0) {
|
||||
audio_adc_linein_open(&linein_demo->linein_ch, AUDIO_ADC_LINE0, &adc_hdl);
|
||||
audio_adc_linein_set_gain(&linein_demo->linein_ch, gain);
|
||||
audio_adc_linein_0dB_en(1);
|
||||
linein_demo->linein_ch_num += 1;
|
||||
}
|
||||
if (linein_idx & AUDIO_ADC_LINE1) {
|
||||
audio_adc_linein1_open(&linein_demo->linein_ch, AUDIO_ADC_LINE1, &adc_hdl);
|
||||
audio_adc_linein1_set_gain(&linein_demo->linein_ch, gain);
|
||||
audio_adc_linein1_0dB_en(1);
|
||||
linein_demo->linein_ch_num += 1;
|
||||
}
|
||||
if (linein_idx & AUDIO_ADC_LINE2) {
|
||||
audio_adc_linein2_open(&linein_demo->linein_ch, AUDIO_ADC_LINE2, &adc_hdl);
|
||||
audio_adc_linein2_set_gain(&linein_demo->linein_ch, gain);
|
||||
audio_adc_linein2_0dB_en(1);
|
||||
linein_demo->linein_ch_num += 1;
|
||||
|
||||
}
|
||||
if (linein_idx & AUDIO_ADC_LINE3) {
|
||||
audio_adc_linein3_open(&linein_demo->linein_ch, AUDIO_ADC_LINE3, &adc_hdl);
|
||||
audio_adc_linein3_set_gain(&linein_demo->linein_ch, gain);
|
||||
audio_adc_linein3_0dB_en(1);
|
||||
linein_demo->linein_ch_num += 1;
|
||||
}
|
||||
//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_add_output_handler(&adc_hdl, &linein_demo->adc_output);
|
||||
//step4:启动linein通道采样
|
||||
audio_adc_linein_start(&linein_demo->linein_ch);
|
||||
|
||||
/*监听配置(可选)*/
|
||||
linein_demo->adc_2_dac = linein_2_dac;
|
||||
linein_demo->linein_idx = linein_idx;
|
||||
if (linein_2_dac) {
|
||||
ADC_DEMO_LOG("max_sys_vol:%d\n", get_max_sys_vol());
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
|
||||
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);
|
||||
}
|
||||
}
|
||||
ADC_DEMO_LOG("audio_adc_linein_demo start succ\n");
|
||||
|
||||
int res = 0;
|
||||
int msg[16];
|
||||
// 循环一直往dac写数据
|
||||
while (1) {
|
||||
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
|
||||
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
|
||||
os_time_dly(500);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* 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_del_output_handler(&adc_hdl, &linein_demo->adc_output);
|
||||
audio_adc_linein_close(&linein_demo->linein_ch);
|
||||
free(linein_demo);
|
||||
linein_demo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//开启audio_adc接口 用于测试BT干扰
|
||||
void audio_adc_mic_dut_open(void)
|
||||
{
|
||||
audio_adc_mic_demo_open(AUDIO_ADC_MIC_0, 10, 16000, 0);
|
||||
}
|
||||
|
||||
|
||||
#if AUDIO_DEMO_LP_REG_ENABLE
|
||||
static u8 adc_demo_idle_query()
|
||||
{
|
||||
return mic_demo ? 0 : 1;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(adc_demo_lp_target) = {
|
||||
.name = "adc_demo",
|
||||
.is_idle = adc_demo_idle_query,
|
||||
};
|
||||
|
||||
#endif/*AUDIO_DEMO_LP_REG_ENABLE*/
|
||||
203
cpu/br28/audio_demo/audio_dac_demo.c
Normal file
203
cpu/br28/audio_demo/audio_dac_demo.c
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Audio DAC Demo
|
||||
*
|
||||
*Description : Audio DAC使用范例
|
||||
*Notes : 本demo为开发测试范例,请不要修改该demo, 如有需求,请自行
|
||||
* 复制再修改
|
||||
****************************************************************************
|
||||
*/
|
||||
#include "audio_demo.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "audio_demo.h"
|
||||
|
||||
#define KEY_TEST 0//(IO_PORTB_01)
|
||||
#define KEY_TEST2 0//(IO_PORTB_02)
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
static u8 dac_demo = 0;
|
||||
|
||||
// 用于 DAC 播放的正弦波数据
|
||||
const s16 data_sin44100[441] = {
|
||||
0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
|
||||
0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
|
||||
0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
|
||||
0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
|
||||
0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
|
||||
0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
|
||||
0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
|
||||
0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
|
||||
0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
|
||||
0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
|
||||
0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
|
||||
0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
|
||||
0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
|
||||
0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
|
||||
0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
|
||||
0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
|
||||
0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
|
||||
0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
|
||||
0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
|
||||
0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
|
||||
0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
|
||||
0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
|
||||
0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
|
||||
0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
|
||||
0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
|
||||
0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
|
||||
0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
|
||||
0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
|
||||
};
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO DAC OPEN
|
||||
* Description: 打开 dac demo
|
||||
* Arguments : None
|
||||
* Return : None.
|
||||
* Note(s) : dac 播放正弦波
|
||||
* 将这个函数放audio_dec_init()后调用即可
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_dac_demo_open(void)
|
||||
{
|
||||
int len = 0;
|
||||
int wlen = 0;
|
||||
s16 *ptr;
|
||||
s16 *data_addr;
|
||||
u32 data_len;
|
||||
|
||||
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol()); // 音量状态设置
|
||||
audio_dac_set_volume(&dac_hdl, get_max_sys_vol()); // dac 音量设置
|
||||
audio_dac_set_sample_rate(&dac_hdl, 44100); // 采样率设置
|
||||
audio_dac_start(&dac_hdl); // dac 启动
|
||||
|
||||
// 判断声道数,双声道需要复制多一个声道的数据
|
||||
if (dac_hdl.channel == 2) {
|
||||
data_addr = zalloc(441 * 2 * 2);
|
||||
if (!data_addr) {
|
||||
printf("demo dac malloc err !!\n");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 882; i++) {
|
||||
data_addr[i] = data_sin44100[i / 2];
|
||||
}
|
||||
data_len = 441 * 2 * 2;
|
||||
} else {
|
||||
data_addr = data_sin44100;
|
||||
data_len = 441 * 2;
|
||||
}
|
||||
|
||||
dac_demo = 1;
|
||||
int res = 0;
|
||||
int msg[16];
|
||||
u8 mode = 0;
|
||||
|
||||
#if KEY_TEST
|
||||
gpio_direction_input(KEY_TEST);
|
||||
gpio_set_pull_down(KEY_TEST, 0);
|
||||
gpio_set_pull_up(KEY_TEST, 1);
|
||||
gpio_set_die(KEY_TEST, 1);
|
||||
#endif
|
||||
#if KEY_TEST2
|
||||
gpio_direction_input(KEY_TEST2);
|
||||
gpio_set_pull_down(KEY_TEST2, 0);
|
||||
gpio_set_pull_up(KEY_TEST2, 1);
|
||||
gpio_set_die(KEY_TEST2, 1);
|
||||
#endif
|
||||
|
||||
// 循环一直往dac写数据
|
||||
while (1) {
|
||||
|
||||
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
|
||||
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
|
||||
|
||||
ptr = data_addr;
|
||||
len = data_len;
|
||||
while (len) {
|
||||
// 往 dac 写数据
|
||||
wlen = audio_dac_write(&dac_hdl, ptr, len);
|
||||
#if KEY_TEST
|
||||
if (0 == gpio_read(KEY_TEST)) {
|
||||
while (0 == gpio_read(KEY_TEST)) {
|
||||
os_time_dly(1);
|
||||
};
|
||||
mode++;
|
||||
if (mode >= 3) {
|
||||
mode = 0;
|
||||
}
|
||||
printf(">> mode:%d\n", mode);
|
||||
if (mode == 0) {
|
||||
JL_AUDIO->DAC_VL0 = 0;
|
||||
printf(">> silence\n");
|
||||
} else if (mode == 1) {
|
||||
JL_AUDIO->DAC_VL0 = 0x40004000;
|
||||
printf(">> 0dB\n");
|
||||
} else {
|
||||
JL_AUDIO->DAC_VL0 = 0x000F000F;
|
||||
printf(">> -60dB\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KEY_TEST2
|
||||
if (0 == gpio_read(KEY_TEST2)) {
|
||||
while (0 == gpio_read(KEY_TEST2)) {
|
||||
os_time_dly(1);
|
||||
};
|
||||
static u8 analog_gain = 0;
|
||||
|
||||
u32 TMP_CON1;
|
||||
TMP_CON1 = JL_ADDA->DAA_CON1;
|
||||
TMP_CON1 &= ~(0xf << 0 | 0xf << 4);
|
||||
TMP_CON1 |= ((u32)(analog_gain & 0xf) << 0) | ((u32)(analog_gain & 0xf) << 4);
|
||||
JL_ADDA->DAA_CON1 = TMP_CON1;
|
||||
printf(">>> analog_gain: %d\n", analog_gain);
|
||||
|
||||
analog_gain++;
|
||||
if (analog_gain > 15) {
|
||||
analog_gain = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (wlen != len) { // dac缓存满了,延时 10ms 后再继续写
|
||||
os_time_dly(1);
|
||||
}
|
||||
ptr += wlen / 2;
|
||||
len -= wlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO DAC CLOSE
|
||||
* Description: 关闭 dac demo
|
||||
* Arguments : None
|
||||
* Return : None.
|
||||
* Note(s) : dac 停止播放正弦波
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_dac_demo_close(void)
|
||||
{
|
||||
// 停止并关闭 DAC
|
||||
audio_dac_stop(&dac_hdl);
|
||||
audio_dac_close(&dac_hdl);
|
||||
dac_demo = 0;
|
||||
}
|
||||
|
||||
#if AUDIO_DEMO_LP_REG_ENABLE
|
||||
static u8 dac_demo_idle_query()
|
||||
{
|
||||
return dac_demo ? 0 : 1;
|
||||
}
|
||||
|
||||
REGISTER_LP_TARGET(dac_demo_lp_target) = {
|
||||
.name = "dac_demo",
|
||||
.is_idle = dac_demo_idle_query,
|
||||
};
|
||||
#endif/*AUDIO_DEMO_LP_REG_ENABLE*/
|
||||
|
||||
|
||||
158
cpu/br28/audio_demo/audio_demo.h
Normal file
158
cpu/br28/audio_demo/audio_demo.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Audio Demo Declaration
|
||||
*
|
||||
*Description : Audio Demo函数声明集合
|
||||
*Notes : None.
|
||||
****************************************************************************
|
||||
*/
|
||||
#ifndef __AUDIO_DEMO_H_
|
||||
#define __AUDIO_DEMO_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
/*audio demo低功耗注册查询,防止调用demo的时候,进入低功耗,影响测试*/
|
||||
#define AUDIO_DEMO_LP_REG_ENABLE 0
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* Audio DAC Demo APIs
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* Audio ADC Demo APIs
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO ADC MIC OPEN
|
||||
* Description: 打开mic通道
|
||||
* Arguments : mic_idx mic通道
|
||||
* gain mic增益
|
||||
* sr mic采样率
|
||||
* mic_2_dac mic数据(通过DAC)监听
|
||||
* Return : None.
|
||||
* Note(s) : (1)打开一个mic通道示例:
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_0,10,16000,1);
|
||||
* 或者
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1,10,16000,1);
|
||||
* (2)打开两个mic通道示例:
|
||||
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1|AUDIO_ADC_MIC_0,10,16000,1);
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO ADC MIC CLOSE
|
||||
* Description: 关闭mic采样模块
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_adc_mic_demo_close(void);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* Audio AudioLink(IIS) APIs
|
||||
*
|
||||
**********************************************************************/
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO IIS OUTPUT/INPUT OPEN
|
||||
* Description: 打开iis通道
|
||||
* Arguments : iis_rx 是否打开iis输入
|
||||
* iis_tx 是否打开iis输出
|
||||
* sr iis采样率
|
||||
* iis_rx_2_dac iis_rx数据(通过DAC)监听
|
||||
* Return : None.
|
||||
* Note(s) : (1)打开一个iis rx通道示例:
|
||||
* audio_link_demo_open(1,0,44100,1);
|
||||
* (2)打开一个iis tx通道示例:
|
||||
* audio_link_demo_open(0,1,44100,0);
|
||||
* (3)同时打开iis tx 和 rx 通道示例:
|
||||
* audio_link_demo_open(1,1,44100,1);
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_link_demo_open(u8 iis_rx, u8 iis_tx, u16 sr, u8 iis_rx_2_dac);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO IIS OUTPUT/INPUT OPEN
|
||||
* Description: 打开iis通道
|
||||
* Arguments : iis_rx 是否关闭iis输入
|
||||
* iis_tx 是否关闭iis输出
|
||||
* Return : None.
|
||||
* Note(s) : (1)关闭一个iis rx通道示例:
|
||||
* audio_link_demo_open(1,0);
|
||||
* (2)关闭一个iis tx通道示例:
|
||||
* audio_link_demo_open(0,1);
|
||||
* (3)同时关闭iis tx 和 rx 通道示例:
|
||||
* audio_link_demo_open(1,1);
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_link_demo_close(u8 iis_rx, u8 iis_tx);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* Audio PDM APIs
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO PDM MIC OPEN
|
||||
* Description: 打开pdm mic模块
|
||||
* Arguments : sample pdm mic采样率
|
||||
* mic_2_dac mic数据(通过DAC)监听
|
||||
* Return : None.
|
||||
* Note(s) : (1)打开pdm mic通道示例:
|
||||
* audio_plnk_demo_open(16000, 1);
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_plnk_demo_open(u16 sample, u8 mic_2_dac);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* AUDIO PDM MIC CLOSE
|
||||
* Description: 关闭pdm mic模块
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
// void audio_plnk_demo_close(void);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* hw_fft_demo_real
|
||||
* Description: 实数数据 FFT 运算 demo
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
// extern void hw_fft_demo_real();
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* hw_fft_demo_complex
|
||||
* Description: 复数数据 FFT 运算 demo
|
||||
* Arguments : None.
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
// extern void hw_fft_demo_complex();
|
||||
|
||||
#endif/*__AUDIO_DEMO_H_*/
|
||||
|
||||
101
cpu/br28/audio_demo/audio_fft_demo.c
Normal file
101
cpu/br28/audio_demo/audio_fft_demo.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Audio FFT Demo
|
||||
*
|
||||
*Description : Audio FFT使用范例
|
||||
*Notes :
|
||||
*(1)本demo为开发测试范例,请不要修改该demo, 如有需求,请自行复制再修改
|
||||
*(2)FFT输入数据位宽
|
||||
*----------------------------------------------------------------------
|
||||
* FFT模式 FFT点数 最大输入位宽
|
||||
*----------------------------------------------------------------------
|
||||
* 复数 64 [21:0]
|
||||
* 128 [20:0]
|
||||
* 256 [19:0]
|
||||
* 512 [18:0]
|
||||
* 1024 [17:0]
|
||||
*----------------------------------------------------------------------
|
||||
* 实数 64 [20:0]
|
||||
* 128 [18:0]
|
||||
* 256 [17:0]
|
||||
* 512 [18:0]
|
||||
* 1024 [16:0]
|
||||
*----------------------------------------------------------------------
|
||||
*(3)IFFT输入位宽:[29:0]
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include "audio_demo.h"
|
||||
#include "hw_fft.h"
|
||||
|
||||
// For 128 point Real_FFT test
|
||||
void hw_fft_demo_real()
|
||||
{
|
||||
|
||||
int tmpbuf[130]; // 130 = (128/2+1)*2
|
||||
unsigned int fft_config;
|
||||
|
||||
printf("********* test start **************\n");
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
tmpbuf[i] = i + 1;
|
||||
printf("tmpbuf[%d]: %d \n", i, tmpbuf[i]);
|
||||
}
|
||||
|
||||
// Do 128 point FFT
|
||||
fft_config = hw_fft_config(128, 7, 1, 0, 1);
|
||||
|
||||
hw_fft_run(fft_config, tmpbuf, tmpbuf);
|
||||
|
||||
for (int i = 0; i < 130; i++) {
|
||||
printf("tmpbuf_[%d]: %d \n", i, tmpbuf[i]);
|
||||
}
|
||||
|
||||
// Do 128 point IFFT
|
||||
fft_config = hw_fft_config(128, 7, 1, 1, 1);
|
||||
|
||||
hw_fft_run(fft_config, tmpbuf, tmpbuf);
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
printf("tmpbuf_[%d]: %d \n", i, tmpbuf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// For 128 point Complex_FFT test
|
||||
void hw_fft_demo_complex()
|
||||
{
|
||||
|
||||
int tmpbuf[280]; // 280 = (128/2+1)*2*2
|
||||
unsigned int fft_config;
|
||||
|
||||
printf("********* test start **************\n");
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
tmpbuf[2 * i] = i + 1;
|
||||
tmpbuf[2 * i + 1] = i + 1;
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
|
||||
}
|
||||
|
||||
// Do 128 point FFT
|
||||
|
||||
fft_config = hw_fft_config(128, 7, 1, 0, 0);
|
||||
|
||||
hw_fft_run(fft_config, tmpbuf, tmpbuf);
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
|
||||
}
|
||||
|
||||
// Do 128 point IFFT
|
||||
fft_config = hw_fft_config(128, 7, 1, 1, 0);
|
||||
|
||||
hw_fft_run(fft_config, tmpbuf, tmpbuf);
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
|
||||
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
558
cpu/br28/audio_demo/audio_matrix_demo.c
Normal file
558
cpu/br28/audio_demo/audio_matrix_demo.c
Normal file
@ -0,0 +1,558 @@
|
||||
#include "asm/MatrixInteFunc.h"
|
||||
|
||||
char src_a_u8[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
char src_b_u8[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
|
||||
char dst_u8[16]__attribute__((aligned(4)));
|
||||
short int src_a_16[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
short int src_b_16[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
|
||||
short int dst_16[16]__attribute__((aligned(4)));
|
||||
int src_a_32[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
int src_b_32[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
|
||||
int dst_32[16]__attribute__((aligned(4)));
|
||||
|
||||
MC MC_t;
|
||||
MXYZ MXYZ_a, MXYZ_b, MXYZ_c;
|
||||
void test_MatrixInteFunc_add_sub()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 4 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
|
||||
MXYZ_a.Dw = DW_16;
|
||||
MXYZ_a.RowStep = MXYZ_a.Dw ;
|
||||
MXYZ_a.ColStep = MXYZ_a.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_a.Conj = 0;
|
||||
|
||||
MXYZ_b.Dw = DW_16;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
|
||||
MXYZ_b.RowStep = MXYZ_b.Dw ;
|
||||
MXYZ_b.ColStep = MXYZ_b.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_b.Conj = 0;
|
||||
|
||||
MXYZ_c.Dw = DW_16;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_16;
|
||||
MXYZ_c.RowStep = MXYZ_c.Dw ;
|
||||
MXYZ_c.ColStep = MXYZ_c.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_c.Conj = 0;
|
||||
|
||||
MatrixADD_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_16[k]);
|
||||
}
|
||||
|
||||
//sub
|
||||
//MXYZ_a.MatAdr = &src_a_16;
|
||||
MXYZ_a.Dw = DW_16;
|
||||
MXYZ_a.RowStep = MXYZ_a.Dw ;
|
||||
MXYZ_a.ColStep = MXYZ_a.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_a.Conj = 0;
|
||||
|
||||
MXYZ_b.Dw = DW_16;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
|
||||
MXYZ_b.RowStep = MXYZ_b.Dw ;
|
||||
MXYZ_b.ColStep = MXYZ_b.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_b.Conj = 0;
|
||||
|
||||
MXYZ_c.Dw = DW_16;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_16;
|
||||
MXYZ_c.RowStep = MXYZ_c.Dw ;
|
||||
MXYZ_c.ColStep = MXYZ_c.Dw * (MC_t.MatCol + 1);
|
||||
MXYZ_c.Conj = 0;
|
||||
|
||||
MatrixSUB_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_16[k]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void test_MatrixInteFunc_scale_add_sub()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 4 - 1;
|
||||
MC_t.MatQ = 1;
|
||||
MC_t.RS = 4;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
|
||||
MXYZ_a.RowStep = 1;
|
||||
MXYZ_a.ColStep = 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_8;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
|
||||
MXYZ_b.RowStep = 1;
|
||||
MXYZ_b.ColStep = 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_8;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
|
||||
MXYZ_c.RowStep = 1;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_8;
|
||||
|
||||
MatrixScaleADD_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_u8[k]);
|
||||
}
|
||||
|
||||
//sub
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_16;
|
||||
MXYZ_a.Dw = DW_16;
|
||||
MXYZ_b.Dw = DW_16;
|
||||
MXYZ_c.Dw = DW_16;
|
||||
MXYZ_a.RowStep = 1 * 2;
|
||||
MXYZ_a.ColStep = 4 * 2;
|
||||
MXYZ_b.RowStep = 1 * 2;
|
||||
MXYZ_b.ColStep = 4 * 2;
|
||||
MXYZ_c.RowStep = 1 * 2;
|
||||
MXYZ_c.ColStep = 4 * 2;
|
||||
MatrixScaleSUB_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_16[k]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void test_MatrixInteFunc_scale_mul_mla_mls()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 4 - 1;
|
||||
MC_t.MatQ = 1;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
|
||||
MXYZ_a.RowStep = 1;
|
||||
MXYZ_a.ColStep = 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_8;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
|
||||
MXYZ_b.RowStep = 1;
|
||||
MXYZ_b.ColStep = 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_8;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
|
||||
MXYZ_c.RowStep = 1;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_8;
|
||||
|
||||
MatrixScaleMUL_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
//
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_u8[k]);
|
||||
}
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
dst_32[k] = k;
|
||||
}
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
MXYZ_a.RowStep = 1 * 4;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_b.RowStep = 1 * 4;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_c.RowStep = 1 * 4;
|
||||
MXYZ_c.ColStep = 4 * 4;
|
||||
|
||||
MatrixScaleMLA_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_32[k]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
for (int k = 0; k < 8; k++) {
|
||||
dst_32[k] = -1;
|
||||
}
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
MatrixScaleMLS_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_32[k]);
|
||||
}
|
||||
|
||||
}
|
||||
void test_Matvec_mul()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 4 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_a.RowStep = 1 * 4;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_b.RowStep = 1 * 4;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
|
||||
/*MXYZ_c.MatAdr = &dst_32;
|
||||
MXYZ_c.RowStep = 1;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_32;*/
|
||||
int sum;
|
||||
MatVecMUL_Real(&MXYZ_a, &MXYZ_b, &sum, &MC_t, 1);
|
||||
//
|
||||
/*for(int k = 0;k<8;k++)
|
||||
{
|
||||
printf("dst_u8=%d\n",dst_32[k]);
|
||||
}*/
|
||||
printf("sum=%d\n", sum);
|
||||
}
|
||||
|
||||
|
||||
//complex
|
||||
void test_MatrixInteFunc_add_sub_complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
|
||||
MXYZ_a.RowStep = 1 * 2;
|
||||
MXYZ_a.ColStep = 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_8;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
|
||||
MXYZ_b.RowStep = 1 * 2;
|
||||
MXYZ_b.ColStep = 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_8;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
|
||||
MXYZ_c.RowStep = 1 * 2;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_8;
|
||||
|
||||
MatrixADD_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_u8[k]);
|
||||
}
|
||||
|
||||
//sub
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_16;
|
||||
MXYZ_a.Dw = DW_16;
|
||||
MXYZ_b.Dw = DW_16;
|
||||
MXYZ_c.Dw = DW_16;
|
||||
MXYZ_a.RowStep = 1 * 2 * 2;
|
||||
MXYZ_a.ColStep = 4 * 2;
|
||||
MXYZ_b.RowStep = 1 * 2 * 2;
|
||||
MXYZ_b.ColStep = 4 * 2;
|
||||
MXYZ_c.RowStep = 1 * 2 * 2;
|
||||
MXYZ_c.ColStep = 4 * 2;
|
||||
MatrixSUB_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_16[k]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void test_MatrixInteFunc_scale_add_sub_complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 1;
|
||||
MC_t.RS = 4;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
|
||||
MXYZ_a.RowStep = 1 * 2;
|
||||
MXYZ_a.ColStep = 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_8;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
|
||||
MXYZ_b.RowStep = 1 * 2;
|
||||
MXYZ_b.ColStep = 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_8;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
|
||||
MXYZ_c.RowStep = 1 * 2;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_8;
|
||||
|
||||
MatrixScaleADD_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_u8[k]);
|
||||
}
|
||||
|
||||
//sub
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_16;
|
||||
MXYZ_a.Dw = DW_16;
|
||||
MXYZ_b.Dw = DW_16;
|
||||
MXYZ_c.Dw = DW_16;
|
||||
MXYZ_a.RowStep = 1 * 2 * 2;
|
||||
MXYZ_a.ColStep = 4 * 2;
|
||||
MXYZ_b.RowStep = 1 * 2 * 2;
|
||||
MXYZ_b.ColStep = 4 * 2;
|
||||
MXYZ_c.RowStep = 1 * 2 * 2;
|
||||
MXYZ_c.ColStep = 4 * 2;
|
||||
|
||||
MatrixScaleSUB_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_16[k]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void test_MatrixInteFunc_scale_mul_mla_mls_complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 1;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
|
||||
MXYZ_a.RowStep = 1 * 2;
|
||||
MXYZ_a.ColStep = 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_8;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
|
||||
MXYZ_b.RowStep = 1 * 2;
|
||||
MXYZ_b.ColStep = 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_8;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
|
||||
MXYZ_c.RowStep = 1 * 2;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_8;
|
||||
|
||||
MatrixScaleMUL_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
//
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_u8[k]);
|
||||
}
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
dst_32[k] = k;
|
||||
}
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
MXYZ_a.RowStep = 1 * 4 * 2;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_b.RowStep = 1 * 4 * 2;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_c.RowStep = 1 * 4 * 2;
|
||||
MXYZ_c.ColStep = 4 * 4;
|
||||
MatrixScaleMLA_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_32[k]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
for (int k = 0; k < 8; k++) {
|
||||
dst_32[k] = -1;
|
||||
}
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
MatrixScaleMLS_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_16=%d\n", dst_32[k]);
|
||||
}
|
||||
|
||||
}
|
||||
void test_Matvec_mul_complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_a.RowStep = 1 * 4 * 2;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_b.RowStep = 1 * 4 * 2;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
|
||||
/*MXYZ_c.MatAdr = &dst_32;
|
||||
MXYZ_c.RowStep = 1;
|
||||
MXYZ_c.ColStep = 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_32;*/
|
||||
int sum[2];
|
||||
MatVecMUL_Complex(&MXYZ_a, &MXYZ_b, (int *)&sum, &MC_t, -1);
|
||||
//
|
||||
/*for(int k = 0;k<8;k++)
|
||||
{
|
||||
printf("dst_u8=%d\n",dst_32[k]);
|
||||
}*/
|
||||
printf("sum1=%d\n", sum[0]);
|
||||
printf("sum2=%d\n", sum[1]);
|
||||
}
|
||||
|
||||
void test_MatrixComplexScaleMul_Complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 1;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_a.RowStep = 1 * 4;
|
||||
MXYZ_a.ColStep = 4 * 2;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
|
||||
MXYZ_b.RowStep = 1 * 4 * 2;
|
||||
MXYZ_b.ColStep = 4 * 2 * 2;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_c.RowStep = 1 * 4 * 2;
|
||||
MXYZ_c.ColStep = 4 * 2 * 2;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
|
||||
|
||||
MatrixComplexScaleMUL_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_32[k]);
|
||||
}
|
||||
}
|
||||
void test_MatrixMUL_Real()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 4 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_a.RowStep = 4;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
|
||||
int src_b_32_T[8]__attribute__((aligned(4))) = {4, 6, 10, 12, 5, 7, 11, 13};
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32_T;
|
||||
MXYZ_b.RowStep = 4;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_c.RowStep = 4;
|
||||
MXYZ_c.ColStep = 4 * 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
|
||||
MatrixMUL_Real(&MXYZ_b, &MXYZ_a, &MXYZ_c, &MC_t, -1);
|
||||
//
|
||||
for (int k = 0; k < 4; k++) {
|
||||
printf("dst_u8=%d\n", dst_32[k]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_MatrixMUL_Complex()
|
||||
{
|
||||
printf(__func__);
|
||||
printf("ssssssnnn\n");
|
||||
|
||||
MC_t.MatRow = 2 - 1;
|
||||
MC_t.MatCol = 2 - 1;
|
||||
MC_t.MatQ = 0;
|
||||
MC_t.RS = 0;
|
||||
|
||||
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
|
||||
MXYZ_a.RowStep = 4;
|
||||
MXYZ_a.ColStep = 4 * 4;
|
||||
MXYZ_a.Conj = 0;
|
||||
MXYZ_a.Dw = DW_32;
|
||||
|
||||
int src_b_32_T1[8]__attribute__((aligned(4))) = {4, 5, 10, 11, 6, 7, 12, 13};
|
||||
|
||||
MXYZ_b.MatAdr = (unsigned int)&src_b_32_T1;
|
||||
MXYZ_b.RowStep = 4;
|
||||
MXYZ_b.ColStep = 4 * 4;
|
||||
MXYZ_b.Conj = 0;
|
||||
MXYZ_b.Dw = DW_32;
|
||||
|
||||
MXYZ_c.MatAdr = (unsigned int)&dst_32;
|
||||
MXYZ_c.RowStep = 4;
|
||||
MXYZ_c.ColStep = 4 * 4;
|
||||
MXYZ_c.Conj = 0;
|
||||
MXYZ_c.Dw = DW_32;
|
||||
|
||||
MatrixMUL_Complex(&MXYZ_b, &MXYZ_a, &MXYZ_c, &MC_t, -1);
|
||||
//
|
||||
for (int k = 0; k < 8; k++) {
|
||||
printf("dst_u8=%d\n", dst_32[k]);
|
||||
}
|
||||
}
|
||||
|
||||
340
cpu/br28/audio_demo/audio_wind_detect_demo.c
Normal file
340
cpu/br28/audio_demo/audio_wind_detect_demo.c
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO_WIND_DETECT_DEMO
|
||||
* File : audio_wind_detect_demo.c
|
||||
* By :
|
||||
* Notes :风噪检测使用,请不要修改本demo,如有需求,请拷贝副
|
||||
* 本,自行修改!
|
||||
* Usage :
|
||||
*(1)需要打开双麦的宏 TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
*(2)需要使用第二版双麦算法 CONST_DMS_GLOBAL_VERSION = DMS_GLOBAL_V200
|
||||
*(3)调用audio_wind_detect_demo_open();使用
|
||||
****************************************************************
|
||||
*/
|
||||
#include "audio_wind_detect_demo.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "audio_adc.h"
|
||||
#include "audio_enc.h"
|
||||
#include "aec_user.h"
|
||||
#include "task.h"
|
||||
#include "cvp/cvp_common.h"
|
||||
#include "lib_h/jlsp_ns.h"
|
||||
#include "online_db_deal.h"
|
||||
#include "spp_user.h"
|
||||
#include "overlay_code.h"
|
||||
#include "app_main.h"
|
||||
|
||||
|
||||
#define WIND_DETECT_TASK_NAME "WindDetect"
|
||||
/* 通过蓝牙spp发送风噪信息
|
||||
* 需要同时打开USER_SUPPORT_PROFILE_SPP和APP_ONLINE_DEBUG*/
|
||||
#define WIND_DETECT_INFO_SPP_DEBUG_ENABLE 0
|
||||
|
||||
#define AUDIO_ADC_BUF_NUM 3 //mic_adc采样buf个数
|
||||
#define AUDIO_ADC_IRQ_POINTS 256 //mic_adc采样长度(单位:点数)
|
||||
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
#define AUDIO_ADC_CH 3 //3mic通话
|
||||
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
#define AUDIO_ADC_CH 2 //双mic通话
|
||||
#else
|
||||
#define AUDIO_ADC_CH 1 //单mic通话
|
||||
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
|
||||
#define AUDIO_ADC_BUFS_SIZE (AUDIO_ADC_BUF_NUM * AUDIO_ADC_IRQ_POINTS * AUDIO_ADC_CH)
|
||||
|
||||
struct audio_mic_hdl {
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
struct adc_mic_ch mic_ch;
|
||||
int adc_dump_cnt;
|
||||
s16 adc_buf[AUDIO_ADC_BUFS_SIZE]; //align 2Bytes
|
||||
#if (AUDIO_ADC_CH > 1)
|
||||
s16 tmp_buf[AUDIO_ADC_IRQ_POINTS];
|
||||
#endif/*AUDIO_ADC_CH*/
|
||||
#if (AUDIO_ADC_CH > 2)
|
||||
s16 tmp_buf_1[AUDIO_ADC_IRQ_POINTS];
|
||||
#endif/*AUDIO_ADC_CH*/
|
||||
};
|
||||
static struct audio_mic_hdl *audio_mic = NULL;
|
||||
extern struct audio_adc_hdl adc_hdl;
|
||||
|
||||
struct audio_wind_detect_hdl {
|
||||
int wd_flag;
|
||||
int wd_val;
|
||||
int wd_lev;
|
||||
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
|
||||
struct spp_operation_t *spp_opt;
|
||||
#endif
|
||||
};
|
||||
static struct audio_wind_detect_hdl *audio_wd = NULL;
|
||||
|
||||
void audio_mic_dump_set(u16 dump_cnt)
|
||||
{
|
||||
printf("adc_dump_cnt:%d\n", dump_cnt);
|
||||
if (audio_mic) {
|
||||
audio_mic->adc_dump_cnt = dump_cnt;
|
||||
}
|
||||
}
|
||||
/*adc_mic采样输出接口*/
|
||||
static void adc_mic_output_handler(void *priv, s16 *data, int len)
|
||||
{
|
||||
if (audio_mic) {
|
||||
if (audio_mic->adc_dump_cnt) {
|
||||
audio_mic->adc_dump_cnt--;
|
||||
//printf("[%d]",audio_mic->adc_dump_cnt);
|
||||
memset(data, 0, len);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (AUDIO_ADC_CH == 3)/*3 Mic*/
|
||||
s16 *mic0_data = data;
|
||||
s16 *mic1_data = data + (len / 2);
|
||||
s16 *mic2_data = data + (len / 2) * 2;
|
||||
int offset = 0;
|
||||
|
||||
s16 *mic1_data_pos = audio_mic->tmp_buf;
|
||||
s16 *mic2_data_pos = audio_mic->tmp_buf_1;
|
||||
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
|
||||
for (u16 i = 0; i < (len >> 1); i++) {
|
||||
mic0_data[i] = data[i * 3];
|
||||
mic1_data[i] = data[i * 3 + 1];
|
||||
mic2_data[i] = data[i * 3 + 2];
|
||||
}
|
||||
memcpy(mic1_data, mic1_data_pos, len);
|
||||
memcpy(mic2_data, mic2_data_pos, len);
|
||||
|
||||
offset = (len / 2) * app_var.talk_ref_mic_ch;
|
||||
audio_aec_inbuf_ref(data + offset, len);
|
||||
offset = (len / 2) * app_var.talk_fb_mic_ch;
|
||||
audio_aec_inbuf_ref_1(data + offset, len);
|
||||
offset = (len / 2) * app_var.talk_mic_ch;
|
||||
audio_aec_inbuf(data + offset, len);
|
||||
return;
|
||||
|
||||
#elif (AUDIO_ADC_CH == 2)/*DualMic*/
|
||||
s16 *mic0_data = data;
|
||||
s16 *mic1_data = audio_mic->tmp_buf;
|
||||
s16 *mic1_data_pos = data + (len / 2);
|
||||
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
|
||||
for (u16 i = 0; i < (len >> 1); i++) {
|
||||
mic0_data[i] = data[i * 2];
|
||||
mic1_data[i] = data[i * 2 + 1];
|
||||
}
|
||||
memcpy(mic1_data_pos, mic1_data, len);
|
||||
|
||||
#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
|
||||
audio_aec_inbuf_ref(mic1_data_pos, len);
|
||||
audio_aec_inbuf(data, len);
|
||||
#else
|
||||
audio_aec_inbuf_ref(data, len);
|
||||
audio_aec_inbuf(mic1_data_pos, len);
|
||||
#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
|
||||
|
||||
#else/*SingleMic*/
|
||||
audio_aec_inbuf(data, len);
|
||||
#endif/*ESCO_ADC_CH*/
|
||||
}
|
||||
}
|
||||
|
||||
/*mic初始化*/
|
||||
static int audio_mic_en(u8 en, u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
|
||||
{
|
||||
printf("audio_mic_en:%d\n", en);
|
||||
u8 mic_ch = en;
|
||||
if (en) {
|
||||
if (audio_mic) {
|
||||
printf("audio_mic re-malloc error\n");
|
||||
return -1;
|
||||
}
|
||||
audio_mic = zalloc(sizeof(struct audio_mic_hdl));
|
||||
if (audio_mic == NULL) {
|
||||
printf("audio mic zalloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
audio_mic_pwr_ctl(MIC_PWR_ON);
|
||||
|
||||
audio_mic_dump_set(3);/*处理开mic后在短时间起3次中断影响aec的问题*/
|
||||
if (en & AUDIO_ADC_MIC_0) {
|
||||
printf("adc_mic0 open,gain:%d\n", mic0_gain);
|
||||
audio_adc_mic_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic_set_gain(&audio_mic->mic_ch, mic0_gain);
|
||||
}
|
||||
if (en & AUDIO_ADC_MIC_1) {
|
||||
printf("adc_mic1 open,gain:%d\n", mic1_gain);
|
||||
audio_adc_mic1_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic1_set_gain(&audio_mic->mic_ch, mic1_gain);
|
||||
}
|
||||
if (en & AUDIO_ADC_MIC_2) {
|
||||
printf("adc_mic2 open,gain:%d\n", mic2_gain);
|
||||
audio_adc_mic2_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic2_set_gain(&audio_mic->mic_ch, mic2_gain);
|
||||
}
|
||||
if (en & AUDIO_ADC_MIC_3) {
|
||||
printf("adc_mic3 open,gain:%d\n", mic3_gain);
|
||||
audio_adc_mic3_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic3_set_gain(&audio_mic->mic_ch, mic3_gain);
|
||||
}
|
||||
audio_adc_mic_set_sample_rate(&audio_mic->mic_ch, sr);
|
||||
audio_adc_mic_set_buffs(&audio_mic->mic_ch, audio_mic->adc_buf,
|
||||
AUDIO_ADC_IRQ_POINTS * 2, AUDIO_ADC_BUF_NUM);
|
||||
audio_mic->adc_output.handler = adc_mic_output_handler;
|
||||
audio_adc_add_output_handler(&adc_hdl, &audio_mic->adc_output);
|
||||
audio_adc_mic_start(&audio_mic->mic_ch);
|
||||
} else {
|
||||
if (audio_mic) {
|
||||
audio_adc_mic_close(&audio_mic->mic_ch);
|
||||
audio_adc_del_output_handler(&adc_hdl, &audio_mic->adc_output);
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
free(audio_mic);
|
||||
audio_mic = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audio_wind_detect_output_hdl(s16 *data, int len)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
/*打开风噪检测*/
|
||||
int audio_wind_detect_open(u32 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
|
||||
{
|
||||
int err = 0;
|
||||
overlay_load_code(OVERLAY_AEC);
|
||||
audio_aec_open(sr, -1, audio_wind_detect_output_hdl);
|
||||
/* audio_aec_open(sr, WNC_EN | ENC_EN | AEC_EN, audio_wind_detect_output_hdl); */
|
||||
audio_mic_en(TCFG_AUDIO_ADC_MIC_CHA, sr, mic0_gain, mic1_gain, mic2_gain, mic3_gain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*关闭风噪检测*/
|
||||
int audio_wind_detect_close()
|
||||
{
|
||||
audio_aec_close();
|
||||
audio_mic_en(0, 0, 0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*风噪检测信息获取任务*/
|
||||
static void audio_wind_detect_task(void *p)
|
||||
{
|
||||
while (1) {
|
||||
os_time_dly(10);
|
||||
audio_get_wind_detect_info();
|
||||
}
|
||||
}
|
||||
|
||||
/*打开获取风噪信息的任务*/
|
||||
int audio_wind_info_task_open()
|
||||
{
|
||||
int err = 0;
|
||||
if (audio_wd) {
|
||||
printf("[err] audio_wd re-malloc !!!");
|
||||
return -1;
|
||||
}
|
||||
audio_wd = zalloc(sizeof(struct audio_wind_detect_hdl));
|
||||
if (audio_wd == NULL) {
|
||||
printf("[err] audio_wd malloc fail !!!");
|
||||
return 0;
|
||||
}
|
||||
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
|
||||
spp_get_operation_table(&audio_wd->spp_opt);
|
||||
#endif
|
||||
overlay_load_code(OVERLAY_AEC);
|
||||
err = os_task_create(audio_wind_detect_task, NULL, 2, 256, 128, WIND_DETECT_TASK_NAME);
|
||||
/* err = task_create(audio_wind_detect_task, NULL, WIND_DETECT_TASK_NAME); */
|
||||
if (err != OS_NO_ERR) {
|
||||
printf("task create error!");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*关闭获取风噪信息的任务*/
|
||||
int audio_wind_info_task_close(void)
|
||||
{
|
||||
if (audio_wd) {
|
||||
/* task_kill(WIND_DETECT_TASK_NAME); */
|
||||
os_task_del(WIND_DETECT_TASK_NAME);
|
||||
free(audio_wd);
|
||||
audio_wd = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*打开风噪检测的demo*/
|
||||
int audio_wind_detect_demo_open(void)
|
||||
{
|
||||
/*打开风噪检测*/
|
||||
audio_wind_detect_open(16000, 4, 4, 1, 1);
|
||||
/*获取风噪的信息*/
|
||||
audio_wind_info_task_open();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*关闭风噪检测的demo*/
|
||||
int audio_wind_detect_demo_close(void)
|
||||
{
|
||||
audio_wind_detect_close();
|
||||
audio_wind_info_task_close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*获取风噪信息*/
|
||||
int audio_get_wind_detect_info(void)
|
||||
{
|
||||
if (audio_wd) {
|
||||
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
|
||||
jlsp_tms_get_wind_detect_info(&audio_wd->wd_flag, &audio_wd->wd_val, &audio_wd->wd_lev);
|
||||
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
|
||||
jlsp_get_wind_detect_info(&audio_wd->wd_flag, &audio_wd->wd_val, &audio_wd->wd_lev);
|
||||
#endif
|
||||
printf("wd_flag:%d, wd_val:%d, wd_lev:%d", audio_wd->wd_flag, audio_wd->wd_val, audio_wd->wd_lev);
|
||||
|
||||
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
|
||||
if (audio_wd->spp_opt && audio_wd->spp_opt->send_data) {
|
||||
char tmpbuf[25];
|
||||
memset(tmpbuf, 0x20, sizeof(tmpbuf));
|
||||
sprintf(tmpbuf, "falg:%d, val:%d, lev:%d", audio_wd->wd_flag, audio_wd->wd_val, audio_wd->wd_lev);
|
||||
audio_wd->spp_opt->send_data(NULL, tmpbuf, sizeof(tmpbuf));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*获取是否有风,0:无风,1:有风*/
|
||||
int audio_get_wd_flag(void)
|
||||
{
|
||||
if (audio_wd) {
|
||||
return audio_wd->wd_flag;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*获取风强*/
|
||||
int audio_get_wd_val(void)
|
||||
{
|
||||
if (audio_wd) {
|
||||
return audio_wd->wd_val;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/*获取预设的风噪等级, 0:弱风,1:中风:2:强风*/
|
||||
int audio_get_wd_lev(void)
|
||||
{
|
||||
if (audio_wd) {
|
||||
return audio_wd->wd_lev;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u8 audio_wind_detect_idle_query()
|
||||
{
|
||||
return (audio_wd == NULL) ? 1 : 0;
|
||||
}
|
||||
REGISTER_LP_TARGET(audio_wind_detect_lp_target) = {
|
||||
.name = "audio_wind_detect",
|
||||
.is_idle = audio_wind_detect_idle_query,
|
||||
};
|
||||
|
||||
|
||||
35
cpu/br28/audio_demo/audio_wind_detect_demo.h
Normal file
35
cpu/br28/audio_demo/audio_wind_detect_demo.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __AUDIO_WIND_DETECT_DEMO_H_
|
||||
#define __AUDIO_WIND_DETECT_DEMO_H_
|
||||
#include "generic/typedef.h"
|
||||
|
||||
/*打开风噪检测的demo*/
|
||||
int audio_wind_detect_demo_open(void);
|
||||
|
||||
/*关闭风噪检测的demo*/
|
||||
int audio_wind_detect_demo_close(void);
|
||||
|
||||
/*打开风噪检测*/
|
||||
int audio_wind_detect_open(u32 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain);
|
||||
|
||||
/*关闭风噪检测*/
|
||||
int audio_wind_detect_close();
|
||||
|
||||
/*打开获取风噪信息的任务*/
|
||||
int audio_wind_info_task_open();
|
||||
|
||||
/*获取风噪信息*/
|
||||
int audio_get_wind_detect_info(void);
|
||||
|
||||
/*关闭获取风噪信息的任务*/
|
||||
int audio_wind_info_task_close(void);
|
||||
|
||||
/*获取是否有风,0:无风,1:有风*/
|
||||
int audio_get_wd_flag(void);
|
||||
|
||||
/*获取风强*/
|
||||
int audio_get_wd_val(void);
|
||||
|
||||
/*获取预设的风噪等级, 0:弱风,1:中风:2:强风*/
|
||||
int audio_get_wd_lev(void);
|
||||
|
||||
#endif /* __AUDIO_WIND_DETECT_DEMO_H_*/
|
||||
67
cpu/br28/audio_effect_develop.c
Normal file
67
cpu/br28/audio_effect_develop.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file audio_effect_develop.c
|
||||
*
|
||||
* \brief 第三方音效算法添加
|
||||
*
|
||||
* Copyright (c) 2011-2023 ZhuHai Jieli Technology Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#include "app_config.h"
|
||||
#include "audio_effect_develop.h"
|
||||
|
||||
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
|
||||
struct audio_effect_develop_handle {
|
||||
int sample_rate;
|
||||
u8 nch;
|
||||
u8 bit_width;
|
||||
};
|
||||
|
||||
void *audio_effect_develop_open(int sample_rate, u8 nch, u8 bit_width)
|
||||
{
|
||||
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)zalloc(sizeof(struct audio_effect_develop_handle));
|
||||
|
||||
if (!hdl) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdl->sample_rate = sample_rate;
|
||||
hdl->nch = nch;
|
||||
hdl->bit_width = bit_width;
|
||||
|
||||
//TODO : 打开算法模块
|
||||
|
||||
return hdl;
|
||||
}
|
||||
|
||||
void audio_effect_develop_close(void *priv)
|
||||
{
|
||||
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)priv;
|
||||
|
||||
//TODO : 关闭算法模块
|
||||
|
||||
if (hdl) {
|
||||
free(hdl);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 音效算法开发处理函数
|
||||
* Input : priv - 第三方音效算法的主要私有句柄
|
||||
data - pcm数据(16bit)
|
||||
len - pcm数据的byte长度
|
||||
* Output : 数据处理长度
|
||||
* Notes :
|
||||
* History :
|
||||
*==============================================================*/
|
||||
int audio_effect_develop_data_handler(void *priv, void *data, int len)
|
||||
{
|
||||
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)priv;
|
||||
|
||||
//TODO : 音效运行
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif
|
||||
45
cpu/br28/audio_effect_develop.h
Normal file
45
cpu/br28/audio_effect_develop.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file audio_effect_develop.h
|
||||
*
|
||||
* \brief
|
||||
*
|
||||
* Copyright (c) 2011-2023 ZhuHai Jieli Technology Co.,Ltd.
|
||||
*
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef _AUDIO_EFFECT_DEVELOP_H_
|
||||
#define _AUDIO_EFFECT_DEVELOP_H_
|
||||
|
||||
/***********************************************************************
|
||||
* 音效算法开发打开
|
||||
* Input : sample_rate - 采样率
|
||||
nch - 声道数
|
||||
bit_width - 位宽(通常默认为16bit)
|
||||
* Output : 音效算法开发的主句柄
|
||||
* Notes :
|
||||
* History :
|
||||
*=====================================================================*/
|
||||
void *audio_effect_develop_open(int sample_rate, u8 nch, u8 bit_width);
|
||||
|
||||
/***********************************************************************
|
||||
* 音效算法开发关闭
|
||||
* Input : priv - 第三方音效算法的主要私有句柄
|
||||
* Output :
|
||||
* Notes :
|
||||
* History :
|
||||
*=====================================================================*/
|
||||
void audio_effect_develop_close(void *priv);
|
||||
|
||||
/***********************************************************************
|
||||
* 音效算法开发处理函数
|
||||
* Input : priv - 第三方音效算法的主要私有句柄
|
||||
data - pcm数据
|
||||
len - pcm数据的byte长度
|
||||
* Output : 数据处理长度
|
||||
* Notes :
|
||||
* History :
|
||||
*=====================================================================*/
|
||||
int audio_effect_develop_data_handler(void *priv, void *data, int len);
|
||||
|
||||
#endif
|
||||
1035
cpu/br28/audio_enc.c
Normal file
1035
cpu/br28/audio_enc.c
Normal file
File diff suppressed because it is too large
Load Diff
29
cpu/br28/audio_enc.h
Normal file
29
cpu/br28/audio_enc.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef _AUDIO_ENC_H_
|
||||
#define _AUDIO_ENC_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
|
||||
enum enc_source {
|
||||
ENCODE_SOURCE_MIX = 0x0,
|
||||
ENCODE_SOURCE_MIC,
|
||||
ENCODE_SOURCE_LINE0_LR,
|
||||
ENCODE_SOURCE_LINE1_LR,
|
||||
ENCODE_SOURCE_LINE2_LR,
|
||||
ENCODE_SOURCE_USER,
|
||||
};
|
||||
|
||||
enum {
|
||||
MIC_PWR_INIT = 1, /*开机状态*/
|
||||
MIC_PWR_ON, /*工作状态*/
|
||||
MIC_PWR_OFF, /*空闲状态*/
|
||||
MIC_PWR_DOWN, /*低功耗状态*/
|
||||
|
||||
};
|
||||
|
||||
int esco_enc_open(u32 coding_type, u8 frame_len);
|
||||
void esco_enc_close();
|
||||
void audio_mic_pwr_ctl(u8 state);
|
||||
u8 get_master_mic_gain(u8 master);
|
||||
void esco_mic_reset(void);
|
||||
void esco_mic_cfg_set(u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain);
|
||||
#endif/*_AUDIO_ENC_H_*/
|
||||
46
cpu/br28/audio_general.c
Normal file
46
cpu/br28/audio_general.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* AUDIO General APIs
|
||||
* Brief : 实现一些依赖CPU的通用接口,适配所有case
|
||||
* Notes :
|
||||
****************************************************************
|
||||
*/
|
||||
#include "system/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
|
||||
void audio_adda_dump(void) //打印所有的dac,adc寄存器
|
||||
{
|
||||
printf("JL_WL_AUD CON0:%x", JL_WL_AUD->CON0);
|
||||
printf("AUD_CON:%x", JL_AUDIO->AUD_CON);
|
||||
printf("DAC_CON:%x", JL_AUDIO->DAC_CON);
|
||||
printf("ADC_CON:%x", JL_AUDIO->ADC_CON);
|
||||
printf("ADC_CON1:%x", JL_AUDIO->ADC_CON1);
|
||||
printf("DAC_TM0:%x", JL_AUDIO->DAC_TM0);
|
||||
printf("DAA_CON 0:%x 1:%x, 2:%x, 3:%x 4:%x\n", JL_ADDA->DAA_CON0, JL_ADDA->DAA_CON1, JL_ADDA->DAA_CON2, JL_ADDA->DAA_CON3, JL_ADDA->DAA_CON4);
|
||||
printf("ADA_CON 0:%x 1:%x 2:%x 3:%x 4:%x 5:%x\n", JL_ADDA->ADA_CON0, JL_ADDA->ADA_CON1, JL_ADDA->ADA_CON2, JL_ADDA->ADA_CON3, JL_ADDA->ADA_CON4, JL_ADDA->ADA_CON5);
|
||||
}
|
||||
|
||||
void audio_gain_dump(void)
|
||||
{
|
||||
int dac_again_max = 7;
|
||||
u8 dac_again_l = JL_ADDA->DAA_CON1 & 0xF;
|
||||
u8 dac_again_r = (JL_ADDA->DAA_CON1 >> 4) & 0xF;
|
||||
int dac_dgain_max = 16384;
|
||||
u32 dac_dgain_l = JL_AUDIO->DAC_VL0 & 0xFFFF;
|
||||
u32 dac_dgain_r = (JL_AUDIO->DAC_VL0 >> 16) & 0xFFFF;
|
||||
|
||||
u8 mic0_0_6 = (JL_ADDA->ADA_CON4) & 0x1;
|
||||
u8 mic1_0_6 = (JL_ADDA->ADA_CON5) & 0x1;
|
||||
u8 mic2_0_6 = (JL_ADDA->ADA_CON6) & 0x1;
|
||||
u8 mic3_0_6 = (JL_ADDA->ADA_CON7) & 0x1;
|
||||
|
||||
u8 mic0_gain = JL_ADDA->ADA_CON8 & 0x1F;
|
||||
u8 mic1_gain = (JL_ADDA->ADA_CON8 >> 5) & 0x1F;
|
||||
u8 mic2_gain = (JL_ADDA->ADA_CON8 >> 10) & 0x1F;
|
||||
u8 mic3_gain = (JL_ADDA->ADA_CON8 >> 15) & 0x1F;
|
||||
|
||||
printf("L Mute:%d ,R Mute:%d\n", (JL_ADDA->DAA_CON2 >> 1) & 0x1, (JL_ADDA->DAA_CON2 >> 11) & 0x1); //PA MUTE
|
||||
printf("MIC_G:%d,%d,%d,%d,MIC_6dB_EN:%d,%d,%d,%d,DAC_AG_MAX:%d,DAC_AG:%d,%d,DAC_DG_MAX:%d,DAC_DG:%d,%d\n", mic0_gain, mic1_gain, mic2_gain, mic3_gain, mic0_0_6, mic1_0_6, mic2_0_6, mic3_0_6, dac_again_max, dac_again_l, dac_again_r, dac_dgain_max, dac_dgain_l, dac_dgain_r);
|
||||
|
||||
}
|
||||
1986
cpu/br28/audio_hearing/audio_hearing_aid.c
Normal file
1986
cpu/br28/audio_hearing/audio_hearing_aid.c
Normal file
File diff suppressed because it is too large
Load Diff
127
cpu/br28/audio_hearing/audio_hearing_aid.h
Normal file
127
cpu/br28/audio_hearing/audio_hearing_aid.h
Normal file
@ -0,0 +1,127 @@
|
||||
#ifndef _AUD_HEARING_AID_H_
|
||||
#define _AUD_HEARING_AID_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "board_config.h"
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* 可选功能模块配置(Optinal Module Define)
|
||||
************************************************************************/
|
||||
#define DHA_DATA_EXPORT_ENABLE 0 //数据导出使能, 需要先开APP_PCM_DEBUG
|
||||
#define DHA_RUN_TIME_TRACE_ENABLE 0 //运行时间log跟踪
|
||||
#define DHA_RUN_TIME_IO_DEBUG_ENABLE 0 //运行时间IO跟踪
|
||||
#ifdef DHA_RUN_TIME_IO_DEBUG_ENABLE
|
||||
#define IO_IDX 7
|
||||
#define IO_INTERVAL_IDX 4 /*DHA节奏,唤醒间隔*/
|
||||
#define DHA_IO_DEBUG_INIT() JL_PORTA->DIR &= ~BIT(IO_IDX)
|
||||
#define DHA_IO_DEBUG_1() JL_PORTA->OUT |= BIT(IO_IDX)
|
||||
#define DHA_IO_DEBUG_0() JL_PORTA->OUT &= ~BIT(IO_IDX)
|
||||
#define DHA_IO_INTERVAL() {JL_PORTA->DIR &= ~BIT(IO_INTERVAL_IDX);JL_PORTA->OUT ^= BIT(IO_INTERVAL_IDX);}
|
||||
#else
|
||||
#define DHA_IO_DEBUG_INIT(...)
|
||||
#define DHA_IO_DEBUG_1(...)
|
||||
#define DHA_IO_DEBUG_0(...)
|
||||
#define DHA_IO_INTERVAL(...)
|
||||
#endif/*DHA_RUN_TIME_IO_DEBUG_ENABLE*/
|
||||
|
||||
/*************************************************************************
|
||||
* 可选功能模块配置(Optinal Module Define)
|
||||
************************************************************************/
|
||||
#define DHA_AND_MEDIA_MUTEX_ENABLE 1 //辅听功能和多媒体播放互斥
|
||||
#define DHA_SRC_USE_HW_ENABLE 0 //SRC选择,1:使用硬件SRC,0:使用软件SRC
|
||||
#define DHA_MIC_DATA_CBUF_ENABLE 0 //是否使用cbuf缓存mic的数据
|
||||
#define DHA_DAC_OUTPUT_ENHANCE_ENABLE 0 //DAC输出音量增强使能:用来提高辅听的动态范围
|
||||
#define DHA_TDE_ENABLE 0 //辅听信号延时估计
|
||||
#define DHA_IN_LOUDNESS_TRACE_ENABLE 0 //跟踪获取当前mic输入幅值
|
||||
#define DHA_OUT_LOUDNESS_TRACE_ENABLE 0 //跟踪获取算法输出幅值
|
||||
#define DHA_USE_WDRC_ENABLE 1 //DRC选择,1:使用WDRC,0:使用普通限幅器DRC
|
||||
|
||||
/*************************************************************************
|
||||
* 验配功能定义(DHA Fitting Define)
|
||||
************************************************************************/
|
||||
|
||||
/*听力验配版本号*/
|
||||
#define DHA_FITTING_VERSION 0x01
|
||||
/*验配通道数*/
|
||||
#define DHA_FITTING_CHANNEL_MAX 6
|
||||
/*通道频率*/
|
||||
#define DHA_CH0_FREQ 250
|
||||
#define DHA_CH1_FREQ 500
|
||||
#define DHA_CH2_FREQ 1000
|
||||
#define DHA_CH3_FREQ 2000
|
||||
#define DHA_CH4_FREQ 4000
|
||||
#define DHA_CH5_FREQ 6000
|
||||
|
||||
/*
|
||||
* 1. PayLoad Format
|
||||
* +---------+---------------+------+
|
||||
* |cmd[8bit]|data_len[16bit]| data |
|
||||
* +---------+---------------+------+
|
||||
* 2.DHA Fitting Commands
|
||||
*/
|
||||
|
||||
|
||||
/*(1)验配信息交互:版本、通道数、通道频率*/
|
||||
#define DHA_FITTING_CMD_INFO 0x50
|
||||
typedef struct {
|
||||
u8 version; /*版本号:DHA_FITTING_VERSION*/
|
||||
u8 ch_num; /*通道数:DHA_FITTING_CHANNEL_MAX*/
|
||||
u16 ch_freq[DHA_FITTING_CHANNEL_MAX]; /*通道频率组:获取通道对应的freq*/
|
||||
} dha_fitting_info_t;
|
||||
|
||||
/*(2)通道验配*/
|
||||
#define DHA_FITTING_CMD_ADJUST 0x51
|
||||
typedef struct {
|
||||
u8 channel: 1; /*左右声道标识:0=左声道 1=右声道*/
|
||||
u8 sine: 2; /*开关验配单频音的标志: BIT(0) = 1 左耳播单频音,BIT(0) = 0 左耳静音
|
||||
BIT(1) = 1 右耳播单频音,BIT(1) = 0 右耳静音*/
|
||||
u8 reserve0: 5; /*保留*/
|
||||
u8 reserve1; /*保留*/
|
||||
u16 freq; /*通道频率*/
|
||||
float gain; /*通道增益*/
|
||||
} dha_fitting_adjust_t;
|
||||
|
||||
/*(3)验配结果保存更新*/
|
||||
/*
|
||||
+---------+------------+--------------------+-------------+---------------+
|
||||
|cmd[8bit]|len[16bit] | type(8bit)左/右/双耳|N个左耳[float]| N个右耳[float] |
|
||||
+---------+------------+--------------------+-------------+---------------+
|
||||
type(8bit) 0:左耳数据,1:右耳数据,2:双耳数据
|
||||
*/
|
||||
#define DHA_FITTING_CMD_UPDATE 0x52
|
||||
|
||||
/*(4)左右耳打开辅听的状态*/
|
||||
#define DHA_FITTING_CMD_STATE 0x53
|
||||
typedef struct {
|
||||
u8 state_left: 1;
|
||||
u8 state_right: 1;
|
||||
u8 reserve: 6;
|
||||
} dha_fitting_state_t;
|
||||
|
||||
/*************************************************************************
|
||||
* 辅听耳机接口声明(DHA APIs Declaration)
|
||||
************************************************************************/
|
||||
int audio_hearing_aid_open(void);
|
||||
int audio_hearing_aid_close(void);
|
||||
void audio_hearing_aid_demo(void);
|
||||
void audio_hearing_aid_resume(void);
|
||||
void audio_hearing_aid_suspend(void);
|
||||
int hearing_aid_fitting_parse(u8 *data, u16 len);
|
||||
int hearing_aid_fitting_start(u8 en);
|
||||
int get_hearing_aid_fitting_info(u8 *data);
|
||||
u8 get_hearing_aid_state(void);
|
||||
u8 get_hearing_aid_fitting_state(void);
|
||||
u8 set_hearing_aid_fitting_state(u8 state);
|
||||
void audio_dha_fitting_sync_close(void);
|
||||
int get_hearing_aid_state_cmd_info(u8 *data);
|
||||
|
||||
/*************************************************************************
|
||||
* 其他引用(Other Reference)
|
||||
************************************************************************/
|
||||
extern int aec_uart_open(u8 nch, u16 single_size);
|
||||
extern int aec_uart_fill(u8 ch, void *buf, u16 size);
|
||||
extern void aec_uart_write(void);
|
||||
extern int aec_uart_close(void);
|
||||
|
||||
#endif/*_AUD_HEARING_AID_H_*/
|
||||
352
cpu/br28/audio_hearing/audio_hearing_aid_lp.c
Normal file
352
cpu/br28/audio_hearing/audio_hearing_aid_lp.c
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
****************************************************************
|
||||
* Hearing Aid Low Power
|
||||
* 检测数据能量的函数
|
||||
* File : audi_hearing_aid_lp.c
|
||||
* By :
|
||||
* Notes :
|
||||
****************************************************************
|
||||
*/
|
||||
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "app_main.h"
|
||||
#include "audio_config.h"
|
||||
#include "app_action.h"
|
||||
#include "audio_hearing_aid_lp.h"
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
extern struct audio_adc_hdl adc_hdl;
|
||||
|
||||
#ifndef TCFG_AUDIO_DHA_MIC_SAMPLE_RATE
|
||||
#define TCFG_AUDIO_DHA_MIC_SAMPLE_RATE 32000
|
||||
#endif
|
||||
|
||||
//*********************************************************************************//
|
||||
// mic能量检测处理配置 //
|
||||
//*********************************************************************************//
|
||||
//是否开启mic 能量检测
|
||||
#define MIC_ENERGY_DETECT 1
|
||||
|
||||
//判断多少ms没有能量就进入低功耗
|
||||
#define MIC_SNIFF_TIME 2 * 60 * 1000
|
||||
//#define MIC_SNIFF_TIME 5 * 1000
|
||||
|
||||
//进入低功耗后每隔多少ms计算一次能量
|
||||
#define MIC_CHECK_INTER 1 * 1000
|
||||
|
||||
//低功耗状态下能量检测计算多少ms的能量
|
||||
#define MIC_ENERGY_TIME 20
|
||||
|
||||
//进入低功耗的能量值,小于此能量值进入低功耗
|
||||
#define enter_sniff_energy 50
|
||||
|
||||
//退出低功耗的能量值,大于退出低功耗 //从低功耗出来时adc 能量值会比较高,需要比较高的阈值
|
||||
#define exit_sniff_energy 170
|
||||
|
||||
//跳过刚上电的多少次中断数据
|
||||
#define adc_isr_ignore_cnt 8
|
||||
|
||||
//是否打开mic 能量的调试打印
|
||||
#define ENERGY_DEBUG_EN 0
|
||||
|
||||
static u8 enter_sleep = 0;
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
static u32 debug_size = 4096 * 2;
|
||||
/* static s16 debug_buf[4096 * 2]; */
|
||||
static u32 debug_p = 0;
|
||||
static u32 zero_cnt = 0;
|
||||
static u32 no_zero_cnt = 0;
|
||||
static u8 debug_flag = 0;
|
||||
#endif
|
||||
|
||||
struct hearing_aid_energy_detect {
|
||||
u32 exit_sniff_points; //一次检测的点数
|
||||
u32 abs_total_0; //mic0 的能量
|
||||
u32 abs_total_1; //mic1 的能量
|
||||
u32 points_count; //点数
|
||||
u32 energy_detect_flag;//是否开始计算能量的标志
|
||||
u32 enter_sniff_points; //多少个点的能量低于阈值进低功耗
|
||||
u32 exit_sniff_timer; //检测能量值定时器
|
||||
u16 dac_start_timer; //检测能量值定时器
|
||||
u16 dac_stop_timer; //检测能量值定时器
|
||||
u8 dac_start_flag; //dac 开启或关闭的标志位
|
||||
u8 isr_ignore_cnt; //跳过刚上电的多少次中断数据
|
||||
u8 adc_ch_num; //打开多少个mic通道
|
||||
struct adc_mic_ch mic_ch;
|
||||
s16 *adc_dma_buf;
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
u8 dac_open;
|
||||
void (*hw_open)(void);
|
||||
void (*hw_close)(void);
|
||||
};
|
||||
|
||||
static struct hearing_aid_energy_detect *mic_aid = NULL;
|
||||
|
||||
void exit_sniff_start(void) //定时能量检测,能量检测的时候mic能不能正常工作
|
||||
{
|
||||
#if ENERGY_DEBUG_EN
|
||||
printf("enter low_power_deal.c %d\n", __LINE__);
|
||||
#endif
|
||||
|
||||
mic_aid->energy_detect_flag = 1; //开始能量计算
|
||||
mic_aid->isr_ignore_cnt = adc_isr_ignore_cnt;
|
||||
|
||||
#if 1 //重新打开mic
|
||||
extern void hearing_aid_energy_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
|
||||
hearing_aid_energy_demo_open(TCFG_AD2DA_LOW_LATENCY_MIC_CHANNEL, 12, TCFG_AUDIO_DHA_MIC_SAMPLE_RATE, 0);
|
||||
/* audio_adc_mic_aid_open(mic_aid->mic_idx, mic_aid->gain, mic_aid->sr, 0); */
|
||||
#else
|
||||
SFR(JL_ADDA->DAA_CON0, 16, 1, 1); // VBG_EN_11v
|
||||
SFR(JL_ADDA->ADA_CON0, 17, 1, 0); // CTADCA_S2_RSTB
|
||||
os_time_dly(50);
|
||||
SFR(JL_ADDA->ADA_CON0, 17, 1, 1); // CTADCA_S2_RSTB
|
||||
SFR(JL_ADDA->DAA_CON0, 12, 1, 1); //AUDIO_IBIAS_EN_11V
|
||||
#endif
|
||||
|
||||
enter_sleep = 0; //退出低功耗
|
||||
sys_timer_del(mic_aid->exit_sniff_timer);
|
||||
}
|
||||
|
||||
|
||||
void dac_start_timer(void) //启动dac
|
||||
{
|
||||
#if ENERGY_DEBUG_EN
|
||||
printf("enter low_power_deal.c%d\n", __LINE__);
|
||||
#endif
|
||||
|
||||
extern void hearing_aid_energy_demo_close(void);
|
||||
hearing_aid_energy_demo_close();
|
||||
|
||||
printf("enter low_power_deal.c%d\n", __LINE__);
|
||||
|
||||
if (mic_aid->hw_open) {
|
||||
mic_aid->hw_open();
|
||||
}
|
||||
/* sound_pcm_dev_start(NULL, 16000, 10); */
|
||||
enter_sleep = 0; //退出低功耗
|
||||
/* mic_aid->adc_2_dac = 1; */
|
||||
mic_aid->dac_start_flag = 1 ;
|
||||
sys_timer_del(mic_aid->dac_start_timer);
|
||||
}
|
||||
|
||||
|
||||
void dac_stop_timer(void) //关闭dac
|
||||
{
|
||||
#if ENERGY_DEBUG_EN
|
||||
printf("enter low_power_deal.c%d\n", __LINE__);
|
||||
#endif
|
||||
|
||||
|
||||
extern void hearing_aid_energy_demo_close(void);
|
||||
hearing_aid_energy_demo_close();
|
||||
|
||||
if (mic_aid->hw_close) {
|
||||
|
||||
printf("enter low_power_deal.c%d,%p\n", __LINE__, mic_aid->hw_close);
|
||||
mic_aid->hw_close();
|
||||
}
|
||||
/* audio_adc_del_output_handler(&adc_hdl, &mic_aid->adc_output); */
|
||||
/* audio_adc_mic_close(&mic_aid->mic_ch); */
|
||||
mic_aid->adc_ch_num = 0; //mic_aid 被关了
|
||||
//将变量清0,开始新一轮计算
|
||||
mic_aid->abs_total_0 = 0;
|
||||
mic_aid->abs_total_1 = 0;
|
||||
mic_aid->points_count = 0;
|
||||
mic_aid->energy_detect_flag = 0;
|
||||
|
||||
enter_sleep = 1; //进入低功耗
|
||||
/* mic_aid->adc_2_dac = 0; */
|
||||
mic_aid->dac_start_flag = 0 ;
|
||||
sys_timer_del(mic_aid->dac_stop_timer);
|
||||
|
||||
printf("enter low_power_deal.c%d\n", __LINE__);
|
||||
}
|
||||
|
||||
|
||||
void audio_hearing_aid_lp_open(u8 ch_num, void (*hw_open)(void), void (*hw_close)(void)) //对多少个通道做数据处理
|
||||
{
|
||||
if (!mic_aid) {
|
||||
printf("enter low_power_deal.c%d\n", __LINE__);
|
||||
mic_aid = zalloc(sizeof(struct hearing_aid_energy_detect));
|
||||
}
|
||||
|
||||
#if 0
|
||||
else {
|
||||
/* memset(mic_aid,0,sizeof(struct hearing_aid_energy_detect)); */
|
||||
}
|
||||
#endif
|
||||
mic_aid->exit_sniff_points = MIC_ENERGY_TIME * (TCFG_AUDIO_DHA_MIC_SAMPLE_RATE / 1000); //进入低功耗后一次检测的点数
|
||||
mic_aid->enter_sniff_points = MIC_SNIFF_TIME * (TCFG_AUDIO_DHA_MIC_SAMPLE_RATE / 1000); //多少个点的能量低于阈值进低功耗
|
||||
mic_aid->adc_ch_num = ch_num;
|
||||
mic_aid-> hw_open = hw_open; //正常工作打开硬件的函数(关mic,关dac)
|
||||
mic_aid-> hw_close = hw_close; //进入低功耗关硬件的函数(开mic,开dac)
|
||||
mic_aid->abs_total_0 = 0;
|
||||
mic_aid->abs_total_1 = 0;
|
||||
mic_aid->points_count = 0;
|
||||
enter_sleep = 0;
|
||||
|
||||
}
|
||||
|
||||
void audio_hearing_aid_lp_close(void)
|
||||
{
|
||||
if (mic_aid) {
|
||||
free(mic_aid);
|
||||
mic_aid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
u8 audio_hearing_aid_lp_flag(void)
|
||||
{
|
||||
return enter_sleep;
|
||||
}
|
||||
|
||||
void audio_hearing_aid_lp_detect(void *priv, s16 *data, int len)
|
||||
{
|
||||
#if MIC_ENERGY_DETECT
|
||||
u32 points = len / 2;
|
||||
s16 *pdata = data;
|
||||
u32 i = 0;
|
||||
s32 total_0 = 0;
|
||||
s32 total_1 = 0;
|
||||
s16 diff = 0;
|
||||
u32 target_points = 0;
|
||||
u32 target_energy = 0;
|
||||
|
||||
if (enter_sleep == 0) { //低功耗期间也会进中断,不能计算能量值
|
||||
if (mic_aid->isr_ignore_cnt > 0) {
|
||||
mic_aid->isr_ignore_cnt--;
|
||||
return;
|
||||
} //跳过刚开始的一次中断数据
|
||||
|
||||
for (i = 0; i < points; i++) {
|
||||
total_0 += *pdata;
|
||||
pdata++;
|
||||
if (mic_aid->adc_ch_num == 2) {
|
||||
total_1 += *pdata;
|
||||
pdata++;
|
||||
}
|
||||
}
|
||||
|
||||
total_0 /= (len / 2 / mic_aid->adc_ch_num); //直流量
|
||||
total_1 /= (len / 2 / mic_aid->adc_ch_num);
|
||||
// printf(">> total_0 %d total_1 %d\n", total_0, total_1);
|
||||
pdata = data;
|
||||
|
||||
if (mic_aid->energy_detect_flag) { //由定时器启动的能量计算
|
||||
target_points = mic_aid->exit_sniff_points; //多少时间检测
|
||||
target_energy = exit_sniff_energy;
|
||||
} else {
|
||||
target_points = mic_aid-> enter_sniff_points; //正常工作检测多久
|
||||
target_energy = enter_sniff_energy;
|
||||
}
|
||||
|
||||
for (i = 0; i < points; i++) {
|
||||
#if ENERGY_DEBUG_EN
|
||||
#if 0
|
||||
if (debug_p < debug_size) {
|
||||
debug_buf[debug_p++] = *pdata ;
|
||||
if (*pdata == 0) {
|
||||
zero_cnt++;
|
||||
} else {
|
||||
no_zero_cnt++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
diff = *pdata - total_0;
|
||||
if (diff > 0) {
|
||||
mic_aid->abs_total_0 += diff;
|
||||
} else {
|
||||
mic_aid->abs_total_0 -= diff;
|
||||
}
|
||||
pdata++;
|
||||
if (mic_aid->adc_ch_num == 2) {
|
||||
diff = *pdata - total_1;
|
||||
if (diff > 0) {
|
||||
mic_aid->abs_total_1 += diff;
|
||||
} else {
|
||||
mic_aid->abs_total_1 -= diff;
|
||||
}
|
||||
pdata++;
|
||||
}
|
||||
mic_aid -> points_count++;
|
||||
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
/* printf("enter audio_adc_aid.c@@@@@@@@@@@@@@@@@@@@@@@@@@%d,%d,%d,%d\n",__LINE__,target_points,enter_sleep,mic_aid->points_count); */
|
||||
#endif
|
||||
|
||||
|
||||
if (mic_aid->points_count == target_points) {
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
printf("enter low_power_deal.c %d,%d,%d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1, mic_aid->points_count, target_points);
|
||||
#endif
|
||||
mic_aid->abs_total_0 /= target_points;
|
||||
mic_aid->abs_total_1 /= target_points;
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
printf("enter low_power_deal.c %d,%d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1, target_energy);
|
||||
#endif
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
extern void audio_adda_dump(void); //打印所有的dac,adc寄存器
|
||||
extern void audio_gain_dump();
|
||||
audio_adda_dump();
|
||||
audio_gain_dump();
|
||||
#endif
|
||||
|
||||
if ((mic_aid->abs_total_0 < target_energy) && (mic_aid->abs_total_1 < target_energy)) { //
|
||||
|
||||
|
||||
|
||||
|
||||
mic_aid->dac_stop_timer = sys_timer_add(NULL, dac_stop_timer, 1);
|
||||
mic_aid->exit_sniff_timer = sys_timer_add(NULL, exit_sniff_start, MIC_CHECK_INTER); //退出低功耗计算能量值
|
||||
#if ENERGY_DEBUG_EN
|
||||
debug_p = 0;
|
||||
zero_cnt = no_zero_cnt = 0;
|
||||
/* memset(debug_buf, 0, debug_size * 2); */
|
||||
printf("enter low_power_deal.c %d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1);
|
||||
#endif
|
||||
break;
|
||||
} else {
|
||||
//将变量清0,开始新一轮计算
|
||||
mic_aid->abs_total_0 = 0;
|
||||
mic_aid->abs_total_1 = 0;
|
||||
mic_aid->points_count = 0;
|
||||
mic_aid->energy_detect_flag = 0;
|
||||
enter_sleep = 0;
|
||||
|
||||
#if ENERGY_DEBUG_EN
|
||||
debug_p = 0;
|
||||
/* memset(debug_buf, 0, debug_size * 2); */
|
||||
zero_cnt = no_zero_cnt = 0;
|
||||
#endif
|
||||
|
||||
if (!audio_dac_is_working(&dac_hdl)) {
|
||||
|
||||
mic_aid->dac_start_timer = sys_timer_add(NULL, dac_start_timer, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} //end of if 点数等于 enter_sniff_points
|
||||
}//endf of for
|
||||
} //end of 低功耗期间也会进中断,不能计算能量值
|
||||
|
||||
if (mic_aid->dac_open == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
58
cpu/br28/audio_hearing/audio_hearing_aid_lp.h
Normal file
58
cpu/br28/audio_hearing/audio_hearing_aid_lp.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef _AUD_HEARING_AID_LOW_POWER_H_
|
||||
#define _AUD_HEARING_AID_LOW_POWER_H_
|
||||
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Energy Detect Open
|
||||
* Description: 打开低功耗能量检测功能
|
||||
* Arguments : ch_num 要处理的数据的通道数
|
||||
* hw_open 注册进去在出低功耗正常工作时会执行的回调
|
||||
a hw_close 注册进去在进低功耗时会执行的回调
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
void audio_hearing_aid_lp_open(u8 ch_num, void (*hw_open)(void), void (*hw_close)(void));
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Energy Detect Run
|
||||
* Description: 对传进去的数据进行能量检测,并根据结果决定进出低功耗
|
||||
* Arguments : priv 私有参数
|
||||
* data 要做处理的数据地址
|
||||
a len 要做处理的数据单个声道的数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
void audio_hearing_aid_lp_detect(void *priv, s16 *data, int len);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Energy Detect Close
|
||||
* Description: 关闭能量检测
|
||||
* Arguments : NULL
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
void audio_hearing_aid_lp_close(void);
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Get Low Power Flag
|
||||
* Description: 获取是否能进低功耗的标志位
|
||||
* Arguments : NULL
|
||||
* Return : 1:代表可以进入低功耗
|
||||
0:代表不能进入低功耗
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
u8 audio_hearing_aid_lp_flag(void);
|
||||
|
||||
#endif/*_AUD_HEARING_AID_LOW_POWER_H_*/
|
||||
169
cpu/br28/audio_hearing/audio_sidetone.c
Normal file
169
cpu/br28/audio_hearing/audio_sidetone.c
Normal file
@ -0,0 +1,169 @@
|
||||
#include "generic/typedef.h"
|
||||
#include "board_config.h"
|
||||
#include "media/includes.h"
|
||||
#include "audio_config.h"
|
||||
#include "sound_device.h"
|
||||
#include "audio_sidetone.h"
|
||||
#include "system/task.h"
|
||||
|
||||
#if TCFG_SIDETONE_ENABLE
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
#define SIDETONE_BUF_LEN 256
|
||||
#define SIDETONE_READBUF_LEN 64 //中断点数设为32,则每次数据长度为64
|
||||
static struct audio_sidetone_hdl {
|
||||
s16 *sidetone_buf;
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
s16 *sidetone_buf_lr;
|
||||
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
|
||||
cbuffer_t cbuf;
|
||||
OS_SEM sem;
|
||||
bool busy; //检测任务是否在阻塞态
|
||||
bool suspend; //暂停监听
|
||||
struct audio_dac_channel dac_ch;
|
||||
struct audio_dac_channel_attr attr;
|
||||
};
|
||||
static struct audio_sidetone_hdl *sidetone_hdl = NULL;
|
||||
|
||||
static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
|
||||
{
|
||||
s16 *mono = mono_pcm;
|
||||
int i = 0;
|
||||
u8 j = 0;
|
||||
|
||||
for (i = 0; i < points; i++, mono++) {
|
||||
*dual_pcm++ = *mono;
|
||||
*dual_pcm++ = *mono;
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_sidetone_task(void)
|
||||
{
|
||||
if (!sidetone_hdl) {
|
||||
sidetone_hdl = zalloc(sizeof(struct audio_sidetone_hdl));
|
||||
if (!sidetone_hdl) {
|
||||
printf("zalloc sidetone_hdl err\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
sidetone_hdl->suspend = 1;
|
||||
sidetone_hdl->sidetone_buf = zalloc(SIDETONE_BUF_LEN);
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
sidetone_hdl->sidetone_buf_lr = zalloc(SIDETONE_READBUF_LEN * 2);
|
||||
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
|
||||
cbuf_init(&sidetone_hdl->cbuf, sidetone_hdl->sidetone_buf, SIDETONE_BUF_LEN);
|
||||
os_sem_create(&sidetone_hdl->sem, 0);
|
||||
|
||||
audio_dac_new_channel(&dac_hdl, &sidetone_hdl->dac_ch);
|
||||
sidetone_hdl->attr.delay_time = 6;
|
||||
sidetone_hdl->attr.protect_time = 8;
|
||||
sidetone_hdl->attr.write_mode = WRITE_MODE_BLOCK;
|
||||
audio_dac_channel_set_attr(&sidetone_hdl->dac_ch, &sidetone_hdl->attr);
|
||||
sound_pcm_dev_start(&sidetone_hdl->dac_ch, 16000, app_audio_get_volume(APP_AUDIO_STATE_CALL));
|
||||
|
||||
while (1) {
|
||||
sidetone_hdl->busy = 0;
|
||||
os_sem_pend(&sidetone_hdl->sem, 0);
|
||||
sidetone_hdl->busy = 1;
|
||||
u16 rlen = cbuf_read(&sidetone_hdl->cbuf, sidetone_hdl->sidetone_buf, SIDETONE_READBUF_LEN);
|
||||
if (rlen != SIDETONE_READBUF_LEN) {
|
||||
printf("rlen err : %d\n", rlen);
|
||||
}
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
audio_pcm_mono_to_dual(sidetone_hdl->sidetone_buf_lr, sidetone_hdl->sidetone_buf, rlen >> 1);
|
||||
u16 wlen = sound_pcm_dev_write(&sidetone_hdl->dac_ch, sidetone_hdl->sidetone_buf_lr, rlen <<= 1);
|
||||
#else
|
||||
u16 wlen = sound_pcm_dev_write(&sidetone_hdl->dac_ch, sidetone_hdl->sidetone_buf, rlen);
|
||||
#endif
|
||||
if (wlen != rlen) {
|
||||
printf("wlen err : %d\n", wlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Sidetone Inbuf
|
||||
* Description: 通话监听数据流输入
|
||||
* Arguments : data 输入数据地址
|
||||
* len 输入数据长度
|
||||
* Return : None.
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
void audio_sidetone_inbuf(s16 *data, u16 len)
|
||||
{
|
||||
if (sidetone_hdl && sidetone_hdl->suspend) {
|
||||
os_sem_post(&sidetone_hdl->sem);
|
||||
u16 wlen = cbuf_write(&sidetone_hdl->cbuf, data, len);
|
||||
if (wlen != len) {
|
||||
printf("wlen = %d, len = %d\n", wlen, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Sidetone Open
|
||||
* Description: 打开通话监听
|
||||
* Arguments : None.
|
||||
* Return : 0成功 其他失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_sidetone_open(void)
|
||||
{
|
||||
if (!sidetone_hdl) {
|
||||
task_create(audio_sidetone_task, NULL, "sidetone");//创建监听任务
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Sidetone Close
|
||||
* Description: 关闭通话监听
|
||||
* Arguments : None.
|
||||
* Return : 0成功 其他失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_sidetone_close(void)
|
||||
{
|
||||
if (!sidetone_hdl) {
|
||||
printf("sidetone already close\n");
|
||||
return -1;
|
||||
}
|
||||
if (!sidetone_hdl->busy) { //任务处于挂起态
|
||||
sound_pcm_dev_stop(&sidetone_hdl->dac_ch); //关闭监听
|
||||
task_kill("sidetone");
|
||||
free(sidetone_hdl->sidetone_buf);
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
|
||||
free(sidetone_hdl->sidetone_buf_lr);
|
||||
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
|
||||
free(sidetone_hdl);
|
||||
sidetone_hdl = NULL;
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* Audio Sidetone Suspend
|
||||
* Description: 暂停通话监听
|
||||
* Arguments : None.
|
||||
* Return : 0成功 其他失败
|
||||
* Note(s) : None.
|
||||
*********************************************************************
|
||||
*/
|
||||
int audio_sidetone_suspend(void)
|
||||
{
|
||||
if (sidetone_hdl) {
|
||||
sidetone_hdl->suspend ? (sidetone_hdl->suspend = 0) : (sidetone_hdl->suspend = 1);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif/*TCFG_SIDETONE_ENABLE*/
|
||||
12
cpu/br28/audio_hearing/audio_sidetone.h
Normal file
12
cpu/br28/audio_hearing/audio_sidetone.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef _AUD_SIDETONE_H_
|
||||
#define _AUD_SIDETONE_H_
|
||||
|
||||
#include "generic/typedef.h"
|
||||
#include "board_config.h"
|
||||
|
||||
void audio_sidetone_inbuf(s16 *data, u16 len);
|
||||
int audio_sidetone_open(void);
|
||||
int audio_sidetone_close(void);
|
||||
int audio_sidetone_suspend(void);
|
||||
#endif
|
||||
|
||||
543
cpu/br28/audio_iis.c
Normal file
543
cpu/br28/audio_iis.c
Normal file
@ -0,0 +1,543 @@
|
||||
|
||||
#define IIS_TX_MIN_PNS (JL_ALNK0->LEN / 4)
|
||||
struct audio_iis_sync_node {
|
||||
void *hdl;
|
||||
struct list_head entry;
|
||||
};
|
||||
/***********************************************************
|
||||
* i2s 使用接口
|
||||
*
|
||||
***********************************************************/
|
||||
int audio_iis_buffered_frames(struct audio_iis_hdl *iis)
|
||||
{
|
||||
return (JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);
|
||||
}
|
||||
|
||||
int audio_iis_buffered_time(struct audio_iis_hdl *iis)
|
||||
{
|
||||
if (!iis) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffered_time = ((audio_iis_buffered_frames(iis) * 1000000) / iis->sample_rate) / 1000;
|
||||
|
||||
return buffered_time;
|
||||
}
|
||||
|
||||
int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *))
|
||||
{
|
||||
local_irq_disable();
|
||||
iis->underrun_time = time;
|
||||
iis->underrun_pns = 0;
|
||||
iis->underrun_data = priv;
|
||||
iis->underrun_feedback = feedback;
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis)
|
||||
{
|
||||
struct audio_iis_sync_node *node;
|
||||
list_for_each_entry(node, &iis->sync_list, entry) {
|
||||
sound_pcm_enter_update_frame(node->hdl);
|
||||
}
|
||||
}
|
||||
|
||||
void audio_iis_syncts_latch_trigger(struct audio_iis_hdl *iis)
|
||||
{
|
||||
struct audio_iis_sync_node *node;
|
||||
|
||||
list_for_each_entry(node, &iis->sync_list, entry) {
|
||||
sound_pcm_syncts_latch_trigger(node->hdl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void audio_iis_dma_update_to_syncts(struct audio_iis_hdl *iis, int frames)
|
||||
{
|
||||
struct audio_iis_sync_node *node;
|
||||
u8 have_syncts = 0;
|
||||
|
||||
list_for_each_entry(node, &iis->sync_list, entry) {
|
||||
sound_pcm_update_frame_num(node->hdl, frames);
|
||||
have_syncts = 1;
|
||||
}
|
||||
|
||||
if (have_syncts) {
|
||||
u16 free_points = *ALNK0_SHN[iis->hw_ch];
|
||||
int timeout = (1000000 / iis->sample_rate) * (clk_get("sys") / 1000000);
|
||||
while (free_points == *ALNK0_SHN[iis->hw_ch] && (--timeout > 0));
|
||||
}
|
||||
}
|
||||
|
||||
void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
|
||||
{
|
||||
struct audio_iis_sync_node *node = (struct audio_iis_sync_node *)zalloc(sizeof(struct audio_iis_sync_node));
|
||||
node->hdl = syncts;
|
||||
|
||||
list_add(&node->entry, &iis->sync_list);
|
||||
|
||||
if (iis->state == SOUND_PCM_STATE_RUNNING) {
|
||||
sound_pcm_syncts_latch_trigger(syncts);
|
||||
}
|
||||
ALINK_DA2BTSRC_SEL(ALINK0, iis->hw_ch);
|
||||
}
|
||||
|
||||
void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
|
||||
{
|
||||
struct audio_iis_sync_node *node;
|
||||
|
||||
list_for_each_entry(node, &iis->sync_list, entry) {
|
||||
if (node->hdl == syncts) {
|
||||
goto remove_node;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
remove_node:
|
||||
|
||||
list_del(&node->entry);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static void audio_iis_tx_irq_handler(struct audio_iis_hdl *iis)
|
||||
{
|
||||
if (iis->irq_trigger && iis->trigger_handler) {
|
||||
iis->trigger_handler(iis->trigger_data);
|
||||
iis->irq_trigger = 0;
|
||||
}
|
||||
|
||||
if (iis->underrun_pns) {
|
||||
int unread_frames = JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1;
|
||||
if (unread_frames <= iis->underrun_pns) {
|
||||
//TODO
|
||||
} else {
|
||||
ALINK_OPNS_SET(ALINK0, iis->underrun_pns);
|
||||
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
|
||||
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
|
||||
}
|
||||
|
||||
extern ALINK_PARM alink0_platform_data;
|
||||
int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int sample_rate)
|
||||
{
|
||||
memset(iis, 0x0, sizeof(struct audio_iis_hdl));
|
||||
INIT_LIST_HEAD(&iis->sync_list);
|
||||
iis->state = SOUND_PCM_STATE_IDLE;
|
||||
iis->sample_rate = sample_rate;
|
||||
iis->alink0_param = alink_init(&alink0_platform_data);
|
||||
alink_channel_init(iis->alink0_param, ch, ALINK_DIR_TX, iis, audio_iis_tx_irq_handler);
|
||||
/*alink_start();*/
|
||||
iis->hw_ch = ch;
|
||||
}
|
||||
|
||||
void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis)
|
||||
{
|
||||
alink_channel_close(iis->hw_ch);
|
||||
iis->state = SOUND_PCM_STATE_IDLE;
|
||||
}
|
||||
|
||||
int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis)
|
||||
{
|
||||
return iis->sample_rate;
|
||||
}
|
||||
|
||||
int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time)
|
||||
{
|
||||
iis->prepared_time = prepared_time;
|
||||
iis->delay_time = delay_time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping)
|
||||
{
|
||||
if (!iis->input_mapping) {
|
||||
iis->input_mapping = mapping;
|
||||
}
|
||||
if ((iis->input_mapping & SOUND_CHMAP_RL) || (iis->input_mapping & SOUND_CHMAP_RR)) {
|
||||
printf("Not support this channel map : 0x%x\n", mapping);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis)
|
||||
{
|
||||
int num = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (iis->input_mapping & BIT(i)) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
#if 0
|
||||
const unsigned char sin44K[88] ALIGNED(4) = {
|
||||
0x00, 0x00, 0x45, 0x0E, 0x41, 0x1C, 0xAA, 0x29, 0x3B, 0x36, 0xB2, 0x41, 0xD5, 0x4B, 0x6E, 0x54,
|
||||
0x51, 0x5B, 0x5A, 0x60, 0x70, 0x63, 0x82, 0x64, 0x8A, 0x63, 0x8E, 0x60, 0x9D, 0x5B, 0xD1, 0x54,
|
||||
0x4D, 0x4C, 0x3D, 0x42, 0xD5, 0x36, 0x50, 0x2A, 0xF1, 0x1C, 0xFB, 0x0E, 0xB7, 0x00, 0x70, 0xF2,
|
||||
0x6E, 0xE4, 0xFD, 0xD6, 0x60, 0xCA, 0xD9, 0xBE, 0xA5, 0xB4, 0xF7, 0xAB, 0xFC, 0xA4, 0xDA, 0x9F,
|
||||
0xAB, 0x9C, 0x7F, 0x9B, 0x5E, 0x9C, 0x3F, 0x9F, 0x19, 0xA4, 0xCE, 0xAA, 0x3D, 0xB3, 0x3A, 0xBD,
|
||||
0x92, 0xC8, 0x0A, 0xD5, 0x60, 0xE2, 0x50, 0xF0
|
||||
};
|
||||
|
||||
int read_44k_sine_data(void *buf, int bytes, int offset, u8 channel)
|
||||
{
|
||||
s16 *sine = (s16 *)sin44K;
|
||||
s16 *data = (s16 *)buf;
|
||||
int frame_len = (bytes >> 1) / channel;
|
||||
int sin44k_frame_len = sizeof(sin44K) / 2;
|
||||
int i, j;
|
||||
|
||||
offset = offset % sin44k_frame_len;
|
||||
|
||||
for (i = 0; i < frame_len; i++) {
|
||||
for (j = 0; j < channel; j++) {
|
||||
*data++ = sine[offset];
|
||||
}
|
||||
if (++offset >= sin44k_frame_len) {
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return i * 2 * channel;
|
||||
}
|
||||
static int frames_offset = 0;
|
||||
#endif
|
||||
|
||||
static int __audio_iis_pcm_write(s16 *dst, s16 *src, int frames, int remapping)
|
||||
{
|
||||
|
||||
/* int frame_bytes = read_44k_sine_data(dst, frames * 2 * 2, frames_offset, 2); */
|
||||
/* putchar('k'); */
|
||||
/* frames_offset += (frame_bytes >> 1) / 2; */
|
||||
/* return frame_bytes; */
|
||||
|
||||
if (remapping == 1) {
|
||||
for (int i = 0; i < frames; i++) {
|
||||
dst[i * 2] = src[i];
|
||||
dst[i * 2 + 1] = src[i];
|
||||
}
|
||||
return frames << 1;
|
||||
}
|
||||
|
||||
if (remapping == 2) {
|
||||
memcpy(dst, src, (frames << 1) * 2);
|
||||
return frames << 2;
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
#define CVP_REF_SRC_ENABLE
|
||||
#ifdef CVP_REF_SRC_ENABLE
|
||||
#define CVP_REF_SRC_TASK_NAME "RefSrcTask"
|
||||
#include "Resample_api.h"
|
||||
#include "aec_user.h"
|
||||
|
||||
#define CVP_REF_SRC_FRAME_SIZE 512
|
||||
typedef struct {
|
||||
volatile u8 state;
|
||||
volatile u8 busy;
|
||||
RS_STUCT_API *sw_src_api;
|
||||
u8 *sw_src_buf;
|
||||
u16 input_rate;
|
||||
u16 output_rate;
|
||||
s16 ref_tmp_buf[CVP_REF_SRC_FRAME_SIZE / 2];
|
||||
cbuffer_t cbuf;
|
||||
u8 ref_buf[CVP_REF_SRC_FRAME_SIZE * 3];
|
||||
} aec_ref_src_t;
|
||||
static aec_ref_src_t *aec_ref_src = NULL;
|
||||
|
||||
extern void audio_aec_ref_src_get_output_rate(u16 *input_rate, u16 *output_rate);
|
||||
extern u8 bt_phone_dec_is_running();
|
||||
|
||||
extern struct audio_iis_hdl iis_hdl;
|
||||
void audio_aec_ref_src_run(s16 *data, int len)
|
||||
{
|
||||
u16 ref_len = 0;
|
||||
if (aec_ref_src) {
|
||||
if (iis_hdl.input_mapping != SOUND_CHMAP_MONO) {
|
||||
/*双变单*/
|
||||
for (int i = 0; i < (len >> 2); i++) {
|
||||
aec_ref_src->ref_tmp_buf[i] = data[2 * i];
|
||||
}
|
||||
len >>= 1;
|
||||
}
|
||||
/* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
|
||||
/* printf("%d %d \n",input_rate,output_rate); */
|
||||
if (aec_ref_src->sw_src_api) {
|
||||
/* aec_ref_src->sw_src_api->set_sr(aec_ref_src->sw_src_buf, aec_ref_src->output_rate); */
|
||||
ref_len = aec_ref_src->sw_src_api->run(aec_ref_src->sw_src_buf, aec_ref_src->ref_tmp_buf, len >> 1, aec_ref_src->ref_tmp_buf);
|
||||
ref_len <<= 1;
|
||||
}
|
||||
/* printf("ref_len %d", ref_len); */
|
||||
audio_aec_refbuf(aec_ref_src->ref_tmp_buf, ref_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_aec_ref_src_task(void *p)
|
||||
{
|
||||
int res;
|
||||
int msg[16];
|
||||
while (1) {
|
||||
|
||||
res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
|
||||
|
||||
if (aec_ref_src && aec_ref_src->state) {
|
||||
s16 *data = (int)msg[1];
|
||||
int len = msg[2];
|
||||
int rlen = 0;
|
||||
|
||||
aec_ref_src->busy = 1;
|
||||
if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
|
||||
cbuf_read(&aec_ref_src->cbuf, aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
|
||||
audio_aec_ref_src_run(aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
|
||||
}
|
||||
aec_ref_src->busy = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int audio_aec_ref_src_data_fill(void *p, s16 *data, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
if (aec_ref_src && aec_ref_src->state) {
|
||||
audio_aec_ref_start(1);
|
||||
if (0 == cbuf_write(&aec_ref_src->cbuf, data, len)) {
|
||||
/* cbuf_clear(&aec_ref_src->cbuf); */
|
||||
printf("ref src cbuf wfail!!");
|
||||
}
|
||||
if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
|
||||
ret = os_taskq_post_msg(CVP_REF_SRC_TASK_NAME, 2, (int)data, len);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int audio_aec_ref_src_open(u32 insr, u32 outsr)
|
||||
{
|
||||
if (aec_ref_src) {
|
||||
printf("aec_ref_src alreadly open !!!");
|
||||
return -1;
|
||||
}
|
||||
aec_ref_src = zalloc(sizeof(aec_ref_src_t));
|
||||
if (aec_ref_src == NULL) {
|
||||
printf("aec_ref_src malloc fail !!!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cbuf_init(&aec_ref_src->cbuf, aec_ref_src->ref_buf, sizeof(aec_ref_src->ref_buf));
|
||||
int err = os_task_create(audio_aec_ref_src_task, NULL, 4, 256, 128, CVP_REF_SRC_TASK_NAME);
|
||||
if (err != OS_NO_ERR) {
|
||||
printf("task create error!");
|
||||
free(aec_ref_src);
|
||||
aec_ref_src = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
|
||||
aec_ref_src->input_rate = insr;
|
||||
aec_ref_src->output_rate = outsr;
|
||||
aec_ref_src->sw_src_api = get_rs16_context();
|
||||
printf("sw_src_api:0x%x\n", aec_ref_src->sw_src_api);
|
||||
ASSERT(aec_ref_src->sw_src_api);
|
||||
int sw_src_need_buf = aec_ref_src->sw_src_api->need_buf();
|
||||
printf("sw_src_buf:%d\n", sw_src_need_buf);
|
||||
aec_ref_src->sw_src_buf = zalloc(sw_src_need_buf);
|
||||
ASSERT(aec_ref_src->sw_src_buf, "sw_src_buf zalloc fail");
|
||||
RS_PARA_STRUCT rs_para_obj;
|
||||
rs_para_obj.nch = 1;
|
||||
if (insr == 44100) {
|
||||
rs_para_obj.new_insample = 44117;
|
||||
} else {
|
||||
rs_para_obj.new_insample = insr;
|
||||
}
|
||||
rs_para_obj.new_outsample = outsr;
|
||||
printf("sw src,ch = %d, in = %d,out = %d\n", rs_para_obj.nch, rs_para_obj.new_insample, rs_para_obj.new_outsample);
|
||||
aec_ref_src->sw_src_api->open(aec_ref_src->sw_src_buf, &rs_para_obj);
|
||||
|
||||
aec_ref_src->state = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void audio_aec_ref_src_close()
|
||||
{
|
||||
if (aec_ref_src) {
|
||||
aec_ref_src->state = 0;
|
||||
while (aec_ref_src->busy) {
|
||||
putchar('w');
|
||||
os_time_dly(1);
|
||||
}
|
||||
int err = os_task_del(CVP_REF_SRC_TASK_NAME);
|
||||
if (err) {
|
||||
log_i("kill task %s: err=%d\n", CVP_REF_SRC_TASK_NAME, err);
|
||||
}
|
||||
if (aec_ref_src->sw_src_api) {
|
||||
aec_ref_src->sw_src_api = NULL;
|
||||
}
|
||||
if (aec_ref_src->sw_src_buf) {
|
||||
free(aec_ref_src->sw_src_buf);
|
||||
aec_ref_src->sw_src_buf = NULL;
|
||||
}
|
||||
free(aec_ref_src);
|
||||
aec_ref_src = NULL;
|
||||
}
|
||||
}
|
||||
#endif/*CVP_REF_SRC_ENABLE*/
|
||||
|
||||
int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len)
|
||||
{
|
||||
if (iis->state != SOUND_PCM_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
int remapping_ch = 2;
|
||||
int frames = 0;
|
||||
if (iis->input_mapping == SOUND_CHMAP_MONO) {
|
||||
frames = len >> 1;
|
||||
remapping_ch = 1;
|
||||
} else if (iis->input_mapping & SOUND_CHMAP_FR) {
|
||||
frames = len >> 2;
|
||||
remapping_ch = 2;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
s16 *ref_data = (s16 *)data;
|
||||
int swp = *ALNK0_SWPTR[iis->hw_ch];
|
||||
int free_frames = *ALNK0_SHN[iis->hw_ch] - iis->reserved_frames;
|
||||
|
||||
/* printf("free : %d, %d\n", *ALNK0_SHN[iis->hw_ch], free_frames); */
|
||||
if (free_frames <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (free_frames > frames) {
|
||||
free_frames = frames;
|
||||
}
|
||||
|
||||
frames = 0;
|
||||
if (swp + free_frames > JL_ALNK0->LEN) {
|
||||
frames = JL_ALNK0->LEN - swp;
|
||||
__audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, frames, remapping_ch);
|
||||
free_frames -= frames;
|
||||
data = (s16 *)data + frames * remapping_ch;
|
||||
swp = 0;
|
||||
}
|
||||
|
||||
__audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, free_frames, remapping_ch);
|
||||
frames += free_frames;
|
||||
|
||||
audio_iis_syncts_update_frame(iis);
|
||||
*ALNK0_SHN[iis->hw_ch] = frames;
|
||||
__asm_csync();
|
||||
audio_iis_dma_update_to_syncts(iis, frames);
|
||||
|
||||
/*printf("frames : %d\n", frames);*/
|
||||
/*printf("CLK CON2 : %d, %d\n", JL_CLOCK->CLK_CON2 & 0x3, (JL_CLOCK->CLK_CON2 >> 2) & 0x3);*/
|
||||
|
||||
#ifdef CVP_REF_SRC_ENABLE
|
||||
if (bt_phone_dec_is_running()) {
|
||||
audio_aec_ref_src_data_fill(iis, ref_data, (frames << 1) * remapping_ch);
|
||||
}
|
||||
#endif
|
||||
return (frames << 1) * remapping_ch;
|
||||
}
|
||||
|
||||
static void audio_iis_dma_fifo_start(struct audio_iis_hdl *iis)
|
||||
{
|
||||
if (iis->state != SOUND_PCM_STATE_PREPARED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iis->prepared_frames) {
|
||||
*ALNK0_SHN[iis->hw_ch] = iis->prepared_frames;
|
||||
__asm_csync();
|
||||
}
|
||||
|
||||
local_irq_disable();
|
||||
iis->state = SOUND_PCM_STATE_RUNNING;
|
||||
ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
|
||||
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
|
||||
local_irq_enable();
|
||||
audio_iis_syncts_latch_trigger(iis);
|
||||
}
|
||||
|
||||
static int audio_iis_fifo_set_delay(struct audio_iis_hdl *iis)
|
||||
{
|
||||
iis->prepared_frames = iis->prepared_time * iis->sample_rate / 1000;
|
||||
int delay_frames = (iis->delay_time * iis->sample_rate) / 1000 / 2 * 2;
|
||||
if (iis->prepared_frames >= JL_ALNK0->LEN) {
|
||||
iis->prepared_frames = JL_ALNK0->LEN / 2;
|
||||
}
|
||||
if (delay_frames < JL_ALNK0->LEN) {
|
||||
iis->reserved_frames = JL_ALNK0->LEN - delay_frames;
|
||||
} else {
|
||||
iis->reserved_frames = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time_ms, void *priv, void (*callback)(void *))
|
||||
{
|
||||
if (iis->state != SOUND_PCM_STATE_RUNNING) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int irq_frames = time_ms * iis->sample_rate / 1000;
|
||||
int pns = audio_iis_buffered_frames(iis) - irq_frames;
|
||||
if (pns < irq_frames) {
|
||||
sys_hi_timeout_add(priv, callback, time_ms);
|
||||
return -EINVAL;
|
||||
}
|
||||
local_irq_disable();
|
||||
if (pns > ALINK_OPNS(ALINK0)) {
|
||||
ALINK_OPNS_SET(ALINK0, pns);
|
||||
}
|
||||
|
||||
iis->irq_trigger = 1;
|
||||
iis->trigger_handler = callback;
|
||||
iis->trigger_data = priv;
|
||||
ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audio_iis_dma_start(struct audio_iis_hdl *iis)
|
||||
{
|
||||
if (iis->state == SOUND_PCM_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
audio_iis_fifo_set_delay(iis);
|
||||
iis->underrun_pns = iis->underrun_time ? (iis->underrun_time * iis->sample_rate / 1000) : 0;
|
||||
ALINK_OPNS_SET(ALINK0, (iis->underrun_pns ? iis->underrun_pns : IIS_TX_MIN_PNS));
|
||||
iis->state = SOUND_PCM_STATE_PREPARED;
|
||||
/* printf("DMA : %d, %d, %d\n", *ALNK0_SHN[iis->hw_ch], *ALNK0_SWPTR[iis->hw_ch], *ALNK0_HWPTR[iis->hw_ch]); */
|
||||
audio_iis_dma_fifo_start(iis);
|
||||
alink_start(iis->alink0_param);
|
||||
/* printf("[iis dma start]... %d, free : %d, prepared_frames : %d, reserved_frames : %d\n", JL_ALNK0->LEN, *ALNK0_SHN[iis->hw_ch], iis->prepared_frames, iis->reserved_frames); */
|
||||
}
|
||||
|
||||
int audio_iis_dma_stop(struct audio_iis_hdl *iis)
|
||||
{
|
||||
if (iis->state != SOUND_PCM_STATE_RUNNING) {
|
||||
return 0;
|
||||
}
|
||||
/*audio_iis_buffered_frames_fade_out(iis, JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);*/
|
||||
ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
|
||||
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
|
||||
/* alink_uninit(iis->alink0_param); */
|
||||
|
||||
iis->input_mapping = 0;
|
||||
iis->state = SOUND_PCM_STATE_SUSPENDED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
68
cpu/br28/audio_iis.h
Normal file
68
cpu/br28/audio_iis.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*****************************************************************
|
||||
>file name : audio_iis.h
|
||||
>create time : Fri 25 Feb 2022 04:35:37 PM CST
|
||||
*****************************************************************/
|
||||
#ifndef _AUDIO_IIS_H_
|
||||
#define _AUDIO_IIS_H_
|
||||
#include "system/includes.h"
|
||||
#include "sound/pcm.h"
|
||||
#include "asm/iis.h"
|
||||
#include "audio_link.h"
|
||||
|
||||
struct audio_iis_hdl {
|
||||
u8 state;
|
||||
u8 hw_ch;
|
||||
u8 irq_trigger;
|
||||
u8 input_mapping;
|
||||
short delay_time;
|
||||
short prepared_time;
|
||||
short prepared_frames;
|
||||
short reserved_frames;
|
||||
short underrun_time;
|
||||
short underrun_pns;
|
||||
void *underrun_data;
|
||||
void (*underrun_feedback)(void *);
|
||||
void *trigger_data;
|
||||
void (*trigger_handler)(void *);
|
||||
int sample_rate;
|
||||
struct list_head sync_list;
|
||||
ALINK_PARM *alink0_param;
|
||||
};
|
||||
|
||||
int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int smaple_rate);
|
||||
|
||||
void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping);
|
||||
|
||||
int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len);
|
||||
|
||||
int audio_iis_dma_start(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_dma_stop(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time);
|
||||
|
||||
int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *));
|
||||
|
||||
int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time, void *priv, void (*callback)(void *));
|
||||
|
||||
void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
|
||||
|
||||
void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
|
||||
|
||||
void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_buffered_frames(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_buffered_time(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis);
|
||||
|
||||
int audio_aec_ref_src_data_fill(void *p, s16 *data, int len);
|
||||
int audio_aec_ref_src_open(u32 insr, u32 outsr);
|
||||
void audio_aec_ref_src_close();
|
||||
#endif
|
||||
|
||||
808
cpu/br28/audio_link.c
Normal file
808
cpu/br28/audio_link.c
Normal file
@ -0,0 +1,808 @@
|
||||
/*****************************************************************
|
||||
>file name : lib/media/cpu/br22/audio_link.c
|
||||
>author :
|
||||
>create time : Fri 7 Dec 2018 14:59:12 PM CST
|
||||
*****************************************************************/
|
||||
#include "includes.h"
|
||||
#include "asm/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "system/includes.h"
|
||||
#include "asm/clock.h"
|
||||
#include "asm/iis.h"
|
||||
#include "audio_link.h"
|
||||
#include "app_config.h"
|
||||
#include "update.h"
|
||||
#include "audio_syncts.h"
|
||||
#include "audio_iis.h"
|
||||
#include "sound/sound.h"
|
||||
|
||||
/* #if TCFG_AUDIO_INPUT_IIS || TCFG_AUDIO_OUTPUT_IIS */
|
||||
#define ALINK_TEST_ENABLE 0
|
||||
|
||||
#define ALINK_DEBUG_INFO
|
||||
#ifdef ALINK_DEBUG_INFO
|
||||
#define alink_printf printf
|
||||
#else
|
||||
#define alink_printf(...)
|
||||
#endif
|
||||
|
||||
static void alink0_info_dump();
|
||||
static u32 *ALNK0_BUF_ADR[] = {
|
||||
(u32 *)(&(JL_ALNK0->ADR0)),
|
||||
(u32 *)(&(JL_ALNK0->ADR1)),
|
||||
(u32 *)(&(JL_ALNK0->ADR2)),
|
||||
(u32 *)(&(JL_ALNK0->ADR3)),
|
||||
};
|
||||
|
||||
static u32 *ALNK0_HWPTR[] = {
|
||||
(u32 *)(&(JL_ALNK0->HWPTR0)),
|
||||
(u32 *)(&(JL_ALNK0->HWPTR1)),
|
||||
(u32 *)(&(JL_ALNK0->HWPTR2)),
|
||||
(u32 *)(&(JL_ALNK0->HWPTR3)),
|
||||
};
|
||||
|
||||
static u32 *ALNK0_SWPTR[] = {
|
||||
(u32 *)(&(JL_ALNK0->SWPTR0)),
|
||||
(u32 *)(&(JL_ALNK0->SWPTR1)),
|
||||
(u32 *)(&(JL_ALNK0->SWPTR2)),
|
||||
(u32 *)(&(JL_ALNK0->SWPTR3)),
|
||||
};
|
||||
|
||||
static u32 *ALNK0_SHN[] = {
|
||||
(u32 *)(&(JL_ALNK0->SHN0)),
|
||||
(u32 *)(&(JL_ALNK0->SHN1)),
|
||||
(u32 *)(&(JL_ALNK0->SHN2)),
|
||||
(u32 *)(&(JL_ALNK0->SHN3)),
|
||||
};
|
||||
|
||||
static u32 PFI_ALNK0_DAT[] = {
|
||||
PFI_ALNK0_DAT0,
|
||||
PFI_ALNK0_DAT1,
|
||||
PFI_ALNK0_DAT2,
|
||||
PFI_ALNK0_DAT3,
|
||||
};
|
||||
|
||||
static u32 FO_ALNK0_DAT[] = {
|
||||
FO_ALNK0_DAT0,
|
||||
FO_ALNK0_DAT1,
|
||||
FO_ALNK0_DAT2,
|
||||
FO_ALNK0_DAT3,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
MCLK_11M2896K = 0,
|
||||
MCLK_12M288K
|
||||
};
|
||||
|
||||
enum {
|
||||
MCLK_EXTERNAL = 0u,
|
||||
MCLK_SYS_CLK ,
|
||||
MCLK_OSC_CLK ,
|
||||
MCLK_PLL_CLK ,
|
||||
};
|
||||
|
||||
enum {
|
||||
MCLK_DIV_1 = 0u,
|
||||
MCLK_DIV_2 ,
|
||||
MCLK_DIV_4 ,
|
||||
MCLK_DIV_8 ,
|
||||
MCLK_DIV_16 ,
|
||||
};
|
||||
|
||||
enum {
|
||||
MCLK_LRDIV_EX = 0u,
|
||||
MCLK_LRDIV_64FS ,
|
||||
MCLK_LRDIV_128FS ,
|
||||
MCLK_LRDIV_192FS ,
|
||||
MCLK_LRDIV_256FS ,
|
||||
MCLK_LRDIV_384FS ,
|
||||
MCLK_LRDIV_512FS ,
|
||||
MCLK_LRDIV_768FS ,
|
||||
};
|
||||
#ifndef TCFG_IIS_SR
|
||||
#define TCFG_IIS_SR 44100
|
||||
#endif
|
||||
|
||||
extern u32 clock_get_pll_target_frequency();
|
||||
u32 audio_iis_hw_rates_match(u32 sr)
|
||||
{
|
||||
u8 i = 0;
|
||||
u32 pll_tar = clock_get_pll_target_frequency();
|
||||
if (pll_tar == 240) {
|
||||
u32 hw_rates[] = {ALINK_SR_48000, ALINK_SR_44100, ALINK_SR_32000, ALINK_SR_24000, ALINK_SR_22050, ALINK_SR_16000, ALINK_SR_12000, ALINK_SR_11025, ALINK_SR_8000};
|
||||
for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
|
||||
if (hw_rates[i] == sr) {
|
||||
log_i("match sr %d\n", sr);
|
||||
return sr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u32 hw_rates[] = {ALINK_SR_44100, ALINK_SR_22050, ALINK_SR_11025};
|
||||
for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
|
||||
if (hw_rates[i] == sr) {
|
||||
log_i("match sr %d\n", sr);
|
||||
return sr;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_e("not match is hw sr %d\n", sr);
|
||||
return TCFG_IIS_SR;
|
||||
}
|
||||
|
||||
|
||||
static ALINK_PARM *p_alink0_parm = NULL;
|
||||
|
||||
u32 alink_get_addr(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
u32 buf_addr = 0;
|
||||
buf_addr = *ALNK0_BUF_ADR[hw_channel_parm->ch_idx];
|
||||
return buf_addr;
|
||||
}
|
||||
|
||||
u32 alink_get_shn(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
int shn = 0;
|
||||
shn = *ALNK0_SHN[hw_channel_parm->ch_idx];
|
||||
return shn;
|
||||
}
|
||||
|
||||
void alink_set_shn(void *hw_channel, u32 len)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
if (len) {
|
||||
*ALNK0_SHN[hw_channel_parm->ch_idx] = len;
|
||||
}
|
||||
}
|
||||
|
||||
u32 alink_get_swptr(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
int swptr = 0;
|
||||
swptr = *ALNK0_SWPTR[hw_channel_parm->ch_idx];
|
||||
return swptr;
|
||||
}
|
||||
|
||||
void alink_set_swptr(void *hw_channel, u32 value)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
*ALNK0_SWPTR[hw_channel_parm->ch_idx] = value;
|
||||
}
|
||||
|
||||
u32 alink_get_hwptr(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
int hwptr = 0;
|
||||
hwptr = *ALNK0_HWPTR[hw_channel_parm->ch_idx];
|
||||
return hwptr;
|
||||
}
|
||||
|
||||
void alink_set_hwptr(void *hw_channel, u32 value)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
*ALNK0_HWPTR[hw_channel_parm->ch_idx] = value;
|
||||
}
|
||||
|
||||
void alink_set_ch_ie(void *hw_channel, u32 value)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, value);
|
||||
}
|
||||
|
||||
void alink_clr_ch_pnd(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
ALINK_CLR_CHx_PND(hw_channel_parm->module, hw_channel_parm->ch_idx);
|
||||
}
|
||||
|
||||
//==================================================
|
||||
static void alink_io_in_init(u8 gpio)
|
||||
{
|
||||
gpio_set_direction(gpio, 1);
|
||||
gpio_set_pull_down(gpio, 0);
|
||||
gpio_set_pull_up(gpio, 1);
|
||||
gpio_set_die(gpio, 1);
|
||||
}
|
||||
|
||||
static void alink_io_out_init(u8 gpio)
|
||||
{
|
||||
gpio_set_direction(gpio, 0);
|
||||
gpio_set_pull_down(gpio, 0);
|
||||
gpio_set_pull_up(gpio, 0);
|
||||
gpio_set_die(gpio, 0);
|
||||
gpio_direction_output(gpio, 1);
|
||||
}
|
||||
|
||||
static void *alink_addr(void *hw_alink, u8 ch)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
s16 *buf_addr = NULL; //can be used
|
||||
u32 buf_index = 0;
|
||||
|
||||
if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
|
||||
buf_addr = (s16 *)(*ALNK0_BUF_ADR[ch] + *ALNK0_SWPTR[ch] * 4);
|
||||
} else {
|
||||
buf_addr = (s16 *)(hw_alink_parm->ch_cfg[ch].buf);
|
||||
u8 index_table[4] = {12, 13, 14, 15};
|
||||
u8 bit_index = index_table[ch];
|
||||
buf_index = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(bit_index)) ? 0 : 1;
|
||||
buf_addr = buf_addr + ((hw_alink_parm->dma_len / 2 / 2) * buf_index);
|
||||
}
|
||||
return buf_addr;
|
||||
}
|
||||
|
||||
___interrupt
|
||||
static void alink0_dma_isr(void)
|
||||
{
|
||||
u16 reg;
|
||||
s16 *buf_addr = NULL ;
|
||||
u8 ch = 0;
|
||||
|
||||
reg = JL_ALNK0->CON2;
|
||||
reg >>= 4;
|
||||
|
||||
for (ch = 0; ch < 4; ch++) {
|
||||
if (!(reg & BIT(ch))) {
|
||||
continue;
|
||||
}
|
||||
buf_addr = (s16 *)alink_addr(p_alink0_parm, ch);
|
||||
if (p_alink0_parm->ch_cfg[ch].isr_cb) {
|
||||
if (p_alink0_parm->buf_mode == ALINK_BUF_CIRCLE) {
|
||||
p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, (JL_ALNK0->PNS & 0xffff) * 4);
|
||||
} else {
|
||||
p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, p_alink0_parm->dma_len / 2);
|
||||
}
|
||||
}
|
||||
ALINK_CLR_CHx_PND(p_alink0_parm->module, ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void alink_sr(void *hw_alink, u32 rate)
|
||||
{
|
||||
alink_printf("ALINK_SR = %d\n", rate);
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
hw_alink_parm->sample_rate = rate;
|
||||
u8 module = hw_alink_parm->module;
|
||||
|
||||
u8 pll_target_frequency = clock_get_pll_target_frequency();
|
||||
alink_printf("pll_target_frequency = %d\n", pll_target_frequency);
|
||||
|
||||
switch (rate) {
|
||||
case ALINK_SR_48000:
|
||||
/*12.288Mhz 256fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
break ;
|
||||
|
||||
case ALINK_SR_44100:
|
||||
/*11.289Mhz 256fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
if (pll_target_frequency == 192) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
} else if (pll_target_frequency == 240) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_128FS);
|
||||
}
|
||||
break ;
|
||||
|
||||
case ALINK_SR_32000:
|
||||
/*12.288Mhz 384fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_384FS);
|
||||
break ;
|
||||
|
||||
case ALINK_SR_24000:
|
||||
/*12.288Mhz 512fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_2);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
break ;
|
||||
|
||||
case ALINK_SR_22050:
|
||||
/*11.289Mhz 512fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
if (pll_target_frequency == 192) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_512FS);
|
||||
} else if (pll_target_frequency == 240) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
}
|
||||
break ;
|
||||
|
||||
case ALINK_SR_16000:
|
||||
/*12.288/2Mhz 384fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_768FS);
|
||||
break ;
|
||||
|
||||
case ALINK_SR_12000:
|
||||
/*12.288/2Mhz 512fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_4);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
break ;
|
||||
|
||||
case ALINK_SR_11025:
|
||||
/*11.289/2Mhz 512fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
|
||||
ALINK_MDIV(module, MCLK_DIV_2);
|
||||
if (pll_target_frequency == 192) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_512FS);
|
||||
} else if (pll_target_frequency == 240) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
}
|
||||
break ;
|
||||
|
||||
case ALINK_SR_8000:
|
||||
/*12.288/4Mhz 384fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_12M288K);
|
||||
ALINK_MDIV(module, MCLK_DIV_4);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_384FS);
|
||||
break ;
|
||||
|
||||
default:
|
||||
//44100
|
||||
/*11.289Mhz 256fs*/
|
||||
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
|
||||
ALINK_MDIV(module, MCLK_DIV_1);
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
|
||||
break;
|
||||
}
|
||||
if (hw_alink_parm->role == ALINK_ROLE_SLAVE) {
|
||||
ALINK_LRDIV(module, MCLK_LRDIV_EX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len))
|
||||
{
|
||||
if (!hw_alink) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
u8 module = hw_alink_parm->module;
|
||||
|
||||
hw_alink_parm->ch_cfg[ch_idx].module = module;
|
||||
hw_alink_parm->ch_cfg[ch_idx].dir = dir;
|
||||
hw_alink_parm->ch_cfg[ch_idx].ch_idx = ch_idx;
|
||||
hw_alink_parm->ch_cfg[ch_idx].isr_cb = handle;
|
||||
hw_alink_parm->ch_cfg[ch_idx].private_data = priv;
|
||||
printf("dma len %d", hw_alink_parm->dma_len);
|
||||
hw_alink_parm->ch_cfg[ch_idx].buf = zalloc(hw_alink_parm->dma_len);
|
||||
|
||||
printf(">>> alink_channel_init %x\n", hw_alink_parm->ch_cfg[ch_idx].buf);
|
||||
u32 *buf_addr;
|
||||
|
||||
//===================================//
|
||||
// ALNK CH DMA BUF //
|
||||
//===================================//
|
||||
buf_addr = ALNK0_BUF_ADR[ch_idx];
|
||||
*buf_addr = (u32)(hw_alink_parm->ch_cfg[ch_idx].buf);
|
||||
|
||||
//===================================//
|
||||
// ALNK工作模式 //
|
||||
//===================================//
|
||||
if (hw_alink_parm->mode > ALINK_MD_IIS_RALIGN) {
|
||||
ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode - ALINK_MD_IIS_RALIGN));
|
||||
} else {
|
||||
ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode));
|
||||
}
|
||||
//===================================//
|
||||
// ALNK CH DAT IO INIT //
|
||||
//===================================//
|
||||
if (hw_alink_parm->ch_cfg[ch_idx].dir == ALINK_DIR_RX) {
|
||||
alink_io_in_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
|
||||
gpio_set_fun_input_port(hw_alink_parm->ch_cfg[ch_idx].data_io, PFI_ALNK0_DAT[ch_idx], LOW_POWER_FREE);
|
||||
} else {
|
||||
alink_io_out_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
|
||||
gpio_set_fun_output_port(hw_alink_parm->ch_cfg[ch_idx].data_io, FO_ALNK0_DAT[ch_idx], 1, 1, LOW_POWER_FREE);
|
||||
}
|
||||
|
||||
ALINK_CHx_DIR_MODE(module, ch_idx, dir);
|
||||
ALINK_CHx_IE(module, ch_idx, 1);
|
||||
|
||||
r_printf("alink%d, ch%d init\n", module, ch_idx);
|
||||
|
||||
return &hw_alink_parm->ch_cfg[ch_idx];
|
||||
}
|
||||
|
||||
static void alink0_info_dump()
|
||||
{
|
||||
alink_printf("JL_ALNK0->CON0 = 0x%x", JL_ALNK0->CON0);
|
||||
alink_printf("JL_ALNK0->CON1 = 0x%x", JL_ALNK0->CON1);
|
||||
alink_printf("JL_ALNK0->CON2 = 0x%x", JL_ALNK0->CON2);
|
||||
alink_printf("JL_ALNK0->CON3 = 0x%x", JL_ALNK0->CON3);
|
||||
alink_printf("JL_ALNK0->LEN = 0x%x", JL_ALNK0->LEN);
|
||||
alink_printf("JL_ALNK0->ADR0 = 0x%x", JL_ALNK0->ADR0);
|
||||
alink_printf("JL_ALNK0->ADR1 = 0x%x", JL_ALNK0->ADR1);
|
||||
alink_printf("JL_ALNK0->ADR2 = 0x%x", JL_ALNK0->ADR2);
|
||||
alink_printf("JL_ALNK0->ADR3 = 0x%x", JL_ALNK0->ADR3);
|
||||
alink_printf("JL_ALNK0->PNS = 0x%x", JL_ALNK0->PNS);
|
||||
alink_printf("JL_ALNK0->HWPTR0 = 0x%x", JL_ALNK0->HWPTR0);
|
||||
alink_printf("JL_ALNK0->HWPTR1 = 0x%x", JL_ALNK0->HWPTR1);
|
||||
alink_printf("JL_ALNK0->HWPTR2 = 0x%x", JL_ALNK0->HWPTR2);
|
||||
alink_printf("JL_ALNK0->HWPTR3 = 0x%x", JL_ALNK0->HWPTR3);
|
||||
alink_printf("JL_ALNK0->SWPTR0 = 0x%x", JL_ALNK0->SWPTR0);
|
||||
alink_printf("JL_ALNK0->SWPTR1 = 0x%x", JL_ALNK0->SWPTR1);
|
||||
alink_printf("JL_ALNK0->SWPTR2 = 0x%x", JL_ALNK0->SWPTR2);
|
||||
alink_printf("JL_ALNK0->SWPTR3 = 0x%x", JL_ALNK0->SWPTR3);
|
||||
alink_printf("JL_ALNK0->SHN0 = 0x%x", JL_ALNK0->SHN0);
|
||||
alink_printf("JL_ALNK0->SHN1 = 0x%x", JL_ALNK0->SHN1);
|
||||
alink_printf("JL_ALNK0->SHN2 = 0x%x", JL_ALNK0->SHN2);
|
||||
alink_printf("JL_ALNK0->SHN3 = 0x%x", JL_ALNK0->SHN3);
|
||||
}
|
||||
|
||||
void *alink_init(void *hw_alink)
|
||||
{
|
||||
if (hw_alink == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
u8 module = hw_alink_parm->module;
|
||||
p_alink0_parm = (ALINK_PARM *)hw_alink_parm;
|
||||
|
||||
ALNK_CON_RESET(module);
|
||||
ALNK_HWPTR_RESET(module);
|
||||
ALNK_SWPTR_RESET(module);
|
||||
ALNK_ADR_RESET(module);
|
||||
ALNK_SHN_RESET(module);
|
||||
ALNK_PNS_RESET(module);
|
||||
ALINK_CLR_ALL_PND(module);
|
||||
|
||||
|
||||
ALINK_MSRC(module, MCLK_PLL_CLK); /*MCLK source*/
|
||||
|
||||
//===================================//
|
||||
// 输出时钟配置 //
|
||||
//===================================//
|
||||
if (hw_alink_parm->role == ALINK_ROLE_MASTER) {
|
||||
//主机输出时钟
|
||||
if (hw_alink_parm->mclk_io != ALINK_CLK_OUPUT_DISABLE) {
|
||||
alink_io_out_init(hw_alink_parm->mclk_io);
|
||||
gpio_set_fun_output_port(hw_alink_parm->mclk_io, FO_ALNK0_MCLK, 1, 1, LOW_POWER_FREE);
|
||||
ALINK_MOE(module, 1); /*MCLK output to IO*/
|
||||
}
|
||||
if ((hw_alink_parm->sclk_io != ALINK_CLK_OUPUT_DISABLE) && (p_alink0_parm->lrclk_io != ALINK_CLK_OUPUT_DISABLE)) {
|
||||
alink_io_out_init(hw_alink_parm->lrclk_io);
|
||||
gpio_set_fun_output_port(hw_alink_parm->lrclk_io, FO_ALNK0_LRCK, 1, 1, LOW_POWER_FREE);
|
||||
alink_io_out_init(hw_alink_parm->sclk_io);
|
||||
gpio_set_fun_output_port(hw_alink_parm->sclk_io, FO_ALNK0_SCLK, 1, 1, LOW_POWER_FREE);
|
||||
ALINK_SOE(module, 1); /*SCLK/LRCK output to IO*/
|
||||
}
|
||||
} else {
|
||||
//从机输入时钟
|
||||
alink_io_in_init(hw_alink_parm->mclk_io);
|
||||
alink_io_in_init(hw_alink_parm->sclk_io);
|
||||
alink_io_in_init(hw_alink_parm->lrclk_io);
|
||||
gpio_set_fun_input_port(hw_alink_parm->mclk_io, PFI_ALNK0_MCLK, LOW_POWER_FREE);
|
||||
gpio_set_fun_input_port(hw_alink_parm->sclk_io, PFI_ALNK0_SCLK, LOW_POWER_FREE);
|
||||
gpio_set_fun_input_port(hw_alink_parm->lrclk_io, PFI_ALNK0_LRCK, LOW_POWER_FREE);
|
||||
ALINK_MOE(module, 0); /*MCLK input to IO*/
|
||||
ALINK_SOE(module, 0); /*SCLK/LRCK output to IO*/
|
||||
}
|
||||
//===================================//
|
||||
// 基本模式/扩展模式 //
|
||||
//===================================//
|
||||
ALINK_DSPE(module, hw_alink_parm->mode >> 2);
|
||||
|
||||
//===================================//
|
||||
// 数据位宽16/32bit //
|
||||
//===================================//
|
||||
//注意: 配置了24bit, 一定要选ALINK_FRAME_64SCLK, 因为sclk32 x 2才会有24bit;
|
||||
if (hw_alink_parm->bitwide == ALINK_LEN_24BIT) {
|
||||
ASSERT(hw_alink_parm->sclk_per_frame == ALINK_FRAME_64SCLK);
|
||||
ALINK_24BIT_MODE(module);
|
||||
//一个点需要4bytes, LR = 2, 双buf = 2
|
||||
} else {
|
||||
ALINK_16BIT_MODE(module);
|
||||
//一个点需要2bytes, LR = 2, 双buf = 2
|
||||
}
|
||||
//===================================//
|
||||
// 时钟边沿选择 //
|
||||
//===================================//
|
||||
SCLKINV(module, hw_alink_parm->clk_mode);
|
||||
//===================================//
|
||||
// 每帧数据sclk个数 //
|
||||
//===================================//
|
||||
F32_EN(module, hw_alink_parm->sclk_per_frame);
|
||||
//===================================//
|
||||
// 设置数据采样率 //
|
||||
//===================================//
|
||||
alink_sr(hw_alink_parm, hw_alink_parm->sample_rate);
|
||||
|
||||
//===================================//
|
||||
// 设置DMA MODE //
|
||||
//===================================//
|
||||
ALINK_DMA_MODE_SEL(module, hw_alink_parm->buf_mode);
|
||||
if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
|
||||
ALINK_OPNS_SET(module, hw_alink_parm->dma_len / 16);
|
||||
if (hw_alink_parm->iperiod) {
|
||||
ALINK_IPNS_SET(module, hw_alink_parm->iperiod);
|
||||
} else {
|
||||
ALINK_IPNS_SET(module, hw_alink_parm->dma_len / 8);
|
||||
}
|
||||
//一个点需要2bytes, LR = 2
|
||||
ALINK_LEN_SET(module, hw_alink_parm->dma_len / 4);
|
||||
} else {
|
||||
//一个点需要2bytes, LR = 2, 双buf = 2
|
||||
ALINK_LEN_SET(module, hw_alink_parm->dma_len / 8);
|
||||
}
|
||||
request_irq(IRQ_ALINK0_IDX, 3, alink0_dma_isr, 0);
|
||||
|
||||
return hw_alink_parm;
|
||||
}
|
||||
|
||||
void alink_channel_close(void *hw_channel)
|
||||
{
|
||||
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
|
||||
|
||||
ALINK_CHx_CLOSE(hw_channel_parm->module, hw_channel_parm->ch_idx);
|
||||
ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, 0);
|
||||
|
||||
gpio_set_pull_up(hw_channel_parm->data_io, 0);
|
||||
gpio_set_pull_down(hw_channel_parm->data_io, 0);
|
||||
gpio_set_direction(hw_channel_parm->data_io, 1);
|
||||
gpio_set_die(hw_channel_parm->data_io, 0);
|
||||
if (hw_channel_parm->buf) {
|
||||
free(hw_channel_parm->buf);
|
||||
hw_channel_parm->buf = NULL;
|
||||
}
|
||||
r_printf("alink_ch %d closed\n", hw_channel_parm->ch_idx);
|
||||
}
|
||||
|
||||
|
||||
int alink_start(void *hw_alink)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
if (hw_alink_parm) {
|
||||
ALINK_EN(hw_alink_parm->module, 1);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void alink_uninit(void *hw_alink)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
|
||||
if (!hw_alink_parm) {
|
||||
return;
|
||||
}
|
||||
|
||||
ALINK_EN(hw_alink_parm->module, 0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (hw_alink_parm->ch_cfg[i].buf) {
|
||||
alink_channel_close(&hw_alink_parm->ch_cfg[i]);
|
||||
}
|
||||
}
|
||||
ALNK_CON_RESET(hw_alink_parm->module);
|
||||
hw_alink_parm = NULL;
|
||||
alink_printf("audio_link_exit OK\n");
|
||||
}
|
||||
|
||||
static u8 iis_driver_close(void)
|
||||
{
|
||||
alink_uninit(p_alink0_parm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
REGISTER_UPDATE_TARGET(iis_update_target) = {
|
||||
.name = "iis",
|
||||
.driver_close = iis_driver_close,
|
||||
};
|
||||
|
||||
int alink_get_sr(void *hw_alink)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
if (hw_alink_parm) {
|
||||
return hw_alink_parm->sample_rate;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int alink_set_sr(void *hw_alink, u32 sr)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
|
||||
if (!hw_alink_parm) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hw_alink_parm->sample_rate == sr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 is_alink_en = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(11));
|
||||
|
||||
if (is_alink_en) {
|
||||
ALINK_EN(hw_alink_parm->module, 0);
|
||||
}
|
||||
|
||||
alink_sr(hw_alink_parm, sr);
|
||||
|
||||
if (is_alink_en) {
|
||||
ALINK_EN(hw_alink_parm->module, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 alink_get_dma_len(void *hw_alink)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
return ALINK_FIFO_LEN(hw_alink_parm->module);
|
||||
}
|
||||
|
||||
void alink_set_tx_pns(void *hw_alink, u32 len)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
ALINK_OPNS_SET(hw_alink_parm->module, len);
|
||||
}
|
||||
|
||||
void alink_set_rx_pns(void *hw_alink, u32 len)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
ALINK_IPNS_SET(hw_alink_parm->module, len);
|
||||
}
|
||||
|
||||
int alink_get_tx_pns(void *hw_alink)
|
||||
{
|
||||
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
|
||||
|
||||
return ALINK_SEL(hw_alink_parm->module, PNS);
|
||||
}
|
||||
|
||||
#include "audio_iis.c"
|
||||
//===============================================//
|
||||
// for APP use demo //
|
||||
//===============================================//
|
||||
|
||||
#if ALINK_TEST_ENABLE
|
||||
|
||||
short const tsin_441k[441] = {
|
||||
0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
|
||||
0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
|
||||
0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
|
||||
0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
|
||||
0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
|
||||
0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
|
||||
0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
|
||||
0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
|
||||
0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
|
||||
0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
|
||||
0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
|
||||
0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
|
||||
0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
|
||||
0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
|
||||
0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
|
||||
0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
|
||||
0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
|
||||
0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
|
||||
0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
|
||||
0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
|
||||
0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
|
||||
0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
|
||||
0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
|
||||
0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
|
||||
0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
|
||||
0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
|
||||
0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
|
||||
0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
|
||||
};
|
||||
|
||||
static short const tsin_16k[16] = {
|
||||
0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
|
||||
};
|
||||
static u16 tx_s_cnt = 0;
|
||||
static int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
|
||||
{
|
||||
while (points--) {
|
||||
if (*s_cnt >= 441) {
|
||||
*s_cnt = 0;
|
||||
}
|
||||
*data++ = tsin_441k[*s_cnt];
|
||||
if (ch == 2) {
|
||||
*data++ = tsin_441k[*s_cnt];
|
||||
}
|
||||
(*s_cnt)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_sine_16k_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
|
||||
{
|
||||
while (points--) {
|
||||
if (*s_cnt >= 16) {
|
||||
*s_cnt = 0;
|
||||
}
|
||||
*data++ = tsin_16k[*s_cnt];
|
||||
if (ch == 2) {
|
||||
*data++ = tsin_16k[*s_cnt];
|
||||
}
|
||||
(*s_cnt)++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern struct audio_decoder_task decode_task;
|
||||
void handle_tx(void *priv, void *buf, u16 len)
|
||||
{
|
||||
putchar('o');
|
||||
#if 1
|
||||
/* get_sine_16k_data(&tx_s_cnt, buf, len / 2 / 2, 2); */
|
||||
get_sine_data(&tx_s_cnt, buf, len / 2 / 2, 2);
|
||||
printf("tx len %x %d", buf, len);
|
||||
/* memset(buf, 0, len); */
|
||||
alink_set_shn(&p_alink0_parm->ch_cfg[0], len / 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
void handle_rx(void *priv, void *buf, u16 len)
|
||||
{
|
||||
/* putchar('r'); */
|
||||
#if 1
|
||||
put_buf(buf, 32);
|
||||
#else
|
||||
|
||||
#endif
|
||||
alink_set_shn(&p_alink0_parm->ch_cfg[1], len / 4);
|
||||
}
|
||||
|
||||
ALINK_PARM test_alink = {
|
||||
.module = ALINK0,
|
||||
.mclk_io = IO_PORTA_12,
|
||||
.sclk_io = IO_PORTA_13,
|
||||
.lrclk_io = IO_PORTA_14,
|
||||
.ch_cfg[0].data_io = IO_PORTA_15,
|
||||
.ch_cfg[1].data_io = IO_PORTA_11,
|
||||
/* .mode = ALINK_MD_IIS_LALIGN, */
|
||||
.mode = ALINK_MD_IIS,
|
||||
/* .role = ALINK_ROLE_SLAVE, */
|
||||
.role = ALINK_ROLE_MASTER,
|
||||
/* .clk_mode = ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, */
|
||||
.clk_mode = ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE,
|
||||
.bitwide = ALINK_LEN_16BIT,
|
||||
/* .bitwide = ALINK_LEN_24BIT, */
|
||||
.sclk_per_frame = ALINK_FRAME_32SCLK,
|
||||
/* .dma_len = ALNK_BUF_POINTS_NUM * 2 * 2 , */
|
||||
.dma_len = 4 * 1024,
|
||||
/* .sample_rate = 16000, */
|
||||
.sample_rate = 44100,
|
||||
/* .sample_rate = TCFG_IIS_SAMPLE_RATE, */
|
||||
/* .buf_mode = ALINK_BUF_CIRCLE, */
|
||||
.buf_mode = ALINK_BUF_DUAL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
void audio_link_test(void)
|
||||
{
|
||||
void *hw_alink = alink_init(&test_alink);
|
||||
|
||||
void *alink_ch0 = alink_channel_init(hw_alink, 0, ALINK_DIR_TX, NULL, handle_tx);
|
||||
/* void *alink_ch1 = alink_channel_init(hw_alink, 1, ALINK_DIR_RX, NULL, handle_rx); */
|
||||
/* void *alink_ch2 = alink_channel_init(hw_alink, 2, ALINK_DIR_TX, NULL, handle_tx); */
|
||||
/* void *alink_ch3 = alink_channel_init(hw_alink, 3, ALINK_DIR_RX, NULL, handle_rx); */
|
||||
clk_set("sys", 96 * 1000000L);
|
||||
alink_start(hw_alink);
|
||||
|
||||
|
||||
alink0_info_dump();
|
||||
while (1) {
|
||||
/* void clr_wdt(void); */
|
||||
/* clr_wdt(); */
|
||||
os_time_dly(2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
132
cpu/br28/audio_link.h
Normal file
132
cpu/br28/audio_link.h
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef _AUDIO_LINK_H_
|
||||
#define _AUDIO_LINK_H_
|
||||
|
||||
#define ALNK_BUF_POINTS_NUM 256
|
||||
|
||||
#define ALINK_CLK_OUPUT_DISABLE 0xFF
|
||||
|
||||
typedef enum {
|
||||
ALINK0 = 0u, //BR28只有一个ALNK模块
|
||||
} ALINK_PORT;
|
||||
|
||||
//ch_num
|
||||
typedef enum {
|
||||
ALINK_CH0 = 0u,
|
||||
ALINK_CH1,
|
||||
ALINK_CH2,
|
||||
ALINK_CH3,
|
||||
} ALINK_CH;
|
||||
|
||||
//ch_dir
|
||||
typedef enum {
|
||||
ALINK_DIR_TX = 0u,
|
||||
ALINK_DIR_RX ,
|
||||
} ALINK_DIR;
|
||||
|
||||
typedef enum {
|
||||
ALINK_LEN_16BIT = 0u,
|
||||
ALINK_LEN_24BIT , //ALINK_FRAME_MODE需要选择: ALINK_FRAME_64SCLK
|
||||
} ALINK_DATA_WIDTH;
|
||||
|
||||
//ch_mode
|
||||
typedef enum {
|
||||
ALINK_MD_NONE = 0u,
|
||||
ALINK_MD_IIS ,
|
||||
ALINK_MD_IIS_LALIGN ,
|
||||
ALINK_MD_IIS_RALIGN ,
|
||||
ALINK_MD_DSP0 ,
|
||||
ALINK_MD_DSP1 ,
|
||||
} ALINK_MODE;
|
||||
|
||||
//ch_mode
|
||||
typedef enum {
|
||||
ALINK_ROLE_MASTER, //主机
|
||||
ALINK_ROLE_SLAVE, //从机
|
||||
} ALINK_ROLE;
|
||||
|
||||
typedef enum {
|
||||
ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE, //下降沿更新数据, 上升沿采样数据
|
||||
ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, //上降沿更新数据, 下升沿采样数据
|
||||
} ALINK_CLK_MODE;
|
||||
|
||||
typedef enum {
|
||||
ALINK_FRAME_64SCLK, //64 sclk/frame
|
||||
ALINK_FRAME_32SCLK, //32 sclk/frame
|
||||
} ALINK_FRAME_MODE;
|
||||
|
||||
//SDK默认PLL是192M,仅支持44100,22050,11025采样率,如需其他采样率,需设置PLL为240M,可支持所有采样率
|
||||
typedef enum {
|
||||
ALINK_SR_48000 = 48000,
|
||||
ALINK_SR_44100 = 44100,
|
||||
ALINK_SR_32000 = 32000,
|
||||
ALINK_SR_24000 = 24000,
|
||||
ALINK_SR_22050 = 22050,
|
||||
ALINK_SR_16000 = 16000,
|
||||
ALINK_SR_12000 = 12000,
|
||||
ALINK_SR_11025 = 11025,
|
||||
ALINK_SR_8000 = 8000,
|
||||
} ALINK_SR;
|
||||
|
||||
typedef enum {
|
||||
ALINK_BUF_DUAL, //乒乓BUF
|
||||
ALINK_BUF_CIRCLE, //循环BUF
|
||||
} ALINK_BUF_MODE;
|
||||
|
||||
struct alnk_hw_ch {
|
||||
ALINK_PORT module;
|
||||
ALINK_CH ch_idx;
|
||||
u8 data_io; //data IO配置
|
||||
ALINK_DIR dir; //通道传输数据方向: Tx, Rx
|
||||
void *buf; //dma buf地址
|
||||
void (*isr_cb)(void *priv, void *addr, int len); //中断回调
|
||||
void *private_data; //音频私有数据
|
||||
};
|
||||
|
||||
//===================================//
|
||||
//多个通道使用需要注意:
|
||||
//1.数据位宽需要保持一致
|
||||
//2.buf长度相同
|
||||
//===================================//
|
||||
typedef struct _ALINK_PARM {
|
||||
ALINK_PORT module;
|
||||
u8 mclk_io; //mclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
|
||||
u8 sclk_io; //sclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
|
||||
u8 lrclk_io; //lrclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
|
||||
struct alnk_hw_ch ch_cfg[4]; //通道内部配置
|
||||
ALINK_MODE mode; //IIS, left, right, dsp0, dsp1
|
||||
ALINK_ROLE role; //主机/从机
|
||||
ALINK_CLK_MODE clk_mode; //更新和采样边沿
|
||||
ALINK_DATA_WIDTH bitwide; //数据位宽16/32bit
|
||||
ALINK_FRAME_MODE sclk_per_frame; //32/64 sclk/frame
|
||||
u16 dma_len; //buf长度: byte
|
||||
u16 iperiod; //输入中断的周期点数
|
||||
ALINK_SR sample_rate; //采样
|
||||
ALINK_BUF_MODE buf_mode; //乒乓buf or 循环buf率
|
||||
} ALINK_PARM;
|
||||
|
||||
//iis 模块相关
|
||||
void *alink_init(void *hw_alink); //iis 初始化
|
||||
int alink_start(void *hw_alink); //iis 开启
|
||||
int alink_set_sr(void *hw_alink, u32 sr); //iis 设置采样率
|
||||
int alink_get_sr(void *hw_alink); //iis 获取采样率
|
||||
u32 alink_get_dma_len(void *hw_alink); //iis 获取DMA_LEN
|
||||
void alink_set_rx_pns(void *hw_alink, u32 len); //iis 设置接收PNS
|
||||
void alink_set_tx_pns(void *hw_alink, u32 len); //iis 设置发送PNS
|
||||
void alink_uninit(void *hw_alink); //iis 退出
|
||||
int alink_get_tx_pns(void *hw_alink);
|
||||
|
||||
//iis 通道相关
|
||||
void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len)); //iis通道初始化,返回句柄
|
||||
void alink_channel_close(void *hw_channel); //iis通道关闭
|
||||
u32 alink_get_addr(void *hw_channel); //iis获取通道DMA地址
|
||||
u32 alink_get_shn(void *hw_channel); //iis获取通道SHN
|
||||
void alink_set_shn(void *hw_channel, u32 len); //iis设置通道SHN
|
||||
u32 alink_get_swptr(void *hw_channel); //iis获取通道swptr
|
||||
void alink_set_swptr(void *hw_channel, u32 value); //iis设置通道swptr
|
||||
u32 alink_get_hwptr(void *hw_channel); //iis获取通道hwptr
|
||||
void alink_set_hwptr(void *hw_channel, u32 value); //iis设置通道hwptr
|
||||
void alink_set_ch_ie(void *hw_channel, u32 value); //iis设置通道ie
|
||||
void alink_clr_ch_pnd(void *hw_channel); //iis清除通道pnd
|
||||
|
||||
u32 audio_iis_hw_rates_match(u32 sr);
|
||||
#endif
|
||||
108
cpu/br28/audio_sync.c
Normal file
108
cpu/br28/audio_sync.c
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
#include "board_config.h"
|
||||
#include "asm/dac.h"
|
||||
#include "media/includes.h"
|
||||
//#include "media/audio_dev.h"
|
||||
#include "effectrs_sync.h"
|
||||
#include "asm/gpio.h"
|
||||
|
||||
#if 0
|
||||
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
extern int bt_media_sync_master(u8 type);
|
||||
extern u8 bt_media_device_online(u8 dev);
|
||||
extern void *bt_media_sync_open(void);
|
||||
extern void bt_media_sync_close(void *);
|
||||
extern int a2dp_media_get_total_buffer_size();
|
||||
/*extern u32 get_bt_slot_time(u8 type, u32 time, u32 *pre_time);*/
|
||||
extern int bt_send_audio_sync_data(void *, void *buf, u32 len);
|
||||
extern void bt_media_sync_set_handler(void *, void *priv,
|
||||
void (*event_handler)(void *, int *, int));
|
||||
extern int bt_audio_sync_nettime_select(u8 basetime);
|
||||
|
||||
|
||||
const static struct audio_tws_conn_ops tws_conn_ops = {
|
||||
.open = bt_media_sync_open,
|
||||
.set_handler = bt_media_sync_set_handler,
|
||||
.close = bt_media_sync_close,
|
||||
/*.time = get_bt_slot_time,*/
|
||||
.master = bt_media_sync_master,
|
||||
.online = bt_media_device_online,
|
||||
.send = bt_send_audio_sync_data,
|
||||
};
|
||||
|
||||
#if (CONFIG_BD_NUM == 2)
|
||||
#define SYNC_DATA_TOP_PERCENT 70
|
||||
#define SYNC_DATA_BOTTOM_PERCENT 50
|
||||
#define SYNC_DATA_BEGIN_PERCENT 60
|
||||
#elif (TCFG_USER_TWS_ENABLE == 1)
|
||||
#if TCFG_BT_SUPPORT_AAC
|
||||
#define SYNC_DATA_TOP_PERCENT 70
|
||||
#define SYNC_DATA_BOTTOM_PERCENT 50
|
||||
#define SYNC_DATA_BEGIN_PERCENT 50
|
||||
#else
|
||||
#define SYNC_DATA_TOP_PERCENT 80
|
||||
#define SYNC_DATA_BOTTOM_PERCENT 60
|
||||
#define SYNC_DATA_BEGIN_PERCENT 60
|
||||
#endif
|
||||
#else
|
||||
#define SYNC_DATA_TOP_PERCENT 80
|
||||
#define SYNC_DATA_BOTTOM_PERCENT 60
|
||||
#define SYNC_DATA_BEGIN_PERCENT 70
|
||||
#endif
|
||||
|
||||
#define SYNC_START_TIME 100
|
||||
void *a2dp_play_sync_open(u8 channel, u32 sample_rate, u32 output_rate, u32 coding_type)
|
||||
{
|
||||
struct audio_wireless_sync_info sync_param;
|
||||
int a2dp_total_size = 0;
|
||||
|
||||
if (coding_type == AUDIO_CODING_AAC) {
|
||||
a2dp_total_size = 15 * 1024;
|
||||
} else if (coding_type == AUDIO_CODING_SBC) {
|
||||
a2dp_total_size = a2dp_media_get_total_buffer_size();
|
||||
}
|
||||
|
||||
sync_param.channel = channel;
|
||||
sync_param.tws_ops = &tws_conn_ops;
|
||||
sync_param.sample_rate = sample_rate;
|
||||
sync_param.output_rate = output_rate;
|
||||
|
||||
sync_param.data_top = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
|
||||
sync_param.data_bottom = SYNC_DATA_BOTTOM_PERCENT * a2dp_total_size / 100;
|
||||
sync_param.begin_size = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
|
||||
sync_param.tws_together_time = SYNC_START_TIME;
|
||||
|
||||
sync_param.protocol = WL_PROTOCOL_RTP;
|
||||
/*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
|
||||
sync_param.dev = &dac_hdl;
|
||||
|
||||
bt_audio_sync_nettime_select(0);
|
||||
|
||||
return audio_wireless_sync_open(&sync_param);
|
||||
}
|
||||
|
||||
void *esco_play_sync_open(u8 channel, u16 sample_rate, u16 output_rate)
|
||||
|
||||
{
|
||||
struct audio_wireless_sync_info sync_param;
|
||||
|
||||
int esco_buffer_size = 60 * 50;
|
||||
|
||||
sync_param.channel = channel;
|
||||
sync_param.sample_rate = sample_rate;
|
||||
sync_param.tws_ops = &tws_conn_ops;
|
||||
sync_param.data_top = 40 * esco_buffer_size / 100;
|
||||
sync_param.data_bottom = 10 * esco_buffer_size / 100;
|
||||
sync_param.begin_size = 15 * esco_buffer_size / 100; /*60*50*6/100 = 180(3 packet)*/
|
||||
sync_param.tws_together_time = SYNC_START_TIME;
|
||||
/*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
|
||||
sync_param.dev = &dac_hdl;
|
||||
|
||||
sync_param.protocol = WL_PROTOCOL_SCO;
|
||||
|
||||
bt_audio_sync_nettime_select(0);
|
||||
|
||||
return audio_wireless_sync_open(&sync_param);
|
||||
}
|
||||
#endif
|
||||
531
cpu/br28/charge.c
Normal file
531
cpu/br28/charge.c
Normal file
@ -0,0 +1,531 @@
|
||||
#include "asm/clock.h"
|
||||
#include "timer.h"
|
||||
#include "asm/power/p33.h"
|
||||
#include "asm/charge.h"
|
||||
#include "asm/adc_api.h"
|
||||
#include "uart.h"
|
||||
#include "device/device.h"
|
||||
#include "asm/power_interface.h"
|
||||
#include "asm/power/power_wakeup.h"
|
||||
#include "system/event.h"
|
||||
#include "asm/efuse.h"
|
||||
#include "gpio.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#define LOG_TAG_CONST CHARGE
|
||||
#define LOG_TAG "[CHARGE]"
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_DUMP_ENABLE
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct _CHARGE_VAR {
|
||||
struct charge_platform_data *data;
|
||||
volatile u8 charge_online_flag;
|
||||
volatile u8 charge_event_flag;
|
||||
volatile u8 init_ok;
|
||||
volatile u8 detect_stop;
|
||||
volatile int ldo5v_timer; //检测LDOIN状态变化的usr timer
|
||||
volatile int charge_timer; //检测充电是否充满的usr timer
|
||||
volatile int cc_timer; //涓流切恒流的sys timer
|
||||
} CHARGE_VAR;
|
||||
|
||||
#define __this (&charge_var)
|
||||
static CHARGE_VAR charge_var;
|
||||
static u8 charge_flag;
|
||||
|
||||
#define BIT_LDO5V_IN BIT(0)
|
||||
#define BIT_LDO5V_OFF BIT(1)
|
||||
#define BIT_LDO5V_KEEP BIT(2)
|
||||
|
||||
u8 get_charge_poweron_en(void)
|
||||
{
|
||||
return __this->data->charge_poweron_en;
|
||||
}
|
||||
|
||||
void set_charge_poweron_en(u32 onOff)
|
||||
{
|
||||
__this->data->charge_poweron_en = onOff;
|
||||
}
|
||||
|
||||
void charge_check_and_set_pinr(u8 level)
|
||||
{
|
||||
u8 pinr_io, reg;
|
||||
reg = P33_CON_GET(P3_PINR_CON1);
|
||||
//开启LDO5V_DET长按复位
|
||||
if ((reg & BIT(0)) && ((reg & BIT(3)) == 0)) {
|
||||
if (level == 0) {
|
||||
P33_CON_SET(P3_PINR_CON1, 2, 1, 0);
|
||||
} else {
|
||||
P33_CON_SET(P3_PINR_CON1, 2, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void udelay(u32 usec);
|
||||
static u8 check_charge_state(void)
|
||||
{
|
||||
u16 i, det_max_time;
|
||||
|
||||
#if TCFG_UMIDIGI_BOX_ENABLE
|
||||
det_max_time = TIMER2CMESSAGE * 16;
|
||||
#else
|
||||
det_max_time = 20;
|
||||
#endif
|
||||
|
||||
__this->charge_online_flag = 0;
|
||||
|
||||
for (i = 0; i < det_max_time; i++) {
|
||||
if (LVCMP_DET_GET() || LDO5V_DET_GET()) {
|
||||
__this->charge_online_flag = 1;
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
return __this->charge_online_flag;
|
||||
}
|
||||
|
||||
void set_charge_online_flag(u8 flag)
|
||||
{
|
||||
__this->charge_online_flag = flag;
|
||||
}
|
||||
|
||||
u8 get_charge_online_flag(void)
|
||||
{
|
||||
return __this->charge_online_flag;
|
||||
}
|
||||
|
||||
void set_charge_event_flag(u8 flag)
|
||||
{
|
||||
__this->charge_event_flag = flag;
|
||||
}
|
||||
|
||||
u8 get_ldo5v_online_hw(void)
|
||||
{
|
||||
return LDO5V_DET_GET();
|
||||
}
|
||||
|
||||
u8 get_lvcmp_det(void)
|
||||
{
|
||||
return LVCMP_DET_GET();
|
||||
}
|
||||
|
||||
u8 get_ldo5v_pulldown_en(void)
|
||||
{
|
||||
if (!__this->data) {
|
||||
return 0;
|
||||
}
|
||||
if (get_ldo5v_online_hw()) {
|
||||
if (__this->data->ldo5v_pulldown_keep == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return __this->data->ldo5v_pulldown_en;
|
||||
}
|
||||
|
||||
u8 get_ldo5v_pulldown_res(void)
|
||||
{
|
||||
if (__this->data) {
|
||||
return __this->data->ldo5v_pulldown_lvl;
|
||||
}
|
||||
return CHARGE_PULLDOWN_200K;
|
||||
}
|
||||
|
||||
void charge_event_to_user(u8 event)
|
||||
{
|
||||
struct sys_event e;
|
||||
e.type = SYS_DEVICE_EVENT;
|
||||
e.arg = (void *)DEVICE_EVENT_FROM_CHARGE;
|
||||
e.u.dev.event = event;
|
||||
e.u.dev.value = 0;
|
||||
sys_event_notify(&e);
|
||||
}
|
||||
|
||||
static void charge_cc_check(void *priv)
|
||||
{
|
||||
if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
|
||||
set_charge_mA(__this->data->charge_mA);
|
||||
usr_timer_del(__this->cc_timer);
|
||||
__this->cc_timer = 0;
|
||||
power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
|
||||
charge_wakeup_isr();
|
||||
}
|
||||
}
|
||||
|
||||
void charge_start(void)
|
||||
{
|
||||
u8 check_full = 0;
|
||||
log_info("%s\n", __func__);
|
||||
|
||||
#if !TCFG_EXTERN_CHARGE_ENABLE
|
||||
if (__this->charge_timer) {
|
||||
usr_timer_del(__this->charge_timer);
|
||||
__this->charge_timer = 0;
|
||||
}
|
||||
|
||||
//进入恒流充电之后,才开启充满检测
|
||||
if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
|
||||
set_charge_mA(__this->data->charge_mA);
|
||||
power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
|
||||
check_full = 1;
|
||||
} else {
|
||||
//涓流阶段系统不进入低功耗,防止电池电量更新过慢导致涓流切恒流时间过长
|
||||
set_charge_mA(__this->data->charge_trickle_mA);
|
||||
if (!__this->cc_timer) {
|
||||
__this->cc_timer = usr_timer_add(NULL, charge_cc_check, 1000, 1);
|
||||
}
|
||||
}
|
||||
|
||||
CHARGE_EN(1);
|
||||
CHGGO_EN(1);
|
||||
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_START);
|
||||
|
||||
//开启充电时,充满标记为1时,主动检测一次是否充满
|
||||
if (check_full && CHARGE_FULL_FLAG_GET()) {
|
||||
charge_wakeup_isr();
|
||||
}
|
||||
#else
|
||||
|
||||
/* 插入检测时使用vpwr 。Full_DET没充满时高阻,充满时低。 */
|
||||
//检测到开始充电,仅发送消息给其他app
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_START);
|
||||
|
||||
/* 初始化充满检测io */
|
||||
//设置为上拉输入
|
||||
gpio_direction_input(TCFG_EXTERN_CHARGE_PORT);
|
||||
gpio_set_pull_down(TCFG_EXTERN_CHARGE_PORT, 0);
|
||||
gpio_set_pull_up(TCFG_EXTERN_CHARGE_PORT, 1);
|
||||
gpio_set_die(TCFG_EXTERN_CHARGE_PORT, 1);
|
||||
|
||||
if (0 == gpio_read(TCFG_EXTERN_CHARGE_PORT)) {
|
||||
log_info("ex_charge has been full\n");
|
||||
//检测到低电平,已经充满了的情况下触发充电,直接走充满流程
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
|
||||
}
|
||||
power_wakeup_enable_with_port(TCFG_EXTERN_CHARGE_PORT);
|
||||
//此时还有一个低电检测定时器在跑,如果需要省充电功耗可以直接关机,等到下降沿来了就会会触发开机进行处理流程。
|
||||
/* power_set_soft_poweroff(); */
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void charge_close(void)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
|
||||
#if !TCFG_EXTERN_CHARGE_ENABLE
|
||||
CHARGE_EN(0);
|
||||
CHGGO_EN(0);
|
||||
|
||||
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
|
||||
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
|
||||
|
||||
if (__this->charge_timer) {
|
||||
usr_timer_del(__this->charge_timer);
|
||||
__this->charge_timer = 0;
|
||||
}
|
||||
if (__this->cc_timer) {
|
||||
usr_timer_del(__this->cc_timer);
|
||||
__this->cc_timer = 0;
|
||||
}
|
||||
#else
|
||||
power_wakeup_disable_with_port(TCFG_EXTERN_CHARGE_PORT);
|
||||
//检测到开始充电,仅发送消息给其他app
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void charge_full_detect(void *priv)
|
||||
{
|
||||
static u16 charge_full_cnt = 0;
|
||||
|
||||
if (CHARGE_FULL_FILTER_GET()) {
|
||||
/* putchar('F'); */
|
||||
if (CHARGE_FULL_FLAG_GET() && LVCMP_DET_GET()) {
|
||||
/* putchar('1'); */
|
||||
if (charge_full_cnt < 10) {
|
||||
charge_full_cnt++;
|
||||
} else {
|
||||
charge_full_cnt = 0;
|
||||
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
|
||||
usr_timer_del(__this->charge_timer);
|
||||
__this->charge_timer = 0;
|
||||
charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
|
||||
}
|
||||
} else {
|
||||
/* putchar('0'); */
|
||||
charge_full_cnt = 0;
|
||||
}
|
||||
} else {
|
||||
/* putchar('K'); */
|
||||
charge_full_cnt = 0;
|
||||
usr_timer_del(__this->charge_timer);
|
||||
__this->charge_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ldo5v_detect(void *priv)
|
||||
{
|
||||
/* log_info("%s\n",__func__); */
|
||||
|
||||
static u16 ldo5v_on_cnt = 0;
|
||||
static u16 ldo5v_keep_cnt = 0;
|
||||
static u16 ldo5v_off_cnt = 0;
|
||||
|
||||
if (__this->detect_stop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (LVCMP_DET_GET()) { //ldoin > vbat
|
||||
/* putchar('X'); */
|
||||
if (ldo5v_on_cnt < __this->data->ldo5v_on_filter) {
|
||||
ldo5v_on_cnt++;
|
||||
} else {
|
||||
/* printf("ldo5V_IN\n"); */
|
||||
set_charge_online_flag(1);
|
||||
ldo5v_off_cnt = 0;
|
||||
ldo5v_keep_cnt = 0;
|
||||
//消息线程未准备好接收消息,继续扫描
|
||||
if (__this->charge_event_flag == 0) {
|
||||
return;
|
||||
}
|
||||
ldo5v_on_cnt = 0;
|
||||
usr_timer_del(__this->ldo5v_timer);
|
||||
__this->ldo5v_timer = 0;
|
||||
if ((charge_flag & BIT_LDO5V_IN) == 0) {
|
||||
charge_flag = BIT_LDO5V_IN;
|
||||
charge_event_to_user(CHARGE_EVENT_LDO5V_IN);
|
||||
}
|
||||
}
|
||||
} else if (LDO5V_DET_GET() == 0) { //ldoin<拔出电压(0.6)
|
||||
/* putchar('Q'); */
|
||||
if (ldo5v_off_cnt < (__this->data->ldo5v_off_filter + 20)) {
|
||||
ldo5v_off_cnt++;
|
||||
} else {
|
||||
/* printf("ldo5V_OFF\n"); */
|
||||
set_charge_online_flag(0);
|
||||
ldo5v_on_cnt = 0;
|
||||
ldo5v_keep_cnt = 0;
|
||||
//消息线程未准备好接收消息,继续扫描
|
||||
if (__this->charge_event_flag == 0) {
|
||||
return;
|
||||
}
|
||||
ldo5v_off_cnt = 0;
|
||||
usr_timer_del(__this->ldo5v_timer);
|
||||
__this->ldo5v_timer = 0;
|
||||
if ((charge_flag & BIT_LDO5V_OFF) == 0) {
|
||||
charge_flag = BIT_LDO5V_OFF;
|
||||
charge_event_to_user(CHARGE_EVENT_LDO5V_OFF);
|
||||
}
|
||||
}
|
||||
} else { //拔出电压(0.6左右)< ldoin < vbat
|
||||
/* putchar('E'); */
|
||||
if (ldo5v_keep_cnt < __this->data->ldo5v_keep_filter) {
|
||||
ldo5v_keep_cnt++;
|
||||
} else {
|
||||
/* printf("ldo5V_ERR\n"); */
|
||||
set_charge_online_flag(1);
|
||||
ldo5v_off_cnt = 0;
|
||||
ldo5v_on_cnt = 0;
|
||||
//消息线程未准备好接收消息,继续扫描
|
||||
if (__this->charge_event_flag == 0) {
|
||||
return;
|
||||
}
|
||||
ldo5v_keep_cnt = 0;
|
||||
usr_timer_del(__this->ldo5v_timer);
|
||||
__this->ldo5v_timer = 0;
|
||||
if ((charge_flag & BIT_LDO5V_KEEP) == 0) {
|
||||
charge_flag = BIT_LDO5V_KEEP;
|
||||
if (__this->data->ldo5v_off_filter) {
|
||||
charge_event_to_user(CHARGE_EVENT_LDO5V_KEEP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ldoin_wakeup_isr(void)
|
||||
{
|
||||
if (!__this->init_ok) {
|
||||
return;
|
||||
}
|
||||
/* printf(" %s \n", __func__); */
|
||||
if (__this->ldo5v_timer == 0) {
|
||||
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void charge_wakeup_isr(void)
|
||||
{
|
||||
if (!__this->init_ok) {
|
||||
return;
|
||||
}
|
||||
/* printf(" %s \n", __func__); */
|
||||
if (__this->charge_timer == 0) {
|
||||
__this->charge_timer = usr_timer_add(0, charge_full_detect, 2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void charge_set_ldo5v_detect_stop(u8 stop)
|
||||
{
|
||||
__this->detect_stop = stop;
|
||||
}
|
||||
|
||||
u8 get_charge_mA_config(void)
|
||||
{
|
||||
return __this->data->charge_mA;
|
||||
}
|
||||
|
||||
void set_charge_mA(u8 charge_mA)
|
||||
{
|
||||
static u8 charge_mA_old = 0xff;
|
||||
if (charge_mA_old != charge_mA) {
|
||||
charge_mA_old = charge_mA;
|
||||
if (charge_mA & BIT(4)) {
|
||||
CHG_TRICKLE_EN(1);
|
||||
} else {
|
||||
CHG_TRICKLE_EN(0);
|
||||
}
|
||||
CHARGE_mA_SEL(charge_mA & 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
const u16 full_table[CHARGE_FULL_V_MAX] = {
|
||||
4041, 4061, 4081, 4101, 4119, 4139, 4159, 4179,
|
||||
4199, 4219, 4238, 4258, 4278, 4298, 4318, 4338,
|
||||
4237, 4257, 4275, 4295, 4315, 4335, 4354, 4374,
|
||||
4394, 4414, 4434, 4454, 4474, 4494, 4514, 4534,
|
||||
};
|
||||
u16 get_charge_full_value(void)
|
||||
{
|
||||
ASSERT(__this->init_ok, "charge not init ok!\n");
|
||||
ASSERT(__this->data->charge_full_V < CHARGE_FULL_V_MAX);
|
||||
return full_table[__this->data->charge_full_V];
|
||||
}
|
||||
|
||||
static void charge_config(void)
|
||||
{
|
||||
u8 charge_trim_val;
|
||||
u8 offset = 0;
|
||||
u8 charge_full_v_val = 0;
|
||||
//判断是用高压档还是低压档
|
||||
if (__this->data->charge_full_V < CHARGE_FULL_V_4237) {
|
||||
CHG_HV_MODE(0);
|
||||
charge_trim_val = get_vbat_trim();//4.20V对应的trim出来的实际档位
|
||||
if (charge_trim_val == 0xf) {
|
||||
log_info("vbat low not trim, use default config!!!!!!");
|
||||
charge_trim_val = CHARGE_FULL_V_4199;
|
||||
}
|
||||
log_info("low charge_trim_val = %d\n", charge_trim_val);
|
||||
if (__this->data->charge_full_V >= CHARGE_FULL_V_4199) {
|
||||
offset = __this->data->charge_full_V - CHARGE_FULL_V_4199;
|
||||
charge_full_v_val = charge_trim_val + offset;
|
||||
if (charge_full_v_val > 0xf) {
|
||||
charge_full_v_val = 0xf;
|
||||
}
|
||||
} else {
|
||||
offset = CHARGE_FULL_V_4199 - __this->data->charge_full_V;
|
||||
if (charge_trim_val >= offset) {
|
||||
charge_full_v_val = charge_trim_val - offset;
|
||||
} else {
|
||||
charge_full_v_val = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CHG_HV_MODE(1);
|
||||
charge_trim_val = get_vbat_trim_435();//4.35V对应的trim出来的实际档位
|
||||
if (charge_trim_val == 0xf) {
|
||||
log_info("vbat high not trim, use default config!!!!!!");
|
||||
charge_trim_val = CHARGE_FULL_V_4354 - 16;
|
||||
}
|
||||
log_info("high charge_trim_val = %d\n", charge_trim_val);
|
||||
if (__this->data->charge_full_V >= CHARGE_FULL_V_4354) {
|
||||
offset = __this->data->charge_full_V - CHARGE_FULL_V_4354;
|
||||
charge_full_v_val = charge_trim_val + offset;
|
||||
if (charge_full_v_val > 0xf) {
|
||||
charge_full_v_val = 0xf;
|
||||
}
|
||||
} else {
|
||||
offset = CHARGE_FULL_V_4354 - __this->data->charge_full_V;
|
||||
if (charge_trim_val >= offset) {
|
||||
charge_full_v_val = charge_trim_val - offset;
|
||||
} else {
|
||||
charge_full_v_val = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_info("charge_full_v_val = %d\n", charge_full_v_val);
|
||||
|
||||
CHARGE_FULL_V_SEL(charge_full_v_val);
|
||||
CHARGE_FULL_mA_SEL(__this->data->charge_full_mA);
|
||||
set_charge_mA(__this->data->charge_trickle_mA);
|
||||
}
|
||||
|
||||
int charge_init(const struct dev_node *node, void *arg)
|
||||
{
|
||||
log_info("%s\n", __func__);
|
||||
|
||||
__this->data = (struct charge_platform_data *)arg;
|
||||
|
||||
ASSERT(__this->data);
|
||||
|
||||
__this->init_ok = 0;
|
||||
__this->charge_online_flag = 0;
|
||||
|
||||
/*先关闭充电使能,后面检测到充电插入再开启*/
|
||||
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
|
||||
CHARGE_EN(0);
|
||||
CHGGO_EN(0);
|
||||
|
||||
/*LDO5V的100K下拉电阻使能*/
|
||||
L5V_RES_DET_S_SEL(__this->data->ldo5v_pulldown_lvl);
|
||||
L5V_LOAD_EN(__this->data->ldo5v_pulldown_en);
|
||||
|
||||
charge_config();
|
||||
|
||||
if (check_charge_state()) {
|
||||
if (__this->ldo5v_timer == 0) {
|
||||
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
|
||||
}
|
||||
} else {
|
||||
charge_flag = BIT_LDO5V_OFF;
|
||||
}
|
||||
|
||||
__this->init_ok = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void charge_module_stop(void)
|
||||
{
|
||||
if (!__this->init_ok) {
|
||||
return;
|
||||
}
|
||||
charge_close();
|
||||
power_awakeup_index_enable(IO_LDOIN_DET, 0);
|
||||
power_awakeup_index_enable(IO_VBTCH_DET, 0);
|
||||
if (__this->ldo5v_timer) {
|
||||
usr_timer_del(__this->ldo5v_timer);
|
||||
__this->ldo5v_timer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void charge_module_restart(void)
|
||||
{
|
||||
if (!__this->init_ok) {
|
||||
return;
|
||||
}
|
||||
if (!__this->ldo5v_timer) {
|
||||
__this->ldo5v_timer = usr_timer_add(NULL, ldo5v_detect, 2, 1);
|
||||
}
|
||||
power_awakeup_index_enable(IO_LDOIN_DET, 1);
|
||||
power_awakeup_index_enable(IO_VBTCH_DET, 1);
|
||||
}
|
||||
|
||||
const struct device_operations charge_dev_ops = {
|
||||
.init = charge_init,
|
||||
};
|
||||
335
cpu/br28/chargestore.c
Normal file
335
cpu/br28/chargestore.c
Normal file
@ -0,0 +1,335 @@
|
||||
#include "generic/typedef.h"
|
||||
#include "generic/gpio.h"
|
||||
#include "asm/power/p33.h"
|
||||
#include "asm/power/p33_app.h"
|
||||
#include "asm/hwi.h"
|
||||
#include "asm/gpio.h"
|
||||
#include "asm/clock.h"
|
||||
#include "asm/charge.h"
|
||||
#include "asm/chargestore.h"
|
||||
#include "update.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if (TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE)
|
||||
struct chargestore_handle {
|
||||
const struct chargestore_platform_data *data;
|
||||
JL_UART_TypeDef *UART;
|
||||
u32 baudrate;
|
||||
};
|
||||
#define DMA_ISR_LEN 64
|
||||
#define DMA_BUF_LEN 64
|
||||
#define __this (&hdl)
|
||||
static struct chargestore_handle hdl;
|
||||
u8 uart_dma_buf[DMA_BUF_LEN] __attribute__((aligned(4)));
|
||||
volatile u8 send_busy;
|
||||
|
||||
//串口时钟和串口超时时钟是分开的
|
||||
#define UART_SRC_CLK clk_get("uart")
|
||||
#define UART_OT_CLK clk_get("lsb")
|
||||
|
||||
enum {
|
||||
UPGRADE_NULL = 0,
|
||||
UPGRADE_USB_HARD_KEY,
|
||||
UPGRADE_USB_SOFTKEY,
|
||||
UPGRADE_UART_SOFT_KEY,
|
||||
UPGRADE_UART_ONE_WIRE_HARD_KEY,
|
||||
};
|
||||
extern void charge_reset_pb5_pd_status(void);
|
||||
extern void nvram_set_boot_state(u32 state);
|
||||
void update_param_boot_ram_set(u8 *buf, u16 len);
|
||||
|
||||
void chargestore_set_update_ram(void)
|
||||
{
|
||||
//需要补充设置ram
|
||||
int tmp;
|
||||
__asm__ volatile("%0 =icfg" : "=r"(tmp));
|
||||
tmp &= ~(3 << 8);
|
||||
__asm__ volatile("icfg = %0" :: "r"(tmp));//GIE1
|
||||
local_irq_disable();
|
||||
#if TCFG_TEST_BOX_ANY_IO_UPDATE
|
||||
update_param_boot_ram_set("UART_UPDATE_CUSTOM", sizeof("UART_UPDATE_CUSTOM"));
|
||||
#else
|
||||
nvram_set_boot_state(UPGRADE_UART_SOFT_KEY);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __attribute__((weak)) chargestore_data_deal(u8 cmd, u8 *data, u8 len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void __attribute__((weak)) chargestore_uart_data_deal(u8 *data, u8 len)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static u8 chargestore_get_f95_det_res(u32 equ_res)
|
||||
{
|
||||
u8 det_res = (equ_res + 50) / 100;
|
||||
if (det_res > 0) {
|
||||
det_res -= 1;
|
||||
}
|
||||
if (det_res > 0x0f) {
|
||||
det_res = 0x0f;
|
||||
}
|
||||
return det_res;
|
||||
}
|
||||
|
||||
//br30(PMU数据未知,IC还未给出测试数据,说是和BR23基本一致)
|
||||
u8 chargestore_get_det_level(u8 chip_type)
|
||||
{
|
||||
u32 res = 1600;
|
||||
switch (chip_type) {
|
||||
case TYPE_F95:
|
||||
if (IS_L5V_LOAD_EN()) {
|
||||
res = (GET_L5V_RES_DET_S_SEL() + 1) * 50;
|
||||
}
|
||||
return chargestore_get_f95_det_res(res);
|
||||
case TYPE_NORMAL:
|
||||
default:
|
||||
return 0x0f;
|
||||
}
|
||||
}
|
||||
|
||||
___interrupt
|
||||
static void uart_isr(void)
|
||||
{
|
||||
u16 i;
|
||||
u32 rx_len = 0;
|
||||
if (__this->data->io_port == IO_PORT_DP) {
|
||||
//测试盒选DP,跟USB功能复用
|
||||
local_irq_disable();
|
||||
}
|
||||
if ((__this->UART->CON0 & BIT(2)) && (__this->UART->CON0 & BIT(15))) {
|
||||
__this->UART->CON0 |= BIT(13);
|
||||
send_busy = 0;
|
||||
chargestore_data_deal(CMD_COMPLETE, NULL, 0);
|
||||
}
|
||||
if ((__this->UART->CON0 & BIT(3)) && (__this->UART->CON0 & BIT(14))) {
|
||||
__this->UART->CON0 |= BIT(12);//清RX PND
|
||||
chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, DMA_ISR_LEN);
|
||||
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
|
||||
__this->UART->RXSADR = (u32)uart_dma_buf;
|
||||
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
|
||||
__this->UART->RXCNT = DMA_ISR_LEN;
|
||||
}
|
||||
if ((__this->UART->CON0 & BIT(5)) && (__this->UART->CON0 & BIT(11))) {
|
||||
//OTCNT PND
|
||||
__this->UART->CON0 |= BIT(7);//DMA模式
|
||||
__this->UART->CON0 |= BIT(10);//清OTCNT PND
|
||||
asm volatile("nop");
|
||||
rx_len = __this->UART->HRXCNT;//读当前串口接收数据的个数
|
||||
__this->UART->CON0 |= BIT(12);//清RX PND(这里的顺序不能改变,这里要清一次)
|
||||
chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, rx_len);
|
||||
chargestore_uart_data_deal(uart_dma_buf, rx_len);
|
||||
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
|
||||
__this->UART->RXSADR = (u32)uart_dma_buf;
|
||||
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
|
||||
__this->UART->RXCNT = DMA_ISR_LEN;
|
||||
}
|
||||
if (__this->data->io_port == IO_PORT_DP) {
|
||||
//测试盒选DP,跟USB功能复用
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
void chargestore_write(u8 *data, u8 len)
|
||||
{
|
||||
ASSERT(((u32)data) % 4 == 0); //4byte对齐
|
||||
send_busy = 1;
|
||||
__this->UART->TXADR = (u32)data;
|
||||
__this->UART->TXCNT = len;
|
||||
}
|
||||
|
||||
void chargestore_open(u8 mode)
|
||||
{
|
||||
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
|
||||
if (mode == MODE_RECVDATA) {
|
||||
charge_set_ldo5v_detect_stop(0);
|
||||
gpio_direction_input(__this->data->io_port);
|
||||
gpio_set_die(__this->data->io_port, 1);
|
||||
__this->UART->CON1 &= ~BIT(4);
|
||||
if (__this->UART == JL_UART0) {
|
||||
gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX, LOW_POWER_FREE);
|
||||
} else if (__this->UART == JL_UART1) {
|
||||
gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX, LOW_POWER_FREE);
|
||||
} else {
|
||||
gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX, LOW_POWER_FREE);
|
||||
}
|
||||
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
|
||||
__this->UART->RXSADR = (u32)uart_dma_buf;
|
||||
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
|
||||
__this->UART->RXCNT = DMA_ISR_LEN;
|
||||
__this->UART->CON0 |= BIT(6) | BIT(5) | BIT(3);
|
||||
} else {
|
||||
charge_set_ldo5v_detect_stop(1);
|
||||
gpio_direction_output(__this->data->io_port, 1);
|
||||
gpio_set_hd(__this->data->io_port, 1);
|
||||
__this->UART->CON1 |= BIT(4);
|
||||
if (__this->UART == JL_UART0) {
|
||||
gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1, LOW_POWER_FREE);
|
||||
} else if (__this->UART == JL_UART1) {
|
||||
gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1, LOW_POWER_FREE);
|
||||
} else {
|
||||
gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1, LOW_POWER_FREE);
|
||||
|
||||
}
|
||||
__this->UART->CON0 |= BIT(2);
|
||||
}
|
||||
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);
|
||||
}
|
||||
|
||||
void chargestore_close(void)
|
||||
{
|
||||
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(0);
|
||||
gpio_set_pull_down(__this->data->io_port, 0);
|
||||
gpio_set_pull_up(__this->data->io_port, 0);
|
||||
gpio_set_die(__this->data->io_port, 1);
|
||||
gpio_set_hd(__this->data->io_port, 0);
|
||||
gpio_direction_input(__this->data->io_port);
|
||||
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
|
||||
charge_set_ldo5v_detect_stop(0);
|
||||
}
|
||||
|
||||
void chargestore_set_baudrate(u32 baudrate)
|
||||
{
|
||||
u32 uart_timeout;
|
||||
__this->baudrate = baudrate;
|
||||
uart_timeout = 20 * 1000000 / __this->baudrate;
|
||||
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
|
||||
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void chargestore_init(const struct chargestore_platform_data *data)
|
||||
{
|
||||
u32 uart_timeout;
|
||||
__this->data = (struct chargestore_platform_data *)data;
|
||||
ASSERT(data);
|
||||
switch (__this->data->uart_irq) {
|
||||
case IRQ_UART0_IDX:
|
||||
__this->UART = JL_UART0;
|
||||
break;
|
||||
case IRQ_UART1_IDX:
|
||||
__this->UART = JL_UART1;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0, "uart irq(%d) err!\n", __this->data->uart_irq);
|
||||
break;
|
||||
}
|
||||
if (__this->UART->CON0 & BIT(0)) {
|
||||
ASSERT(0, "uart used!\n");
|
||||
}
|
||||
uart_timeout = 20 * 1000000 / __this->data->baudrate;
|
||||
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
|
||||
__this->UART->OTCNT = uart_timeout * (clk_get("uart") / 1000000);
|
||||
__this->UART->BAUD = (clk_get("uart") / __this->data->baudrate) / 4 - 1;
|
||||
__this->UART->CON1 = (((clk_get("uart") / __this->data->baudrate) % 4) << 4);
|
||||
gpio_set_pull_down(__this->data->io_port, 0);
|
||||
gpio_set_pull_up(__this->data->io_port, 0);
|
||||
gpio_set_die(__this->data->io_port, 1);
|
||||
gpio_direction_input(__this->data->io_port);
|
||||
request_irq(__this->data->uart_irq, 2, uart_isr, 0);
|
||||
JL_IOMAP->CON1 &= ~(0xf << 8);
|
||||
//约定:
|
||||
//使用UART0时,使用output channel0 和 input channel 0
|
||||
//使用UART1时,使用output channel1 和 input channel 1 //由于irflt需要用到INPUT_CH1,所以串口1输入改成INPUT_CH3
|
||||
if (__this->UART == JL_UART0) {
|
||||
//不占用IO
|
||||
JL_IOMAP->CON3 &= ~BIT(3);
|
||||
//100:input channel0
|
||||
//101:input channel1
|
||||
//110:input channel2
|
||||
//111:input channel3
|
||||
JL_IOMAP->CON3 &= ~(0b111 << 0);
|
||||
JL_IOMAP->CON3 |= (0b100 << 0);
|
||||
//[29:24]:input channel 3 io sel
|
||||
//[21:16]:input channel 2 io sel
|
||||
//[13:08]:input channel 1 io sel
|
||||
//[05:00]:input channel 0 io sel
|
||||
JL_IOMAP->CON2 &= ~(0b111111 << 0);
|
||||
JL_IOMAP->CON2 |= (__this->data->io_port << 0);
|
||||
//000:output channel 0 sel UT0_TX
|
||||
//001:output channel 0 sel UT1_TX
|
||||
JL_IOMAP->CON1 &= ~(0b1111 << 8);
|
||||
JL_IOMAP->CON1 |= (0 << 8);//outchl0 -> ut0_tx
|
||||
} else {
|
||||
//不占用IO
|
||||
JL_IOMAP->CON3 &= ~BIT(7);
|
||||
//100:input channel0
|
||||
//101:input channel1
|
||||
//110:input channel2
|
||||
//111:input channel3
|
||||
JL_IOMAP->CON3 &= ~(0b111 << 4);
|
||||
JL_IOMAP->CON3 |= (0b111 << 4);
|
||||
//[29:24]:input channel 3 io sel
|
||||
//[21:16]:input channel 2 io sel
|
||||
//[13:08]:input channel 1 io sel
|
||||
//[05:00]:input channel 0 io sel
|
||||
JL_IOMAP->CON2 &= ~(0b111111 << 24);
|
||||
JL_IOMAP->CON2 |= (__this->data->io_port << 24);
|
||||
//000:output channel 1 sel UT0_TX
|
||||
//001:output channel 1 sel UT1_TX
|
||||
JL_IOMAP->CON3 &= ~(0b1111 << 20);
|
||||
JL_IOMAP->CON3 |= (1 << 20);//outchl1 -> ut1_tx
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
void chargestore_init(const struct chargestore_platform_data *data)
|
||||
{
|
||||
u32 uart_timeout;
|
||||
__this->data = (struct chargestore_platform_data *)data;
|
||||
ASSERT(data);
|
||||
if (!(JL_UART0->CON0 & BIT(0))) {
|
||||
JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10);
|
||||
request_irq(IRQ_UART0_IDX, 2, uart_isr, 0);
|
||||
__this->UART = JL_UART0;
|
||||
} else if (!(JL_UART1->CON0 & BIT(0))) {
|
||||
JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10);
|
||||
request_irq(IRQ_UART1_IDX, 2, uart_isr, 0);
|
||||
__this->UART = JL_UART1;
|
||||
} else if (!(JL_UART2->CON0 & BIT(0))) {
|
||||
JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10);
|
||||
request_irq(IRQ_UART2_IDX, 2, uart_isr, 0);
|
||||
__this->UART = JL_UART2;
|
||||
} else {
|
||||
ASSERT(0, "uart all used!\n");
|
||||
}
|
||||
send_busy = 0;
|
||||
uart_timeout = 20 * 1000000 / __this->data->baudrate;
|
||||
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);//占用该串口,不被其他模块使用
|
||||
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
|
||||
__this->UART->BAUD = (UART_SRC_CLK / __this->data->baudrate) / 4 - 1;
|
||||
__this->baudrate = __this->data->baudrate;
|
||||
gpio_set_pull_down(__this->data->io_port, 0);
|
||||
gpio_set_pull_up(__this->data->io_port, 0);
|
||||
gpio_set_die(__this->data->io_port, 1);
|
||||
gpio_direction_input(__this->data->io_port);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void clock_critical_enter(void)
|
||||
{
|
||||
u8 cmp_buf[2] = {0x55, 0xAA};
|
||||
//等待数据收完
|
||||
extern void *memmem(void *srcmem, int src_len, void *desmem, int des_len);
|
||||
while (memmem(uart_dma_buf, sizeof(uart_dma_buf), cmp_buf, sizeof(cmp_buf)));
|
||||
//等待数据发完
|
||||
while (send_busy);
|
||||
}
|
||||
static void clock_critical_exit(void)
|
||||
{
|
||||
u32 uart_timeout;
|
||||
if (__this->UART == NULL) {
|
||||
return;
|
||||
}
|
||||
uart_timeout = 20 * 1000000 / __this->baudrate;
|
||||
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
|
||||
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
|
||||
}
|
||||
CLOCK_CRITICAL_HANDLE_REG(chargestore, clock_critical_enter, clock_critical_exit)
|
||||
|
||||
#endif
|
||||
|
||||
118
cpu/br28/clock_cfg.h
Normal file
118
cpu/br28/clock_cfg.h
Normal file
@ -0,0 +1,118 @@
|
||||
#ifndef CLOCK_CFG_H
|
||||
#define CLOCK_CFG_H
|
||||
|
||||
#include "typedef.h"
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
enum {
|
||||
|
||||
BT_IDLE_CLOCK = 1,
|
||||
MUSIC_IDLE_CLOCK,
|
||||
FM_IDLE_CLOCK,
|
||||
LINEIN_IDLE_CLOCK,
|
||||
PC_IDLE_CLOCK,
|
||||
REC_IDLE_CLOCK,
|
||||
RTC_IDLE_CLOCK,
|
||||
SPDIF_IDLE_CLOCK,
|
||||
BOX_IDLE_CLOCK,
|
||||
|
||||
|
||||
DEC_SBC_CLK ,
|
||||
DEC_AAC_CLK ,
|
||||
DEC_MSBC_CLK,
|
||||
DEC_CVSD_CLK,
|
||||
|
||||
AEC8K_CLK ,
|
||||
AEC8K_ADV_CLK,
|
||||
AEC16K_CLK ,
|
||||
AEC16K_ADV_CLK,
|
||||
AEC8K_SPX_CLK,
|
||||
AEC16K_SPX_CLK,
|
||||
|
||||
DEC_TONE_CLK,
|
||||
DEC_MP3_CLK ,
|
||||
DEC_WAV_CLK , /// 10
|
||||
DEC_G729_CLK,
|
||||
DEC_G726_CLK,
|
||||
DEC_PCM_CLK ,
|
||||
DEC_MTY_CLK ,
|
||||
DEC_WMA_CLK ,
|
||||
|
||||
DEC_APE_CLK ,
|
||||
DEC_FLAC_CLK,
|
||||
DEC_AMR_CLK ,
|
||||
DEC_DTS_CLK ,
|
||||
|
||||
DEC_M4A_CLK , ///20
|
||||
DEC_ALAC_CLK,
|
||||
DEC_FM_CLK ,
|
||||
DEC_LINE_CLK,
|
||||
DEC_TWS_SBC_CLK,
|
||||
SPDIF_CLK ,
|
||||
|
||||
ENC_RECODE_CLK,
|
||||
ENC_SBC_CLK ,
|
||||
ENC_WAV_CLK ,
|
||||
ENC_G726_CLK,
|
||||
ENC_MP3_CLK ,
|
||||
ENC_TWS_SBC_CLK,
|
||||
|
||||
ENC_MSBC_CLK, //////30
|
||||
ENC_CVSD_CLK,
|
||||
SYNC_CLK ,
|
||||
AUTOMUTE_CLK ,
|
||||
FINDF_CLK ,
|
||||
FM_INSIDE_CLK,
|
||||
BT_CONN_CLK ,
|
||||
|
||||
EQ_CLK ,
|
||||
EQ_DRC_CLK ,
|
||||
EQ_ONLINE_CLK,
|
||||
REVERB_CLK ,
|
||||
REVERB_HOWLING_CLK,
|
||||
REVERB_PITCH_CLK,
|
||||
|
||||
DEC_MP3PICK_CLK ,
|
||||
DEC_WMAPICK_CLK ,
|
||||
DEC_M4APICK_CLK ,
|
||||
DEC_MIX_CLK,
|
||||
|
||||
DEC_IIS_CLK,
|
||||
DEC_UI_CLK,
|
||||
DEC_MIDI_CLK,
|
||||
|
||||
DEC_3D_CLK,
|
||||
DEC_VBASS_CLK,
|
||||
DEC_LOUDNES_CLK,
|
||||
|
||||
DONGLE_ENC_CLK,
|
||||
|
||||
LCD_UI_CLK,
|
||||
SCAN_DISK_CLK,
|
||||
SPECTRUM_CLK,
|
||||
|
||||
LOCALTWS_CLK,
|
||||
|
||||
AI_SPEECH_CLK,
|
||||
SMARTBOX_ACTION_CLK,
|
||||
|
||||
ADAPTER_PROCESS_CLK,
|
||||
|
||||
ENUM_MAX_CLK = 63 ,
|
||||
};
|
||||
|
||||
void clock_pause_play(u8 mode);
|
||||
|
||||
|
||||
void clock_idle(u32 type);
|
||||
void clock_add(u32 type);
|
||||
void clock_remove(u32 type);
|
||||
void clock_set_cur(void);
|
||||
void clock_add_set(u32 type);
|
||||
void clock_remove_set(u32 type);
|
||||
|
||||
|
||||
#endif
|
||||
411
cpu/br28/clock_manager.c
Normal file
411
cpu/br28/clock_manager.c
Normal file
@ -0,0 +1,411 @@
|
||||
#include "system/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "clock_cfg.h"
|
||||
#include "asm/dac.h"
|
||||
struct clock_type {
|
||||
u8 type;
|
||||
u32 clock;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/*****
|
||||
|
||||
idle clk : 模式里面的空闲时钟
|
||||
|
||||
时钟通过idle clk 加上每一种解码或者运算的时钟
|
||||
累加总和来设置需要的时钟
|
||||
|
||||
模式空闲时钟设置
|
||||
void clock_idle(u32 type)
|
||||
|
||||
|
||||
把时钟设置加入到ext中,但是不是立刻设置时钟
|
||||
需要最后调用clock_set_cur来最后设置时钟
|
||||
用于连续地方设置时钟
|
||||
用完后必须把时钟remove
|
||||
void clock_add(u32 type)
|
||||
void clock_remove(u32 type)
|
||||
void clock_set_cur(void)
|
||||
|
||||
|
||||
把时钟设置加入到ext中,立刻设置时钟
|
||||
需要立刻添加时钟
|
||||
用完后必须把时钟remove
|
||||
void clock_add_set(u32 type)
|
||||
void clock_remove_set(u32 type)
|
||||
|
||||
*****/
|
||||
|
||||
//// 如果clock_fix 为0 就按照配置设置时钟,如果有值就固定频率
|
||||
#if TCFG_MIC_EFFECT_ENABLE
|
||||
#define CLOCK_FIX (192)
|
||||
#else
|
||||
#define CLOCK_FIX 0
|
||||
#endif
|
||||
|
||||
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) && TCFG_EQ_DIVIDE_ENABLE
|
||||
#define EQ4_CLK (24)
|
||||
#else
|
||||
#define EQ4_CLK (0)
|
||||
#endif
|
||||
|
||||
#if TCFG_EQ_ONLINE_ENABLE
|
||||
#define EQ_ONLINE_CLK (64)
|
||||
#else
|
||||
#define EQ_ONLINE_CLK (0)
|
||||
#endif
|
||||
|
||||
#define MIX_SRC_CLK (24)//src
|
||||
|
||||
const struct clock_type clock_enum[] = {
|
||||
|
||||
{ BT_IDLE_CLOCK , (24), " BT_IDLE_CLOCK " },
|
||||
#ifndef CONFIG_SOUNDBOX_FLASH_256K
|
||||
{ MUSIC_IDLE_CLOCK , (24), " MUSIC_IDLE_CLOCK " },
|
||||
{ FM_IDLE_CLOCK , (12), " FM_IDLE_CLOCK " },
|
||||
{ LINEIN_IDLE_CLOCK , (96), " LINEIN_IDLE_CLOCK " },
|
||||
{ PC_IDLE_CLOCK , (120), " PC_IDLE_CLOCK " },
|
||||
{ REC_IDLE_CLOCK , (12), " REC_IDLE_CLOCK " },
|
||||
{ RTC_IDLE_CLOCK , (12), " RTC_IDLE_CLOCK " },
|
||||
{ SPDIF_IDLE_CLOCK , (12), " SPDIF_IDLE_CLOCK " },
|
||||
{ BOX_IDLE_CLOCK , (24), " BOX_IDLE_CLOCK " },
|
||||
|
||||
|
||||
{ DEC_SBC_CLK , (32), "DEC_SBC_CLK " },
|
||||
{ DEC_AAC_CLK , (32), "DEC_AAC_CLK " },
|
||||
#endif
|
||||
{ DEC_MSBC_CLK , (12), "DEC_MSBC_CLK " },
|
||||
{ DEC_CVSD_CLK , (8), "DEC_CVSD_CLK " },
|
||||
|
||||
{ AEC8K_CLK , (10), "AEC8K_CLK " },
|
||||
{ AEC8K_ADV_CLK , (50), "AEC8K_ADV_CLK " },
|
||||
{ AEC16K_CLK , (10), "AEC16K_CLK " },
|
||||
{ AEC16K_ADV_CLK, (50), "AEC16K_ADV_CLK " },
|
||||
{ AEC8K_SPX_CLK , (10), "AEC8K_SPX_CLK " },
|
||||
{ AEC16K_SPX_CLK, (10), "AEC16K_SPX_CLK " },
|
||||
|
||||
{ DEC_TONE_CLK , (24 + 32), "DEC_TONE_CLK " },
|
||||
{ DEC_G729_CLK , (24), "DEC_G729_CLK " },
|
||||
{ DEC_PCM_CLK , (24), "DEC_PCM_CLK " },
|
||||
#ifndef CONFIG_SOUNDBOX_FLASH_256K
|
||||
{ DEC_MP3_CLK , (80), "DEC_MP3_CLK " },
|
||||
{ DEC_WAV_CLK , (32), "DEC_WAV_CLK " },
|
||||
{ DEC_G726_CLK , (24), "DEC_G726_CLK " },
|
||||
{ DEC_MTY_CLK , (24), "DEC_MTY_CLK " },
|
||||
{ DEC_WMA_CLK , (48), "DEC_WMA_CLK " },
|
||||
|
||||
{ DEC_APE_CLK , (160), "DEC_APE_CLK "},
|
||||
{ DEC_FLAC_CLK , (96), "DEC_FLAC_CLK "},
|
||||
{ DEC_AMR_CLK , (96), "DEC_AMR_CLK "},
|
||||
{ DEC_DTS_CLK , (120), "DEC_DTS_CLK " },
|
||||
|
||||
{ DEC_M4A_CLK , (48), "DEC_M4A_CLK "},
|
||||
{ DEC_ALAC_CLK , (48), "DEC_ALAC_CLK "},
|
||||
{ DEC_FM_CLK , (12), "DEC_FM_CLK " },
|
||||
{ DEC_LINE_CLK , (24), "DEC_LINE_CLK " },
|
||||
{ DEC_TWS_SBC_CLK, (32), "DEC_TWS_SBC_CLK" },
|
||||
{ SPDIF_CLK , (120), "SPDIF_CLK " },
|
||||
|
||||
{ ENC_RECODE_CLK, (64), "ENC_RECODE_CLK " },
|
||||
{ ENC_SBC_CLK , (64), "ENC_SBC_CLK " },
|
||||
{ ENC_WAV_CLK , (96), "ENC_WAV_CLK " },
|
||||
{ ENC_G726_CLK, (64), "ENC_G726_CLK " },
|
||||
{ ENC_MP3_CLK , (120), "ENC_MP3_CLK " },
|
||||
{ ENC_TWS_SBC_CLK, (48), "ENC_TWS_SBC_CLK" },
|
||||
#endif
|
||||
{ ENC_MSBC_CLK , (12), "ENC_MSBC_CLK " },
|
||||
{ ENC_CVSD_CLK , (8), "ENC_CVSD_CLK " },
|
||||
|
||||
{ SYNC_CLK , (4), "SYNC_CLK " },
|
||||
{ AUTOMUTE_CLK , (16), "AUTOMUTE_CLK" },
|
||||
|
||||
#ifndef CONFIG_SOUNDBOX_FLASH_256K
|
||||
{ FINDF_CLK , (120), "FINDF_CLK " },
|
||||
{ FM_INSIDE_CLK , (96), "FM_INSIDE_CLK " },
|
||||
#endif
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
{ BT_CONN_CLK , (48), "BT_CONN_CLK " },
|
||||
#else
|
||||
{ BT_CONN_CLK , (16), "BT_CONN_CLK " },
|
||||
#endif
|
||||
|
||||
|
||||
{ EQ_CLK , (24 + EQ_ONLINE_CLK + EQ4_CLK), " EQ_CLK " },
|
||||
{ EQ_DRC_CLK , (60), " EQ_DRC_CLK " },
|
||||
/* { EQ_ONLINE_CLK, (120), " EQ_ONLINE_CLK " }, */
|
||||
#ifndef CONFIG_SOUNDBOX_FLASH_256K
|
||||
{ REVERB_CLK , (64), " REVERB_CLK " },
|
||||
{ REVERB_HOWLING_CLK , (32), " REVERB_HOWLING_CLK " },
|
||||
{ REVERB_PITCH_CLK , (24), " REVERB_PITCH_CLK " },
|
||||
|
||||
{ DEC_MP3PICK_CLK, (8), "DEC_MP3PICK_CLK" },
|
||||
{ DEC_WMAPICK_CLK, (8), "DEC_WMAICK_CLK" },
|
||||
{ DEC_M4APICK_CLK, (8), "DEC_M4AICK_CLK" },
|
||||
#endif
|
||||
{ DEC_MIX_CLK, (6 + MIX_SRC_CLK), "DEC_MIX_CLK" },
|
||||
|
||||
{ DEC_UI_CLK, (160), "DEC_UI_CLK" },
|
||||
#ifndef CONFIG_SOUNDBOX_FLASH_256K
|
||||
{ DEC_IIS_CLK, (64), "DEC_IIS_CLK" },
|
||||
|
||||
//midi音色文件跳转读取频繁,外挂flash baud 调到6000000L, midi_clk 80M就够
|
||||
{ DEC_MIDI_CLK, (110), "DEC_MIDI_CLK" },
|
||||
/* { DEC_MIDI_CLK, (80), "DEC_MIDI_CLK" }, */
|
||||
|
||||
{ DEC_3D_CLK, (24), "DEC_3D_CLK" },
|
||||
{ DEC_VBASS_CLK, (8), "DEC_VBASS_CLK" },
|
||||
{ DEC_LOUDNES_CLK, (108), "DEC_LOUDNES_CLK"},
|
||||
|
||||
{ DONGLE_ENC_CLK, (48), "DONGLE_ENC_CLK" },
|
||||
#endif
|
||||
|
||||
{ SCAN_DISK_CLK, (120), "SCAN_DISK_CLK" },//提高扫盘速度
|
||||
|
||||
#if TCFG_DEC2TWS_ENABLE
|
||||
{ LOCALTWS_CLK, (24), "LOCALTWS_CLK" },
|
||||
#endif
|
||||
{SPECTRUM_CLK, (5), "SPECTRUM_CLK" },
|
||||
|
||||
{AI_SPEECH_CLK, (120), "AI_SPEECH_CLK" },
|
||||
{SMARTBOX_ACTION_CLK, (160), "SMARTBOX_ACTION_CLK" },
|
||||
|
||||
#ifdef CONFIG_ADAPTER_ENABLE
|
||||
{ADAPTER_PROCESS_CLK, (64), "ADAPTER_PROCESS_CLK" },
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if (defined(TCFG_CLOCK_PLL_240MHZ) && TCFG_CLOCK_PLL_240MHZ)
|
||||
static int hsb_clock_init(void)
|
||||
{
|
||||
clock_set_pll_target_frequency(240);
|
||||
return 0;
|
||||
}
|
||||
platform_initcall(hsb_clock_init);
|
||||
|
||||
const u8 clock_tb[] = {
|
||||
24,
|
||||
32,
|
||||
48,
|
||||
80,
|
||||
96,
|
||||
120,
|
||||
160,
|
||||
};
|
||||
#else /* #if TCFG_CLOCK_PLL_240MHZ */
|
||||
const u8 clock_tb[] = {
|
||||
24,
|
||||
32,
|
||||
48,
|
||||
64,
|
||||
96,
|
||||
128,
|
||||
160,
|
||||
};
|
||||
#endif /* #if TCFG_CLOCK_PLL_240MHZ */
|
||||
|
||||
static u8 ext_clk_tb[10];
|
||||
static u32 idle_type = 0;
|
||||
|
||||
static void clock_ext_dump()
|
||||
{
|
||||
u8 i, j;
|
||||
for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
|
||||
if (idle_type == clock_enum[i].type) {
|
||||
y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
|
||||
if (ext_clk_tb[i]) {
|
||||
for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
|
||||
if (ext_clk_tb[i] == clock_enum[j].type) {
|
||||
y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u8 clock_idle_selet(u32 type)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
#if (CLOCK_FIX )
|
||||
return CLOCK_FIX;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
|
||||
if (type == clock_enum[i].type) {
|
||||
/* y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name); */
|
||||
return clock_enum[i].clock;
|
||||
}
|
||||
}
|
||||
|
||||
return 24;
|
||||
}
|
||||
|
||||
u8 clock_ext_push(u8 ext_type)
|
||||
{
|
||||
u8 i;
|
||||
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
|
||||
if (ext_type == ext_clk_tb[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
|
||||
if (!ext_clk_tb[i]) {
|
||||
ext_clk_tb[i] = ext_type;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
y_printf("clock ext over!!! \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 clock_ext_pop(u8 ext_type)
|
||||
{
|
||||
u8 i;
|
||||
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
|
||||
if (ext_type == ext_clk_tb[i]) {
|
||||
ext_clk_tb[i] = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 clock_match(u16 clk)
|
||||
{
|
||||
u8 i;
|
||||
for (i = 0; i < ARRAY_SIZE(clock_tb); i++) {
|
||||
if (clk <= clock_tb[i]) {
|
||||
return clock_tb[i];
|
||||
}
|
||||
}
|
||||
y_printf("clock overlimit!!! %d\n", clock_tb[ARRAY_SIZE(clock_tb) - 1]);
|
||||
return clock_tb[ARRAY_SIZE(clock_tb) - 1];
|
||||
}
|
||||
|
||||
|
||||
u16 clock_ext_cal()
|
||||
{
|
||||
u32 ext_clk = 0 ;
|
||||
u8 i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
|
||||
if (ext_clk_tb[i]) {
|
||||
for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
|
||||
if (ext_clk_tb[i] == clock_enum[j].type) {
|
||||
/* y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name); */
|
||||
ext_clk += clock_enum[j].clock;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ext_clk;
|
||||
}
|
||||
|
||||
u32 clock_cur_cal()
|
||||
{
|
||||
u32 idle_clk, cur_clk, ext_clk;
|
||||
|
||||
#if (CLOCK_FIX )
|
||||
return CLOCK_FIX;
|
||||
#endif
|
||||
|
||||
local_irq_disable();
|
||||
idle_clk = clock_idle_selet(idle_type);
|
||||
ext_clk = clock_ext_cal();
|
||||
cur_clk = idle_clk + ext_clk;
|
||||
cur_clk = clock_match(cur_clk);
|
||||
local_irq_enable();
|
||||
return cur_clk ;
|
||||
}
|
||||
|
||||
void clock_pause_play(u8 mode)
|
||||
{
|
||||
u32 idle_clk, cur_clk ;
|
||||
if (mode) {
|
||||
idle_clk = clock_idle_selet(idle_type);
|
||||
clk_set("sys", idle_clk * 1000000L);
|
||||
} else {
|
||||
clock_ext_dump();
|
||||
cur_clk = clock_cur_cal();
|
||||
clk_set("sys", cur_clk * 1000000L);
|
||||
}
|
||||
}
|
||||
|
||||
void clock_idle(u32 type)
|
||||
{
|
||||
u32 cur_clk;
|
||||
local_irq_disable();
|
||||
idle_type = type;
|
||||
cur_clk = clock_cur_cal();
|
||||
local_irq_enable();
|
||||
clock_ext_dump();
|
||||
clk_set("sys", cur_clk * 1000000L);
|
||||
}
|
||||
|
||||
//////把时钟设置加入到ext中,但是不是立刻设置时钟
|
||||
void clock_add(u32 type)
|
||||
{
|
||||
u32 cur_clk ;
|
||||
u8 resoult = clock_ext_push(type);
|
||||
if (!resoult) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void clock_remove(u32 type)
|
||||
{
|
||||
u32 cur_clk ;
|
||||
|
||||
u8 resoult = clock_ext_pop(type);
|
||||
if (!resoult) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void clock_set_cur(void)
|
||||
{
|
||||
u32 cur_clk ;
|
||||
clock_ext_dump();
|
||||
cur_clk = clock_cur_cal();
|
||||
clk_set("sys", cur_clk * 1000000L);
|
||||
}
|
||||
|
||||
//////把时钟设置加入到ext中,立刻设置时钟
|
||||
void clock_add_set(u32 type)
|
||||
{
|
||||
u32 cur_clk ;
|
||||
u8 resoult = clock_ext_push(type);
|
||||
if (!resoult) {
|
||||
return;
|
||||
}
|
||||
clock_ext_dump();
|
||||
cur_clk = clock_cur_cal();
|
||||
clk_set("sys", cur_clk * 1000000L);
|
||||
}
|
||||
|
||||
void clock_remove_set(u32 type)
|
||||
{
|
||||
u32 cur_clk ;
|
||||
|
||||
u8 resoult = clock_ext_pop(type);
|
||||
if (!resoult) {
|
||||
return;
|
||||
}
|
||||
|
||||
clock_ext_dump();
|
||||
cur_clk = clock_cur_cal();
|
||||
clk_set("sys", cur_clk * 1000000L);
|
||||
}
|
||||
697
cpu/br28/eq_config.c
Normal file
697
cpu/br28/eq_config.c
Normal file
@ -0,0 +1,697 @@
|
||||
|
||||
#include "system/includes.h"
|
||||
#include "media/includes.h"
|
||||
#include "app_config.h"
|
||||
#include "app_online_cfg.h"
|
||||
#include "online_db/online_db_deal.h"
|
||||
#include "config/config_interface.h"
|
||||
#include "application/eq_config.h"
|
||||
#include "audio_config.h"
|
||||
#include "cfg_tool.h"
|
||||
|
||||
#ifdef CONFIG_EQ_APP_SEG_ENABLE
|
||||
#pragma const_seg( ".eq_app_codec_const")
|
||||
#pragma code_seg ( ".eq_app_codec_code" )
|
||||
#endif
|
||||
const u8 audio_eq_sdk_name[16] = "AC701N";
|
||||
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
|
||||
const u8 audio_eq_ver[4] = {0, 8, 4, 0};//包含虚拟低音、多带drc、以及辅听耳机音效
|
||||
#else
|
||||
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
|
||||
const u8 audio_eq_ver[4] = {0, 8, 3, 0};
|
||||
#else
|
||||
const u8 audio_eq_ver[4] = {0, 8, 0, 0};
|
||||
#endif
|
||||
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
||||
|
||||
#if TCFG_EQ_FILE_SWITCH_EN
|
||||
const u8 *eq_file_switch_list[] = {
|
||||
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin",
|
||||
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin",
|
||||
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw2.bin",
|
||||
};
|
||||
#endif
|
||||
|
||||
//eq_cfg_hw.bin中播歌eq曲线,当作用户自定义模式,参与效果切换.
|
||||
//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
|
||||
//EQ_FILE_CP_TO_CUSTOM 1使能时,同时板极文件中 TCFG_USE_EQ_FILE 配 0
|
||||
#define EQ_FILE_CP_TO_CUSTOM 0
|
||||
|
||||
|
||||
/*************************非用户配置区*************************/
|
||||
#if TCFG_EQ_ONLINE_ENABLE
|
||||
#undef EQ_FILE_CP_TO_CUSTOM
|
||||
#define EQ_FILE_CP_TO_CUSTOM 0
|
||||
#endif
|
||||
#ifndef TCFG_USER_EQ_MODE_NUM
|
||||
#define TCFG_USER_EQ_MODE_NUM 0
|
||||
#endif
|
||||
#ifndef APP_ONLINE_DEBUG
|
||||
#define APP_ONLINE_DEBUG 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef TCFG_CALL_DL_EQ_SECTION
|
||||
#define TCFG_CALL_DL_EQ_SECTION 3
|
||||
#endif
|
||||
#ifndef TCFG_CALL_UL_EQ_SECTION
|
||||
#define TCFG_CALL_UL_EQ_SECTION 3
|
||||
#endif
|
||||
/*************************************************************/
|
||||
|
||||
#if (TCFG_EQ_ENABLE != 0)
|
||||
|
||||
#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
|
||||
#define AUDIO_EQ_Q 1.5f
|
||||
#else
|
||||
#define AUDIO_EQ_Q 0.7f
|
||||
#endif
|
||||
|
||||
|
||||
#if !TCFG_USE_EQ_FILE
|
||||
const struct eq_seg_info eq_tab_normal[] = {
|
||||
#if TCFG_USER_EQ_MODE_NUM > 0
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct eq_seg_info eq_tab_rock[] = {
|
||||
|
||||
#if TCFG_USER_EQ_MODE_NUM > 1
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 2, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, -2, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, -2, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct eq_seg_info eq_tab_pop[] = {
|
||||
|
||||
#if TCFG_USER_EQ_MODE_NUM > 2
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, 3, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 1, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, -2, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, -4, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, -4, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, -2, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 1, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct eq_seg_info eq_tab_classic[] = {
|
||||
|
||||
#if TCFG_USER_EQ_MODE_NUM > 3
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 8, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 8, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 2, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct eq_seg_info eq_tab_country[] = {
|
||||
#if TCFG_USER_EQ_MODE_NUM > 5
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 2, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, 2, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
const struct eq_seg_info eq_tab_jazz[] = {
|
||||
#if TCFG_USER_EQ_MODE_NUM > 4
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, 4, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 4, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 2, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 3, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
#endif
|
||||
|
||||
};
|
||||
struct eq_seg_info eq_tab_custom[] = {
|
||||
#if TCFG_USER_EQ_MODE_NUM > 6
|
||||
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
|
||||
|
||||
#if (EQ_SECTION_MAX > 10)
|
||||
//10段之后频率值设置96k,目的是让10段之后的eq走直通
|
||||
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
|
||||
#endif
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
const EQ_CFG_SEG *eq_type_tab[EQ_MODE_MAX] = {
|
||||
eq_tab_normal, eq_tab_rock, eq_tab_pop, eq_tab_classic, eq_tab_jazz, eq_tab_country, eq_tab_custom
|
||||
};
|
||||
// 默认系数表,每个表对应的总增益,用户可修改
|
||||
float type_gain_tab[EQ_MODE_MAX] = {0, 0, 0, 0, 0, 0, 0};
|
||||
#endif
|
||||
|
||||
__attribute__((weak)) u32 get_eq_mode_tab(void)
|
||||
{
|
||||
#if !TCFG_USE_EQ_FILE
|
||||
return (u32)eq_type_tab;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
__attribute__((weak)) u8 get_eq_mode_max(void)
|
||||
{
|
||||
return EQ_MODE_MAX;
|
||||
}
|
||||
|
||||
#if (EQ_SECTION_MAX==9)
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
0, 1, 2, 3, 4, 5, /*6,*/ 7, 8, 9
|
||||
};
|
||||
#elif (EQ_SECTION_MAX==8)
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
0, /*1,*/ 2, 3, 4, 5, 6, 7, /*8,*/ 9
|
||||
};
|
||||
#elif (EQ_SECTION_MAX==7)
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
0, /*1,*/ 2, 3, 4, 5, /*6,*/ 7, /*8,*/ 9
|
||||
};
|
||||
#elif (EQ_SECTION_MAX==6)
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
0, /*1,*/ 2, 3, 4, /*5,*/ /*6,*/ 7, /*8,*/ 9
|
||||
};
|
||||
#elif (EQ_SECTION_MAX==5)
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
/*0,*/ 1, /*2,*/ 3, /*4,*/ 5, /*6,*/ 7, /*8,*/ 9
|
||||
};
|
||||
#else
|
||||
static const u8 eq_mode_use_idx[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
||||
};
|
||||
#endif
|
||||
/*
|
||||
*通话下行eq系数表
|
||||
* */
|
||||
#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
|
||||
#if EQ_FILE_CP_TO_CUSTOM
|
||||
struct eq_seg_info phone_eq_tab_normal[] = {
|
||||
#else
|
||||
const struct eq_seg_info phone_eq_tab_normal[] = {
|
||||
#endif
|
||||
{0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
#if TCFG_CALL_DL_EQ_SECTION > 3
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
*通话上行eq系数表
|
||||
* */
|
||||
#if EQ_FILE_CP_TO_CUSTOM
|
||||
struct eq_seg_info ul_eq_tab_normal[] = {
|
||||
#else
|
||||
const struct eq_seg_info ul_eq_tab_normal[] = {
|
||||
#endif
|
||||
{0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
|
||||
{1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
|
||||
{2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
#if TCFG_CALL_UL_EQ_SECTION > 3
|
||||
{3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
{9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define SONG_SECTION EQ_SECTION_MAX
|
||||
#define CALL_SECTION TCFG_CALL_DL_EQ_SECTION//下行段数,小于等于SONG_SECTION
|
||||
#define UL_SECTION TCFG_CALL_UL_EQ_SECTION//上行段数,小于等于SONG_SECTION
|
||||
/*
|
||||
*下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
|
||||
*表的每一项顺序不可修改
|
||||
* */
|
||||
eq_tool_cfg eq_tool_tab[] = {
|
||||
{call_eq_mode, (u8 *)"通话宽频下行EQ", 0x3001, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
|
||||
{call_narrow_eq_mode, (u8 *)"通话窄频下行EQ", 0x3002, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
|
||||
{aec_eq_mode, (u8 *)"通话宽频上行EQ", 0x3003, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
|
||||
{aec_narrow_eq_mode, (u8 *)"通话窄频上行EQ", 0x3004, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
|
||||
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
|
||||
{song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, {EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_MULTI_WDRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},//多带wdrc
|
||||
{hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
|
||||
{hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
|
||||
#else
|
||||
{song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, { EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_DRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},
|
||||
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
|
||||
{hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
|
||||
{hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
|
||||
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
||||
#endif
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief eq 段数更新,需要在eq_init前就准备好
|
||||
@param mode:call_eq_mode\call_narrow_eq_section等模式
|
||||
@param section:段数最大为EQ_SECTION_MAX
|
||||
@return
|
||||
@note 下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
void set_eq_tool_tab_section(u8 mode, u8 section)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(eq_tool_tab); i++) {
|
||||
if (mode == eq_tool_tab[i].mode_index) {
|
||||
eq_tool_tab[i].section = section;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eq_section_num_set(u8 song, u8 call_16k_8k, u8 aec_16k_8k)
|
||||
{
|
||||
set_eq_tool_tab_section(song_eq_mode, song);
|
||||
set_eq_tool_tab_section(call_eq_mode, call_16k_8k);
|
||||
set_eq_tool_tab_section(call_narrow_eq_mode, call_16k_8k);
|
||||
set_eq_tool_tab_section(aec_eq_mode, aec_16k_8k);
|
||||
set_eq_tool_tab_section(aec_narrow_eq_mode, aec_16k_8k);
|
||||
}
|
||||
void drc_default_init(EQ_CFG *eq_cfg, u8 mode)
|
||||
{
|
||||
#if TCFG_DRC_ENABLE
|
||||
int i = mode;
|
||||
if (eq_cfg && eq_cfg->drc) {
|
||||
//限幅器的初始值
|
||||
int th = 0;//db -60db~0db
|
||||
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768); // 0db:32768, -60db:33
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc.nband = 1;
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc.type = 1;
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].attacktime = 5;
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].releasetime = 500;
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[0] = threshold;
|
||||
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[1] = 32768;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#if EQ_FILE_CP_TO_CUSTOM
|
||||
//eq_cfg_hw.bin中播歌eq曲线,当作用户自定义模式,参与效果切换.
|
||||
//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
|
||||
//EQ_FILE_CP_TO_CUSTOM 1使能时,同时板极文件中 TCFG_USE_EQ_FILE 配 0
|
||||
static void eq_file_cp_to_custon_mode_fun(EQ_CFG *eq_cfg)
|
||||
{
|
||||
if (eq_cfg->eq_type == EQ_TYPE_FILE) {
|
||||
eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
|
||||
for (int i = 0; i < eq_cfg->mode_num; i++) {
|
||||
if ((i == song_eq_mode) || (i == call_eq_mode) || (i == aec_eq_mode)) { //播歌eq 通话宽频上下行eq
|
||||
u32 seg_num = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.seg_num;
|
||||
u8 index = 0;
|
||||
for (int j = 0; j < ARRAY_SIZE(eq_tool_tab); j++) {
|
||||
if (i == eq_tool_tab[j].mode_index) {
|
||||
index = j;
|
||||
}
|
||||
}
|
||||
if (seg_num > eq_tool_tab[index].section) {
|
||||
seg_num = eq_tool_tab[index].section;
|
||||
}
|
||||
void *tar = NULL;
|
||||
if (i == call_eq_mode) {
|
||||
#if TCFG_PHONE_EQ_ENABLE
|
||||
tar = eq_cfg->phone_eq_tab;
|
||||
#endif
|
||||
} else if (i == aec_eq_mode) {
|
||||
tar = eq_cfg->ul_eq_tab;
|
||||
} else if (i == song_eq_mode) {
|
||||
tar = eq_tab_custom;
|
||||
eq_cfg->type_gain_tab[EQ_MODE_MAX - 1] = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.global_gain;
|
||||
}
|
||||
if (tar) {
|
||||
memcpy(tar, eq_cfg->cfg_parm[i].song_eq_parm.parm.seg, seg_num * sizeof(EQ_CFG_SEG));
|
||||
eq_cfg->seg_num[i] = seg_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__attribute__((weak))
|
||||
s16 get_ci_tx_size()
|
||||
{
|
||||
return 0x30;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static u8 reply_to_tool = 0;
|
||||
static u8 reply_sq = 0;
|
||||
/*
|
||||
*新调音回调
|
||||
* */
|
||||
static void eq_online_callback_new_protocol(uint8_t *packet, uint16_t size)
|
||||
{
|
||||
u8 *ptr = packet;
|
||||
reply_sq = ptr[1];
|
||||
reply_to_tool = 0;
|
||||
u8 *new_packet = (void *)&packet[2];
|
||||
eq_online_callback(new_packet, size);
|
||||
}
|
||||
//新调音注册
|
||||
REGISTER_DETECT_TARGET(eq_adj_target) = {
|
||||
.id = EQ_CONFIG_ID,
|
||||
.tool_message_deal = eq_online_callback_new_protocol,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int ci_send_cmd(void *priv, u32 id, u8 *packet, int size)
|
||||
{
|
||||
EQ_CFG *eq_cfg = (EQ_CFG *)priv;
|
||||
if (!eq_cfg) {
|
||||
return 0;
|
||||
}
|
||||
#if TCFG_ONLINE_ENABLE
|
||||
#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
|
||||
all_assemble_package_send_to_pc(reply_to_tool, reply_sq, packet, size);
|
||||
#else
|
||||
ci_send_packet(id, packet, size);
|
||||
#endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
struct virtual_bass_tool_set vbass_default_param = {
|
||||
.prev_gain = -3, //dB预处理,降低数据增益,防止虚拟低音把数据调爆
|
||||
.parm = {
|
||||
.ratio = 10, //比率(0~100),越大,低音强度越大
|
||||
.boost = 1, //(低音自动增强0, 1)
|
||||
.fc = 100, //截止频率(30~300Hz)
|
||||
},
|
||||
};
|
||||
|
||||
struct virtual_bass_tool_set *get_vbass_parm()
|
||||
{
|
||||
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
|
||||
if (!eq_cfg) {
|
||||
return NULL;
|
||||
}
|
||||
#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
|
||||
return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
|
||||
#else
|
||||
if (eq_cfg->vbass_file) {
|
||||
return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
|
||||
} else {
|
||||
return &vbass_default_param;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int eq_init(void)
|
||||
{
|
||||
eq_adjust_parm parm = {0};
|
||||
#if TCFG_EQ_ONLINE_ENABLE
|
||||
parm.online_en = 1;
|
||||
#endif
|
||||
if (config_filter_coeff_fade_en) {
|
||||
parm.fade_en = 1;
|
||||
}
|
||||
|
||||
#if TCFG_USE_EQ_FILE
|
||||
parm.file_en = 1;
|
||||
#endif
|
||||
|
||||
#if EQ_FILE_CP_TO_CUSTOM
|
||||
parm.file_en = 1;
|
||||
parm.type_gain_tab = type_gain_tab;
|
||||
#endif
|
||||
|
||||
#if TCFG_DRC_ENABLE
|
||||
parm.drc = 1;
|
||||
#endif
|
||||
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
parm.tws = 1;
|
||||
#endif
|
||||
|
||||
|
||||
#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
|
||||
/* parm.limit_zero = 1; */
|
||||
#endif
|
||||
|
||||
/* #if TCFG_EQ_DIVIDE_ENABLE */
|
||||
/* parm.stero = 1; */
|
||||
/* parm.mode_num = 8; */
|
||||
/* #endif */
|
||||
|
||||
if (!parm.stero) {
|
||||
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
|
||||
parm.mode_num = 7;//一共有多少个模式
|
||||
#else
|
||||
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
|
||||
parm.mode_num = 7;// 一共有多少个模式
|
||||
#else
|
||||
parm.mode_num = 5;// 一共有多少个模式
|
||||
#endif
|
||||
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
|
||||
/* #ifdef DAC_OUTPUT_FRONT_LR_REAR_LR */
|
||||
/* #if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) */
|
||||
/* parm.mode_num = 6; */
|
||||
/* #endif */
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
#if TCFG_PHONE_EQ_ENABLE
|
||||
parm.phone_eq_tab = (void *)phone_eq_tab_normal;
|
||||
parm.phone_eq_tab_size = TCFG_CALL_DL_EQ_SECTION;//ARRAY_SIZE(phone_eq_tab_normal);
|
||||
#endif
|
||||
|
||||
#if TCFG_AEC_UL_EQ_ENABLE
|
||||
parm.ul_eq_tab = (void *)ul_eq_tab_normal;
|
||||
parm.ul_eq_tab_size = TCFG_CALL_UL_EQ_SECTION;//ARRAY_SIZE(ul_eq_tab_normal);
|
||||
#endif
|
||||
|
||||
parm.eq_tool_tab = eq_tool_tab;
|
||||
parm.eq_mode_use_idx = (u8 *)eq_mode_use_idx;
|
||||
|
||||
parm.eq_type_tab = (void *)get_eq_mode_tab();
|
||||
#if TCFG_USER_EQ_MODE_NUM
|
||||
parm.type_num = TCFG_USER_EQ_MODE_NUM;//EQ_MODE_MAX;
|
||||
#endif
|
||||
|
||||
parm.section_max = EQ_SECTION_MAX;
|
||||
|
||||
EQ_CFG *eq_cfg = eq_cfg_open(&parm);
|
||||
if (eq_cfg) {
|
||||
eq_cfg->priv = eq_cfg;
|
||||
eq_cfg->send_cmd = ci_send_cmd;
|
||||
eq_cfg->custom_mode_id = EQ_MODE_CUSTOM;
|
||||
#if defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
|
||||
eq_cfg->vbass = 1;
|
||||
#endif
|
||||
#if EQ_FILE_CP_TO_CUSTOM
|
||||
eq_file_cp_to_custon_mode_fun(eq_cfg);
|
||||
#else
|
||||
for (int i = 0; i < eq_cfg->mode_num; i++) {
|
||||
if (eq_cfg->eq_type == EQ_TYPE_MODE_TAB) {
|
||||
if (!eq_cfg->type_gain_tab) {//没指定总增益时,才配置默认总增益0
|
||||
set_global_gain(eq_cfg, i, 0);
|
||||
}
|
||||
drc_default_init(eq_cfg, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int cpu_section = 0;
|
||||
//单声道或者立体声申请的cpu eq mem
|
||||
if (EQ_SECTION_MAX > 10) {
|
||||
u8 add_num = 0;
|
||||
if (hw_crossover_type0) {
|
||||
add_num = 4;//drc分频器使用eq硬件加速时、3段4阶使用最大eq段数24段(每段4个eq, 6声道)
|
||||
}
|
||||
cpu_section = EQ_SECTION_MAX - (int)&EQ_PRIV_SECTION_NUM + add_num;
|
||||
}
|
||||
audio_eq_init(cpu_section);
|
||||
return 0;
|
||||
}
|
||||
__initcall(eq_init);
|
||||
|
||||
|
||||
#if TCFG_EQ_FILE_SWITCH_EN
|
||||
//根据eq_file_switch_list切换到指定的eq文件
|
||||
void eq_file_set_by_index(u8 index)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(eq_file_switch_list)) {
|
||||
printf("err, max index %d\n", ARRAY_SIZE(eq_file_switch_list));
|
||||
return;
|
||||
}
|
||||
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
|
||||
if (!eq_cfg) {
|
||||
return;
|
||||
}
|
||||
int ret = eq_file_get_cfg(eq_cfg, eq_file_switch_list[index]);
|
||||
printf("eq_file_switch : %d, ret : %d", index, ret);
|
||||
}
|
||||
|
||||
//根据eq_file_switch_list成员个数顺序切换eq文件
|
||||
void eq_file_switch()
|
||||
{
|
||||
static u8 index = 0;
|
||||
index++;
|
||||
if (index >= ARRAY_SIZE(eq_file_switch_list)) {
|
||||
index = 0;
|
||||
}
|
||||
eq_file_set_by_index(index);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
220
cpu/br28/hw_fft.c
Normal file
220
cpu/br28/hw_fft.c
Normal file
@ -0,0 +1,220 @@
|
||||
#include "includes.h"
|
||||
|
||||
/*FFT模块资源互斥方式配置*/
|
||||
#define CRITICAL_NULL 0
|
||||
#define CRITICAL_IRQ 1
|
||||
#define CRITICAL_MUTEX 2
|
||||
#define CRITICAL_SPIN_LOCK 3
|
||||
#define FFT_CRITICAL_MODE CRITICAL_SPIN_LOCK
|
||||
|
||||
#if (FFT_CRITICAL_MODE == CRITICAL_MUTEX)
|
||||
static OS_MUTEX fft_mutex;
|
||||
#define FFT_CRITICAL_INIT() os_mutex_create(&fft_mutex)
|
||||
#define FFT_ENTER_CRITICAL() os_mutex_pend(&fft_mutex, 0)
|
||||
#define FFT_EXIT_CRITICAL() os_mutex_post(&fft_mutex)
|
||||
#elif (FFT_CRITICAL_MODE == CRITICAL_IRQ)
|
||||
#define FFT_CRITICAL_INIT(...)
|
||||
#define FFT_ENTER_CRITICAL() local_irq_disable()
|
||||
#define FFT_EXIT_CRITICAL() local_irq_enable()
|
||||
#elif (FFT_CRITICAL_MODE == CRITICAL_SPIN_LOCK)
|
||||
static spinlock_t fft_lock;
|
||||
#define FFT_CRITICAL_INIT() spin_lock_init(&fft_lock)
|
||||
#define FFT_ENTER_CRITICAL() spin_lock(&fft_lock)
|
||||
#define FFT_EXIT_CRITICAL() spin_unlock(&fft_lock)
|
||||
|
||||
#endif /*FFT_CRITICAL_MODE*/
|
||||
|
||||
static volatile u8 fft_init = 0;
|
||||
|
||||
typedef struct {
|
||||
unsigned int fft_config;
|
||||
const int *in;
|
||||
int *out;
|
||||
} pi32v2_hw_fft_ctx;
|
||||
|
||||
#define FFT_ISR_IE 0
|
||||
void hw_fft_wrap(pi32v2_hw_fft_ctx *ctx)
|
||||
{
|
||||
if (fft_init == 0) {
|
||||
fft_init = 1;
|
||||
FFT_CRITICAL_INIT();
|
||||
}
|
||||
FFT_ENTER_CRITICAL();
|
||||
|
||||
JL_FFT->CON = 0;
|
||||
JL_FFT->CON |= 1 << 8;
|
||||
JL_FFT->CADR = (unsigned int)ctx;
|
||||
JL_FFT->CON = (1 << 8) | (0 << 6) | (FFT_ISR_IE << 2) | (0 << 1) | (1 << 0); //((1<<8)|(1<<0))
|
||||
while ((JL_FFT->CON & (1 << 7)) == 0);
|
||||
JL_FFT->CON |= (1 << 6);
|
||||
|
||||
FFT_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
static int REAL_FFT_CONFIG[6] = {
|
||||
809501970, 813696546, 822085426, 838862898, 872417602, 939526722,
|
||||
};
|
||||
|
||||
/**** Real IFFT *******/
|
||||
static int REAL_IFFT_CONFIG[6] = {
|
||||
809501958, 1082131974, 822085382, 1107298310, 872417542, 1207962118,
|
||||
};
|
||||
|
||||
/****************************
|
||||
*
|
||||
* Complex Support points
|
||||
* 32\64\128\256\512\1024\2048
|
||||
*
|
||||
* *************************/
|
||||
/**** Complex FFT *******/
|
||||
static int COMPLEX_FFT_CONFIG[7] = {
|
||||
538969360, 541066784, 545261344, 553650224, 570427696, 603982400, 671091520,
|
||||
};
|
||||
|
||||
/**** Complex IFFT *******/
|
||||
static int COMPLEX_IFFT_CONFIG[7] = {
|
||||
1075840276, 809502212, 1082132244, 822085636, 1107298580, 872417796, 1207962388,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* hw_fft_config
|
||||
* Description: 根据配置生成 FFT_config
|
||||
* Arguments : N 运算数据量;
|
||||
log2N 运算数据量的对数值
|
||||
is_same_addr 输入输出是否同一个地址,0:否,1:是
|
||||
is_ifft 运算类型 0:FFT运算, 1:IFFT运算
|
||||
is_real 运算数据的类型 1:实数, 0:复数
|
||||
* Return : ConfgPars 写入FFT寄存器
|
||||
* Note(s) : None.
|
||||
*********************************************************************/
|
||||
unsigned int hw_fft_config(int N, int log2N, int is_same_addr, int is_ifft, int is_real)
|
||||
{
|
||||
unsigned int ConfgPars;
|
||||
ConfgPars = 0;
|
||||
if (is_real == 1) {
|
||||
if (is_ifft == 0) {
|
||||
ConfgPars = REAL_FFT_CONFIG[log2N - 6];
|
||||
ConfgPars |= is_same_addr;
|
||||
} else {
|
||||
ConfgPars = REAL_IFFT_CONFIG[log2N - 6];
|
||||
ConfgPars |= is_same_addr;
|
||||
}
|
||||
} else {
|
||||
if (is_ifft == 0) {
|
||||
ConfgPars = COMPLEX_FFT_CONFIG[log2N - 5];
|
||||
ConfgPars |= is_same_addr;
|
||||
} else {
|
||||
ConfgPars = COMPLEX_IFFT_CONFIG[log2N - 5];
|
||||
ConfgPars |= is_same_addr;
|
||||
}
|
||||
}
|
||||
/* printf("ConfgPars%x\n",ConfgPars); */
|
||||
return ConfgPars;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* hw_fft_run
|
||||
* Description: fft/ifft运算函数
|
||||
* Arguments :fft_config FFT运算配置寄存器值
|
||||
in 输入数据地址(满足4byte对其,以及非const类型)
|
||||
out 输出数据地址
|
||||
* Return : void
|
||||
* Note(s) : None.
|
||||
*********************************************************************/
|
||||
void hw_fft_run(unsigned int fft_config, const int *in, int *out)
|
||||
{
|
||||
pi32v2_hw_fft_ctx ctx;
|
||||
ctx.fft_config = fft_config;
|
||||
ctx.in = in;
|
||||
ctx.out = out;
|
||||
hw_fft_wrap(&ctx);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// VECTOR
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
unsigned long vector_con;
|
||||
unsigned long vector_xadr;
|
||||
unsigned long vector_yadr;
|
||||
unsigned long vector_zadr;
|
||||
unsigned long vector_config0;
|
||||
unsigned long vector_config1;
|
||||
unsigned long vector_config2;
|
||||
unsigned long null;
|
||||
} hwvec_ctx_t;
|
||||
|
||||
static hwvec_ctx_t g_vector_core_set __attribute__((aligned(16)));
|
||||
|
||||
//__attribute__ ((always_inline)) inline
|
||||
void hwvec_exec(
|
||||
void *xptr,
|
||||
void *yptr,
|
||||
void *zptr,
|
||||
short x_inc,
|
||||
short y_inc,
|
||||
short z_inc,
|
||||
short nlen,
|
||||
short nloop,
|
||||
char q,
|
||||
long config,
|
||||
long const_dat
|
||||
)
|
||||
{
|
||||
|
||||
if (fft_init == 0) {
|
||||
fft_init = 1;
|
||||
FFT_CRITICAL_INIT();
|
||||
}
|
||||
|
||||
FFT_ENTER_CRITICAL();
|
||||
|
||||
g_vector_core_set.vector_con = config;
|
||||
g_vector_core_set.vector_config0 = (q << 24) | (nloop << 12) | (nlen);
|
||||
g_vector_core_set.vector_config1 = (z_inc << 20) | (y_inc << 10) | x_inc;
|
||||
//printf("nlen0:%d,nloop:%d,q:%d,config:%d,%d\n",nlen,nloop,q,config,const_dat);
|
||||
|
||||
g_vector_core_set.vector_xadr = (unsigned long)xptr;
|
||||
g_vector_core_set.vector_yadr = (unsigned long)yptr;
|
||||
g_vector_core_set.vector_zadr = (unsigned long)zptr;
|
||||
|
||||
JL_FFT->CONST = const_dat;
|
||||
|
||||
JL_FFT->CADR = (unsigned long)(&g_vector_core_set);
|
||||
|
||||
|
||||
// nu clr vector ie en
|
||||
JL_FFT->CON = (1 << 8) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 0);
|
||||
|
||||
|
||||
lp_waiting((int *)&JL_FFT->CON, BIT(7), BIT(6), 116);
|
||||
|
||||
FFT_EXIT_CRITICAL();
|
||||
}
|
||||
|
||||
u8 fft_wrap_for_ldac_enable(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _FFT_wrap_(int cfg, int *in, int *out)
|
||||
{
|
||||
//init pi32v2 fft hardware
|
||||
pi32v2_hw_fft_ctx ctx;
|
||||
if (in == out) {
|
||||
cfg |= 1;
|
||||
}
|
||||
|
||||
ctx.fft_config = cfg;
|
||||
ctx.in = in;
|
||||
ctx.out = out;
|
||||
hw_fft_wrap(&ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
343
cpu/br28/icsd_anc_user.c
Normal file
343
cpu/br28/icsd_anc_user.c
Normal file
@ -0,0 +1,343 @@
|
||||
#include "app_config.h"
|
||||
#include "icsd_anc_user.h"
|
||||
#include "audio_codec_clock.h"
|
||||
#include "asm/clock.h"
|
||||
#include "audio_enc.h"
|
||||
#include "asm/audio_adc.h"
|
||||
#include "tone_player.h"
|
||||
#include "avctp_user.h"
|
||||
#include "asm/audio_src_base.h"
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
#include "bt_tws.h"
|
||||
#endif
|
||||
#include "app_main.h"
|
||||
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
#include "audio_anc.h"
|
||||
|
||||
struct audio_mic_hdl {
|
||||
struct audio_adc_output_hdl adc_output;
|
||||
struct adc_mic_ch mic_ch;
|
||||
s16 *adc_buf; //align 2Bytes
|
||||
u16 dump_packet;
|
||||
};
|
||||
static struct audio_mic_hdl *audio_mic = NULL;
|
||||
extern struct audio_dac_hdl dac_hdl;
|
||||
extern struct audio_adc_hdl adc_hdl;
|
||||
extern s16 esco_adc_buf[]; //align 2Bytes
|
||||
extern void tws_tx_unsniff_req(void);
|
||||
extern void tws_tx_sniff_req(void);
|
||||
extern void set_tws_t_sniff(u16 slot);
|
||||
extern void bt_sniff_set_enable(u8 en);
|
||||
|
||||
int audio_mic_en(u8 en, audio_mic_param_t *mic_param,
|
||||
void (*data_handler)(void *priv, s16 *data, int len))
|
||||
{
|
||||
printf("audio_mic_en : %d", en);
|
||||
if (en) {
|
||||
if (audio_mic) {
|
||||
printf("audio_mic re-malloc error\n");
|
||||
return -1;
|
||||
}
|
||||
audio_mic = zalloc(sizeof(struct audio_mic_hdl));
|
||||
if (audio_mic == NULL) {
|
||||
printf("audio mic zalloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 mic_ch = mic_param->mic_ch_sel;
|
||||
u16 sr = mic_param->sample_rate;
|
||||
u8 gain0 = mic_param->mic0_gain;
|
||||
u8 gain1 = mic_param->mic1_gain;
|
||||
u8 gain2 = mic_param->mic2_gain;
|
||||
u8 gain3 = mic_param->mic3_gain;
|
||||
|
||||
u8 mic_num = 0;
|
||||
/*打开mic电压*/
|
||||
audio_mic_pwr_ctl(MIC_PWR_ON);
|
||||
/*打开mic0*/
|
||||
if (mic_ch & BIT(0)) {
|
||||
printf("adc_mic0 open, sr:%d, gain:%d\n", sr, gain0);
|
||||
audio_adc_mic_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic_set_gain(&audio_mic->mic_ch, gain0);
|
||||
mic_num ++;
|
||||
}
|
||||
/*打开mic1*/
|
||||
if (mic_ch & BIT(1)) {
|
||||
printf("adc_mic1 open, sr:%d, gain:%d\n", sr, gain1);
|
||||
audio_adc_mic1_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic1_set_gain(&audio_mic->mic_ch, gain1);
|
||||
mic_num ++;
|
||||
}
|
||||
/*打开mic2*/
|
||||
if (mic_ch & BIT(2)) {
|
||||
printf("adc_mic2 open, sr:%d, gain:%d\n", sr, gain2);
|
||||
audio_adc_mic2_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic2_set_gain(&audio_mic->mic_ch, gain2);
|
||||
mic_num ++;
|
||||
}
|
||||
/*打开mic3*/
|
||||
if (mic_ch & BIT(3)) {
|
||||
printf("adc_mic3 open, sr:%d, gain:%d\n", sr, gain3);
|
||||
audio_adc_mic3_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
|
||||
audio_adc_mic3_set_gain(&audio_mic->mic_ch, gain3);
|
||||
mic_num ++;
|
||||
}
|
||||
|
||||
int adc_buf_size = mic_param->adc_irq_points * 2 * mic_param->adc_buf_num * mic_num;
|
||||
printf("adc irq points %d, adc_buf_size : %d", mic_param->adc_irq_points, adc_buf_size);
|
||||
audio_mic->adc_buf = esco_adc_buf;
|
||||
/* audio_mic->adc_buf = zalloc(adc_buf_size); */
|
||||
if (audio_mic->adc_buf == NULL) {
|
||||
printf("audio->adc_buf mic zalloc failed\n");
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
free(audio_mic);
|
||||
audio_mic = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
audio_adc_mic_set_sample_rate(&audio_mic->mic_ch, sr);
|
||||
audio_adc_mic_set_buffs(&audio_mic->mic_ch, audio_mic->adc_buf,
|
||||
mic_param->adc_irq_points * 2, mic_param->adc_buf_num);
|
||||
audio_mic->adc_output.handler = data_handler;
|
||||
audio_adc_add_output_handler(&adc_hdl, &audio_mic->adc_output);
|
||||
audio_adc_mic_start(&audio_mic->mic_ch);
|
||||
} else {
|
||||
if (audio_mic) {
|
||||
/*设置fb mic为复用mic*/
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
audio_anc_mic_mana_fb_mult_set(1);
|
||||
#endif
|
||||
audio_adc_mic_close(&audio_mic->mic_ch);
|
||||
audio_adc_del_output_handler(&adc_hdl, &audio_mic->adc_output);
|
||||
if (audio_mic->adc_buf) {
|
||||
/* free(audio_mic->adc_buf); */
|
||||
}
|
||||
/*清除fb mic为复用mic的标志*/
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
audio_anc_mic_mana_fb_mult_set(0);
|
||||
if (anc_status_get() == 0)
|
||||
#endif
|
||||
{
|
||||
audio_mic_pwr_ctl(MIC_PWR_OFF);
|
||||
}
|
||||
free(audio_mic);
|
||||
audio_mic = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *tone_index_to_name(u8 index)
|
||||
{
|
||||
char *file_name = NULL;
|
||||
switch (index) {
|
||||
case ICSD_ADT_TONE_NUM0 :
|
||||
file_name = TONE_NUM_0;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM1 :
|
||||
file_name = TONE_NUM_1;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM2 :
|
||||
file_name = TONE_NUM_2;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM3 :
|
||||
file_name = TONE_NUM_3;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM4 :
|
||||
file_name = TONE_NUM_4;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM5 :
|
||||
file_name = TONE_NUM_5;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM6 :
|
||||
file_name = TONE_NUM_6;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM7 :
|
||||
file_name = TONE_NUM_7;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM8 :
|
||||
file_name = TONE_NUM_8;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NUM9 :
|
||||
file_name = TONE_NUM_9;
|
||||
break;
|
||||
case ICSD_ADT_TONE_NORMAL :
|
||||
/* file_name = (char *)get_tone_files()->normal; */
|
||||
break;
|
||||
case ICSD_ADT_TONE_SPKCHAT_ON :
|
||||
file_name = TONE_SPKCHAT_ON;
|
||||
break;
|
||||
case ICSD_ADT_TONE_SPKCHAT_OFF :
|
||||
file_name = TONE_SPKCHAT_OFF;
|
||||
break;
|
||||
case ICSD_ADT_TONE_WCLICK_ON :
|
||||
file_name = TONE_WCLICK_ON;
|
||||
break;
|
||||
case ICSD_ADT_TONE_WCLICK_OFF :
|
||||
file_name = TONE_WCLICK_OFF;
|
||||
break;
|
||||
case ICSD_ADT_TONE_WINDDET_ON :
|
||||
file_name = TONE_WINDDET_ON;
|
||||
break;
|
||||
case ICSD_ADT_TONE_WINDDET_OFF :
|
||||
file_name = TONE_WINDDET_OFF;
|
||||
break;
|
||||
}
|
||||
return file_name;
|
||||
}
|
||||
|
||||
int icsd_adt_tone_play_callback(u8 index, void (*evt_handler)(void *priv), void *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
char *file_name = tone_index_to_name(index);
|
||||
if (index == ICSD_ADT_TONE_NORMAL) {
|
||||
ret = tone_play_index_with_callback(index, 0, evt_handler, priv);
|
||||
} else {
|
||||
ret = tone_play_with_callback(file_name, 0, evt_handler, priv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int icsd_adt_tone_play(u8 index)
|
||||
{
|
||||
int ret = 0;
|
||||
char *file_name = tone_index_to_name(index);
|
||||
if (index == ICSD_ADT_TONE_NORMAL) {
|
||||
ret = tone_play_index(IDEX_TONE_NORMAL, 0);
|
||||
} else {
|
||||
ret = tone_play(file_name, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void icsd_adt_clock_add()
|
||||
{
|
||||
/* clock_refurbish(); */
|
||||
audio_codec_clock_set(SPEAK_TO_CHAT_MODE, AUDIO_CODING_PCM, 0);
|
||||
}
|
||||
|
||||
static void icsd_adt_clock_del()
|
||||
{
|
||||
audio_codec_clock_del(SPEAK_TO_CHAT_MODE);
|
||||
}
|
||||
|
||||
void icsd_set_clk()
|
||||
{
|
||||
clk_set_sys_lock(128 * (1000000L), 0);
|
||||
/* clock_alloc("icsd_adt", 128 * 1000000L); */
|
||||
}
|
||||
|
||||
static void icsd_anc_fade_set(int gain)
|
||||
{
|
||||
#if TCFG_AUDIO_ANC_ENABLE
|
||||
audio_anc_fade_ctr_set(ANC_FADE_MODE_WIND_NOISE, AUDIO_ANC_FDAE_CH_ALL, gain);
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 esco_player_runing()
|
||||
{
|
||||
return bt_phone_dec_is_running();
|
||||
}
|
||||
|
||||
u8 bt_get_call_status()
|
||||
{
|
||||
return get_call_status();
|
||||
}
|
||||
|
||||
u8 bt_a2dp_get_status()
|
||||
{
|
||||
return a2dp_get_status();
|
||||
}
|
||||
|
||||
void bt_cmd_prepare(u8 cmd, u16 param_len, u8 *param)
|
||||
{
|
||||
user_send_cmd_prepare(cmd, param_len, param);
|
||||
}
|
||||
|
||||
void *icsd_adt_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int))
|
||||
{
|
||||
void *src_hdl = audio_resample_hw_open(1, in_rate, out_rate, 1);
|
||||
audio_resample_hw_set_output_handler(src_hdl, 0, handler);
|
||||
return src_hdl;
|
||||
|
||||
/* void *src_hdl = zalloc(sizeof(struct audio_src_handle)); */
|
||||
/* audio_hw_src_open(src_hdl, 1, 1); */
|
||||
/* audio_hw_src_set_rate(src_hdl, in_rate, out_rate); */
|
||||
/* audio_src_set_output_handler(src_hdl, 0, handler); */
|
||||
/* return src_hdl; */
|
||||
}
|
||||
|
||||
void icsd_adt_src_write(void *data, int len, void *resample)
|
||||
{
|
||||
audio_resample_hw_write(resample, data, len);
|
||||
/* audio_src_resample_write(resample, data, len); */
|
||||
}
|
||||
|
||||
void icsd_adt_src_push(void *resample)
|
||||
{
|
||||
audio_resample_hw_push_data_out(resample);
|
||||
/* audio_src_push_data_out((struct audio_src_handle *)resample); */
|
||||
}
|
||||
|
||||
void icsd_adt_src_close(void *resample)
|
||||
{
|
||||
audio_resample_hw_close(resample);
|
||||
/* audio_hw_src_close(resample); */
|
||||
/* free(resample); */
|
||||
resample = NULL;
|
||||
}
|
||||
|
||||
void icsd_adt_tx_unsniff_req()
|
||||
{
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
tws_tx_unsniff_req();
|
||||
#endif
|
||||
}
|
||||
|
||||
void icsd_bt_sniff_set_enable(u8 en)
|
||||
{
|
||||
bt_sniff_set_enable(en);
|
||||
}
|
||||
|
||||
|
||||
void icsd_set_tws_t_sniff(u16 slot)
|
||||
{
|
||||
#if TCFG_USER_TWS_ENABLE
|
||||
set_tws_t_sniff(slot);
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 icsd_get_talk_mic_ch(void)
|
||||
{
|
||||
return app_var.talk_mic_ch;
|
||||
}
|
||||
|
||||
u8 icsd_get_ref_mic_ch(void)
|
||||
{
|
||||
return BIT(TCFG_AUDIO_ANCL_FF_MIC);
|
||||
}
|
||||
|
||||
u8 icsd_get_fb_mic_ch(void)
|
||||
{
|
||||
return BIT(TCFG_AUDIO_ANCL_FB_MIC);
|
||||
}
|
||||
|
||||
u8 icsd_get_esco_mic_en_map(void)
|
||||
{
|
||||
return TCFG_AUDIO_ADC_MIC_CHA;
|
||||
}
|
||||
|
||||
u8 audio_adc_file_get_esco_mic_num(void)
|
||||
{
|
||||
u8 mic_num = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (TCFG_AUDIO_ADC_MIC_CHA & BIT(i)) {
|
||||
mic_num++;
|
||||
}
|
||||
}
|
||||
return mic_num;
|
||||
}
|
||||
|
||||
#endif /*TCFG_AUDIO_ANC_ENABLE*/
|
||||
75
cpu/br28/icsd_anc_user.h
Normal file
75
cpu/br28/icsd_anc_user.h
Normal file
@ -0,0 +1,75 @@
|
||||
#ifndef _ICSD_ANC_USER_H_
|
||||
#define _ICSD_ANC_USER_H_
|
||||
|
||||
#include "typedef.h"
|
||||
// #include "esco_player.h"
|
||||
|
||||
typedef struct {
|
||||
u16 mic_ch_sel;
|
||||
u16 sample_rate;
|
||||
u16 adc_irq_points;
|
||||
u16 adc_buf_num;
|
||||
u16 mic0_gain;
|
||||
u16 mic1_gain;
|
||||
u16 mic2_gain;
|
||||
u16 mic3_gain;
|
||||
} audio_mic_param_t;
|
||||
|
||||
enum {
|
||||
ICSD_ADT_TONE_NUM0 = 0,
|
||||
ICSD_ADT_TONE_NUM1,
|
||||
ICSD_ADT_TONE_NUM2,
|
||||
ICSD_ADT_TONE_NUM3,
|
||||
ICSD_ADT_TONE_NUM4,
|
||||
ICSD_ADT_TONE_NUM5,
|
||||
ICSD_ADT_TONE_NUM6,
|
||||
ICSD_ADT_TONE_NUM7,
|
||||
ICSD_ADT_TONE_NUM8,
|
||||
ICSD_ADT_TONE_NUM9,
|
||||
|
||||
ICSD_ADT_TONE_NORMAL,
|
||||
ICSD_ADT_TONE_SPKCHAT_ON,
|
||||
ICSD_ADT_TONE_SPKCHAT_OFF,
|
||||
ICSD_ADT_TONE_WCLICK_ON,
|
||||
ICSD_ADT_TONE_WCLICK_OFF,
|
||||
ICSD_ADT_TONE_WINDDET_ON,
|
||||
ICSD_ADT_TONE_WINDDET_OFF,
|
||||
};
|
||||
|
||||
#define TCFG_AUDIO_ANCL_FF_MIC ANCL_FF_MIC
|
||||
#define TCFG_AUDIO_ANCL_FB_MIC ANCL_FB_MIC
|
||||
#define TCFG_AUDIO_ANCR_FF_MIC ANCR_FF_MIC
|
||||
#define TCFG_AUDIO_ANCR_FB_MIC ANCR_FB_MIC
|
||||
|
||||
int audio_mic_en(u8 en, audio_mic_param_t *mic_param,
|
||||
void (*data_handler)(void *priv, s16 *data, int len));
|
||||
|
||||
int icsd_adt_tone_play_callback(u8 index, void (*evt_handler)(void *priv), void *priv);
|
||||
int icsd_adt_tone_play(u8 index);
|
||||
|
||||
void icsd_adt_clock_add();
|
||||
void icsd_adt_clock_del();
|
||||
void icsd_set_clk();
|
||||
|
||||
void icsd_anc_fade_set(int gain);
|
||||
|
||||
u8 esco_player_runing();
|
||||
u8 bt_get_call_status();
|
||||
u8 bt_a2dp_get_status();
|
||||
void bt_cmd_prepare(u8 cmd, u16 param_len, u8 *param);
|
||||
|
||||
void *icsd_adt_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int));
|
||||
void icsd_adt_src_write(void *data, int len, void *resample);
|
||||
void icsd_adt_src_push(void *resample);
|
||||
void icsd_adt_src_close(void *resample);
|
||||
|
||||
void icsd_set_tws_t_sniff(u16 slot);
|
||||
void icsd_bt_sniff_set_enable(u8 en);
|
||||
void icsd_adt_tx_unsniff_req();
|
||||
|
||||
u8 icsd_get_talk_mic_ch(void);
|
||||
u8 icsd_get_ref_mic_ch(void);
|
||||
u8 icsd_get_fb_mic_ch(void);
|
||||
u8 icsd_get_esco_mic_en_map(void);
|
||||
u8 audio_adc_file_get_esco_mic_num(void);
|
||||
#endif
|
||||
366
cpu/br28/iic_hw.c
Normal file
366
cpu/br28/iic_hw.c
Normal file
@ -0,0 +1,366 @@
|
||||
#include "asm/iic_hw.h"
|
||||
#include "system/generic/gpio.h"
|
||||
#include "system/generic/log.h"
|
||||
#include "asm/clock.h"
|
||||
#include "asm/cpu.h"
|
||||
|
||||
/*
|
||||
[[ 注意!!! ]]
|
||||
* 适用于带cfg_done的硬件IIC,另一种硬件IIC另作说明
|
||||
* 硬件IIC的START / ACK(NACK)必须在发送或接收字节cfg_done前设置,且不能
|
||||
接cfg_done单独发送;而STOP则应在发送或接收字节cfg_done后设置,必须接
|
||||
cfg_done单独发送
|
||||
*/
|
||||
|
||||
static JL_IIC_TypeDef *const iic_regs[IIC_HW_NUM] = {
|
||||
JL_IIC,
|
||||
};
|
||||
|
||||
#define iic_get_id(iic) (iic)
|
||||
|
||||
#define iic_info_port(iic, x) (hw_iic_cfg[iic_get_id(iic)].port[x])
|
||||
#define iic_info_baud(iic) (hw_iic_cfg[iic_get_id(iic)].baudrate)
|
||||
#define iic_info_hdrive(iic) (hw_iic_cfg[iic_get_id(iic)].hdrive)
|
||||
#define iic_info_io_filt(iic) (hw_iic_cfg[iic_get_id(iic)].io_filter)
|
||||
#define iic_info_io_pu(iic) (hw_iic_cfg[iic_get_id(iic)].io_pu)
|
||||
#define iic_info_role(iic) (hw_iic_cfg[iic_get_id(iic)].role)
|
||||
|
||||
static inline u32 iic_get_scl(hw_iic_dev iic)
|
||||
{
|
||||
u8 port = iic_info_port(iic, 0);
|
||||
return port;
|
||||
}
|
||||
|
||||
static inline u32 iic_get_sda(hw_iic_dev iic)
|
||||
{
|
||||
u8 port = iic_info_port(iic, 1);
|
||||
return port;
|
||||
}
|
||||
|
||||
static int iic_port_init(hw_iic_dev iic)
|
||||
{
|
||||
u32 reg;
|
||||
int ret = 0;
|
||||
u8 id = iic_get_id(iic);
|
||||
u32 scl, sda;
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
if (id == 0) {
|
||||
gpio_set_fun_output_port(scl, FO_IIC_SCL, 1, 1, LOW_POWER_FREE);
|
||||
gpio_set_fun_output_port(sda, FO_IIC_SDA, 1, 1, LOW_POWER_FREE);
|
||||
gpio_set_fun_input_port(scl, PFI_IIC_SCL, LOW_POWER_FREE);
|
||||
gpio_set_fun_input_port(sda, PFI_IIC_SDA, LOW_POWER_FREE);
|
||||
if (iic_info_hdrive(iic)) {
|
||||
gpio_set_hd(scl, 1);
|
||||
gpio_set_hd(sda, 1);
|
||||
} else {
|
||||
gpio_set_hd(scl, 0);
|
||||
gpio_set_hd(sda, 0);
|
||||
}
|
||||
if (iic_info_io_pu(iic)) {
|
||||
gpio_set_pull_up(scl, 1);
|
||||
gpio_set_pull_up(sda, 1);
|
||||
} else {
|
||||
gpio_set_pull_up(scl, 0);
|
||||
gpio_set_pull_up(sda, 0);
|
||||
}
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hw_iic_set_baud(hw_iic_dev iic, u32 baud)
|
||||
{
|
||||
//f_iic = f_sys / ((IIC_BAUD + 1) * 2)
|
||||
//=> IIC_BAUD = f_sys / (2 * f_iic) - 1
|
||||
u32 sysclk;
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
sysclk = clk_get("lsb");
|
||||
if (sysclk < 2 * baud) {
|
||||
return -EINVAL;
|
||||
}
|
||||
iic_baud_reg(iic_regs[id]) = sysclk / (2 * baud) - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hw_iic_set_die(hw_iic_dev iic, u8 en)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
u32 scl, sda;
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
if (id == 0) {
|
||||
gpio_set_die(scl, en);
|
||||
gpio_set_die(sda, en);
|
||||
} else {
|
||||
//undefined
|
||||
}
|
||||
}
|
||||
|
||||
void hw_iic_suspend(hw_iic_dev iic)
|
||||
{
|
||||
hw_iic_set_die(iic, 0);
|
||||
}
|
||||
|
||||
void hw_iic_resume(hw_iic_dev iic)
|
||||
{
|
||||
hw_iic_set_die(iic, 1);
|
||||
}
|
||||
|
||||
int hw_iic_init(hw_iic_dev iic)
|
||||
{
|
||||
int ret;
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
if ((ret = iic_port_init(iic))) {
|
||||
log_e("invalid hardware iic port\n");
|
||||
return ret;
|
||||
}
|
||||
hw_iic_set_die(iic, 1);
|
||||
if (iic_info_role(iic) == IIC_MASTER) {
|
||||
iic_role_host(iic_regs[id]);
|
||||
} else {
|
||||
iic_role_slave(iic_regs[id]);
|
||||
iic_si_mode_en(iic_regs[id]);
|
||||
}
|
||||
if (iic_info_io_filt(iic)) {
|
||||
iic_isel_filter(iic_regs[id]);
|
||||
} else {
|
||||
iic_isel_direct(iic_regs[id]);
|
||||
}
|
||||
if ((ret = hw_iic_set_baud(iic, iic_info_baud(iic)))) {
|
||||
log_e("iic baudrate is invalid\n");
|
||||
return ret ;
|
||||
}
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
iic_end_pnd_clr(iic_regs[id]);
|
||||
iic_start_pnd_clr(iic_regs[id]);
|
||||
iic_enable(iic_regs[id]);
|
||||
#if 0
|
||||
printf("info->scl = %d\n", iic_get_scl(iic));
|
||||
printf("info->sda = %d\n", iic_get_sda(iic));
|
||||
printf("info->baudrate = %d\n", iic_info_baud(iic));
|
||||
printf("info->hdrive = %d\n", iic_info_hdrive(iic));
|
||||
printf("info->io_filter = %d\n", iic_info_io_filt(iic));
|
||||
printf("info->io_pu = %d\n", iic_info_io_pu(iic));
|
||||
printf("info->role = %d\n", iic_info_role(iic));
|
||||
printf("IIC_CON0 0x%04x\n", iic_regs[id]->CON0);
|
||||
printf("IIC_CON1 0x%04x\n", iic_regs[id]->CON1);
|
||||
printf("IIC_BAUD 0x%02x\n", iic_regs[id]->BAUD);
|
||||
//printf("IIC_BUF %02x\n", iic_regs[id]->BUF);
|
||||
printf("IOMC1 0x%08x\n", JL_IOMAP->CON1);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hw_iic_uninit(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
u32 scl, sda;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
hw_iic_set_die(iic, 0);
|
||||
if (id == 0) {
|
||||
gpio_set_hd(scl, 0);
|
||||
gpio_set_hd(sda, 0);
|
||||
gpio_set_pull_up(scl, 0);
|
||||
gpio_set_pull_up(sda, 0);
|
||||
}
|
||||
iic_disable(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_start(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
iic_preset_restart(iic_regs[id]);
|
||||
//don't add iic_cfg_done() here, it must be used with send byte
|
||||
}
|
||||
|
||||
void hw_iic_stop(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
iic_preset_end(iic_regs[id]);
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
}
|
||||
|
||||
u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
iic_dir_out(iic_regs[id]);
|
||||
iic_buf_reg(iic_regs[id]) = byte;
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
/* putchar('a'); */
|
||||
while (!iic_pnd(iic_regs[id]));
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
/* putchar('b'); */
|
||||
return iic_send_is_ack(iic_regs[id]);
|
||||
}
|
||||
|
||||
u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
iic_dir_in(iic_regs[id]);
|
||||
if (ack) {
|
||||
iic_recv_ack(iic_regs[id]);
|
||||
} else {
|
||||
iic_recv_nack(iic_regs[id]);
|
||||
}
|
||||
iic_buf_reg(iic_regs[id]) = 0xff;
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
/* putchar('c'); */
|
||||
while (!iic_pnd(iic_regs[id]));
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
/* putchar('d'); */
|
||||
return iic_buf_reg(iic_regs[id]);
|
||||
}
|
||||
|
||||
int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
int i;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
iic_dir_in(iic_regs[id]);
|
||||
iic_recv_ack(iic_regs[id]);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i == len - 1) {
|
||||
iic_recv_nack(iic_regs[id]);
|
||||
}
|
||||
iic_buf_reg(iic_regs[id]) = 0xff;
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
while (!iic_pnd(iic_regs[id]));
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
((u8 *)buf)[i] = iic_buf_reg(iic_regs[id]);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
int i = 0;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
iic_dir_out(iic_regs[id]);
|
||||
for (i = 0; i < len; i++) {
|
||||
iic_buf_reg(iic_regs[id]) = ((u8 *)buf)[i];
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
while (!iic_pnd(iic_regs[id]));
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
if (!iic_send_is_ack(iic_regs[id])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void hw_iic_set_ie(hw_iic_dev iic, u8 en)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
if (en) {
|
||||
iic_set_ie(iic_regs[id]);
|
||||
} else {
|
||||
iic_clr_ie(iic_regs[id]);
|
||||
}
|
||||
}
|
||||
|
||||
u8 hw_iic_get_pnd(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
return !!iic_pnd(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_clr_pnd(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
iic_pnd_clr(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_set_end_ie(hw_iic_dev iic, u8 en)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
if (en) {
|
||||
iic_set_end_ie(iic_regs[id]);
|
||||
} else {
|
||||
iic_clr_end_ie(iic_regs[id]);
|
||||
}
|
||||
}
|
||||
|
||||
u8 hw_iic_get_end_pnd(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
return !!iic_end_pnd(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_clr_end_pnd(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
iic_end_pnd_clr(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_slave_set_addr(hw_iic_dev iic, u8 addr, u8 addr_ack)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
iic_baud_reg(iic_regs[id]) = (addr & 0xfe) | !!addr_ack;
|
||||
}
|
||||
|
||||
void hw_iic_slave_rx_prepare(hw_iic_dev iic, u8 ack)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
iic_dir_in(iic_regs[id]);
|
||||
if (ack) {
|
||||
iic_recv_ack(iic_regs[id]);
|
||||
} else {
|
||||
iic_recv_nack(iic_regs[id]);
|
||||
}
|
||||
iic_buf_reg(iic_regs[id]) = 0xff;
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
}
|
||||
|
||||
u8 hw_iic_slave_rx_byte(hw_iic_dev iic, bool *is_start_addr)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
if (iic_start_pnd(iic_regs[id])) {
|
||||
iic_start_pnd_clr(iic_regs[id]);
|
||||
is_start_addr ? (*is_start_addr = 1) : 0;
|
||||
} else {
|
||||
is_start_addr ? (*is_start_addr = 0) : 0;
|
||||
}
|
||||
return iic_buf_reg(iic_regs[id]);
|
||||
}
|
||||
|
||||
void hw_iic_slave_tx_byte(hw_iic_dev iic, u8 byte)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
iic_dir_out(iic_regs[id]);
|
||||
iic_buf_reg(iic_regs[id]) = byte;
|
||||
iic_cfg_done(iic_regs[id]);
|
||||
}
|
||||
|
||||
u8 hw_iic_slave_tx_check_ack(hw_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
|
||||
return iic_send_is_ack(iic_regs[id]);
|
||||
}
|
||||
void iic_disable_for_ota()
|
||||
{
|
||||
JL_IIC->CON0 = 0;
|
||||
}
|
||||
|
||||
345
cpu/br28/iic_soft.c
Normal file
345
cpu/br28/iic_soft.c
Normal file
@ -0,0 +1,345 @@
|
||||
|
||||
//#include "system/init.h"
|
||||
#include "asm/iic_soft.h"
|
||||
#include "generic/gpio.h"
|
||||
|
||||
#define IIC_SCL_DIR(scl, val) \
|
||||
gpio_set_direction(scl, val)
|
||||
|
||||
#define IIC_SCL_SET_PU(scl, on) \
|
||||
gpio_set_pull_up(scl, on)
|
||||
|
||||
#define IIC_SCL_SET_PD(scl, on) \
|
||||
gpio_set_pull_down(scl, on)
|
||||
|
||||
#define IIC_SCL_SET_DIE(scl, on) \
|
||||
gpio_set_die(scl, on)
|
||||
|
||||
#define IIC_SCL_H(scl) \
|
||||
gpio_set_direction(scl, 1)
|
||||
|
||||
#define IIC_SCL_L(scl) \
|
||||
gpio_direction_output(scl, 0)
|
||||
|
||||
#define IIC_SDA_DIR(sda, val) \
|
||||
gpio_set_direction(sda, val)
|
||||
|
||||
#define IIC_SDA_SET_PU(sda, on) \
|
||||
gpio_set_pull_up(sda, on)
|
||||
|
||||
#define IIC_SDA_SET_PD(sda, on) \
|
||||
gpio_set_pull_down(sda, on)
|
||||
|
||||
#define IIC_SDA_SET_DIE(sda, on) \
|
||||
gpio_set_die(sda, on)
|
||||
|
||||
#define IIC_SDA_H(sda) \
|
||||
gpio_set_direction(sda, 1)
|
||||
|
||||
#define IIC_SDA_L(sda) \
|
||||
gpio_direction_output(sda, 0)
|
||||
|
||||
#define IIC_SDA_READ(sda) \
|
||||
gpio_read(sda)
|
||||
|
||||
#define iic_get_id(iic) (iic)
|
||||
|
||||
static inline u32 iic_get_scl(soft_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
return soft_iic_cfg[id].scl;
|
||||
}
|
||||
|
||||
static inline u32 iic_get_sda(soft_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
return soft_iic_cfg[id].sda;
|
||||
}
|
||||
|
||||
static inline u32 iic_get_delay(soft_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
return soft_iic_cfg[id].delay;
|
||||
/* return soft_iic_real_delay[id]; */
|
||||
}
|
||||
|
||||
static inline u32 iic_get_io_pu(soft_iic_dev iic)
|
||||
{
|
||||
u8 id = iic_get_id(iic);
|
||||
return soft_iic_cfg[id].io_pu;
|
||||
}
|
||||
|
||||
|
||||
int soft_iic_init(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
|
||||
if (iic_get_io_pu(iic)) {
|
||||
IIC_SCL_SET_PU(scl, 1);
|
||||
IIC_SDA_SET_PU(sda, 1);
|
||||
} else {
|
||||
IIC_SCL_SET_PU(scl, 0);
|
||||
IIC_SDA_SET_PU(sda, 0);
|
||||
}
|
||||
|
||||
gpio_set_hd(scl, 0);
|
||||
gpio_set_hd0(scl, 1);
|
||||
gpio_set_hd(sda, 0);
|
||||
gpio_set_hd0(sda, 1);
|
||||
IIC_SDA_H(sda);
|
||||
IIC_SCL_H(scl);
|
||||
IIC_SCL_SET_PD(scl, 0);
|
||||
IIC_SCL_SET_DIE(scl, 1);
|
||||
IIC_SDA_SET_PD(sda, 0);
|
||||
IIC_SDA_SET_DIE(sda, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void soft_iic_uninit(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
|
||||
IIC_SCL_DIR(scl, 1);
|
||||
IIC_SCL_SET_PU(scl, 0);
|
||||
IIC_SCL_SET_PD(scl, 0);
|
||||
IIC_SCL_SET_DIE(scl, 0);
|
||||
gpio_set_hd(scl, 0);
|
||||
gpio_set_hd0(scl, 0);
|
||||
|
||||
IIC_SDA_DIR(sda, 1);
|
||||
IIC_SDA_SET_PU(sda, 0);
|
||||
IIC_SDA_SET_PD(sda, 0);
|
||||
IIC_SDA_SET_DIE(sda, 0);
|
||||
gpio_set_hd(sda, 0);
|
||||
gpio_set_hd0(sda, 0);
|
||||
}
|
||||
|
||||
void soft_iic_suspend(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
|
||||
IIC_SCL_SET_DIE(scl, 0);
|
||||
IIC_SDA_SET_DIE(sda, 0);
|
||||
}
|
||||
|
||||
void soft_iic_resume(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
|
||||
IIC_SCL_SET_DIE(scl, 1);
|
||||
IIC_SDA_SET_DIE(sda, 1);
|
||||
}
|
||||
|
||||
void soft_iic_start(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_H(sda);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t * 2);
|
||||
|
||||
IIC_SDA_L(sda);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
}
|
||||
|
||||
void soft_iic_stop(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_L(sda);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t * 2);
|
||||
|
||||
IIC_SDA_H(sda);
|
||||
delay(dly_t);
|
||||
}
|
||||
|
||||
static u8 soft_iic_check_ack(soft_iic_dev iic)
|
||||
{
|
||||
u8 ack;
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_DIR(sda, 1);
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t);
|
||||
|
||||
if (IIC_SDA_READ(sda) == 0) {
|
||||
ack = 1;
|
||||
} else {
|
||||
ack = 0;
|
||||
}
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
IIC_SDA_DIR(sda, 0);
|
||||
IIC_SDA_L(sda);
|
||||
|
||||
return ack;
|
||||
}
|
||||
|
||||
static void soft_iic_rx_ack(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_L(sda);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
}
|
||||
|
||||
static void soft_iic_rx_nack(soft_iic_dev iic)
|
||||
{
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_H(sda);
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
}
|
||||
|
||||
u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte)
|
||||
{
|
||||
u8 i, ret;
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
for (i = 0; i < 8; i++) { //MSB FIRST
|
||||
if ((byte << i) & 0x80) {
|
||||
IIC_SDA_H(sda);
|
||||
} else {
|
||||
IIC_SDA_L(sda);
|
||||
}
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
}
|
||||
return soft_iic_check_ack(iic);
|
||||
}
|
||||
|
||||
u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack)
|
||||
{
|
||||
u8 byte = 0, i;
|
||||
u32 scl, sda, dly_t;
|
||||
|
||||
scl = iic_get_scl(iic);
|
||||
sda = iic_get_sda(iic);
|
||||
dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_DIR(sda, 1);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_H(scl);
|
||||
delay(dly_t);
|
||||
|
||||
byte = byte << 1;
|
||||
if (IIC_SDA_READ(sda)) {
|
||||
byte |= 1;
|
||||
}
|
||||
delay(dly_t);
|
||||
|
||||
IIC_SCL_L(scl);
|
||||
delay(dly_t);
|
||||
}
|
||||
|
||||
IIC_SDA_DIR(sda, 0);
|
||||
if (ack) {
|
||||
soft_iic_rx_ack(iic);
|
||||
} else {
|
||||
soft_iic_rx_nack(iic);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
|
||||
int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
((u8 *)buf)[i] = soft_iic_rx_byte(iic, 1);
|
||||
}
|
||||
((u8 *)buf)[len - 1] = soft_iic_rx_byte(iic, 0);
|
||||
return len;
|
||||
}
|
||||
|
||||
int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len)
|
||||
{
|
||||
int i;
|
||||
u8 ack;
|
||||
|
||||
if (!buf || !len) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
ack = soft_iic_tx_byte(iic, ((u8 *)buf)[i]);
|
||||
if (ack == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
234
cpu/br28/irflt.c
Normal file
234
cpu/br28/irflt.c
Normal file
@ -0,0 +1,234 @@
|
||||
#include "asm/includes.h"
|
||||
#include "asm/irflt.h"
|
||||
#include "timer.h"
|
||||
#include "generic/gpio.h"
|
||||
|
||||
#define ir_log printf
|
||||
|
||||
//红外定时器定义
|
||||
#define IR_TIMER TIMER5
|
||||
#define IR_IRQ_TIME_IDX IRQ_TIME5_IDX
|
||||
#define IR_TIME_REG JL_TIMER5
|
||||
|
||||
#define USE_IRFLT_OUT 1
|
||||
|
||||
IR_CODE ir_code; ///<红外遥控信息
|
||||
|
||||
static u8 cmp_start = 0;
|
||||
|
||||
static const u16 timer_div[] = {
|
||||
/*0000*/ 1,
|
||||
/*0001*/ 4,
|
||||
/*0010*/ 16,
|
||||
/*0011*/ 64,
|
||||
/*0100*/ 2,
|
||||
/*0101*/ 8,
|
||||
/*0110*/ 32,
|
||||
/*0111*/ 128,
|
||||
/*1000*/ 256,
|
||||
/*1001*/ 4 * 256,
|
||||
/*1010*/ 16 * 256,
|
||||
/*1011*/ 64 * 256,
|
||||
/*1100*/ 2 * 256,
|
||||
/*1101*/ 8 * 256,
|
||||
/*1110*/ 32 * 256,
|
||||
/*1111*/ 128 * 256,
|
||||
};
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief time1红外中断服务函数
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void timer1_ir_isr(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
___interrupt
|
||||
void timer_ir_isr(void)
|
||||
{
|
||||
IR_TIME_REG->CON |= BIT(14);
|
||||
u16 bCap1 = IR_TIME_REG->PRD;
|
||||
IR_TIME_REG->CNT = 0;
|
||||
u8 cap = bCap1 / ir_code.timer_pad;
|
||||
|
||||
ir_code.boverflow = 0;
|
||||
|
||||
if (cmp_start < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* putchar('0' + (cap/10)); */
|
||||
/* putchar('0' + (cap%10)); */
|
||||
|
||||
if (cap <= 1) {
|
||||
ir_code.wData >>= 1;
|
||||
ir_code.bState++;
|
||||
} else if (cap == 2) {
|
||||
ir_code.wData >>= 1;
|
||||
ir_code.wData |= 0x8000;
|
||||
ir_code.bState++;
|
||||
}
|
||||
|
||||
if (ir_code.bState == 16) {
|
||||
ir_code.wUserCode = ir_code.wData;
|
||||
}
|
||||
if (ir_code.bState == 33) {
|
||||
ir_code.bState = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief ir按键初始化
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void set_ir_clk(void)
|
||||
|
||||
((cnt - 1)* 分频数)/lsb_clk = 1ms
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
#define TIMER_UNIT_MS 1
|
||||
#define MAX_TIME_CNT 0x07ff //分频准确范围,更具实际情况调整
|
||||
#define MIN_TIME_CNT 0x0030
|
||||
void set_ir_clk(void)
|
||||
{
|
||||
u32 prd_cnt;
|
||||
u8 index;
|
||||
u32 app_timer_clk = 24000000;
|
||||
|
||||
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
|
||||
prd_cnt = TIMER_UNIT_MS * (app_timer_clk / 1000) / timer_div[index];
|
||||
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ir_code.timer_pad = prd_cnt;
|
||||
cmp_start = 0;
|
||||
if (IR_IRQ_TIME_IDX == IRQ_TIME3_IDX) {
|
||||
bit_clr_ie(IRQ_TIME3_IDX);
|
||||
}
|
||||
request_irq(IR_IRQ_TIME_IDX, 5, timer_ir_isr, 0);
|
||||
#if USE_IRFLT_OUT
|
||||
IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(2) | BIT(1) | BIT(0));
|
||||
#else
|
||||
IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(1) | BIT(0));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/**@brief 获取ir按键值
|
||||
@param void
|
||||
@param void
|
||||
@return void
|
||||
@note void get_irkey_value(void)
|
||||
*/
|
||||
/*----------------------------------------------------------------------------*/
|
||||
u8 get_irflt_value(void)
|
||||
{
|
||||
u8 tkey = 0xff;
|
||||
if (ir_code.bState != 32) {
|
||||
return tkey;
|
||||
}
|
||||
if ((((u8 *)&ir_code.wData)[0] ^ ((u8 *)&ir_code.wData)[1]) == 0xff) {
|
||||
tkey = (u8)ir_code.wData;
|
||||
} else {
|
||||
ir_code.bState = 0;
|
||||
}
|
||||
return tkey;
|
||||
}
|
||||
|
||||
static u8 ir_io_level = 0;
|
||||
static u8 ir_io = 0;
|
||||
void ir_input_io_sel(u8 port)
|
||||
{
|
||||
ir_io = port;
|
||||
#if USE_IRFLT_OUT
|
||||
gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_IRFLT, INPUT_CH_TYPE_GP_ICH);
|
||||
#else
|
||||
gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_TIMER0_CAPTURE + 2 * IR_TIMER, INPUT_CH_TYPE_GP_ICH);
|
||||
#endif
|
||||
gpio_set_direction(port, 1);
|
||||
gpio_set_die(port, 1);
|
||||
gpio_set_pull_up(port, 1);
|
||||
gpio_set_pull_down(port, 0);
|
||||
}
|
||||
|
||||
void ir_output_timer_sel()
|
||||
{
|
||||
}
|
||||
|
||||
static void ir_timeout(void *priv)
|
||||
{
|
||||
ir_code.boverflow++;
|
||||
if (ir_code.boverflow > 56) { //56*2ms ~= 112ms
|
||||
ir_code.boverflow = 56;
|
||||
ir_code.bState = 0;
|
||||
}
|
||||
cmp_start ++;
|
||||
if (cmp_start > 3) {
|
||||
cmp_start = 3;
|
||||
}
|
||||
}
|
||||
|
||||
void ir_timeout_set(void)
|
||||
{
|
||||
sys_s_hi_timer_add(NULL, ir_timeout, 2); //2ms
|
||||
}
|
||||
|
||||
static u8 ir_io_sus = 0;
|
||||
u8 ir_io_suspend(void)
|
||||
{
|
||||
if (ir_io_sus) {
|
||||
return 1;
|
||||
}
|
||||
if (ir_code.boverflow < 7) { //14ms内,红外接收有可能在忙碌
|
||||
return 1;
|
||||
}
|
||||
ir_io_level = gpio_read(ir_io);
|
||||
IR_TIME_REG->CON |= BIT(14);
|
||||
IR_TIME_REG->CON &= ~(0b11 << 0);
|
||||
ir_io_sus = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 ir_io_resume(void)
|
||||
{
|
||||
if (!ir_io_sus) {
|
||||
return 0;
|
||||
}
|
||||
ir_io_sus = 0;
|
||||
gpio_set_direction(ir_io, 1);
|
||||
gpio_set_die(ir_io, 1);
|
||||
gpio_set_pull_up(ir_io, 1);
|
||||
gpio_set_pull_down(ir_io, 0);
|
||||
delay(10);
|
||||
if ((ir_io_level) && (ir_io_level != (gpio_read(ir_io)))) {
|
||||
ir_code.boverflow = 0;
|
||||
}
|
||||
cmp_start = 0;
|
||||
IR_TIME_REG->CNT = 0;
|
||||
IR_TIME_REG->CON |= BIT(14);
|
||||
IR_TIME_REG->CON |= (0b11 << 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void irflt_config()
|
||||
{
|
||||
JL_IR->RFLT_CON = 0;
|
||||
/* JL_IR->RFLT_CON |= BIT(7); //256 div */
|
||||
/* JL_IR->RFLT_CON |= BIT(3); //osc 24m */
|
||||
JL_IR->RFLT_CON |= BIT(7) | BIT(4); //512 div
|
||||
JL_IR->RFLT_CON |= BIT(3) | BIT(2); //PLL_48m(兼容省晶振)
|
||||
JL_IR->RFLT_CON |= BIT(0); //irflt enable
|
||||
|
||||
set_ir_clk();
|
||||
}
|
||||
|
||||
void log_irflt_info()
|
||||
{
|
||||
ir_log("RFLT_CON = 0x%x", JL_IR->RFLT_CON);
|
||||
ir_log("IR_TIME_REG = 0x%x", IR_TIME_REG->CON);
|
||||
}
|
||||
|
||||
BIN
cpu/br28/liba/SensorCalib.a
Normal file
BIN
cpu/br28/liba/SensorCalib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/SpatialAudio.a
Normal file
BIN
cpu/br28/liba/SpatialAudio.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/VirtualBass.a
Normal file
BIN
cpu/br28/liba/VirtualBass.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/aac_dec_lib.a
Normal file
BIN
cpu/br28/liba/aac_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/aec.a
Normal file
BIN
cpu/br28/liba/aec.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/agreement.a
Normal file
BIN
cpu/br28/liba/agreement.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/amr_dec_lib.a
Normal file
BIN
cpu/br28/liba/amr_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/ape_dec_lib.a
Normal file
BIN
cpu/br28/liba/ape_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/bfilterfun_lib.a
Normal file
BIN
cpu/br28/liba/bfilterfun_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/bt_hash_enc.a
Normal file
BIN
cpu/br28/liba/bt_hash_enc.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/btctrler.a
Normal file
BIN
cpu/br28/liba/btctrler.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/btstack.a
Normal file
BIN
cpu/br28/liba/btstack.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/compressor.a
Normal file
BIN
cpu/br28/liba/compressor.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/cpu.a
Normal file
BIN
cpu/br28/liba/cpu.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/crossover_coff_old.a
Normal file
BIN
cpu/br28/liba/crossover_coff_old.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/crypto_toolbox_Osize.a
Normal file
BIN
cpu/br28/liba/crypto_toolbox_Osize.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/drc.a
Normal file
BIN
cpu/br28/liba/drc.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/dts_dec_lib.a
Normal file
BIN
cpu/br28/liba/dts_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/flac_dec_lib.a
Normal file
BIN
cpu/br28/liba/flac_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/google_fps.a
Normal file
BIN
cpu/br28/liba/google_fps.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/howling.a
Normal file
BIN
cpu/br28/liba/howling.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/lc3_codec_lib.a
Normal file
BIN
cpu/br28/liba/lc3_codec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/ldac_dec_lib.a
Normal file
BIN
cpu/br28/liba/ldac_dec_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/lfaudio_plc_lib.a
Normal file
BIN
cpu/br28/liba/lfaudio_plc_lib.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libAdaptiveEchoSuppress_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libAptFilt_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libAptFilt_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libDelayEstimate_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libDualMicSystem_flexible_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libDualMicSystem_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libEchoSuppress_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libFFT_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libFFT_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libNoiseSuppress_pi32v2_OnChip.a
Normal file
Binary file not shown.
BIN
cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a
Normal file
BIN
cpu/br28/liba/libOpcore_maskrom_pi32v2_OnChip.a
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user