Initial import
This commit is contained in:
+2871
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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_*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 (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
|
||||
@@ -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 0
|
||||
#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 0 //通话丢包修复
|
||||
#define TCFG_AEC_ENABLE 0 //通话回音消除使能
|
||||
#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 (10) // 具体数值应小于联合音量等级的数组大小 (combined_vol_list)
|
||||
#define MAX_DIG_VOL (10)
|
||||
|
||||
/*
|
||||
数字音量等级表生成参数(软件数字音量和硬件数字音量共用两个参数)
|
||||
修改 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 0
|
||||
#define SYS_DEFAULT_SIN_VOL 0
|
||||
|
||||
#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_*/
|
||||
@@ -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*/
|
||||
|
||||
@@ -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_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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*/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __AUDIO_DEC_IIS_H
|
||||
#define __AUDIO_DEC_IIS_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_*/
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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