This commit is contained in:
lmx
2025-10-29 13:10:02 +08:00
commit 49a07fa419
2284 changed files with 642060 additions and 0 deletions

2871
cpu/br28/a2dp_dec.c Normal file

File diff suppressed because it is too large Load Diff

680
cpu/br28/adc_api.c Normal file
View File

@ -0,0 +1,680 @@
#include "typedef.h"
#include "asm/clock.h"
#include "asm/adc_api.h"
#include "timer.h"
#include "init.h"
#include "asm/efuse.h"
#include "irq.h"
#include "asm/power/p33.h"
#include "asm/power/p11.h"
#include "asm/power_interface.h"
#include "jiffies.h"
u32 adc_sample(u32 ch);
static volatile u16 _adc_res;
static volatile u16 cur_ch_value;
static u8 cur_ch = 0;
struct adc_info_t {
u32 ch;
u16 value;
u32 jiffies;
u32 sample_period;
};
#define ENABLE_OCCUPY_MODE 1
static struct adc_info_t adc_queue[ADC_MAX_CH + ENABLE_OCCUPY_MODE];
static u8 adc_sample_flag = 0;
static u16 dtemp_voltage = 0;
#define ADC_SRC_CLK clk_get("adc")
/*config adc clk according to sys_clk*/
static const u32 sys2adc_clk_info[] = {
128000000L,
96000000L,
72000000L,
48000000L,
24000000L,
12000000L,
6000000L,
1000000L,
};
u32 adc_add_sample_ch(u32 ch)
{
u32 i = 0;
for (i = 0; i < ADC_MAX_CH; i++) {
/* printf("%s() %d %x %x\n", __func__, i, ch, adc_queue[i].ch); */
if (adc_queue[i].ch == ch) {
break;
} else if (adc_queue[i].ch == -1) {
adc_queue[i].ch = ch;
adc_queue[i].value = 1;
adc_queue[i].jiffies = 0;
adc_queue[i].sample_period = msecs_to_jiffies(0);
printf("add sample ch %x\n", ch);
break;
}
}
return i;
}
u32 adc_set_sample_freq(u32 ch, u32 ms)
{
u32 i;
for (i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
adc_queue[i].sample_period = msecs_to_jiffies(ms);
adc_queue[i].jiffies = msecs_to_jiffies(ms) + jiffies;
break;
}
}
return i;
}
u32 adc_remove_sample_ch(u32 ch)
{
u32 i = 0;
for (i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
adc_queue[i].ch = -1;
break;
}
}
return i;
}
static u32 adc_get_next_ch(u32 cur_ch)
{
for (int i = cur_ch + 1; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch != -1) {
return i;
}
}
return 0;
}
#define PMU_CH_SAMPLE_FREQ 500 //ms
#define PMU_CH_VALUE_ARRAY_SIZE (16 + 1)
static u16 vbat_value_array[PMU_CH_VALUE_ARRAY_SIZE];
static u16 vbg_value_array[PMU_CH_VALUE_ARRAY_SIZE];
static void adc_value_push(u16 *array, u16 adc_value)
{
u16 pos = array[0];
pos++;
if (pos >= PMU_CH_VALUE_ARRAY_SIZE) {
pos = 1;
}
array[pos] = adc_value;
array[0] = pos;
}
static u16 adc_value_avg(u16 *array)
{
u32 i, j, sum = 0;
for (i = 1, j = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
if (array[i]) {
sum += array[i];
j += 1;
}
}
if (sum) {
return (sum / j);
}
return 1;
}
static void adc_value_array_reset(u16 *array)
{
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i++) {
array[i] = 0;
}
}
u32 adc_get_value(u32 ch)
{
if (ch == AD_CH_VBAT) {
return adc_value_avg(vbat_value_array);
} else if (ch == AD_CH_LDOREF) {
return adc_value_avg(vbg_value_array);
}
for (int i = 0; i < ADC_MAX_CH; i++) {
if (adc_queue[i].ch == ch) {
return adc_queue[i].value;
}
}
return 1;
}
#define VBG_CENTER 801
#define VBG_RES 3
u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
{
u32 adc_res = adc_ch_val;
u32 adc_trim = get_vbg_trim();
u32 tmp, tmp1;
tmp1 = adc_trim & 0x0f;
tmp = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
/* printf("adc_res %d mv vbg:%d adc:%d adc_trim:%x\n", adc_res, adc_vbg, adc_ch_val, adc_trim); */
if (adc_vbg == 0) {
adc_vbg = 1; //防止div0异常
}
adc_res = adc_res * tmp / adc_vbg;
return adc_res;
}
u32 adc_get_voltage(u32 ch)
{
#ifdef CONFIG_FPGA_ENABLE
return 1000;
#endif
if (ch == AD_CH_DTEMP) {
return dtemp_voltage;
}
u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
u32 adc_res = adc_get_value(ch);
return adc_value_to_voltage(adc_vbg, adc_res);
}
u32 adc_check_vbat_lowpower()
{
return 0;
}
void adc_audio_ch_select(u32 ch)
{
SFR(JL_ADDA->ADDA_CON1, 1, 1, 1);
SFR(JL_ADDA->ADDA_CON0, 0, 12, 0);
switch (ch << 16) {
case AD_AUDIO_VADADC:
SFR(JL_ADDA->ADDA_CON0, 12, 1, 1);
break;
case AD_AUDIO_VCM:
SFR(JL_ADDA->ADDA_CON0, 11, 1, 1);
break;
case AD_AUDIO_VBGLDO:
SFR(JL_ADDA->ADDA_CON0, 10, 1, 1);
break;
case AD_AUDIO_HPVDD:
SFR(JL_ADDA->ADDA_CON0, 9, 1, 1);
break;
case AD_AUDIO_RN:
SFR(JL_ADDA->ADDA_CON0, 4, 1, 1);
break;
case AD_AUDIO_RP:
SFR(JL_ADDA->ADDA_CON0, 3, 1, 1);
break;
case AD_AUDIO_LN:
SFR(JL_ADDA->ADDA_CON0, 2, 1, 1);
break;
case AD_AUDIO_LP:
SFR(JL_ADDA->ADDA_CON0, 1, 1, 1);
break;
case AD_AUDIO_DACVDD:
SFR(JL_ADDA->ADDA_CON0, 0, 1, 1);
break;
default:
break;
}
}
void adc_close()
{
JL_ADC->CON = 0;
JL_ADC->CON = 0;
}
void adc_suspend()
{
JL_ADC->CON &= ~BIT(4);
}
void adc_resume()
{
JL_ADC->CON |= BIT(4);
}
void adc_enter_occupy_mode(u32 ch)
{
if (JL_ADC->CON & BIT(4)) {
return;
}
adc_queue[ADC_MAX_CH].ch = ch;
cur_ch_value = adc_sample(ch);
}
void adc_exit_occupy_mode()
{
adc_queue[ADC_MAX_CH].ch = -1;
}
u32 adc_occupy_run()
{
if (adc_queue[ADC_MAX_CH].ch != -1) {
while (1) {
asm volatile("idle");//wait isr
if (_adc_res != (u16) - 1) {
break;
}
}
if (_adc_res == 0) {
_adc_res ++;
}
adc_queue[ADC_MAX_CH].value = _adc_res;
_adc_res = cur_ch_value;
return adc_queue[ADC_MAX_CH].value;
}
return 0;
}
u32 adc_get_occupy_value()
{
if (adc_queue[ADC_MAX_CH].ch != -1) {
return adc_queue[ADC_MAX_CH].value;
}
return 0;
}
u32 get_adc_div(u32 src_clk)
{
u32 adc_clk;
u32 adc_clk_idx;
u32 cnt;
adc_clk = src_clk;
cnt = ARRAY_SIZE(sys2adc_clk_info);
for (adc_clk_idx = 0; adc_clk_idx < cnt; adc_clk_idx ++) {
if (adc_clk > sys2adc_clk_info[adc_clk_idx]) {
break;
}
}
if (adc_clk_idx < cnt) {
adc_clk_idx = cnt - adc_clk_idx;
} else {
adc_clk_idx = cnt - 1;
}
return adc_clk_idx;
}
___interrupt
static void adc_isr()
{
_adc_res = JL_ADC->RES;
local_irq_disable();
JL_ADC->CON = BIT(6);
local_irq_enable();
#if 1
if (adc_sample_flag > 1) {
extern void adc_scan(void *priv);
adc_scan((void *)&adc_sample_flag);
}
#endif
}
u32 adc_sample(u32 ch)
{
const u32 tmp_adc_res = _adc_res;
_adc_res = (u16) - 1;
u32 adc_con = 0;
SFR(adc_con, 0, 3, 0b110);//div 96
adc_con |= (0xf << 12); //启动延时控制,实际启动延时为此数值*8个ADC时钟
adc_con |= BIT(3); //ana en
adc_con |= BIT(6); //clr pend
adc_con |= BIT(5);//ie
adc_con |= BIT(17);//clk en
/* adc_con |= BIT(18)|BIT(19);//clk en */
SFR(adc_con, 21, 3, 0b010);
switch (ch & 0xff) {
case AD_CH_BT:
SFR(adc_con, 18, 3, AD_CH_BT & 0xf);
break;
case AD_CH_PMU:
if (adc_sample_flag > 1) {
SFR(adc_con, 0, 3, 0b011);//div 24
adc_con &= ~(0xf << 12);
}
SFR(adc_con, 18, 3, AD_CH_PMU & 0xf);
adc_pmu_ch_select(ch >> 16);
break;
case AD_CH_AUDIO:
SFR(adc_con, 18, 3, AD_CH_AUDIO & 0xf);
adc_audio_ch_select(ch >> 16);
break;
case AD_CH_LPCTM:
SFR(adc_con, 18, 3, AD_CH_LPCTM & 0xf);
break;
case AD_CH_X32K:
SFR(adc_con, 18, 3, AD_CH_X32K & 0xf);
break;
case AD_CH_PLL1:
SFR(adc_con, 18, 3, AD_CH_PLL1 & 0xf);
break;
default:
SFR(adc_con, 21, 3, 0b001);
SFR(adc_con, 8, 4, ch & 0xf);
break;
}
JL_ADC->CON = adc_con;
JL_ADC->CON |= BIT(4);//en
/* printf("ch %x %x %x %x",ch,ch >> 16,JL_ADC->CON,P3_ANA_CON4); */
JL_ADC->CON |= BIT(6);//kistart
return tmp_adc_res;
}
void adc_scan(void *priv)
{
static u16 vbg_adc_res = 0;
static u16 dtemp_adc_res = 0;
if ((priv == NULL) && (adc_sample_flag > 1)) {
return;
}
if (adc_queue[ADC_MAX_CH].ch != -1) { //occupy mode
return;
}
if (JL_ADC->CON & BIT(4)) {
adc_sample_flag = 0;
return ;
}
if (_adc_res == 0xffff) {
adc_sample_flag = 0;
}
if (adc_sample_flag) {
if (adc_sample_flag == 2) {
dtemp_adc_res = _adc_res;
adc_sample_flag = 3;
adc_sample(AD_CH_LDOREF);
return;
} else if (adc_sample_flag == 3) {
vbg_adc_res = _adc_res;
dtemp_voltage = adc_value_to_voltage(vbg_adc_res, dtemp_adc_res);
/* printf("vbg:%d dtemp:%d vol:%dmv\n", vbg_adc_res, dtemp_adc_res, dtemp_voltage); */
} else {
adc_queue[cur_ch].value = _adc_res;
if (adc_queue[cur_ch].ch == AD_CH_VBAT) {
adc_value_push(vbat_value_array, _adc_res);
/* printf("vbat %d",_adc_res); */
} else if (adc_queue[cur_ch].ch == AD_CH_LDOREF) {
adc_value_push(vbg_value_array, _adc_res);
/* printf("vbg %d",_adc_res); */
}
}
adc_sample_flag = 0;
}
u8 next_ch = adc_get_next_ch(cur_ch);
if (adc_queue[next_ch].sample_period) {
if (time_before(adc_queue[next_ch].jiffies, jiffies)) {
if (adc_queue[next_ch].ch == AD_CH_DTEMP) {
adc_sample_flag = 2;
} else {
adc_sample_flag = 1;
}
adc_sample(adc_queue[next_ch].ch);
adc_queue[next_ch].jiffies += adc_queue[next_ch].sample_period;
}
} else {
adc_sample(adc_queue[next_ch].ch);
adc_sample_flag = 1;
}
cur_ch = next_ch;
}
static u16 adc_wait_pnd()
{
while (!(JL_ADC->CON & BIT(7)));
u32 adc_res = JL_ADC->RES;
/* printf("adc_res =%d\n",adc_res); */
asm("nop");
JL_ADC->CON |= BIT(6);
return adc_res;
}
static int hpvdd_voltage = 0;
static void read_hpvdd_voltage(void)
{
int hpvdd_adc_value = 0;
int tvalue = 0;
adc_sample(AD_CH_AUDIO_HPVDD);
for (int i = 0; i < 10; i++) {
tvalue = adc_wait_pnd();
hpvdd_adc_value += tvalue;
}
hpvdd_adc_value /= 10;
u32 adc_vbg = adc_get_value(AD_CH_LDOREF);
hpvdd_voltage = adc_value_to_voltage(adc_vbg, hpvdd_adc_value);
printf("hpvdd = %d mV\n", hpvdd_voltage);
SFR(JL_ADDA->ADDA_CON0, 9, 1, 0);
}
int get_hpvdd_voltage(void)
{
return hpvdd_voltage;
}
void adc_reset(void)
{
int i, j;
local_irq_disable();
JL_ADC->CON = 0;
memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
u32 sum_ad = 0;
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
sum_ad += adc_wait_pnd();
}
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
adc_value_push(vbg_value_array, sum_ad);
printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
sum_ad = 0;
adc_sample(AD_CH_VBAT);
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
sum_ad += adc_wait_pnd();
}
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
adc_value_push(vbat_value_array, sum_ad);
printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
JL_ADC->CON = BIT(6);
cur_ch = 0;
adc_sample_flag = 0;
local_irq_enable();
}
void _adc_init(u32 sys_lvd_en)
{
memset(adc_queue, 0xff, sizeof(adc_queue));
memset(vbg_value_array, 0x0, sizeof(vbg_value_array));
memset(vbat_value_array, 0x0, sizeof(vbat_value_array));
JL_ADC->CON = 0;
JL_ADC->CON = 0;
adc_add_sample_ch(AD_CH_LDOREF);
adc_set_sample_freq(AD_CH_LDOREF, PMU_CH_SAMPLE_FREQ);
adc_add_sample_ch(AD_CH_VBAT);
adc_set_sample_freq(AD_CH_VBAT, PMU_CH_SAMPLE_FREQ);
adc_add_sample_ch(AD_CH_DTEMP);
adc_set_sample_freq(AD_CH_DTEMP, PMU_CH_SAMPLE_FREQ);
u32 sum_ad = 0;
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
sum_ad += adc_wait_pnd();
}
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
adc_value_push(vbg_value_array, sum_ad);
printf("vbg_adc_value = %d\n", adc_value_avg(vbg_value_array));
sum_ad = 0;
adc_sample(AD_CH_VBAT);
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
sum_ad += adc_wait_pnd();
}
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
adc_value_push(vbat_value_array, sum_ad);
printf("vbat_adc_value = %d\n", adc_value_avg(vbat_value_array));
printf("vbat = %d mv\n", adc_get_voltage(AD_CH_VBAT) * 4);
sum_ad = 0;
adc_sample(AD_CH_DTEMP);
for (int i = 0; i < PMU_CH_VALUE_ARRAY_SIZE; i ++) {
sum_ad += adc_wait_pnd();
}
sum_ad /= PMU_CH_VALUE_ARRAY_SIZE;
dtemp_voltage = adc_value_to_voltage(adc_value_avg(vbg_value_array), sum_ad);
printf("dtemp_adc_value = %d\n", sum_ad);
printf("dtemp = %d mv\n", dtemp_voltage);
read_hpvdd_voltage();
request_irq(IRQ_GPADC_IDX, 0, adc_isr, 0);
usr_timer_add(NULL, adc_scan, 5, 0); //2ms
/* void btosc_fast_boot_test(void); */
/* btosc_fast_boot_test(); */
/* sys_timer_add(NULL, adc_scan, 10); //2ms */
/* void adc_test(); */
/* usr_timer_add(NULL, adc_test, 1000, 0); //2ms */
/* extern void wdt_close(); */
/* wdt_close(); */
/* */
/* while(1); */
}
u32 get_vdd_voltage(u32 ch)
{
u32 vbg_value = 0;
u32 wvdd_value = 0;
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < 10; i++) {
vbg_value += adc_wait_pnd();
}
adc_sample(ch);
for (int i = 0; i < 10; i++) {
wvdd_value += adc_wait_pnd();
}
u32 adc_vbg = vbg_value / 10;
u32 adc_res = wvdd_value / 10;
return adc_value_to_voltage(adc_vbg, adc_res);
}
#define ADC_SCAN_NUM 16
__attribute__((noinline))
AT(.volatile_ram_code)
u32 get_vddio_voltage()
{
u32 vbg_value = 0;
u32 vddio_value = 0;
u32 min = -1;
u32 max = 0;
adc_pmu_detect_en(0);
adc_sample(AD_CH_LDOREF);
for (int i = 0; i < ADC_SCAN_NUM; i++) {
while (!(JL_ADC->CON & BIT(7))) { //wait pending
}
u32 adc_res = JL_ADC->RES;
vbg_value += adc_res;
JL_ADC->CON |= BIT(6);
if (max < adc_res) {
max = adc_res;
}
if (min > adc_res) {
min = adc_res;
}
}
u32 adc_vbg = (vbg_value - max - min) / (ADC_SCAN_NUM - 2);
u32 adc_trim = get_vbg_trim();
u32 vbg_voltage, tmp1;
tmp1 = adc_trim & 0x0f;
vbg_voltage = (adc_trim & BIT(4)) ? VBG_CENTER - tmp1 * VBG_RES : VBG_CENTER + tmp1 * VBG_RES;
u32 vddio_voltage = vbg_voltage * 1023 / adc_vbg;
return vddio_voltage;
}
void adc_init()
{
adc_pmu_detect_en(1);
volatage_trim_init();
_adc_init(1);
}
//late_initcall(adc_init);
void adc_test()
{
/* void efuse_test(); */
/* efuse_test(); */
/* printf("\n\n%s() chip_id :%x\n", __func__, get_chip_id()); */
/* printf("%s() vbg trim:%x\n", __func__, get_vbg_trim()); */
/* printf("%s() vbat trim:%x\n", __func__, get_vbat_trim()); */
/* printf("\n\nWLA_CON0 %x\n", JL_ANA->WLA_CON0); */
/* printf("WLA_CON9 %x\n", JL_ANA->WLA_CON9); */
/* printf("WLA_CON10 %x\n", JL_ANA->WLA_CON10); */
/* printf("WLA_CON21 %x\n", JL_ANA->WLA_CON21); */
/* printf("ADA_CON %x\n", JL_ANA->ADA_CON3); */
/* printf("PLL_CON1 %x\n", JL_CLOCK->PLL_CON1); */
printf("\n%s() VBAT:%d %d mv\n\n", __func__,
adc_get_value(AD_CH_VBAT), adc_get_voltage(AD_CH_VBAT) * 4);
/* printf("\n%s() pa3:%d %d mv\n\n", __func__, */
/* adc_get_value(AD_CH_PA3), adc_get_voltage(AD_CH_PA3)); */
}
void adc_vbg_init()
{
return ;
}
//__initcall(adc_vbg_init);

456
cpu/br28/aec_tool.c Normal file
View File

@ -0,0 +1,456 @@
#include "system/includes.h"
#include "media/includes.h"
#include "app_config.h"
#include "app_online_cfg.h"
#include "online_db_deal.h"
#include "math.h"
#include "config/config_target.h"
#include "config/config_interface.h"
#include "aec_user.h"
extern int aec_cfg_online_init();
extern int aec_cfg_online_update(int root_cmd, void *cfg);
extern int get_aec_config(u8 *buf, int version);
#if TCFG_AEC_TOOL_ONLINE_ENABLE
/* #define LOG_TAG_CONST AEC_TOOL */
#define LOG_TAG "[AEC-TOOL]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#include "debug.h"
const u8 audio_sdk_name[16] = "AC701N";
/* const u8 audio_aec_ver[4] = {1, 7, 1, 1}; */
const u8 audio_aec_ver[4] = {1, 7, 1, 2};
#define audio_eq_password "000"
#define password_en 0
enum {
AEC_ONLINE_CMD_GETVER = 0x5,
AEC_ONLINE_CMD_GET_SOFT_SECTION,//br22专用
AEC_ONLINE_CMD_GET_SECTION_NUM = 0x7,//工具查询 小机需要的eq段数
AEC_ONLINE_CMD_GLOBAL_GAIN_SUPPORT_FLOAT = 0x8,
AEC_ONLINE_CMD_PASSWORD = 0x9,
AEC_ONLINE_CMD_VERIFY_PASSWORD = 0xA,
AEC_ONLINE_CMD_FILE_SIZE = 0xB,
AEC_ONLINE_CMD_FILE = 0xC,
AEC_ONLINE_CMD_GET_SECTION_NUM_NEW = 0xD,//该命令新加与 0x7功能一样
AEC_ONLINE_CMD_CHANGE_MODE = 0xE,//切模式
AEC_ONLINE_CMD_MODE_COUNT = 0x100,//模式个数a 1
AEC_ONLINE_CMD_MODE_NAME = 0x101,//模式的名字a eq
AEC_ONLINE_CMD_MODE_GROUP_COUNT = 0x102,//模式下组的个数,4个字节 1
AEC_ONLINE_CMD_MODE_GROUP_RANGE = 0x103,//模式下组的id内容 0x11
AEC_ONLINE_CMD_EQ_GROUP_COUNT = 0x104,//eq组的id个数 1
AEC_ONLINE_CMD_EQ_GROUP_RANGE = 0x105,//eq组的id内容 0x11
AEC_ONLINE_CMD_MODE_SEQ_NUMBER = 0x106,//mode的编号 magic num
AEC_ONLINE_CMD_MAX,//最后一个
};
typedef struct _aec_tool_cfg {
u8 mode_index; //模式序号
u8 *mode_name; //模式名
u32 mode_seq; //模式的seq,用于识别离线文件功能类型
u8 fun_num; //模式下有多少种功能
u16 fun_type[6]; //模式下拥有哪些功能
} aec_tool_cfg;
typedef struct _aec_parm {
u8 app: 1; //是否手机app在线调试
u8 online_en: 1;
aec_tool_cfg *aec_tool_tab;
} aec_adjust_parm;
typedef struct {
u32 aec_updata;
spinlock_t lock;
u8 app: 1;
u8 online_en: 1;
u8 password_ok: 1;
u8 parse_seq;
aec_tool_cfg *aec_tool_tab;
} AEC_CFG;
static AEC_CFG *p_aec_cfg = NULL;
/*----------------------------------------------------------------------------*/
/**@brief 在线调试,应答接口
@param *packet
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void ci_send_packet_new(AEC_CFG *aec_cfg, u32 id, u8 *packet, int size)
{
ASSERT(aec_cfg);
if (aec_cfg->app) {
if (AEC_CONFIG_ID == id) {
app_online_db_ack(aec_cfg->parse_seq, packet, size);
return;
}
}
#if TCFG_ONLINE_ENABLE
ci_send_packet(id, packet, size);
#endif
}
/*
*aec 在线调试,系数解析函数
* */
static s32 aec_online_update(AEC_CFG *aec_cfg, void *_packet)
{
typedef struct {
int cmd; ///<AEC_ONLINE_CMD
int data[45]; ///<data
} AEC_ONLINE_PACKET;
AEC_ONLINE_PACKET *packet = _packet;
int ret = -1;
log_d("aec_cmd:0x%x ", packet->cmd);
spin_lock(&aec_cfg->lock);
ret = aec_cfg_online_update(packet->cmd, packet->data);
spin_unlock(&aec_cfg->lock);
return ret;
}
/*
* 打开工具时,相关的命令通讯
* */
static int aec_online_nor_cmd(AEC_CFG *aec_cfg, void *_packet)
{
typedef struct {
int cmd; ///<AEC_ONLINE_CMD
int data[45]; ///<data
} AEC_ONLINE_PACKET;
AEC_ONLINE_PACKET *packet = _packet;
aec_tool_cfg *aec_tool_tab = aec_cfg->aec_tool_tab;
u32 id = AEC_CONFIG_ID;
if (packet->cmd == AEC_ONLINE_CMD_GETVER) {
struct eq_ver_info {
char sdkname[16];
u8 eqver[4];
};
struct eq_ver_info eq_ver_info = {0};
memcpy(eq_ver_info.sdkname, audio_sdk_name, sizeof(audio_sdk_name));
memcpy(eq_ver_info.eqver, audio_aec_ver, sizeof(audio_aec_ver));
ci_send_packet_new(aec_cfg, id, (u8 *)&eq_ver_info, sizeof(struct eq_ver_info));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_GET_SECTION_NUM || (packet->cmd == AEC_ONLINE_CMD_GET_SECTION_NUM_NEW)) {
struct _cmd {
int id;
int groupId;
};
struct _cmd cmd = {0};
memcpy(&cmd, packet->data, sizeof(struct _cmd));
uint8_t hw_section = 0;
log_d("hw_section %d cmd.id:%x\n", hw_section, cmd.id);
ci_send_packet_new(aec_cfg, id, (u8 *)&hw_section, sizeof(uint8_t));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_GLOBAL_GAIN_SUPPORT_FLOAT) {
uint8_t support_float = 1;
ci_send_packet_new(aec_cfg, id, (u8 *)&support_float, sizeof(uint8_t));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_PASSWORD) {
uint8_t password = 0;
if (password_en) {
password = 1;
}
ci_send_packet_new(aec_cfg, id, (u8 *)&password, sizeof(uint8_t));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_VERIFY_PASSWORD) {
//check password
int len = 0;
char pass[64];
typedef struct password {
int len;
char pass[45];
} PASSWORD;
PASSWORD ps = {0};
spin_lock(&aec_cfg->lock);
memcpy(&ps, packet->data, sizeof(PASSWORD));
memcpy(&ps, packet->data, sizeof(int) + ps.len);
spin_unlock(&aec_cfg->lock);
uint8_t password_ok = 0;
if (!strcmp(ps.pass, audio_eq_password)) {
password_ok = 1;
} else {
log_error("password verify failxx \n");
}
aec_cfg->password_ok = password_ok;
ci_send_packet_new(aec_cfg, id, (u8 *)&password_ok, sizeof(uint8_t));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_FILE_SIZE) {
y_printf("get aec file_size");
#if TCFG_AUDIO_DUAL_MIC_ENABLE
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
u32 cfg_file_size = sizeof(AEC_DMS_CONFIG);
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
u32 cfg_file_size = sizeof(DMS_FLEXIBLE_CONFIG);
#endif/*TCFG_AUDIO_DMS_SEL*/
#else/*SINGLE MIC*/
u32 cfg_file_size = sizeof(AEC_CONFIG);
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
ci_send_packet_new(aec_cfg, id, (u8 *)&cfg_file_size, sizeof(u32));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_FILE) {
y_printf("get aec file");
put_buf(packet, 64);
#if TCFG_AUDIO_DUAL_MIC_ENABLE
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
AEC_DMS_CONFIG cfg_file;
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
DMS_FLEXIBLE_CONFIG cfg_file;
#endif/*TCFG_AUDIO_DMS_SEL*/
#else/*SINGLE MIC*/
AEC_CONFIG cfg_file;
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
int version = 0;
memcpy(&version, packet->data, 4);
printf("version %x", version);
int cfg_file_len = get_aec_config(&cfg_file, version);
ci_send_packet_new(aec_cfg, id, (u8 *)&cfg_file, cfg_file_len);
return 0;//-EINVAL;
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_COUNT) {
//模式个数
int mode_cnt = 1;//aec_cfg->mode_num;
ci_send_packet_new(aec_cfg, id, (u8 *)&mode_cnt, sizeof(int));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_NAME) {
//utf8编码得名字
struct cmd {
int id;
int modeId;
};
struct cmd cmd;
memcpy(&cmd, packet, sizeof(struct cmd));
u8 tmp[32] = {0};
u8 name_len = strlen(aec_tool_tab[cmd.modeId].mode_name);
memcpy(tmp, aec_tool_tab[cmd.modeId].mode_name, name_len);
ci_send_packet_new(aec_cfg, id, (u8 *)tmp, name_len);
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_GROUP_COUNT) {
struct cmd {
int id;
int modeId;
};
struct cmd cmd;
memcpy(&cmd, packet, sizeof(struct cmd));
int groups_num = aec_tool_tab[cmd.modeId].fun_num;
ci_send_packet_new(aec_cfg, id, (u8 *)&groups_num, sizeof(int));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_GROUP_RANGE) { //摸下是组的id
struct cmd {
int id;
int modeId;
int offset;
int count;
};
struct cmd cmd;
memcpy(&cmd, packet, sizeof(struct cmd));
u16 *group_tmp = aec_tool_tab[cmd.modeId].fun_type;//groups[cmd.modeId];
ci_send_packet_new(aec_cfg, id, (u8 *)&group_tmp[cmd.offset], cmd.count * sizeof(u16));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_EQ_GROUP_COUNT) {
u32 eq_group_num = 0;
ci_send_packet_new(aec_cfg, id, (u8 *)&eq_group_num, sizeof(u32));
return 0;
} else if (packet->cmd == AEC_ONLINE_CMD_EQ_GROUP_RANGE) {
} else if (packet->cmd == AEC_ONLINE_CMD_CHANGE_MODE) {
} else if (packet->cmd == AEC_ONLINE_CMD_MODE_SEQ_NUMBER) {
struct cmd {
int id;
int modeId;
};
struct cmd cmd;
memcpy(&cmd, packet, sizeof(struct cmd));
ci_send_packet_new(aec_cfg, id, (u8 *)&aec_tool_tab[cmd.modeId].mode_seq, sizeof(u32));
return 0;
}
return -EINVAL;
}
/*
*注册到协议端的,数据回调接口
* */
static void aec_online_callback(uint8_t *packet, uint16_t size)
{
s32 res = 0;
AEC_CFG *aec_cfg = p_aec_cfg;
if (!aec_cfg) {
return ;
}
//u8 *tmp_packet = malloc(size);
//memcpy(tmp_packet, packet, size);
u8 *tmp_packet = packet;
ASSERT(((int)tmp_packet & 0x3) == 0, "buf %x size %d\n", tmp_packet, size);
res = aec_online_update(aec_cfg, (void *)tmp_packet);
u32 id = AEC_CONFIG_ID;
if (res == 0) {
log_d("Ack");
ci_send_packet_new(aec_cfg, id, (u8 *)"OK", 2);
} else {
res = aec_online_nor_cmd(aec_cfg, (void *)tmp_packet);
if (res == 0) {
//free(tmp_packet);
return ;
}
log_d("Nack");
ci_send_packet_new(aec_cfg, id, (u8 *)"ER", 2);
}
//free(tmp_packet);
}
REGISTER_CONFIG_TARGET(aec_config_target) = {
.id = AEC_CONFIG_ID,
.callback = aec_online_callback,
};
//AEC在线调试不进power down
static u8 aec_online_idle_query(void)
{
AEC_CFG *cfg = p_aec_cfg;
if (!cfg) {
return 1;
}
if (cfg->online_en) {
return 0;
}
return 1;
}
REGISTER_LP_TARGET(aec_online_lp_target) = {
.name = "aec_online",
.is_idle = aec_online_idle_query,
};
/*----------------------------------------------------------------------------*/
/**@brief 手机app 在线调时,数据解析的回调
@param *packet
@param
@return
@note
*/
/*----------------------------------------------------------------------------*/
int aec_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
{
AEC_CFG *aec_cfg = p_aec_cfg;
ASSERT(aec_cfg);
if (aec_cfg->online_en) {
aec_cfg->parse_seq = ext_data[1];
aec_online_callback(packet, size);
} else {
printf("AEC_ONLINE,not enable!\n");
}
return 0;
}
void *aec_cfg_open(aec_adjust_parm *parm)
{
AEC_CFG *aec_cfg = NULL;
if (aec_cfg == NULL) {
aec_cfg = zalloc(sizeof(AEC_CFG));
ASSERT(aec_cfg);
}
aec_cfg->aec_tool_tab = parm->aec_tool_tab;
aec_cfg->app = parm->app;
aec_cfg->online_en = parm->online_en;
spin_lock_init(&aec_cfg->lock);
p_aec_cfg = aec_cfg;
return aec_cfg;
}
void aec_cfg_close(AEC_CFG *aec_cfg)
{
if (!aec_cfg) {
return ;
}
free(aec_cfg);
aec_cfg = NULL;
}
aec_tool_cfg aec_tool_tab[] = {
{0, (u8 *)"AEC tool", AEC_CONFIG_ID, 1, {0x3000, 0x3100, 0x3200, 0x3300, 0x3400, 0x3500}},
};
/*----------------------------------------------------------------------------*/
/**@brief 设置CVP算法类型
@param cvp_mode 配置的算法类型
@return
@note
*/
/*----------------------------------------------------------------------------*/
void cvp_mode_set(u16 cvp_mode)
{
printf("cvp_mode_set:0x%x\n", cvp_mode);
aec_tool_tab[0].fun_type[0] = cvp_mode;
}
int aec_cfg_init(void)
{
#if TCFG_AUDIO_DUAL_MIC_ENABLE
#if (TCFG_AUDIO_DMS_SEL == DMS_NORMAL)
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
cvp_mode_set(0x3100);
#else/*CVP_DNS_MODE*/
cvp_mode_set(0x3300);
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
#else/*TCFG_AUDIO_DMS_SEL == DMS_FLEXIBLE*/
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
cvp_mode_set(0x3400);
#else/*CVP_DNS_MODE*/
cvp_mode_set(0x3500);
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
#endif/*TCFG_AUDIO_DMS_SEL*/
#else/*SINGLE MIC*/
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
cvp_mode_set(0x3000);
#else/*CVP_DNS_MODE*/
cvp_mode_set(0x3200);
#endif/*TCFG_AUDIO_CVP_NS_MODE*/
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
aec_adjust_parm parm = {0};
parm.online_en = 1;
#if APP_ONLINE_DEBUG
parm.app = 1;
#endif
parm.aec_tool_tab = aec_tool_tab;
AEC_CFG *aec_cfg = aec_cfg_open(&parm);
if (aec_cfg->app) {
app_online_db_register_handle(DB_PKT_TYPE_AEC, aec_app_online_parse);
}
aec_cfg_online_init();
return 0;
}
__initcall(aec_cfg_init);
#endif

1029
cpu/br28/app_audio.c Normal file

File diff suppressed because it is too large Load Diff

3528
cpu/br28/audio_anc.c Normal file

File diff suppressed because it is too large Load Diff

405
cpu/br28/audio_anc.h Normal file
View File

@ -0,0 +1,405 @@
#ifndef AUDIO_ANC_H
#define AUDIO_ANC_H
#include "generic/typedef.h"
#include "asm/anc.h"
#include "anc_btspp.h"
#include "anc_uart.h"
#include "app_config.h"
#include "in_ear_detect/in_ear_manage.h"
#include "audio_anc_mult_scene.h"
#include "icsd_anc_app.h"
#include "audio_anc_fade_ctr.h"
/*******************ANC User Config***********************/
#define ANC_COEFF_SAVE_ENABLE 1 /*ANC滤波器表保存使能*/
#define ANC_INFO_SAVE_ENABLE 0 /*ANC信息记忆:保存上一次关机时所处的降噪模式等等*/
#define ANC_TONE_PREEMPTION 0 /*ANC提示音打断播放(1)还是叠加播放(0)*/
#define ANC_BOX_READ_COEFF 1 /*支持通过工具读取ANC训练系数*/
#define ANC_FADE_EN 1 /*ANC淡入淡出使能*/
#define ANC_MODE_SYSVDD_EN 0 /*ANC模式提高SYSVDD避免某些IC电压太低导致ADC模块工作不正常*/
#define ANC_TONE_END_MODE_SW 1 /*ANC提示音结束进行模式切换*/
#define ANC_MODE_EN_MODE_NEXT_SW 1 /*ANC提示音结束后才允许下一次模式切换*/
#define ANC_MODE_FADE_LVL 1 /*降噪模式淡入步进 * 53ms*/
/*
ANC多场景滤波器配置
*/
#define ANC_MULT_ORDER_ENABLE 0 /*ANC多滤波器使能*/
#define ANC_MULT_ORDER_CMP_ONLY_USE_ID1 1 /*ANC多滤波器-CMP音乐补偿仅使用场景ID1的参数*/
#define ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 0 /*ANC多滤波器-通透模式仅使用场景ID1的参数*/
#define ANC_MULT_ORDER_NORMAL_ID 1 /*ANC多滤波器-开机默认场景ID*/
//ANC多滤波器-耳道自适应ID匹配选择0则跟随当前场景
#define ANC_MULT_ADPTIVE_TRAIN_USE_ID 1 /*耳道自适应-训练使用的场景ID*/
#define ANC_MULT_ADPTIVE_MATCH_USE_ID 1 /*耳道自适应-匹配使用的场景ID*/
/*-------------------耳道自适应开发者模式说明------------------
开发者模式(支持工具在线修改)
权限:
1、MIC/SPK数据获取采样率跟随ANC
2、支持工具自适应数据读取,会占用3-4K ram
3、TWS区分左右参数
4、进入后不支持产测关机自动退出开发者模式
ANC_DEVELOPER_MODE_EN
开发者强制模式(不支持工具修改, 开机默认开发者模式)
新增权限:
5、每次自适应都保存数据保存前会校验数据确保开机转换数据正常不会死机
6、自适应失败播放提示音
-------------------------------------------------------------*/
#define ANC_DEVELOPER_MODE_EN 0 /*开发者强制模式强制使能,启动后不支持产测, 优先级最高, 不受工具控制*/
#define ANC_EAR_ADAPTIVE_EN TCFG_AUDIO_ANC_EAR_ADAPTIVE_EN /*ANC耳道自适应使能, 耳道是变量*/
#define ANC_POWEOFF_SAVE_ADAPTIVE_DATA 1 /*保存耳道自适应数据 0 每次保存1 关机保存*/
#define ANC_EAR_ADAPTIVE_CMP_EN ANC_ADAPTIVE_CMP_EN /*ANC耳道自适应音乐补偿使能*/
#define ANC_EAR_ADAPTIVE_EVERY_TIME 0 /*每次切ANC_ON都进行自适应*/
/*
ANC场景增益自适应配置
(场景是变量,与耳道自适应功能相互独立)
*/
#define ANC_ADAPTIVE_EN 0 /*ANC增益自适应使能*/
#define ANC_ADAPTIVE_MODE ANC_ADAPTIVE_GAIN_MODE /*ANC增益自适应模式*/
#define ANC_ADAPTIVE_TONE_EN 0 /*ANC增益自适应提示音使能*/
/*
音乐响度ANC动态增益调节, 随着音乐响度增大而减小ANC增益, 开此功能可关闭AUDIO_DRC
*/
#define ANC_MUSIC_DYNAMIC_GAIN_EN 0 /*音乐动态ANC增益使能*/
#define ANC_MUSIC_DYNAMIC_GAIN_THR -12 /*音乐动态ANC增益触发阈值(单位dB), range: (-30 ~ 0]*/
#define ANC_MUSIC_DYNAMIC_GAIN_SINGLE_FB 1 /*动态增益单独调FB增益使能*/
#if ANC_TRAIN_MODE == ANC_FB_EN
#define ANC_MODE_ENABLE ANC_OFF_BIT | ANC_ON_BIT
#else
#define ANC_MODE_ENABLE ANC_OFF_BIT | ANC_ON_BIT | ANC_TRANS_BIT
#endif/*ANC_TRAIN_MODE*/
//************************************************************************//
// ICSD ADT 相关功能配置 //
//************************************************************************//
#define AUDIO_ANC_WIDE_AREA_TAP_EVENT_SYNC 0//广域点击左右耳同步使能
/*支持开免摘的anc模式*/
#define SPEAK_TO_CHAT_ANC_MODE_ENABLE (ANC_ON_BIT)
//****************** ICSD ADT 相关功能配置 end ************************//
/*ANC工具配对码使能*/
#define ANCTOOL_NEED_PAIR_KEY 1
#define ANCTOOL_PAIR_KEY "123456" /*ANC工具默认配对码*/
/*******************ANC User Config End*******************/
/*ANC模式调试信息*/
static const char *anc_mode_str[] = {
"NULL", /*无效/非法*/
"ANC_OFF", /*关闭模式*/
"ANC_ON", /*降噪模式*/
"Transparency", /*通透模式*/
"ANC_BYPASS", /*BYPASS模式*/
"ANC_TRAIN", /*训练模式*/
"ANC_TRANS_TRAIN", /*通透训练模式*/
};
/*ANC状态调试信息*/
static const char *anc_state_str[] = {
"anc_close", /*关闭状态*/
"anc_init", /*初始化状态*/
"anc_open", /*打开状态*/
};
/*ANC MSG List*/
enum {
ANC_MSG_TRAIN_OPEN = 0xA1,
ANC_MSG_TRAIN_CLOSE,
ANC_MSG_RUN,
ANC_MSG_FADE_END,
ANC_MSG_MODE_SYNC,
ANC_MSG_TONE_SYNC,
ANC_MSG_DRC_TIMER,
ANC_MSG_DEBUG_OUTPUT,
ANC_MSG_ADAPTIVE_SYNC,
ANC_MSG_MUSIC_DYN_GAIN,
ANC_MSG_ICSD_ANC_CMD,
ANC_MSG_USER_TRAIN_INIT,
ANC_MSG_USER_TRAIN_RUN,
ANC_MSG_USER_TRAIN_SETPARAM,
ANC_MSG_USER_TRAIN_TIMEOUT,
ANC_MSG_ADT,
ANC_MSG_USER_TRAIN_END,
ANC_MSG_MIC_DATA_GET,
ANC_MSG_RESET,
ANC_MSG_SZ_FFT_OPEN,
ANC_MSG_SZ_FFT_RUN,
ANC_MSG_SZ_FFT_CLOSE,
ANC_MSG_MODE_SWITCH_IN_ANCTASK,
};
/*ANC MIC动态增益调整状态*/
enum {
ANC_MIC_DY_STA_INIT = 0, /*准备状态*/
ANC_MIC_DY_STA_START, /*进行状态*/
ANC_MIC_DY_STA_STOP, /*停止状态*/
};
#define ANC_CONFIG_LFF_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FF_EN)) && (ANC_CH & ANC_L_CH))
#define ANC_CONFIG_LFB_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FB_EN)) && (ANC_CH & ANC_L_CH))
#define ANC_CONFIG_RFF_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FF_EN)) && (ANC_CH & ANC_R_CH))
#define ANC_CONFIG_RFB_EN ((ANC_TRAIN_MODE & (ANC_HYBRID_EN | ANC_FB_EN)) && (ANC_CH & ANC_R_CH))
/*ANC记忆信息*/
typedef struct {
u8 mode; /*当前模式*/
u8 mode_enable; /*使能的模式*/
#if INEAR_ANC_UI
u8 inear_tws_mode;
#endif/*INEAR_ANC_UI*/
//s32 coeff[488];
} anc_info_t;
#if ANC_EAR_ADAPTIVE_EN
typedef struct {
#if ANC_EAR_RECORD_EN
float record_FL[EAR_RECORD_MAX][ANC_VMDATA_FF_RECORD_SIZE];
float record_FR[EAR_RECORD_MAX][ANC_VMDATA_FF_RECORD_SIZE];
int record_num;
// u8 record_num;
#endif/*ANC_EAR_RECORD_EN*/
u8 result;
#if ANC_CONFIG_LFF_EN
float lff_gain;
anc_fr_t lff[ANC_ADAPTIVE_FF_ORDER];
#endif/*ANC_CONFIG_LFF_EN*/
#if ANC_CONFIG_LFB_EN
float lfb_gain;
anc_fr_t lfb[ANC_ADAPTIVE_FB_ORDER];
#if ANC_EAR_ADAPTIVE_CMP_EN
float lcmp_gain;
anc_fr_t lcmp[ANC_ADAPTIVE_CMP_ORDER];
#endif/*ANC_EAR_ADAPTIVE_CMP_EN*/
#endif/*ANC_CONFIG_LFB_EN*/
#if ANC_CONFIG_RFF_EN
float rff_gain;
anc_fr_t rff[ANC_ADAPTIVE_FF_ORDER];
#endif/*ANC_CONFIG_RFF_EN*/
#if ANC_CONFIG_RFB_EN
float rfb_gain;
anc_fr_t rfb[ANC_ADAPTIVE_FB_ORDER];
#if ANC_EAR_ADAPTIVE_CMP_EN
float rcmp_gain;
anc_fr_t rcmp[ANC_ADAPTIVE_CMP_ORDER];
#endif/*ANC_EAR_ADAPTIVE_CMP_EN*/
#endif/*ANC_CONFIG_RFB_EN*/
} _PACKED anc_adaptive_iir_t;
#endif/*ANC_EAR_ADAPTIVE_EN */
/*ANC初始化*/
void anc_init(void);
/*ANC训练模式*/
void anc_train_open(u8 mode, u8 debug_sel);
/*ANC关闭训练*/
void anc_train_close(void);
/*
*ANC状态获取
*return 0: idle(初始化)
*return 1: busy(ANC/通透/训练)
*/
u8 anc_status_get(void);
/*获取anc当前模式*/
u8 anc_mode_get(void);
/*获取anc记录的最新的目标ANC模式*/
u8 anc_new_target_mode_get(void);
#define ANC_DAC_CH_L 0
#define ANC_DAC_CH_R 1
/*获取anc模式dac左右声道的增益*/
u8 anc_dac_gain_get(u8 ch);
/*获取anc模式ff_mic的增益*/
u8 audio_anc_ffmic_gain_get(void);
/*获取anc模式fb_mic的增益*/
u8 audio_anc_fbmic_gain_get(void);
/*获取anc模式指定mic的增益, mic_sel:目标MIC通道*/
u8 audio_anc_mic_gain_get(u8 mic_sel);
/*ANC模式切换(切换到指定模式),并配置是否播放提示音*/
void anc_mode_switch(u8 mode, u8 tone_play);
/*在anc任务里面切换anc模式
*避免上一次切换没有完成,这次切换被忽略的情况*/
void anc_mode_switch_in_anctask(u8 mode, u8 tone_play);
/*ANC模式同步(tws模式)*/
void anc_mode_sync(u8 *data);
void anc_poweron(void);
/*ANC poweroff*/
void anc_poweroff(void);
/*ANC模式切换(下一个模式)*/
void anc_mode_next(void);
/*ANC通过ui菜单选择anc模式,处理快速切换的情景*/
void anc_ui_mode_sel(u8 mode, u8 tone_play);
/*设置ANC支持切换的模式*/
void anc_mode_enable_set(u8 mode_enable);
/*anc coeff 长度大小获取*/
int anc_coeff_size_get(u8 mode);
void anc_coeff_size_set(u8 mode, int len);
int *anc_debug_ctr(u8 free_en);
/*
*查询当前ANC是否处于训练状态
*@return 1:处于训练状态
*@return 0:其他状态
*/
int anc_train_open_query(void);
/*ANC在线调试繁忙标志设置*/
void anc_online_busy_set(u8 en);
/*ANC在线调试繁忙标志获取*/
u8 anc_online_busy_get(void);
/*tws同步播放模式提示音并且同步进入anc模式*/
void anc_tone_sync_play(int tone_name);
/*anc coeff读接口*/
int *anc_coeff_read(void);
/*anc coeff写接口*/
int anc_coeff_write(int *coeff, u16 len);
/*ANC挂起*/
void anc_suspend(void);
/*ANC恢复*/
void anc_resume(void);
/*通话动态MIC增益开始函数*/
void anc_dynamic_micgain_start(u8 audio_mic_gain);
/*通话动态MIC增益结束函数*/
void anc_dynamic_micgain_stop(void);
/*anc_gains参数读写接口*/
void anc_param_fill(u8 cmd, anc_gain_t *cfg);
/*ANC_DUT audio模块使能函数用于分离功耗*/
void audio_anc_dut_enable_set(u8 enablebit);
/*ANC自适应TWS同步信息处理*/
void audio_anc_adap_sync(int ref_num, int err_num, int err);
void audio_anc_adap_num_compare(int ref_num, int err_num);
/*设置fb mic为复用mic*/
void audio_anc_mic_mana_fb_mult_set(u8 mult_flag);
//ANC MIC信息管理
void audio_anc_mic_management(audio_anc_t *param);
/*切换ANC自适应模式*/
void audio_anc_adaptive_mode_set(u8 mode, u8 lvl);
/*ANC增益调节 音乐响度检测*/
void audio_anc_music_dynamic_gain_det(s16 *data, int len);
/*ANC增益调节 音乐响度初始化*/
void audio_anc_music_dynamic_gain_init(int sr);
/*ANC增益调节 音乐响度复位*/
void audio_anc_music_dynamic_gain_reset(u8 effect_reset_en);
/*
自适应模式-重新检测
param: tws_sync_en 1 TWS同步自适应支持TWS降噪平衡需左右耳一起调用此接口
0 单耳自适应, 不支持TWS降噪平衡可TWS状态下单耳自适应
*/
int audio_anc_mode_ear_adaptive(u8 tws_sync_en);
/*
自适应/普通参数切换
param: mode 0 使用普通参数; 1 使用自适应参数
tone_play 0 不播放提示音1 播放提示音
update_flag 0 不更新效果; 1 即时更新效果
*/
int audio_anc_coeff_adaptive_set(u32 mode, u8 tone_play, u8 update_flag);
/*ANC滤波器模式循环切换*/
int audio_anc_coeff_adaptive_switch();
/*判断当前是否处于训练中*/
u8 audio_anc_adaptive_busy_get(void);
/*当前ANC滤波器模式获取 0:普通参数 1:自适应参数*/
int audio_anc_coeff_mode_get(void);
/*强制停止ANC训练 - 并用回默认参数*/
void anc_ear_adaptive_forced_exit(void);
/*自适应训练失败处理回调函数*/
void audio_anc_adaptive_fail_callback(u8 anc_err);
void audio_anc_develop_set(u8 mode);
u8 audio_anc_develop_get(void);
/*自适应主从序号*/
u8 anc_ear_adaptive_seq_get(void);
void audio_anc_param_map(u8 coeff_en, u8 gain_en);
/*
多滤波器-场景切换
param: scene 场景ID
update_flag 非ANC_OFF时即时更新效果: 0 不更新1 更新
Note: ID 从1 开始
*/
void audio_anc_mult_scene_set(u16 scene_id, u8 update_flag);
/*多滤波器-获取当前场景的滤波器*/
u8 audio_anc_mult_scene_get(void);
/*多滤波器-最大场景个数设置*/
void audio_anc_mult_scene_max_set(u8 scene_cnt);
/*多滤波器-最大场景个数获取*/
u8 audio_anc_mult_scene_max_get(void);
/*多滤波器-场景循环切换*/
void audio_anc_mult_scene_switch(u8 tone_flag);
/*
ANC结构设置, 下一次切模式或复位ANC时生效
param: enablebit ANC结构配置如(ANC_FF_EN/ANC_FB_EN/ANC_HYBRID_EN)
update_flag 非ANC_OFF时即时更新效果: 0 不更新1 更新
*/
void audio_anc_enable_set(u8 enablebit, u8 update_flag);
//ANC产测/调试模式设置
void audio_anc_prodution_mode_set(u8 mode);
extern int anc_uart_write(u8 *buf, u8 len);
extern void ci_send_packet(u32 id, u8 *packet, int size);
extern void sys_auto_shut_down_enable(void);
extern void sys_auto_shut_down_disable(void);
#endif/*AUDIO_ANC_H*/

270
cpu/br28/audio_anc_coeff.h Normal file
View File

@ -0,0 +1,270 @@
#ifndef _AUDIO_ANC_COEFF_H_
#define _AUDIO_ANC_COEFF_H_
#include "generic/typedef.h"
//46K
// const double trans_coeff_test[10] = {
// 1.000000e+00,
// -2.000000e+00,
// 1.000000e+00,
// -1.626608e+00,
// 6.662413e-01,
// 1.000000e+00,
// -2.000000e+00,
// 1.000000e+00,
// -1.802846e+00,
// 8.467739e-01
// };
//93k
const double trans_coeff_test[15] = {
1.000000e+00,
-2.000000e+00,
1.000000e+00,
-1.878287e+00,
8.825817e-01,
1.000000e+00,
-2.000000e+00,
1.000000e+00,
-1.945184e+00,
9.496315e-01,
5.154418e-02,
1.030884e-01,
5.154418e-02,
-1.263093e+00,
4.692696e-01
};
static const s32 fz_coef_test[100] = {
-15,
-27,
-10,
-14,
-38,
-8,
-22,
-40,
-29,
14,
28,
26,
-28,
-21,
2,
-52,
-95,
-99,
-25,
103,
62,
-58,
-116,
-137,
-27,
77,
25,
-138,
-250,
-174,
11,
147,
80,
-52,
-108,
7,
146,
217,
122,
3,
-49,
35,
93,
93,
20,
-43,
-84,
-46,
-4,
3,
-50,
-71,
-64,
-25,
30,
3,
-54,
-56,
-65,
-15,
17,
-36,
-55,
-50,
-21,
33,
41,
4,
-33,
-49,
-13,
23,
25,
5,
-26,
-37,
-13,
17,
22,
28,
6,
-1,
10,
28,
29,
7,
-16,
-21,
1,
17,
5,
-13,
-24,
-11,
3,
10,
-2,
-22,
-9,
-9
};
#if 1
const double ancl_fb_coef_test[100] = {
1.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00,
0.000000e+00
};
const double ancl_ff_coef_test[100] = {
};
const double ancl_sz_coef_test[100] = {
};
const double ancr_fb_coef_test[100] = {
};
const double ancr_ff_coef_test[100] = {
};
const double ancr_sz_coef_test[100] = {
};
#endif
#endif/*_AUDIO_ANC_COEFF_H_*/

View File

@ -0,0 +1,138 @@
#include "audio_anc_fade_ctr.h"
#include "anc.h"
#include "audio_anc.h"
/*
****************************************************************
* AUDIO ANC
* File : audio_anc_fade_ctr.c
* By : Junhao
* Notes : ANC fade gain管理支持多场景并行使用
*
****************************************************************
*/
#if 0
#define anc_fade_log printf
#else
#define anc_fade_log(...)
#endif/*log_en*/
//默认淡入增益dB换算公式 fade_gain = 10^(dB/20) * 16384;
#define AUDIO_ANC_FADE_GAIN_DEFAULT 16384 //(0dB)
struct anc_fade_context {
struct list_head entry;
enum anc_fade_mode_t mode;
u8 ch;
u16 fade_gain;
};
static LIST_HEAD(anc_fade_head);
static OS_MUTEX fade_mutex;
static void anc_fade_ctr_list_del(enum anc_fade_mode_t mode)
{
struct anc_fade_context *ctx;
if (list_empty(&anc_fade_head)) {
return;
}
list_for_each_entry(ctx, &anc_fade_head, entry) {
if (!strcmp(ctx->mode, mode)) {
goto __fade_del;
}
}
return;
__fade_del:
list_del(&ctx->entry);
free(ctx);
}
static void anc_fade_ctr_list_add(enum anc_fade_mode_t mode, u8 ch, u16 gain)
{
struct anc_fade_context *new_ctx = malloc(sizeof(struct anc_fade_context));
new_ctx->mode = mode;
//通道检测,有些芯片 fade_gain 不区分通道
new_ctx->ch = anc_fade_ctr_ch_check(ch);
new_ctx->fade_gain = gain;
list_add_tail(&new_ctx->entry, &anc_fade_head);
}
static int anc_fade_ctr_update(enum anc_fade_mode_t mode, u8 ch, u16 gain)
{
struct anc_fade_context *ctx;
if (list_empty(&anc_fade_head)) {
return 1;
}
list_for_each_entry(ctx, &anc_fade_head, entry) {
if (ctx->mode == mode) {
if (ctx->ch != ch) {
printf("ERR!!!anc_fade_gain mode&ch is no \"one to one\" \n");
}
ctx->fade_gain = gain;
return 0;
}
}
return 1;
}
void audio_anc_fade_ctr_init(void)
{
os_mutex_create(&fade_mutex);
}
void audio_anc_fade_ctr_set(enum anc_fade_mode_t mode, u8 ch, u16 gain)
{
os_mutex_pend(&fade_mutex, 0);
u16 lff_gain, lfb_gain, rff_gain, rfb_gain;
struct anc_fade_context *ctx;
u8 fade_en = anc_api_get_fade_en();
/* anc_fade_log("fade in mode %d, gain %d\n", mode, gain); */
lff_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
lfb_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
rff_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
rfb_gain = AUDIO_ANC_FADE_GAIN_DEFAULT;
if (gain == AUDIO_ANC_FADE_GAIN_DEFAULT) {
anc_fade_ctr_list_del(mode); //删除
} else {
if (anc_fade_ctr_update(mode, ch, gain)) { //更新
anc_fade_ctr_list_add(mode, ch, gain); //新增
}
}
//遍历链表
if (!list_empty(&anc_fade_head)) {
list_for_each_entry(ctx, &anc_fade_head, entry) {
/* anc_fade_log("fade list : mode %d, gain %d\n", ctx->mode, ctx->fade_gain); */
if ((ctx->ch & AUDIO_ANC_FADE_CH_LFF) && (ctx->fade_gain < lff_gain)) {
lff_gain = ctx->fade_gain;
}
if ((ctx->ch & AUDIO_ANC_FADE_CH_LFB) && (ctx->fade_gain < lfb_gain)) {
lfb_gain = ctx->fade_gain;
}
if ((ctx->ch & AUDIO_ANC_FADE_CH_RFF) && (ctx->fade_gain < rff_gain)) {
rff_gain = ctx->fade_gain;
}
if ((ctx->ch & AUDIO_ANC_FADE_CH_RFB) && (ctx->fade_gain < rfb_gain)) {
rfb_gain = ctx->fade_gain;
}
}
}
anc_fade_log("fade lff %d, lfb %d, rff %d, rfb %d\n", lff_gain, lfb_gain, rff_gain, rfb_gain);
audio_anc_fade_cfg_set(fade_en, 1, 0);
audio_anc_fade(AUDIO_ANC_FADE_CH_LFF, lff_gain);
audio_anc_fade(AUDIO_ANC_FADE_CH_LFB, lfb_gain);
audio_anc_fade(AUDIO_ANC_FADE_CH_RFF, rff_gain);
audio_anc_fade(AUDIO_ANC_FADE_CH_RFB, rfb_gain);
os_mutex_post(&fade_mutex);
}
void audio_anc_fade_ctr_del(enum anc_fade_mode_t mode)
{
audio_anc_fade_ctr_set(mode, 0, AUDIO_ANC_FADE_GAIN_DEFAULT);
}

View File

@ -0,0 +1,39 @@
#ifndef _AUDIO_ANC_FADE_CTR_H_
#define _AUDIO_ANC_FADE_CTR_H_
#include "generic/typedef.h"
//ANC全部通道
#define AUDIO_ANC_FDAE_CH_ALL AUDIO_ANC_FADE_CH_LFF | AUDIO_ANC_FADE_CH_LFB | AUDIO_ANC_FADE_CH_RFF | AUDIO_ANC_FADE_CH_RFB
enum anc_fade_mode_t {
ANC_FADE_MODE_RESET = 0, //复位
ANC_FADE_MODE_SWITCH, //ANC模式切换
ANC_FADE_MODE_MUSIC_DYNAMIC, //音乐动态增益
ANC_FADE_MODE_SCENE_ADAPTIVE, //ANC场景噪声自适应
ANC_FADE_MODE_WIND_NOISE, //ANC风噪检测
ANC_FADE_MODE_SUSPEND, //ANC挂起
//可再此继续添加模式
};
/*
ANC淡入淡出增益设置
param: mode 场景模式
ch 设置目标通道(支持多通道)
gain 设置增益
notes: ch 支持配置多个通道但mode 必须与 ch配置一一对应;
当设置gain = 16384, 会自动删除对应模式
*/
void audio_anc_fade_ctr_set(enum anc_fade_mode_t mode, u8 ch, u16 gain);
//删除fade mode
void audio_anc_fade_ctr_del(enum anc_fade_mode_t mode);
//fade ctr 初始化
void audio_anc_fade_ctr_init(void);
#endif/*_AUDIO_ANC_FADE_CTR_H_*/

View File

@ -0,0 +1,972 @@
/*******************************************************************
ANC 多滤波器场景
*******************************************************************/
#include "audio_anc.h"
#include "audio_anc_mult_scene.h"
#if ANC_MULT_ORDER_ENABLE
#if 0
#define anc_mult_log printf
#else
#define anc_mult_log(...)
#endif/*log_en*/
//ANC重组数据流程测试
#define ANC_MULT_DATA_TEST 0 //1 测试读取 2 测试重组
typedef struct {
u8 yorder;
anc_mult_gain_t *gains; //gains, 复用flash位置
anc_fr_t *fr; //滤波器复用flash位置
} anc_mult_param_t;
typedef struct {
struct list_head entry;
u16 scene_id; //场景号
anc_mult_param_t lff;
anc_mult_param_t lfb;
anc_mult_param_t ltrans;
anc_mult_param_t lcmp;
anc_mult_param_t rff;
anc_mult_param_t rfb;
anc_mult_param_t rtrans;
anc_mult_param_t rcmp;
} anc_mult_bulk_t;
typedef struct {
struct list_head head;
audio_anc_t *param;
u16 cur_scene;
double *lff_coeff;
double *lfb_coeff;
double *lcmp_coeff;
double *ltrans_coeff;
double *rff_coeff;
double *rfb_coeff;
double *rcmp_coeff;
double *rtrans_coeff;
} anc_mult_hdl_t;
//场景数据子结构;
typedef struct {
u16 scene_id;
u16 cnt;
u8 dat[0]; //小心访问非对齐异常
} anc_mult_scene_file_t;
/*
包含关系
anc_coeff_t
->anc_mult_scene_file_t
->struct anc_param_head_t
->data;
*/
anc_mult_hdl_t *mult_hdl = NULL;
static anc_coeff_t *anc_mult_cfg_test(int *db_len);
static anc_coeff_t *anc_mult_cfg_part_test(int *db_len);
//多滤波器数据填充
static int anc_mult_scene_param_read(struct list_head *list, u8 *dat)
{
int i = 0;
int file_offset = 0;
u8 *temp_dat;
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)dat;
anc_mult_scene_file_t file_align;
memcpy((u8 *)&file_align, (u8 *)file, sizeof(anc_mult_scene_file_t));
struct anc_param_head_t id_head[file_align.cnt];
anc_mult_bulk_t *bulk = zalloc(sizeof(anc_mult_bulk_t));
bulk->scene_id = file_align.scene_id;
/* put_buf(db_coeff->dat, db_coeff->cnt * 6); */
anc_mult_log("anc_mult_scene_id %d\n", file_align.scene_id);
temp_dat = file->dat + (file_align.cnt * 6);
for (i = 0; i < file_align.cnt; i++) {
memcpy(&id_head[i], file->dat + (i * 6), 6); //结构体为8字节这里只有6字节
anc_mult_log("id:0X%x, offset:%d,len:%d\n", id_head[i].id, id_head[i].offset, id_head[i].len);
switch (id_head[i].id) {
case ANC_L_FF_FGQ:
anc_mult_log("ANC_L_FF_FGQ\n");
bulk->lff.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->lff.yorder = id_head[i].len / 13;
break;
case ANC_L_FB_FGQ:
anc_mult_log("ANC_L_FB_FGQ\n");
bulk->lfb.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->lfb.yorder = id_head[i].len / 13;
break;
case ANC_L_CMP_FGQ:
anc_mult_log("ANC_L_CMP_FGQ\n");
bulk->lcmp.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->lcmp.yorder = id_head[i].len / 13;
break;
case ANC_L_TRANS_FGQ:
anc_mult_log("ANC_L_TRANS_FGQ\n");
bulk->ltrans.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->ltrans.yorder = id_head[i].len / 13;
break;
case ANC_L_FF_PARM:
anc_mult_log("ANC_L_FF_PARM\n");
bulk->lff.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_L_FB_PARM:
anc_mult_log("ANC_L_FB_PARM\n");
bulk->lfb.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_L_CMP_PARM:
anc_mult_log("ANC_L_CMP_PARM\n");
bulk->lcmp.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_L_TRANS_PARM:
anc_mult_log("ANC_L_TRANS_PARM\n");
bulk->ltrans.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_R_FF_FGQ:
anc_mult_log("ANC_R_FF_FGQ\n");
bulk->rff.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->rff.yorder = id_head[i].len / 13;
break;
case ANC_R_FB_FGQ:
anc_mult_log("ANC_R_FB_FGQ\n");
bulk->rfb.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->rfb.yorder = id_head[i].len / 13;
break;
case ANC_R_CMP_FGQ:
anc_mult_log("ANC_R_CMP_FGQ\n");
bulk->rcmp.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->rcmp.yorder = id_head[i].len / 13;
break;
case ANC_R_TRANS_FGQ:
anc_mult_log("ANC_R_TRANS_FGQ\n");
bulk->rtrans.fr = (anc_fr_t *)(temp_dat + id_head[i].offset);
bulk->rtrans.yorder = id_head[i].len / 13;
break;
case ANC_R_FF_PARM:
anc_mult_log("ANC_R_FF_PARM\n");
bulk->rff.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_R_FB_PARM:
anc_mult_log("ANC_R_FB_PARM\n");
bulk->rfb.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_R_CMP_PARM:
anc_mult_log("ANC_R_CMP_PARM\n");
bulk->rcmp.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_R_TRANS_PARM:
anc_mult_log("ANC_R_TRANS_PARM\n");
bulk->rtrans.gains = (anc_mult_gain_t *)(temp_dat + id_head[i].offset);
break;
case ANC_L_ADAP_GOLD_CURVE:
case ANC_R_ADAP_GOLD_CURVE:
if (mult_hdl->param->adaptive) {
anc_mult_log("ANC_L/R_ADAP_GOLD_CURVE\n");
mult_hdl->param->adaptive->ref_ff_curve = temp_dat + id_head[i].offset;
mult_hdl->param->adaptive->ref_ff_curve_len = id_head[i].len;
}
break;
default:
break;
}
/* put_buf((u8 *)(temp_dat + id_head[i].offset), id_head[i].len); */
}
//加入链表
list_add_tail(&bulk->entry, list);
//下一个场景的数据偏移量
file_offset = ((u32)temp_dat - (u32)dat) + id_head[file_align.cnt - 1].offset + id_head[file_align.cnt - 1].len;
anc_mult_log("next scene offset %d\n", file_offset);
return file_offset;
}
static int anc_mult_scene_list_del(struct list_head *list)
{
anc_mult_bulk_t *bulk;
anc_mult_bulk_t *temp;
list_for_each_entry_safe(bulk, temp, list, entry) {
list_del(&bulk->entry);
free(bulk);
}
}
//多滤波器文件读取
int anc_mult_coeff_file_fill(anc_coeff_t *db_coeff)
{
int offset = 0;
u8 *temp_dat;
#if ANC_MULT_DATA_TEST == 1
int len;
db_coeff = anc_mult_cfg_test(&len);
#endif/*ANC_MULT_DATA_TEST*/
if (mult_hdl && db_coeff) {
if ((db_coeff->version & 0xF0) == 0xA0) {
anc_mult_log("%s scene_cnt %d\n", __func__, db_coeff->cnt);
anc_mult_scene_list_del(&mult_hdl->head); //先卸载所有链表
audio_anc_mult_scene_max_set(db_coeff->cnt);
temp_dat = db_coeff->dat;
for (int i = 0; i < db_coeff->cnt; i++) {
//temp_dat表示当前场景数据指针以下函数会返回 下一个场景相对当前temp_dat的偏移量
temp_dat += anc_mult_scene_param_read(&mult_hdl->head, temp_dat);
}
return 0;
}
}
return 1;
}
//多滤波器初始化API
void anc_mult_init(audio_anc_t *param)
{
mult_hdl = zalloc(sizeof(anc_mult_hdl_t));
mult_hdl->param = param;
//链表初始化
INIT_LIST_HEAD(&mult_hdl->head);
}
extern void audio_anc_biquad2ab_double(anc_fr_t *iir, double *out_coeff, u8 order, int alogm);
static int anc_mult_cfg_analsis(anc_mult_param_t *p, double **coeff, float *gain, int alogm)
{
if (*coeff) {
free(*coeff);
*coeff = NULL;
}
if (!p->yorder) {
//没有滤波器, 退出
return -1;
}
*coeff = (double *)malloc(p->yorder * 40);
/* g_printf("coeff %x\n", (u32)*coeff); */
audio_anc_biquad2ab_double(p->fr, *coeff, p->yorder, alogm);
float temp;
memcpy((u8 *)&temp, (u8 *)&p->gains->iir_gain, 4);
if (temp < 0) {
*gain = 0 - temp;
return 1; //返回符号位
} else {
*gain = temp;
return 0; //返回符号位
}
}
//场景ID校验
int audio_anc_mult_scene_id_check(u16 scene_id)
{
if (!mult_hdl) {
return 1;
}
anc_mult_bulk_t *bulk;
list_for_each_entry(bulk, &mult_hdl->head, entry) {
if (bulk->scene_id == scene_id) {
return 0;
}
}
return 1;
}
//目标场景, 转成IIR滤波器并设置到lib coeff/gain变量
int anc_mult_scene_set(u16 scene_id)
{
int ret = 1;
if (!mult_hdl) {
return 1;
}
anc_mult_log("anc_mult_scene_set cur scene_id %d\n", scene_id);
u8 gain_sign = 0;
audio_anc_t *param = mult_hdl->param;
mult_hdl->cur_scene = scene_id;
anc_mult_bulk_t *bulk;
anc_mult_bulk_t *cmp_bulk;
anc_mult_bulk_t *trans_bulk;
list_for_each_entry(bulk, &mult_hdl->head, entry) {
if (bulk->scene_id == scene_id) {
if (anc_mult_cfg_analsis(&bulk->lff, &mult_hdl->lff_coeff, &param->gains.l_ffgain, param->gains.alogm) > 0) {
gain_sign |= ANCL_FF_SIGN;
}
param->lff_coeff = mult_hdl->lff_coeff;
param->lff_yorder = bulk->lff.yorder;
/* g_printf("param->lff_yorder %d\n", param->lff_yorder); */
/* put_buf((u8 *)mult_hdl->lff_coeff, bulk->lff.yorder * 40); */
/* g_printf("gain %d/100, gain_sign %x\n", (int)(param->gains.l_ffgain * 100.0f), gain_sign); */
if (anc_mult_cfg_analsis(&bulk->lfb, &mult_hdl->lfb_coeff, &param->gains.l_fbgain, param->gains.alogm) > 0) {
gain_sign |= ANCL_FB_SIGN;
}
param->lfb_coeff = mult_hdl->lfb_coeff;
param->lfb_yorder = bulk->lfb.yorder;
if (anc_mult_cfg_analsis(&bulk->rff, &mult_hdl->rff_coeff, &param->gains.r_ffgain, param->gains.alogm) > 0) {
gain_sign |= ANCR_FF_SIGN;
}
param->rff_coeff = mult_hdl->rff_coeff;
param->rff_yorder = bulk->rff.yorder;
if (anc_mult_cfg_analsis(&bulk->rfb, &mult_hdl->rfb_coeff, &param->gains.r_fbgain, param->gains.alogm) > 0) {
gain_sign |= ANCR_FB_SIGN;
}
param->rfb_coeff = mult_hdl->rfb_coeff;
param->rfb_yorder = bulk->rfb.yorder;
#if !ANC_MULT_ORDER_CMP_ONLY_USE_ID1 //CMP支持多场景
cmp_bulk = bulk;
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
#if !ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 //通透支持多场景
trans_bulk = bulk;
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
ret = 0;
}
if (bulk->scene_id == 1) {
#if ANC_MULT_ORDER_CMP_ONLY_USE_ID1 //CMP固定使用场景1的参数
cmp_bulk = bulk;
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
#if ANC_MULT_ORDER_TRANS_ONLY_USE_ID1 //通透固定使用场景1的参数
trans_bulk = bulk;
#endif/*ANC_MULT_ORDER_CMP_ONLY_USE_ID1*/
}
}
if (anc_mult_cfg_analsis(&cmp_bulk->lcmp, &mult_hdl->lcmp_coeff, &param->gains.l_cmpgain, param->gains.alogm) > 0) {
gain_sign |= ANCL_CMP_SIGN;
}
param->lcmp_coeff = mult_hdl->lcmp_coeff;
param->lcmp_yorder = cmp_bulk->lcmp.yorder;
if (anc_mult_cfg_analsis(&cmp_bulk->rcmp, &mult_hdl->rcmp_coeff, &param->gains.r_cmpgain, param->gains.alogm) > 0) {
gain_sign |= ANCR_CMP_SIGN;
}
param->rcmp_coeff = mult_hdl->rcmp_coeff;
param->rcmp_yorder = cmp_bulk->rcmp.yorder;
if (anc_mult_cfg_analsis(&trans_bulk->ltrans, &mult_hdl->ltrans_coeff, &param->gains.l_transgain, param->gains.trans_alogm) > 0) {
gain_sign |= ANCL_TRANS_SIGN;
}
param->ltrans_coeff = mult_hdl->ltrans_coeff;
param->ltrans_yorder = trans_bulk->ltrans.yorder;
if (anc_mult_cfg_analsis(&trans_bulk->rtrans, &mult_hdl->rtrans_coeff, &param->gains.r_transgain, param->gains.trans_alogm) > 0) {
gain_sign |= ANCR_TRANS_SIGN;
}
param->rtrans_coeff = mult_hdl->rtrans_coeff;
param->rtrans_yorder = trans_bulk->rtrans.yorder;
param->gains.gain_sign = gain_sign;
audio_anc_max_yorder_verify(param);
#if ANC_EAR_ADAPTIVE_EN
//ANC自适应开发者模式映射左右参数
audio_anc_param_map(1, 1);
#endif/*ANC_EAR_ADAPTIVE_EN*/
return ret;
}
//释放IIR滤波器空间
void audio_anc_mult_scene_coeff_free(void)
{
/*
空间暂不释放:
频繁切场景时或与自适应交叉使用时set 和 free的动作可能不是一一对应的
导致最后一个信号量响应时,滤波器已经被提前释放了。
*/
return;
if (!mult_hdl) {
return;
}
if (mult_hdl->lff_coeff) {
free(mult_hdl->lff_coeff);
mult_hdl->param->lff_coeff = NULL;
mult_hdl->lff_coeff = NULL;
}
if (mult_hdl->lfb_coeff) {
free(mult_hdl->lfb_coeff);
mult_hdl->param->lfb_coeff = NULL;
mult_hdl->lfb_coeff = NULL;
}
if (mult_hdl->ltrans_coeff) {
free(mult_hdl->ltrans_coeff);
mult_hdl->param->ltrans_coeff = NULL;
mult_hdl->ltrans_coeff = NULL;
}
if (mult_hdl->lcmp_coeff) {
free(mult_hdl->lcmp_coeff);
mult_hdl->param->lcmp_coeff = NULL;
mult_hdl->lcmp_coeff = NULL;
}
if (mult_hdl->rff_coeff) {
free(mult_hdl->rff_coeff);
mult_hdl->param->rff_coeff = NULL;
mult_hdl->rff_coeff = NULL;
}
if (mult_hdl->rfb_coeff) {
free(mult_hdl->rfb_coeff);
mult_hdl->param->rfb_coeff = NULL;
mult_hdl->rfb_coeff = NULL;
}
if (mult_hdl->rtrans_coeff) {
free(mult_hdl->rtrans_coeff);
mult_hdl->param->rtrans_coeff = NULL;
mult_hdl->rtrans_coeff = NULL;
}
if (mult_hdl->rcmp_coeff) {
free(mult_hdl->rcmp_coeff);
mult_hdl->param->rcmp_coeff = NULL;
mult_hdl->rcmp_coeff = NULL;
}
}
/*ANC滤波器格式校验*/
static int anc_mult_coeff_check(anc_coeff_t *db_coeff, u16 len)
{
u32 coeff_len = 0;
int i;
if ((db_coeff->version & 0xF0) != 0xA0) {
return 1;
}
if (db_coeff->cnt > 5) { //理论上最大ID个数
return 1;
}
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)db_coeff->dat;
struct anc_param_head_t coeff_head[file->cnt];
for (i = 0; i < file->cnt; i++) {
memcpy(&coeff_head[i], file->dat + (i * 6), 6); //结构体为8字节这里只有6字节
if (coeff_len != coeff_head[i].offset) {
return 1;
}
coeff_len += coeff_head[i].len;
}
return 0;
}
const static u8 anc_mult_part_id[8][2] = {
{ANC_L_FF_PARM, ANC_L_FF_FGQ},
{ANC_L_FB_PARM, ANC_L_FB_FGQ},
{ANC_L_CMP_PARM, ANC_L_CMP_FGQ},
{ANC_L_TRANS_PARM, ANC_L_TRANS_FGQ},
{ANC_R_FF_PARM, ANC_R_FF_FGQ},
{ANC_R_FB_PARM, ANC_R_FB_FGQ},
{ANC_R_CMP_PARM, ANC_R_CMP_FGQ},
{ANC_R_TRANS_PARM, ANC_R_TRANS_FGQ}
};
//部分数据文件-头部信息重组
static void anc_mult_part_head_recombination(u16 *cnt, struct anc_param_head_t *id_head, anc_mult_param_t *p, anc_mult_param_t *new_p, u8 type)
{
u8 order = (new_p->fr) ? new_p->yorder : p->yorder;
if ((p->gains != NULL) || (new_p->gains != NULL)) {
id_head[*cnt].id = anc_mult_part_id[type][0];
id_head[*cnt].len = sizeof(anc_mult_gain_t);
if (*cnt) {
id_head[*cnt].offset = id_head[(*cnt) - 1].len + id_head[(*cnt) - 1].offset;
}
(*cnt)++;
}
if (order) {
id_head[*cnt].id = anc_mult_part_id[type][1];
id_head[*cnt].len = order * sizeof(anc_fr_t);
if (*cnt) {
id_head[*cnt].offset = id_head[(*cnt) - 1].len + id_head[(*cnt) - 1].offset;
}
(*cnt)++;
}
}
//部分数据文件-数据信息重组
static void anc_mult_part_data_recombination(anc_mult_param_t *new_p, anc_mult_param_t *p, anc_mult_param_t *t_p, u8 type)
{
if (t_p->gains != NULL) {
memcpy((u8 *)new_p->gains, (u8 *)t_p->gains, sizeof(anc_mult_gain_t));
} else if (p->gains != NULL) {
memcpy((u8 *)new_p->gains, (u8 *)p->gains, sizeof(anc_mult_gain_t));
}
if (t_p->fr != NULL) {
memcpy((u8 *)new_p->fr, (u8 *)t_p->fr, t_p->yorder * sizeof(anc_fr_t));
} else if (p->fr != NULL) {
memcpy((u8 *)new_p->fr, (u8 *)p->fr, p->yorder * sizeof(anc_fr_t));
}
}
//部分数据文件-写,不支持新增场景
static int anc_mult_part_coeff_write(anc_coeff_t *target_coeff, u16 len)
{
u16 head_cnt, i, new_id_flag;
u16 scene_cnt = 0;
int ret = 0;
int new_len = sizeof(anc_coeff_t);
anc_coeff_t *old_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, &mult_hdl->param->coeff_size);
u8 *temp_dat;
anc_mult_bulk_t *new_bulk;
anc_mult_bulk_t *target_bulk;
anc_mult_bulk_t *old_bulk;
anc_mult_bulk_t *t_bulk;
if ((old_coeff->version & 0xF0) != 0xA0) {
return -1;
}
anc_mult_scene_file_t *file[old_coeff->cnt];
//1、解析目标数据信息
struct list_head target_list;
INIT_LIST_HEAD(&target_list);
if ((target_coeff->version & 0xF0) != 0xA0) {
return -1;
}
temp_dat = target_coeff->dat;
for (i = 0; i < target_coeff->cnt; i++) {
//temp_dat表示当前场景数据指针以下函数会返回 下一个场景相对当前temp_dat的偏移量
temp_dat += anc_mult_scene_param_read(&target_list, temp_dat);
}
//检查是否属于新场景(目前不支持新加场景重组)
list_for_each_entry(target_bulk, &target_list, entry) {
new_id_flag = 1;
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
if (target_bulk->scene_id == old_bulk->scene_id) {
new_id_flag = 0;
break;
}
}
if (new_id_flag) {
ret = -2;
goto __free2;
}
}
//2、重组新数据头信息
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
t_bulk = old_bulk;
list_for_each_entry(target_bulk, &target_list, entry) {
if (target_bulk->scene_id == old_bulk->scene_id) {
t_bulk = target_bulk;
break;
}
}
file[scene_cnt] = zalloc(sizeof(struct anc_param_head_t) * 16 + sizeof(anc_mult_scene_file_t));
struct anc_param_head_t *id_head = (struct anc_param_head_t *)file[scene_cnt]->dat;
head_cnt = 0;
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lff, &t_bulk->lff, 0);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lfb, &t_bulk->lfb, 1);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->lcmp, &t_bulk->lcmp, 2);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->ltrans, &t_bulk->ltrans, 3);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rff, &t_bulk->rff, 4);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rfb, &t_bulk->rfb, 5);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rcmp, &t_bulk->rcmp, 6);
anc_mult_part_head_recombination(&head_cnt, id_head, &old_bulk->rtrans, &t_bulk->rtrans, 7);
file[scene_cnt]->scene_id = old_bulk->scene_id;
file[scene_cnt]->cnt = head_cnt;
scene_cnt++;
//file+id_head+data(len+offset)
new_len += sizeof(anc_mult_scene_file_t) + (sizeof(struct anc_param_head_t) * head_cnt) + \
id_head[head_cnt - 1].len + id_head[head_cnt - 1].offset;
/* printf("last len%d, cnt%d, offset%d, len%d\n", new_len, head_cnt, id_head[head_cnt - 1].len, id_head[head_cnt - 1].offset); */
}
//重组后数据长度
anc_mult_log("PART FILE new_file_len %d\n", new_len);
//3、申请新数据空间
anc_coeff_t *new_coeff = (anc_coeff_t *)zalloc(new_len);
struct list_head new_list;
INIT_LIST_HEAD(&new_list);
int new_offset = 0;
if (!new_coeff) {
ret = -1;
goto __free1;
}
memcpy((u8 *)new_coeff, (u8 *)old_coeff, sizeof(anc_coeff_t));
temp_dat = new_coeff->dat;
//4、拷贝数据头至新数据空间
for (i = 0; i < new_coeff->cnt; i++) {
memcpy(temp_dat, (u8 *)file[i], sizeof(anc_mult_scene_file_t));
memcpy(temp_dat + sizeof(anc_mult_scene_file_t), file[i]->dat, \
sizeof(struct anc_param_head_t) * file[i]->cnt);
/* put_buf((u8*)new_coeff, new_len); */
new_offset = anc_mult_scene_param_read(&new_list, temp_dat);
temp_dat += new_offset;
}
//5、重组新数据
list_for_each_entry(old_bulk, &mult_hdl->head, entry) {
t_bulk = old_bulk;
list_for_each_entry(target_bulk, &target_list, entry) {
if (target_bulk->scene_id == old_bulk->scene_id) {
t_bulk = target_bulk;
break;
}
}
list_for_each_entry(new_bulk, &new_list, entry) {
if (new_bulk->scene_id == old_bulk->scene_id) {
anc_mult_part_data_recombination(&new_bulk->lff, &old_bulk->lff, &t_bulk->lff, 0);
anc_mult_part_data_recombination(&new_bulk->lfb, &old_bulk->lfb, &t_bulk->lfb, 1);
anc_mult_part_data_recombination(&new_bulk->lcmp, &old_bulk->lcmp, &t_bulk->lcmp, 2);
anc_mult_part_data_recombination(&new_bulk->ltrans, &old_bulk->ltrans, &t_bulk->ltrans, 3);
anc_mult_part_data_recombination(&new_bulk->rff, &old_bulk->rff, &t_bulk->rff, 4);
anc_mult_part_data_recombination(&new_bulk->rfb, &old_bulk->rfb, &t_bulk->rfb, 5);
anc_mult_part_data_recombination(&new_bulk->rcmp, &old_bulk->rcmp, &t_bulk->rcmp, 6);
anc_mult_part_data_recombination(&new_bulk->rtrans, &old_bulk->rtrans, &t_bulk->rtrans, 7);
}
}
}
//重组后数据内容
/* put_buf((u8*)new_coeff, new_len); */
//6、写入flash
mult_hdl->param->write_coeff_size = new_len; //更新滤波器长度
ret = anc_db_put(mult_hdl->param, NULL, new_coeff);
//7、释放新数据链表、ram
anc_mult_scene_list_del(&new_list);
free(new_coeff);
__free1:
//8、释放重组临时ram
for (i = 0; i < old_coeff->cnt; i++) {
free(file[i]);
}
__free2:
//9、释放目标数据解析链表
anc_mult_scene_list_del(&target_list);
return ret;
}
//单独增益ID设置-兼容之前的命令
void audio_anc_mult_gains_id_set(u8 gain_id, int data)
{
if (!mult_hdl) {
return;
}
anc_mult_bulk_t *bulk;
u8 *temp_dat;
float fgain = *((float *)&data);
int i;
struct list_head list;
INIT_LIST_HEAD(&list);
anc_coeff_t *db_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, &mult_hdl->param->coeff_size);
if ((db_coeff->version & 0xF0) != 0xA0) {
return;
}
anc_coeff_t *coeff = malloc(mult_hdl->param->coeff_size);
memcpy((u8 *)coeff, (u8 *)db_coeff, mult_hdl->param->coeff_size);
temp_dat = coeff->dat;
for (i = 0; i < coeff->cnt; i++) {
temp_dat += anc_mult_scene_param_read(&list, temp_dat);
}
list_for_each_entry(bulk, &list, entry) {
if (bulk->scene_id == audio_anc_mult_scene_get()) {
break;
}
}
switch (gain_id) {
case ANC_FFGAIN_SET:
if (bulk->lff.gains) {
bulk->lff.gains->iir_gain = (bulk->lff.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_FBGAIN_SET:
if (bulk->lfb.gains) {
bulk->lfb.gains->iir_gain = (bulk->lfb.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_TRANS_GAIN_SET:
if (bulk->ltrans.gains) {
bulk->ltrans.gains->iir_gain = (bulk->ltrans.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_CMP_GAIN_SET:
if (bulk->lcmp.gains) {
bulk->lcmp.gains->iir_gain = (bulk->lcmp.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_RFF_GAIN_SET:
if (bulk->rff.gains) {
bulk->rff.gains->iir_gain = (bulk->rff.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_RFB_GAIN_SET:
if (bulk->rfb.gains) {
bulk->rfb.gains->iir_gain = (bulk->rfb.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_RTRANS_GAIN_SET:
if (bulk->rtrans.gains) {
bulk->rtrans.gains->iir_gain = (bulk->rtrans.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_RCMP_GAIN_SET:
if (bulk->rcmp.gains) {
bulk->rcmp.gains->iir_gain = (bulk->rcmp.gains->iir_gain > 0) ? fgain : 0 - fgain;
}
break;
case ANC_GAIN_SIGN_SET:
anc_mult_param_t *p;
for (i = 0; i < 8; i++) {
p = &bulk->lff + i;
if (!p->gains) {
continue;
}
if (((data & BIT(i)) && (p->gains->iir_gain > 0)) || \
((!(data & BIT(i))) && (p->gains->iir_gain < 0))) {
p->gains->iir_gain = 0 - p->gains->iir_gain;
}
}
break;
}
mult_hdl->param->write_coeff_size = mult_hdl->param->coeff_size;
if (anc_db_put(mult_hdl->param, NULL, (anc_coeff_t *)coeff)) {
anc_mult_log("anc_coeff_write err!");
}
audio_anc_mult_coeff_file_read();
free(coeff);
}
//获取并解析flash anc_coeff.bin实时更新参数效果
int audio_anc_mult_coeff_file_read(void)
{
if (!mult_hdl) {
return 1;
}
audio_anc_t *param = mult_hdl->param;
//读flash
anc_coeff_t *db_coeff = (anc_coeff_t *)anc_db_get(ANC_DB_COEFF, &param->coeff_size);
anc_mult_log("anc_db coeff_size %d\n", param->coeff_size);
//更新参数链表
int ret = anc_mult_coeff_file_fill(db_coeff);
//更新效果
if (param->mode != ANC_OFF) {
/* g_printf("read cur scene_id %d\n",mult_hdl->cur_scene); */
anc_mult_scene_set(mult_hdl->cur_scene);
audio_anc_reset(param, 0);
}
return ret;
}
//anc_coeff.bin在线更新支持全部数据文件写、部分数据文件写
int audio_anc_mult_coeff_write(ANC_coeff_fill_t type, int *coeff, u16 len)
{
int ret = 0;
u8 single_type = 0;
#if ANC_MULT_DATA_TEST == 2 //流程测试,确认重组数据正常
int test_len;
if (type == ANC_MULT_COEFF_FILL_PART) {
coeff = (int *)anc_mult_cfg_part_test((int)&test_len);
} else {
coeff = (int *)anc_mult_cfg_test((int)&test_len);
}
len = test_len;
mult_hdl->param->write_coeff_size = len;
#endif/*ANC_MULT_DATA_TEST*/
anc_coeff_t *db_coeff = (anc_coeff_t *)coeff;
anc_coeff_t *tmp_coeff = NULL;
if (!mult_hdl) {
return -1;
}
anc_mult_log("anc_coeff_write:0x%x, len:%d", (u32)coeff, len);
ret = anc_mult_coeff_check(db_coeff, len);
if (ret) {
r_printf("err %d\n", ret);
return ret;
}
if (type == ANC_MULT_COEFF_FILL_PART) {
ret = anc_mult_part_coeff_write(db_coeff, len);
} else if (type == ANC_MULT_COEFF_FILL_ALL) {
ret = anc_db_put(mult_hdl->param, NULL, (anc_coeff_t *)coeff);
}
if (ret) {
anc_mult_log("anc_coeff_write err:%d", ret);
return -1;
}
ret = audio_anc_mult_coeff_file_read();
return ret;
}
#if ANC_MULT_DATA_TEST
static anc_coeff_t *anc_mult_cfg_test(int *db_len)
{
int i, j;
int offset = 0;
int len = 4 + 2 * (4 + 6 + 6) + 4 + 4 + 26 + 39;
anc_coeff_t *db = (anc_coeff_t *)zalloc(len);
anc_mult_log("test_db_len %d\n", len);
db->version = ANC_VERSION_BR28_MULT;
db->cnt = 2;
u8 *scene_temp = db->dat;
u8 *temp_dat;
struct anc_param_head_t *id_head;
anc_fr_t fr;
anc_mult_gain_t *gain;
for (j = 0; j < db->cnt; j++) {
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)scene_temp;
switch (j) {
case 0:
file->cnt = 2;
file->scene_id = 1;
temp_dat = file->dat + (file->cnt * 6);
id_head = (struct anc_param_head_t *)file->dat;
id_head[0].id = ANC_L_FF_PARM;
id_head[0].offset = 0;
id_head[0].len = 4;
gain = (anc_mult_gain_t *)temp_dat;
gain->iir_gain = 2.0f;
id_head[1].id = ANC_L_FF_FGQ;
id_head[1].offset = 4;
id_head[1].len = 26;
fr.type = ANC_IIR_BAND_PASS;
fr.a[0] = 500.0f;
fr.a[1] = 10.0f;
fr.a[2] = 3.0f;
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[1].offset + id_head[1].len;
break;
case 1:
file->cnt = 2;
file->scene_id = 2;
temp_dat = file->dat + (file->cnt * 6);
id_head = (struct anc_param_head_t *)file->dat;
id_head[0].id = ANC_L_FF_PARM;
id_head[0].offset = 0;
id_head[0].len = 4;
gain = (anc_mult_gain_t *)temp_dat;
gain->iir_gain = -3.0f;
id_head[1].id = ANC_L_FF_FGQ;
id_head[1].offset = 4;
id_head[1].len = 39;
fr.type = ANC_IIR_BAND_PASS;
fr.a[0] = 5000.0f;
fr.a[1] = 10.0f;
fr.a[2] = 3.0f;
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
memcpy(temp_dat + id_head[1].offset + 26, (u8 *)&fr, 13);
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[1].offset + id_head[1].len;
break;
}
scene_temp += offset;
}
*db_len = len;
put_buf((u8 *)db, *db_len);
return db;
}
anc_coeff_t *anc_mult_cfg_part_test(int *db_len)
{
int i, j;
int offset = 0;
/* int len = 4 + 2 * (4 + 6 ) + 4 + 4 + 26 + 39; */
int len = 4 + 2 * (4 + 6) + 6 + 4 + 4 + 39;
anc_coeff_t *db = (anc_coeff_t *)zalloc(len);
anc_mult_log("test_db_len %d\n", len);
db->version = ANC_VERSION_BR28_MULT;
db->cnt = 2;
u8 *scene_temp = db->dat;
u8 *temp_dat;
struct anc_param_head_t *id_head;
anc_fr_t fr;
anc_mult_gain_t *gain;
for (j = 0; j < db->cnt; j++) {
anc_mult_scene_file_t *file = (anc_mult_scene_file_t *)scene_temp;
switch (j) {
case 0:
file->cnt = 1;
file->scene_id = 1;
temp_dat = file->dat + (file->cnt * 6);
id_head = (struct anc_param_head_t *)file->dat;
id_head[0].id = ANC_L_FF_PARM;
id_head[0].offset = 0;
id_head[0].len = 4;
gain = (anc_mult_gain_t *)temp_dat;
gain->iir_gain = 1.0f;
/* id_head[1].id = ANC_L_FF_FGQ; */
/* id_head[1].offset = 4; */
/* id_head[1].len = 26; */
/* fr.type = ANC_IIR_BAND_PASS; */
/* fr.a[0] = 500.0f; */
/* fr.a[1] = 10.0f; */
/* fr.a[2] = 3.0f; */
/* memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13); */
/* memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13); */
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[0].offset + id_head[0].len;
break;
case 1:
file->cnt = 2;
file->scene_id = 2;
temp_dat = file->dat + (file->cnt * 6);
id_head = (struct anc_param_head_t *)file->dat;
id_head[0].id = ANC_L_FF_PARM;
id_head[0].offset = 0;
id_head[0].len = 4;
gain = (anc_mult_gain_t *)temp_dat;
gain->iir_gain = 1.0f;
id_head[1].id = ANC_L_FF_FGQ;
id_head[1].offset = 4;
/* id_head[1].len = 39; */
id_head[1].len = 26;
fr.type = ANC_IIR_BAND_PASS;
fr.a[0] = 1.0f;
fr.a[1] = 1.0f;
fr.a[2] = 1.0f;
memcpy(temp_dat + id_head[1].offset, (u8 *)&fr, 13);
memcpy(temp_dat + id_head[1].offset + 13, (u8 *)&fr, 13);
/* memcpy(temp_dat + id_head[1].offset + 26, (u8 *)&fr, 13); */
offset = ((u32)temp_dat - (u32)scene_temp) + id_head[0].offset + id_head[0].len;
break;
}
scene_temp += offset;
}
*db_len = len;
put_buf((u8 *)db, *db_len);
return db;
}
#endif/*ANC_MULT_DATA_TEST*/
#endif/*ANC_MULT_ORDER_ENABLE*/

View File

@ -0,0 +1,27 @@
#ifndef AUDIO_ANC_MULT_SCENE_H
#define AUDIO_ANC_MULT_SCENE_H
#include "generic/typedef.h"
#include "asm/anc.h"
typedef enum {
ANC_MULT_COEFF_FILL_ALL = 0, //滤波器全部填充
ANC_MULT_COEFF_FILL_PART, //滤波器部分填充
} ANC_coeff_fill_t;
int audio_anc_mult_coeff_file_read(void);
void anc_mult_init(audio_anc_t *param);
int anc_mult_scene_set(u16 scene_id);
int audio_anc_mult_coeff_write(ANC_coeff_fill_t type, int *coeff, u16 len);
void audio_anc_mult_scene_coeff_free(void);
void audio_anc_mult_gains_id_set(u8 gain_id, int data);
int audio_anc_mult_scene_id_check(u16 scene_id);
#endif/*AUDIO_ANC_MULT_SCENE_H*/

1080
cpu/br28/audio_capture.c Normal file

File diff suppressed because it is too large Load Diff

9
cpu/br28/audio_capture.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _AUDIO_CAPTURE_H_
#define _AUDIO_CAPTURE_H_
#include "generic/typedef.h"
int audio_capture_init(void);
int audio_capture_exit(void);
#endif/*_AUDIO_CAPTURE_H_*/

View File

@ -0,0 +1,374 @@
/*****************************************************************
>file name : audio_codec_clock.c
>create time : Thu 03 Jun 2021 09:36:12 AM CST
>History :
2021-11-19 : 增加后台叠加时钟的配置,用于满足一些后台运行的
音频处理
*****************************************************************/
#define LOG_TAG "[CODEC_CLK]"
#define LOG_INFO_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_DUMP_ENABLE
#define LOG_ERROR_ENABLE
#define LOG_WARN_ENABLE
#include "debug.h"
#include "app_config.h"
#include "system/includes.h"
#include "audio_codec_clock.h"
#include "audio_dec_eff.h"
#include "asm/dac.h"
#include "avctp_user.h"
#define AUDIO_CODING_ALL (0xffffffff)
#define MAX_CODING_TYPE_NUM 4 //可根据模式的解码格式需求扩展
#define AUDIO_CODEC_BASE_CLK SYS_24M
static LIST_HEAD(codec_clock_head);
struct audio_codec_clock {
u32 coding_type;
u32 clk;
u8 background; //后台运行的时钟
};
struct audio_codec_clk_context {
u8 mode;
struct audio_codec_clock params;
struct list_head entry;
};
#define SYS_60M SYS_64M
const struct audio_codec_clock audio_clock[AUDIO_MAX_MODE][MAX_CODING_TYPE_NUM] = {
{
//A2DP_MODE
{
AUDIO_CODING_SBC,
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
SYS_76M,
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)) || (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_76M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) && AUDIO_OUT_EFFECT_ENABLE)) || (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG)
SYS_60M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE) || TCFG_DRC_ENABLE || TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_48M,
#else
SYS_32M,
#endif
},
{
AUDIO_CODING_AAC,
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_96M,
#else
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || AUDIO_VBASS_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
SYS_76M,
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_64M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) || AUDIO_SURROUND_CONFIG || TCFG_DRC_ENABLE
#if (TCFG_AUDIO_ANC_ENABLE)
SYS_64M,
#else
SYS_60M,
#endif /*TCFG_AUDIO_ANC_ENABLE*/
#else
SYS_48M,
#endif
#endif
},
{
AUDIO_CODING_LDAC,
#if (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_128M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) | (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG) || TCFG_DRC_ENABLE
#if (TCFG_AUDIO_ANC_ENABLE)
SYS_128M,
#else
SYS_128M,
#endif /*TCFG_AUDIO_ANC_ENABLE*/
#else
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_128M,
#else
SYS_128M,
#endif /*TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR*/
#endif
}
},
{
//ESCO MODE
{
AUDIO_CODING_MSBC,
#if TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
SYS_76M,
#else /*TCFG_AUDIO_CVP_NS_MODE == CVP_DNS_MODE*/
SYS_96M,
#endif /*TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE*/
#else
/* SYS_48M, */
0,
#endif
},
{AUDIO_CODING_CVSD, 0},
},
{
//TONE MODE
{AUDIO_CODING_AAC | AUDIO_CODING_WAV | AUDIO_CODING_WTGV2 | AUDIO_CODING_MP3, SYS_64M},
{AUDIO_CODING_ALL, 0},
},
{
//FILE MODE
{AUDIO_CODING_ALL, 120 * 1000000L},
},
{
//PC MODE
{AUDIO_CODING_ALL, 96 * 1000000L},
},
{
//USB MIC MODE
#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
{AUDIO_CODING_ALL, 128 * 1000000L},
#else
{AUDIO_CODING_ALL, 96 * 1000000L},
#endif
},
{
//VAD MODE
{AUDIO_CODING_ALL, SYS_32M, 1},
},
{
//SPATIAL EFFECT MODE
#if ((defined TCFG_AUDIO_EFFECT_TASK_EBABLE) && TCFG_AUDIO_EFFECT_TASK_EBABLE)
{AUDIO_CODING_ALL, SYS_32M, 1},
#else
{AUDIO_CODING_ALL, SYS_120M, 1},
#endif /*TCFG_AUDIO_EFFECT_TASK_EBABLE*/
},
{
// SPEAK_TO_CHAT_MODE
{AUDIO_CODING_ALL, 48 * 1000000L}
},
{
// ANC_EAR_ADAPTIVE_MODE
{AUDIO_CODING_ALL, SYS_160M, 0}
},
{
// ANC_DUT_SZ_FFT_MODE
{AUDIO_CODING_ALL, SYS_120M, 0}
},
//TODO
};
static u32 audio_codec_background_clock(void)
{
struct audio_codec_clk_context *ctx;
u32 clk = 0;
if (list_empty(&codec_clock_head)) {
return 0;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->params.background) {
clk += ctx->params.clk;
}
}
return clk;
}
static void audio_codec_background_clock_add(u32 clk)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
ctx->params.clk += clk;
}
}
static void audio_codec_background_clock_del(u32 clk)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
ctx->params.clk -= clk;
}
}
static bool audio_codec_mode_exist(u8 mode)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return false;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->mode == mode) {
return true;
}
}
return false;
}
int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption)
{
u32 new_clk = 0;
u32 background_clk = 0;
if (mode >= AUDIO_MAX_MODE) {
log_error("Not support this mode : %d", mode);
return -EINVAL;
}
if (audio_codec_mode_exist(mode)) {
return 0;
}
const struct audio_codec_clock *params = audio_clock[mode];
int i = 0;
for (i = 0; i < MAX_CODING_TYPE_NUM; i++) {
if (params[i].coding_type & coding_type) {
goto match_clock;
}
}
log_error("Not found right coding type : %d", coding_type);
return -EINVAL;
match_clock:
if (params[i].background) {
/*如果是后台运行的,则需要处理最终时钟为前台+后台时钟总和*/
audio_codec_background_clock_add(params[i].clk);
new_clk = params[i].clk;
struct audio_codec_clk_context *first = list_empty(&codec_clock_head) ? NULL : list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (first) {
new_clk = first->params.clk;
} else {
/*后台运行时钟比较接近负载极限容易导致其他跑不过来因此多加12M*/
new_clk += 12 * 1000000L;
}
goto clock_set;
}
background_clk = audio_codec_background_clock();
new_clk = (params[i].clk ? params[i].clk : clk_get("sys")) + background_clk;
if (!preemption) {
struct audio_codec_clk_context *ctx1;
if (!list_empty(&codec_clock_head)) {
ctx1 = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (ctx1 && !ctx1->params.background) {
if (new_clk <= ctx1->params.clk) {
/*叠加解码的时钟不可小于在播放的音频时钟*/
new_clk = ctx1->params.clk + 12 * 1000000;
} else {
new_clk += 32 * 1000000;
}
}
}
}
clock_set:
struct audio_codec_clk_context *ctx = (struct audio_codec_clk_context *)zalloc(sizeof(struct audio_codec_clk_context));
ctx->mode = mode;
ctx->params.coding_type = coding_type;
ctx->params.background = params[i].background;
ctx->params.clk = ctx->params.background ? params[i].clk : new_clk;
clk_set("sys", new_clk);
if (ctx->params.background) {
list_add_tail(&ctx->entry, &codec_clock_head);
} else {
list_add(&ctx->entry, &codec_clock_head);
}
return 0;
}
void audio_codec_clock_del(u8 mode)
{
struct audio_codec_clk_context *ctx;
int next_clk = 0;
u32 remove_clk = 0;
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->mode == mode) {
goto clock_del;
}
}
return;
clock_del:
list_del(&ctx->entry);
if (ctx->params.background) {
audio_codec_background_clock_del(ctx->params.clk);
remove_clk = ctx->params.clk;
}
free(ctx);
if (!list_empty(&codec_clock_head)) {
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (ctx) {
next_clk = ctx->params.clk;
}
} else {
u32 current_clk = clk_get("sys");
#if (TCFG_BD_NUM == 2)&&(TCFG_BT_SUPPORT_AAC==1)
if ((mode == AUDIO_A2DP_MODE) && (get_total_connect_dev() > 1)) {
next_clk = current_clk - remove_clk;
} else {
if (remove_clk) {
next_clk = current_clk - remove_clk;
} else {
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
}
}
#else
if (remove_clk) {
next_clk = current_clk - remove_clk;
} else {
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
}
#endif
}
if (!next_clk || next_clk < AUDIO_CODEC_BASE_CLK) {
next_clk = list_empty(&codec_clock_head) ? clk_get("sys") : AUDIO_CODEC_BASE_CLK;
}
clk_set("sys", next_clk);
}
void audio_codec_clock_check(void)
{
struct audio_codec_clk_context *ctx;
if (!list_empty(&codec_clock_head)) {
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (!ctx) {
return;
}
u32 current_clk = clk_get("sys");
u32 expect_clk = ctx->params.background ? (ctx->params.clk + 12 * 1000000L) : ctx->params.clk;
if ((current_clk < 192 * 1000000L) && current_clk < expect_clk) {
log_error("Audio codec clock error : %dM, %dM.", current_clk / 1000000, expect_clk / 1000000);
clk_set("sys", expect_clk);
}
}
}

View File

@ -0,0 +1,55 @@
/*****************************************************************
>file name : audio_codec_clock.h
>create time : Thu 03 Jun 2021 09:36:25 AM CST
*****************************************************************/
#ifndef _AUDIO_CODEC_CLOCK_H_
#define _AUDIO_CODEC_CLOCK_H_
#include "audio_base.h"
enum {
AUDIO_A2DP_MODE = 0,
AUDIO_ESCO_MODE,
AUDIO_TONE_MODE,
AUDIO_FILE_MODE,
AUDIO_PC_MODE,
AUDIO_USB_MIC_MODE,
SMART_VOICE_MODE,
SPATIAL_EFFECT_MODE,
SPEAK_TO_CHAT_MODE,
ANC_EAR_ADAPTIVE_MODE,
ANC_DUT_SZ_FFT_MODE,
AUDIO_MAX_MODE,
};
/*************************************************************************
* 音频编解码时钟设置
*
* Input : mode - 音频模式coding_type - 模式下的解码格式
* preemption - 打断/叠加.
* Output : 0 - 成功, 非0 - 出错.
* Notes : 目前在耳机SDK用于A2DP/ESCO/TONE三个模式的时钟切换.
* History : 2021/06/03 初始版本
*=======================================================================*/
int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption);
/*************************************************************************
* 音频编解码时钟删除
*
* Input : mode - 音频模式
* Output : 无.
* Notes : 需和audio_codec_clock_set结对使用.
* History : 2021/06/03 初始版本
*=======================================================================*/
void audio_codec_clock_del(u8 mode);
/*************************************************************************
* 音频编解码时钟检查
*
* Input : 无
* Output : 无.
* Notes : 检查音频使用中是否有时钟被修改的情况并报错
* History : 2021/11/18
*=======================================================================*/
void audio_codec_clock_check(void);
#endif

View File

@ -0,0 +1,304 @@
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "classic/hci_lmp.h"
#include "aec_user.h"
#include "asm/audio_src.h"
#include "audio_enc.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
#endif
#include "app_main.h"
#include "btstack/avctp_user.h"
#if 1//(TCFG_ENC_OPUS_ENABLE) || (TCFG_ENC_SPEEX_ENABLE)
extern struct audio_encoder_task *encode_task;
//static struct audio_encoder_task *encode_task = NULL;
#define ENC_ADC_BUF_NUM (2)
#if TCFG_AUDIO_ANC_ENABLE
//JL701N打开ANCADC需要使用相同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打开ANCADC需要使用相同buffer和中断点数
extern s16 esco_adc_buf[];
audio_adc_mic_set_buffs(&mic_enc->mic_ch, esco_adc_buf,
ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
#else
audio_adc_mic_set_buffs(&mic_enc->mic_ch, mic_enc->adc_buf,
ENC_ADC_IRQ_POINTS * 2, ENC_ADC_BUF_NUM);
#endif/*TCFG_AUDIO_ANC_ENABLE*/
mic_enc->adc_output.handler = adc_mic_output_handler;
audio_adc_add_output_handler(&adc_hdl, &mic_enc->adc_output);
//app_audio_output_samplerate_set(44100);
//app_audio_output_start();
audio_adc_mic_start(&mic_enc->mic_ch);
#endif
printf("mic_enc_open ok %d\n", start_err);
return 0;
__err:
audio_encoder_close(&mic_enc->encoder);
local_irq_disable();
free(mic_enc);
mic_enc = NULL;
local_irq_enable();
return err;
}
int audio_mic_enc_close()
{
if (!mic_enc) {
return -1;
}
printf("audio_mic_enc_close\n");
#if MIC_USE_MIC_CHANNEL
audio_adc_mic_close(&mic_enc->mic_ch);
#if TCFG_AUDIO_ANC_ENABLE
if (anc_status_get() == 0) {
audio_mic_pwr_ctl(MIC_PWR_OFF);
}
#else
audio_mic_pwr_ctl(MIC_PWR_OFF);
#endif
audio_adc_del_output_handler(&adc_hdl, &mic_enc->adc_output);
#endif
mic_enc_resume();
audio_encoder_close(&mic_enc->encoder);
/* if (encode_task) { */
/* audio_encoder_task_del(encode_task); */
/* free(encode_task); */
/* encode_task = NULL; */
/* } */
free(mic_enc);
mic_enc = NULL;
printf("audio_mic_enc_close end\n");
return 0;
}
#endif

208
cpu/br28/audio_config.h Normal file
View File

@ -0,0 +1,208 @@
#ifndef _APP_AUDIO_H_
#define _APP_AUDIO_H_
#include "generic/typedef.h"
#include "board_config.h"
#if BT_SUPPORT_MUSIC_VOL_SYNC
#define TCFG_MAX_VOL_PROMPT 0
#else
#define TCFG_MAX_VOL_PROMPT 1
#endif
//*********************************************************************************//
// USB Audio配置 //
//*********************************************************************************//
/*usb mic的数据是否经过CVP,包括里面的回音消除(AEC)、非线性回音压制(NLP)、降噪(ANS)模块*/
#define TCFG_USB_MIC_CVP_ENABLE DISABLE_THIS_MOUDLE
#define TCFG_USB_MIC_CVP_MODE (ANS_EN | NLP_EN)
//*********************************************************************************//
// CVP配置 //
//*********************************************************************************//
//麦克风阵列校准使能
#define TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE 0
//上行同步使能
#define TCFG_AUDIO_CVP_SYNC 0
/*
*该配置适用于没有音量按键的产品,防止打开音量同步之后
*连接支持音量同步的设备,将音量调小过后,连接不支持音
*量同步的设备,音量没有恢复,导致音量小的问题
*/
#define TCFG_VOL_RESET_WHEN_NO_SUPPORT_VOL_SYNC 0 //不支持音量同步的设备默认最大音量
#define MC_BIAS_ADJUST_DISABLE 0 //省电容mic偏置校准关闭
#define MC_BIAS_ADJUST_ONE 1 //省电容mic偏置只校准一次跟dac trim一样
#define MC_BIAS_ADJUST_POWER_ON 2 //省电容mic偏置每次上电复位都校准(Power_On_Reset)
#define MC_BIAS_ADJUST_ALWAYS 3 //省电容mic偏置每次开机都校准(包括上电复位和其他复位)
/*
*省电容mic偏置电压自动调整(因为校准需要时间,所以有不同的方式)
*1、烧完程序完全更新包括配置区开机校准一次
*2、上电复位的时候都校准,即断电重新上电就会校准是否有偏差(默认)
*3、每次开机都校准不管有没有断过电即校准流程每次都跑
*/
#define TCFG_MC_BIAS_AUTO_ADJUST MC_BIAS_ADJUST_DISABLE
#define TCFG_ESCO_PLC 1 //通话丢包修复
#define TCFG_AEC_ENABLE 1 //通话回音消除使能
#define TCFG_AUDIO_CONFIG_TRACE 0 //音频模块配置跟踪查看
#define TCFG_DIG_PHASE_INVERTER_EN 0 //数字反相器用来矫正DAC的输出相位(AC701N输出正相默认关)
#define MAX_ANA_VOL (3) //系统最大模拟音量 (0-3)
#define MAX_COM_VOL (16) // 具体数值应小于联合音量等级的数组大小 (combined_vol_list)
#define MAX_DIG_VOL (16)
/*
数字音量等级表生成参数(软件数字音量和硬件数字音量共用两个参数)
修改 DIG_VOL_MAX_VALUE 也要留意一下 DIG_VOL_STEP 参数,避免在小音量等级时候音量太小。
*/
#if TCFG_AUDIO_HEARING_AID_ENABLE
#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_L_DIFF)
#define DIG_VOL_MAX_VALUE (-5.0f) // 数字音量最大值(单位:dB)
#elif (TCFG_AUDIO_DAC_MODE == DAC_MODE_H1_DIFF)
#define DIG_VOL_MAX_VALUE (-8.0f) // 数字音量最大值(单位:dB)
#else
#define DIG_VOL_MAX_VALUE (0.0f) // 数字音量最大值(单位:dB)
#endif
#define DIG_VOL_STEP (3.0f) // 逐级递减差值(单位:dB)
/*
*ANC下当数字音量大于-6dB时会导致播歌失真以下任意一种方式都可解决, SDK默认第一种
*1、数字音量限制在-6dB以下
*2、开启音乐动态增益ANC_MUSIC_DYNAMIC_GAIN_EN
*/
#if (TCFG_AUDIO_ANC_ENABLE)
#define ANC_MODE_DIG_VOL_LIMIT (-6.0f)
#endif/*TCFG_AUDIO_ANC_ENABLE*/
/*
*软件数字音量表自定义
* 0:使用软件数字音量文件中的默认数组
* 1:按上面设置的参数重新生成
*/
#define SW_DIG_VOL_TAB_USER_DEFINED 0
#if ((SYS_VOL_TYPE == VOL_TYPE_DIGITAL) || (SYS_VOL_TYPE == VOL_TYPE_DIGITAL_HW))
#define SYS_MAX_VOL MAX_DIG_VOL
#define SYS_DEFAULT_VOL 0//SYS_MAX_VOL
#define SYS_DEFAULT_TONE_VOL 8
#define SYS_DEFAULT_SIN_VOL 6
#elif (SYS_VOL_TYPE == VOL_TYPE_AD)
#define SYS_MAX_VOL MAX_COM_VOL
#define SYS_DEFAULT_VOL SYS_MAX_VOL
#define SYS_DEFAULT_TONE_VOL 14
#define SYS_DEFAULT_SIN_VOL 8
#else
#error "SYS_VOL_TYPE define error"
#endif
/*数字音量最大值定义*/
#define DEFAULT_DIGITAL_VOLUME 16384
#define BT_MUSIC_VOL_LEAVE_MAX 16 /*高级音频音量等级*/
#define BT_MUSIC_VOL_STEP (-3.0f) /*高级音频音量等级衰减步进*/
#define BT_CALL_VOL_LEAVE_MAX 15 /*通话音量等级*/
#define BT_CALL_VOL_STEP (-2.0f) /*通话音量等级衰减步进*/
/*
*audio state define
*/
#define APP_AUDIO_STATE_IDLE 0
#define APP_AUDIO_STATE_MUSIC 1
#define APP_AUDIO_STATE_CALL 2
#define APP_AUDIO_STATE_WTONE 3
#define APP_AUDIO_STATE_LINEIN 4
#define APP_AUDIO_CURRENT_STATE 5
#define APP_AUDIO_MAX_STATE (APP_AUDIO_CURRENT_STATE + 1)
#define AUDIO_OUTPUT_INCLUDE_BT ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_BT)) \
|| ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_BT))
#define AUDIO_OUTPUT_INCLUDE_FM ((defined(AUDIO_OUTPUT_WAY)) && (AUDIO_OUTPUT_WAY == AUDIO_OUTPUT_WAY_FM)) \
|| ((defined(AUDIO_OUT_WAY_TYPE)) && (AUDIO_OUT_WAY_TYPE & AUDIO_WAY_TYPE_FM))
#if TCFG_MIC_EFFECT_ENABLE
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_REVERB_SAMPLERATE_DEFUAL)
#elif (TCFG_AD2DA_LOW_LATENCY_ENABLE || TCFG_AUDIO_HEARING_AID_ENABLE)
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (TCFG_AD2DA_LOW_LATENCY_SAMPLE_RATE)
#elif TCFG_SIDETONE_ENABLE
#define TCFG_AUDIO_DAC_MIX_ENABLE (1)
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
#else
#define TCFG_AUDIO_DAC_MIX_ENABLE (0)
#define TCFG_AUDIO_DAC_MIX_SAMPLE_RATE (44100)
#endif
u8 get_max_sys_vol(void);
u8 get_tone_vol(void);
s8 app_audio_get_volume(u8 state);
s8 app_audio_get_volume_r(u8 state);
void app_audio_set_volume(u8 state, s8 volume, u8 fade);
void app_audio_set_volume_each_channel(u8 state, s8 volume_l, s8 volume_r, u8 fade);
void app_audio_volume_up(u8 value);
void app_audio_volume_down(u8 value);
void app_audio_volume_set(u8 value);
void app_audio_state_switch(u8 state, s16 max_volume);
void app_audio_mute(u8 value);
s16 app_audio_get_max_volume(void);
void app_audio_state_switch(u8 state, s16 max_volume);
void app_audio_state_exit(u8 state);
void app_audio_set_max_volume(u8 state, s16 max_volume);
u8 app_audio_get_state(void);
void volume_up_down_direct(s8 value);
void app_audio_set_mix_volume(u8 front_volume, u8 back_volume);
void app_audio_set_digital_volume(s16 volume);
void app_set_sys_vol(s16 vol_l, s16 vol_r);
void app_set_max_vol(s16 vol);
void audio_volume_list_init(u8 cfg_en);
u32 phone_call_eq_open();
int eq_mode_sw();
int mic_test_start();
int mic_test_stop();
void dac_power_on(void);
void dac_power_off(void);
/*打印audio模块的数字模拟增益DAC/ADC*/
void audio_gain_dump();
void audio_adda_dump(void); //打印所有的dac,adc寄存器
void app_audio_volume_init(void);
void app_audio_output_init(void);
int app_audio_output_mode_set(u8 output);
int app_audio_output_mode_get(void);
int app_audio_output_channel_get(void);
int app_audio_output_channel_set(u8 channel);
int app_audio_output_write(void *buf, int len);
int app_audio_output_samplerate_select(u32 sample_rate, u8 high);
int app_audio_output_samplerate_set(int sample_rate);
int app_audio_output_samplerate_get(void);
int app_audio_output_start(void);
int app_audio_output_stop(void);
int audio_dac_trim_value_check(struct audio_dac_trim *dac_trim);
int esco_enc_reset(void);
u8 bt_phone_dec_is_running();
u8 bt_media_is_running(void);
void a2dp_dec_dut_enable(u8 dut_enable);
#endif/*_APP_AUDIO_H_*/

652
cpu/br28/audio_cvp_dut.c Normal file
View File

@ -0,0 +1,652 @@
/*
****************************************************************************
* Audio CVP DUT
*
*
****************************************************************************
*/
#include "audio_cvp_dut.h"
#include "online_db_deal.h"
#include "system/includes.h"
#include "app_config.h"
#include "audio_adc.h"
#include "anc.h"
#include "aec_user.h"
#include "app_main.h"
#include "user_cfg_id.h"
#include "audio_config.h"
#include "math.h"
#if 0
#define cvp_dut_log printf
#define cvp_dut_put_float put_float
#else
#define cvp_dut_log(...)
#define cvp_dut_put_float(...)
#endif
#define CVP_DUT_BIG_ENDDIAN 1 //大端数据输出
#define CVP_DUT_LITTLE_ENDDIAN 2 //小端数据输出
#define CVP_DUT_OUTPUT_WAY CVP_DUT_LITTLE_ENDDIAN
#if TCFG_AUDIO_CVP_DUT_ENABLE
static cvp_dut_t *cvp_dut_hdl = NULL;
static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
int cvp_dut_new_rx_packet(u8 *dat, u8 len);
int cvp_dut_spp_rx_packet(u8 *dat, u8 len);
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
extern void audio_aec_output_sel(u8 sel, u8 agc);
#endif/*TCFG_AUDIO_TRIPLE_MIC_ENABLE*/
extern void put_float(double fv);
extern void sys_enter_soft_poweroff(void *priv);
extern int audio_aec_toggle_set(u8 toggle);
/*未经过算法处理主要用于分析ANC MIC的频响*/
int cvp_dut_bypass_mic_ch_sel(u8 mic_num)
{
if (cvp_dut_hdl) {
switch (mic_num) {
case A_MIC0:
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_0;
break;
case A_MIC1:
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_1;
break;
case A_MIC2:
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_2;
break;
case A_MIC3:
cvp_dut_hdl->mic_ch_sel = AUDIO_ADC_MIC_3;
break;
default:
break;
}
}
return 0;
}
u8 cvp_dut_mic_ch_get(void)
{
if (cvp_dut_hdl) {
return cvp_dut_hdl->mic_ch_sel;
}
return 0;
}
u8 cvp_dut_mode_get(void)
{
if (cvp_dut_hdl) {
return cvp_dut_hdl->mode;
}
return 0;
}
void cvp_dut_mode_set(u8 mode)
{
if (cvp_dut_hdl) {
cvp_dut_hdl->mode = mode;
}
}
int cvp_dut_event_deal(u8 *dat)
{
if (cvp_dut_hdl) {
switch (dat[3]) {
#if TCFG_AUDIO_DUAL_MIC_ENABLE
//双麦ENC DUT 事件处理
case CVP_DUT_DMS_MASTER_MIC:
cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
break;
case CVP_DUT_DMS_SLAVE_MIC:
cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
break;
case CVP_DUT_DMS_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
break;
#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
case CVP_DUT_3MIC_MASTER_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(1, 0);
break;
case CVP_DUT_3MIC_SLAVE_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(2, 0);
break;
case CVP_DUT_3MIC_FB_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(3, 0);
break;
case CVP_DUT_3MIC_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(0, 0);
break;
#else
//单麦SMS/DNS DUT 事件处理
case CVP_DUT_DMS_MASTER_MIC:
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(0);
break;
case CVP_DUT_DMS_OPEN_ALGORITHM:
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(1);
break;
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
#if TCFG_AUDIO_ANC_ENABLE
case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH & ANC_L_CH) {
cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
} else {
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
}
break;
case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH & ANC_L_CH) {
cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
} else {
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
}
break;
case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
}
break;
case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
}
break;
case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
cvp_dut_log("CMD:CVP_DUT_RESUME\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
break;
#endif/*TCFG_AUDIO_ANC_ENABLE*/
//JL自研算法指令API
#if !TCFG_CVP_DEVELOP_ENABLE
case CVP_DUT_NS_OPEN:
cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
break;
case CVP_DUT_NS_CLOSE:
cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
break;
#endif/*TCFG_CVP_DEVELOP_ENABLE*/
case CVP_DUT_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(1);
break;
case CVP_DUT_CLOSE_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(0);
break;
case CVP_DUT_POWEROFF:
cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
sys_enter_soft_poweroff(NULL);
break;
default:
cvp_dut_log("CMD:UNKNOW CMD!!!\n");
return CVP_DUT_ACK_ERR_UNKNOW;
}
return CVP_DUT_ACK_SUCCESS;
}
return CVP_DUT_ACK_ERR_UNKNOW;
}
void cvp_dut_init(void)
{
cvp_dut_log("tx dat");
if (cvp_dut_hdl == NULL) {
cvp_dut_hdl = zalloc(sizeof(cvp_dut_t));
}
//开机默认设置成算法模式
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
app_online_db_register_handle(DB_PKT_TYPE_DMS, cvp_dut_app_online_parse);
}
void cvp_dut_unit(void)
{
free(cvp_dut_hdl);
cvp_dut_hdl = NULL;
}
int cvp_dut_spp_tx_packet(u8 command)
{
if (cvp_dut_hdl) {
cvp_dut_hdl->tx_buf.magic = CVP_DUT_SPP_MAGIC;
cvp_dut_hdl->tx_buf.dat[0] = 0;
cvp_dut_hdl->tx_buf.dat[1] = 0;
cvp_dut_hdl->tx_buf.dat[2] = 0;
cvp_dut_hdl->tx_buf.dat[3] = command;
cvp_dut_log("tx dat");
#if CVP_DUT_OUTPUT_WAY == CVP_DUT_LITTLE_ENDDIAN // 小端格式
cvp_dut_hdl->tx_buf.crc = CRC16((&cvp_dut_hdl->tx_buf.dat), CVP_DUT_PACK_NUM - 4);
put_buf((u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)&cvp_dut_hdl->tx_buf.magic, CVP_DUT_PACK_NUM);
#else
u16 crc_temp;
int i;
u8 dat[CVP_DUT_PACK_NUM];
u8 dat_temp;
memcpy(dat, &(cvp_dut_hdl->tx_buf), CVP_DUT_PACK_NUM);
crc_temp = CRC16(dat + 4, 6);
printf("crc0x%x,0x%x", crc_temp, cvp_dut_hdl->tx_buf.crc);
for (i = 0; i < 6; i += 2) { //小端数据转大端
dat_temp = dat[i];
dat[i] = dat[i + 1];
dat[i + 1] = dat_temp;
}
crc_temp = CRC16(dat + 4, CVP_DUT_PACK_NUM - 4);
dat[2] = crc_temp >> 8;
dat[3] = crc_temp & 0xff;
put_buf(dat, CVP_DUT_PACK_NUM);
app_online_db_send(DB_PKT_TYPE_DMS, dat, CVP_DUT_PACK_NUM);
#endif
}
return 0;
}
static int cvp_dut_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size)
{
if (cvp_dut_hdl) {
cvp_dut_hdl->parse_seq = ext_data[1];
int ret = cvp_dut_spp_rx_packet(packet, size);
if (ret) {
cvp_dut_new_rx_packet(packet, size);
}
}
return 0;
}
int cvp_dut_spp_rx_packet(u8 *dat, u8 len)
{
if (cvp_dut_hdl) {
u8 dat_temp;
u16 crc = 0;
int ret = 0;
u8 dat_packet[CVP_DUT_PACK_NUM];
if (len > CVP_DUT_PACK_NUM) {
return 1;
}
/* cvp_dut_log("rx dat,%d\n", CVP_DUT_PACK_NUM); */
put_buf(dat, len);
memcpy(dat_packet, dat, len);
crc = CRC16(dat + 4, len - 4);
#if CVP_DUT_OUTPUT_WAY == CVP_DUT_BIG_ENDDIAN // 大端格式
for (int i = 0; i < 6; i += 2) { // 大端数据转小端
dat_temp = dat_packet[i];
dat_packet[i] = dat_packet[i + 1];
dat_packet[i + 1] = dat_temp;
}
#endif
cvp_dut_log("rx dat_packet");
memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, 4);
if (cvp_dut_hdl->rx_buf.magic == CVP_DUT_SPP_MAGIC) {
cvp_dut_log("crc %x,cvp_dut_hdl->rx_buf.crc %x\n", crc, cvp_dut_hdl->rx_buf.crc);
if (cvp_dut_hdl->rx_buf.crc == crc || cvp_dut_hdl->rx_buf.crc == 0x1) {
memcpy(&(cvp_dut_hdl->rx_buf), dat_packet, len);
ret = cvp_dut_event_deal(cvp_dut_hdl->rx_buf.dat);
cvp_dut_spp_tx_packet(ret); //反馈收到命令
return 0;
}
}
}
return 1;
}
/***************************************************************************
CVP SPP产测 NEW STRUCT
***************************************************************************/
struct cvp_dut_packet_t {
u8 cmd; //命令
u16 len; //参数长度
u8 dat[0]; //参数
} __attribute__((packed));
struct cvp_dut_head_t {
u16 magic; //标识符
u16 crc; //CRC, 从packet开始计算
struct cvp_dut_packet_t packet;
} __attribute__((packed));
/*
CVP 命令处理函数
param: struct cvp_dut_head_t 类型的数据
return 执行结果
*/
int cvp_dut_new_event_deal(void *packet)
{
struct cvp_dut_packet_t *hdl = (struct cvp_dut_packet_t *)packet;
u16 len = hdl->len;
int wlen = 0;
int ret = -1;
u8 last_mode, reset_flag;
cvp_dut_log("CVP_DUT CMD:0X%x,LEN:%d\n", hdl->cmd, len);
put_buf((u8 *)packet, hdl->len + sizeof(struct cvp_dut_packet_t));
if (cvp_dut_hdl) {
reset_flag = 0;
last_mode = cvp_dut_hdl->mode;
switch (hdl->cmd) {
#if TCFG_AUDIO_DUAL_MIC_ENABLE
//双麦ENC DUT 事件处理
case CVP_DUT_DMS_MASTER_MIC:
cvp_dut_log("CMD:CVP_DUT_DMS_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_MASTER, 0);
break;
case CVP_DUT_DMS_SLAVE_MIC:
cvp_dut_log("CMD:CVP_DUT_DMS_SLAVE_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_SLAVE, 0);
break;
case CVP_DUT_DMS_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_DMS_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(DMS_OUTPUT_SEL_DEFAULT, 1);
break;
#elif TCFG_AUDIO_TRIPLE_MIC_ENABLE
case CVP_DUT_3MIC_MASTER_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(1, 0);
break;
case CVP_DUT_3MIC_SLAVE_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_SLAVE_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(2, 0);
break;
case CVP_DUT_3MIC_FB_MIC:
cvp_dut_log("CMD:CVP_DUT_3MIC_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(3, 0);
break;
case CVP_DUT_3MIC_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_3MIC_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_output_sel(0, 0);
break;
#else
//单麦SMS/DNS DUT 事件处理
case CVP_DUT_DMS_MASTER_MIC:
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_MASTER_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(0);
break;
case CVP_DUT_DMS_OPEN_ALGORITHM:
cvp_dut_log("CMD:SMS/CVP_DUT_DMS_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(1);
break;
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
#if TCFG_AUDIO_ANC_ENABLE
case CVP_DUT_FF_MIC: //TWS_FF_MIC测试 或者 头戴式FF_L_MIC测试
cvp_dut_log("CMD:CVP_DUT_FF_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH & ANC_L_CH) {
cvp_dut_bypass_mic_ch_sel(ANCL_FF_MIC);
} else {
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
}
reset_flag = 1;
break;
case CVP_DUT_FB_MIC: //TWS_FB_MIC测试 或者 头戴式FB_L_MIC测试
cvp_dut_log("CMD:CVP_DUT_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH & ANC_L_CH) {
cvp_dut_bypass_mic_ch_sel(ANCL_FB_MIC);
} else {
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
}
reset_flag = 1;
break;
case CVP_DUT_HEAD_PHONE_R_FF_MIC: //头戴式FF_R_MIC测试
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FF_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
cvp_dut_bypass_mic_ch_sel(ANCR_FF_MIC);
}
reset_flag = 1;
break;
case CVP_DUT_HEAD_PHONE_R_FB_MIC: //头戴式FB_R_MIC测试
cvp_dut_log("CMD:CVP_DUT_HEAD_PHONE_R_FB_MIC\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_BYPASS;
if (ANC_CH == (ANC_L_CH | ANC_R_CH)) {
cvp_dut_bypass_mic_ch_sel(ANCR_FB_MIC);
}
reset_flag = 1;
break;
case CVP_DUT_MODE_ALGORITHM_SET: //CVP恢复正常模式
cvp_dut_log("CMD:CVP_DUT_RESUME\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
break;
#endif/*TCFG_AUDIO_ANC_ENABLE*/
//JL自研算法指令API
#if !TCFG_CVP_DEVELOP_ENABLE
case CVP_DUT_NS_OPEN:
cvp_dut_log("CMD:CVP_DUT_NS_OPEN\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_cvp_ioctl(CVP_NS_SWITCH, 1, NULL); //降噪关
break;
case CVP_DUT_NS_CLOSE:
cvp_dut_log("CMD:CVP_DUT_NS_CLOSE\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_cvp_ioctl(CVP_NS_SWITCH, 0, NULL); //降噪开
break;
#endif/*TCFG_CVP_DEVELOP_ENABLE*/
case CVP_DUT_OPEN_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_OPEN_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(1);
break;
case CVP_DUT_CLOSE_ALGORITHM:
cvp_dut_log("CMD:CVP_DUT_CLOSE_ALGORITHM\n");
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_aec_toggle_set(0);
break;
case CVP_DUT_POWEROFF:
cvp_dut_log("CMD:CVP_DUT_POWEROFF\n");
sys_enter_soft_poweroff(NULL);
break;
/*enc麦克风校准补偿*/
#if TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE
case CVP_ENC_MIC_DIFF_CMP_SET: //主MIC - 副MIC
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_SET\n");
float diff;
memcpy((u8 *)&diff, hdl->dat, len);
cvp_dut_log("diff:");
cvp_dut_put_float(diff);
float dms_mic_diff = log10(app_var.enc_degradation) * 20;
app_var.audio_mic_array_diff_cmp = pow(10, (diff + dms_mic_diff) / 20);
wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
printf("mic array diff cap vm write fail !!!");
ret = CVP_DUT_ACK_VM_WRITE_ERR;
}
cvp_dut_log("mic_array_diff_cmp:");
cvp_dut_put_float(app_var.audio_mic_array_diff_cmp);
break;
case CVP_ENC_MIC_DIFF_CMP_EN:
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_EN\n");
u8 en;
memcpy(&en, hdl->dat, len);
app_var.audio_mic_array_trim_en = en;
wlen = syscfg_write(CFG_MIC_ARRAY_TRIM_EN, (u8 *)(&app_var.audio_mic_array_trim_en), sizeof(app_var.audio_mic_array_trim_en));
if (wlen != sizeof(app_var.audio_mic_array_trim_en)) {
cvp_dut_log("mic array trim en vm write fail !!!");
ret = CVP_DUT_ACK_VM_WRITE_ERR;
}
cvp_dut_log("mic array trim en: %d\n", app_var.audio_mic_array_trim_en);
break;
case CVP_ENC_MIC_DIFF_CMP_CLEAN:
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
app_var.audio_mic_array_diff_cmp = 1.0f;
app_var.audio_mic_cmp.talk = 1.0f;
app_var.audio_mic_cmp.ff = 1.0f;
app_var.audio_mic_cmp.fb = 1.0f;
wlen = syscfg_write(CFG_MIC_ARRAY_DIFF_CMP_VALUE, (u8 *)(&app_var.audio_mic_array_diff_cmp), sizeof(app_var.audio_mic_array_diff_cmp));
if (wlen != sizeof(app_var.audio_mic_array_diff_cmp)) {
cvp_dut_log("mic array diff cap vm write fail !!!");
ret = CVP_DUT_ACK_VM_WRITE_ERR;
}
wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
if (wlen != sizeof(audio_mic_cmp_t)) {
printf("mic array diff cap vm write fail !!!");
ret = CVP_DUT_ACK_VM_WRITE_ERR;
}
cvp_dut_log("CMD:CVP_ENC_MIC_DIFF_CMP_CLEAN\n");
break;
case CVP_ENC_TARGET_MIC_DIFF_SET:
cvp_dut_log("CMD:CVP_ENC_TARGET_MIC_DIFF_SET\n");
float talk_diff, ff_diff, fb_diff;
memcpy((u8 *)&talk_diff, hdl->dat, 4);
memcpy((u8 *)&ff_diff, hdl->dat + 4, 4);
memcpy((u8 *)&fb_diff, hdl->dat + 8, 4);
cvp_dut_log("talk_diff:");
cvp_dut_put_float(talk_diff);
cvp_dut_log("ff_diff:");
cvp_dut_put_float(ff_diff);
cvp_dut_log("fb_diff:");
cvp_dut_put_float(fb_diff);
app_var.audio_mic_cmp.talk = pow(10, (talk_diff) / 20);
app_var.audio_mic_cmp.ff = pow(10, (ff_diff) / 20);
app_var.audio_mic_cmp.fb = pow(10, (fb_diff) / 20);
wlen = syscfg_write(CFG_MIC_TARGET_DIFF_CMP, (u8 *)(&app_var.audio_mic_cmp), sizeof(audio_mic_cmp_t));
if (wlen != sizeof(audio_mic_cmp_t)) {
printf("mic array diff cap vm write fail !!!");
ret = CVP_DUT_ACK_VM_WRITE_ERR;
}
break;
#endif /*TCFG_AUDIO_MIC_ARRAY_TRIM_ENABLE*/
/*通话算法模块开关*/
case CVP_DUT_CVP_IOCTL:
cvp_dut_log("CMD:CVP_DUT_CVP_IOCTL\n");
u8 ioctl_cmd = hdl->dat[0];
u8 toggle = hdl->dat[1];
cvp_dut_log(" io ctl cmd %d, toggle %d", ioctl_cmd, toggle);
cvp_dut_hdl->mode = CVP_DUT_MODE_ALGORITHM;
audio_cvp_ioctl(ioctl_cmd, toggle, NULL);
break;
case CVP_DUT_DEC_DUT_SET:
cvp_dut_log("CVP_DUT_DEC_DUT_SET: %d\n", hdl->dat[0]);
cvp_dut_hdl->dec_dut_enable = hdl->dat[0];
a2dp_dec_dut_enable(cvp_dut_hdl->dec_dut_enable);
break;
default:
cvp_dut_log("CMD:UNKNOW CMD!!!\n");
ret = CVP_DUT_ACK_ERR_UNKNOW;
}
if (last_mode != cvp_dut_hdl->mode) {
reset_flag = 1; //模式被修改,则复位通话
}
if (reset_flag) {
if (bt_phone_dec_is_running()) {
esco_enc_reset();
}
}
ret = (ret == -1) ? CVP_DUT_ACK_SUCCESS : ret;
}
return ret;
}
//len = 参数数据长度(不包括cmd)
int cvp_dut_new_tx_packet(u8 cmd, u8 *data, int len)
{
if (cvp_dut_hdl) {
int packet_len = sizeof(struct cvp_dut_head_t) + len;
struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)malloc(packet_len);
head->magic = CVP_DUT_NEW_SPP_MAGIC;
head->packet.cmd = cmd;
head->packet.len = len;
head->crc = CRC16(&head->packet, packet_len - 4);
if (len) {
memcpy(head->packet.dat, data, len);
}
cvp_dut_log("tx new_dat_packet %d\n", packet_len);
//put_buf((u8 *)head, packet_len);
app_online_db_send(DB_PKT_TYPE_DMS, (u8 *)head, packet_len);
free(head);
}
return 0;
}
int cvp_dut_new_rx_packet(u8 *dat, u8 len)
{
u16 crc = 0;
int ret = 0;
struct cvp_dut_head_t *head = (struct cvp_dut_head_t *)dat;
if (cvp_dut_hdl) {
cvp_dut_log("rx new_dat_packet");
//put_buf(dat, len);
crc = CRC16(&head->packet, len - 4);
if (head->magic == CVP_DUT_NEW_SPP_MAGIC) {
if (head->crc == crc || head->crc == 0x1) {
ret = cvp_dut_new_event_deal(&head->packet);
cvp_dut_new_tx_packet(ret, NULL, 0); //反馈收到命令
if (ret == CVP_DUT_ACK_SUCCESS) {
return 0;
}
} else {
cvp_dut_log("ERR head->crc %x != %x\n", head->crc, crc);
cvp_dut_new_tx_packet(CVP_DUT_ACK_CRC_ERR, NULL, 0); //反馈收到命令
}
}
}
return 1;
}
/*
DEC产测状态获取
param: music_decide 1 需判断播歌状态; 0 不需判断
*/
u8 audio_dec_dut_en_get(u8 music_decide)
{
if (!cvp_dut_hdl) {
return 0;
}
if (music_decide && !bt_media_is_running()) {
//当前非播歌状态
return 0;
}
return cvp_dut_hdl->dec_dut_enable;
}
#endif /*TCFG_AUDIO_CVP_DUT_ENABLE*/

121
cpu/br28/audio_cvp_dut.h Normal file
View File

@ -0,0 +1,121 @@
#ifndef _AUDIO_CVP_DUT_H_
#define _AUDIO_CVP_DUT_H_
#include "generic/typedef.h"
/*******************CVP测试命令集*********************/
#define CVP_DUT_DMS_MASTER_MIC 0x01 //DMS-测试主MIC SMS-关闭CVP算法
#define CVP_DUT_DMS_SLAVE_MIC 0x02 //DMS-测试副MIC
#define CVP_DUT_DMS_OPEN_ALGORITHM 0x03 //DMS-测试dms算法 SMS-打开CVP算法
#define CVP_DUT_NS_OPEN 0x04 //打开NS模块
#define CVP_DUT_NS_CLOSE 0x05 //关闭NS模块
//ANC MIC 频响测试指令且需切换到CVP_DUT_MODE_BYPASS在通话HFP前设置
#define CVP_DUT_FF_MIC 0x06 //测试TWS FF MIC/头戴式左耳FF_MIC
#define CVP_DUT_FB_MIC 0x07 //测试TWS FB MIC/头戴式左耳FB_MIC
#define CVP_DUT_HEAD_PHONE_R_FF_MIC 0x08 //测试头戴式右耳FF_MIC
#define CVP_DUT_HEAD_PHONE_R_FB_MIC 0x09 //测试头戴式右耳FB_MIC
#define CVP_DUT_OPEN_ALGORITHM 0x0a //CVP算法开启
#define CVP_DUT_CLOSE_ALGORITHM 0x0b //CVP算法关闭
#define CVP_DUT_MODE_ALGORITHM_SET 0x0c //CVP_DUT 开关算法模式
#define CVP_DUT_POWEROFF 0x0d //耳机关机指令
#define CVP_ENC_MIC_DIFF_CMP_SET 0x0f //设置补偿值(主MIC - 副MIC)
#define CVP_ENC_MIC_DIFF_CMP_EN 0x10 //补偿使能
#define CVP_ENC_MIC_DIFF_CMP_CLEAN 0x11 //清除补偿
//三麦通话测试指令
#define CVP_DUT_3MIC_MASTER_MIC CVP_DUT_DMS_MASTER_MIC //测试三麦算法主麦频响
#define CVP_DUT_3MIC_SLAVE_MIC CVP_DUT_DMS_SLAVE_MIC //测试三麦算法副麦频响
#define CVP_DUT_3MIC_FB_MIC 0x0e //测试三麦算法FBmic频响
#define CVP_DUT_3MIC_OPEN_ALGORITHM CVP_DUT_DMS_OPEN_ALGORITHM //测试三麦算法副麦频响
#define CVP_DUT_CVP_IOCTL 0x12 //CVP算法单元独立控制
#define CVP_DUT_DEC_DUT_SET 0x13 //DEC 产测模式设置 (bypass数据处理)
#define CVP_ENC_TARGET_MIC_DIFF_SET 0x14 //设置MIC与目标金机MIC的差值(主-副-FB)
//命令回复
#define CVP_DUT_ACK_SUCCESS 0x01 //命令接收成功
//错误回复
#define CVP_DUT_ACK_ERR_UNKNOW 0xA1 //未知命令
#define CVP_DUT_ACK_CRC_ERR 0xA2 //CRC错误
#define CVP_DUT_ACK_VM_WRITE_ERR 0xA3 //VM写入错误
/*******************CVP测试命令集END*********************/
#define CVP_DUT_SPP_MAGIC 0x55BB
#define CVP_DUT_PACK_NUM sizeof(cvp_dut_data_t) //数据包总长度
#define CVP_DUT_NEW_SPP_MAGIC 0x55CC
typedef enum {
/*
CVP_DUT 算法模式
通话中设置命令,可自由开关每个算法,测试性能指标
*/
CVP_DUT_MODE_ALGORITHM = 1,
/*
CVP_DUT BYPASS模式
通话前设置命令不经过算法可自由选择需要测试的MIC
每次通话结束默认恢复成 CVP_DUT算法模式
*/
CVP_DUT_MODE_BYPASS = 2,
} CVP_DUT_mode_t;
typedef enum {
CVP_3MIC_OUTPUT_SEL_DEFAULT = 0, /*默认输出*/
CVP_3MIC_OUTPUT_SEL_MASTER, /*Talk mic原始数据*/
CVP_3MIC_OUTPUT_SEL_SLAVE, /*FF mic原始数据*/
CVP_3MIC_OUTPUT_SEL_FBMIC, /*FB mic原始数据*/
} CVP_3MIC_OUTPUT_ENUM;
//DEC 产测模式
typedef enum {
AUDIO_DEC_DUT_MODE_CLOSE = 0, /*DEC_DUT 关闭*/
AUDIO_DEC_DUT_MODE_BYPASS, /*DEC_DUT 开启bypass所有数据处理*/
AUDIO_DEC_DUT_MODE_SPK_EQ, /*DEC_DUT 开启仅保留SPK_EQ*/
} audio_dec_dut_mode_t;
typedef struct {
u16 magic;
u16 crc;
u8 dat[4];
} cvp_dut_data_t;
typedef struct {
u8 parse_seq;
u8 mic_ch_sel; //bypass模式下MIC通道号
u8 mode; //CVP DUT MODE
u8 dec_dut_enable; //DEC DUT 模式
cvp_dut_data_t rx_buf; //spp接收buf
cvp_dut_data_t tx_buf; //spp发送buf
} cvp_dut_t;
//cvp_dut 测试初始化接口
void cvp_dut_init(void);
//cvp_dut 卸载接口
void cvp_dut_unit(void);
//cvp_dut MIC 通道 获取接口
u8 cvp_dut_mic_ch_get(void);
//cvp_dut 模式获取
u8 cvp_dut_mode_get(void);
//cvp_dut 模式设置
void cvp_dut_mode_set(u8 mode);
/*
DEC产测状态获取
param: music_decide 1 需判断播歌状态; 0 不需判断
*/
u8 audio_dec_dut_en_get(u8 music_decide);
//cvp_dut 数据解析函数
int cvp_dut_new_rx_packet(u8 *dat, u8 len);
#endif/*_AUDIO_CVP_DUT_*/

161
cpu/br28/audio_cvp_sync.c Normal file
View File

@ -0,0 +1,161 @@
#include "system/includes.h"
#include "media/includes.h"
#include "audio_config.h"
#if TCFG_AUDIO_CVP_SYNC
#if 0
#define cvp_sync_log printf
#else
#define cvp_sync_log(...)
#endif
enum {
CVP_SYNC_STA_NORMAL = 0, //普通状态
CVP_SYNC_STA_DOWNSAMPLING, //下采样状态
CVP_SYNC_STA_UPSAMPLING, //上采样状态
};
#define AUDIO_CVP_SRCBUF_SIZE 672 //输入输出BUFFER长度
#define AUDIO_CVP_CATCH_LEN AUDIO_CVP_SRCBUF_SIZE //SRC 拼包BUF 长度, 注意每帧不能超过此长度
#define AUDIO_CVP_DETECT_TIME 1000 //定时检测周期
typedef struct {
u8 ch_num;
u8 src_break;
u8 state;
u8 det_flag;
u8 cnt;
u16 offset;
u16 det_time_id;
u32 target_sample_rate; //目标采样率
u32 sample_rate; //采样率
s16 src_inbuf[AUDIO_CVP_SRCBUF_SIZE / 2];
s16 src_outbuf[AUDIO_CVP_SRCBUF_SIZE / 2];
u8 frame_catch[AUDIO_CVP_CATCH_LEN];
struct audio_src_handle *hw_src; //SRC句柄
} audio_cvp_sync_t;
static audio_cvp_sync_t *hdl = NULL;
extern int lmp_private_get_esco_send_packet_len();
extern int audio_aec_sync_buffer_set(s16 *data, int len);
static int audio_cvp_sync_output_handler(void *priv, void *data, int len)
{
if ((hdl->offset + len) > AUDIO_CVP_CATCH_LEN) {
printf("cvp sync output buf full\n");
hdl->src_break = 1;
}
//回调仅做拼包
memcpy(hdl->frame_catch + hdl->offset, (u8 *)data, len);
hdl->offset += len;
/* if (hdl->cnt > 5) { */
/* cvp_sync_log("sync len %d, offset %d\n", len, hdl->offset); */
/* } */
return len;
}
static void audio_cvp_sync_det_set(void *priv)
{
if (hdl) {
hdl->det_flag = 1;
}
}
int audio_cvp_sync_open(u16 sr)
{
if (!hdl) {
hdl = zalloc(sizeof(audio_cvp_sync_t));
}
if (!hdl) {
return 1;
}
hdl->hw_src = zalloc(sizeof(struct audio_src_handle));
if (!hdl->hw_src) {
return 1;
}
hdl->ch_num = 1;
hdl->sample_rate = sr;
hdl->target_sample_rate = sr;
audio_hw_src_open(hdl->hw_src, hdl->ch_num, SRC_TYPE_RESAMPLE);
audio_hw_src_set_output_buffer(hdl->hw_src, hdl->src_outbuf, AUDIO_CVP_SRCBUF_SIZE);
audio_hw_src_set_input_buffer(hdl->hw_src, hdl->src_inbuf, AUDIO_CVP_SRCBUF_SIZE);
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate);
audio_src_set_output_handler(hdl->hw_src, NULL, audio_cvp_sync_output_handler);
hdl->det_time_id = sys_timer_add(NULL, audio_cvp_sync_det_set, AUDIO_CVP_DETECT_TIME);
return 0;
}
int audio_cvp_sync_run(s16 *data, int len)
{
int wlen = 0;
int btlen = lmp_private_get_esco_send_packet_len();
if (!hdl) {
return 0;
}
if (hdl->det_flag) {
if (btlen > 360) {
if (hdl->state != CVP_SYNC_STA_UPSAMPLING) {
hdl->state = CVP_SYNC_STA_UPSAMPLING;
hdl->cnt = 0;
}
if (++hdl->cnt > 5) {
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate - 1);
cvp_sync_log("cvp_src_upsr btlen %d, cnt %d, len %d\n", btlen, hdl->cnt, len);
}
} else if (btlen < 120) {
if (hdl->state != CVP_SYNC_STA_DOWNSAMPLING) {
hdl->state = CVP_SYNC_STA_DOWNSAMPLING;
hdl->cnt = 0;
}
if (++hdl->cnt > 5) {
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate + 1);
cvp_sync_log("cvp_src_downsr btlen %d, cnt %d, len %d\n", btlen, hdl->cnt, len);
}
} else {
hdl->state = CVP_SYNC_STA_NORMAL;
hdl->det_flag = 0;
hdl->cnt = 0;
}
}
#if 0 //测试模块
hdl->cnt = 6;
static int max_btlen = 0;
audio_hw_src_set_rate(hdl->hw_src, hdl->sample_rate, hdl->target_sample_rate + 10);
if (btlen > max_btlen) {
max_btlen = btlen;
cvp_sync_log("btlen %d, len %d \n", max_btlen, len);
}
#endif/*测试模块*/
if (hdl->hw_src) {
while (len) {
hdl->offset = 0;
wlen = audio_src_resample_write(hdl->hw_src, data, len);
audio_resample_hw_push_data_out(hdl->hw_src); //执行完则表示当前帧的数据全部输出完毕
audio_aec_sync_buffer_set((s16 *)hdl->frame_catch, hdl->offset); //输出到CVP
data += wlen / 2;
len -= wlen;
if (hdl->src_break) {
hdl->src_break = 0;
break;
}
}
}
return len;
}
int audio_cvp_sync_close()
{
if (hdl->hw_src) {
audio_hw_src_stop(hdl->hw_src);
audio_hw_src_close(hdl->hw_src);
sys_timer_del(hdl->det_time_id);
free(hdl->hw_src);
free(hdl);
hdl = NULL;
}
return 0;
}
#endif/*TCFG_AUDIO_CVP_SYNC*/

37
cpu/br28/audio_cvp_sync.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef AUDIO_CVP_SYNC_H
#define AUDIO_CVP_SYNC_H
/*
*********************************************************************
* Audio CVP Sync Open
* Description: 通话上行同步打开
* Arguments : sr 采样率
* Return : 0 成功 其他 失败
* Note(s) : null
*********************************************************************
*/
int audio_cvp_sync_open(u16 sr);
/*
*********************************************************************
* Audio CVP Sync Run
* Description: 通话上行同步处理
* Arguments : data 数据指针, len 数据长度(byte)
* Return : len 写入的数据长度0 写入失败
* Note(s) : null
*********************************************************************
*/
int audio_cvp_sync_run(s16 *data, int len);
/*
*********************************************************************
* Audio CVP Sync Close
* Description: 通话上行同步关闭
* Arguments : null
* Return : 0 成功 其他 失败
* Note(s) : null
*********************************************************************
*/
int audio_cvp_sync_close();
#endif/*AUDIO_CVP_SYNC_H*/

1841
cpu/br28/audio_dec.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
#ifndef _AUDIO_DEC_H_
#define _AUDIO_DEC_H_
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "asm/audio_src.h"
// #include "audio_digital_vol.h"
/*#include "application/audio_eq_drc_apply.h"*/
#ifndef RB16
#define RB16(b) (u16)(((u8 *)b)[0] << 8 | (((u8 *)b))[1])
#endif
extern struct audio_decoder_task decode_task;
extern struct audio_mixer mixer;
extern struct audio_mixer recorder_mixer;
u32 audio_output_rate(int input_rate);
u32 audio_output_channel_num(void);
int audio_output_set_start_volume(u8 state);
int audio_output_start(u32 sample_rate, u8 reset_rate);
void audio_output_stop(void);
struct audio_src_handle *audio_hw_resample_open(void *priv, int (*output_handler)(void *, void *, int),
u8 channel, u16 input_sample_rate, u16 output_sample_rate);
void audio_hw_resample_close(struct audio_src_handle *hdl);
void audio_resume_all_decoder(void);
//////////////////////////////////////////////////////////////////////////////
void audio_sbc_enc_inbuf_resume(void);
int audio_dec_init();
void set_source_sample_rate(u16 sample_rate);
u16 get_source_sample_rate();
#if USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0
void a2dp_user_digital_volume_set(u8 vol);
u8 a2dp_user_audio_digital_volume_get();
void a2dp_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void linein_user_digital_volume_set(u8 vol);
u8 linein_user_audio_digital_volume_get();
void linein_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void fm_user_digital_volume_set(u8 vol);
u8 fm_user_audio_digital_volume_get();
void fm_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void file_user_digital_volume_set(u8 vol);
u8 file_user_audio_digital_volume_get();
void file_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void pc_user_digital_volume_set(u8 vol);
u8 pc_user_audio_digital_volume_get();
void pc_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void spdif_user_digital_volume_set(u8 vol);
u8 spdif_user_audio_digital_volume_get();
void spdif_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
void reverb_user_digital_volume_set(u8 vol);
u8 reverb_user_audio_digital_volume_get();
void reverb_user_digital_volume_tab_set(u16 *user_vol_tab, u8 user_vol_max);
#endif
void reverb_set_dodge_threshold(int threshold_in, int threshold_out, u8 fade_tar, u8 dodge_en);
void a2dp_dec_output_set_start_bt_time(u32 bt_tmr);
/*void mix_out_high_bass(u32 cmd, struct high_bass *hb);
void mix_out_high_bass_dis(u32 cmd, u8 dis);*/
//////////////////////////////////////////////////////////////////////////////
static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
{
s16 *mono = mono_pcm;
int i = 0;
u8 j = 0;
for (i = 0; i < points; i++, mono++) {
*dual_pcm++ = *mono;
*dual_pcm++ = *mono;
}
}
//////////////////////////////////////////////////////////////////////////////
#include "audio_dec_file.h"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
#ifndef _AUDIO_DEC_FILE_H_
#define _AUDIO_DEC_FILE_H_
#include "asm/includes.h"
#include "media/includes.h"
#include "media/file_decoder.h"
#include "system/includes.h"
#include "media/audio_decoder.h"
#include "app_config.h"
#include "music/music_decrypt.h"
#include "music/music_id3.h"
#include "audio_dec_eff.h"
#define FILE_DEC_REPEAT_EN 0 // 无缝循环播放
enum {
FILE_DEC_STREAM_CLOSE = 0,
FILE_DEC_STREAM_OPEN,
};
struct file_dec_hdl {
//struct audio_stream *stream; // 音频流
struct file_decoder file_dec; // file解码句柄
struct audio_res_wait wait; // 资源等待句柄
#if TCFG_USER_TWS_ENABLE
struct file_decoder trans_dec; // 解码句柄
u8 *frame;
u16 frame_len;
u16 frame_remain_len;
u8 trans_dec_end;
u8 wait_tws_confirm;
u8 tws_channel;
u16 seqn;
u16 tx_seqn;
u32 wait_tws_timeout;
void *ts_handle;
void *syncts;
u32 pcm_num;
u32 mix_ch_event_params[3];
#endif
struct audio_mixer_ch mix_ch; // 叠加句柄
#if TCFG_EQ_ENABLE&&TCFG_MUSIC_MODE_EQ_ENABLE
struct dec_eq_drc *eq_drc;
#endif//TCFG_MUSIC_MODE_EQ_ENABLE
u8 remain;
struct audio_dec_breakpoint *dec_bp; // 断点
u32 id; // 唯一标识符,随机值
void *file; // 文件句柄
u32 pick_flag : 1; // 挑出数据帧发送如MP3等)。不是输出pcm后级不能接任何音效处理等
u32 pcm_enc_flag : 1; // pcm压缩成数据帧发送如WAV等
u32 read_err : 2; // 读数出错 0:no err 1:fat err, 2:disk err
u32 wait_add : 1; // 是否马上得到执行
#if TCFG_DEC_DECRYPT_ENABLE
CIPHER mply_cipher; // 解密播放
#endif
#if TCFG_DEC_ID3_V1_ENABLE
MP3_ID3_OBJ *p_mp3_id3_v1; // id3_v1信息
#endif
#if TCFG_DEC_ID3_V2_ENABLE
MP3_ID3_OBJ *p_mp3_id3_v2; // id3_v2信息
#endif
#if FILE_DEC_REPEAT_EN
u8 repeat_num; // 无缝循环次数
struct fixphase_repair_obj repair_buf; // 无缝循环句柄
#endif
struct audio_dec_breakpoint *bp; // 断点信息
void *evt_priv; // 事件回调私有参数
void (*evt_cb)(void *, int argc, int *argv); // 事件回调句柄
void (*stream_handler)(void *priv, int event, struct file_dec_hdl *); // 数据流设置回调
void *stream_priv; // 数据流设置回调私有句柄
};
enum {
FILE_FROM_LOCAL,
FILE_FROM_TWS,
};
struct file_decoder *file_dec_get_file_decoder_hdl(void);
#define file_dec_is_stop() file_decoder_is_stop(file_dec_get_file_decoder_hdl())
#define file_dec_is_play() file_decoder_is_play(file_dec_get_file_decoder_hdl())
#define file_dec_is_pause() file_decoder_is_pause(file_dec_get_file_decoder_hdl())
#define file_dec_pp() file_decoder_pp(file_dec_get_file_decoder_hdl())
#define file_dec_FF(x) file_decoder_FF(file_dec_get_file_decoder_hdl(),x)
#define file_dec_FR(x) file_decoder_FR(file_dec_get_file_decoder_hdl(),x)
#define file_dec_get_breakpoint(x) file_decoder_get_breakpoint(file_dec_get_file_decoder_hdl(),x)
#define file_dec_get_total_time() file_decoder_get_total_time(file_dec_get_file_decoder_hdl())
#define file_dec_get_cur_time() file_decoder_get_cur_time(file_dec_get_file_decoder_hdl())
#define file_dec_get_decoder_type() file_decoder_get_decoder_type(file_dec_get_file_decoder_hdl())
int file_dec_create(void *priv, void (*handler)(void *, int argc, int *argv));
int file_dec_open(void *file, struct audio_dec_breakpoint *bp);
void file_dec_close();
int file_dec_restart(int id);
int file_dec_push_restart(void);
int file_dec_get_status(void);
void file_dec_set_stream_set_hdl(struct file_dec_hdl *dec,
void (*stream_handler)(void *priv, int event, struct file_dec_hdl *),
void *stream_priv);
void *get_file_dec_hdl();
int tws_local_media_dec_open(u8 channel, u8 *arg);
void tws_local_media_dec_close(u8 channel);
int tws_local_media_dec_state();
void send_local_media_dec_open_cmd();
int file_dec_get_source();
#endif /*TCFG_APP_MUSIC_EN*/

View File

@ -0,0 +1,391 @@
#include "audio_dec_iis.h"
#include "app_config.h"
#include "audio_decoder.h"
#include "media/includes.h"
#include "audio_config.h"
#include "system/includes.h"
#include "audio_enc.h"
#include "application/audio_eq.h"
#include "application/audio_drc.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_main.h"
#include "clock_cfg.h"
#include "audio_dec_eff.h"
#include "audio_codec_clock.h"
#include "audio_dvol.h"
#include "audio_link.h"
#include "circular_buf.h"
#include "sound_device.h"
#if (TCFG_AUDIO_INPUT_IIS)
extern ALINK_PARM alink0_platform_data;
extern struct audio_dac_hdl dac_hdl;
extern struct audio_decoder_task decode_task;
extern struct audio_mixer mixer;
/* extern void *hw_alink; //alink初始化句柄 */
#define IIS_IN_STORE_PCM_SIZE (4 * 1024)
//iis 驱动结构体
struct iis_in_sample_hdl {
OS_SEM sem;
s16 *store_pcm_buf;
cbuffer_t cbuf;
int sample_rate;
void *hw_alink;
void *alink_ch;
};
// iis 输入解码结构体
struct iis_in_dec_hdl {
struct audio_decoder decoder;
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
u8 channel;
u8 start;
u8 need_resume;
u8 remain;
u8 output_ch;
int sample_rate;
void *iis_in; //驱动句柄
};
static struct iis_in_dec_hdl *iis_in_dec = NULL;
// ********************** iis in 驱动 ************************* //
static void iis_in_dec_resume(void)
{
if (iis_in_dec) {
audio_decoder_resume(&iis_in_dec->decoder);
}
}
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
{
s16 pcm_L;
s16 pcm_R;
int i = 0;
for (i = 0; i < points_len; i++, pcm_lr += 2) {
pcm_L = *pcm_lr;
pcm_R = *(pcm_lr + 1);
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
}
}
static void iis_in_data_handler(void *priv, void *_data, int len)
{
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)priv;
s16 *data = (s16 *)_data;
u16 temp_len = len;
int wlen = 0;
if (iis_in_dec->start == 0) {
goto __exit;
}
//iis 默认输入的是双声道数据
if (iis_in_dec->output_ch == 1) {
s16 *mono_data = data;
for (int i = 0; i < len / 4; i++) {
mono_data[i] = mono_data[i * 2];
}
len = len / 2;
wlen = cbuf_write(&iis_in->cbuf, mono_data, len);
if (wlen != len) {
putchar('w');
}
} else if (iis_in_dec->output_ch == 2) {
wlen = cbuf_write(&iis_in->cbuf, data, len);
/* os_sem_post(&iis_in->sem); */
if (wlen != len) {
putchar('W');
}
} else {
putchar('e');
goto __exit;
}
if (iis_in_dec && iis_in_dec->need_resume) {
iis_in_dec->need_resume = 0;
iis_in_dec_resume();
}
__exit:
alink_set_shn(&alink0_platform_data.ch_cfg[1], temp_len / 4);
}
static void *iis_in_open(int sr)
{
struct iis_in_sample_hdl *iis_in = NULL;
iis_in = zalloc(sizeof(struct iis_in_sample_hdl));
if (!iis_in) {
return NULL;
}
iis_in->store_pcm_buf = malloc(IIS_IN_STORE_PCM_SIZE);
if (!iis_in->store_pcm_buf) {
free(iis_in);
return NULL;
}
cbuf_init(&iis_in->cbuf, iis_in->store_pcm_buf, IIS_IN_STORE_PCM_SIZE);
iis_in->hw_alink = (ALINK_PARM *)get_iis_alink_param();
if (iis_in->hw_alink == NULL) {
iis_in->hw_alink = alink_init(&alink0_platform_data);
}
iis_in->alink_ch = alink_channel_init(iis_in->hw_alink, 1, ALINK_DIR_RX, (void *)iis_in, iis_in_data_handler);
alink_start(iis_in->hw_alink);
iis_in->sample_rate = sr;
return iis_in;
}
// *********************** iis in dec 解码 ***************************//
static int iis_in_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
{
int rlen = 0;
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
if (!iis_in || iis_in_dec->start == 0) {
goto __exit;
}
if (!iis_in->store_pcm_buf) {
goto __exit;
}
int read_len = cbuf_get_data_size(&iis_in->cbuf);
if (read_len) {
read_len = read_len > len ? len : read_len;
rlen = cbuf_read(&iis_in->cbuf, buf, read_len);
/* printf("--- rlen : %d\n", rlen); */
}
__exit:
if (!rlen) {
iis_in_dec->need_resume = 1;
return -1;
}
/* y_printf("--- rlen = %d\n",rlen); */
return rlen;
}
static int iis_in_dec_probe_handler(struct audio_decoder *decoder)
{
/* struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder); */
struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
return 0;
}
static int iis_in_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
struct iis_in_dec_hdl *dec = container_of(decoder, struct iis_in_dec_hdl, decoder);
if (!dec) {
return 0;
}
int rlen = len;
int wlen = 0;
if (!dec->remain) {
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(MUSIC_DVOL, data, len);
#endif
}
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
if (!wlen) {
putchar('w');
}
rlen -= wlen;
if (rlen == 0) {
dec->remain = 0;
} else {
dec->remain = 1;
}
return len - rlen;
}
static const struct audio_dec_handler iis_in_dec_handler = {
.dec_probe = iis_in_dec_probe_handler,
.dec_output = iis_in_dec_output_handler,
};
static const struct audio_dec_input iis_input = {
.coding_type = AUDIO_CODING_PCM,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = iis_in_stream_read,
}
}
};
static void iis_in_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
/*pcm_audio_close();*/
break;
}
}
//开始 iis dec 解码
static int iis_in_dec_start(void)
{
int err;
y_printf(">>>>>>>> Enter Func: %s \n", __func__);
struct audio_fmt f = {0};
struct iis_in_dec_hdl *dec = iis_in_dec;
if (!iis_in_dec && iis_in_dec->start == 1) {
return -EINVAL;
}
err = audio_decoder_open(&dec->decoder, &iis_input, &decode_task);
if (err) {
goto __err;
}
if (dec->iis_in == NULL) {
y_printf("--> %s, %d, Init iis_in!\n", __func__, __LINE__);
dec->iis_in = iis_in_open(dec->sample_rate);
if (!dec->iis_in) {
goto __err;
}
}
audio_decoder_set_handler(&dec->decoder, &iis_in_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, iis_in_dec_event_handler, 0);
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
if (dac_conn == DAC_OUTPUT_LR) {
dec->output_ch = 2;
} else {
dec->output_ch = 1;
}
f.coding_type = AUDIO_CODING_PCM;
f.sample_rate = dec->sample_rate;
f.channel = dec->output_ch;
sound_pcm_dev_channel_mapping(dec->output_ch);
err = audio_decoder_set_fmt(&dec->decoder, &f);
if (err) {
goto __err;
}
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
#endif
// 设置叠加功能
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 1);
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err;
}
/* audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption); */
dec->start = 1;
return 0;
__err:
return err;
}
// iis in 解码资源等待
void iis_in_dec_stop(void);
static int iis_in_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
// 启动解码
err = iis_in_dec_start();
} else if (event == AUDIO_RES_PUT) {
// 被打断
iis_in_dec_stop();
}
return err;
}
int iis_in_dec_open(void)
{
int err;
struct iis_in_dec_hdl *dec = NULL;;
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
iis_in_dec = dec;
dec->sample_rate = TCFG_IIS_SR;
dec->channel = 2; //iis 是双声道数据
dec->wait.priority = 2;
dec->wait.preemption = 1;
dec->wait.handler = iis_in_wait_res_handler;
err = audio_decoder_task_add_wait(&decode_task, &dec->wait);
clock_add(DEC_PCM_CLK);
return err;
}
void iis_in_dec_stop(void)
{
if (iis_in_dec && iis_in_dec->start == 1) {
struct iis_in_sample_hdl *iis_in = (struct iis_in_sample_hdl *)iis_in_dec->iis_in;
iis_in_dec->start = 0;
audio_decoder_close(&iis_in_dec->decoder);
audio_mixer_ch_close(&iis_in_dec->mix_ch);
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(MUSIC_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
local_irq_disable();
#if 1
if (iis_in) {
void *alink_p = (ALINK_PARM *)get_iis_alink_param();
if (iis_in->hw_alink && !alink_p) {
alink_uninit(iis_in->hw_alink);
iis_in->hw_alink = NULL;
} else {
/* alink_uninit(iis_in->hw_alink); */
alink_channel_close(iis_in->alink_ch);
}
if (iis_in->store_pcm_buf) {
free(iis_in->store_pcm_buf);
iis_in->store_pcm_buf = NULL;
}
free(iis_in);
iis_in = NULL;
iis_in_dec->iis_in = NULL;
}
#endif
local_irq_enable();
}
}
void iis_in_dec_close(void)
{
if (!iis_in_dec) {
return;
}
iis_in_dec_stop();
audio_decoder_task_del_wait(&decode_task, &iis_in_dec->wait);
clock_remove(DEC_PCM_CLK);
local_irq_disable();
free(iis_in_dec);
iis_in_dec = NULL;
local_irq_enable();
}
#endif

View File

@ -0,0 +1,9 @@
#ifndef __AUDIO_DEC_IIS_H
#define __AUDIO_DEC_IIS_H
#endif

View File

@ -0,0 +1,921 @@
#include "uac_stream.h"
#include "app_config.h"
#include "audio_decoder.h"
#include "media/includes.h"
#include "audio_config.h"
#include "system/includes.h"
#include "audio_enc.h"
#include "application/audio_eq.h"
#include "application/audio_drc.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_main.h"
#include "clock_cfg.h"
#include "audio_dec_eff.h"
#include "audio_codec_clock.h"
#include "audio_dvol.h"
#include "sound_device.h"
#if TCFG_UI_ENABLE
#include "ui/ui_api.h"
#endif
#if TCFG_PC_ENABLE//TCFG_APP_PC_EN
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_SBC
#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
#else
#define UAC_DEC_PCM_ENC_TYPE AUDIO_CODING_MP3
#define UAC_DEC_PCM_ENC_CHANNEL AUDIO_CH_LR
#endif
struct usb_audio_handle {
int top_size;
int bottom_size;
int begin_size;
};
#define RATE_INC_STEP 2
#define RATE_DEC_STEP 2
struct uac_dec_hdl {
struct audio_decoder decoder;
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
int begin_size;
int top_size;
int bottom_size;
u8 start;
u8 channel;
u8 output_ch;
u8 sync_start;
u32 src_out_sr;
u32 dec_no_out_sound : 1; // 解码不直接输出声音用于TWS转发
u32 sample_rate;
u32 audio_new_rate;
u32 usb_audio_max_speed;
u32 usb_audio_min_speed;
struct audio_src_handle *src_sync;
u8 remain;
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
struct dec_eq_drc *eq_drc;
#endif
struct user_audio_parm *user_hdl;
u32 cnt: 8;
u32 state: 1;
int check_data_timer;
};
extern struct audio_dac_hdl dac_hdl;
extern struct audio_decoder_task decode_task;
extern struct audio_mixer mixer;
static u16 sys_event_id = 0;
static struct uac_dec_hdl *uac_dec = NULL;
static u8 uac_dec_maigc = 0;
extern void uac_get_cur_vol(const u8 id, u16 *l_vol, u16 *r_vol);
extern u8 uac_get_mute(void);
extern void bt_tws_sync_volume();
void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt);
void pc_eq_drc_close(struct uac_dec_hdl *dec);
int uac_vol_switch(int vol)
{
u16 valsum = vol * (SYS_MAX_VOL + 1) / 100;
if (valsum > SYS_MAX_VOL) {
valsum = SYS_MAX_VOL;
}
return valsum;
}
static void uac_dec_set_output_channel(struct uac_dec_hdl *dec)
{
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
if (dac_conn == DAC_OUTPUT_LR) {
dec->output_ch = 2;
} else {
dec->output_ch = 1;
}
}
static int uac_sync_output_handler(void *priv, void *buf, int len)
{
struct uac_dec_hdl *dec = (struct uac_dec_hdl *)priv;
int remain_len = len;
int wlen = 0;
s16 *data = (s16 *)buf;
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
if (dec->dec_no_out_sound) {
return pcm2tws_enc_output(NULL, data, len);
}
#endif
wlen = audio_mixer_ch_write(&dec->mix_ch, data, len);
return wlen;
}
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
{
s16 pcm_L;
s16 pcm_R;
int i = 0;
for (i = 0; i < points_len; i++, pcm_lr += 2) {
pcm_L = *pcm_lr;
pcm_R = *(pcm_lr + 1);
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
}
}
static int uac_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
int rlen = len;
int wlen = 0;
/* if (dec->channel == 2 && dec->output_ch == 1) { //这里 */
/* pcm_LR_to_mono((s16 *)data, (s16 *)data, len >> 2); //这里有双声道转单声道 */
/* len >>= 1; */
/* } */
if (!dec->remain) {
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
if (dec->user_hdl) {
u8 ch_num = dec->output_ch;
user_audio_process_handler_run(dec->user_hdl, data, len, ch_num);
}
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(MUSIC_DVOL, data, len);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
}
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
if (dec->eq_drc && dec->eq_drc->async) {
int eqlen = eq_drc_run(dec->eq_drc, data, len);
len -= eqlen;
if (len == 0) {
dec->remain = 0;
} else {
dec->remain = 1;
}
return eqlen;
}
if (!dec->remain) {
eq_drc_run(dec->eq_drc, data, len);
}
#endif//TCFG_PC_MODE_EQ_ENABLE
if (dec->src_sync) {
wlen = audio_src_resample_write(dec->src_sync, data, rlen);
/*printf("%d - %d\n", len, wlen);*/
/* return wlen; */
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
} else if (dec->dec_no_out_sound) {
wlen = pcm2tws_enc_output(NULL, data, rlen);
#endif
} else {
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
}
rlen -= wlen;
if (rlen == 0) {
dec->remain = 0;
} else {
dec->remain = 1;
}
return len - rlen;
}
/*----------------------------------------------------------------------------*/
/**@brief 检测uac是否收到数据没数据时暂停mix_ch
@param *priv: 私有参数
@return
@note
*/
/*----------------------------------------------------------------------------*/
static void audio_pc_check_timer(void *priv)
{
#if 1
u8 alive = uac_speaker_get_alive();
if (alive) {
uac_dec->cnt++;
if (uac_dec->cnt > 5) {
if (!uac_dec->state) {
#if TCFG_DEC2TWS_ENABLE
if (uac_dec->pcm_dec.dec_no_out_sound) {
localtws_decoder_pause(1);
}
#endif
audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
audio_decoder_resume_all(&decode_task);
uac_dec->state = 1;
}
}
} else {
if (uac_dec->cnt) {
uac_dec->cnt--;
}
if (uac_dec->state) {
uac_dec->state = 0;
uac_dec->cnt = 0;
#if TCFG_DEC2TWS_ENABLE
if (uac_dec->pcm_dec.dec_no_out_sound) {
localtws_decoder_pause(0);
}
#endif
audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
audio_decoder_resume_all(&decode_task);
}
}
uac_speaker_set_alive(1);
#else
static u8 cnt = 0;
if (uac_speaker_stream_size(NULL) == 0) {
if (cnt < 20) {
cnt++;
}
if (cnt == 15) {
#if TCFG_DEC2TWS_ENABLE
if (uac_dec->pcm_dec.dec_no_out_sound) {
localtws_decoder_pause(1);
}
#endif
audio_mixer_ch_pause(&uac_dec->mix_ch, 1);
audio_decoder_resume_all(&decode_task);
}
} else {
if (cnt > 14) {
#if TCFG_DEC2TWS_ENABLE
if (uac_dec->pcm_dec.dec_no_out_sound) {
localtws_decoder_pause(0);
}
#endif
audio_mixer_ch_pause(&uac_dec->mix_ch, 0);
audio_decoder_resume_all(&decode_task);
}
cnt = 0;
}
#endif
}
static int uac_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
{
int rlen = 0;
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
if (!dec->sync_start) {
if (uac_speaker_stream_size() < dec->begin_size) {
return -1;
}
dec->sync_start = 1;
}
rlen = uac_speaker_read(NULL, (void *)buf, len);
if (dec->channel == 2 && dec->output_ch == 1) {
pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2);
rlen >>= 1;
}
if (!rlen) {
return -1;
}
return rlen;
}
static const struct audio_dec_input uac_input = {
.coding_type = AUDIO_CODING_PCM,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = uac_stream_read,
/*.fseek = uac_stream_seek,*/
/*.flen = uac_stream_len,*/
}
}
};
int uac_speaker_stream_sample_rate(void);
static int usb_audio_stream_sync(struct uac_dec_hdl *dec, int data_size)
{
if (!dec->src_sync) {
return 0;
}
#if 1
//优化下行播放同步得调节步进
u32 in_sr = uac_speaker_stream_sample_rate();
u32 out_sr = (long long)dec->audio_new_rate * (long long)in_sr / dec->sample_rate; //统计得输入采样率,转换成输出采样率
if (data_size < dec->bottom_size) {
out_sr += out_sr * 5 / 10000;
/* putchar('+'); */
}
if (data_size > dec->top_size) {
out_sr -= out_sr * 5 / 10000;
/* putchar('-'); */
}
if (out_sr != dec->audio_new_rate) {
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, out_sr);
}
#else
u32 sr = dec->audio_new_rate;
if (data_size < dec->bottom_size) {
dec->audio_new_rate += RATE_INC_STEP;
/*printf("rate inc\n");*/
}
if (data_size > dec->top_size) {
dec->audio_new_rate -= RATE_DEC_STEP;
/*printf("rate dec : %d\n", __this->audio_new_rate);*/
}
if (dec->audio_new_rate < dec->usb_audio_min_speed) {
dec->audio_new_rate = dec->usb_audio_min_speed;
} else if (dec->audio_new_rate > dec->usb_audio_max_speed) {
dec->audio_new_rate = dec->usb_audio_max_speed;
}
if (sr != dec->audio_new_rate) {
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
}
#endif
return 0;
}
static int uac_dec_probe_handler(struct audio_decoder *decoder)
{
struct uac_dec_hdl *dec = container_of(decoder, struct uac_dec_hdl, decoder);
int err = 0;
#if 0
if (!dec->sync_start) {
if (uac_speaker_stream_size() > dec->begin_size) {
dec->sync_start = 1;
return 0;
} else {
os_time_dly(2);
audio_decoder_suspend(&dec->decoder, 0);
/* audio_decoder_resume(&dec->decoder); */
/* return 0;//临时 */
return -EINVAL;
}
}
#else
if (!dec->sync_start) {
return 0;
}
#endif
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
if (dec->dec_no_out_sound) {
// localtws同步有微调处理
return 0;
}
#endif
usb_audio_stream_sync(dec, uac_speaker_stream_size());
return err;
}
static const struct audio_dec_handler uac_dec_handler = {
.dec_probe = uac_dec_probe_handler,
.dec_output = uac_dec_output_handler,
};
static int uac_audio_sync_init(struct uac_dec_hdl *dec)
{
dec->sync_start = 0;
dec->begin_size = uac_speaker_stream_length() * 60 / 100;
dec->top_size = uac_speaker_stream_length() * 70 / 100;
dec->bottom_size = uac_speaker_stream_length() * 40 / 100;
dec->audio_new_rate = dec->src_out_sr;//audio_output_rate(dec->sample_rate);
printf("out_sr:%d, dsr:%d, \n", dec->audio_new_rate, dec->sample_rate);
dec->usb_audio_max_speed = dec->audio_new_rate + 50;
dec->usb_audio_min_speed = dec->audio_new_rate - 50;
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
if (dec->dec_no_out_sound) {
if (dec->audio_new_rate == dec->sample_rate) {
return -ENODEV;
}
}
#endif
dec->src_sync = zalloc(sizeof(struct audio_src_handle));
if (!dec->src_sync) {
return -ENODEV;
}
audio_hw_src_open(dec->src_sync, dec->output_ch, SRC_TYPE_RESAMPLE);
audio_hw_src_set_rate(dec->src_sync, dec->sample_rate, dec->audio_new_rate);
audio_src_set_output_handler(dec->src_sync, dec, uac_sync_output_handler);
return 0;
}
static int uac_audio_sync_release(struct uac_dec_hdl *dec)
{
if (dec->src_sync) {
audio_hw_src_stop(dec->src_sync);
audio_hw_src_close(dec->src_sync);
local_irq_disable();
free(dec->src_sync);
dec->src_sync = NULL;
local_irq_enable();
}
return 0;
}
static int uac_audio_close(void)
{
if (!uac_dec || !uac_dec->start) {
return 0;
}
uac_dec->start = 0;
uac_dec->sync_start = 0;
if (uac_dec->check_data_timer) {
sys_hi_timer_del(uac_dec->check_data_timer);
}
audio_decoder_close(&uac_dec->decoder);
uac_audio_sync_release(uac_dec);
if (!uac_dec->dec_no_out_sound) {
audio_mixer_ch_close(&uac_dec->mix_ch);
app_audio_state_exit(APP_AUDIO_STATE_MUSIC);
}
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
if (uac_dec->dec_no_out_sound) {
uac_dec->dec_no_out_sound = 0;
pcm2tws_enc_close();
encfile_tws_dec_close();
local_tws_stop();
}
#endif
pc_eq_drc_close(uac_dec);
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
if (uac_dec->user_hdl) {
user_audio_process_close(uac_dec->user_hdl);
uac_dec->user_hdl = NULL;
}
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(MUSIC_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
/* 此处不进行clock_del改为在usb_audio_demo_exit后 */
/* 由于usb_audio_mic_close前adc中断还会不断唤醒usb_audio_mic_write_task */
/* 降低时钟会导致系统跑不过来 */
/* audio_codec_clock_del(AUDIO_PC_MODE); */
return 0;
}
static void uac_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
puts("USB AUDIO_DEC_EVENT_END\n");
if ((u8)argv[1] != (u8)(uac_dec_maigc - 1)) {
log_i("maigc err, %s\n", __FUNCTION__);
break;
}
/*uac_audio_close();*/
break;
}
}
static int uac_audio_start(void)
{
int err;
struct audio_fmt f = {0};
struct uac_dec_hdl *dec = uac_dec;
if (!uac_dec) {
return -EINVAL;
}
err = audio_decoder_open(&dec->decoder, &uac_input, &decode_task);
if (err) {
goto __err;
}
audio_decoder_set_handler(&dec->decoder, &uac_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, uac_dec_event_handler, uac_dec_maigc++);
uac_dec_set_output_channel(dec);
f.coding_type = AUDIO_CODING_PCM;
f.sample_rate = dec->sample_rate;
f.channel = dec->output_ch;
sound_pcm_dev_channel_mapping(dec->output_ch);
err = audio_decoder_set_fmt(&dec->decoder, &f);
if (err) {
goto __err;
}
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
dec->dec_no_out_sound = 0;
if (dec2tws_check_enable() == true) {
audio_decoder_set_output_channel(&dec->decoder, UAC_DEC_PCM_ENC_CHANNEL);
dec->output_ch = AUDIO_CH_IS_MONO(UAC_DEC_PCM_ENC_CHANNEL) ? 1 : 2;;
struct audio_fmt enc_fmt = {0};
enc_fmt.coding_type = UAC_DEC_PCM_ENC_TYPE;
enc_fmt.bit_rate = 128;
enc_fmt.channel = dec->output_ch;
enc_fmt.sample_rate = audio_output_rate(dec->sample_rate);//dec->decoder.fmt.sample_rate;
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
#endif
int ret = pcm2tws_enc_open(&enc_fmt);
if (ret == 0) {
#if (defined(TCFG_PCM2TWS_SBC_ENABLE) && (TCFG_PCM2TWS_SBC_ENABLE))
pcm2tws_enc_set_output_handler(local_tws_output);
#else
pcm2tws_enc_set_output_handler(encfile_tws_wfile);
ret = encfile_tws_dec_open(&enc_fmt);
#endif
if (ret == 0) {
dec->dec_no_out_sound = 1;
pcm2tws_enc_set_resume_handler(uac_dec_resume);
audio_decoder_task_del_wait(&decode_task, &dec->wait);
local_tws_start(&enc_fmt);
audio_decoder_set_run_max(&dec->decoder, 20);
dec->src_out_sr = enc_fmt.sample_rate;
goto __dec_start;
} else {
pcm2tws_enc_close();
}
}
}
#endif
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
// 设置叠加功能
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
dec->src_out_sr = audio_output_rate(f.sample_rate);
__dec_start:
uac_audio_sync_init(dec);
pc_eq_drc_open(dec, &f);
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
u16 l_volume, r_volume;
uac_get_cur_vol(0, &l_volume, &r_volume);
u8 vol = uac_vol_switch(l_volume);
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
bt_tws_sync_volume();
#endif
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
struct user_audio_digital_parm vol_parm = {0};
#if (defined(USER_DIGITAL_VOLUME_ADJUST_ENABLE) && (USER_DIGITAL_VOLUME_ADJUST_ENABLE != 0))
vol_parm.en = true;
vol_parm.vol = app_audio_get_volume(APP_AUDIO_CURRENT_STATE);
vol_parm.vol_max = app_audio_get_max_volume();
vol_parm.fade_step = 2;
#endif
dec->user_hdl = user_audio_process_open((void *)&vol_parm, NULL, NULL);
#endif
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err;
}
dec->state = 0;
dec->cnt = 0;
dec->check_data_timer = sys_hi_timer_add(NULL, audio_pc_check_timer, 10);
audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
dec->start = 1;
return 0;
__err:
pc_eq_drc_close(dec);
#if (defined(USER_AUDIO_PROCESS_ENABLE) && (USER_AUDIO_PROCESS_ENABLE != 0))
if (dec->user_hdl) {
user_audio_process_close(dec->user_hdl);
dec->user_hdl = NULL;
}
#endif
return err;
}
static int uac_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
err = uac_audio_start();
} else if (event == AUDIO_RES_PUT) {
uac_audio_close();
}
return err;
}
static void uac_speaker_stream_rx_handler(int event, void *data, int len)
{
if (uac_dec) {
audio_decoder_resume(&uac_dec->decoder);
}
}
extern struct uac_stream_info *puac_speaker_info;
static int usb_audio_play_open(void *_info)
{
struct uac_dec_hdl *dec;
if (uac_dec) {
return 0;
}
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
uac_dec = dec;
dec->sample_rate = (u32)_info & 0xFFFFFF;
dec->channel = (u32)_info >> 24;
printf("usb_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
set_uac_speaker_rx_handler(dec, uac_speaker_stream_rx_handler);
dec->wait.priority = 2;
dec->wait.preemption = 1;
dec->wait.handler = uac_wait_res_handler;
audio_decoder_task_add_wait(&decode_task, &dec->wait);
clock_add(DEC_PCM_CLK);
return 0;
}
static int usb_audio_play_close(void *arg)
{
int err = 0;
if (!uac_dec) {
return 0;
}
if (uac_dec->start) {
uac_audio_close();
}
audio_decoder_task_del_wait(&decode_task, &uac_dec->wait);
clock_remove(DEC_PCM_CLK);
local_irq_disable();
free(uac_dec);
uac_dec = NULL;
local_irq_enable();
return 0;
}
int uac_dec_restart(int magic)
{
if ((!uac_dec) || (magic != uac_dec_maigc)) {
return -1;
}
int _info = (uac_dec->channel << 24) | uac_dec->sample_rate;
usb_audio_play_close(NULL);
int err = usb_audio_play_open((void *)_info);
return err;
}
int uac_dec_push_restart(void)
{
if (!uac_dec) {
return false;
}
int argv[3];
argv[0] = (int)uac_dec_restart;
argv[1] = 1;
argv[2] = (int)uac_dec_maigc;
os_taskq_post_type(os_current_task(), Q_CALLBACK, ARRAY_SIZE(argv), argv);
return true;
}
void uac_dec_resume(void)
{
if (uac_dec && (uac_dec->start)) {
audio_decoder_resume(&uac_dec->decoder);
}
}
int uac_dec_no_out_sound(void)
{
if (uac_dec && uac_dec->dec_no_out_sound) {
return true;
}
return false;
}
extern int usb_audio_mic_open(void *_info);
extern int usb_audio_mic_close(void *arg);
extern void usb_audio_mic_set_gain(int gain);
static int usb_device_event_handler(u8 event, int value)
{
switch (event) {
case USB_AUDIO_PLAY_OPEN:
/*tone_play_stop();*/
usb_audio_play_open((void *)value);
break;
case USB_AUDIO_PLAY_CLOSE:
usb_audio_play_close((void *)value);
break;
case USB_AUDIO_MIC_OPEN:
usb_audio_mic_open((void *)value);
break;
case USB_AUDIO_MIC_CLOSE:
usb_audio_mic_close((void *)value);
break;
case USB_AUDIO_SET_MIC_VOL:
usb_audio_mic_set_gain(value);
break;
case USB_AUDIO_SET_PLAY_VOL:
value = uac_vol_switch(value & 0xffff); //left ch volume
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, value, 1);
#if (defined(TCFG_DEC2TWS_ENABLE) && (TCFG_DEC2TWS_ENABLE))
bt_tws_sync_volume();
#endif
#if TCFG_UI_ENABLE
u8 vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
ui_set_tmp_menu(MENU_MAIN_VOL, 1000, vol, NULL);
#endif //TCFG_UI_ENABLE
break;
default:
break;
}
return 0;
}
static void usb_audio_event_handler(struct sys_event *event, void *priv)
{
switch (event->type) {
case SYS_DEVICE_EVENT:
if ((u32)event->arg == DEVICE_EVENT_FROM_UAC) {
log_d("usb device event : %d %x\n", event->u.dev.event, event->u.dev.value);
usb_device_event_handler(event->u.dev.event, event->u.dev.value);
}
return;
default:
break;
}
return;
}
__attribute__((weak))int audio_dev_init()
{
return 0;
}
int usb_audio_demo_init(void)
{
int err = 0;
audio_dev_init();
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_UAC, 2,
usb_audio_event_handler);
return 0;
}
void usb_audio_demo_exit(void)
{
unregister_sys_event_handler(usb_audio_event_handler);
usb_audio_play_close(NULL);
usb_audio_mic_close(NULL);
audio_codec_clock_del(AUDIO_PC_MODE);
}
int audio_pc_src_resample_write(void *priv, s16 *data, u32 len)
{
if (uac_dec && uac_dec->start) { //避免src已经关闭异步eq 还在输出写src导致异常
return audio_src_resample_write(priv, data, len);
}
return 0;
}
void pc_eq_drc_open(struct uac_dec_hdl *dec, struct audio_fmt *fmt)
{
if (!dec) {
return;
}
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
u8 drc_en = 0;
#if TCFG_DRC_ENABLE&&TCFG_PC_MODE_DRC_ENABLE
drc_en = 1;
#endif//TCFG_PC_MODE_DRC_ENABLE
if (dec->src_sync) {
dec->eq_drc = dec_eq_drc_setup(dec->src_sync, (eq_output_cb)audio_pc_src_resample_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
} else if (dec->dec_no_out_sound) {
#if (defined(TCFG_PCM_ENC2TWS_ENABLE) && (TCFG_PCM_ENC2TWS_ENABLE))
dec->eq_drc = dec_eq_drc_setup(dec->dec_no_out_sound, (eq_output_cb)pcm2tws_enc_output, fmt->sample_rate, dec->output_ch, 1, drc_en);
#endif
} else {
dec->eq_drc = dec_eq_drc_setup(&dec->mix_ch, (eq_output_cb)audio_mixer_ch_write, fmt->sample_rate, dec->output_ch, 1, drc_en);
}
#endif//TCFG_PC_MODE_EQ_ENABLE
}
void pc_eq_drc_close(struct uac_dec_hdl *dec)
{
if (!dec) {
return;
}
#if TCFG_EQ_ENABLE&&TCFG_PC_MODE_EQ_ENABLE
if (dec->eq_drc) {
dec_eq_drc_free(dec->eq_drc);
dec->eq_drc = NULL;
}
#endif//TCFG_PC_MODE_EQ_ENABLE
}
#endif /* TCFG_APP_PC_EN */

View File

@ -0,0 +1,286 @@
#include "app_config.h"
#include "audio_decoder.h"
#include "media/includes.h"
#include "audio_config.h"
#include "system/includes.h"
#include "audio_enc.h"
#include "application/audio_eq.h"
#include "application/audio_drc.h"
#include "app_config.h"
#include "audio_config.h"
#include "audio_dec.h"
#include "app_main.h"
#include "clock_cfg.h"
#include "audio_dec_eff.h"
#include "audio_codec_clock.h"
#include "audio_dvol.h"
#include "audio_dec_pcm.h"
struct pcm_dec_hdl {
struct audio_decoder decoder;
struct audio_res_wait wait;
struct audio_mixer_ch mix_ch;
u8 start;
u8 remain;
u8 channel;
u8 output_ch;
int sample_rate;
int (*pcm_read_cb)(void *, void *, int);
};
static struct pcm_dec_hdl *pcm_dec = NULL;
extern struct audio_decoder_task decode_task;
extern struct audio_dac_hdl dac_hdl;
void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int))
{
local_irq_disable();
if (pcm_dec && pcm_dec->start == 1) {
pcm_dec->pcm_read_cb = pcm_read_func;
} else {
y_printf(">>> %s, %d, pcm_dec set read cb failed!\n", __func__, __LINE__);
}
local_irq_enable();
}
static void pcm_LR_to_mono(s16 *pcm_lr, s16 *pcm_mono, int points_len)
{
s16 pcm_L;
s16 pcm_R;
int i = 0;
for (i = 0; i < points_len; i++, pcm_lr += 2) {
pcm_L = *pcm_lr;
pcm_R = *(pcm_lr + 1);
*pcm_mono++ = (s16)(((int)pcm_L + pcm_R) >> 1);
}
}
static int pcm_stream_read(struct audio_decoder *decoder, void *buf, u32 len)
{
int rlen = 0;
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
local_irq_disable();
if (dec) {
if (dec->pcm_read_cb) {
rlen = dec->pcm_read_cb(NULL, (void *)buf, len);
}
if (dec->channel == 2 && dec->output_ch == 1) {
/* pcm_LR_to_mono((s16 *)buf, (s16 *)buf, rlen >> 2); */
/* rlen >>= 1; */
}
}
local_irq_enable();
if (!rlen) {
return -1;
}
return rlen;
}
static const struct audio_dec_input pcm_input = {
.coding_type = AUDIO_CODING_PCM,
.data_type = AUDIO_INPUT_FILE,
.ops = {
.file = {
.fread = pcm_stream_read,
}
}
};
static int pcm_dec_probe_handler(struct audio_decoder *decoder)
{
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
return 0;
}
static int pcm_dec_output_handler(struct audio_decoder *decoder, s16 *data, int len, void *priv)
{
struct pcm_dec_hdl *dec = container_of(decoder, struct pcm_dec_hdl, decoder);
if (!dec) {
return 0;
}
int rlen = len;
int wlen = 0;
if (!dec->remain) {
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_run(MUSIC_DVOL, data, len);
#endif
}
wlen = audio_mixer_ch_write(&dec->mix_ch, data, rlen);
if (!wlen) {
putchar('w');
}
rlen -= wlen;
if (rlen == 0) {
dec->remain = 0;
} else {
dec->remain = 1;
}
return len - rlen;
}
static const struct audio_dec_handler pcm_dec_handler = {
.dec_probe = pcm_dec_probe_handler,
.dec_output = pcm_dec_output_handler,
};
static void pcm_dec_event_handler(struct audio_decoder *decoder, int argc, int *argv)
{
switch (argv[0]) {
case AUDIO_DEC_EVENT_END:
/*pcm_audio_close();*/
break;
}
}
void pcm_dec_resume(void)
{
local_irq_disable();
if (pcm_dec && pcm_dec->start) {
audio_decoder_resume(&pcm_dec->decoder);
}
local_irq_enable();
}
static int pcm_audio_play_start(void)
{
int err;
y_printf(">>>>>>>> Enter Func: %s \n", __func__);
struct audio_fmt f = {0};
struct pcm_dec_hdl *dec = pcm_dec;
if (!pcm_dec) {
return -EINVAL;
}
err = audio_decoder_open(&dec->decoder, &pcm_input, &decode_task);
if (err) {
goto __err;
}
audio_decoder_set_handler(&dec->decoder, &pcm_dec_handler);
audio_decoder_set_event_handler(&dec->decoder, pcm_dec_event_handler, 0);
u8 dac_conn = audio_dac_get_channel(&dac_hdl);
if (dac_conn == DAC_OUTPUT_LR) {
dec->output_ch = 2;
} else {
dec->output_ch = 1;
}
f.coding_type = AUDIO_CODING_PCM;
f.sample_rate = dec->sample_rate;
f.channel = dec->output_ch;
err = audio_decoder_set_fmt(&dec->decoder, &f);
printf(">>>>>>>> %s, dec->output_ch : %d\n", __func__, dec->output_ch);
#if TCFG_AUDIO_OUTPUT_IIS
sound_pcm_dev_channel_mapping(dec->output_ch);
#endif
if (err) {
goto __err;
}
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_open(MUSIC_DVOL, app_audio_get_volume(APP_AUDIO_STATE_MUSIC), MUSIC_DVOL_MAX, MUSIC_DVOL_FS, -1);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
// 设置叠加功能
audio_mixer_ch_open(&dec->mix_ch, &mixer);
audio_mixer_ch_set_sample_rate(&dec->mix_ch, audio_output_rate(f.sample_rate));
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, vol, 0);
err = audio_decoder_start(&dec->decoder);
if (err) {
goto __err;
}
audio_codec_clock_set(AUDIO_PC_MODE, AUDIO_CODING_PCM, dec->wait.preemption);
dec->start = 1;
return 0;
__err:
return err;
}
static int pcm_audio_play_stop(void)
{
if (!pcm_dec || !pcm_dec->start) {
return 0;
}
pcm_dec->start = 0;
audio_decoder_close(&pcm_dec->decoder);
audio_mixer_ch_close(&pcm_dec->mix_ch);
#if (SYS_VOL_TYPE == VOL_TYPE_DIGITAL)
audio_digital_vol_close(MUSIC_DVOL);
#endif/*SYS_VOL_TYPE == VOL_TYPE_DIGITAL*/
return 0;
}
static int pcm_wait_res_handler(struct audio_res_wait *wait, int event)
{
int err = 0;
if (event == AUDIO_RES_GET) {
err = pcm_audio_play_start();
} else if (event == AUDIO_RES_PUT) {
/* pcm_audio_play_stop(); */
}
return err;
}
int pcm_audio_play_open(int sr, u8 ch)
{
struct pcm_dec_hdl *dec;
if (pcm_dec) {
return 0;
}
dec = zalloc(sizeof(*dec));
if (!dec) {
return -ENOMEM;
}
pcm_dec = dec;
dec->sample_rate = sr;
dec->channel = ch;
y_printf(">>> pcm_audio_play_open sr:%d ch:%d\n", dec->sample_rate, dec->channel); //通道是2个
dec->wait.priority = 2;
dec->wait.preemption = 1;
dec->wait.handler = pcm_wait_res_handler;
audio_decoder_task_add_wait(&decode_task, &dec->wait);
clock_add(DEC_PCM_CLK);
return 0;
}
void pcm_audio_play_close(void)
{
if (!pcm_dec) {
return;
}
pcm_audio_play_stop();
audio_decoder_task_del_wait(&decode_task, &pcm_dec->wait);
clock_remove(DEC_PCM_CLK);
local_irq_disable();
free(pcm_dec);
pcm_dec = NULL;
local_irq_enable();
}

View File

@ -0,0 +1,16 @@
#ifndef __AUDIO_DEC_PCM_H
#define __AUDIO_DEC_PCM_H
#include "asm/cpu.h"
void pcm_dec_resume(void);
void pcm_dec_set_read_cb(int (*pcm_read_func)(void *, void *, int));
int pcm_audio_play_open(int sr, u8 ch);
void pcm_audio_play_close(void);
extern int sound_pcm_dev_channel_mapping(int ch_num);
#endif

View File

@ -0,0 +1,920 @@
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "device/uac_stream.h"
#include "audio_enc.h"
#include "app_main.h"
#include "user_cfg_id.h"
#include "app_config.h"
#include "audio_codec_clock.h"
#include "audio_config.h"
/* #include "application/audio_echo_reverb.h" */
/*USB MIC上行数据同步及变采样模块使能*/
#define USB_MIC_SRC_ENABLE 1
#if TCFG_USB_MIC_CVP_ENABLE
#include "aec_user.h"
#include "overlay_code.h"
#endif/*TCFG_USB_MIC_CVP_ENABLE*/
#if USB_MIC_SRC_ENABLE
#include "audio_track.h"
#include "Resample_api.h"
#endif/*USB_MIC_SRC_ENABLE*/
#define USB_AUDIO_MIC_WRITE_TASK_NAME "usbmic_write"
#define PCM_ENC2USB_OUTBUF_LEN (6 * 1024)
#define USB_MIC_BUF_NUM 3
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
#define USB_MIC_CH_NUM 3 /* 3mic通话 */
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
#define USB_MIC_CH_NUM 2 /* 双mic通话 */
#else
#define USB_MIC_CH_NUM 1 /* 单mic通话 */
#endif
#define USB_MIC_IRQ_POINTS 256
#define USB_MIC_BUFS_SIZE (USB_MIC_CH_NUM * USB_MIC_BUF_NUM * USB_MIC_IRQ_POINTS)
#define USB_MIC_STOP 0x00
#define USB_MIC_START 0x01
#ifndef VM_USB_MIC_GAIN
#define VM_USB_MIC_GAIN 5
#endif
#define USB_PLNK_MIC_GAIN_ENABLE 1 //PLNK_MIC数字增益放大使能
#define USB_PLNK_MIC_DIG_GAIN 60.f //PLNK_MIC数字增益Gain = 10^(dB_diff/20))
extern struct audio_adc_hdl adc_hdl;
extern u16 uac_get_mic_vol(const u8 usb_id);
extern int usb_output_sample_rate();
#if USB_MIC_SRC_ENABLE
typedef struct {
u8 start;
u8 busy;
u16 in_sample_rate;
u16 out_sample_rate;
u32 *runbuf;
s16 output[320 * 3 + 16];
RS_STUCT_API *ops;
void *audio_track;
} usb_mic_sw_src_t;
static usb_mic_sw_src_t *usb_mic_src = NULL;
#endif/*USB_MIC_SRC_ENABLE*/
struct _usb_mic_hdl {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 adc_buf[USB_MIC_BUFS_SIZE];
enum enc_source source;
OS_SEM sem;
cbuffer_t output_cbuf;
u8 *output_buf;//[PCM_ENC2USB_OUTBUF_LEN];
u8 rec_tx_channels;
u8 mic_data_ok;/*mic数据等到一定长度再开始发送*/
u8 status;
u8 drop_data; //用来丢掉刚开mic的前几帧数据
#if TCFG_USB_MIC_ECHO_ENABLE
ECHO_API_STRUCT *p_echo_hdl;
#endif
#if (USB_MIC_CH_NUM > 1)
s16 tmp_buf[USB_MIC_IRQ_POINTS];
#endif/*USB_MIC_CH_NUM*/
#if (USB_MIC_CH_NUM > 2)
s16 tmp_buf_1[USB_MIC_IRQ_POINTS];
#endif/*USB_MIC_CH_NUM*/
s16 *usb_mic_data;
u16 data_len;
float dig_gain;
};
struct audio_sample_track_context {
u32 in_sr;
volatile u8 track_step;
volatile int samples;
volatile u32 sample_rate;
volatile u32 adc_points;
volatile u32 next_period;
volatile int period;
};
static u32 adc_hwp = 0;
static u32 adc_points = 0;
static void *user_audio_local_sample_track_open(int in_sr, int sample_rate, int period)
{
struct audio_sample_track_context *ctx;
ctx = (struct audio_sample_track_context *)zalloc(sizeof(struct audio_sample_track_context));
if (!ctx) {
return NULL;
}
ctx->in_sr = in_sr;
ctx->sample_rate = sample_rate;
ctx->period = period * sample_rate / 1000;
adc_points = 0;
return ctx;
}
int get_audio_adc_points_time()//获取总的采样周期
{
return adc_points + ((JL_AUDIO->ADC_HWP > adc_hwp) ? (JL_AUDIO->ADC_HWP - adc_hwp) : (JL_AUDIO->ADC_HWP + JL_AUDIO->ADC_LEN - adc_hwp));
}
static int user_audio_local_sample_track_in_period(void *c, int samples)
{
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
if (ctx->track_step == 0) {
ctx->track_step = 1;
goto __exit;
}
if (ctx->track_step == 1) {
ctx->track_step = 2;
ctx->next_period = ctx->period;
ctx->samples = 0;
goto __exit;
}
ctx->samples += samples;
if (time_after(ctx->samples, ctx->next_period)) {
int adc_points = get_audio_adc_points_time();
int points_diff = (adc_points - ctx->adc_points);
if (points_diff > 0) {
int sample_rate = ((u64)((u64)ctx->in_sr * (u64)ctx->samples)) / points_diff;
/* printf("> track : %d %d %d %d< \n", sample_rate, ctx->samples, ctx->in_sr, points_diff); */
/* printf("> track : %d < \n", sample_rate); */
ctx->sample_rate = sample_rate;
}
ctx->adc_points = adc_points;
ctx->next_period = ctx->period;
ctx->samples = 0;
}
__exit:
return ctx->sample_rate;
}
static int user_audio_local_sample_track_rate(void *c)
{
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
return ctx->sample_rate;
}
static void user_audio_local_sample_track_close(void *c)
{
struct audio_sample_track_context *ctx = (struct audio_sample_track_context *)c;
if (!ctx) {
return;
}
ctx->track_step = 0;
free(ctx);
}
static struct _usb_mic_hdl *usb_mic_hdl = NULL;
#if TCFG_USB_MIC_ECHO_ENABLE
ECHO_PARM_SET usbmic_echo_parm_default = {
.delay = 200, //回声的延时时间 0-300ms
.decayval = 50, // 0-70%
.direct_sound_enable = 1, //直达声使能 0/1
.filt_enable = 1, //发散滤波器使能
};
EF_REVERB_FIX_PARM usbmic_echo_fix_parm_default = {
.wetgain = 2048, ////湿声增益:[0:4096]
.drygain = 4096, ////干声增益: [0:4096]
.sr = MIC_EFFECT_SAMPLERATE, ////采样率
.max_ms = 200, ////所需要的最大延时,影响 need_buf 大小
};
#endif
static int usb_audio_mic_sync(u32 data_size)
{
#if 0
int change_point = 0;
if (data_size > __this->rec_top_size) {
change_point = -1;
} else if (data_size < __this->rec_bottom_size) {
change_point = 1;
}
if (change_point) {
struct audio_pcm_src src;
src.resample = 0;
src.ratio_i = (1024) * 2;
src.ratio_o = (1024 + change_point) * 2;
src.convert = 1;
dev_ioctl(__this->rec_dev, AUDIOC_PCM_RATE_CTL, (u32)&src);
}
#endif
return 0;
}
static int usb_audio_mic_tx_handler(int event, void *data, int len)
{
if (usb_mic_hdl == NULL) {
return 0;
}
if (usb_mic_hdl->status == USB_MIC_STOP) {
return 0;
}
int i = 0;
int r_len = 0;
u8 ch = 0;
u8 double_read = 0;
/* int rlen = 0; */
if (usb_mic_hdl->mic_data_ok == 0) {
if (usb_mic_hdl->output_cbuf.data_len > (PCM_ENC2USB_OUTBUF_LEN / 4)) {
usb_mic_hdl->mic_data_ok = 1;
}
//y_printf("mic_tx NULL\n");
memset(data, 0, len);
return len;
}
#if USB_MIC_SRC_ENABLE
if (usb_mic_src && usb_mic_src->audio_track) {
user_audio_local_sample_track_in_period(usb_mic_src->audio_track, (len >> 1) / usb_mic_hdl->rec_tx_channels);
}
#endif/*USB_MIC_SRC_ENABLE*/
/* usb_audio_mic_sync(size); */
if (usb_mic_hdl->rec_tx_channels == 2) {
len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len / 2);
s16 *tx_pcm = (s16 *)data;
int cnt = len / 2;
for (cnt = len / 2; cnt >= 2;) {
tx_pcm[cnt - 1] = tx_pcm[cnt / 2 - 1];
tx_pcm[cnt - 2] = tx_pcm[cnt / 2 - 1];
cnt -= 2;
}
len *= 2;
} else {
len = cbuf_read(&usb_mic_hdl->output_cbuf, data, len);
}
if (!len) {
putchar('M');
}
return len;
}
int usb_audio_mic_write(void *data, u16 len)
{
int wlen = len;
if (usb_mic_hdl) {
if (usb_mic_hdl->status == USB_MIC_STOP) {
return len;
}
int outlen = len;
s16 *obuf = data;
#if USB_MIC_SRC_ENABLE
if (usb_mic_src && usb_mic_src->start) {
usb_mic_src->busy = 1;
u32 sr = usb_output_sample_rate();
usb_mic_src->ops->set_sr(usb_mic_src->runbuf, sr);
outlen = usb_mic_src->ops->run(usb_mic_src->runbuf, data, len >> 1, usb_mic_src->output);
usb_mic_src->busy = 0;
ASSERT(outlen <= (sizeof(usb_mic_src->output) >> 1));
//printf("16->48k:%d,%d,%d\n",len >> 1,outlen,sizeof(usb_mic_src->output));
obuf = usb_mic_src->output;
outlen = outlen << 1;
}
#endif/*USB_MIC_SRC_ENABLE*/
wlen = cbuf_write(&usb_mic_hdl->output_cbuf, obuf, outlen);
if (wlen != outlen) {
r_printf("usb_mic write full:%d-%d\n", wlen, outlen);
}
}
return wlen;
}
static void adc_output_to_cbuf(void *priv, s16 *data, int len)
{
if (usb_mic_hdl == NULL) {
return ;
}
if (usb_mic_hdl->status == USB_MIC_STOP) {
return ;
}
switch (usb_mic_hdl->source) {
case ENCODE_SOURCE_MIC:
case ENCODE_SOURCE_LINE0_LR:
case ENCODE_SOURCE_LINE1_LR:
case ENCODE_SOURCE_LINE2_LR: {
adc_hwp = JL_AUDIO->ADC_HWP;
adc_points += len / 2;
#if TCFG_USB_MIC_CVP_ENABLE
#if (USB_MIC_CH_NUM == 3)/*3 Mic*/
s16 *mic0_data = data;
s16 *mic1_data = usb_mic_hdl->tmp_buf;
s16 *mic1_data_pos = usb_mic_hdl->tmp_buf_1;
//printf("mic_data: %x, %x, %d\n",data, mic1_data_pos, len);
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 3];
mic1_data[i] = data[i * 3 + 1];
mic1_data_pos[i] = data[i * 3 + 2];
}
audio_aec_inbuf_ref(mic1_data, len);
audio_aec_inbuf_ref_1(mic1_data_pos, len);
audio_aec_inbuf(data, len);
return;
#elif (USB_MIC_CH_NUM == 2)/*DualMic*/
s16 *mic0_data = data;
s16 *mic1_data = usb_mic_hdl->tmp_buf;
s16 *mic1_data_pos = data + (len / 2);
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 2];
mic1_data[i] = data[i * 2 + 1];
}
memcpy(mic1_data_pos, mic1_data, len);
#if 0 /*debug*/
static u16 mic_cnt = 0;
if (mic_cnt++ > 300) {
putchar('1');
audio_aec_inbuf(mic1_data_pos, len);
if (mic_cnt > 600) {
mic_cnt = 0;
}
} else {
putchar('0');
audio_aec_inbuf(mic0_data, len);
}
return;
#endif/*debug end*/
#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
audio_aec_inbuf_ref(mic1_data_pos, len);
audio_aec_inbuf(data, len);
#else
audio_aec_inbuf_ref(data, len);
audio_aec_inbuf(mic1_data_pos, len);
#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
#else/*SingleMic*/
audio_aec_inbuf(data, len);
#endif/*USB_MIC_CH_NUM*/
#else /* TCFG_USB_MIC_CVP_ENABLE == 0 */
if (usb_mic_hdl->drop_data != 0) {
usb_mic_hdl-> drop_data--;
memset(data, 0, len);
}
#if TCFG_USB_MIC_ECHO_ENABLE
if (usb_mic_hdl->p_echo_hdl) {
run_echo(usb_mic_hdl->p_echo_hdl, data, data, len);
}
#endif
/* 由于usb_audio_mic_write中SRC执行时间较长在adc中断中写数据会影响usb中断 */
/* 改为在usb_audio_mic_write_task中向usb写数据 */
/* adc输入一帧数据唤醒一次运行任务处理数据 */
usb_mic_hdl->usb_mic_data = data;
usb_mic_hdl->data_len = len;
os_sem_set(&usb_mic_hdl->sem, 0);
os_sem_post(&usb_mic_hdl->sem);
#endif
}
break;
default:
break;
}
}
#if USB_MIC_SRC_ENABLE
static int sw_src_init(u32 in_sr, u32 out_sr)
{
usb_mic_src = zalloc(sizeof(usb_mic_sw_src_t));
ASSERT(usb_mic_src);
usb_mic_src->in_sample_rate = in_sr;
usb_mic_src->out_sample_rate = out_sr;
usb_mic_src->ops = get_rs16_context();
/* usb_mic_src->ops = get_rsfast_context(); */
g_printf("ops:0x%x\n", usb_mic_src->ops);
ASSERT(usb_mic_src->ops);
u32 need_buf = usb_mic_src->ops->need_buf();
g_printf("runbuf:%d\n", need_buf);
usb_mic_src->runbuf = malloc(need_buf);
ASSERT(usb_mic_src->runbuf);
RS_PARA_STRUCT rs_para_obj;
rs_para_obj.nch = 1;
rs_para_obj.new_insample = in_sr;
rs_para_obj.new_outsample = out_sr;
printf("sw src,in = %d,out = %d\n", rs_para_obj.new_insample, rs_para_obj.new_outsample);
usb_mic_src->ops->open(usb_mic_src->runbuf, &rs_para_obj);
usb_mic_src->audio_track = user_audio_local_sample_track_open(in_sr, out_sr, 2000);
usb_mic_src->start = 1;
return 0;
}
static int sw_src_exit(void)
{
if (usb_mic_src) {
usb_mic_src->start = 0;
while (usb_mic_src->busy) {
putchar('w');
os_time_dly(2);
}
user_audio_local_sample_track_close(usb_mic_src->audio_track);
usb_mic_src->audio_track = NULL;
local_irq_disable();
if (usb_mic_src->runbuf) {
free(usb_mic_src->runbuf);
usb_mic_src->runbuf = 0;
}
free(usb_mic_src);
usb_mic_src = NULL;
local_irq_enable();
printf("sw_src_exit\n");
}
printf("sw_src_exit ok\n");
return 0;
}
#endif/*USB_MIC_SRC_ENABLE*/
#if TCFG_USB_MIC_CVP_ENABLE
static int usb_mic_aec_output(s16 *data, u16 len)
{
//putchar('k');
if (usb_mic_hdl == NULL) {
return len ;
}
if (usb_mic_hdl->status == USB_MIC_STOP) {
return len;
}
int outlen = len;
s16 *outdat = data;
/* if (aec_hdl->dump_packet) { */
/* aec_hdl->dump_packet--; */
/* //memset(outdat, 0, outlen); */
/* } */
u16 wlen = usb_audio_mic_write(outdat, outlen);
return len;
}
#endif
int uac_mic_vol_switch(int vol)
{
return vol * 14 / 100;
}
float uac_mic_dig_gain_switch(int vol)
{
float gain = vol / 10.f;
return gain;
}
/*
*********************************************************************
* USB Audio MIC Write Task
* Description: USB MIC 写数据任务
* Arguments : priv 私用参数
* Return : None.
* Note(s) : None.
*********************************************************************
*/
static void usb_audio_mic_write_task(void *priv)
{
printf("==Audio Usb Mic Write Task==\n");
while (1) {
os_sem_pend(&usb_mic_hdl->sem, 0);
putchar('.');
if (usb_mic_hdl->status) {
usb_audio_mic_write(usb_mic_hdl->usb_mic_data, usb_mic_hdl->data_len);
}
}
}
/*
*********************************************************************
* PDM MIC API
* Description: PDM mic操作接口
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
/* #define USB_PLNK_SR 16000#<{(|16000/44100/48000|)}># */
#define USB_PLNK_SCLK 2400000 /*1M-4M,SCLK/SR需为整数且在1-4096范围*/
#define USB_PLNK_CH_NUM 1 /*支持的最大通道(max = 2)*/
#define USB_PLNK_IRQ_POINTS 256 /*采样中断点数*/
#include "pdm_link.h"
#include "media/audio_gain_process.h"
static audio_plnk_t *audio_plnk_mic = NULL;
static void audio_plnk_mic_output(void *buf, u16 len)
{
s16 *mic0 = (s16 *)buf;
if (audio_plnk_mic) {
#if TCFG_USB_MIC_CVP_ENABLE
audio_aec_inbuf(mic0, len << 1);
#else
#if USB_PLNK_MIC_GAIN_ENABLE
GainProcess_16Bit(mic0, mic0, USB_PLNK_MIC_DIG_GAIN, 1, 1, 1, len);
#endif
usb_mic_hdl->usb_mic_data = mic0;
usb_mic_hdl->data_len = len << 1;
os_sem_set(&usb_mic_hdl->sem, 0);
os_sem_post(&usb_mic_hdl->sem);
#endif
}
}
static int usb_pdm_mic_en(u8 en, u16 sr, u16 gain)
{
printf("usb_pdm_mic_en:%d\n", en);
if (en) {
if (audio_plnk_mic) {
printf("audio_plnk_mic re-malloc error\n");
return -1;
}
audio_plnk_mic = zalloc(sizeof(audio_plnk_t));
if (audio_plnk_mic == NULL) {
printf("audio_plnk_mic zalloc failed\n");
return -1;
}
audio_mic_pwr_ctl(MIC_PWR_ON);
audio_plnk_mic->ch_num = USB_PLNK_CH_NUM;
audio_plnk_mic->sr = sr;
audio_plnk_mic->buf_len = USB_PLNK_IRQ_POINTS;
#if (PLNK_CH_EN == PLNK_CH0_EN)
audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
audio_plnk_mic->ch1_mode = CH1MD_CH0_SCLK_FALLING_EDGE;
#elif (PLNK_CH_EN == PLNK_CH1_EN)
audio_plnk_mic->ch0_mode = CH0MD_CH1_SCLK_FALLING_EDGE;
audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#else
audio_plnk_mic->ch0_mode = CH0MD_CH0_SCLK_RISING_EDGE;
audio_plnk_mic->ch1_mode = CH1MD_CH1_SCLK_RISING_EDGE;
#endif
audio_plnk_mic->buf = zalloc(audio_plnk_mic->buf_len * audio_plnk_mic->ch_num * 2 * 2);
ASSERT(audio_plnk_mic->buf);
audio_plnk_mic->sclk_io = TCFG_AUDIO_PLNK_SCLK_PIN;
audio_plnk_mic->ch0_io = TCFG_AUDIO_PLNK_DAT0_PIN;
audio_plnk_mic->ch1_io = TCFG_AUDIO_PLNK_DAT1_PIN;
audio_plnk_mic->output = audio_plnk_mic_output;
audio_plnk_open(audio_plnk_mic);
audio_plnk_start(audio_plnk_mic);
SFR(JL_ASS->CLK_CON, 0, 2, 3);
} else {
audio_plnk_close();
#if TCFG_AUDIO_ANC_ENABLE
//printf("anc_status:%d\n",anc_status_get());
if (anc_status_get() == 0) {
audio_mic_pwr_ctl(MIC_PWR_OFF);
}
#else
audio_mic_pwr_ctl(MIC_PWR_OFF);
#endif/*TCFG_AUDIO_ANC_ENABLE*/
if (audio_plnk_mic->buf) {
free(audio_plnk_mic->buf);
}
if (audio_plnk_mic) {
free(audio_plnk_mic);
audio_plnk_mic = NULL;
}
}
return 0;
}
#endif/* #if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC) */
int usb_audio_mic_open(void *_info)
{
int err = 0;
if (usb_mic_hdl) {
return 0;
}
usb_mic_hdl = zalloc(sizeof(*usb_mic_hdl));
if (!usb_mic_hdl) {
return -EFAULT;
}
usb_mic_hdl->status = USB_MIC_STOP;
usb_mic_hdl->output_buf = zalloc(PCM_ENC2USB_OUTBUF_LEN);
if (!usb_mic_hdl->output_buf) {
printf("usb_mic_hdl->output_buf NULL\n");
if (usb_mic_hdl) {
free(usb_mic_hdl);
usb_mic_hdl = NULL;
}
return -EFAULT;
}
u32 sample_rate = (u32)_info & 0xFFFFFF;
usb_mic_hdl->rec_tx_channels = (u32)_info >> 24;
usb_mic_hdl->source = ENCODE_SOURCE_MIC;
printf("usb mic sr:%d ch:%d\n", sample_rate, usb_mic_hdl->rec_tx_channels);
usb_mic_hdl->drop_data = 10; //用来丢掉前几帧数据
usb_mic_hdl->dig_gain = 1.f; // 用来初始化数字增益
u32 out_sample_rate = sample_rate;
#if TCFG_USB_MIC_CVP_ENABLE
sample_rate = 16000;
printf("usb mic sr[aec]:%d\n", sample_rate);
/*加载清晰语音处理代码*/
audio_cvp_code_load();
audio_aec_open(sample_rate, TCFG_USB_MIC_CVP_MODE, usb_mic_aec_output);
#else
os_sem_create(&usb_mic_hdl->sem, 0);
err = task_create(usb_audio_mic_write_task, NULL, USB_AUDIO_MIC_WRITE_TASK_NAME);
#endif
#if USB_MIC_SRC_ENABLE
sw_src_init(sample_rate, out_sample_rate);
#endif /*USB_MIC_SRC_ENABLE*/
cbuf_init(&usb_mic_hdl->output_cbuf, usb_mic_hdl->output_buf, PCM_ENC2USB_OUTBUF_LEN);
#if TCFG_MIC_EFFECT_ENABLE
app_var.usb_mic_gain = mic_effect_get_micgain();
#else
app_var.usb_mic_gain = uac_mic_vol_switch(uac_get_mic_vol(0));
#endif//TCFG_MIC_EFFECT_ENABLE
#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
mic_effect_to_usbmic_onoff(1);
#else
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
usb_pdm_mic_en(1, sample_rate, app_var.usb_mic_gain);
#else
audio_mic_pwr_ctl(MIC_PWR_ON);
#if 1
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0)
printf("adc_mic0 open\n");
audio_adc_mic_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
#ifndef TALK_MIC0_GAIN
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
#else
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, TALK_MIC0_GAIN);
#endif
#endif/*TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_0*/
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)
printf("adc_mic1 open\n");
audio_adc_mic1_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_1, &adc_hdl);
#ifndef FF_MIC1_GAIN
audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
#else
audio_adc_mic1_set_gain(&usb_mic_hdl->mic_ch, FF_MIC1_GAIN);
#endif
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_1)*/
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)
printf("adc_mic2 open\n");
audio_adc_mic2_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_2, &adc_hdl);
#ifndef FB_MIC2_GAIN
audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
#else
audio_adc_mic2_set_gain(&usb_mic_hdl->mic_ch, FB_MIC2_GAIN);
#endif
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_2)*/
#if (TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)
printf("adc_mic3 open\n");
audio_adc_mic3_open(&usb_mic_hdl->mic_ch, AUDIO_ADC_MIC_3, &adc_hdl);
#ifndef OTHER_MIC3_GAIN
audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, app_var.usb_mic_gain);
#else
audio_adc_mic3_set_gain(&usb_mic_hdl->mic_ch, OTHER_MIC3_GAIN);
#endif
#endif/*(TCFG_AUDIO_ADC_MIC_CHA & AUDIO_ADC_MIC_3)*/
audio_adc_mic_set_sample_rate(&usb_mic_hdl->mic_ch, sample_rate);
audio_adc_mic_set_buffs(&usb_mic_hdl->mic_ch, usb_mic_hdl->adc_buf, USB_MIC_IRQ_POINTS * 2, USB_MIC_BUF_NUM);
usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
audio_adc_add_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
audio_adc_mic_start(&usb_mic_hdl->mic_ch);
#else
audio_mic_open(&usb_mic_hdl->mic_ch, sample_rate, app_var.usb_mic_gain);
usb_mic_hdl->adc_output.handler = adc_output_to_cbuf;
audio_mic_add_output(&usb_mic_hdl->adc_output);
audio_mic_start(&usb_mic_hdl->mic_ch);
#endif
#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
#if TCFG_USB_MIC_ECHO_ENABLE
usb_mic_hdl->p_echo_hdl = open_echo(&usbmic_echo_parm_default, &usbmic_echo_fix_parm_default);
if (usb_mic_hdl->p_echo_hdl) {
update_echo_gain(usb_mic_hdl->p_echo_hdl, usbmic_echo_fix_parm_default.wetgain, usbmic_echo_fix_parm_default.drygain);
}
#endif
#endif//TCFG_USB_MIC_DATA_FROM_MICEFFECT
set_uac_mic_tx_handler(NULL, usb_audio_mic_tx_handler);
/* 需要用时钟管理防止其他操作降低USB_MIC时钟 */
audio_codec_clock_set(AUDIO_USB_MIC_MODE, AUDIO_CODING_PCM, 0);
usb_mic_hdl->status = USB_MIC_START;
/* __this->rec_begin = 0; */
return 0;
return -EFAULT;
}
u32 usb_mic_is_running()
{
if (usb_mic_hdl) {
return SPK_AUDIO_RATE;
}
return 0;
}
/*
*************************************************************
*
* usb mic gain save
*
*************************************************************
*/
static int usb_mic_gain_save_timer;
static u8 usb_mic_gain_save_cnt;
static void usb_audio_mic_gain_save_do(void *priv)
{
//printf(" usb_audio_mic_gain_save_do %d\n", usb_mic_gain_save_cnt);
local_irq_disable();
if (++usb_mic_gain_save_cnt >= 5) {
sys_timer_del(usb_mic_gain_save_timer);
usb_mic_gain_save_timer = 0;
usb_mic_gain_save_cnt = 0;
local_irq_enable();
printf("USB_GAIN_SAVE\n");
syscfg_write(VM_USB_MIC_GAIN, &app_var.usb_mic_gain, 1);
return;
}
local_irq_enable();
}
static void usb_audio_mic_gain_change(u8 gain)
{
local_irq_disable();
app_var.usb_mic_gain = gain;
usb_mic_gain_save_cnt = 0;
if (usb_mic_gain_save_timer == 0) {
usb_mic_gain_save_timer = sys_timer_add(NULL, usb_audio_mic_gain_save_do, 1000);
}
local_irq_enable();
}
int usb_audio_mic_get_gain(void)
{
return app_var.usb_mic_gain;
}
void usb_audio_mic_set_gain(int gain)
{
if (usb_mic_hdl == NULL) {
r_printf("usb_mic_hdl NULL gain");
return;
}
#ifndef CONFIG_BOARD_AISPEECH_NR_GAIN
gain = uac_mic_vol_switch(gain);
audio_adc_mic_set_gain(&usb_mic_hdl->mic_ch, gain);
usb_audio_mic_gain_change(gain);
#else
printf("AIS 3MIC set digital gain");
usb_mic_hdl->dig_gain = uac_mic_dig_gain_switch(gain);
#endif /*CONFIG_BOARD_AISPEECH_NR_GAIN*/
}
float usb_audio_mic_get_dig_gain(void)
{
if (usb_mic_hdl == NULL) {
r_printf("usb_mic_hdl NULL gain");
return 1;
}
return usb_mic_hdl->dig_gain;
}
int usb_audio_mic_close(void *arg)
{
if (usb_mic_hdl == NULL) {
r_printf("usb_mic_hdl NULL close");
return 0;
}
printf("usb_mic_hdl->status %x\n", usb_mic_hdl->status);
if (usb_mic_hdl && usb_mic_hdl->status == USB_MIC_START) {
printf("usb_audio_mic_close in\n");
usb_mic_hdl->status = USB_MIC_STOP;
#if TCFG_USB_MIC_CVP_ENABLE
audio_aec_close();
#else
task_kill(USB_AUDIO_MIC_WRITE_TASK_NAME);
#endif
#if (TCFG_USB_MIC_DATA_FROM_MICEFFECT)
mic_effect_to_usbmic_onoff(0);
#else
#if (TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC)
usb_pdm_mic_en(0, 0, 0);
#else
#if 1
audio_adc_mic_close(&usb_mic_hdl->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &usb_mic_hdl->adc_output);
#else
audio_mic_close(&usb_mic_hdl->mic_ch, &usb_mic_hdl->adc_output);
#endif
audio_mic_pwr_ctl(MIC_PWR_OFF);
#endif/*TCFG_AUDIO_ADC_MIC_CHA == PLNK_MIC*/
#if TCFG_USB_MIC_ECHO_ENABLE
if (usb_mic_hdl->p_echo_hdl) {
close_echo(usb_mic_hdl->p_echo_hdl);
}
#endif
#endif
#if USB_MIC_SRC_ENABLE
sw_src_exit();
#endif /*USB_MIC_SRC_ENABLE*/
cbuf_clear(&usb_mic_hdl->output_cbuf);
if (usb_mic_hdl) {
if (usb_mic_hdl->output_buf) {
free(usb_mic_hdl->output_buf);
usb_mic_hdl->output_buf = NULL;
}
free(usb_mic_hdl);
usb_mic_hdl = NULL;
}
#if TCFG_USB_MIC_CVP_ENABLE
audio_codec_clock_del(AUDIO_USB_MIC_MODE);
#endif /*TCFG_USB_MIC_CVP_ENABLE*/
}
printf("usb_audio_mic_close out\n");
return 0;
}
int usb_mic_stream_sample_rate(void)
{
#if USB_MIC_SRC_ENABLE
if (usb_mic_src && usb_mic_src->audio_track) {
int sr = user_audio_local_sample_track_rate(usb_mic_src->audio_track);
if ((sr < (usb_mic_src->out_sample_rate + 50)) && (sr > (usb_mic_src->out_sample_rate - 50))) {
return sr;
}
return usb_mic_src->out_sample_rate;
}
#endif /*USB_MIC_SRC_ENABLE*/
return 0;
}
u32 usb_mic_stream_size()
{
if (!usb_mic_hdl) {
return 0;
}
if (usb_mic_hdl->status == USB_MIC_START) {
if (usb_mic_hdl) {
return cbuf_get_data_size(&usb_mic_hdl->output_cbuf);
}
}
return 0;
}
u32 usb_mic_stream_length()
{
return PCM_ENC2USB_OUTBUF_LEN;
}
int usb_output_sample_rate()
{
int sample_rate = usb_mic_stream_sample_rate();
int buf_size = usb_mic_stream_size();
sample_rate = (u32)(usb_mic_src->in_sample_rate * sample_rate) / usb_mic_src->out_sample_rate;/*统计输出采样率,重新转换成输入采样率调输入*/
if (buf_size >= (usb_mic_stream_length() * 1 / 2)) {
sample_rate += (sample_rate * 5 / 10000);
//putchar('+');
}
if (buf_size <= (usb_mic_stream_length() / 3)) {
sample_rate -= (sample_rate * 5 / 10000);
//putchar('-');
}
return sample_rate;
}

1860
cpu/br28/audio_dec_eff.c Normal file

File diff suppressed because it is too large Load Diff

134
cpu/br28/audio_dec_eff.h Normal file
View File

@ -0,0 +1,134 @@
#ifndef _AUD_DEC_EFF_H
#define _AUD_DEC_EFF_H
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "classic/tws_api.h"
#include "classic/hci_lmp.h"
#include "media/eq_config.h"
#include "media/audio_surround.h"
#include "app_config.h"
#include "audio_config.h"
#include "app_main.h"
#include "media/audio_vbass.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
#endif/*TCFG_AUDIO_ANC_ENABLE*/
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG
#include "online_db_deal.h"
#endif
struct dec_sur {
#if AUDIO_SURROUND_CONFIG
surround_hdl *surround; //环绕音效句柄
u8 surround_eff; //音效模式记录
#endif
};
#if (defined(TCFG_AUDIO_OUT_EQ_ENABLE) && (TCFG_AUDIO_OUT_EQ_ENABLE != 0))
#define AUDIO_OUT_EQ_USE_SPEC_NUM 2 // 使用特定的eq段
#else
#define AUDIO_OUT_EQ_USE_SPEC_NUM 0
#endif
#define AUDIO_EQ_FADE_EN 1
#define HIGH_BASS_EQ_FADE_STEP (1)
#if TCFG_EQ_ENABLE&&TCFG_AUDIO_OUT_EQ_ENABLE
#define AUDIO_OUT_EFFECT_ENABLE 1 // 音频输出时的音效处理
#else
#define AUDIO_OUT_EFFECT_ENABLE 0
#endif//TCFG_AUDIO_OUT_EQ_ENABLE
extern struct audio_mixer mixer;
typedef int (*eq_output_cb)(void *, void *, int);
struct eq_filter_fade {
u16 tmr;
int cur_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
int use_gain[AUDIO_OUT_EQ_USE_SPEC_NUM];
};
struct dec_eq_drc {
s16 *eq_out_buf;
int eq_out_buf_len;
int eq_out_points;
int eq_out_total;
void *priv;
eq_output_cb out_cb;
void *drc_prev;
void *eq;
void *spk_eq;
void *drc;
u8 async;
u8 drc_bef_eq;
struct eq_filter_fade fade;
u8 remain;
};
struct eq_parm_new {
u8 in_mode: 2;
u8 run_mode: 2;
u8 data_in_mode: 2;
u8 data_out_mode: 2;
};
void *audio_surround_setup(u8 channel, u8 eff);
void audio_surround_free(void *sur);
void audio_surround_set_ch(void *sur, u8 channel);
void audio_surround_voice(void *sur, u8 en);
vbass_hdl *audio_vbass_setup(u32 sample_rate, u8 channel);
void audio_vbass_free(vbass_hdl *vbass);
void *dec_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
void dec_eq_drc_free(void *eff);
void *esco_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
void esco_eq_drc_free(void *eff);
void *audio_out_eq_drc_setup(void *priv, int (*eq_output_cb)(void *, void *, int), u32 sample_rate, u8 channel, u8 async, u8 drc_en);
void audio_out_eq_drc_free(void *eff);
int audio_out_eq_set_gain(void *eff, u8 idx, int gain);
int eq_drc_run(void *priv, void *data, u32 len);
void mix_out_drc_open(u16 sample_rate);
void mix_out_drc_close();
void mix_out_drc_run(s16 *data, u32 len);
/*----------------------------------------------------------------------------*/
/**@brief mix_out后限幅器系数更新
@param threadhold限幅器阈值-60~0,单位db
@return
@note
*/
/*----------------------------------------------------------------------------*/
void mix_out_drc_threadhold_update(float threadhold);
struct audio_drc *esco_limiter_open(u16 sample_rate, u16 ch_num);
void esco_limiter_run(struct audio_drc *limiter, s16 *data, u32 len);
void esco_limiter_close(struct audio_drc *limiter);
void spk_eq_seg_update(struct eq_seg_info *seg);
void spk_eq_global_gain_udapte(float global_gain);
void *spk_eq_open(u32 sample_rate, u8 ch_num, u8 bitwide);
void spk_eq_close(void *eq);
void spk_eq_run(void *eq, void *in, void *out, u16 len);
int spk_eq_save_to_vm();
void spk_eq_read_from_vm();
void spk_eq_set_send_data_handler(void (*handler)(u8 seq, u8 *packet, u8 size));
int spk_eq_app_online_parse(u8 *packet, u8 size, u8 *ext_data, u16 ext_size);
int spk_eq_spp_rx_packet(u8 *packet, u8 len);
int spk_eq_read_seg_l(u8 **buf);
int spk_eq_read_seg_r(u8 **buf);
void *audio_bass_boost_open(u32 sample_rate, u8 ch_num);
void audio_bass_boost_run(void *hdl, s16 *data, int len);
void audio_bass_boost_close(void *hdl);
extern struct virtual_bass_tool_set *get_vbass_parm();
#endif

View File

@ -0,0 +1,447 @@
/*
****************************************************************************
* Audio ADC Demo
*
*Description : Audio ADC使用范例
*Notes : (1)本demo为开发测试范例请不要修改该demo 如有需求,请自行
* 复制再修改
* (2)mic工作模式说明
* A.单端隔直(cap_mode)
* 可以选择mic供电方式外部供电还是内部供电(mic_bias_inside = 1)
* B.单端省电容(capless_mode)
* C.差分模式(cap_diff_mode)
****************************************************************************
*/
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "app_main.h"
#include "audio_config.h"
#include "audio_demo.h"
#include "asm/audio_adc.h"
#if 1
#define ADC_DEMO_LOG printf
#else
#define ADC_DEMO_LOG(...)
#endif
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#define ADC_DEMO_CH_NUM 4 /*支持的最大采样通道(max = 2)*/
#define ADC_DEMO_BUF_NUM 2 /*采样buf数*/
#define ADC_DEMO_IRQ_POINTS 256 /*采样中断点数*/
#define ADC_DEMO_BUFS_SIZE (ADC_DEMO_CH_NUM * ADC_DEMO_BUF_NUM * ADC_DEMO_IRQ_POINTS)
struct adc_demo {
u8 adc_2_dac;
u8 mic_idx;
u8 linein_idx;
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
struct adc_linein_ch linein_ch;
s16 adc_buf[ADC_DEMO_BUFS_SIZE];
u8 linein_ch_num;
u8 linein_ch_sel;
};
static struct adc_demo *mic_demo = NULL;
static struct adc_demo *linein_demo = NULL;
/* 选择输出哪路 linein采样的数据,可通过按键调用此函数实现每按一下按键切一下输出的linein通路 */
void linein_output_channel_sel()
{
if (linein_demo) {
linein_demo->linein_ch_sel += 1;
if (linein_demo->linein_ch_sel > linein_demo->linein_ch_num - 1) {
linein_demo->linein_ch_sel = 0;
}
}
}
/*
*********************************************************************
* AUDIO MIC OUTPUT
* Description: mic采样数据回调
* Arguments : pric 私有参数
* data mic数据
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 单声道数据格式
* L0 L1 L2 L3 L4 ...
* 双声道数据格式()
* L0 R0 L1 R1 L2 R2...
*********************************************************************
*/
#define ADC_DEBUG_BUF (0)
#define ADC_DEBUF_SIZE (32000)
#if ADC_DEBUG_BUF
u32 d_skip_cnt = 100;
s16 d_buf[ADC_DEBUF_SIZE / 2] = {0};
u8 *d_ptr = d_buf;
u32 d_buf_cnt = 0;
#endif
static void adc_mic_demo_output(void *priv, s16 *data, int len)
{
//printf("> %d %d %d %d\n", data[0], data[1], data[2], data[3]);
int wlen = 0;
if (mic_demo && mic_demo->adc_2_dac) {
if (mic_demo->mic_idx == (AUDIO_ADC_MIC_0 | AUDIO_ADC_MIC_1)) {
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
/*输出两个mic的数据到DAC两个通道*/
putchar('a');
wlen = audio_dac_write(&dac_hdl, data, len * 2);
#else
/*输出其中一个mic的数据到DAC一个通道*/
putchar('b');
s16 *mono_data = data;
for (int i = 0; i < (len / 2); i++) {
mono_data[i] = data[i * 2]; /*MIC_L*/
//mono_data[i] = data[i * 2 + 1]; /*MIC_R*/
}
wlen = audio_dac_write(&dac_hdl, mono_data, len);
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
} else {
/*输出一个mic的数据到DAC一个通道*/
putchar('c');
wlen = audio_dac_write(&dac_hdl, data, len);
}
}
#if ADC_DEBUG_BUF
wdt_close();
if (d_skip_cnt) {
d_skip_cnt--;
return;
}
d_buf_cnt += len * ADC_DEMO_CH_NUM;
if (d_buf_cnt >= ADC_DEBUF_SIZE) {
wdt_close();
local_irq_disable();
printf(">>> hex\n\n");
put_buf(d_buf, ADC_DEBUF_SIZE);
printf(">>> hex end\n\n");
u32 i;
for (i = 0; i < ADC_DEBUF_SIZE / 2; i++) {
/* printf("%d\n", d_buf[i]); */
}
printf(">>> printf end\n\n");
while (1);
}
memcpy(d_ptr, data, len * ADC_DEMO_CH_NUM);
d_ptr += len * ADC_DEMO_CH_NUM;
#endif
}
/*
*********************************************************************
* AUDIO Linein OUTPUT
* Description: linein采样数据回调
* Arguments : pric 私有参数
* data mic数据
* len 数据长度
* Return : 0 成功 其他 失败
* Note(s) : 单声道数据格式
* L0 L1 L2 L3 L4 ...
* 双声道数据格式()
* L0 R0 L1 R1 L2 R2...
*********************************************************************
*/
#define LINEIN_DEBUG_BUF (0)
#define LINEIN_DEBUF_SIZE (32000)
#if LINEIN_DEBUG_BUF
u32 l_skip_cnt = 100;
s16 l_buf[LINEIN_DEBUF_SIZE / 2] = {0};
u8 *l_ptr = l_buf;
u32 l_buf_cnt = 0;
#endif
static void adc_linein_demo_output(void *priv, s16 *data, int len)
{
/* printf("> %d %d %d %d\n", data[0], data[1], data[2], data[3]); */
int wlen = 0;
if (linein_demo && linein_demo->adc_2_dac) {
if (linein_demo->linein_ch_num >= 2) {
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
/*输出两个linein的数据到DAC两个通道,默认输出第一个和第二个采样通道的数据*/
putchar('a');
s16 temp[len * 2];
for (int i = 0; i < len / 2; i++) {
temp[2 * i] = data[linein_demo->linein_ch_num * i];
temp[2 * i + 1] = data[linein_demo->linein_ch_num * i + 1];
}
wlen = audio_dac_write(&dac_hdl, temp, len * 2);
#else
/*输出其中一个linein的数据到DAC一个通道*/
putchar('b');
s16 *mono_data = data;
for (int i = 0; i < (len / 2); i++) {
switch (linein_demo->linein_ch_sel) {
case 0:
mono_data[i] = data[i * linein_demo->linein_ch_num]; /*第一路 linein采样的数据*/
break;
case 1:
mono_data[i] = data[i * linein_demo->linein_ch_num + 1]; /*第一路 linein采样的数据*/
break;
case 2:
mono_data[i] = data[i * linein_demo->linein_ch_num + 2]; /*第三路 linein采样的数据*/
break;
case 3:
mono_data[i] = data[i * linein_demo->linein_ch_num + 3]; /*第四路 linein采样的数据*/
break;
default:
break;
}
}
wlen = audio_dac_write(&dac_hdl, mono_data, len);
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
} else {
/*输出一个linein的数据到DAC一个通道*/
putchar('c');
wlen = audio_dac_write(&dac_hdl, data, len);
}
}
#if LINEIN_DEBUG_BUF
wdt_close();
if (l_skip_cnt) {
l_skip_cnt--;
return;
}
l_buf_cnt += len * ADC_DEMO_CH_NUM;
if (l_buf_cnt >= LINEIN_DEBUF_SIZE) {
wdt_close();
local_irq_disable();
printf(">>> hex\n\n");
put_buf(l_buf, LINEIN_DEBUF_SIZE);
printf(">>> hex end\n\n");
u32 i;
for (i = 0; i < LINEIN_DEBUF_SIZE / 2; i++) {
/* printf("%d\n", l_buf[i]); */
}
printf(">>> printf end\n\n");
while (1);
}
memcpy(l_ptr, data, len * ADC_DEMO_CH_NUM);
l_ptr += len * ADC_DEMO_CH_NUM;
#endif
}
/*
*********************************************************************
* AUDIO ADC MIC OPEN
* Description: 打开mic通道
* Arguments : mic_idx mic通道
* gain mic增益
* sr mic采样率
* mic_2_dac mic数据通过DAC监听
* Return : None.
* Note(s) : (1)打开一个mic通道示例
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_0,10,16000,1);
* 或者
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1,10,16000,1);
* (2)打开两个mic通道示例
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1|AUDIO_ADC_MIC_0,10,16000,1);
*********************************************************************
*/
void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac)
{
ADC_DEMO_LOG("audio_adc_mic_demo open:%d,gain:%d,sr:%d,mic_2_dac:%d\n", mic_idx, gain, sr, mic_2_dac);
mic_demo = zalloc(sizeof(struct adc_demo));
if (mic_demo) {
//step0:打开mic通道并设置增益
audio_adc_mic_open(&mic_demo->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
audio_adc_mic_set_gain(&mic_demo->mic_ch, gain);
audio_adc_mic_0dB_en(1);
//step1:设置mic通道采样率
audio_adc_mic_set_sample_rate(&mic_demo->mic_ch, sr);
//step2:设置mic采样buf
audio_adc_mic_set_buffs(&mic_demo->mic_ch, mic_demo->adc_buf, ADC_DEMO_IRQ_POINTS * 2, ADC_DEMO_BUF_NUM);
//step3:设置mic采样输出回调函数
mic_demo->adc_output.handler = adc_mic_demo_output;
audio_adc_add_output_handler(&adc_hdl, &mic_demo->adc_output);
//step4:启动mic通道采样
audio_adc_mic_start(&mic_demo->mic_ch);
/*监听配置(可选)*/
mic_demo->adc_2_dac = mic_2_dac;
mic_demo->mic_idx = mic_idx;
if (mic_2_dac) {
ADC_DEMO_LOG("max_sys_vol:%d\n", get_max_sys_vol());
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
ADC_DEMO_LOG("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_sample_rate(&dac_hdl, sr);
audio_dac_start(&dac_hdl);
}
}
ADC_DEMO_LOG("audio_adc_mic_demo start succ\n");
int res = 0;
int msg[16];
// 循环一直往dac写数据
#ifdef BT_DUT_ADC_INTERFERE
while (0) {
#else
while (1) {
#endif/*BT_DUT_ADC_INTERFERE*/
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
os_time_dly(500);
}
}
/*
*********************************************************************
* AUDIO ADC MIC CLOSE
* Description: 关闭mic采样模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_adc_mic_demo_close(void)
{
ADC_DEMO_LOG("audio_adc_mic_demo_close\n");
if (mic_demo) {
audio_adc_del_output_handler(&adc_hdl, &mic_demo->adc_output);
audio_adc_mic_close(&mic_demo->mic_ch);
free(mic_demo);
mic_demo = NULL;
}
}
/*
*********************************************************************
* AUDIO ADC linein OPEN
* Description: 打开linein通道
* Arguments : linein_idx linein通道
* gain linein增益
* sr linein采样率
* linein_2_dac linein数据通过DAC监听
* Return : None.
* Note(s) : (1)打开一个linein通道示例
* audio_adc_linein_demo_open(AUDIO_ADC_LINE0,10,16000,1);
* 或者
* audio_adc_linein_demo_open(AUDIO_ADC_LINE1,10,16000,1);
* (2)打开两个linein通道示例
* audio_adc_linein_demo_open(AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
* (3)打开四个linein通道示例
* audio_adc_linein_demo_open(AUDIO_ADC_LINE3|AUDIO_ADC_LINE2|AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
*********************************************************************
*/
void audio_adc_linein_demo_open(u8 linein_idx, u8 gain, u16 sr, u8 linein_2_dac)
{
ADC_DEMO_LOG("audio_adc_linein_demo open:%d,gain:%d,sr:%d,linein_2_dac:%d\n", linein_idx, gain, sr, linein_2_dac);
linein_demo = zalloc(sizeof(struct adc_demo));
if (linein_demo) {
//step0:打开linein通道并设置增益
if (linein_idx & AUDIO_ADC_LINE0) {
audio_adc_linein_open(&linein_demo->linein_ch, AUDIO_ADC_LINE0, &adc_hdl);
audio_adc_linein_set_gain(&linein_demo->linein_ch, gain);
audio_adc_linein_0dB_en(1);
linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE1) {
audio_adc_linein1_open(&linein_demo->linein_ch, AUDIO_ADC_LINE1, &adc_hdl);
audio_adc_linein1_set_gain(&linein_demo->linein_ch, gain);
audio_adc_linein1_0dB_en(1);
linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE2) {
audio_adc_linein2_open(&linein_demo->linein_ch, AUDIO_ADC_LINE2, &adc_hdl);
audio_adc_linein2_set_gain(&linein_demo->linein_ch, gain);
audio_adc_linein2_0dB_en(1);
linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE3) {
audio_adc_linein3_open(&linein_demo->linein_ch, AUDIO_ADC_LINE3, &adc_hdl);
audio_adc_linein3_set_gain(&linein_demo->linein_ch, gain);
audio_adc_linein3_0dB_en(1);
linein_demo->linein_ch_num += 1;
}
//step1:设置linein通道采样率
audio_adc_linein_set_sample_rate(&linein_demo->linein_ch, sr);
//step2:设置linein采样buf
audio_adc_linein_set_buffs(&linein_demo->linein_ch, linein_demo->adc_buf, ADC_DEMO_IRQ_POINTS * 2, ADC_DEMO_BUF_NUM);
//step3:设置linein采样输出回调函数
linein_demo->adc_output.handler = adc_linein_demo_output;
audio_adc_add_output_handler(&adc_hdl, &linein_demo->adc_output);
//step4:启动linein通道采样
audio_adc_linein_start(&linein_demo->linein_ch);
/*监听配置(可选)*/
linein_demo->adc_2_dac = linein_2_dac;
linein_demo->linein_idx = linein_idx;
if (linein_2_dac) {
ADC_DEMO_LOG("max_sys_vol:%d\n", get_max_sys_vol());
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
ADC_DEMO_LOG("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_sample_rate(&dac_hdl, sr);
audio_dac_start(&dac_hdl);
}
}
ADC_DEMO_LOG("audio_adc_linein_demo start succ\n");
int res = 0;
int msg[16];
// 循环一直往dac写数据
while (1) {
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
os_time_dly(500);
}
}
/*
*********************************************************************
* AUDIO ADC linein CLOSE
* Description: 关闭linein采样模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_adc_linein_demo_close(void)
{
ADC_DEMO_LOG("audio_adc_linein_demo_close\n");
if (linein_demo) {
audio_adc_del_output_handler(&adc_hdl, &linein_demo->adc_output);
audio_adc_linein_close(&linein_demo->linein_ch);
free(linein_demo);
linein_demo = NULL;
}
}
//开启audio_adc接口 用于测试BT干扰
void audio_adc_mic_dut_open(void)
{
audio_adc_mic_demo_open(AUDIO_ADC_MIC_0, 10, 16000, 0);
}
#if AUDIO_DEMO_LP_REG_ENABLE
static u8 adc_demo_idle_query()
{
return mic_demo ? 0 : 1;
}
REGISTER_LP_TARGET(adc_demo_lp_target) = {
.name = "adc_demo",
.is_idle = adc_demo_idle_query,
};
#endif/*AUDIO_DEMO_LP_REG_ENABLE*/

View File

@ -0,0 +1,203 @@
/*
****************************************************************************
* Audio DAC Demo
*
*Description : Audio DAC使用范例
*Notes : 本demo为开发测试范例请不要修改该demo 如有需求,请自行
* 复制再修改
****************************************************************************
*/
#include "audio_demo.h"
#include "media/includes.h"
#include "audio_config.h"
#include "audio_demo.h"
#define KEY_TEST 0//(IO_PORTB_01)
#define KEY_TEST2 0//(IO_PORTB_02)
extern struct audio_dac_hdl dac_hdl;
static u8 dac_demo = 0;
// 用于 DAC 播放的正弦波数据
const s16 data_sin44100[441] = {
0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
};
/*
*********************************************************************
* AUDIO DAC OPEN
* Description: 打开 dac demo
* Arguments : None
* Return : None.
* Note(s) : dac 播放正弦波
* 将这个函数放audio_dec_init()后调用即可
*********************************************************************
*/
void audio_dac_demo_open(void)
{
int len = 0;
int wlen = 0;
s16 *ptr;
s16 *data_addr;
u32 data_len;
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol()); // 音量状态设置
audio_dac_set_volume(&dac_hdl, get_max_sys_vol()); // dac 音量设置
audio_dac_set_sample_rate(&dac_hdl, 44100); // 采样率设置
audio_dac_start(&dac_hdl); // dac 启动
// 判断声道数,双声道需要复制多一个声道的数据
if (dac_hdl.channel == 2) {
data_addr = zalloc(441 * 2 * 2);
if (!data_addr) {
printf("demo dac malloc err !!\n");
return;
}
for (int i = 0; i < 882; i++) {
data_addr[i] = data_sin44100[i / 2];
}
data_len = 441 * 2 * 2;
} else {
data_addr = data_sin44100;
data_len = 441 * 2;
}
dac_demo = 1;
int res = 0;
int msg[16];
u8 mode = 0;
#if KEY_TEST
gpio_direction_input(KEY_TEST);
gpio_set_pull_down(KEY_TEST, 0);
gpio_set_pull_up(KEY_TEST, 1);
gpio_set_die(KEY_TEST, 1);
#endif
#if KEY_TEST2
gpio_direction_input(KEY_TEST2);
gpio_set_pull_down(KEY_TEST2, 0);
gpio_set_pull_up(KEY_TEST2, 1);
gpio_set_die(KEY_TEST2, 1);
#endif
// 循环一直往dac写数据
while (1) {
// 这句是为了防止线程太久没有响应系统而产生异常,实际使用不需要
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
ptr = data_addr;
len = data_len;
while (len) {
// 往 dac 写数据
wlen = audio_dac_write(&dac_hdl, ptr, len);
#if KEY_TEST
if (0 == gpio_read(KEY_TEST)) {
while (0 == gpio_read(KEY_TEST)) {
os_time_dly(1);
};
mode++;
if (mode >= 3) {
mode = 0;
}
printf(">> mode:%d\n", mode);
if (mode == 0) {
JL_AUDIO->DAC_VL0 = 0;
printf(">> silence\n");
} else if (mode == 1) {
JL_AUDIO->DAC_VL0 = 0x40004000;
printf(">> 0dB\n");
} else {
JL_AUDIO->DAC_VL0 = 0x000F000F;
printf(">> -60dB\n");
}
}
#endif
#if KEY_TEST2
if (0 == gpio_read(KEY_TEST2)) {
while (0 == gpio_read(KEY_TEST2)) {
os_time_dly(1);
};
static u8 analog_gain = 0;
u32 TMP_CON1;
TMP_CON1 = JL_ADDA->DAA_CON1;
TMP_CON1 &= ~(0xf << 0 | 0xf << 4);
TMP_CON1 |= ((u32)(analog_gain & 0xf) << 0) | ((u32)(analog_gain & 0xf) << 4);
JL_ADDA->DAA_CON1 = TMP_CON1;
printf(">>> analog_gain: %d\n", analog_gain);
analog_gain++;
if (analog_gain > 15) {
analog_gain = 0;
}
}
#endif
if (wlen != len) { // dac缓存满了延时 10ms 后再继续写
os_time_dly(1);
}
ptr += wlen / 2;
len -= wlen;
}
}
}
/*
*********************************************************************
* AUDIO DAC CLOSE
* Description: 关闭 dac demo
* Arguments : None
* Return : None.
* Note(s) : dac 停止播放正弦波
*********************************************************************
*/
void audio_dac_demo_close(void)
{
// 停止并关闭 DAC
audio_dac_stop(&dac_hdl);
audio_dac_close(&dac_hdl);
dac_demo = 0;
}
#if AUDIO_DEMO_LP_REG_ENABLE
static u8 dac_demo_idle_query()
{
return dac_demo ? 0 : 1;
}
REGISTER_LP_TARGET(dac_demo_lp_target) = {
.name = "dac_demo",
.is_idle = dac_demo_idle_query,
};
#endif/*AUDIO_DEMO_LP_REG_ENABLE*/

View File

@ -0,0 +1,158 @@
/*
****************************************************************************
* Audio Demo Declaration
*
*Description : Audio Demo函数声明集合
*Notes : None.
****************************************************************************
*/
#ifndef __AUDIO_DEMO_H_
#define __AUDIO_DEMO_H_
#include "generic/typedef.h"
/*audio demo低功耗注册查询防止调用demo的时候进入低功耗影响测试*/
#define AUDIO_DEMO_LP_REG_ENABLE 0
/**********************************************************************
*
* Audio DAC Demo APIs
*
**********************************************************************/
/**********************************************************************
*
* Audio ADC Demo APIs
*
**********************************************************************/
/*
*********************************************************************
* AUDIO ADC MIC OPEN
* Description: 打开mic通道
* Arguments : mic_idx mic通道
* gain mic增益
* sr mic采样率
* mic_2_dac mic数据通过DAC监听
* Return : None.
* Note(s) : (1)打开一个mic通道示例
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_0,10,16000,1);
* 或者
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1,10,16000,1);
* (2)打开两个mic通道示例
* audio_adc_mic_demo_open(AUDIO_ADC_MIC_1|AUDIO_ADC_MIC_0,10,16000,1);
*********************************************************************
*/
// void audio_adc_mic_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
/*
*********************************************************************
* AUDIO ADC MIC CLOSE
* Description: 关闭mic采样模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
// void audio_adc_mic_demo_close(void);
/**********************************************************************
*
* Audio AudioLink(IIS) APIs
*
**********************************************************************/
/*
*********************************************************************
* AUDIO IIS OUTPUT/INPUT OPEN
* Description: 打开iis通道
* Arguments : iis_rx 是否打开iis输入
* iis_tx 是否打开iis输出
* sr iis采样率
* iis_rx_2_dac iis_rx数据通过DAC监听
* Return : None.
* Note(s) : (1)打开一个iis rx通道示例
* audio_link_demo_open(1,0,44100,1);
* (2)打开一个iis tx通道示例
* audio_link_demo_open(0,1,44100,0);
* (3)同时打开iis tx 和 rx 通道示例:
* audio_link_demo_open(1,1,44100,1);
*********************************************************************
*/
// void audio_link_demo_open(u8 iis_rx, u8 iis_tx, u16 sr, u8 iis_rx_2_dac);
/*
*********************************************************************
* AUDIO IIS OUTPUT/INPUT OPEN
* Description: 打开iis通道
* Arguments : iis_rx 是否关闭iis输入
* iis_tx 是否关闭iis输出
* Return : None.
* Note(s) : (1)关闭一个iis rx通道示例
* audio_link_demo_open(1,0);
* (2)关闭一个iis tx通道示例
* audio_link_demo_open(0,1);
* (3)同时关闭iis tx 和 rx 通道示例:
* audio_link_demo_open(1,1);
*********************************************************************
*/
// void audio_link_demo_close(u8 iis_rx, u8 iis_tx);
/**********************************************************************
*
* Audio PDM APIs
*
**********************************************************************/
/*
*********************************************************************
* AUDIO PDM MIC OPEN
* Description: 打开pdm mic模块
* Arguments : sample pdm mic采样率
* mic_2_dac mic数据通过DAC监听
* Return : None.
* Note(s) : (1)打开pdm mic通道示例
* audio_plnk_demo_open(16000, 1);
*********************************************************************
*/
// void audio_plnk_demo_open(u16 sample, u8 mic_2_dac);
/*
*********************************************************************
* AUDIO PDM MIC CLOSE
* Description: 关闭pdm mic模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
// void audio_plnk_demo_close(void);
/*
*********************************************************************
* hw_fft_demo_real
* Description: 实数数据 FFT 运算 demo
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
// extern void hw_fft_demo_real();
/*
*********************************************************************
* hw_fft_demo_complex
* Description: 复数数据 FFT 运算 demo
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
// extern void hw_fft_demo_complex();
#endif/*__AUDIO_DEMO_H_*/

View File

@ -0,0 +1,101 @@
/*
****************************************************************************
* Audio FFT Demo
*
*Description : Audio FFT使用范例
*Notes :
*(1)本demo为开发测试范例请不要修改该demo 如有需求,请自行复制再修改
*(2)FFT输入数据位宽
*----------------------------------------------------------------------
* FFT模式 FFT点数 最大输入位宽
*----------------------------------------------------------------------
* 复数 64 [21:0]
* 128 [20:0]
* 256 [19:0]
* 512 [18:0]
* 1024 [17:0]
*----------------------------------------------------------------------
* 实数 64 [20:0]
* 128 [18:0]
* 256 [17:0]
* 512 [18:0]
* 1024 [16:0]
*----------------------------------------------------------------------
*(3)IFFT输入位宽[29:0]
****************************************************************************
*/
#include "audio_demo.h"
#include "hw_fft.h"
// For 128 point Real_FFT test
void hw_fft_demo_real()
{
int tmpbuf[130]; // 130 = (128/2+1)*2
unsigned int fft_config;
printf("********* test start **************\n");
for (int i = 0; i < 128; i++) {
tmpbuf[i] = i + 1;
printf("tmpbuf[%d]: %d \n", i, tmpbuf[i]);
}
// Do 128 point FFT
fft_config = hw_fft_config(128, 7, 1, 0, 1);
hw_fft_run(fft_config, tmpbuf, tmpbuf);
for (int i = 0; i < 130; i++) {
printf("tmpbuf_[%d]: %d \n", i, tmpbuf[i]);
}
// Do 128 point IFFT
fft_config = hw_fft_config(128, 7, 1, 1, 1);
hw_fft_run(fft_config, tmpbuf, tmpbuf);
for (int i = 0; i < 128; i++) {
printf("tmpbuf_[%d]: %d \n", i, tmpbuf[i]);
}
}
// For 128 point Complex_FFT test
void hw_fft_demo_complex()
{
int tmpbuf[280]; // 280 = (128/2+1)*2*2
unsigned int fft_config;
printf("********* test start **************\n");
for (int i = 0; i < 128; i++) {
tmpbuf[2 * i] = i + 1;
tmpbuf[2 * i + 1] = i + 1;
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
}
// Do 128 point FFT
fft_config = hw_fft_config(128, 7, 1, 0, 0);
hw_fft_run(fft_config, tmpbuf, tmpbuf);
for (int i = 0; i < 128; i++) {
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
}
// Do 128 point IFFT
fft_config = hw_fft_config(128, 7, 1, 1, 0);
hw_fft_run(fft_config, tmpbuf, tmpbuf);
for (int i = 0; i < 128; i++) {
printf("tmpbuf[%d]: %d \n", 2 * i, tmpbuf[2 * i]);
printf("tmpbuf[%d]: %d \n", 2 * i + 1, tmpbuf[2 * i + 1]);
}
}

View File

@ -0,0 +1,558 @@
#include "asm/MatrixInteFunc.h"
char src_a_u8[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
char src_b_u8[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
char dst_u8[16]__attribute__((aligned(4)));
short int src_a_16[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
short int src_b_16[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
short int dst_16[16]__attribute__((aligned(4)));
int src_a_32[16]__attribute__((aligned(4))) = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
int src_b_32[16]__attribute__((aligned(4))) = {4, 5, 6, 7, 10, 11, 12, 13, 4, 5, 6, 7, 10, 11, 12, 13};
int dst_32[16]__attribute__((aligned(4)));
MC MC_t;
MXYZ MXYZ_a, MXYZ_b, MXYZ_c;
void test_MatrixInteFunc_add_sub()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 4 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
MXYZ_a.Dw = DW_16;
MXYZ_a.RowStep = MXYZ_a.Dw ;
MXYZ_a.ColStep = MXYZ_a.Dw * (MC_t.MatCol + 1);
MXYZ_a.Conj = 0;
MXYZ_b.Dw = DW_16;
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
MXYZ_b.RowStep = MXYZ_b.Dw ;
MXYZ_b.ColStep = MXYZ_b.Dw * (MC_t.MatCol + 1);
MXYZ_b.Conj = 0;
MXYZ_c.Dw = DW_16;
MXYZ_c.MatAdr = (unsigned int)&dst_16;
MXYZ_c.RowStep = MXYZ_c.Dw ;
MXYZ_c.ColStep = MXYZ_c.Dw * (MC_t.MatCol + 1);
MXYZ_c.Conj = 0;
MatrixADD_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_16[k]);
}
//sub
//MXYZ_a.MatAdr = &src_a_16;
MXYZ_a.Dw = DW_16;
MXYZ_a.RowStep = MXYZ_a.Dw ;
MXYZ_a.ColStep = MXYZ_a.Dw * (MC_t.MatCol + 1);
MXYZ_a.Conj = 0;
MXYZ_b.Dw = DW_16;
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
MXYZ_b.RowStep = MXYZ_b.Dw ;
MXYZ_b.ColStep = MXYZ_b.Dw * (MC_t.MatCol + 1);
MXYZ_b.Conj = 0;
MXYZ_c.Dw = DW_16;
MXYZ_c.MatAdr = (unsigned int)&dst_16;
MXYZ_c.RowStep = MXYZ_c.Dw ;
MXYZ_c.ColStep = MXYZ_c.Dw * (MC_t.MatCol + 1);
MXYZ_c.Conj = 0;
MatrixSUB_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_16[k]);
}
}
void test_MatrixInteFunc_scale_add_sub()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 4 - 1;
MC_t.MatQ = 1;
MC_t.RS = 4;
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
MXYZ_a.RowStep = 1;
MXYZ_a.ColStep = 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_8;
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
MXYZ_b.RowStep = 1;
MXYZ_b.ColStep = 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_8;
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
MXYZ_c.RowStep = 1;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_8;
MatrixScaleADD_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_u8[k]);
}
//sub
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
MXYZ_c.MatAdr = (unsigned int)&dst_16;
MXYZ_a.Dw = DW_16;
MXYZ_b.Dw = DW_16;
MXYZ_c.Dw = DW_16;
MXYZ_a.RowStep = 1 * 2;
MXYZ_a.ColStep = 4 * 2;
MXYZ_b.RowStep = 1 * 2;
MXYZ_b.ColStep = 4 * 2;
MXYZ_c.RowStep = 1 * 2;
MXYZ_c.ColStep = 4 * 2;
MatrixScaleSUB_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_16[k]);
}
}
void test_MatrixInteFunc_scale_mul_mla_mls()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 4 - 1;
MC_t.MatQ = 1;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
MXYZ_a.RowStep = 1;
MXYZ_a.ColStep = 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_8;
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
MXYZ_b.RowStep = 1;
MXYZ_b.ColStep = 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_8;
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
MXYZ_c.RowStep = 1;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_8;
MatrixScaleMUL_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
//
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_u8[k]);
}
for (int k = 0; k < 8; k++) {
dst_32[k] = k;
}
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_a.Dw = DW_32;
MXYZ_b.Dw = DW_32;
MXYZ_c.Dw = DW_32;
MXYZ_a.RowStep = 1 * 4;
MXYZ_a.ColStep = 4 * 4;
MXYZ_b.RowStep = 1 * 4;
MXYZ_b.ColStep = 4 * 4;
MXYZ_c.RowStep = 1 * 4;
MXYZ_c.ColStep = 4 * 4;
MatrixScaleMLA_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_32[k]);
}
//
for (int k = 0; k < 8; k++) {
dst_32[k] = -1;
}
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_a.Dw = DW_32;
MXYZ_b.Dw = DW_32;
MXYZ_c.Dw = DW_32;
MatrixScaleMLS_Real(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_32[k]);
}
}
void test_Matvec_mul()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 4 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_a.RowStep = 1 * 4;
MXYZ_a.ColStep = 4 * 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_b.RowStep = 1 * 4;
MXYZ_b.ColStep = 4 * 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_32;
/*MXYZ_c.MatAdr = &dst_32;
MXYZ_c.RowStep = 1;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_32;*/
int sum;
MatVecMUL_Real(&MXYZ_a, &MXYZ_b, &sum, &MC_t, 1);
//
/*for(int k = 0;k<8;k++)
{
printf("dst_u8=%d\n",dst_32[k]);
}*/
printf("sum=%d\n", sum);
}
//complex
void test_MatrixInteFunc_add_sub_complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
MXYZ_a.RowStep = 1 * 2;
MXYZ_a.ColStep = 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_8;
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
MXYZ_b.RowStep = 1 * 2;
MXYZ_b.ColStep = 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_8;
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
MXYZ_c.RowStep = 1 * 2;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_8;
MatrixADD_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_u8[k]);
}
//sub
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
MXYZ_c.MatAdr = (unsigned int)&dst_16;
MXYZ_a.Dw = DW_16;
MXYZ_b.Dw = DW_16;
MXYZ_c.Dw = DW_16;
MXYZ_a.RowStep = 1 * 2 * 2;
MXYZ_a.ColStep = 4 * 2;
MXYZ_b.RowStep = 1 * 2 * 2;
MXYZ_b.ColStep = 4 * 2;
MXYZ_c.RowStep = 1 * 2 * 2;
MXYZ_c.ColStep = 4 * 2;
MatrixSUB_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_16[k]);
}
}
void test_MatrixInteFunc_scale_add_sub_complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 1;
MC_t.RS = 4;
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
MXYZ_a.RowStep = 1 * 2;
MXYZ_a.ColStep = 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_8;
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
MXYZ_b.RowStep = 1 * 2;
MXYZ_b.ColStep = 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_8;
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
MXYZ_c.RowStep = 1 * 2;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_8;
MatrixScaleADD_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_u8[k]);
}
//sub
MXYZ_a.MatAdr = (unsigned int)&src_a_16;
MXYZ_b.MatAdr = (unsigned int)&src_b_16;
MXYZ_c.MatAdr = (unsigned int)&dst_16;
MXYZ_a.Dw = DW_16;
MXYZ_b.Dw = DW_16;
MXYZ_c.Dw = DW_16;
MXYZ_a.RowStep = 1 * 2 * 2;
MXYZ_a.ColStep = 4 * 2;
MXYZ_b.RowStep = 1 * 2 * 2;
MXYZ_b.ColStep = 4 * 2;
MXYZ_c.RowStep = 1 * 2 * 2;
MXYZ_c.ColStep = 4 * 2;
MatrixScaleSUB_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_16[k]);
}
}
void test_MatrixInteFunc_scale_mul_mla_mls_complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 1;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_u8;
MXYZ_a.RowStep = 1 * 2;
MXYZ_a.ColStep = 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_8;
MXYZ_b.MatAdr = (unsigned int)&src_b_u8;
MXYZ_b.RowStep = 1 * 2;
MXYZ_b.ColStep = 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_8;
MXYZ_c.MatAdr = (unsigned int)&dst_u8;
MXYZ_c.RowStep = 1 * 2;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_8;
MatrixScaleMUL_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
//
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_u8[k]);
}
for (int k = 0; k < 8; k++) {
dst_32[k] = k;
}
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_a.Dw = DW_32;
MXYZ_b.Dw = DW_32;
MXYZ_c.Dw = DW_32;
MXYZ_a.RowStep = 1 * 4 * 2;
MXYZ_a.ColStep = 4 * 4;
MXYZ_b.RowStep = 1 * 4 * 2;
MXYZ_b.ColStep = 4 * 4;
MXYZ_c.RowStep = 1 * 4 * 2;
MXYZ_c.ColStep = 4 * 4;
MatrixScaleMLA_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_32[k]);
}
//
for (int k = 0; k < 8; k++) {
dst_32[k] = -1;
}
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_a.Dw = DW_32;
MXYZ_b.Dw = DW_32;
MXYZ_c.Dw = DW_32;
MatrixScaleMLS_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_16=%d\n", dst_32[k]);
}
}
void test_Matvec_mul_complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_a.RowStep = 1 * 4 * 2;
MXYZ_a.ColStep = 4 * 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_b.RowStep = 1 * 4 * 2;
MXYZ_b.ColStep = 4 * 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_32;
/*MXYZ_c.MatAdr = &dst_32;
MXYZ_c.RowStep = 1;
MXYZ_c.ColStep = 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_32;*/
int sum[2];
MatVecMUL_Complex(&MXYZ_a, &MXYZ_b, (int *)&sum, &MC_t, -1);
//
/*for(int k = 0;k<8;k++)
{
printf("dst_u8=%d\n",dst_32[k]);
}*/
printf("sum1=%d\n", sum[0]);
printf("sum2=%d\n", sum[1]);
}
void test_MatrixComplexScaleMul_Complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 1;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_a.RowStep = 1 * 4;
MXYZ_a.ColStep = 4 * 2;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_32;
MXYZ_b.MatAdr = (unsigned int)&src_b_32;
MXYZ_b.RowStep = 1 * 4 * 2;
MXYZ_b.ColStep = 4 * 2 * 2;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_c.RowStep = 1 * 4 * 2;
MXYZ_c.ColStep = 4 * 2 * 2;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_32;
MatrixComplexScaleMUL_Complex(&MXYZ_a, &MXYZ_b, &MXYZ_c, &MC_t);
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_32[k]);
}
}
void test_MatrixMUL_Real()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 4 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_a.RowStep = 4;
MXYZ_a.ColStep = 4 * 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_32;
int src_b_32_T[8]__attribute__((aligned(4))) = {4, 6, 10, 12, 5, 7, 11, 13};
MXYZ_b.MatAdr = (unsigned int)&src_b_32_T;
MXYZ_b.RowStep = 4;
MXYZ_b.ColStep = 4 * 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_c.RowStep = 4;
MXYZ_c.ColStep = 4 * 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_32;
MatrixMUL_Real(&MXYZ_b, &MXYZ_a, &MXYZ_c, &MC_t, -1);
//
for (int k = 0; k < 4; k++) {
printf("dst_u8=%d\n", dst_32[k]);
}
}
void test_MatrixMUL_Complex()
{
printf(__func__);
printf("ssssssnnn\n");
MC_t.MatRow = 2 - 1;
MC_t.MatCol = 2 - 1;
MC_t.MatQ = 0;
MC_t.RS = 0;
MXYZ_a.MatAdr = (unsigned int)&src_a_32;
MXYZ_a.RowStep = 4;
MXYZ_a.ColStep = 4 * 4;
MXYZ_a.Conj = 0;
MXYZ_a.Dw = DW_32;
int src_b_32_T1[8]__attribute__((aligned(4))) = {4, 5, 10, 11, 6, 7, 12, 13};
MXYZ_b.MatAdr = (unsigned int)&src_b_32_T1;
MXYZ_b.RowStep = 4;
MXYZ_b.ColStep = 4 * 4;
MXYZ_b.Conj = 0;
MXYZ_b.Dw = DW_32;
MXYZ_c.MatAdr = (unsigned int)&dst_32;
MXYZ_c.RowStep = 4;
MXYZ_c.ColStep = 4 * 4;
MXYZ_c.Conj = 0;
MXYZ_c.Dw = DW_32;
MatrixMUL_Complex(&MXYZ_b, &MXYZ_a, &MXYZ_c, &MC_t, -1);
//
for (int k = 0; k < 8; k++) {
printf("dst_u8=%d\n", dst_32[k]);
}
}

View File

@ -0,0 +1,340 @@
/*
****************************************************************
* AUDIO_WIND_DETECT_DEMO
* File : audio_wind_detect_demo.c
* By :
* Notes :风噪检测使用请不要修改本demo如有需求请拷贝副
* 本,自行修改!
* Usage :
*(1)需要打开双麦的宏 TCFG_AUDIO_DUAL_MIC_ENABLE
*(2)需要使用第二版双麦算法 CONST_DMS_GLOBAL_VERSION = DMS_GLOBAL_V200
*(3)调用audio_wind_detect_demo_open();使用
****************************************************************
*/
#include "audio_wind_detect_demo.h"
#include "system/includes.h"
#include "app_config.h"
#include "audio_adc.h"
#include "audio_enc.h"
#include "aec_user.h"
#include "task.h"
#include "cvp/cvp_common.h"
#include "lib_h/jlsp_ns.h"
#include "online_db_deal.h"
#include "spp_user.h"
#include "overlay_code.h"
#include "app_main.h"
#define WIND_DETECT_TASK_NAME "WindDetect"
/* 通过蓝牙spp发送风噪信息
* 需要同时打开USER_SUPPORT_PROFILE_SPP和APP_ONLINE_DEBUG*/
#define WIND_DETECT_INFO_SPP_DEBUG_ENABLE 0
#define AUDIO_ADC_BUF_NUM 3 //mic_adc采样buf个数
#define AUDIO_ADC_IRQ_POINTS 256 //mic_adc采样长度单位点数
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
#define AUDIO_ADC_CH 3 //3mic通话
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
#define AUDIO_ADC_CH 2 //双mic通话
#else
#define AUDIO_ADC_CH 1 //单mic通话
#endif/*TCFG_AUDIO_DUAL_MIC_ENABLE*/
#define AUDIO_ADC_BUFS_SIZE (AUDIO_ADC_BUF_NUM * AUDIO_ADC_IRQ_POINTS * AUDIO_ADC_CH)
struct audio_mic_hdl {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
int adc_dump_cnt;
s16 adc_buf[AUDIO_ADC_BUFS_SIZE]; //align 2Bytes
#if (AUDIO_ADC_CH > 1)
s16 tmp_buf[AUDIO_ADC_IRQ_POINTS];
#endif/*AUDIO_ADC_CH*/
#if (AUDIO_ADC_CH > 2)
s16 tmp_buf_1[AUDIO_ADC_IRQ_POINTS];
#endif/*AUDIO_ADC_CH*/
};
static struct audio_mic_hdl *audio_mic = NULL;
extern struct audio_adc_hdl adc_hdl;
struct audio_wind_detect_hdl {
int wd_flag;
int wd_val;
int wd_lev;
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
struct spp_operation_t *spp_opt;
#endif
};
static struct audio_wind_detect_hdl *audio_wd = NULL;
void audio_mic_dump_set(u16 dump_cnt)
{
printf("adc_dump_cnt:%d\n", dump_cnt);
if (audio_mic) {
audio_mic->adc_dump_cnt = dump_cnt;
}
}
/*adc_mic采样输出接口*/
static void adc_mic_output_handler(void *priv, s16 *data, int len)
{
if (audio_mic) {
if (audio_mic->adc_dump_cnt) {
audio_mic->adc_dump_cnt--;
//printf("[%d]",audio_mic->adc_dump_cnt);
memset(data, 0, len);
return;
}
#if (AUDIO_ADC_CH == 3)/*3 Mic*/
s16 *mic0_data = data;
s16 *mic1_data = data + (len / 2);
s16 *mic2_data = data + (len / 2) * 2;
int offset = 0;
s16 *mic1_data_pos = audio_mic->tmp_buf;
s16 *mic2_data_pos = audio_mic->tmp_buf_1;
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 3];
mic1_data[i] = data[i * 3 + 1];
mic2_data[i] = data[i * 3 + 2];
}
memcpy(mic1_data, mic1_data_pos, len);
memcpy(mic2_data, mic2_data_pos, len);
offset = (len / 2) * app_var.talk_ref_mic_ch;
audio_aec_inbuf_ref(data + offset, len);
offset = (len / 2) * app_var.talk_fb_mic_ch;
audio_aec_inbuf_ref_1(data + offset, len);
offset = (len / 2) * app_var.talk_mic_ch;
audio_aec_inbuf(data + offset, len);
return;
#elif (AUDIO_ADC_CH == 2)/*DualMic*/
s16 *mic0_data = data;
s16 *mic1_data = audio_mic->tmp_buf;
s16 *mic1_data_pos = data + (len / 2);
//printf("mic_data:%x,%x,%d\n",data,mic1_data_pos,len);
for (u16 i = 0; i < (len >> 1); i++) {
mic0_data[i] = data[i * 2];
mic1_data[i] = data[i * 2 + 1];
}
memcpy(mic1_data_pos, mic1_data, len);
#if (TCFG_AUDIO_DMS_MIC_MANAGE == DMS_MASTER_MIC0)
audio_aec_inbuf_ref(mic1_data_pos, len);
audio_aec_inbuf(data, len);
#else
audio_aec_inbuf_ref(data, len);
audio_aec_inbuf(mic1_data_pos, len);
#endif/*TCFG_AUDIO_DMS_MIC_MANAGE*/
#else/*SingleMic*/
audio_aec_inbuf(data, len);
#endif/*ESCO_ADC_CH*/
}
}
/*mic初始化*/
static int audio_mic_en(u8 en, u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
{
printf("audio_mic_en:%d\n", en);
u8 mic_ch = en;
if (en) {
if (audio_mic) {
printf("audio_mic re-malloc error\n");
return -1;
}
audio_mic = zalloc(sizeof(struct audio_mic_hdl));
if (audio_mic == NULL) {
printf("audio mic zalloc failed\n");
return -1;
}
audio_mic_pwr_ctl(MIC_PWR_ON);
audio_mic_dump_set(3);/*处理开mic后在短时间起3次中断影响aec的问题*/
if (en & AUDIO_ADC_MIC_0) {
printf("adc_mic0 open,gain:%d\n", mic0_gain);
audio_adc_mic_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic_set_gain(&audio_mic->mic_ch, mic0_gain);
}
if (en & AUDIO_ADC_MIC_1) {
printf("adc_mic1 open,gain:%d\n", mic1_gain);
audio_adc_mic1_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic1_set_gain(&audio_mic->mic_ch, mic1_gain);
}
if (en & AUDIO_ADC_MIC_2) {
printf("adc_mic2 open,gain:%d\n", mic2_gain);
audio_adc_mic2_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic2_set_gain(&audio_mic->mic_ch, mic2_gain);
}
if (en & AUDIO_ADC_MIC_3) {
printf("adc_mic3 open,gain:%d\n", mic3_gain);
audio_adc_mic3_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic3_set_gain(&audio_mic->mic_ch, mic3_gain);
}
audio_adc_mic_set_sample_rate(&audio_mic->mic_ch, sr);
audio_adc_mic_set_buffs(&audio_mic->mic_ch, audio_mic->adc_buf,
AUDIO_ADC_IRQ_POINTS * 2, AUDIO_ADC_BUF_NUM);
audio_mic->adc_output.handler = adc_mic_output_handler;
audio_adc_add_output_handler(&adc_hdl, &audio_mic->adc_output);
audio_adc_mic_start(&audio_mic->mic_ch);
} else {
if (audio_mic) {
audio_adc_mic_close(&audio_mic->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &audio_mic->adc_output);
audio_mic_pwr_ctl(MIC_PWR_OFF);
free(audio_mic);
audio_mic = NULL;
}
}
return 0;
}
static int audio_wind_detect_output_hdl(s16 *data, int len)
{
return len;
}
/*打开风噪检测*/
int audio_wind_detect_open(u32 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain)
{
int err = 0;
overlay_load_code(OVERLAY_AEC);
audio_aec_open(sr, -1, audio_wind_detect_output_hdl);
/* audio_aec_open(sr, WNC_EN | ENC_EN | AEC_EN, audio_wind_detect_output_hdl); */
audio_mic_en(TCFG_AUDIO_ADC_MIC_CHA, sr, mic0_gain, mic1_gain, mic2_gain, mic3_gain);
return 0;
}
/*关闭风噪检测*/
int audio_wind_detect_close()
{
audio_aec_close();
audio_mic_en(0, 0, 0, 0, 0, 0);
return 0;
}
/*风噪检测信息获取任务*/
static void audio_wind_detect_task(void *p)
{
while (1) {
os_time_dly(10);
audio_get_wind_detect_info();
}
}
/*打开获取风噪信息的任务*/
int audio_wind_info_task_open()
{
int err = 0;
if (audio_wd) {
printf("[err] audio_wd re-malloc !!!");
return -1;
}
audio_wd = zalloc(sizeof(struct audio_wind_detect_hdl));
if (audio_wd == NULL) {
printf("[err] audio_wd malloc fail !!!");
return 0;
}
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
spp_get_operation_table(&audio_wd->spp_opt);
#endif
overlay_load_code(OVERLAY_AEC);
err = os_task_create(audio_wind_detect_task, NULL, 2, 256, 128, WIND_DETECT_TASK_NAME);
/* err = task_create(audio_wind_detect_task, NULL, WIND_DETECT_TASK_NAME); */
if (err != OS_NO_ERR) {
printf("task create error!");
return -1;
}
return 0;
}
/*关闭获取风噪信息的任务*/
int audio_wind_info_task_close(void)
{
if (audio_wd) {
/* task_kill(WIND_DETECT_TASK_NAME); */
os_task_del(WIND_DETECT_TASK_NAME);
free(audio_wd);
audio_wd = NULL;
}
return 0;
}
/*打开风噪检测的demo*/
int audio_wind_detect_demo_open(void)
{
/*打开风噪检测*/
audio_wind_detect_open(16000, 4, 4, 1, 1);
/*获取风噪的信息*/
audio_wind_info_task_open();
return 0;
}
/*关闭风噪检测的demo*/
int audio_wind_detect_demo_close(void)
{
audio_wind_detect_close();
audio_wind_info_task_close();
return 0;
}
/*获取风噪信息*/
int audio_get_wind_detect_info(void)
{
if (audio_wd) {
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
jlsp_tms_get_wind_detect_info(&audio_wd->wd_flag, &audio_wd->wd_val, &audio_wd->wd_lev);
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
jlsp_get_wind_detect_info(&audio_wd->wd_flag, &audio_wd->wd_val, &audio_wd->wd_lev);
#endif
printf("wd_flag:%d, wd_val:%d, wd_lev:%d", audio_wd->wd_flag, audio_wd->wd_val, audio_wd->wd_lev);
#if WIND_DETECT_INFO_SPP_DEBUG_ENABLE
if (audio_wd->spp_opt && audio_wd->spp_opt->send_data) {
char tmpbuf[25];
memset(tmpbuf, 0x20, sizeof(tmpbuf));
sprintf(tmpbuf, "falg:%d, val:%d, lev:%d", audio_wd->wd_flag, audio_wd->wd_val, audio_wd->wd_lev);
audio_wd->spp_opt->send_data(NULL, tmpbuf, sizeof(tmpbuf));
}
#endif
}
return 0;
}
/*获取是否有风0无风1有风*/
int audio_get_wd_flag(void)
{
if (audio_wd) {
return audio_wd->wd_flag;
}
return -1;
}
/*获取风强*/
int audio_get_wd_val(void)
{
if (audio_wd) {
return audio_wd->wd_val;
}
return -1;
}
/*获取预设的风噪等级, 0弱风1中风2强风*/
int audio_get_wd_lev(void)
{
if (audio_wd) {
return audio_wd->wd_lev;
}
return -1;
}
static u8 audio_wind_detect_idle_query()
{
return (audio_wd == NULL) ? 1 : 0;
}
REGISTER_LP_TARGET(audio_wind_detect_lp_target) = {
.name = "audio_wind_detect",
.is_idle = audio_wind_detect_idle_query,
};

View File

@ -0,0 +1,35 @@
#ifndef __AUDIO_WIND_DETECT_DEMO_H_
#define __AUDIO_WIND_DETECT_DEMO_H_
#include "generic/typedef.h"
/*打开风噪检测的demo*/
int audio_wind_detect_demo_open(void);
/*关闭风噪检测的demo*/
int audio_wind_detect_demo_close(void);
/*打开风噪检测*/
int audio_wind_detect_open(u32 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain);
/*关闭风噪检测*/
int audio_wind_detect_close();
/*打开获取风噪信息的任务*/
int audio_wind_info_task_open();
/*获取风噪信息*/
int audio_get_wind_detect_info(void);
/*关闭获取风噪信息的任务*/
int audio_wind_info_task_close(void);
/*获取是否有风0无风1有风*/
int audio_get_wd_flag(void);
/*获取风强*/
int audio_get_wd_val(void);
/*获取预设的风噪等级, 0弱风1中风2强风*/
int audio_get_wd_lev(void);
#endif /* __AUDIO_WIND_DETECT_DEMO_H_*/

View File

@ -0,0 +1,67 @@
/*************************************************************************************************/
/*!
* \file audio_effect_develop.c
*
* \brief 第三方音效算法添加
*
* Copyright (c) 2011-2023 ZhuHai Jieli Technology Co.,Ltd.
*
*/
/*************************************************************************************************/
#include "app_config.h"
#include "audio_effect_develop.h"
#if ((defined TCFG_EFFECT_DEVELOP_ENABLE) && TCFG_EFFECT_DEVELOP_ENABLE)
struct audio_effect_develop_handle {
int sample_rate;
u8 nch;
u8 bit_width;
};
void *audio_effect_develop_open(int sample_rate, u8 nch, u8 bit_width)
{
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)zalloc(sizeof(struct audio_effect_develop_handle));
if (!hdl) {
return NULL;
}
hdl->sample_rate = sample_rate;
hdl->nch = nch;
hdl->bit_width = bit_width;
//TODO : 打开算法模块
return hdl;
}
void audio_effect_develop_close(void *priv)
{
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)priv;
//TODO : 关闭算法模块
if (hdl) {
free(hdl);
}
}
/*********************************************************************** 
 * 音效算法开发处理函数 
 * Input    :  priv - 第三方音效算法的主要私有句柄 
               data - pcm数据(16bit) 
               len  - pcm数据的byte长度 
 * Output   :  数据处理长度 
 * Notes    : 
 * History  : 
 *==============================================================*/  
int audio_effect_develop_data_handler(void *priv, void *data, int len)
{
struct audio_effect_develop_handle *hdl = (struct audio_effect_develop_handle *)priv;
//TODO : 音效运行
return len;
}
#endif

View File

@ -0,0 +1,45 @@
/*************************************************************************************************/
/*!
* \file audio_effect_develop.h
*
* \brief
*
* Copyright (c) 2011-2023 ZhuHai Jieli Technology Co.,Ltd.
*
*/
/*************************************************************************************************/
#ifndef _AUDIO_EFFECT_DEVELOP_H_
#define _AUDIO_EFFECT_DEVELOP_H_
/*********************************************************************** 
 * 音效算法开发打开 
 * Input    :  sample_rate  - 采样率 
               nch - 声道数 
bit_width - 位宽(通常默认为16bit)
 * Output   : 音效算法开发的主句柄 
 * Notes    : 
 * History  : 
 *=====================================================================*/  
void *audio_effect_develop_open(int sample_rate, u8 nch, u8 bit_width);
/*********************************************************************** 
 * 音效算法开发关闭 
 * Input    :  priv - 第三方音效算法的主要私有句柄 
 * Output   :  
 * Notes    :  
 * History  : 
 *=====================================================================*/  
void audio_effect_develop_close(void *priv);
/*********************************************************************** 
 * 音效算法开发处理函数 
 * Input    :  priv - 第三方音效算法的主要私有句柄 
               data - pcm数据 
               len  - pcm数据的byte长度 
 * Output   :  数据处理长度 
 * Notes    : 
 * History  : 
 *=====================================================================*/  
int audio_effect_develop_data_handler(void *priv, void *data, int len);
#endif

1035
cpu/br28/audio_enc.c Normal file

File diff suppressed because it is too large Load Diff

29
cpu/br28/audio_enc.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef _AUDIO_ENC_H_
#define _AUDIO_ENC_H_
#include "generic/typedef.h"
enum enc_source {
ENCODE_SOURCE_MIX = 0x0,
ENCODE_SOURCE_MIC,
ENCODE_SOURCE_LINE0_LR,
ENCODE_SOURCE_LINE1_LR,
ENCODE_SOURCE_LINE2_LR,
ENCODE_SOURCE_USER,
};
enum {
MIC_PWR_INIT = 1, /*开机状态*/
MIC_PWR_ON, /*工作状态*/
MIC_PWR_OFF, /*空闲状态*/
MIC_PWR_DOWN, /*低功耗状态*/
};
int esco_enc_open(u32 coding_type, u8 frame_len);
void esco_enc_close();
void audio_mic_pwr_ctl(u8 state);
u8 get_master_mic_gain(u8 master);
void esco_mic_reset(void);
void esco_mic_cfg_set(u16 sr, u16 mic0_gain, u16 mic1_gain, u16 mic2_gain, u16 mic3_gain);
#endif/*_AUDIO_ENC_H_*/

46
cpu/br28/audio_general.c Normal file
View File

@ -0,0 +1,46 @@
/*
****************************************************************
* AUDIO General APIs
* Brief : 实现一些依赖CPU的通用接口适配所有case
* Notes :
****************************************************************
*/
#include "system/includes.h"
#include "media/includes.h"
#include "audio_config.h"
void audio_adda_dump(void) //打印所有的dac,adc寄存器
{
printf("JL_WL_AUD CON0:%x", JL_WL_AUD->CON0);
printf("AUD_CON:%x", JL_AUDIO->AUD_CON);
printf("DAC_CON:%x", JL_AUDIO->DAC_CON);
printf("ADC_CON:%x", JL_AUDIO->ADC_CON);
printf("ADC_CON1:%x", JL_AUDIO->ADC_CON1);
printf("DAC_TM0:%x", JL_AUDIO->DAC_TM0);
printf("DAA_CON 0:%x 1:%x, 2:%x, 3:%x 4:%x\n", JL_ADDA->DAA_CON0, JL_ADDA->DAA_CON1, JL_ADDA->DAA_CON2, JL_ADDA->DAA_CON3, JL_ADDA->DAA_CON4);
printf("ADA_CON 0:%x 1:%x 2:%x 3:%x 4:%x 5:%x\n", JL_ADDA->ADA_CON0, JL_ADDA->ADA_CON1, JL_ADDA->ADA_CON2, JL_ADDA->ADA_CON3, JL_ADDA->ADA_CON4, JL_ADDA->ADA_CON5);
}
void audio_gain_dump(void)
{
int dac_again_max = 7;
u8 dac_again_l = JL_ADDA->DAA_CON1 & 0xF;
u8 dac_again_r = (JL_ADDA->DAA_CON1 >> 4) & 0xF;
int dac_dgain_max = 16384;
u32 dac_dgain_l = JL_AUDIO->DAC_VL0 & 0xFFFF;
u32 dac_dgain_r = (JL_AUDIO->DAC_VL0 >> 16) & 0xFFFF;
u8 mic0_0_6 = (JL_ADDA->ADA_CON4) & 0x1;
u8 mic1_0_6 = (JL_ADDA->ADA_CON5) & 0x1;
u8 mic2_0_6 = (JL_ADDA->ADA_CON6) & 0x1;
u8 mic3_0_6 = (JL_ADDA->ADA_CON7) & 0x1;
u8 mic0_gain = JL_ADDA->ADA_CON8 & 0x1F;
u8 mic1_gain = (JL_ADDA->ADA_CON8 >> 5) & 0x1F;
u8 mic2_gain = (JL_ADDA->ADA_CON8 >> 10) & 0x1F;
u8 mic3_gain = (JL_ADDA->ADA_CON8 >> 15) & 0x1F;
printf("L Mute:%d ,R Mute:%d\n", (JL_ADDA->DAA_CON2 >> 1) & 0x1, (JL_ADDA->DAA_CON2 >> 11) & 0x1); //PA MUTE
printf("MIC_G:%d,%d,%d,%d,MIC_6dB_EN:%d,%d,%d,%d,DAC_AG_MAX:%d,DAC_AG:%d,%d,DAC_DG_MAX:%d,DAC_DG:%d,%d\n", mic0_gain, mic1_gain, mic2_gain, mic3_gain, mic0_0_6, mic1_0_6, mic2_0_6, mic3_0_6, dac_again_max, dac_again_l, dac_again_r, dac_dgain_max, dac_dgain_l, dac_dgain_r);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
#ifndef _AUD_HEARING_AID_H_
#define _AUD_HEARING_AID_H_
#include "generic/typedef.h"
#include "board_config.h"
/*************************************************************************
* 可选功能模块配置(Optinal Module Define)
************************************************************************/
#define DHA_DATA_EXPORT_ENABLE 0 //数据导出使能, 需要先开APP_PCM_DEBUG
#define DHA_RUN_TIME_TRACE_ENABLE 0 //运行时间log跟踪
#define DHA_RUN_TIME_IO_DEBUG_ENABLE 0 //运行时间IO跟踪
#ifdef DHA_RUN_TIME_IO_DEBUG_ENABLE
#define IO_IDX 7
#define IO_INTERVAL_IDX 4 /*DHA节奏唤醒间隔*/
#define DHA_IO_DEBUG_INIT() JL_PORTA->DIR &= ~BIT(IO_IDX)
#define DHA_IO_DEBUG_1() JL_PORTA->OUT |= BIT(IO_IDX)
#define DHA_IO_DEBUG_0() JL_PORTA->OUT &= ~BIT(IO_IDX)
#define DHA_IO_INTERVAL() {JL_PORTA->DIR &= ~BIT(IO_INTERVAL_IDX);JL_PORTA->OUT ^= BIT(IO_INTERVAL_IDX);}
#else
#define DHA_IO_DEBUG_INIT(...)
#define DHA_IO_DEBUG_1(...)
#define DHA_IO_DEBUG_0(...)
#define DHA_IO_INTERVAL(...)
#endif/*DHA_RUN_TIME_IO_DEBUG_ENABLE*/
/*************************************************************************
* 可选功能模块配置(Optinal Module Define)
************************************************************************/
#define DHA_AND_MEDIA_MUTEX_ENABLE 1 //辅听功能和多媒体播放互斥
#define DHA_SRC_USE_HW_ENABLE 0 //SRC选择1:使用硬件SRC0:使用软件SRC
#define DHA_MIC_DATA_CBUF_ENABLE 0 //是否使用cbuf缓存mic的数据
#define DHA_DAC_OUTPUT_ENHANCE_ENABLE 0 //DAC输出音量增强使能用来提高辅听的动态范围
#define DHA_TDE_ENABLE 0 //辅听信号延时估计
#define DHA_IN_LOUDNESS_TRACE_ENABLE 0 //跟踪获取当前mic输入幅值
#define DHA_OUT_LOUDNESS_TRACE_ENABLE 0 //跟踪获取算法输出幅值
#define DHA_USE_WDRC_ENABLE 1 //DRC选择1:使用WDRC0:使用普通限幅器DRC
/*************************************************************************
* 验配功能定义(DHA Fitting Define)
************************************************************************/
/*听力验配版本号*/
#define DHA_FITTING_VERSION 0x01
/*验配通道数*/
#define DHA_FITTING_CHANNEL_MAX 6
/*通道频率*/
#define DHA_CH0_FREQ 250
#define DHA_CH1_FREQ 500
#define DHA_CH2_FREQ 1000
#define DHA_CH3_FREQ 2000
#define DHA_CH4_FREQ 4000
#define DHA_CH5_FREQ 6000
/*
* 1. PayLoad Format
* +---------+---------------+------+
* |cmd[8bit]|data_len[16bit]| data |
* +---------+---------------+------+
* 2.DHA Fitting Commands
*/
/*(1)验配信息交互:版本、通道数、通道频率*/
#define DHA_FITTING_CMD_INFO 0x50
typedef struct {
u8 version; /*版本号DHA_FITTING_VERSION*/
u8 ch_num; /*通道数DHA_FITTING_CHANNEL_MAX*/
u16 ch_freq[DHA_FITTING_CHANNEL_MAX]; /*通道频率组获取通道对应的freq*/
} dha_fitting_info_t;
/*(2)通道验配*/
#define DHA_FITTING_CMD_ADJUST 0x51
typedef struct {
u8 channel: 1; /*左右声道标识:0=左声道 1=右声道*/
u8 sine: 2; /*开关验配单频音的标志: BIT(0) = 1 左耳播单频音BIT(0) = 0 左耳静音
BIT(1) = 1 右耳播单频音BIT(1) = 0 右耳静音*/
u8 reserve0: 5; /*保留*/
u8 reserve1; /*保留*/
u16 freq; /*通道频率*/
float gain; /*通道增益*/
} dha_fitting_adjust_t;
/*(3)验配结果保存更新*/
/*
+---------+------------+--------------------+-------------+---------------+
|cmd[8bit]|len[16bit] | type(8bit)左/右/双耳|N个左耳[float]| N个右耳[float] |
+---------+------------+--------------------+-------------+---------------+
type(8bit) 0:左耳数据1:右耳数据2:双耳数据
*/
#define DHA_FITTING_CMD_UPDATE 0x52
/*(4)左右耳打开辅听的状态*/
#define DHA_FITTING_CMD_STATE 0x53
typedef struct {
u8 state_left: 1;
u8 state_right: 1;
u8 reserve: 6;
} dha_fitting_state_t;
/*************************************************************************
* 辅听耳机接口声明(DHA APIs Declaration)
************************************************************************/
int audio_hearing_aid_open(void);
int audio_hearing_aid_close(void);
void audio_hearing_aid_demo(void);
void audio_hearing_aid_resume(void);
void audio_hearing_aid_suspend(void);
int hearing_aid_fitting_parse(u8 *data, u16 len);
int hearing_aid_fitting_start(u8 en);
int get_hearing_aid_fitting_info(u8 *data);
u8 get_hearing_aid_state(void);
u8 get_hearing_aid_fitting_state(void);
u8 set_hearing_aid_fitting_state(u8 state);
void audio_dha_fitting_sync_close(void);
int get_hearing_aid_state_cmd_info(u8 *data);
/*************************************************************************
* 其他引用(Other Reference)
************************************************************************/
extern int aec_uart_open(u8 nch, u16 single_size);
extern int aec_uart_fill(u8 ch, void *buf, u16 size);
extern void aec_uart_write(void);
extern int aec_uart_close(void);
#endif/*_AUD_HEARING_AID_H_*/

View File

@ -0,0 +1,352 @@
/*
****************************************************************
* Hearing Aid Low Power
* 检测数据能量的函数
* File : audi_hearing_aid_lp.c
* By :
* Notes :
****************************************************************
*/
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "app_main.h"
#include "audio_config.h"
#include "app_action.h"
#include "audio_hearing_aid_lp.h"
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#ifndef TCFG_AUDIO_DHA_MIC_SAMPLE_RATE
#define TCFG_AUDIO_DHA_MIC_SAMPLE_RATE 32000
#endif
//*********************************************************************************//
// mic能量检测处理配置 //
//*********************************************************************************//
//是否开启mic 能量检测
#define MIC_ENERGY_DETECT 1
//判断多少ms没有能量就进入低功耗
#define MIC_SNIFF_TIME 2 * 60 * 1000
//#define MIC_SNIFF_TIME 5 * 1000
//进入低功耗后每隔多少ms计算一次能量
#define MIC_CHECK_INTER 1 * 1000
//低功耗状态下能量检测计算多少ms的能量
#define MIC_ENERGY_TIME 20
//进入低功耗的能量值,小于此能量值进入低功耗
#define enter_sniff_energy 50
//退出低功耗的能量值,大于退出低功耗 //从低功耗出来时adc 能量值会比较高,需要比较高的阈值
#define exit_sniff_energy 170
//跳过刚上电的多少次中断数据
#define adc_isr_ignore_cnt 8
//是否打开mic 能量的调试打印
#define ENERGY_DEBUG_EN 0
static u8 enter_sleep = 0;
#if ENERGY_DEBUG_EN
static u32 debug_size = 4096 * 2;
/* static s16 debug_buf[4096 * 2]; */
static u32 debug_p = 0;
static u32 zero_cnt = 0;
static u32 no_zero_cnt = 0;
static u8 debug_flag = 0;
#endif
struct hearing_aid_energy_detect {
u32 exit_sniff_points; //一次检测的点数
u32 abs_total_0; //mic0 的能量
u32 abs_total_1; //mic1 的能量
u32 points_count; //点数
u32 energy_detect_flag;//是否开始计算能量的标志
u32 enter_sniff_points; //多少个点的能量低于阈值进低功耗
u32 exit_sniff_timer; //检测能量值定时器
u16 dac_start_timer; //检测能量值定时器
u16 dac_stop_timer; //检测能量值定时器
u8 dac_start_flag; //dac 开启或关闭的标志位
u8 isr_ignore_cnt; //跳过刚上电的多少次中断数据
u8 adc_ch_num; //打开多少个mic通道
struct adc_mic_ch mic_ch;
s16 *adc_dma_buf;
struct audio_adc_output_hdl adc_output;
u8 dac_open;
void (*hw_open)(void);
void (*hw_close)(void);
};
static struct hearing_aid_energy_detect *mic_aid = NULL;
void exit_sniff_start(void) //定时能量检测,能量检测的时候mic能不能正常工作
{
#if ENERGY_DEBUG_EN
printf("enter low_power_deal.c %d\n", __LINE__);
#endif
mic_aid->energy_detect_flag = 1; //开始能量计算
mic_aid->isr_ignore_cnt = adc_isr_ignore_cnt;
#if 1 //重新打开mic
extern void hearing_aid_energy_demo_open(u8 mic_idx, u8 gain, u16 sr, u8 mic_2_dac);
hearing_aid_energy_demo_open(TCFG_AD2DA_LOW_LATENCY_MIC_CHANNEL, 12, TCFG_AUDIO_DHA_MIC_SAMPLE_RATE, 0);
/* audio_adc_mic_aid_open(mic_aid->mic_idx, mic_aid->gain, mic_aid->sr, 0); */
#else
SFR(JL_ADDA->DAA_CON0, 16, 1, 1); // VBG_EN_11v
SFR(JL_ADDA->ADA_CON0, 17, 1, 0); // CTADCA_S2_RSTB
os_time_dly(50);
SFR(JL_ADDA->ADA_CON0, 17, 1, 1); // CTADCA_S2_RSTB
SFR(JL_ADDA->DAA_CON0, 12, 1, 1); //AUDIO_IBIAS_EN_11V
#endif
enter_sleep = 0; //退出低功耗
sys_timer_del(mic_aid->exit_sniff_timer);
}
void dac_start_timer(void) //启动dac
{
#if ENERGY_DEBUG_EN
printf("enter low_power_deal.c%d\n", __LINE__);
#endif
extern void hearing_aid_energy_demo_close(void);
hearing_aid_energy_demo_close();
printf("enter low_power_deal.c%d\n", __LINE__);
if (mic_aid->hw_open) {
mic_aid->hw_open();
}
/* sound_pcm_dev_start(NULL, 16000, 10); */
enter_sleep = 0; //退出低功耗
/* mic_aid->adc_2_dac = 1; */
mic_aid->dac_start_flag = 1 ;
sys_timer_del(mic_aid->dac_start_timer);
}
void dac_stop_timer(void) //关闭dac
{
#if ENERGY_DEBUG_EN
printf("enter low_power_deal.c%d\n", __LINE__);
#endif
extern void hearing_aid_energy_demo_close(void);
hearing_aid_energy_demo_close();
if (mic_aid->hw_close) {
printf("enter low_power_deal.c%d,%p\n", __LINE__, mic_aid->hw_close);
mic_aid->hw_close();
}
/* audio_adc_del_output_handler(&adc_hdl, &mic_aid->adc_output); */
/* audio_adc_mic_close(&mic_aid->mic_ch); */
mic_aid->adc_ch_num = 0; //mic_aid 被关了
//将变量清0开始新一轮计算
mic_aid->abs_total_0 = 0;
mic_aid->abs_total_1 = 0;
mic_aid->points_count = 0;
mic_aid->energy_detect_flag = 0;
enter_sleep = 1; //进入低功耗
/* mic_aid->adc_2_dac = 0; */
mic_aid->dac_start_flag = 0 ;
sys_timer_del(mic_aid->dac_stop_timer);
printf("enter low_power_deal.c%d\n", __LINE__);
}
void audio_hearing_aid_lp_open(u8 ch_num, void (*hw_open)(void), void (*hw_close)(void)) //对多少个通道做数据处理
{
if (!mic_aid) {
printf("enter low_power_deal.c%d\n", __LINE__);
mic_aid = zalloc(sizeof(struct hearing_aid_energy_detect));
}
#if 0
else {
/* memset(mic_aid,0,sizeof(struct hearing_aid_energy_detect)); */
}
#endif
mic_aid->exit_sniff_points = MIC_ENERGY_TIME * (TCFG_AUDIO_DHA_MIC_SAMPLE_RATE / 1000); //进入低功耗后一次检测的点数
mic_aid->enter_sniff_points = MIC_SNIFF_TIME * (TCFG_AUDIO_DHA_MIC_SAMPLE_RATE / 1000); //多少个点的能量低于阈值进低功耗
mic_aid->adc_ch_num = ch_num;
mic_aid-> hw_open = hw_open; //正常工作打开硬件的函数(关mic关dac)
mic_aid-> hw_close = hw_close; //进入低功耗关硬件的函数(开mic开dac)
mic_aid->abs_total_0 = 0;
mic_aid->abs_total_1 = 0;
mic_aid->points_count = 0;
enter_sleep = 0;
}
void audio_hearing_aid_lp_close(void)
{
if (mic_aid) {
free(mic_aid);
mic_aid = NULL;
}
}
u8 audio_hearing_aid_lp_flag(void)
{
return enter_sleep;
}
void audio_hearing_aid_lp_detect(void *priv, s16 *data, int len)
{
#if MIC_ENERGY_DETECT
u32 points = len / 2;
s16 *pdata = data;
u32 i = 0;
s32 total_0 = 0;
s32 total_1 = 0;
s16 diff = 0;
u32 target_points = 0;
u32 target_energy = 0;
if (enter_sleep == 0) { //低功耗期间也会进中断,不能计算能量值
if (mic_aid->isr_ignore_cnt > 0) {
mic_aid->isr_ignore_cnt--;
return;
} //跳过刚开始的一次中断数据
for (i = 0; i < points; i++) {
total_0 += *pdata;
pdata++;
if (mic_aid->adc_ch_num == 2) {
total_1 += *pdata;
pdata++;
}
}
total_0 /= (len / 2 / mic_aid->adc_ch_num); //直流量
total_1 /= (len / 2 / mic_aid->adc_ch_num);
// printf(">> total_0 %d total_1 %d\n", total_0, total_1);
pdata = data;
if (mic_aid->energy_detect_flag) { //由定时器启动的能量计算
target_points = mic_aid->exit_sniff_points; //多少时间检测
target_energy = exit_sniff_energy;
} else {
target_points = mic_aid-> enter_sniff_points; //正常工作检测多久
target_energy = enter_sniff_energy;
}
for (i = 0; i < points; i++) {
#if ENERGY_DEBUG_EN
#if 0
if (debug_p < debug_size) {
debug_buf[debug_p++] = *pdata ;
if (*pdata == 0) {
zero_cnt++;
} else {
no_zero_cnt++;
}
}
#endif
#endif
diff = *pdata - total_0;
if (diff > 0) {
mic_aid->abs_total_0 += diff;
} else {
mic_aid->abs_total_0 -= diff;
}
pdata++;
if (mic_aid->adc_ch_num == 2) {
diff = *pdata - total_1;
if (diff > 0) {
mic_aid->abs_total_1 += diff;
} else {
mic_aid->abs_total_1 -= diff;
}
pdata++;
}
mic_aid -> points_count++;
#if ENERGY_DEBUG_EN
/* printf("enter audio_adc_aid.c@@@@@@@@@@@@@@@@@@@@@@@@@@%d,%d,%d,%d\n",__LINE__,target_points,enter_sleep,mic_aid->points_count); */
#endif
if (mic_aid->points_count == target_points) {
#if ENERGY_DEBUG_EN
printf("enter low_power_deal.c %d,%d,%d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1, mic_aid->points_count, target_points);
#endif
mic_aid->abs_total_0 /= target_points;
mic_aid->abs_total_1 /= target_points;
#if ENERGY_DEBUG_EN
printf("enter low_power_deal.c %d,%d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1, target_energy);
#endif
#if ENERGY_DEBUG_EN
extern void audio_adda_dump(void); //打印所有的dac,adc寄存器
extern void audio_gain_dump();
audio_adda_dump();
audio_gain_dump();
#endif
if ((mic_aid->abs_total_0 < target_energy) && (mic_aid->abs_total_1 < target_energy)) { //
mic_aid->dac_stop_timer = sys_timer_add(NULL, dac_stop_timer, 1);
mic_aid->exit_sniff_timer = sys_timer_add(NULL, exit_sniff_start, MIC_CHECK_INTER); //退出低功耗计算能量值
#if ENERGY_DEBUG_EN
debug_p = 0;
zero_cnt = no_zero_cnt = 0;
/* memset(debug_buf, 0, debug_size * 2); */
printf("enter low_power_deal.c %d,%d,%d\n", __LINE__, mic_aid->abs_total_0, mic_aid->abs_total_1);
#endif
break;
} else {
//将变量清0开始新一轮计算
mic_aid->abs_total_0 = 0;
mic_aid->abs_total_1 = 0;
mic_aid->points_count = 0;
mic_aid->energy_detect_flag = 0;
enter_sleep = 0;
#if ENERGY_DEBUG_EN
debug_p = 0;
/* memset(debug_buf, 0, debug_size * 2); */
zero_cnt = no_zero_cnt = 0;
#endif
if (!audio_dac_is_working(&dac_hdl)) {
mic_aid->dac_start_timer = sys_timer_add(NULL, dac_start_timer, 1);
}
}
} //end of if 点数等于 enter_sniff_points
}//endf of for
} //end of 低功耗期间也会进中断,不能计算能量值
if (mic_aid->dac_open == 0) {
return;
}
#endif
}

View File

@ -0,0 +1,58 @@
#ifndef _AUD_HEARING_AID_LOW_POWER_H_
#define _AUD_HEARING_AID_LOW_POWER_H_
/*
*********************************************************************
* Energy Detect Open
* Description: 打开低功耗能量检测功能
* Arguments : ch_num 要处理的数据的通道数
* hw_open 注册进去在出低功耗正常工作时会执行的回调
a hw_close 注册进去在进低功耗时会执行的回调
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_hearing_aid_lp_open(u8 ch_num, void (*hw_open)(void), void (*hw_close)(void));
/*
*********************************************************************
* Energy Detect Run
* Description: 对传进去的数据进行能量检测,并根据结果决定进出低功耗
* Arguments : priv 私有参数
* data 要做处理的数据地址
a len 要做处理的数据单个声道的数据长度
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_hearing_aid_lp_detect(void *priv, s16 *data, int len);
/*
*********************************************************************
* Energy Detect Close
* Description: 关闭能量检测
* Arguments : NULL
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_hearing_aid_lp_close(void);
/*
*********************************************************************
* Get Low Power Flag
* Description: 获取是否能进低功耗的标志位
* Arguments : NULL
* Return : 1:代表可以进入低功耗
0:代表不能进入低功耗
* Note(s) : None.
*********************************************************************
*/
u8 audio_hearing_aid_lp_flag(void);
#endif/*_AUD_HEARING_AID_LOW_POWER_H_*/

View File

@ -0,0 +1,169 @@
#include "generic/typedef.h"
#include "board_config.h"
#include "media/includes.h"
#include "audio_config.h"
#include "sound_device.h"
#include "audio_sidetone.h"
#include "system/task.h"
#if TCFG_SIDETONE_ENABLE
extern struct audio_dac_hdl dac_hdl;
#define SIDETONE_BUF_LEN 256
#define SIDETONE_READBUF_LEN 64 //中断点数设为32则每次数据长度为64
static struct audio_sidetone_hdl {
s16 *sidetone_buf;
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
s16 *sidetone_buf_lr;
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
cbuffer_t cbuf;
OS_SEM sem;
bool busy; //检测任务是否在阻塞态
bool suspend; //暂停监听
struct audio_dac_channel dac_ch;
struct audio_dac_channel_attr attr;
};
static struct audio_sidetone_hdl *sidetone_hdl = NULL;
static inline void audio_pcm_mono_to_dual(s16 *dual_pcm, s16 *mono_pcm, int points)
{
s16 *mono = mono_pcm;
int i = 0;
u8 j = 0;
for (i = 0; i < points; i++, mono++) {
*dual_pcm++ = *mono;
*dual_pcm++ = *mono;
}
}
static void audio_sidetone_task(void)
{
if (!sidetone_hdl) {
sidetone_hdl = zalloc(sizeof(struct audio_sidetone_hdl));
if (!sidetone_hdl) {
printf("zalloc sidetone_hdl err\n");
return;
}
}
sidetone_hdl->suspend = 1;
sidetone_hdl->sidetone_buf = zalloc(SIDETONE_BUF_LEN);
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
sidetone_hdl->sidetone_buf_lr = zalloc(SIDETONE_READBUF_LEN * 2);
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
cbuf_init(&sidetone_hdl->cbuf, sidetone_hdl->sidetone_buf, SIDETONE_BUF_LEN);
os_sem_create(&sidetone_hdl->sem, 0);
audio_dac_new_channel(&dac_hdl, &sidetone_hdl->dac_ch);
sidetone_hdl->attr.delay_time = 6;
sidetone_hdl->attr.protect_time = 8;
sidetone_hdl->attr.write_mode = WRITE_MODE_BLOCK;
audio_dac_channel_set_attr(&sidetone_hdl->dac_ch, &sidetone_hdl->attr);
sound_pcm_dev_start(&sidetone_hdl->dac_ch, 16000, app_audio_get_volume(APP_AUDIO_STATE_CALL));
while (1) {
sidetone_hdl->busy = 0;
os_sem_pend(&sidetone_hdl->sem, 0);
sidetone_hdl->busy = 1;
u16 rlen = cbuf_read(&sidetone_hdl->cbuf, sidetone_hdl->sidetone_buf, SIDETONE_READBUF_LEN);
if (rlen != SIDETONE_READBUF_LEN) {
printf("rlen err : %d\n", rlen);
}
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
audio_pcm_mono_to_dual(sidetone_hdl->sidetone_buf_lr, sidetone_hdl->sidetone_buf, rlen >> 1);
u16 wlen = sound_pcm_dev_write(&sidetone_hdl->dac_ch, sidetone_hdl->sidetone_buf_lr, rlen <<= 1);
#else
u16 wlen = sound_pcm_dev_write(&sidetone_hdl->dac_ch, sidetone_hdl->sidetone_buf, rlen);
#endif
if (wlen != rlen) {
printf("wlen err : %d\n", wlen);
}
}
}
/*
*********************************************************************
* Audio Sidetone Inbuf
* Description: 通话监听数据流输入
* Arguments : data 输入数据地址
* len 输入数据长度
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_sidetone_inbuf(s16 *data, u16 len)
{
if (sidetone_hdl && sidetone_hdl->suspend) {
os_sem_post(&sidetone_hdl->sem);
u16 wlen = cbuf_write(&sidetone_hdl->cbuf, data, len);
if (wlen != len) {
printf("wlen = %d, len = %d\n", wlen, len);
}
}
}
/*
*********************************************************************
* Audio Sidetone Open
* Description: 打开通话监听
* Arguments : None.
* Return : 0成功 其他失败
* Note(s) : None.
*********************************************************************
*/
int audio_sidetone_open(void)
{
if (!sidetone_hdl) {
task_create(audio_sidetone_task, NULL, "sidetone");//创建监听任务
return 0;
}
return -1;
}
/*
*********************************************************************
* Audio Sidetone Close
* Description: 关闭通话监听
* Arguments : None.
* Return : 0成功 其他失败
* Note(s) : None.
*********************************************************************
*/
int audio_sidetone_close(void)
{
if (!sidetone_hdl) {
printf("sidetone already close\n");
return -1;
}
if (!sidetone_hdl->busy) { //任务处于挂起态
sound_pcm_dev_stop(&sidetone_hdl->dac_ch); //关闭监听
task_kill("sidetone");
free(sidetone_hdl->sidetone_buf);
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
free(sidetone_hdl->sidetone_buf_lr);
#endif/*(TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)*/
free(sidetone_hdl);
sidetone_hdl = NULL;
return 0;
}
return -2;
}
/*
*********************************************************************
* Audio Sidetone Suspend
* Description: 暂停通话监听
* Arguments : None.
* Return : 0成功 其他失败
* Note(s) : None.
*********************************************************************
*/
int audio_sidetone_suspend(void)
{
if (sidetone_hdl) {
sidetone_hdl->suspend ? (sidetone_hdl->suspend = 0) : (sidetone_hdl->suspend = 1);
return 0;
}
return -1;
}
#endif/*TCFG_SIDETONE_ENABLE*/

View File

@ -0,0 +1,12 @@
#ifndef _AUD_SIDETONE_H_
#define _AUD_SIDETONE_H_
#include "generic/typedef.h"
#include "board_config.h"
void audio_sidetone_inbuf(s16 *data, u16 len);
int audio_sidetone_open(void);
int audio_sidetone_close(void);
int audio_sidetone_suspend(void);
#endif

543
cpu/br28/audio_iis.c Normal file
View File

@ -0,0 +1,543 @@
#define IIS_TX_MIN_PNS (JL_ALNK0->LEN / 4)
struct audio_iis_sync_node {
void *hdl;
struct list_head entry;
};
/***********************************************************
* i2s 使用接口
*
***********************************************************/
int audio_iis_buffered_frames(struct audio_iis_hdl *iis)
{
return (JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);
}
int audio_iis_buffered_time(struct audio_iis_hdl *iis)
{
if (!iis) {
return 0;
}
int buffered_time = ((audio_iis_buffered_frames(iis) * 1000000) / iis->sample_rate) / 1000;
return buffered_time;
}
int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *))
{
local_irq_disable();
iis->underrun_time = time;
iis->underrun_pns = 0;
iis->underrun_data = priv;
iis->underrun_feedback = feedback;
local_irq_enable();
return 0;
}
void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis)
{
struct audio_iis_sync_node *node;
list_for_each_entry(node, &iis->sync_list, entry) {
sound_pcm_enter_update_frame(node->hdl);
}
}
void audio_iis_syncts_latch_trigger(struct audio_iis_hdl *iis)
{
struct audio_iis_sync_node *node;
list_for_each_entry(node, &iis->sync_list, entry) {
sound_pcm_syncts_latch_trigger(node->hdl);
}
}
void audio_iis_dma_update_to_syncts(struct audio_iis_hdl *iis, int frames)
{
struct audio_iis_sync_node *node;
u8 have_syncts = 0;
list_for_each_entry(node, &iis->sync_list, entry) {
sound_pcm_update_frame_num(node->hdl, frames);
have_syncts = 1;
}
if (have_syncts) {
u16 free_points = *ALNK0_SHN[iis->hw_ch];
int timeout = (1000000 / iis->sample_rate) * (clk_get("sys") / 1000000);
while (free_points == *ALNK0_SHN[iis->hw_ch] && (--timeout > 0));
}
}
void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
{
struct audio_iis_sync_node *node = (struct audio_iis_sync_node *)zalloc(sizeof(struct audio_iis_sync_node));
node->hdl = syncts;
list_add(&node->entry, &iis->sync_list);
if (iis->state == SOUND_PCM_STATE_RUNNING) {
sound_pcm_syncts_latch_trigger(syncts);
}
ALINK_DA2BTSRC_SEL(ALINK0, iis->hw_ch);
}
void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts)
{
struct audio_iis_sync_node *node;
list_for_each_entry(node, &iis->sync_list, entry) {
if (node->hdl == syncts) {
goto remove_node;
}
}
return;
remove_node:
list_del(&node->entry);
free(node);
}
static void audio_iis_tx_irq_handler(struct audio_iis_hdl *iis)
{
if (iis->irq_trigger && iis->trigger_handler) {
iis->trigger_handler(iis->trigger_data);
iis->irq_trigger = 0;
}
if (iis->underrun_pns) {
int unread_frames = JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1;
if (unread_frames <= iis->underrun_pns) {
//TODO
} else {
ALINK_OPNS_SET(ALINK0, iis->underrun_pns);
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
return;
}
}
ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
}
extern ALINK_PARM alink0_platform_data;
int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int sample_rate)
{
memset(iis, 0x0, sizeof(struct audio_iis_hdl));
INIT_LIST_HEAD(&iis->sync_list);
iis->state = SOUND_PCM_STATE_IDLE;
iis->sample_rate = sample_rate;
iis->alink0_param = alink_init(&alink0_platform_data);
alink_channel_init(iis->alink0_param, ch, ALINK_DIR_TX, iis, audio_iis_tx_irq_handler);
/*alink_start();*/
iis->hw_ch = ch;
}
void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis)
{
alink_channel_close(iis->hw_ch);
iis->state = SOUND_PCM_STATE_IDLE;
}
int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis)
{
return iis->sample_rate;
}
int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time)
{
iis->prepared_time = prepared_time;
iis->delay_time = delay_time;
return 0;
}
int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping)
{
if (!iis->input_mapping) {
iis->input_mapping = mapping;
}
if ((iis->input_mapping & SOUND_CHMAP_RL) || (iis->input_mapping & SOUND_CHMAP_RR)) {
printf("Not support this channel map : 0x%x\n", mapping);
}
return 0;
}
int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis)
{
int num = 0;
for (int i = 0; i < 2; i++) {
if (iis->input_mapping & BIT(i)) {
num++;
}
}
return num;
}
#if 0
const unsigned char sin44K[88] ALIGNED(4) = {
0x00, 0x00, 0x45, 0x0E, 0x41, 0x1C, 0xAA, 0x29, 0x3B, 0x36, 0xB2, 0x41, 0xD5, 0x4B, 0x6E, 0x54,
0x51, 0x5B, 0x5A, 0x60, 0x70, 0x63, 0x82, 0x64, 0x8A, 0x63, 0x8E, 0x60, 0x9D, 0x5B, 0xD1, 0x54,
0x4D, 0x4C, 0x3D, 0x42, 0xD5, 0x36, 0x50, 0x2A, 0xF1, 0x1C, 0xFB, 0x0E, 0xB7, 0x00, 0x70, 0xF2,
0x6E, 0xE4, 0xFD, 0xD6, 0x60, 0xCA, 0xD9, 0xBE, 0xA5, 0xB4, 0xF7, 0xAB, 0xFC, 0xA4, 0xDA, 0x9F,
0xAB, 0x9C, 0x7F, 0x9B, 0x5E, 0x9C, 0x3F, 0x9F, 0x19, 0xA4, 0xCE, 0xAA, 0x3D, 0xB3, 0x3A, 0xBD,
0x92, 0xC8, 0x0A, 0xD5, 0x60, 0xE2, 0x50, 0xF0
};
int read_44k_sine_data(void *buf, int bytes, int offset, u8 channel)
{
s16 *sine = (s16 *)sin44K;
s16 *data = (s16 *)buf;
int frame_len = (bytes >> 1) / channel;
int sin44k_frame_len = sizeof(sin44K) / 2;
int i, j;
offset = offset % sin44k_frame_len;
for (i = 0; i < frame_len; i++) {
for (j = 0; j < channel; j++) {
*data++ = sine[offset];
}
if (++offset >= sin44k_frame_len) {
offset = 0;
}
}
return i * 2 * channel;
}
static int frames_offset = 0;
#endif
static int __audio_iis_pcm_write(s16 *dst, s16 *src, int frames, int remapping)
{
/* int frame_bytes = read_44k_sine_data(dst, frames * 2 * 2, frames_offset, 2); */
/* putchar('k'); */
/* frames_offset += (frame_bytes >> 1) / 2; */
/* return frame_bytes; */
if (remapping == 1) {
for (int i = 0; i < frames; i++) {
dst[i * 2] = src[i];
dst[i * 2 + 1] = src[i];
}
return frames << 1;
}
if (remapping == 2) {
memcpy(dst, src, (frames << 1) * 2);
return frames << 2;
}
return frames;
}
#define CVP_REF_SRC_ENABLE
#ifdef CVP_REF_SRC_ENABLE
#define CVP_REF_SRC_TASK_NAME "RefSrcTask"
#include "Resample_api.h"
#include "aec_user.h"
#define CVP_REF_SRC_FRAME_SIZE 512
typedef struct {
volatile u8 state;
volatile u8 busy;
RS_STUCT_API *sw_src_api;
u8 *sw_src_buf;
u16 input_rate;
u16 output_rate;
s16 ref_tmp_buf[CVP_REF_SRC_FRAME_SIZE / 2];
cbuffer_t cbuf;
u8 ref_buf[CVP_REF_SRC_FRAME_SIZE * 3];
} aec_ref_src_t;
static aec_ref_src_t *aec_ref_src = NULL;
extern void audio_aec_ref_src_get_output_rate(u16 *input_rate, u16 *output_rate);
extern u8 bt_phone_dec_is_running();
extern struct audio_iis_hdl iis_hdl;
void audio_aec_ref_src_run(s16 *data, int len)
{
u16 ref_len = 0;
if (aec_ref_src) {
if (iis_hdl.input_mapping != SOUND_CHMAP_MONO) {
/*双变单*/
for (int i = 0; i < (len >> 2); i++) {
aec_ref_src->ref_tmp_buf[i] = data[2 * i];
}
len >>= 1;
}
/* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
/* printf("%d %d \n",input_rate,output_rate); */
if (aec_ref_src->sw_src_api) {
/* aec_ref_src->sw_src_api->set_sr(aec_ref_src->sw_src_buf, aec_ref_src->output_rate); */
ref_len = aec_ref_src->sw_src_api->run(aec_ref_src->sw_src_buf, aec_ref_src->ref_tmp_buf, len >> 1, aec_ref_src->ref_tmp_buf);
ref_len <<= 1;
}
/* printf("ref_len %d", ref_len); */
audio_aec_refbuf(aec_ref_src->ref_tmp_buf, ref_len);
}
}
static void audio_aec_ref_src_task(void *p)
{
int res;
int msg[16];
while (1) {
res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
if (aec_ref_src && aec_ref_src->state) {
s16 *data = (int)msg[1];
int len = msg[2];
int rlen = 0;
aec_ref_src->busy = 1;
if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
cbuf_read(&aec_ref_src->cbuf, aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
audio_aec_ref_src_run(aec_ref_src->ref_tmp_buf, CVP_REF_SRC_FRAME_SIZE);
}
aec_ref_src->busy = 0;
}
}
}
int audio_aec_ref_src_data_fill(void *p, s16 *data, int len)
{
int ret = 0;
if (aec_ref_src && aec_ref_src->state) {
audio_aec_ref_start(1);
if (0 == cbuf_write(&aec_ref_src->cbuf, data, len)) {
/* cbuf_clear(&aec_ref_src->cbuf); */
printf("ref src cbuf wfail!!");
}
if (cbuf_get_data_len(&aec_ref_src->cbuf) >= CVP_REF_SRC_FRAME_SIZE) {
ret = os_taskq_post_msg(CVP_REF_SRC_TASK_NAME, 2, (int)data, len);
}
}
return ret;
}
int audio_aec_ref_src_open(u32 insr, u32 outsr)
{
if (aec_ref_src) {
printf("aec_ref_src alreadly open !!!");
return -1;
}
aec_ref_src = zalloc(sizeof(aec_ref_src_t));
if (aec_ref_src == NULL) {
printf("aec_ref_src malloc fail !!!");
return -1;
}
cbuf_init(&aec_ref_src->cbuf, aec_ref_src->ref_buf, sizeof(aec_ref_src->ref_buf));
int err = os_task_create(audio_aec_ref_src_task, NULL, 4, 256, 128, CVP_REF_SRC_TASK_NAME);
if (err != OS_NO_ERR) {
printf("task create error!");
free(aec_ref_src);
aec_ref_src = NULL;
return -1;
}
/* audio_aec_ref_src_get_output_rate(&aec_ref_src->input_rate, &aec_ref_src->output_rate); */
aec_ref_src->input_rate = insr;
aec_ref_src->output_rate = outsr;
aec_ref_src->sw_src_api = get_rs16_context();
printf("sw_src_api:0x%x\n", aec_ref_src->sw_src_api);
ASSERT(aec_ref_src->sw_src_api);
int sw_src_need_buf = aec_ref_src->sw_src_api->need_buf();
printf("sw_src_buf:%d\n", sw_src_need_buf);
aec_ref_src->sw_src_buf = zalloc(sw_src_need_buf);
ASSERT(aec_ref_src->sw_src_buf, "sw_src_buf zalloc fail");
RS_PARA_STRUCT rs_para_obj;
rs_para_obj.nch = 1;
if (insr == 44100) {
rs_para_obj.new_insample = 44117;
} else {
rs_para_obj.new_insample = insr;
}
rs_para_obj.new_outsample = outsr;
printf("sw src,ch = %d, in = %d,out = %d\n", rs_para_obj.nch, rs_para_obj.new_insample, rs_para_obj.new_outsample);
aec_ref_src->sw_src_api->open(aec_ref_src->sw_src_buf, &rs_para_obj);
aec_ref_src->state = 1;
return 0;
}
void audio_aec_ref_src_close()
{
if (aec_ref_src) {
aec_ref_src->state = 0;
while (aec_ref_src->busy) {
putchar('w');
os_time_dly(1);
}
int err = os_task_del(CVP_REF_SRC_TASK_NAME);
if (err) {
log_i("kill task %s: err=%d\n", CVP_REF_SRC_TASK_NAME, err);
}
if (aec_ref_src->sw_src_api) {
aec_ref_src->sw_src_api = NULL;
}
if (aec_ref_src->sw_src_buf) {
free(aec_ref_src->sw_src_buf);
aec_ref_src->sw_src_buf = NULL;
}
free(aec_ref_src);
aec_ref_src = NULL;
}
}
#endif/*CVP_REF_SRC_ENABLE*/
int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len)
{
if (iis->state != SOUND_PCM_STATE_RUNNING) {
return 0;
}
int remapping_ch = 2;
int frames = 0;
if (iis->input_mapping == SOUND_CHMAP_MONO) {
frames = len >> 1;
remapping_ch = 1;
} else if (iis->input_mapping & SOUND_CHMAP_FR) {
frames = len >> 2;
remapping_ch = 2;
} else {
}
s16 *ref_data = (s16 *)data;
int swp = *ALNK0_SWPTR[iis->hw_ch];
int free_frames = *ALNK0_SHN[iis->hw_ch] - iis->reserved_frames;
/* printf("free : %d, %d\n", *ALNK0_SHN[iis->hw_ch], free_frames); */
if (free_frames <= 0) {
return 0;
}
if (free_frames > frames) {
free_frames = frames;
}
frames = 0;
if (swp + free_frames > JL_ALNK0->LEN) {
frames = JL_ALNK0->LEN - swp;
__audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, frames, remapping_ch);
free_frames -= frames;
data = (s16 *)data + frames * remapping_ch;
swp = 0;
}
__audio_iis_pcm_write((s16 *)(*ALNK0_BUF_ADR[iis->hw_ch] + swp * 2 * 2), (s16 *)data, free_frames, remapping_ch);
frames += free_frames;
audio_iis_syncts_update_frame(iis);
*ALNK0_SHN[iis->hw_ch] = frames;
__asm_csync();
audio_iis_dma_update_to_syncts(iis, frames);
/*printf("frames : %d\n", frames);*/
/*printf("CLK CON2 : %d, %d\n", JL_CLOCK->CLK_CON2 & 0x3, (JL_CLOCK->CLK_CON2 >> 2) & 0x3);*/
#ifdef CVP_REF_SRC_ENABLE
if (bt_phone_dec_is_running()) {
audio_aec_ref_src_data_fill(iis, ref_data, (frames << 1) * remapping_ch);
}
#endif
return (frames << 1) * remapping_ch;
}
static void audio_iis_dma_fifo_start(struct audio_iis_hdl *iis)
{
if (iis->state != SOUND_PCM_STATE_PREPARED) {
return;
}
if (iis->prepared_frames) {
*ALNK0_SHN[iis->hw_ch] = iis->prepared_frames;
__asm_csync();
}
local_irq_disable();
iis->state = SOUND_PCM_STATE_RUNNING;
ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
local_irq_enable();
audio_iis_syncts_latch_trigger(iis);
}
static int audio_iis_fifo_set_delay(struct audio_iis_hdl *iis)
{
iis->prepared_frames = iis->prepared_time * iis->sample_rate / 1000;
int delay_frames = (iis->delay_time * iis->sample_rate) / 1000 / 2 * 2;
if (iis->prepared_frames >= JL_ALNK0->LEN) {
iis->prepared_frames = JL_ALNK0->LEN / 2;
}
if (delay_frames < JL_ALNK0->LEN) {
iis->reserved_frames = JL_ALNK0->LEN - delay_frames;
} else {
iis->reserved_frames = 0;
}
return 0;
}
int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time_ms, void *priv, void (*callback)(void *))
{
if (iis->state != SOUND_PCM_STATE_RUNNING) {
return -EINVAL;
}
int irq_frames = time_ms * iis->sample_rate / 1000;
int pns = audio_iis_buffered_frames(iis) - irq_frames;
if (pns < irq_frames) {
sys_hi_timeout_add(priv, callback, time_ms);
return -EINVAL;
}
local_irq_disable();
if (pns > ALINK_OPNS(ALINK0)) {
ALINK_OPNS_SET(ALINK0, pns);
}
iis->irq_trigger = 1;
iis->trigger_handler = callback;
iis->trigger_data = priv;
ALINK_CHx_IE(ALINK0, iis->hw_ch, 1);
local_irq_enable();
return 0;
}
int audio_iis_dma_start(struct audio_iis_hdl *iis)
{
if (iis->state == SOUND_PCM_STATE_RUNNING) {
return 0;
}
audio_iis_fifo_set_delay(iis);
iis->underrun_pns = iis->underrun_time ? (iis->underrun_time * iis->sample_rate / 1000) : 0;
ALINK_OPNS_SET(ALINK0, (iis->underrun_pns ? iis->underrun_pns : IIS_TX_MIN_PNS));
iis->state = SOUND_PCM_STATE_PREPARED;
/* printf("DMA : %d, %d, %d\n", *ALNK0_SHN[iis->hw_ch], *ALNK0_SWPTR[iis->hw_ch], *ALNK0_HWPTR[iis->hw_ch]); */
audio_iis_dma_fifo_start(iis);
alink_start(iis->alink0_param);
/* printf("[iis dma start]... %d, free : %d, prepared_frames : %d, reserved_frames : %d\n", JL_ALNK0->LEN, *ALNK0_SHN[iis->hw_ch], iis->prepared_frames, iis->reserved_frames); */
}
int audio_iis_dma_stop(struct audio_iis_hdl *iis)
{
if (iis->state != SOUND_PCM_STATE_RUNNING) {
return 0;
}
/*audio_iis_buffered_frames_fade_out(iis, JL_ALNK0->LEN - *ALNK0_SHN[iis->hw_ch] - 1);*/
ALINK_CHx_IE(ALINK0, iis->hw_ch, 0);
ALINK_CLR_CHx_PND(ALINK0, iis->hw_ch);
/* alink_uninit(iis->alink0_param); */
iis->input_mapping = 0;
iis->state = SOUND_PCM_STATE_SUSPENDED;
return 0;
}

68
cpu/br28/audio_iis.h Normal file
View File

@ -0,0 +1,68 @@
/*****************************************************************
>file name : audio_iis.h
>create time : Fri 25 Feb 2022 04:35:37 PM CST
*****************************************************************/
#ifndef _AUDIO_IIS_H_
#define _AUDIO_IIS_H_
#include "system/includes.h"
#include "sound/pcm.h"
#include "asm/iis.h"
#include "audio_link.h"
struct audio_iis_hdl {
u8 state;
u8 hw_ch;
u8 irq_trigger;
u8 input_mapping;
short delay_time;
short prepared_time;
short prepared_frames;
short reserved_frames;
short underrun_time;
short underrun_pns;
void *underrun_data;
void (*underrun_feedback)(void *);
void *trigger_data;
void (*trigger_handler)(void *);
int sample_rate;
struct list_head sync_list;
ALINK_PARM *alink0_param;
};
int audio_iis_pcm_tx_open(struct audio_iis_hdl *iis, u8 ch, int smaple_rate);
void audio_iis_pcm_tx_close(struct audio_iis_hdl *iis);
int audio_iis_pcm_remapping(struct audio_iis_hdl *iis, u8 mapping);
int audio_iis_pcm_write(struct audio_iis_hdl *iis, void *data, int len);
int audio_iis_dma_start(struct audio_iis_hdl *iis);
int audio_iis_dma_stop(struct audio_iis_hdl *iis);
int audio_iis_set_delay_time(struct audio_iis_hdl *iis, int prepared_time, int delay_time);
int audio_iis_set_underrun_params(struct audio_iis_hdl *iis, int time, void *priv, void (*feedback)(void *));
int audio_iis_trigger_interrupt(struct audio_iis_hdl *iis, int time, void *priv, void (*callback)(void *));
void audio_iis_add_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
void audio_iis_remove_syncts_handle(struct audio_iis_hdl *iis, void *syncts);
void audio_iis_syncts_update_frame(struct audio_iis_hdl *iis);
int audio_iis_buffered_frames(struct audio_iis_hdl *iis);
int audio_iis_buffered_time(struct audio_iis_hdl *iis);
int audio_iis_pcm_channel_num(struct audio_iis_hdl *iis);
int audio_iis_pcm_sample_rate(struct audio_iis_hdl *iis);
int audio_aec_ref_src_data_fill(void *p, s16 *data, int len);
int audio_aec_ref_src_open(u32 insr, u32 outsr);
void audio_aec_ref_src_close();
#endif

808
cpu/br28/audio_link.c Normal file
View File

@ -0,0 +1,808 @@
/*****************************************************************
>file name : lib/media/cpu/br22/audio_link.c
>author :
>create time : Fri 7 Dec 2018 14:59:12 PM CST
*****************************************************************/
#include "includes.h"
#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "asm/clock.h"
#include "asm/iis.h"
#include "audio_link.h"
#include "app_config.h"
#include "update.h"
#include "audio_syncts.h"
#include "audio_iis.h"
#include "sound/sound.h"
/* #if TCFG_AUDIO_INPUT_IIS || TCFG_AUDIO_OUTPUT_IIS */
#define ALINK_TEST_ENABLE 0
#define ALINK_DEBUG_INFO
#ifdef ALINK_DEBUG_INFO
#define alink_printf printf
#else
#define alink_printf(...)
#endif
static void alink0_info_dump();
static u32 *ALNK0_BUF_ADR[] = {
(u32 *)(&(JL_ALNK0->ADR0)),
(u32 *)(&(JL_ALNK0->ADR1)),
(u32 *)(&(JL_ALNK0->ADR2)),
(u32 *)(&(JL_ALNK0->ADR3)),
};
static u32 *ALNK0_HWPTR[] = {
(u32 *)(&(JL_ALNK0->HWPTR0)),
(u32 *)(&(JL_ALNK0->HWPTR1)),
(u32 *)(&(JL_ALNK0->HWPTR2)),
(u32 *)(&(JL_ALNK0->HWPTR3)),
};
static u32 *ALNK0_SWPTR[] = {
(u32 *)(&(JL_ALNK0->SWPTR0)),
(u32 *)(&(JL_ALNK0->SWPTR1)),
(u32 *)(&(JL_ALNK0->SWPTR2)),
(u32 *)(&(JL_ALNK0->SWPTR3)),
};
static u32 *ALNK0_SHN[] = {
(u32 *)(&(JL_ALNK0->SHN0)),
(u32 *)(&(JL_ALNK0->SHN1)),
(u32 *)(&(JL_ALNK0->SHN2)),
(u32 *)(&(JL_ALNK0->SHN3)),
};
static u32 PFI_ALNK0_DAT[] = {
PFI_ALNK0_DAT0,
PFI_ALNK0_DAT1,
PFI_ALNK0_DAT2,
PFI_ALNK0_DAT3,
};
static u32 FO_ALNK0_DAT[] = {
FO_ALNK0_DAT0,
FO_ALNK0_DAT1,
FO_ALNK0_DAT2,
FO_ALNK0_DAT3,
};
enum {
MCLK_11M2896K = 0,
MCLK_12M288K
};
enum {
MCLK_EXTERNAL = 0u,
MCLK_SYS_CLK ,
MCLK_OSC_CLK ,
MCLK_PLL_CLK ,
};
enum {
MCLK_DIV_1 = 0u,
MCLK_DIV_2 ,
MCLK_DIV_4 ,
MCLK_DIV_8 ,
MCLK_DIV_16 ,
};
enum {
MCLK_LRDIV_EX = 0u,
MCLK_LRDIV_64FS ,
MCLK_LRDIV_128FS ,
MCLK_LRDIV_192FS ,
MCLK_LRDIV_256FS ,
MCLK_LRDIV_384FS ,
MCLK_LRDIV_512FS ,
MCLK_LRDIV_768FS ,
};
#ifndef TCFG_IIS_SR
#define TCFG_IIS_SR 44100
#endif
extern u32 clock_get_pll_target_frequency();
u32 audio_iis_hw_rates_match(u32 sr)
{
u8 i = 0;
u32 pll_tar = clock_get_pll_target_frequency();
if (pll_tar == 240) {
u32 hw_rates[] = {ALINK_SR_48000, ALINK_SR_44100, ALINK_SR_32000, ALINK_SR_24000, ALINK_SR_22050, ALINK_SR_16000, ALINK_SR_12000, ALINK_SR_11025, ALINK_SR_8000};
for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
if (hw_rates[i] == sr) {
log_i("match sr %d\n", sr);
return sr;
}
}
} else {
u32 hw_rates[] = {ALINK_SR_44100, ALINK_SR_22050, ALINK_SR_11025};
for (i = 0; i < ARRAY_SIZE(hw_rates); i++) {
if (hw_rates[i] == sr) {
log_i("match sr %d\n", sr);
return sr;
}
}
}
log_e("not match is hw sr %d\n", sr);
return TCFG_IIS_SR;
}
static ALINK_PARM *p_alink0_parm = NULL;
u32 alink_get_addr(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
u32 buf_addr = 0;
buf_addr = *ALNK0_BUF_ADR[hw_channel_parm->ch_idx];
return buf_addr;
}
u32 alink_get_shn(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
int shn = 0;
shn = *ALNK0_SHN[hw_channel_parm->ch_idx];
return shn;
}
void alink_set_shn(void *hw_channel, u32 len)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
if (len) {
*ALNK0_SHN[hw_channel_parm->ch_idx] = len;
}
}
u32 alink_get_swptr(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
int swptr = 0;
swptr = *ALNK0_SWPTR[hw_channel_parm->ch_idx];
return swptr;
}
void alink_set_swptr(void *hw_channel, u32 value)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
*ALNK0_SWPTR[hw_channel_parm->ch_idx] = value;
}
u32 alink_get_hwptr(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
int hwptr = 0;
hwptr = *ALNK0_HWPTR[hw_channel_parm->ch_idx];
return hwptr;
}
void alink_set_hwptr(void *hw_channel, u32 value)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
*ALNK0_HWPTR[hw_channel_parm->ch_idx] = value;
}
void alink_set_ch_ie(void *hw_channel, u32 value)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, value);
}
void alink_clr_ch_pnd(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
ALINK_CLR_CHx_PND(hw_channel_parm->module, hw_channel_parm->ch_idx);
}
//==================================================
static void alink_io_in_init(u8 gpio)
{
gpio_set_direction(gpio, 1);
gpio_set_pull_down(gpio, 0);
gpio_set_pull_up(gpio, 1);
gpio_set_die(gpio, 1);
}
static void alink_io_out_init(u8 gpio)
{
gpio_set_direction(gpio, 0);
gpio_set_pull_down(gpio, 0);
gpio_set_pull_up(gpio, 0);
gpio_set_die(gpio, 0);
gpio_direction_output(gpio, 1);
}
static void *alink_addr(void *hw_alink, u8 ch)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
s16 *buf_addr = NULL; //can be used
u32 buf_index = 0;
if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
buf_addr = (s16 *)(*ALNK0_BUF_ADR[ch] + *ALNK0_SWPTR[ch] * 4);
} else {
buf_addr = (s16 *)(hw_alink_parm->ch_cfg[ch].buf);
u8 index_table[4] = {12, 13, 14, 15};
u8 bit_index = index_table[ch];
buf_index = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(bit_index)) ? 0 : 1;
buf_addr = buf_addr + ((hw_alink_parm->dma_len / 2 / 2) * buf_index);
}
return buf_addr;
}
___interrupt
static void alink0_dma_isr(void)
{
u16 reg;
s16 *buf_addr = NULL ;
u8 ch = 0;
reg = JL_ALNK0->CON2;
reg >>= 4;
for (ch = 0; ch < 4; ch++) {
if (!(reg & BIT(ch))) {
continue;
}
buf_addr = (s16 *)alink_addr(p_alink0_parm, ch);
if (p_alink0_parm->ch_cfg[ch].isr_cb) {
if (p_alink0_parm->buf_mode == ALINK_BUF_CIRCLE) {
p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, (JL_ALNK0->PNS & 0xffff) * 4);
} else {
p_alink0_parm->ch_cfg[ch].isr_cb(p_alink0_parm->ch_cfg[ch].private_data, buf_addr, p_alink0_parm->dma_len / 2);
}
}
ALINK_CLR_CHx_PND(p_alink0_parm->module, ch);
}
}
static void alink_sr(void *hw_alink, u32 rate)
{
alink_printf("ALINK_SR = %d\n", rate);
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
hw_alink_parm->sample_rate = rate;
u8 module = hw_alink_parm->module;
u8 pll_target_frequency = clock_get_pll_target_frequency();
alink_printf("pll_target_frequency = %d\n", pll_target_frequency);
switch (rate) {
case ALINK_SR_48000:
/*12.288Mhz 256fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_1);
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
break ;
case ALINK_SR_44100:
/*11.289Mhz 256fs*/
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
ALINK_MDIV(module, MCLK_DIV_1);
if (pll_target_frequency == 192) {
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
} else if (pll_target_frequency == 240) {
ALINK_LRDIV(module, MCLK_LRDIV_128FS);
}
break ;
case ALINK_SR_32000:
/*12.288Mhz 384fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_1);
ALINK_LRDIV(module, MCLK_LRDIV_384FS);
break ;
case ALINK_SR_24000:
/*12.288Mhz 512fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_2);
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
break ;
case ALINK_SR_22050:
/*11.289Mhz 512fs*/
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
ALINK_MDIV(module, MCLK_DIV_1);
if (pll_target_frequency == 192) {
ALINK_LRDIV(module, MCLK_LRDIV_512FS);
} else if (pll_target_frequency == 240) {
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
}
break ;
case ALINK_SR_16000:
/*12.288/2Mhz 384fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_1);
ALINK_LRDIV(module, MCLK_LRDIV_768FS);
break ;
case ALINK_SR_12000:
/*12.288/2Mhz 512fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_4);
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
break ;
case ALINK_SR_11025:
/*11.289/2Mhz 512fs*/
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
ALINK_MDIV(module, MCLK_DIV_2);
if (pll_target_frequency == 192) {
ALINK_LRDIV(module, MCLK_LRDIV_512FS);
} else if (pll_target_frequency == 240) {
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
}
break ;
case ALINK_SR_8000:
/*12.288/4Mhz 384fs*/
audio_link_clock_sel(ALINK_CLOCK_12M288K);
ALINK_MDIV(module, MCLK_DIV_4);
ALINK_LRDIV(module, MCLK_LRDIV_384FS);
break ;
default:
//44100
/*11.289Mhz 256fs*/
audio_link_clock_sel(ALINK_CLOCK_11M2896K);
ALINK_MDIV(module, MCLK_DIV_1);
ALINK_LRDIV(module, MCLK_LRDIV_256FS);
break;
}
if (hw_alink_parm->role == ALINK_ROLE_SLAVE) {
ALINK_LRDIV(module, MCLK_LRDIV_EX);
}
}
void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len))
{
if (!hw_alink) {
return NULL;
}
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
u8 module = hw_alink_parm->module;
hw_alink_parm->ch_cfg[ch_idx].module = module;
hw_alink_parm->ch_cfg[ch_idx].dir = dir;
hw_alink_parm->ch_cfg[ch_idx].ch_idx = ch_idx;
hw_alink_parm->ch_cfg[ch_idx].isr_cb = handle;
hw_alink_parm->ch_cfg[ch_idx].private_data = priv;
printf("dma len %d", hw_alink_parm->dma_len);
hw_alink_parm->ch_cfg[ch_idx].buf = zalloc(hw_alink_parm->dma_len);
printf(">>> alink_channel_init %x\n", hw_alink_parm->ch_cfg[ch_idx].buf);
u32 *buf_addr;
//===================================//
// ALNK CH DMA BUF //
//===================================//
buf_addr = ALNK0_BUF_ADR[ch_idx];
*buf_addr = (u32)(hw_alink_parm->ch_cfg[ch_idx].buf);
//===================================//
// ALNK工作模式 //
//===================================//
if (hw_alink_parm->mode > ALINK_MD_IIS_RALIGN) {
ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode - ALINK_MD_IIS_RALIGN));
} else {
ALINK_CHx_MODE_SEL(module, ch_idx, (hw_alink_parm->mode));
}
//===================================//
// ALNK CH DAT IO INIT //
//===================================//
if (hw_alink_parm->ch_cfg[ch_idx].dir == ALINK_DIR_RX) {
alink_io_in_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
gpio_set_fun_input_port(hw_alink_parm->ch_cfg[ch_idx].data_io, PFI_ALNK0_DAT[ch_idx], LOW_POWER_FREE);
} else {
alink_io_out_init(hw_alink_parm->ch_cfg[ch_idx].data_io);
gpio_set_fun_output_port(hw_alink_parm->ch_cfg[ch_idx].data_io, FO_ALNK0_DAT[ch_idx], 1, 1, LOW_POWER_FREE);
}
ALINK_CHx_DIR_MODE(module, ch_idx, dir);
ALINK_CHx_IE(module, ch_idx, 1);
r_printf("alink%d, ch%d init\n", module, ch_idx);
return &hw_alink_parm->ch_cfg[ch_idx];
}
static void alink0_info_dump()
{
alink_printf("JL_ALNK0->CON0 = 0x%x", JL_ALNK0->CON0);
alink_printf("JL_ALNK0->CON1 = 0x%x", JL_ALNK0->CON1);
alink_printf("JL_ALNK0->CON2 = 0x%x", JL_ALNK0->CON2);
alink_printf("JL_ALNK0->CON3 = 0x%x", JL_ALNK0->CON3);
alink_printf("JL_ALNK0->LEN = 0x%x", JL_ALNK0->LEN);
alink_printf("JL_ALNK0->ADR0 = 0x%x", JL_ALNK0->ADR0);
alink_printf("JL_ALNK0->ADR1 = 0x%x", JL_ALNK0->ADR1);
alink_printf("JL_ALNK0->ADR2 = 0x%x", JL_ALNK0->ADR2);
alink_printf("JL_ALNK0->ADR3 = 0x%x", JL_ALNK0->ADR3);
alink_printf("JL_ALNK0->PNS = 0x%x", JL_ALNK0->PNS);
alink_printf("JL_ALNK0->HWPTR0 = 0x%x", JL_ALNK0->HWPTR0);
alink_printf("JL_ALNK0->HWPTR1 = 0x%x", JL_ALNK0->HWPTR1);
alink_printf("JL_ALNK0->HWPTR2 = 0x%x", JL_ALNK0->HWPTR2);
alink_printf("JL_ALNK0->HWPTR3 = 0x%x", JL_ALNK0->HWPTR3);
alink_printf("JL_ALNK0->SWPTR0 = 0x%x", JL_ALNK0->SWPTR0);
alink_printf("JL_ALNK0->SWPTR1 = 0x%x", JL_ALNK0->SWPTR1);
alink_printf("JL_ALNK0->SWPTR2 = 0x%x", JL_ALNK0->SWPTR2);
alink_printf("JL_ALNK0->SWPTR3 = 0x%x", JL_ALNK0->SWPTR3);
alink_printf("JL_ALNK0->SHN0 = 0x%x", JL_ALNK0->SHN0);
alink_printf("JL_ALNK0->SHN1 = 0x%x", JL_ALNK0->SHN1);
alink_printf("JL_ALNK0->SHN2 = 0x%x", JL_ALNK0->SHN2);
alink_printf("JL_ALNK0->SHN3 = 0x%x", JL_ALNK0->SHN3);
}
void *alink_init(void *hw_alink)
{
if (hw_alink == NULL) {
return NULL;
}
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
u8 module = hw_alink_parm->module;
p_alink0_parm = (ALINK_PARM *)hw_alink_parm;
ALNK_CON_RESET(module);
ALNK_HWPTR_RESET(module);
ALNK_SWPTR_RESET(module);
ALNK_ADR_RESET(module);
ALNK_SHN_RESET(module);
ALNK_PNS_RESET(module);
ALINK_CLR_ALL_PND(module);
ALINK_MSRC(module, MCLK_PLL_CLK); /*MCLK source*/
//===================================//
// 输出时钟配置 //
//===================================//
if (hw_alink_parm->role == ALINK_ROLE_MASTER) {
//主机输出时钟
if (hw_alink_parm->mclk_io != ALINK_CLK_OUPUT_DISABLE) {
alink_io_out_init(hw_alink_parm->mclk_io);
gpio_set_fun_output_port(hw_alink_parm->mclk_io, FO_ALNK0_MCLK, 1, 1, LOW_POWER_FREE);
ALINK_MOE(module, 1); /*MCLK output to IO*/
}
if ((hw_alink_parm->sclk_io != ALINK_CLK_OUPUT_DISABLE) && (p_alink0_parm->lrclk_io != ALINK_CLK_OUPUT_DISABLE)) {
alink_io_out_init(hw_alink_parm->lrclk_io);
gpio_set_fun_output_port(hw_alink_parm->lrclk_io, FO_ALNK0_LRCK, 1, 1, LOW_POWER_FREE);
alink_io_out_init(hw_alink_parm->sclk_io);
gpio_set_fun_output_port(hw_alink_parm->sclk_io, FO_ALNK0_SCLK, 1, 1, LOW_POWER_FREE);
ALINK_SOE(module, 1); /*SCLK/LRCK output to IO*/
}
} else {
//从机输入时钟
alink_io_in_init(hw_alink_parm->mclk_io);
alink_io_in_init(hw_alink_parm->sclk_io);
alink_io_in_init(hw_alink_parm->lrclk_io);
gpio_set_fun_input_port(hw_alink_parm->mclk_io, PFI_ALNK0_MCLK, LOW_POWER_FREE);
gpio_set_fun_input_port(hw_alink_parm->sclk_io, PFI_ALNK0_SCLK, LOW_POWER_FREE);
gpio_set_fun_input_port(hw_alink_parm->lrclk_io, PFI_ALNK0_LRCK, LOW_POWER_FREE);
ALINK_MOE(module, 0); /*MCLK input to IO*/
ALINK_SOE(module, 0); /*SCLK/LRCK output to IO*/
}
//===================================//
// 基本模式/扩展模式 //
//===================================//
ALINK_DSPE(module, hw_alink_parm->mode >> 2);
//===================================//
// 数据位宽16/32bit //
//===================================//
//注意: 配置了24bit, 一定要选ALINK_FRAME_64SCLK, 因为sclk32 x 2才会有24bit;
if (hw_alink_parm->bitwide == ALINK_LEN_24BIT) {
ASSERT(hw_alink_parm->sclk_per_frame == ALINK_FRAME_64SCLK);
ALINK_24BIT_MODE(module);
//一个点需要4bytes, LR = 2, 双buf = 2
} else {
ALINK_16BIT_MODE(module);
//一个点需要2bytes, LR = 2, 双buf = 2
}
//===================================//
// 时钟边沿选择 //
//===================================//
SCLKINV(module, hw_alink_parm->clk_mode);
//===================================//
// 每帧数据sclk个数 //
//===================================//
F32_EN(module, hw_alink_parm->sclk_per_frame);
//===================================//
// 设置数据采样率 //
//===================================//
alink_sr(hw_alink_parm, hw_alink_parm->sample_rate);
//===================================//
// 设置DMA MODE //
//===================================//
ALINK_DMA_MODE_SEL(module, hw_alink_parm->buf_mode);
if (hw_alink_parm->buf_mode == ALINK_BUF_CIRCLE) {
ALINK_OPNS_SET(module, hw_alink_parm->dma_len / 16);
if (hw_alink_parm->iperiod) {
ALINK_IPNS_SET(module, hw_alink_parm->iperiod);
} else {
ALINK_IPNS_SET(module, hw_alink_parm->dma_len / 8);
}
//一个点需要2bytes, LR = 2
ALINK_LEN_SET(module, hw_alink_parm->dma_len / 4);
} else {
//一个点需要2bytes, LR = 2, 双buf = 2
ALINK_LEN_SET(module, hw_alink_parm->dma_len / 8);
}
request_irq(IRQ_ALINK0_IDX, 3, alink0_dma_isr, 0);
return hw_alink_parm;
}
void alink_channel_close(void *hw_channel)
{
struct alnk_hw_ch *hw_channel_parm = (struct alnk_hw_ch *)hw_channel;
ALINK_CHx_CLOSE(hw_channel_parm->module, hw_channel_parm->ch_idx);
ALINK_CHx_IE(hw_channel_parm->module, hw_channel_parm->ch_idx, 0);
gpio_set_pull_up(hw_channel_parm->data_io, 0);
gpio_set_pull_down(hw_channel_parm->data_io, 0);
gpio_set_direction(hw_channel_parm->data_io, 1);
gpio_set_die(hw_channel_parm->data_io, 0);
if (hw_channel_parm->buf) {
free(hw_channel_parm->buf);
hw_channel_parm->buf = NULL;
}
r_printf("alink_ch %d closed\n", hw_channel_parm->ch_idx);
}
int alink_start(void *hw_alink)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
if (hw_alink_parm) {
ALINK_EN(hw_alink_parm->module, 1);
return 0;
}
return -1;
}
void alink_uninit(void *hw_alink)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
if (!hw_alink_parm) {
return;
}
ALINK_EN(hw_alink_parm->module, 0);
for (int i = 0; i < 4; i++) {
if (hw_alink_parm->ch_cfg[i].buf) {
alink_channel_close(&hw_alink_parm->ch_cfg[i]);
}
}
ALNK_CON_RESET(hw_alink_parm->module);
hw_alink_parm = NULL;
alink_printf("audio_link_exit OK\n");
}
static u8 iis_driver_close(void)
{
alink_uninit(p_alink0_parm);
return 0;
}
REGISTER_UPDATE_TARGET(iis_update_target) = {
.name = "iis",
.driver_close = iis_driver_close,
};
int alink_get_sr(void *hw_alink)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
if (hw_alink_parm) {
return hw_alink_parm->sample_rate;
} else {
return -1;
}
}
int alink_set_sr(void *hw_alink, u32 sr)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
if (!hw_alink_parm) {
return -1;
}
if (hw_alink_parm->sample_rate == sr) {
return 0;
}
u8 is_alink_en = (ALINK_SEL(hw_alink_parm->module, CON0) & BIT(11));
if (is_alink_en) {
ALINK_EN(hw_alink_parm->module, 0);
}
alink_sr(hw_alink_parm, sr);
if (is_alink_en) {
ALINK_EN(hw_alink_parm->module, 1);
}
return 0;
}
u32 alink_get_dma_len(void *hw_alink)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
return ALINK_FIFO_LEN(hw_alink_parm->module);
}
void alink_set_tx_pns(void *hw_alink, u32 len)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
ALINK_OPNS_SET(hw_alink_parm->module, len);
}
void alink_set_rx_pns(void *hw_alink, u32 len)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
ALINK_IPNS_SET(hw_alink_parm->module, len);
}
int alink_get_tx_pns(void *hw_alink)
{
ALINK_PARM *hw_alink_parm = (ALINK_PARM *)hw_alink;
return ALINK_SEL(hw_alink_parm->module, PNS);
}
#include "audio_iis.c"
//===============================================//
// for APP use demo //
//===============================================//
#if ALINK_TEST_ENABLE
short const tsin_441k[441] = {
0x0000, 0x122d, 0x23fb, 0x350f, 0x450f, 0x53aa, 0x6092, 0x6b85, 0x744b, 0x7ab5, 0x7ea2, 0x7fff, 0x7ec3, 0x7af6, 0x74ab, 0x6c03,
0x612a, 0x545a, 0x45d4, 0x35e3, 0x24db, 0x1314, 0x00e9, 0xeeba, 0xdce5, 0xcbc6, 0xbbb6, 0xad08, 0xa008, 0x94fa, 0x8c18, 0x858f,
0x8181, 0x8003, 0x811d, 0x84ca, 0x8af5, 0x9380, 0x9e3e, 0xaaf7, 0xb969, 0xc94a, 0xda46, 0xec06, 0xfe2d, 0x105e, 0x223a, 0x3365,
0x4385, 0x5246, 0x5f5d, 0x6a85, 0x7384, 0x7a2d, 0x7e5b, 0x7ffa, 0x7f01, 0x7b75, 0x7568, 0x6cfb, 0x6258, 0x55b7, 0x4759, 0x3789,
0x2699, 0x14e1, 0x02bc, 0xf089, 0xdea7, 0xcd71, 0xbd42, 0xae6d, 0xa13f, 0x95fd, 0x8ce1, 0x861a, 0x81cb, 0x800b, 0x80e3, 0x844e,
0x8a3c, 0x928c, 0x9d13, 0xa99c, 0xb7e6, 0xc7a5, 0xd889, 0xea39, 0xfc5a, 0x0e8f, 0x2077, 0x31b8, 0x41f6, 0x50de, 0x5e23, 0x697f,
0x72b8, 0x799e, 0x7e0d, 0x7fee, 0x7f37, 0x7bed, 0x761f, 0x6ded, 0x6380, 0x570f, 0x48db, 0x392c, 0x2855, 0x16ad, 0x048f, 0xf259,
0xe06b, 0xcf20, 0xbed2, 0xafd7, 0xa27c, 0x9705, 0x8db0, 0x86ab, 0x821c, 0x801a, 0x80b0, 0x83da, 0x8988, 0x919c, 0x9bee, 0xa846,
0xb666, 0xc603, 0xd6ce, 0xe86e, 0xfa88, 0x0cbf, 0x1eb3, 0x3008, 0x4064, 0x4f73, 0x5ce4, 0x6874, 0x71e6, 0x790a, 0x7db9, 0x7fdc,
0x7f68, 0x7c5e, 0x76d0, 0x6ed9, 0x64a3, 0x5863, 0x4a59, 0x3acc, 0x2a0f, 0x1878, 0x0661, 0xf42a, 0xe230, 0xd0d0, 0xc066, 0xb145,
0xa3bd, 0x9813, 0x8e85, 0x8743, 0x8274, 0x8030, 0x8083, 0x836b, 0x88da, 0x90b3, 0x9acd, 0xa6f5, 0xb4ea, 0xc465, 0xd515, 0xe6a3,
0xf8b6, 0x0aee, 0x1ced, 0x2e56, 0x3ecf, 0x4e02, 0x5ba1, 0x6764, 0x710e, 0x786f, 0x7d5e, 0x7fc3, 0x7f91, 0x7cc9, 0x777a, 0x6fc0,
0x65c1, 0x59b3, 0x4bd3, 0x3c6a, 0x2bc7, 0x1a41, 0x0833, 0xf5fb, 0xe3f6, 0xd283, 0xc1fc, 0xb2b7, 0xa503, 0x9926, 0x8f60, 0x87e1,
0x82d2, 0x804c, 0x805d, 0x8303, 0x8833, 0x8fcf, 0x99b2, 0xa5a8, 0xb372, 0xc2c9, 0xd35e, 0xe4da, 0xf6e4, 0x091c, 0x1b26, 0x2ca2,
0x3d37, 0x4c8e, 0x5a58, 0x664e, 0x7031, 0x77cd, 0x7cfd, 0x7fa3, 0x7fb4, 0x7d2e, 0x781f, 0x70a0, 0x66da, 0x5afd, 0x4d49, 0x3e04,
0x2d7d, 0x1c0a, 0x0a05, 0xf7cd, 0xe5bf, 0xd439, 0xc396, 0xb42d, 0xa64d, 0x9a3f, 0x9040, 0x8886, 0x8337, 0x806f, 0x803d, 0x82a2,
0x8791, 0x8ef2, 0x989c, 0xa45f, 0xb1fe, 0xc131, 0xd1aa, 0xe313, 0xf512, 0x074a, 0x195d, 0x2aeb, 0x3b9b, 0x4b16, 0x590b, 0x6533,
0x6f4d, 0x7726, 0x7c95, 0x7f7d, 0x7fd0, 0x7d8c, 0x78bd, 0x717b, 0x67ed, 0x5c43, 0x4ebb, 0x3f9a, 0x2f30, 0x1dd0, 0x0bd6, 0xf99f,
0xe788, 0xd5f1, 0xc534, 0xb5a7, 0xa79d, 0x9b5d, 0x9127, 0x8930, 0x83a2, 0x8098, 0x8024, 0x8247, 0x86f6, 0x8e1a, 0x978c, 0xa31c,
0xb08d, 0xbf9c, 0xcff8, 0xe14d, 0xf341, 0x0578, 0x1792, 0x2932, 0x39fd, 0x499a, 0x57ba, 0x6412, 0x6e64, 0x7678, 0x7c26, 0x7f50,
0x7fe6, 0x7de4, 0x7955, 0x7250, 0x68fb, 0x5d84, 0x5029, 0x412e, 0x30e0, 0x1f95, 0x0da7, 0xfb71, 0xe953, 0xd7ab, 0xc6d4, 0xb725,
0xa8f1, 0x9c80, 0x9213, 0x89e1, 0x8413, 0x80c9, 0x8012, 0x81f3, 0x8662, 0x8d48, 0x9681, 0xa1dd, 0xaf22, 0xbe0a, 0xce48, 0xdf89,
0xf171, 0x03a6, 0x15c7, 0x2777, 0x385b, 0x481a, 0x5664, 0x62ed, 0x6d74, 0x75c4, 0x7bb2, 0x7f1d, 0x7ff5, 0x7e35, 0x79e6, 0x731f,
0x6a03, 0x5ec1, 0x5193, 0x42be, 0x328f, 0x2159, 0x0f77, 0xfd44, 0xeb1f, 0xd967, 0xc877, 0xb8a7, 0xaa49, 0x9da8, 0x9305, 0x8a98,
0x848b, 0x80ff, 0x8006, 0x81a5, 0x85d3, 0x8c7c, 0x957b, 0xa0a3, 0xadba, 0xbc7b, 0xcc9b, 0xddc6, 0xefa2, 0x01d3, 0x13fa, 0x25ba,
0x36b6, 0x4697, 0x5509, 0x61c2, 0x6c80, 0x750b, 0x7b36, 0x7ee3, 0x7ffd, 0x7e7f, 0x7a71, 0x73e8, 0x6b06, 0x5ff8, 0x52f8, 0x444a,
0x343a, 0x231b, 0x1146, 0xff17, 0xecec, 0xdb25, 0xca1d, 0xba2c, 0xaba6, 0x9ed6, 0x93fd, 0x8b55, 0x850a, 0x813d, 0x8001, 0x815e,
0x854b, 0x8bb5, 0x947b, 0x9f6e, 0xac56, 0xbaf1, 0xcaf1, 0xdc05, 0xedd3
};
static short const tsin_16k[16] = {
0x0000, 0x30fd, 0x5a83, 0x7641, 0x7fff, 0x7642, 0x5a82, 0x30fc, 0x0000, 0xcf04, 0xa57d, 0x89be, 0x8000, 0x89be, 0xa57e, 0xcf05,
};
static u16 tx_s_cnt = 0;
static int get_sine_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
{
while (points--) {
if (*s_cnt >= 441) {
*s_cnt = 0;
}
*data++ = tsin_441k[*s_cnt];
if (ch == 2) {
*data++ = tsin_441k[*s_cnt];
}
(*s_cnt)++;
}
return 0;
}
static int get_sine_16k_data(u16 *s_cnt, s16 *data, u16 points, u8 ch)
{
while (points--) {
if (*s_cnt >= 16) {
*s_cnt = 0;
}
*data++ = tsin_16k[*s_cnt];
if (ch == 2) {
*data++ = tsin_16k[*s_cnt];
}
(*s_cnt)++;
}
return 0;
}
extern struct audio_decoder_task decode_task;
void handle_tx(void *priv, void *buf, u16 len)
{
putchar('o');
#if 1
/* get_sine_16k_data(&tx_s_cnt, buf, len / 2 / 2, 2); */
get_sine_data(&tx_s_cnt, buf, len / 2 / 2, 2);
printf("tx len %x %d", buf, len);
/* memset(buf, 0, len); */
alink_set_shn(&p_alink0_parm->ch_cfg[0], len / 4);
#endif
}
extern struct audio_dac_hdl dac_hdl;
void handle_rx(void *priv, void *buf, u16 len)
{
/* putchar('r'); */
#if 1
put_buf(buf, 32);
#else
#endif
alink_set_shn(&p_alink0_parm->ch_cfg[1], len / 4);
}
ALINK_PARM test_alink = {
.module = ALINK0,
.mclk_io = IO_PORTA_12,
.sclk_io = IO_PORTA_13,
.lrclk_io = IO_PORTA_14,
.ch_cfg[0].data_io = IO_PORTA_15,
.ch_cfg[1].data_io = IO_PORTA_11,
/* .mode = ALINK_MD_IIS_LALIGN, */
.mode = ALINK_MD_IIS,
/* .role = ALINK_ROLE_SLAVE, */
.role = ALINK_ROLE_MASTER,
/* .clk_mode = ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, */
.clk_mode = ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE,
.bitwide = ALINK_LEN_16BIT,
/* .bitwide = ALINK_LEN_24BIT, */
.sclk_per_frame = ALINK_FRAME_32SCLK,
/* .dma_len = ALNK_BUF_POINTS_NUM * 2 * 2 , */
.dma_len = 4 * 1024,
/* .sample_rate = 16000, */
.sample_rate = 44100,
/* .sample_rate = TCFG_IIS_SAMPLE_RATE, */
/* .buf_mode = ALINK_BUF_CIRCLE, */
.buf_mode = ALINK_BUF_DUAL,
};
void audio_link_test(void)
{
void *hw_alink = alink_init(&test_alink);
void *alink_ch0 = alink_channel_init(hw_alink, 0, ALINK_DIR_TX, NULL, handle_tx);
/* void *alink_ch1 = alink_channel_init(hw_alink, 1, ALINK_DIR_RX, NULL, handle_rx); */
/* void *alink_ch2 = alink_channel_init(hw_alink, 2, ALINK_DIR_TX, NULL, handle_tx); */
/* void *alink_ch3 = alink_channel_init(hw_alink, 3, ALINK_DIR_RX, NULL, handle_rx); */
clk_set("sys", 96 * 1000000L);
alink_start(hw_alink);
alink0_info_dump();
while (1) {
/* void clr_wdt(void); */
/* clr_wdt(); */
os_time_dly(2);
}
}
#endif

132
cpu/br28/audio_link.h Normal file
View File

@ -0,0 +1,132 @@
#ifndef _AUDIO_LINK_H_
#define _AUDIO_LINK_H_
#define ALNK_BUF_POINTS_NUM 256
#define ALINK_CLK_OUPUT_DISABLE 0xFF
typedef enum {
ALINK0 = 0u, //BR28只有一个ALNK模块
} ALINK_PORT;
//ch_num
typedef enum {
ALINK_CH0 = 0u,
ALINK_CH1,
ALINK_CH2,
ALINK_CH3,
} ALINK_CH;
//ch_dir
typedef enum {
ALINK_DIR_TX = 0u,
ALINK_DIR_RX ,
} ALINK_DIR;
typedef enum {
ALINK_LEN_16BIT = 0u,
ALINK_LEN_24BIT , //ALINK_FRAME_MODE需要选择: ALINK_FRAME_64SCLK
} ALINK_DATA_WIDTH;
//ch_mode
typedef enum {
ALINK_MD_NONE = 0u,
ALINK_MD_IIS ,
ALINK_MD_IIS_LALIGN ,
ALINK_MD_IIS_RALIGN ,
ALINK_MD_DSP0 ,
ALINK_MD_DSP1 ,
} ALINK_MODE;
//ch_mode
typedef enum {
ALINK_ROLE_MASTER, //主机
ALINK_ROLE_SLAVE, //从机
} ALINK_ROLE;
typedef enum {
ALINK_CLK_FALL_UPDATE_RAISE_SAMPLE, //下降沿更新数据, 上升沿采样数据
ALINK_CLK_RAISE_UPDATE_FALL_SAMPLE, //上降沿更新数据, 下升沿采样数据
} ALINK_CLK_MODE;
typedef enum {
ALINK_FRAME_64SCLK, //64 sclk/frame
ALINK_FRAME_32SCLK, //32 sclk/frame
} ALINK_FRAME_MODE;
//SDK默认PLL是192M,仅支持44100,22050,11025采样率,如需其他采样率,需设置PLL为240M,可支持所有采样率
typedef enum {
ALINK_SR_48000 = 48000,
ALINK_SR_44100 = 44100,
ALINK_SR_32000 = 32000,
ALINK_SR_24000 = 24000,
ALINK_SR_22050 = 22050,
ALINK_SR_16000 = 16000,
ALINK_SR_12000 = 12000,
ALINK_SR_11025 = 11025,
ALINK_SR_8000 = 8000,
} ALINK_SR;
typedef enum {
ALINK_BUF_DUAL, //乒乓BUF
ALINK_BUF_CIRCLE, //循环BUF
} ALINK_BUF_MODE;
struct alnk_hw_ch {
ALINK_PORT module;
ALINK_CH ch_idx;
u8 data_io; //data IO配置
ALINK_DIR dir; //通道传输数据方向: Tx, Rx
void *buf; //dma buf地址
void (*isr_cb)(void *priv, void *addr, int len); //中断回调
void *private_data; //音频私有数据
};
//===================================//
//多个通道使用需要注意:
//1.数据位宽需要保持一致
//2.buf长度相同
//===================================//
typedef struct _ALINK_PARM {
ALINK_PORT module;
u8 mclk_io; //mclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
u8 sclk_io; //sclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
u8 lrclk_io; //lrclk IO输出配置: ALINK_CLK_OUPUT_DISABLE不输出该时钟
struct alnk_hw_ch ch_cfg[4]; //通道内部配置
ALINK_MODE mode; //IIS, left, right, dsp0, dsp1
ALINK_ROLE role; //主机/从机
ALINK_CLK_MODE clk_mode; //更新和采样边沿
ALINK_DATA_WIDTH bitwide; //数据位宽16/32bit
ALINK_FRAME_MODE sclk_per_frame; //32/64 sclk/frame
u16 dma_len; //buf长度: byte
u16 iperiod; //输入中断的周期点数
ALINK_SR sample_rate; //采样
ALINK_BUF_MODE buf_mode; //乒乓buf or 循环buf率
} ALINK_PARM;
//iis 模块相关
void *alink_init(void *hw_alink); //iis 初始化
int alink_start(void *hw_alink); //iis 开启
int alink_set_sr(void *hw_alink, u32 sr); //iis 设置采样率
int alink_get_sr(void *hw_alink); //iis 获取采样率
u32 alink_get_dma_len(void *hw_alink); //iis 获取DMA_LEN
void alink_set_rx_pns(void *hw_alink, u32 len); //iis 设置接收PNS
void alink_set_tx_pns(void *hw_alink, u32 len); //iis 设置发送PNS
void alink_uninit(void *hw_alink); //iis 退出
int alink_get_tx_pns(void *hw_alink);
//iis 通道相关
void *alink_channel_init(void *hw_alink, ALINK_CH ch_idx, u8 dir, void *priv, void (*handle)(void *priv, void *addr, int len)); //iis通道初始化返回句柄
void alink_channel_close(void *hw_channel); //iis通道关闭
u32 alink_get_addr(void *hw_channel); //iis获取通道DMA地址
u32 alink_get_shn(void *hw_channel); //iis获取通道SHN
void alink_set_shn(void *hw_channel, u32 len); //iis设置通道SHN
u32 alink_get_swptr(void *hw_channel); //iis获取通道swptr
void alink_set_swptr(void *hw_channel, u32 value); //iis设置通道swptr
u32 alink_get_hwptr(void *hw_channel); //iis获取通道hwptr
void alink_set_hwptr(void *hw_channel, u32 value); //iis设置通道hwptr
void alink_set_ch_ie(void *hw_channel, u32 value); //iis设置通道ie
void alink_clr_ch_pnd(void *hw_channel); //iis清除通道pnd
u32 audio_iis_hw_rates_match(u32 sr);
#endif

108
cpu/br28/audio_sync.c Normal file
View File

@ -0,0 +1,108 @@
#include "board_config.h"
#include "asm/dac.h"
#include "media/includes.h"
//#include "media/audio_dev.h"
#include "effectrs_sync.h"
#include "asm/gpio.h"
#if 0
extern struct audio_dac_hdl dac_hdl;
extern int bt_media_sync_master(u8 type);
extern u8 bt_media_device_online(u8 dev);
extern void *bt_media_sync_open(void);
extern void bt_media_sync_close(void *);
extern int a2dp_media_get_total_buffer_size();
/*extern u32 get_bt_slot_time(u8 type, u32 time, u32 *pre_time);*/
extern int bt_send_audio_sync_data(void *, void *buf, u32 len);
extern void bt_media_sync_set_handler(void *, void *priv,
void (*event_handler)(void *, int *, int));
extern int bt_audio_sync_nettime_select(u8 basetime);
const static struct audio_tws_conn_ops tws_conn_ops = {
.open = bt_media_sync_open,
.set_handler = bt_media_sync_set_handler,
.close = bt_media_sync_close,
/*.time = get_bt_slot_time,*/
.master = bt_media_sync_master,
.online = bt_media_device_online,
.send = bt_send_audio_sync_data,
};
#if (CONFIG_BD_NUM == 2)
#define SYNC_DATA_TOP_PERCENT 70
#define SYNC_DATA_BOTTOM_PERCENT 50
#define SYNC_DATA_BEGIN_PERCENT 60
#elif (TCFG_USER_TWS_ENABLE == 1)
#if TCFG_BT_SUPPORT_AAC
#define SYNC_DATA_TOP_PERCENT 70
#define SYNC_DATA_BOTTOM_PERCENT 50
#define SYNC_DATA_BEGIN_PERCENT 50
#else
#define SYNC_DATA_TOP_PERCENT 80
#define SYNC_DATA_BOTTOM_PERCENT 60
#define SYNC_DATA_BEGIN_PERCENT 60
#endif
#else
#define SYNC_DATA_TOP_PERCENT 80
#define SYNC_DATA_BOTTOM_PERCENT 60
#define SYNC_DATA_BEGIN_PERCENT 70
#endif
#define SYNC_START_TIME 100
void *a2dp_play_sync_open(u8 channel, u32 sample_rate, u32 output_rate, u32 coding_type)
{
struct audio_wireless_sync_info sync_param;
int a2dp_total_size = 0;
if (coding_type == AUDIO_CODING_AAC) {
a2dp_total_size = 15 * 1024;
} else if (coding_type == AUDIO_CODING_SBC) {
a2dp_total_size = a2dp_media_get_total_buffer_size();
}
sync_param.channel = channel;
sync_param.tws_ops = &tws_conn_ops;
sync_param.sample_rate = sample_rate;
sync_param.output_rate = output_rate;
sync_param.data_top = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
sync_param.data_bottom = SYNC_DATA_BOTTOM_PERCENT * a2dp_total_size / 100;
sync_param.begin_size = SYNC_DATA_BEGIN_PERCENT * a2dp_total_size / 100;
sync_param.tws_together_time = SYNC_START_TIME;
sync_param.protocol = WL_PROTOCOL_RTP;
/*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
sync_param.dev = &dac_hdl;
bt_audio_sync_nettime_select(0);
return audio_wireless_sync_open(&sync_param);
}
void *esco_play_sync_open(u8 channel, u16 sample_rate, u16 output_rate)
{
struct audio_wireless_sync_info sync_param;
int esco_buffer_size = 60 * 50;
sync_param.channel = channel;
sync_param.sample_rate = sample_rate;
sync_param.tws_ops = &tws_conn_ops;
sync_param.data_top = 40 * esco_buffer_size / 100;
sync_param.data_bottom = 10 * esco_buffer_size / 100;
sync_param.begin_size = 15 * esco_buffer_size / 100; /*60*50*6/100 = 180(3 packet)*/
sync_param.tws_together_time = SYNC_START_TIME;
/*sync_param.dev_type = AUDIO_OUTPUT_DAC;*/
sync_param.dev = &dac_hdl;
sync_param.protocol = WL_PROTOCOL_SCO;
bt_audio_sync_nettime_select(0);
return audio_wireless_sync_open(&sync_param);
}
#endif

531
cpu/br28/charge.c Normal file
View File

@ -0,0 +1,531 @@
#include "asm/clock.h"
#include "timer.h"
#include "asm/power/p33.h"
#include "asm/charge.h"
#include "asm/adc_api.h"
#include "uart.h"
#include "device/device.h"
#include "asm/power_interface.h"
#include "asm/power/power_wakeup.h"
#include "system/event.h"
#include "asm/efuse.h"
#include "gpio.h"
#include "app_config.h"
#define LOG_TAG_CONST CHARGE
#define LOG_TAG "[CHARGE]"
#define LOG_INFO_ENABLE
#define LOG_DUMP_ENABLE
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#include "debug.h"
typedef struct _CHARGE_VAR {
struct charge_platform_data *data;
volatile u8 charge_online_flag;
volatile u8 charge_event_flag;
volatile u8 init_ok;
volatile u8 detect_stop;
volatile int ldo5v_timer; //检测LDOIN状态变化的usr timer
volatile int charge_timer; //检测充电是否充满的usr timer
volatile int cc_timer; //涓流切恒流的sys timer
} CHARGE_VAR;
#define __this (&charge_var)
static CHARGE_VAR charge_var;
static u8 charge_flag;
#define BIT_LDO5V_IN BIT(0)
#define BIT_LDO5V_OFF BIT(1)
#define BIT_LDO5V_KEEP BIT(2)
u8 get_charge_poweron_en(void)
{
return __this->data->charge_poweron_en;
}
void set_charge_poweron_en(u32 onOff)
{
__this->data->charge_poweron_en = onOff;
}
void charge_check_and_set_pinr(u8 level)
{
u8 pinr_io, reg;
reg = P33_CON_GET(P3_PINR_CON1);
//开启LDO5V_DET长按复位
if ((reg & BIT(0)) && ((reg & BIT(3)) == 0)) {
if (level == 0) {
P33_CON_SET(P3_PINR_CON1, 2, 1, 0);
} else {
P33_CON_SET(P3_PINR_CON1, 2, 1, 1);
}
}
}
extern void udelay(u32 usec);
static u8 check_charge_state(void)
{
u16 i, det_max_time;
#if TCFG_UMIDIGI_BOX_ENABLE
det_max_time = TIMER2CMESSAGE * 16;
#else
det_max_time = 20;
#endif
__this->charge_online_flag = 0;
for (i = 0; i < det_max_time; i++) {
if (LVCMP_DET_GET() || LDO5V_DET_GET()) {
__this->charge_online_flag = 1;
break;
}
udelay(1000);
}
return __this->charge_online_flag;
}
void set_charge_online_flag(u8 flag)
{
__this->charge_online_flag = flag;
}
u8 get_charge_online_flag(void)
{
return __this->charge_online_flag;
}
void set_charge_event_flag(u8 flag)
{
__this->charge_event_flag = flag;
}
u8 get_ldo5v_online_hw(void)
{
return LDO5V_DET_GET();
}
u8 get_lvcmp_det(void)
{
return LVCMP_DET_GET();
}
u8 get_ldo5v_pulldown_en(void)
{
if (!__this->data) {
return 0;
}
if (get_ldo5v_online_hw()) {
if (__this->data->ldo5v_pulldown_keep == 0) {
return 0;
}
}
return __this->data->ldo5v_pulldown_en;
}
u8 get_ldo5v_pulldown_res(void)
{
if (__this->data) {
return __this->data->ldo5v_pulldown_lvl;
}
return CHARGE_PULLDOWN_200K;
}
void charge_event_to_user(u8 event)
{
struct sys_event e;
e.type = SYS_DEVICE_EVENT;
e.arg = (void *)DEVICE_EVENT_FROM_CHARGE;
e.u.dev.event = event;
e.u.dev.value = 0;
sys_event_notify(&e);
}
static void charge_cc_check(void *priv)
{
if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
set_charge_mA(__this->data->charge_mA);
usr_timer_del(__this->cc_timer);
__this->cc_timer = 0;
power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
charge_wakeup_isr();
}
}
void charge_start(void)
{
u8 check_full = 0;
log_info("%s\n", __func__);
#if !TCFG_EXTERN_CHARGE_ENABLE
if (__this->charge_timer) {
usr_timer_del(__this->charge_timer);
__this->charge_timer = 0;
}
//进入恒流充电之后,才开启充满检测
if ((adc_get_voltage(AD_CH_VBAT) * 4 / 10) > CHARGE_CCVOL_V) {
set_charge_mA(__this->data->charge_mA);
power_awakeup_gpio_enable(IO_CHGFL_DET, 1);
check_full = 1;
} else {
//涓流阶段系统不进入低功耗,防止电池电量更新过慢导致涓流切恒流时间过长
set_charge_mA(__this->data->charge_trickle_mA);
if (!__this->cc_timer) {
__this->cc_timer = usr_timer_add(NULL, charge_cc_check, 1000, 1);
}
}
CHARGE_EN(1);
CHGGO_EN(1);
charge_event_to_user(CHARGE_EVENT_CHARGE_START);
//开启充电时,充满标记为1时,主动检测一次是否充满
if (check_full && CHARGE_FULL_FLAG_GET()) {
charge_wakeup_isr();
}
#else
/* 插入检测时使用vpwr 。Full_DET没充满时高阻充满时低。 */
//检测到开始充电仅发送消息给其他app
charge_event_to_user(CHARGE_EVENT_CHARGE_START);
/* 初始化充满检测io */
//设置为上拉输入
gpio_direction_input(TCFG_EXTERN_CHARGE_PORT);
gpio_set_pull_down(TCFG_EXTERN_CHARGE_PORT, 0);
gpio_set_pull_up(TCFG_EXTERN_CHARGE_PORT, 1);
gpio_set_die(TCFG_EXTERN_CHARGE_PORT, 1);
if (0 == gpio_read(TCFG_EXTERN_CHARGE_PORT)) {
log_info("ex_charge has been full\n");
//检测到低电平,已经充满了的情况下触发充电,直接走充满流程
charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
}
power_wakeup_enable_with_port(TCFG_EXTERN_CHARGE_PORT);
//此时还有一个低电检测定时器在跑,如果需要省充电功耗可以直接关机,等到下降沿来了就会会触发开机进行处理流程。
/* power_set_soft_poweroff(); */
#endif
}
void charge_close(void)
{
log_info("%s\n", __func__);
#if !TCFG_EXTERN_CHARGE_ENABLE
CHARGE_EN(0);
CHGGO_EN(0);
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
if (__this->charge_timer) {
usr_timer_del(__this->charge_timer);
__this->charge_timer = 0;
}
if (__this->cc_timer) {
usr_timer_del(__this->cc_timer);
__this->cc_timer = 0;
}
#else
power_wakeup_disable_with_port(TCFG_EXTERN_CHARGE_PORT);
//检测到开始充电仅发送消息给其他app
charge_event_to_user(CHARGE_EVENT_CHARGE_CLOSE);
#endif
}
static void charge_full_detect(void *priv)
{
static u16 charge_full_cnt = 0;
if (CHARGE_FULL_FILTER_GET()) {
/* putchar('F'); */
if (CHARGE_FULL_FLAG_GET() && LVCMP_DET_GET()) {
/* putchar('1'); */
if (charge_full_cnt < 10) {
charge_full_cnt++;
} else {
charge_full_cnt = 0;
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
usr_timer_del(__this->charge_timer);
__this->charge_timer = 0;
charge_event_to_user(CHARGE_EVENT_CHARGE_FULL);
}
} else {
/* putchar('0'); */
charge_full_cnt = 0;
}
} else {
/* putchar('K'); */
charge_full_cnt = 0;
usr_timer_del(__this->charge_timer);
__this->charge_timer = 0;
}
}
static void ldo5v_detect(void *priv)
{
/* log_info("%s\n",__func__); */
static u16 ldo5v_on_cnt = 0;
static u16 ldo5v_keep_cnt = 0;
static u16 ldo5v_off_cnt = 0;
if (__this->detect_stop) {
return;
}
if (LVCMP_DET_GET()) { //ldoin > vbat
/* putchar('X'); */
if (ldo5v_on_cnt < __this->data->ldo5v_on_filter) {
ldo5v_on_cnt++;
} else {
/* printf("ldo5V_IN\n"); */
set_charge_online_flag(1);
ldo5v_off_cnt = 0;
ldo5v_keep_cnt = 0;
//消息线程未准备好接收消息,继续扫描
if (__this->charge_event_flag == 0) {
return;
}
ldo5v_on_cnt = 0;
usr_timer_del(__this->ldo5v_timer);
__this->ldo5v_timer = 0;
if ((charge_flag & BIT_LDO5V_IN) == 0) {
charge_flag = BIT_LDO5V_IN;
charge_event_to_user(CHARGE_EVENT_LDO5V_IN);
}
}
} else if (LDO5V_DET_GET() == 0) { //ldoin<拔出电压0.6
/* putchar('Q'); */
if (ldo5v_off_cnt < (__this->data->ldo5v_off_filter + 20)) {
ldo5v_off_cnt++;
} else {
/* printf("ldo5V_OFF\n"); */
set_charge_online_flag(0);
ldo5v_on_cnt = 0;
ldo5v_keep_cnt = 0;
//消息线程未准备好接收消息,继续扫描
if (__this->charge_event_flag == 0) {
return;
}
ldo5v_off_cnt = 0;
usr_timer_del(__this->ldo5v_timer);
__this->ldo5v_timer = 0;
if ((charge_flag & BIT_LDO5V_OFF) == 0) {
charge_flag = BIT_LDO5V_OFF;
charge_event_to_user(CHARGE_EVENT_LDO5V_OFF);
}
}
} else { //拔出电压0.6左右)< ldoin < vbat
/* putchar('E'); */
if (ldo5v_keep_cnt < __this->data->ldo5v_keep_filter) {
ldo5v_keep_cnt++;
} else {
/* printf("ldo5V_ERR\n"); */
set_charge_online_flag(1);
ldo5v_off_cnt = 0;
ldo5v_on_cnt = 0;
//消息线程未准备好接收消息,继续扫描
if (__this->charge_event_flag == 0) {
return;
}
ldo5v_keep_cnt = 0;
usr_timer_del(__this->ldo5v_timer);
__this->ldo5v_timer = 0;
if ((charge_flag & BIT_LDO5V_KEEP) == 0) {
charge_flag = BIT_LDO5V_KEEP;
if (__this->data->ldo5v_off_filter) {
charge_event_to_user(CHARGE_EVENT_LDO5V_KEEP);
}
}
}
}
}
void ldoin_wakeup_isr(void)
{
if (!__this->init_ok) {
return;
}
/* printf(" %s \n", __func__); */
if (__this->ldo5v_timer == 0) {
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
}
}
void charge_wakeup_isr(void)
{
if (!__this->init_ok) {
return;
}
/* printf(" %s \n", __func__); */
if (__this->charge_timer == 0) {
__this->charge_timer = usr_timer_add(0, charge_full_detect, 2, 1);
}
}
void charge_set_ldo5v_detect_stop(u8 stop)
{
__this->detect_stop = stop;
}
u8 get_charge_mA_config(void)
{
return __this->data->charge_mA;
}
void set_charge_mA(u8 charge_mA)
{
static u8 charge_mA_old = 0xff;
if (charge_mA_old != charge_mA) {
charge_mA_old = charge_mA;
if (charge_mA & BIT(4)) {
CHG_TRICKLE_EN(1);
} else {
CHG_TRICKLE_EN(0);
}
CHARGE_mA_SEL(charge_mA & 0x0F);
}
}
const u16 full_table[CHARGE_FULL_V_MAX] = {
4041, 4061, 4081, 4101, 4119, 4139, 4159, 4179,
4199, 4219, 4238, 4258, 4278, 4298, 4318, 4338,
4237, 4257, 4275, 4295, 4315, 4335, 4354, 4374,
4394, 4414, 4434, 4454, 4474, 4494, 4514, 4534,
};
u16 get_charge_full_value(void)
{
ASSERT(__this->init_ok, "charge not init ok!\n");
ASSERT(__this->data->charge_full_V < CHARGE_FULL_V_MAX);
return full_table[__this->data->charge_full_V];
}
static void charge_config(void)
{
u8 charge_trim_val;
u8 offset = 0;
u8 charge_full_v_val = 0;
//判断是用高压档还是低压档
if (__this->data->charge_full_V < CHARGE_FULL_V_4237) {
CHG_HV_MODE(0);
charge_trim_val = get_vbat_trim();//4.20V对应的trim出来的实际档位
if (charge_trim_val == 0xf) {
log_info("vbat low not trim, use default config!!!!!!");
charge_trim_val = CHARGE_FULL_V_4199;
}
log_info("low charge_trim_val = %d\n", charge_trim_val);
if (__this->data->charge_full_V >= CHARGE_FULL_V_4199) {
offset = __this->data->charge_full_V - CHARGE_FULL_V_4199;
charge_full_v_val = charge_trim_val + offset;
if (charge_full_v_val > 0xf) {
charge_full_v_val = 0xf;
}
} else {
offset = CHARGE_FULL_V_4199 - __this->data->charge_full_V;
if (charge_trim_val >= offset) {
charge_full_v_val = charge_trim_val - offset;
} else {
charge_full_v_val = 0;
}
}
} else {
CHG_HV_MODE(1);
charge_trim_val = get_vbat_trim_435();//4.35V对应的trim出来的实际档位
if (charge_trim_val == 0xf) {
log_info("vbat high not trim, use default config!!!!!!");
charge_trim_val = CHARGE_FULL_V_4354 - 16;
}
log_info("high charge_trim_val = %d\n", charge_trim_val);
if (__this->data->charge_full_V >= CHARGE_FULL_V_4354) {
offset = __this->data->charge_full_V - CHARGE_FULL_V_4354;
charge_full_v_val = charge_trim_val + offset;
if (charge_full_v_val > 0xf) {
charge_full_v_val = 0xf;
}
} else {
offset = CHARGE_FULL_V_4354 - __this->data->charge_full_V;
if (charge_trim_val >= offset) {
charge_full_v_val = charge_trim_val - offset;
} else {
charge_full_v_val = 0;
}
}
}
log_info("charge_full_v_val = %d\n", charge_full_v_val);
CHARGE_FULL_V_SEL(charge_full_v_val);
CHARGE_FULL_mA_SEL(__this->data->charge_full_mA);
set_charge_mA(__this->data->charge_trickle_mA);
}
int charge_init(const struct dev_node *node, void *arg)
{
log_info("%s\n", __func__);
__this->data = (struct charge_platform_data *)arg;
ASSERT(__this->data);
__this->init_ok = 0;
__this->charge_online_flag = 0;
/*先关闭充电使能,后面检测到充电插入再开启*/
power_awakeup_gpio_enable(IO_CHGFL_DET, 0);
CHARGE_EN(0);
CHGGO_EN(0);
/*LDO5V的100K下拉电阻使能*/
L5V_RES_DET_S_SEL(__this->data->ldo5v_pulldown_lvl);
L5V_LOAD_EN(__this->data->ldo5v_pulldown_en);
charge_config();
if (check_charge_state()) {
if (__this->ldo5v_timer == 0) {
__this->ldo5v_timer = usr_timer_add(0, ldo5v_detect, 2, 1);
}
} else {
charge_flag = BIT_LDO5V_OFF;
}
__this->init_ok = 1;
return 0;
}
void charge_module_stop(void)
{
if (!__this->init_ok) {
return;
}
charge_close();
power_awakeup_index_enable(IO_LDOIN_DET, 0);
power_awakeup_index_enable(IO_VBTCH_DET, 0);
if (__this->ldo5v_timer) {
usr_timer_del(__this->ldo5v_timer);
__this->ldo5v_timer = 0;
}
}
void charge_module_restart(void)
{
if (!__this->init_ok) {
return;
}
if (!__this->ldo5v_timer) {
__this->ldo5v_timer = usr_timer_add(NULL, ldo5v_detect, 2, 1);
}
power_awakeup_index_enable(IO_LDOIN_DET, 1);
power_awakeup_index_enable(IO_VBTCH_DET, 1);
}
const struct device_operations charge_dev_ops = {
.init = charge_init,
};

335
cpu/br28/chargestore.c Normal file
View File

@ -0,0 +1,335 @@
#include "generic/typedef.h"
#include "generic/gpio.h"
#include "asm/power/p33.h"
#include "asm/power/p33_app.h"
#include "asm/hwi.h"
#include "asm/gpio.h"
#include "asm/clock.h"
#include "asm/charge.h"
#include "asm/chargestore.h"
#include "update.h"
#include "app_config.h"
#if (TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE)
struct chargestore_handle {
const struct chargestore_platform_data *data;
JL_UART_TypeDef *UART;
u32 baudrate;
};
#define DMA_ISR_LEN 64
#define DMA_BUF_LEN 64
#define __this (&hdl)
static struct chargestore_handle hdl;
u8 uart_dma_buf[DMA_BUF_LEN] __attribute__((aligned(4)));
volatile u8 send_busy;
//串口时钟和串口超时时钟是分开的
#define UART_SRC_CLK clk_get("uart")
#define UART_OT_CLK clk_get("lsb")
enum {
UPGRADE_NULL = 0,
UPGRADE_USB_HARD_KEY,
UPGRADE_USB_SOFTKEY,
UPGRADE_UART_SOFT_KEY,
UPGRADE_UART_ONE_WIRE_HARD_KEY,
};
extern void charge_reset_pb5_pd_status(void);
extern void nvram_set_boot_state(u32 state);
void update_param_boot_ram_set(u8 *buf, u16 len);
void chargestore_set_update_ram(void)
{
//需要补充设置ram
int tmp;
__asm__ volatile("%0 =icfg" : "=r"(tmp));
tmp &= ~(3 << 8);
__asm__ volatile("icfg = %0" :: "r"(tmp));//GIE1
local_irq_disable();
#if TCFG_TEST_BOX_ANY_IO_UPDATE
update_param_boot_ram_set("UART_UPDATE_CUSTOM", sizeof("UART_UPDATE_CUSTOM"));
#else
nvram_set_boot_state(UPGRADE_UART_SOFT_KEY);
#endif
}
void __attribute__((weak)) chargestore_data_deal(u8 cmd, u8 *data, u8 len)
{
}
void __attribute__((weak)) chargestore_uart_data_deal(u8 *data, u8 len)
{
}
static u8 chargestore_get_f95_det_res(u32 equ_res)
{
u8 det_res = (equ_res + 50) / 100;
if (det_res > 0) {
det_res -= 1;
}
if (det_res > 0x0f) {
det_res = 0x0f;
}
return det_res;
}
//br30(PMU数据未知,IC还未给出测试数据,说是和BR23基本一致)
u8 chargestore_get_det_level(u8 chip_type)
{
u32 res = 1600;
switch (chip_type) {
case TYPE_F95:
if (IS_L5V_LOAD_EN()) {
res = (GET_L5V_RES_DET_S_SEL() + 1) * 50;
}
return chargestore_get_f95_det_res(res);
case TYPE_NORMAL:
default:
return 0x0f;
}
}
___interrupt
static void uart_isr(void)
{
u16 i;
u32 rx_len = 0;
if (__this->data->io_port == IO_PORT_DP) {
//测试盒选DP跟USB功能复用
local_irq_disable();
}
if ((__this->UART->CON0 & BIT(2)) && (__this->UART->CON0 & BIT(15))) {
__this->UART->CON0 |= BIT(13);
send_busy = 0;
chargestore_data_deal(CMD_COMPLETE, NULL, 0);
}
if ((__this->UART->CON0 & BIT(3)) && (__this->UART->CON0 & BIT(14))) {
__this->UART->CON0 |= BIT(12);//清RX PND
chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, DMA_ISR_LEN);
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
__this->UART->RXCNT = DMA_ISR_LEN;
}
if ((__this->UART->CON0 & BIT(5)) && (__this->UART->CON0 & BIT(11))) {
//OTCNT PND
__this->UART->CON0 |= BIT(7);//DMA模式
__this->UART->CON0 |= BIT(10);//清OTCNT PND
asm volatile("nop");
rx_len = __this->UART->HRXCNT;//读当前串口接收数据的个数
__this->UART->CON0 |= BIT(12);//清RX PND(这里的顺序不能改变,这里要清一次)
chargestore_data_deal(CMD_RECVDATA, uart_dma_buf, rx_len);
chargestore_uart_data_deal(uart_dma_buf, rx_len);
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
__this->UART->RXCNT = DMA_ISR_LEN;
}
if (__this->data->io_port == IO_PORT_DP) {
//测试盒选DP跟USB功能复用
local_irq_enable();
}
}
void chargestore_write(u8 *data, u8 len)
{
ASSERT(((u32)data) % 4 == 0); //4byte对齐
send_busy = 1;
__this->UART->TXADR = (u32)data;
__this->UART->TXCNT = len;
}
void chargestore_open(u8 mode)
{
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
if (mode == MODE_RECVDATA) {
charge_set_ldo5v_detect_stop(0);
gpio_direction_input(__this->data->io_port);
gpio_set_die(__this->data->io_port, 1);
__this->UART->CON1 &= ~BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART0_RX, LOW_POWER_FREE);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART1_RX, LOW_POWER_FREE);
} else {
gpio_set_fun_input_port(__this->data->io_port, PFI_UART2_RX, LOW_POWER_FREE);
}
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
__this->UART->RXSADR = (u32)uart_dma_buf;
__this->UART->RXEADR = (u32)(uart_dma_buf + DMA_BUF_LEN);
__this->UART->RXCNT = DMA_ISR_LEN;
__this->UART->CON0 |= BIT(6) | BIT(5) | BIT(3);
} else {
charge_set_ldo5v_detect_stop(1);
gpio_direction_output(__this->data->io_port, 1);
gpio_set_hd(__this->data->io_port, 1);
__this->UART->CON1 |= BIT(4);
if (__this->UART == JL_UART0) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART0_TX, 1, 1, LOW_POWER_FREE);
} else if (__this->UART == JL_UART1) {
gpio_set_fun_output_port(__this->data->io_port, FO_UART1_TX, 1, 1, LOW_POWER_FREE);
} else {
gpio_set_fun_output_port(__this->data->io_port, FO_UART2_TX, 1, 1, LOW_POWER_FREE);
}
__this->UART->CON0 |= BIT(2);
}
__this->UART->CON0 |= BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);
}
void chargestore_close(void)
{
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(0);
gpio_set_pull_down(__this->data->io_port, 0);
gpio_set_pull_up(__this->data->io_port, 0);
gpio_set_die(__this->data->io_port, 1);
gpio_set_hd(__this->data->io_port, 0);
gpio_direction_input(__this->data->io_port);
memset((void *)uart_dma_buf, 0, sizeof(uart_dma_buf));
charge_set_ldo5v_detect_stop(0);
}
void chargestore_set_baudrate(u32 baudrate)
{
u32 uart_timeout;
__this->baudrate = baudrate;
uart_timeout = 20 * 1000000 / __this->baudrate;
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
}
#if 0
void chargestore_init(const struct chargestore_platform_data *data)
{
u32 uart_timeout;
__this->data = (struct chargestore_platform_data *)data;
ASSERT(data);
switch (__this->data->uart_irq) {
case IRQ_UART0_IDX:
__this->UART = JL_UART0;
break;
case IRQ_UART1_IDX:
__this->UART = JL_UART1;
break;
default:
ASSERT(0, "uart irq(%d) err!\n", __this->data->uart_irq);
break;
}
if (__this->UART->CON0 & BIT(0)) {
ASSERT(0, "uart used!\n");
}
uart_timeout = 20 * 1000000 / __this->data->baudrate;
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10);
__this->UART->OTCNT = uart_timeout * (clk_get("uart") / 1000000);
__this->UART->BAUD = (clk_get("uart") / __this->data->baudrate) / 4 - 1;
__this->UART->CON1 = (((clk_get("uart") / __this->data->baudrate) % 4) << 4);
gpio_set_pull_down(__this->data->io_port, 0);
gpio_set_pull_up(__this->data->io_port, 0);
gpio_set_die(__this->data->io_port, 1);
gpio_direction_input(__this->data->io_port);
request_irq(__this->data->uart_irq, 2, uart_isr, 0);
JL_IOMAP->CON1 &= ~(0xf << 8);
//约定:
//使用UART0时,使用output channel0 和 input channel 0
//使用UART1时,使用output channel1 和 input channel 1 //由于irflt需要用到INPUT_CH1,所以串口1输入改成INPUT_CH3
if (__this->UART == JL_UART0) {
//不占用IO
JL_IOMAP->CON3 &= ~BIT(3);
//100:input channel0
//101:input channel1
//110:input channel2
//111:input channel3
JL_IOMAP->CON3 &= ~(0b111 << 0);
JL_IOMAP->CON3 |= (0b100 << 0);
//[29:24]:input channel 3 io sel
//[21:16]:input channel 2 io sel
//[13:08]:input channel 1 io sel
//[05:00]:input channel 0 io sel
JL_IOMAP->CON2 &= ~(0b111111 << 0);
JL_IOMAP->CON2 |= (__this->data->io_port << 0);
//000:output channel 0 sel UT0_TX
//001:output channel 0 sel UT1_TX
JL_IOMAP->CON1 &= ~(0b1111 << 8);
JL_IOMAP->CON1 |= (0 << 8);//outchl0 -> ut0_tx
} else {
//不占用IO
JL_IOMAP->CON3 &= ~BIT(7);
//100:input channel0
//101:input channel1
//110:input channel2
//111:input channel3
JL_IOMAP->CON3 &= ~(0b111 << 4);
JL_IOMAP->CON3 |= (0b111 << 4);
//[29:24]:input channel 3 io sel
//[21:16]:input channel 2 io sel
//[13:08]:input channel 1 io sel
//[05:00]:input channel 0 io sel
JL_IOMAP->CON2 &= ~(0b111111 << 24);
JL_IOMAP->CON2 |= (__this->data->io_port << 24);
//000:output channel 1 sel UT0_TX
//001:output channel 1 sel UT1_TX
JL_IOMAP->CON3 &= ~(0b1111 << 20);
JL_IOMAP->CON3 |= (1 << 20);//outchl1 -> ut1_tx
}
}
#endif
#if 1
void chargestore_init(const struct chargestore_platform_data *data)
{
u32 uart_timeout;
__this->data = (struct chargestore_platform_data *)data;
ASSERT(data);
if (!(JL_UART0->CON0 & BIT(0))) {
JL_UART0->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART0_IDX, 2, uart_isr, 0);
__this->UART = JL_UART0;
} else if (!(JL_UART1->CON0 & BIT(0))) {
JL_UART1->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART1_IDX, 2, uart_isr, 0);
__this->UART = JL_UART1;
} else if (!(JL_UART2->CON0 & BIT(0))) {
JL_UART2->CON0 = BIT(13) | BIT(12) | BIT(10);
request_irq(IRQ_UART2_IDX, 2, uart_isr, 0);
__this->UART = JL_UART2;
} else {
ASSERT(0, "uart all used!\n");
}
send_busy = 0;
uart_timeout = 20 * 1000000 / __this->data->baudrate;
__this->UART->CON0 = BIT(13) | BIT(12) | BIT(10) | BIT(1) | BIT(0);//占用该串口,不被其他模块使用
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
__this->UART->BAUD = (UART_SRC_CLK / __this->data->baudrate) / 4 - 1;
__this->baudrate = __this->data->baudrate;
gpio_set_pull_down(__this->data->io_port, 0);
gpio_set_pull_up(__this->data->io_port, 0);
gpio_set_die(__this->data->io_port, 1);
gpio_direction_input(__this->data->io_port);
}
#endif
static void clock_critical_enter(void)
{
u8 cmp_buf[2] = {0x55, 0xAA};
//等待数据收完
extern void *memmem(void *srcmem, int src_len, void *desmem, int des_len);
while (memmem(uart_dma_buf, sizeof(uart_dma_buf), cmp_buf, sizeof(cmp_buf)));
//等待数据发完
while (send_busy);
}
static void clock_critical_exit(void)
{
u32 uart_timeout;
if (__this->UART == NULL) {
return;
}
uart_timeout = 20 * 1000000 / __this->baudrate;
__this->UART->OTCNT = uart_timeout * (UART_OT_CLK / 1000000);
__this->UART->BAUD = (UART_SRC_CLK / __this->baudrate) / 4 - 1;
}
CLOCK_CRITICAL_HANDLE_REG(chargestore, clock_critical_enter, clock_critical_exit)
#endif

118
cpu/br28/clock_cfg.h Normal file
View File

@ -0,0 +1,118 @@
#ifndef CLOCK_CFG_H
#define CLOCK_CFG_H
#include "typedef.h"
/*
*/
enum {
BT_IDLE_CLOCK = 1,
MUSIC_IDLE_CLOCK,
FM_IDLE_CLOCK,
LINEIN_IDLE_CLOCK,
PC_IDLE_CLOCK,
REC_IDLE_CLOCK,
RTC_IDLE_CLOCK,
SPDIF_IDLE_CLOCK,
BOX_IDLE_CLOCK,
DEC_SBC_CLK ,
DEC_AAC_CLK ,
DEC_MSBC_CLK,
DEC_CVSD_CLK,
AEC8K_CLK ,
AEC8K_ADV_CLK,
AEC16K_CLK ,
AEC16K_ADV_CLK,
AEC8K_SPX_CLK,
AEC16K_SPX_CLK,
DEC_TONE_CLK,
DEC_MP3_CLK ,
DEC_WAV_CLK , /// 10
DEC_G729_CLK,
DEC_G726_CLK,
DEC_PCM_CLK ,
DEC_MTY_CLK ,
DEC_WMA_CLK ,
DEC_APE_CLK ,
DEC_FLAC_CLK,
DEC_AMR_CLK ,
DEC_DTS_CLK ,
DEC_M4A_CLK , ///20
DEC_ALAC_CLK,
DEC_FM_CLK ,
DEC_LINE_CLK,
DEC_TWS_SBC_CLK,
SPDIF_CLK ,
ENC_RECODE_CLK,
ENC_SBC_CLK ,
ENC_WAV_CLK ,
ENC_G726_CLK,
ENC_MP3_CLK ,
ENC_TWS_SBC_CLK,
ENC_MSBC_CLK, //////30
ENC_CVSD_CLK,
SYNC_CLK ,
AUTOMUTE_CLK ,
FINDF_CLK ,
FM_INSIDE_CLK,
BT_CONN_CLK ,
EQ_CLK ,
EQ_DRC_CLK ,
EQ_ONLINE_CLK,
REVERB_CLK ,
REVERB_HOWLING_CLK,
REVERB_PITCH_CLK,
DEC_MP3PICK_CLK ,
DEC_WMAPICK_CLK ,
DEC_M4APICK_CLK ,
DEC_MIX_CLK,
DEC_IIS_CLK,
DEC_UI_CLK,
DEC_MIDI_CLK,
DEC_3D_CLK,
DEC_VBASS_CLK,
DEC_LOUDNES_CLK,
DONGLE_ENC_CLK,
LCD_UI_CLK,
SCAN_DISK_CLK,
SPECTRUM_CLK,
LOCALTWS_CLK,
AI_SPEECH_CLK,
SMARTBOX_ACTION_CLK,
ADAPTER_PROCESS_CLK,
ENUM_MAX_CLK = 63 ,
};
void clock_pause_play(u8 mode);
void clock_idle(u32 type);
void clock_add(u32 type);
void clock_remove(u32 type);
void clock_set_cur(void);
void clock_add_set(u32 type);
void clock_remove_set(u32 type);
#endif

411
cpu/br28/clock_manager.c Normal file
View File

@ -0,0 +1,411 @@
#include "system/includes.h"
#include "app_config.h"
#include "clock_cfg.h"
#include "asm/dac.h"
struct clock_type {
u8 type;
u32 clock;
const char *name;
};
/*****
idle clk : 模式里面的空闲时钟
时钟通过idle clk 加上每一种解码或者运算的时钟
累加总和来设置需要的时钟
模式空闲时钟设置
void clock_idle(u32 type)
把时钟设置加入到ext中但是不是立刻设置时钟
需要最后调用clock_set_cur来最后设置时钟
用于连续地方设置时钟
用完后必须把时钟remove
void clock_add(u32 type)
void clock_remove(u32 type)
void clock_set_cur(void)
把时钟设置加入到ext中立刻设置时钟
需要立刻添加时钟
用完后必须把时钟remove
void clock_add_set(u32 type)
void clock_remove_set(u32 type)
*****/
//// 如果clock_fix 为0 就按照配置设置时钟,如果有值就固定频率
#if TCFG_MIC_EFFECT_ENABLE
#define CLOCK_FIX (192)
#else
#define CLOCK_FIX 0
#endif
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) && TCFG_EQ_DIVIDE_ENABLE
#define EQ4_CLK (24)
#else
#define EQ4_CLK (0)
#endif
#if TCFG_EQ_ONLINE_ENABLE
#define EQ_ONLINE_CLK (64)
#else
#define EQ_ONLINE_CLK (0)
#endif
#define MIX_SRC_CLK (24)//src
const struct clock_type clock_enum[] = {
{ BT_IDLE_CLOCK , (24), " BT_IDLE_CLOCK " },
#ifndef CONFIG_SOUNDBOX_FLASH_256K
{ MUSIC_IDLE_CLOCK , (24), " MUSIC_IDLE_CLOCK " },
{ FM_IDLE_CLOCK , (12), " FM_IDLE_CLOCK " },
{ LINEIN_IDLE_CLOCK , (96), " LINEIN_IDLE_CLOCK " },
{ PC_IDLE_CLOCK , (120), " PC_IDLE_CLOCK " },
{ REC_IDLE_CLOCK , (12), " REC_IDLE_CLOCK " },
{ RTC_IDLE_CLOCK , (12), " RTC_IDLE_CLOCK " },
{ SPDIF_IDLE_CLOCK , (12), " SPDIF_IDLE_CLOCK " },
{ BOX_IDLE_CLOCK , (24), " BOX_IDLE_CLOCK " },
{ DEC_SBC_CLK , (32), "DEC_SBC_CLK " },
{ DEC_AAC_CLK , (32), "DEC_AAC_CLK " },
#endif
{ DEC_MSBC_CLK , (12), "DEC_MSBC_CLK " },
{ DEC_CVSD_CLK , (8), "DEC_CVSD_CLK " },
{ AEC8K_CLK , (10), "AEC8K_CLK " },
{ AEC8K_ADV_CLK , (50), "AEC8K_ADV_CLK " },
{ AEC16K_CLK , (10), "AEC16K_CLK " },
{ AEC16K_ADV_CLK, (50), "AEC16K_ADV_CLK " },
{ AEC8K_SPX_CLK , (10), "AEC8K_SPX_CLK " },
{ AEC16K_SPX_CLK, (10), "AEC16K_SPX_CLK " },
{ DEC_TONE_CLK , (24 + 32), "DEC_TONE_CLK " },
{ DEC_G729_CLK , (24), "DEC_G729_CLK " },
{ DEC_PCM_CLK , (24), "DEC_PCM_CLK " },
#ifndef CONFIG_SOUNDBOX_FLASH_256K
{ DEC_MP3_CLK , (80), "DEC_MP3_CLK " },
{ DEC_WAV_CLK , (32), "DEC_WAV_CLK " },
{ DEC_G726_CLK , (24), "DEC_G726_CLK " },
{ DEC_MTY_CLK , (24), "DEC_MTY_CLK " },
{ DEC_WMA_CLK , (48), "DEC_WMA_CLK " },
{ DEC_APE_CLK , (160), "DEC_APE_CLK "},
{ DEC_FLAC_CLK , (96), "DEC_FLAC_CLK "},
{ DEC_AMR_CLK , (96), "DEC_AMR_CLK "},
{ DEC_DTS_CLK , (120), "DEC_DTS_CLK " },
{ DEC_M4A_CLK , (48), "DEC_M4A_CLK "},
{ DEC_ALAC_CLK , (48), "DEC_ALAC_CLK "},
{ DEC_FM_CLK , (12), "DEC_FM_CLK " },
{ DEC_LINE_CLK , (24), "DEC_LINE_CLK " },
{ DEC_TWS_SBC_CLK, (32), "DEC_TWS_SBC_CLK" },
{ SPDIF_CLK , (120), "SPDIF_CLK " },
{ ENC_RECODE_CLK, (64), "ENC_RECODE_CLK " },
{ ENC_SBC_CLK , (64), "ENC_SBC_CLK " },
{ ENC_WAV_CLK , (96), "ENC_WAV_CLK " },
{ ENC_G726_CLK, (64), "ENC_G726_CLK " },
{ ENC_MP3_CLK , (120), "ENC_MP3_CLK " },
{ ENC_TWS_SBC_CLK, (48), "ENC_TWS_SBC_CLK" },
#endif
{ ENC_MSBC_CLK , (12), "ENC_MSBC_CLK " },
{ ENC_CVSD_CLK , (8), "ENC_CVSD_CLK " },
{ SYNC_CLK , (4), "SYNC_CLK " },
{ AUTOMUTE_CLK , (16), "AUTOMUTE_CLK" },
#ifndef CONFIG_SOUNDBOX_FLASH_256K
{ FINDF_CLK , (120), "FINDF_CLK " },
{ FM_INSIDE_CLK , (96), "FM_INSIDE_CLK " },
#endif
#if TCFG_DEC2TWS_ENABLE
{ BT_CONN_CLK , (48), "BT_CONN_CLK " },
#else
{ BT_CONN_CLK , (16), "BT_CONN_CLK " },
#endif
{ EQ_CLK , (24 + EQ_ONLINE_CLK + EQ4_CLK), " EQ_CLK " },
{ EQ_DRC_CLK , (60), " EQ_DRC_CLK " },
/* { EQ_ONLINE_CLK, (120), " EQ_ONLINE_CLK " }, */
#ifndef CONFIG_SOUNDBOX_FLASH_256K
{ REVERB_CLK , (64), " REVERB_CLK " },
{ REVERB_HOWLING_CLK , (32), " REVERB_HOWLING_CLK " },
{ REVERB_PITCH_CLK , (24), " REVERB_PITCH_CLK " },
{ DEC_MP3PICK_CLK, (8), "DEC_MP3PICK_CLK" },
{ DEC_WMAPICK_CLK, (8), "DEC_WMAICK_CLK" },
{ DEC_M4APICK_CLK, (8), "DEC_M4AICK_CLK" },
#endif
{ DEC_MIX_CLK, (6 + MIX_SRC_CLK), "DEC_MIX_CLK" },
{ DEC_UI_CLK, (160), "DEC_UI_CLK" },
#ifndef CONFIG_SOUNDBOX_FLASH_256K
{ DEC_IIS_CLK, (64), "DEC_IIS_CLK" },
//midi音色文件跳转读取频繁外挂flash baud 调到6000000L, midi_clk 80M就够
{ DEC_MIDI_CLK, (110), "DEC_MIDI_CLK" },
/* { DEC_MIDI_CLK, (80), "DEC_MIDI_CLK" }, */
{ DEC_3D_CLK, (24), "DEC_3D_CLK" },
{ DEC_VBASS_CLK, (8), "DEC_VBASS_CLK" },
{ DEC_LOUDNES_CLK, (108), "DEC_LOUDNES_CLK"},
{ DONGLE_ENC_CLK, (48), "DONGLE_ENC_CLK" },
#endif
{ SCAN_DISK_CLK, (120), "SCAN_DISK_CLK" },//提高扫盘速度
#if TCFG_DEC2TWS_ENABLE
{ LOCALTWS_CLK, (24), "LOCALTWS_CLK" },
#endif
{SPECTRUM_CLK, (5), "SPECTRUM_CLK" },
{AI_SPEECH_CLK, (120), "AI_SPEECH_CLK" },
{SMARTBOX_ACTION_CLK, (160), "SMARTBOX_ACTION_CLK" },
#ifdef CONFIG_ADAPTER_ENABLE
{ADAPTER_PROCESS_CLK, (64), "ADAPTER_PROCESS_CLK" },
#endif
};
#if (defined(TCFG_CLOCK_PLL_240MHZ) && TCFG_CLOCK_PLL_240MHZ)
static int hsb_clock_init(void)
{
clock_set_pll_target_frequency(240);
return 0;
}
platform_initcall(hsb_clock_init);
const u8 clock_tb[] = {
24,
32,
48,
80,
96,
120,
160,
};
#else /* #if TCFG_CLOCK_PLL_240MHZ */
const u8 clock_tb[] = {
24,
32,
48,
64,
96,
128,
160,
};
#endif /* #if TCFG_CLOCK_PLL_240MHZ */
static u8 ext_clk_tb[10];
static u32 idle_type = 0;
static void clock_ext_dump()
{
u8 i, j;
for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
if (idle_type == clock_enum[i].type) {
y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name);
break;
}
}
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
if (ext_clk_tb[i]) {
for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
if (ext_clk_tb[i] == clock_enum[j].type) {
y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name);
continue;
}
}
}
}
}
u8 clock_idle_selet(u32 type)
{
u8 i;
#if (CLOCK_FIX )
return CLOCK_FIX;
#endif
for (i = 0; i < ARRAY_SIZE(clock_enum); i++) {
if (type == clock_enum[i].type) {
/* y_printf("--- %d %s \n", clock_enum[i].clock, clock_enum[i].name); */
return clock_enum[i].clock;
}
}
return 24;
}
u8 clock_ext_push(u8 ext_type)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
if (ext_type == ext_clk_tb[i]) {
return 0;
}
}
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
if (!ext_clk_tb[i]) {
ext_clk_tb[i] = ext_type;
return 1;
}
}
y_printf("clock ext over!!! \n");
return 0;
}
u8 clock_ext_pop(u8 ext_type)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
if (ext_type == ext_clk_tb[i]) {
ext_clk_tb[i] = 0;
return 1;
}
}
return 0;
}
u16 clock_match(u16 clk)
{
u8 i;
for (i = 0; i < ARRAY_SIZE(clock_tb); i++) {
if (clk <= clock_tb[i]) {
return clock_tb[i];
}
}
y_printf("clock overlimit!!! %d\n", clock_tb[ARRAY_SIZE(clock_tb) - 1]);
return clock_tb[ARRAY_SIZE(clock_tb) - 1];
}
u16 clock_ext_cal()
{
u32 ext_clk = 0 ;
u8 i, j;
for (i = 0; i < ARRAY_SIZE(ext_clk_tb); i++) {
if (ext_clk_tb[i]) {
for (j = 0; j < ARRAY_SIZE(clock_enum); j++) {
if (ext_clk_tb[i] == clock_enum[j].type) {
/* y_printf("--- %d %s \n", clock_enum[j].clock, clock_enum[j].name); */
ext_clk += clock_enum[j].clock;
continue;
}
}
}
}
return ext_clk;
}
u32 clock_cur_cal()
{
u32 idle_clk, cur_clk, ext_clk;
#if (CLOCK_FIX )
return CLOCK_FIX;
#endif
local_irq_disable();
idle_clk = clock_idle_selet(idle_type);
ext_clk = clock_ext_cal();
cur_clk = idle_clk + ext_clk;
cur_clk = clock_match(cur_clk);
local_irq_enable();
return cur_clk ;
}
void clock_pause_play(u8 mode)
{
u32 idle_clk, cur_clk ;
if (mode) {
idle_clk = clock_idle_selet(idle_type);
clk_set("sys", idle_clk * 1000000L);
} else {
clock_ext_dump();
cur_clk = clock_cur_cal();
clk_set("sys", cur_clk * 1000000L);
}
}
void clock_idle(u32 type)
{
u32 cur_clk;
local_irq_disable();
idle_type = type;
cur_clk = clock_cur_cal();
local_irq_enable();
clock_ext_dump();
clk_set("sys", cur_clk * 1000000L);
}
//////把时钟设置加入到ext中但是不是立刻设置时钟
void clock_add(u32 type)
{
u32 cur_clk ;
u8 resoult = clock_ext_push(type);
if (!resoult) {
return;
}
}
void clock_remove(u32 type)
{
u32 cur_clk ;
u8 resoult = clock_ext_pop(type);
if (!resoult) {
return;
}
}
void clock_set_cur(void)
{
u32 cur_clk ;
clock_ext_dump();
cur_clk = clock_cur_cal();
clk_set("sys", cur_clk * 1000000L);
}
//////把时钟设置加入到ext中立刻设置时钟
void clock_add_set(u32 type)
{
u32 cur_clk ;
u8 resoult = clock_ext_push(type);
if (!resoult) {
return;
}
clock_ext_dump();
cur_clk = clock_cur_cal();
clk_set("sys", cur_clk * 1000000L);
}
void clock_remove_set(u32 type)
{
u32 cur_clk ;
u8 resoult = clock_ext_pop(type);
if (!resoult) {
return;
}
clock_ext_dump();
cur_clk = clock_cur_cal();
clk_set("sys", cur_clk * 1000000L);
}

697
cpu/br28/eq_config.c Normal file
View File

@ -0,0 +1,697 @@
#include "system/includes.h"
#include "media/includes.h"
#include "app_config.h"
#include "app_online_cfg.h"
#include "online_db/online_db_deal.h"
#include "config/config_interface.h"
#include "application/eq_config.h"
#include "audio_config.h"
#include "cfg_tool.h"
#ifdef CONFIG_EQ_APP_SEG_ENABLE
#pragma const_seg( ".eq_app_codec_const")
#pragma code_seg ( ".eq_app_codec_code" )
#endif
const u8 audio_eq_sdk_name[16] = "AC701N";
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
const u8 audio_eq_ver[4] = {0, 8, 4, 0};//包含虚拟低音、多带drc、以及辅听耳机音效
#else
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
const u8 audio_eq_ver[4] = {0, 8, 3, 0};
#else
const u8 audio_eq_ver[4] = {0, 8, 0, 0};
#endif
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
#if TCFG_EQ_FILE_SWITCH_EN
const u8 *eq_file_switch_list[] = {
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw.bin",
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw1.bin",
(u8 *)SDFILE_RES_ROOT_PATH"eq_cfg_hw2.bin",
};
#endif
//eq_cfg_hw.bin中播歌eq曲线当作用户自定义模式参与效果切换.
//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
//EQ_FILE_CP_TO_CUSTOM 1使能时同时板极文件中 TCFG_USE_EQ_FILE 配 0
#define EQ_FILE_CP_TO_CUSTOM 0
/*************************非用户配置区*************************/
#if TCFG_EQ_ONLINE_ENABLE
#undef EQ_FILE_CP_TO_CUSTOM
#define EQ_FILE_CP_TO_CUSTOM 0
#endif
#ifndef TCFG_USER_EQ_MODE_NUM
#define TCFG_USER_EQ_MODE_NUM 0
#endif
#ifndef APP_ONLINE_DEBUG
#define APP_ONLINE_DEBUG 0
#endif
#ifndef TCFG_CALL_DL_EQ_SECTION
#define TCFG_CALL_DL_EQ_SECTION 3
#endif
#ifndef TCFG_CALL_UL_EQ_SECTION
#define TCFG_CALL_UL_EQ_SECTION 3
#endif
/*************************************************************/
#if (TCFG_EQ_ENABLE != 0)
#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
#define AUDIO_EQ_Q 1.5f
#else
#define AUDIO_EQ_Q 0.7f
#endif
#if !TCFG_USE_EQ_FILE
const struct eq_seg_info eq_tab_normal[] = {
#if TCFG_USER_EQ_MODE_NUM > 0
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const struct eq_seg_info eq_tab_rock[] = {
#if TCFG_USER_EQ_MODE_NUM > 1
{0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 2, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, -2, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, -2, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const struct eq_seg_info eq_tab_pop[] = {
#if TCFG_USER_EQ_MODE_NUM > 2
{0, EQ_IIR_TYPE_BAND_PASS, 31, 3, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 1, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, -2, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, -4, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, -4, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, -2, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 1, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const struct eq_seg_info eq_tab_classic[] = {
#if TCFG_USER_EQ_MODE_NUM > 3
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 8, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 8, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 2, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 2, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const struct eq_seg_info eq_tab_country[] = {
#if TCFG_USER_EQ_MODE_NUM > 5
{0, EQ_IIR_TYPE_BAND_PASS, 31, -2, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 2, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 2, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 4, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const struct eq_seg_info eq_tab_jazz[] = {
#if TCFG_USER_EQ_MODE_NUM > 4
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 4, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 4, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 4, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 2, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 3, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 4, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
struct eq_seg_info eq_tab_custom[] = {
#if TCFG_USER_EQ_MODE_NUM > 6
{0, EQ_IIR_TYPE_BAND_PASS, 31, 0, AUDIO_EQ_Q},
{1, EQ_IIR_TYPE_BAND_PASS, 62, 0, AUDIO_EQ_Q},
{2, EQ_IIR_TYPE_BAND_PASS, 125, 0, AUDIO_EQ_Q},
{3, EQ_IIR_TYPE_BAND_PASS, 250, 0, AUDIO_EQ_Q},
{4, EQ_IIR_TYPE_BAND_PASS, 500, 0, AUDIO_EQ_Q},
{5, EQ_IIR_TYPE_BAND_PASS, 1000, 0, AUDIO_EQ_Q},
{6, EQ_IIR_TYPE_BAND_PASS, 2000, 0, AUDIO_EQ_Q},
{7, EQ_IIR_TYPE_BAND_PASS, 4000, 0, AUDIO_EQ_Q},
{8, EQ_IIR_TYPE_BAND_PASS, 8000, 0, AUDIO_EQ_Q},
{9, EQ_IIR_TYPE_BAND_PASS, 16000, 0, AUDIO_EQ_Q},
#if (EQ_SECTION_MAX > 10)
//10段之后频率值设置96k,目的是让10段之后的eq走直通
{10, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{11, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{12, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{13, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{14, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{15, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{16, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{17, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{18, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
{19, EQ_IIR_TYPE_BAND_PASS, 96000, 0, AUDIO_EQ_Q},
#endif
#endif
};
const EQ_CFG_SEG *eq_type_tab[EQ_MODE_MAX] = {
eq_tab_normal, eq_tab_rock, eq_tab_pop, eq_tab_classic, eq_tab_jazz, eq_tab_country, eq_tab_custom
};
// 默认系数表,每个表对应的总增益,用户可修改
float type_gain_tab[EQ_MODE_MAX] = {0, 0, 0, 0, 0, 0, 0};
#endif
__attribute__((weak)) u32 get_eq_mode_tab(void)
{
#if !TCFG_USE_EQ_FILE
return (u32)eq_type_tab;
#else
return 0;
#endif
}
__attribute__((weak)) u8 get_eq_mode_max(void)
{
return EQ_MODE_MAX;
}
#if (EQ_SECTION_MAX==9)
static const u8 eq_mode_use_idx[] = {
0, 1, 2, 3, 4, 5, /*6,*/ 7, 8, 9
};
#elif (EQ_SECTION_MAX==8)
static const u8 eq_mode_use_idx[] = {
0, /*1,*/ 2, 3, 4, 5, 6, 7, /*8,*/ 9
};
#elif (EQ_SECTION_MAX==7)
static const u8 eq_mode_use_idx[] = {
0, /*1,*/ 2, 3, 4, 5, /*6,*/ 7, /*8,*/ 9
};
#elif (EQ_SECTION_MAX==6)
static const u8 eq_mode_use_idx[] = {
0, /*1,*/ 2, 3, 4, /*5,*/ /*6,*/ 7, /*8,*/ 9
};
#elif (EQ_SECTION_MAX==5)
static const u8 eq_mode_use_idx[] = {
/*0,*/ 1, /*2,*/ 3, /*4,*/ 5, /*6,*/ 7, /*8,*/ 9
};
#else
static const u8 eq_mode_use_idx[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
};
#endif
/*
*通话下行eq系数表
* */
#if TCFG_EQ_ENABLE && TCFG_PHONE_EQ_ENABLE
#if EQ_FILE_CP_TO_CUSTOM
struct eq_seg_info phone_eq_tab_normal[] = {
#else
const struct eq_seg_info phone_eq_tab_normal[] = {
#endif
{0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
{1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
{2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
#if TCFG_CALL_DL_EQ_SECTION > 3
{3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
#endif
};
#endif
/*
*通话上行eq系数表
* */
#if EQ_FILE_CP_TO_CUSTOM
struct eq_seg_info ul_eq_tab_normal[] = {
#else
const struct eq_seg_info ul_eq_tab_normal[] = {
#endif
{0, EQ_IIR_TYPE_HIGH_PASS, 200, 0, 0.7f},
{1, EQ_IIR_TYPE_BAND_PASS, 300, 0, 0.7f},
{2, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
#if TCFG_CALL_UL_EQ_SECTION > 3
{3, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{4, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{5, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{6, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{7, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{8, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
{9, EQ_IIR_TYPE_BAND_PASS, 400, 0, 0.7f},
#endif
};
#define SONG_SECTION EQ_SECTION_MAX
#define CALL_SECTION TCFG_CALL_DL_EQ_SECTION//下行段数,小于等于SONG_SECTION
#define UL_SECTION TCFG_CALL_UL_EQ_SECTION//上行段数,小于等于SONG_SECTION
/*
*下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
*表的每一项顺序不可修改
* */
eq_tool_cfg eq_tool_tab[] = {
{call_eq_mode, (u8 *)"通话宽频下行EQ", 0x3001, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
{call_narrow_eq_mode, (u8 *)"通话窄频下行EQ", 0x3002, CALL_SECTION, 1, {EQ_ONLINE_CMD_CALL_EQ_V1_SEG, 0}},
{aec_eq_mode, (u8 *)"通话宽频上行EQ", 0x3003, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
{aec_narrow_eq_mode, (u8 *)"通话窄频上行EQ", 0x3004, UL_SECTION, 1, {EQ_ONLINE_CMD_AEC_EQ_V1_SEG, 0}},
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
{song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, {EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_MULTI_WDRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},//多带wdrc
{hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
{hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
#else
{song_eq_mode, (u8 *)"普通音频EQ", 0x3000, SONG_SECTION, 3, { EQ_ONLINE_CMD_SONG_EQ_V1_SEG, EQ_ONLINE_CMD_SONG_DRC, EQ_ONLINE_CMD_VIRTUAL_BASS}},
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
{hearing_aid_mode, (u8 *)"辅听EQ", 0x3005, SONG_SECTION, 2, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG, EQ_ONLINE_CMD_SONG_WDRC}},
{hearing_aid_mode2, (u8 *)"辅听EQ2", 0x3006, SONG_SECTION, 1, {EQ_ONLINE_CMD_HEARING_AID_EQ_SEG2}},
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
#endif
};
/*----------------------------------------------------------------------------*/
/**@brief eq 段数更新,需要在eq_init前就准备好
@param mode:call_eq_mode\call_narrow_eq_section等模式
@param section:段数最大为EQ_SECTION_MAX
@return
@note 下行的宽频和窄频段数需一致,上行的宽频和窄频段数需要一致
*/
/*----------------------------------------------------------------------------*/
void set_eq_tool_tab_section(u8 mode, u8 section)
{
for (int i = 0; i < ARRAY_SIZE(eq_tool_tab); i++) {
if (mode == eq_tool_tab[i].mode_index) {
eq_tool_tab[i].section = section;
}
}
}
void eq_section_num_set(u8 song, u8 call_16k_8k, u8 aec_16k_8k)
{
set_eq_tool_tab_section(song_eq_mode, song);
set_eq_tool_tab_section(call_eq_mode, call_16k_8k);
set_eq_tool_tab_section(call_narrow_eq_mode, call_16k_8k);
set_eq_tool_tab_section(aec_eq_mode, aec_16k_8k);
set_eq_tool_tab_section(aec_narrow_eq_mode, aec_16k_8k);
}
void drc_default_init(EQ_CFG *eq_cfg, u8 mode)
{
#if TCFG_DRC_ENABLE
int i = mode;
if (eq_cfg && eq_cfg->drc) {
//限幅器的初始值
int th = 0;//db -60db~0db
int threshold = roundf(powf(10.0f, th / 20.0f) * 32768); // 0db:32768, -60db:33
eq_cfg->cfg_parm[i].drc_parm.parm.drc.nband = 1;
eq_cfg->cfg_parm[i].drc_parm.parm.drc.type = 1;
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].attacktime = 5;
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].releasetime = 500;
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[0] = threshold;
eq_cfg->cfg_parm[i].drc_parm.parm.drc._p.limiter[0].threshold[1] = 32768;
}
#endif
}
#if EQ_FILE_CP_TO_CUSTOM
//eq_cfg_hw.bin中播歌eq曲线当作用户自定义模式参与效果切换.
//通话宽频上下行eq曲线也对应放到phone_eq_tab_normal、ul_eq_tab_normal
//EQ_FILE_CP_TO_CUSTOM 1使能时同时板极文件中 TCFG_USE_EQ_FILE 配 0
static void eq_file_cp_to_custon_mode_fun(EQ_CFG *eq_cfg)
{
if (eq_cfg->eq_type == EQ_TYPE_FILE) {
eq_cfg->eq_type = EQ_TYPE_MODE_TAB;
for (int i = 0; i < eq_cfg->mode_num; i++) {
if ((i == song_eq_mode) || (i == call_eq_mode) || (i == aec_eq_mode)) { //播歌eq 通话宽频上下行eq
u32 seg_num = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.seg_num;
u8 index = 0;
for (int j = 0; j < ARRAY_SIZE(eq_tool_tab); j++) {
if (i == eq_tool_tab[j].mode_index) {
index = j;
}
}
if (seg_num > eq_tool_tab[index].section) {
seg_num = eq_tool_tab[index].section;
}
void *tar = NULL;
if (i == call_eq_mode) {
#if TCFG_PHONE_EQ_ENABLE
tar = eq_cfg->phone_eq_tab;
#endif
} else if (i == aec_eq_mode) {
tar = eq_cfg->ul_eq_tab;
} else if (i == song_eq_mode) {
tar = eq_tab_custom;
eq_cfg->type_gain_tab[EQ_MODE_MAX - 1] = eq_cfg->cfg_parm[i].song_eq_parm.parm.par.global_gain;
}
if (tar) {
memcpy(tar, eq_cfg->cfg_parm[i].song_eq_parm.parm.seg, seg_num * sizeof(EQ_CFG_SEG));
eq_cfg->seg_num[i] = seg_num;
}
}
}
}
}
#endif
__attribute__((weak))
s16 get_ci_tx_size()
{
return 0x30;
}
/*----------------------------------------------------------------------------*/
static u8 reply_to_tool = 0;
static u8 reply_sq = 0;
/*
*新调音回调
* */
static void eq_online_callback_new_protocol(uint8_t *packet, uint16_t size)
{
u8 *ptr = packet;
reply_sq = ptr[1];
reply_to_tool = 0;
u8 *new_packet = (void *)&packet[2];
eq_online_callback(new_packet, size);
}
//新调音注册
REGISTER_DETECT_TARGET(eq_adj_target) = {
.id = EQ_CONFIG_ID,
.tool_message_deal = eq_online_callback_new_protocol,
};
/*
/*----------------------------------------------------------------------------*/
int ci_send_cmd(void *priv, u32 id, u8 *packet, int size)
{
EQ_CFG *eq_cfg = (EQ_CFG *)priv;
if (!eq_cfg) {
return 0;
}
#if TCFG_ONLINE_ENABLE
#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
all_assemble_package_send_to_pc(reply_to_tool, reply_sq, packet, size);
#else
ci_send_packet(id, packet, size);
#endif
#endif
return 0;
}
struct virtual_bass_tool_set vbass_default_param = {
.prev_gain = -3, //dB预处理降低数据增益防止虚拟低音把数据调爆
.parm = {
.ratio = 10, //比率(0~100),越大,低音强度越大
.boost = 1, //(低音自动增强0, 1)
.fc = 100, //截止频率(30~300Hz)
},
};
struct virtual_bass_tool_set *get_vbass_parm()
{
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
if (!eq_cfg) {
return NULL;
}
#if defined(TCFG_EFFECT_TOOL_ENABLE) && TCFG_EFFECT_TOOL_ENABLE
return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
#else
if (eq_cfg->vbass_file) {
return &eq_cfg->cfg_parm[song_eq_mode].vbass_parm.parm;
} else {
return &vbass_default_param;
}
#endif
}
int eq_init(void)
{
eq_adjust_parm parm = {0};
#if TCFG_EQ_ONLINE_ENABLE
parm.online_en = 1;
#endif
if (config_filter_coeff_fade_en) {
parm.fade_en = 1;
}
#if TCFG_USE_EQ_FILE
parm.file_en = 1;
#endif
#if EQ_FILE_CP_TO_CUSTOM
parm.file_en = 1;
parm.type_gain_tab = type_gain_tab;
#endif
#if TCFG_DRC_ENABLE
parm.drc = 1;
#endif
#if TCFG_USER_TWS_ENABLE
parm.tws = 1;
#endif
#if (RCSP_ADV_EN)&&(JL_EARPHONE_APP_EN)&&(TCFG_DRC_ENABLE == 0)
/* parm.limit_zero = 1; */
#endif
/* #if TCFG_EQ_DIVIDE_ENABLE */
/* parm.stero = 1; */
/* parm.mode_num = 8; */
/* #endif */
if (!parm.stero) {
#if defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
parm.mode_num = 7;//一共有多少个模式
#else
#if defined(TCFG_AUDIO_HEARING_AID_ENABLE) && TCFG_AUDIO_HEARING_AID_ENABLE
parm.mode_num = 7;// 一共有多少个模式
#else
parm.mode_num = 5;// 一共有多少个模式
#endif
#endif /*TCFG_AUDIO_HEARING_AID_ENABLE*/
/* #ifdef DAC_OUTPUT_FRONT_LR_REAR_LR */
/* #if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_FRONT_LR_REAR_LR) */
/* parm.mode_num = 6; */
/* #endif */
/* #endif */
}
#if TCFG_PHONE_EQ_ENABLE
parm.phone_eq_tab = (void *)phone_eq_tab_normal;
parm.phone_eq_tab_size = TCFG_CALL_DL_EQ_SECTION;//ARRAY_SIZE(phone_eq_tab_normal);
#endif
#if TCFG_AEC_UL_EQ_ENABLE
parm.ul_eq_tab = (void *)ul_eq_tab_normal;
parm.ul_eq_tab_size = TCFG_CALL_UL_EQ_SECTION;//ARRAY_SIZE(ul_eq_tab_normal);
#endif
parm.eq_tool_tab = eq_tool_tab;
parm.eq_mode_use_idx = (u8 *)eq_mode_use_idx;
parm.eq_type_tab = (void *)get_eq_mode_tab();
#if TCFG_USER_EQ_MODE_NUM
parm.type_num = TCFG_USER_EQ_MODE_NUM;//EQ_MODE_MAX;
#endif
parm.section_max = EQ_SECTION_MAX;
EQ_CFG *eq_cfg = eq_cfg_open(&parm);
if (eq_cfg) {
eq_cfg->priv = eq_cfg;
eq_cfg->send_cmd = ci_send_cmd;
eq_cfg->custom_mode_id = EQ_MODE_CUSTOM;
#if defined(AUDIO_VBASS_CONFIG)&&AUDIO_VBASS_CONFIG
eq_cfg->vbass = 1;
#endif
#if EQ_FILE_CP_TO_CUSTOM
eq_file_cp_to_custon_mode_fun(eq_cfg);
#else
for (int i = 0; i < eq_cfg->mode_num; i++) {
if (eq_cfg->eq_type == EQ_TYPE_MODE_TAB) {
if (!eq_cfg->type_gain_tab) {//没指定总增益时才配置默认总增益0
set_global_gain(eq_cfg, i, 0);
}
drc_default_init(eq_cfg, i);
}
}
#endif
}
int cpu_section = 0;
//单声道或者立体声申请的cpu eq mem
if (EQ_SECTION_MAX > 10) {
u8 add_num = 0;
if (hw_crossover_type0) {
add_num = 4;//drc分频器使用eq硬件加速时、3段4阶使用最大eq段数24段(每段4个eq, 6声道)
}
cpu_section = EQ_SECTION_MAX - (int)&EQ_PRIV_SECTION_NUM + add_num;
}
audio_eq_init(cpu_section);
return 0;
}
__initcall(eq_init);
#if TCFG_EQ_FILE_SWITCH_EN
//根据eq_file_switch_list切换到指定的eq文件
void eq_file_set_by_index(u8 index)
{
if (index >= ARRAY_SIZE(eq_file_switch_list)) {
printf("err, max index %d\n", ARRAY_SIZE(eq_file_switch_list));
return;
}
EQ_CFG *eq_cfg = get_eq_cfg_hdl();
if (!eq_cfg) {
return;
}
int ret = eq_file_get_cfg(eq_cfg, eq_file_switch_list[index]);
printf("eq_file_switch : %d, ret : %d", index, ret);
}
//根据eq_file_switch_list成员个数顺序切换eq文件
void eq_file_switch()
{
static u8 index = 0;
index++;
if (index >= ARRAY_SIZE(eq_file_switch_list)) {
index = 0;
}
eq_file_set_by_index(index);
}
#endif
#endif

220
cpu/br28/hw_fft.c Normal file
View File

@ -0,0 +1,220 @@
#include "includes.h"
/*FFT模块资源互斥方式配置*/
#define CRITICAL_NULL 0
#define CRITICAL_IRQ 1
#define CRITICAL_MUTEX 2
#define CRITICAL_SPIN_LOCK 3
#define FFT_CRITICAL_MODE CRITICAL_SPIN_LOCK
#if (FFT_CRITICAL_MODE == CRITICAL_MUTEX)
static OS_MUTEX fft_mutex;
#define FFT_CRITICAL_INIT() os_mutex_create(&fft_mutex)
#define FFT_ENTER_CRITICAL() os_mutex_pend(&fft_mutex, 0)
#define FFT_EXIT_CRITICAL() os_mutex_post(&fft_mutex)
#elif (FFT_CRITICAL_MODE == CRITICAL_IRQ)
#define FFT_CRITICAL_INIT(...)
#define FFT_ENTER_CRITICAL() local_irq_disable()
#define FFT_EXIT_CRITICAL() local_irq_enable()
#elif (FFT_CRITICAL_MODE == CRITICAL_SPIN_LOCK)
static spinlock_t fft_lock;
#define FFT_CRITICAL_INIT() spin_lock_init(&fft_lock)
#define FFT_ENTER_CRITICAL() spin_lock(&fft_lock)
#define FFT_EXIT_CRITICAL() spin_unlock(&fft_lock)
#endif /*FFT_CRITICAL_MODE*/
static volatile u8 fft_init = 0;
typedef struct {
unsigned int fft_config;
const int *in;
int *out;
} pi32v2_hw_fft_ctx;
#define FFT_ISR_IE 0
void hw_fft_wrap(pi32v2_hw_fft_ctx *ctx)
{
if (fft_init == 0) {
fft_init = 1;
FFT_CRITICAL_INIT();
}
FFT_ENTER_CRITICAL();
JL_FFT->CON = 0;
JL_FFT->CON |= 1 << 8;
JL_FFT->CADR = (unsigned int)ctx;
JL_FFT->CON = (1 << 8) | (0 << 6) | (FFT_ISR_IE << 2) | (0 << 1) | (1 << 0); //((1<<8)|(1<<0))
while ((JL_FFT->CON & (1 << 7)) == 0);
JL_FFT->CON |= (1 << 6);
FFT_EXIT_CRITICAL();
}
static int REAL_FFT_CONFIG[6] = {
809501970, 813696546, 822085426, 838862898, 872417602, 939526722,
};
/**** Real IFFT *******/
static int REAL_IFFT_CONFIG[6] = {
809501958, 1082131974, 822085382, 1107298310, 872417542, 1207962118,
};
/****************************
*
* Complex Support points
* 32\64\128\256\512\1024\2048
*
* *************************/
/**** Complex FFT *******/
static int COMPLEX_FFT_CONFIG[7] = {
538969360, 541066784, 545261344, 553650224, 570427696, 603982400, 671091520,
};
/**** Complex IFFT *******/
static int COMPLEX_IFFT_CONFIG[7] = {
1075840276, 809502212, 1082132244, 822085636, 1107298580, 872417796, 1207962388,
};
/*********************************************************************
* hw_fft_config
* Description: 根据配置生成 FFT_config
* Arguments : N 运算数据量;
log2N 运算数据量的对数值
is_same_addr 输入输出是否同一个地址0:否1:是
is_ifft 运算类型 0:FFT运算, 1:IFFT运算
is_real 运算数据的类型 1:实数, 0:复数
* Return : ConfgPars 写入FFT寄存器
* Note(s) : None.
*********************************************************************/
unsigned int hw_fft_config(int N, int log2N, int is_same_addr, int is_ifft, int is_real)
{
unsigned int ConfgPars;
ConfgPars = 0;
if (is_real == 1) {
if (is_ifft == 0) {
ConfgPars = REAL_FFT_CONFIG[log2N - 6];
ConfgPars |= is_same_addr;
} else {
ConfgPars = REAL_IFFT_CONFIG[log2N - 6];
ConfgPars |= is_same_addr;
}
} else {
if (is_ifft == 0) {
ConfgPars = COMPLEX_FFT_CONFIG[log2N - 5];
ConfgPars |= is_same_addr;
} else {
ConfgPars = COMPLEX_IFFT_CONFIG[log2N - 5];
ConfgPars |= is_same_addr;
}
}
/* printf("ConfgPars%x\n",ConfgPars); */
return ConfgPars;
}
/*********************************************************************
* hw_fft_run
* Description: fft/ifft运算函数
* Arguments :fft_config FFT运算配置寄存器值
in 输入数据地址(满足4byte对其以及非const类型)
out 输出数据地址
* Return : void
* Note(s) : None.
*********************************************************************/
void hw_fft_run(unsigned int fft_config, const int *in, int *out)
{
pi32v2_hw_fft_ctx ctx;
ctx.fft_config = fft_config;
ctx.in = in;
ctx.out = out;
hw_fft_wrap(&ctx);
}
//////////////////////////////////////////////////////////////////////////
// VECTOR
//////////////////////////////////////////////////////////////////////////
typedef struct {
unsigned long vector_con;
unsigned long vector_xadr;
unsigned long vector_yadr;
unsigned long vector_zadr;
unsigned long vector_config0;
unsigned long vector_config1;
unsigned long vector_config2;
unsigned long null;
} hwvec_ctx_t;
static hwvec_ctx_t g_vector_core_set __attribute__((aligned(16)));
//__attribute__ ((always_inline)) inline
void hwvec_exec(
void *xptr,
void *yptr,
void *zptr,
short x_inc,
short y_inc,
short z_inc,
short nlen,
short nloop,
char q,
long config,
long const_dat
)
{
if (fft_init == 0) {
fft_init = 1;
FFT_CRITICAL_INIT();
}
FFT_ENTER_CRITICAL();
g_vector_core_set.vector_con = config;
g_vector_core_set.vector_config0 = (q << 24) | (nloop << 12) | (nlen);
g_vector_core_set.vector_config1 = (z_inc << 20) | (y_inc << 10) | x_inc;
//printf("nlen0:%d,nloop:%d,q:%d,config:%d,%d\n",nlen,nloop,q,config,const_dat);
g_vector_core_set.vector_xadr = (unsigned long)xptr;
g_vector_core_set.vector_yadr = (unsigned long)yptr;
g_vector_core_set.vector_zadr = (unsigned long)zptr;
JL_FFT->CONST = const_dat;
JL_FFT->CADR = (unsigned long)(&g_vector_core_set);
// nu clr vector ie en
JL_FFT->CON = (1 << 8) | (1 << 6) | (1 << 3) | (1 << 2) | (1 << 0);
lp_waiting((int *)&JL_FFT->CON, BIT(7), BIT(6), 116);
FFT_EXIT_CRITICAL();
}
u8 fft_wrap_for_ldac_enable(void)
{
return 1;
}
int _FFT_wrap_(int cfg, int *in, int *out)
{
//init pi32v2 fft hardware
pi32v2_hw_fft_ctx ctx;
if (in == out) {
cfg |= 1;
}
ctx.fft_config = cfg;
ctx.in = in;
ctx.out = out;
hw_fft_wrap(&ctx);
return 0;
}

343
cpu/br28/icsd_anc_user.c Normal file
View File

@ -0,0 +1,343 @@
#include "app_config.h"
#include "icsd_anc_user.h"
#include "audio_codec_clock.h"
#include "asm/clock.h"
#include "audio_enc.h"
#include "asm/audio_adc.h"
#include "tone_player.h"
#include "avctp_user.h"
#include "asm/audio_src_base.h"
#if TCFG_USER_TWS_ENABLE
#include "bt_tws.h"
#endif
#include "app_main.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
struct audio_mic_hdl {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 *adc_buf; //align 2Bytes
u16 dump_packet;
};
static struct audio_mic_hdl *audio_mic = NULL;
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
extern s16 esco_adc_buf[]; //align 2Bytes
extern void tws_tx_unsniff_req(void);
extern void tws_tx_sniff_req(void);
extern void set_tws_t_sniff(u16 slot);
extern void bt_sniff_set_enable(u8 en);
int audio_mic_en(u8 en, audio_mic_param_t *mic_param,
void (*data_handler)(void *priv, s16 *data, int len))
{
printf("audio_mic_en : %d", en);
if (en) {
if (audio_mic) {
printf("audio_mic re-malloc error\n");
return -1;
}
audio_mic = zalloc(sizeof(struct audio_mic_hdl));
if (audio_mic == NULL) {
printf("audio mic zalloc failed\n");
return -1;
}
u16 mic_ch = mic_param->mic_ch_sel;
u16 sr = mic_param->sample_rate;
u8 gain0 = mic_param->mic0_gain;
u8 gain1 = mic_param->mic1_gain;
u8 gain2 = mic_param->mic2_gain;
u8 gain3 = mic_param->mic3_gain;
u8 mic_num = 0;
/*打开mic电压*/
audio_mic_pwr_ctl(MIC_PWR_ON);
/*打开mic0*/
if (mic_ch & BIT(0)) {
printf("adc_mic0 open, sr:%d, gain:%d\n", sr, gain0);
audio_adc_mic_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic_set_gain(&audio_mic->mic_ch, gain0);
mic_num ++;
}
/*打开mic1*/
if (mic_ch & BIT(1)) {
printf("adc_mic1 open, sr:%d, gain:%d\n", sr, gain1);
audio_adc_mic1_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic1_set_gain(&audio_mic->mic_ch, gain1);
mic_num ++;
}
/*打开mic2*/
if (mic_ch & BIT(2)) {
printf("adc_mic2 open, sr:%d, gain:%d\n", sr, gain2);
audio_adc_mic2_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic2_set_gain(&audio_mic->mic_ch, gain2);
mic_num ++;
}
/*打开mic3*/
if (mic_ch & BIT(3)) {
printf("adc_mic3 open, sr:%d, gain:%d\n", sr, gain3);
audio_adc_mic3_open(&audio_mic->mic_ch, mic_ch, &adc_hdl);
audio_adc_mic3_set_gain(&audio_mic->mic_ch, gain3);
mic_num ++;
}
int adc_buf_size = mic_param->adc_irq_points * 2 * mic_param->adc_buf_num * mic_num;
printf("adc irq points %d, adc_buf_size : %d", mic_param->adc_irq_points, adc_buf_size);
audio_mic->adc_buf = esco_adc_buf;
/* audio_mic->adc_buf = zalloc(adc_buf_size); */
if (audio_mic->adc_buf == NULL) {
printf("audio->adc_buf mic zalloc failed\n");
audio_mic_pwr_ctl(MIC_PWR_OFF);
free(audio_mic);
audio_mic = NULL;
return -1;
}
audio_adc_mic_set_sample_rate(&audio_mic->mic_ch, sr);
audio_adc_mic_set_buffs(&audio_mic->mic_ch, audio_mic->adc_buf,
mic_param->adc_irq_points * 2, mic_param->adc_buf_num);
audio_mic->adc_output.handler = data_handler;
audio_adc_add_output_handler(&adc_hdl, &audio_mic->adc_output);
audio_adc_mic_start(&audio_mic->mic_ch);
} else {
if (audio_mic) {
/*设置fb mic为复用mic*/
#if TCFG_AUDIO_ANC_ENABLE
audio_anc_mic_mana_fb_mult_set(1);
#endif
audio_adc_mic_close(&audio_mic->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &audio_mic->adc_output);
if (audio_mic->adc_buf) {
/* free(audio_mic->adc_buf); */
}
/*清除fb mic为复用mic的标志*/
#if TCFG_AUDIO_ANC_ENABLE
audio_anc_mic_mana_fb_mult_set(0);
if (anc_status_get() == 0)
#endif
{
audio_mic_pwr_ctl(MIC_PWR_OFF);
}
free(audio_mic);
audio_mic = NULL;
}
}
return 0;
}
static char *tone_index_to_name(u8 index)
{
char *file_name = NULL;
switch (index) {
case ICSD_ADT_TONE_NUM0 :
file_name = TONE_NUM_0;
break;
case ICSD_ADT_TONE_NUM1 :
file_name = TONE_NUM_1;
break;
case ICSD_ADT_TONE_NUM2 :
file_name = TONE_NUM_2;
break;
case ICSD_ADT_TONE_NUM3 :
file_name = TONE_NUM_3;
break;
case ICSD_ADT_TONE_NUM4 :
file_name = TONE_NUM_4;
break;
case ICSD_ADT_TONE_NUM5 :
file_name = TONE_NUM_5;
break;
case ICSD_ADT_TONE_NUM6 :
file_name = TONE_NUM_6;
break;
case ICSD_ADT_TONE_NUM7 :
file_name = TONE_NUM_7;
break;
case ICSD_ADT_TONE_NUM8 :
file_name = TONE_NUM_8;
break;
case ICSD_ADT_TONE_NUM9 :
file_name = TONE_NUM_9;
break;
case ICSD_ADT_TONE_NORMAL :
/* file_name = (char *)get_tone_files()->normal; */
break;
case ICSD_ADT_TONE_SPKCHAT_ON :
file_name = TONE_SPKCHAT_ON;
break;
case ICSD_ADT_TONE_SPKCHAT_OFF :
file_name = TONE_SPKCHAT_OFF;
break;
case ICSD_ADT_TONE_WCLICK_ON :
file_name = TONE_WCLICK_ON;
break;
case ICSD_ADT_TONE_WCLICK_OFF :
file_name = TONE_WCLICK_OFF;
break;
case ICSD_ADT_TONE_WINDDET_ON :
file_name = TONE_WINDDET_ON;
break;
case ICSD_ADT_TONE_WINDDET_OFF :
file_name = TONE_WINDDET_OFF;
break;
}
return file_name;
}
int icsd_adt_tone_play_callback(u8 index, void (*evt_handler)(void *priv), void *priv)
{
int ret = 0;
char *file_name = tone_index_to_name(index);
if (index == ICSD_ADT_TONE_NORMAL) {
ret = tone_play_index_with_callback(index, 0, evt_handler, priv);
} else {
ret = tone_play_with_callback(file_name, 0, evt_handler, priv);
}
return ret;
}
int icsd_adt_tone_play(u8 index)
{
int ret = 0;
char *file_name = tone_index_to_name(index);
if (index == ICSD_ADT_TONE_NORMAL) {
ret = tone_play_index(IDEX_TONE_NORMAL, 0);
} else {
ret = tone_play(file_name, 0);
}
return ret;
}
static void icsd_adt_clock_add()
{
/* clock_refurbish(); */
audio_codec_clock_set(SPEAK_TO_CHAT_MODE, AUDIO_CODING_PCM, 0);
}
static void icsd_adt_clock_del()
{
audio_codec_clock_del(SPEAK_TO_CHAT_MODE);
}
void icsd_set_clk()
{
clk_set_sys_lock(128 * (1000000L), 0);
/* clock_alloc("icsd_adt", 128 * 1000000L); */
}
static void icsd_anc_fade_set(int gain)
{
#if TCFG_AUDIO_ANC_ENABLE
audio_anc_fade_ctr_set(ANC_FADE_MODE_WIND_NOISE, AUDIO_ANC_FDAE_CH_ALL, gain);
#endif
}
u8 esco_player_runing()
{
return bt_phone_dec_is_running();
}
u8 bt_get_call_status()
{
return get_call_status();
}
u8 bt_a2dp_get_status()
{
return a2dp_get_status();
}
void bt_cmd_prepare(u8 cmd, u16 param_len, u8 *param)
{
user_send_cmd_prepare(cmd, param_len, param);
}
void *icsd_adt_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int))
{
void *src_hdl = audio_resample_hw_open(1, in_rate, out_rate, 1);
audio_resample_hw_set_output_handler(src_hdl, 0, handler);
return src_hdl;
/* void *src_hdl = zalloc(sizeof(struct audio_src_handle)); */
/* audio_hw_src_open(src_hdl, 1, 1); */
/* audio_hw_src_set_rate(src_hdl, in_rate, out_rate); */
/* audio_src_set_output_handler(src_hdl, 0, handler); */
/* return src_hdl; */
}
void icsd_adt_src_write(void *data, int len, void *resample)
{
audio_resample_hw_write(resample, data, len);
/* audio_src_resample_write(resample, data, len); */
}
void icsd_adt_src_push(void *resample)
{
audio_resample_hw_push_data_out(resample);
/* audio_src_push_data_out((struct audio_src_handle *)resample); */
}
void icsd_adt_src_close(void *resample)
{
audio_resample_hw_close(resample);
/* audio_hw_src_close(resample); */
/* free(resample); */
resample = NULL;
}
void icsd_adt_tx_unsniff_req()
{
#if TCFG_USER_TWS_ENABLE
tws_tx_unsniff_req();
#endif
}
void icsd_bt_sniff_set_enable(u8 en)
{
bt_sniff_set_enable(en);
}
void icsd_set_tws_t_sniff(u16 slot)
{
#if TCFG_USER_TWS_ENABLE
set_tws_t_sniff(slot);
#endif
}
u8 icsd_get_talk_mic_ch(void)
{
return app_var.talk_mic_ch;
}
u8 icsd_get_ref_mic_ch(void)
{
return BIT(TCFG_AUDIO_ANCL_FF_MIC);
}
u8 icsd_get_fb_mic_ch(void)
{
return BIT(TCFG_AUDIO_ANCL_FB_MIC);
}
u8 icsd_get_esco_mic_en_map(void)
{
return TCFG_AUDIO_ADC_MIC_CHA;
}
u8 audio_adc_file_get_esco_mic_num(void)
{
u8 mic_num = 0;
for (int i = 0; i < 4; i++) {
if (TCFG_AUDIO_ADC_MIC_CHA & BIT(i)) {
mic_num++;
}
}
return mic_num;
}
#endif /*TCFG_AUDIO_ANC_ENABLE*/

75
cpu/br28/icsd_anc_user.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _ICSD_ANC_USER_H_
#define _ICSD_ANC_USER_H_
#include "typedef.h"
// #include "esco_player.h"
typedef struct {
u16 mic_ch_sel;
u16 sample_rate;
u16 adc_irq_points;
u16 adc_buf_num;
u16 mic0_gain;
u16 mic1_gain;
u16 mic2_gain;
u16 mic3_gain;
} audio_mic_param_t;
enum {
ICSD_ADT_TONE_NUM0 = 0,
ICSD_ADT_TONE_NUM1,
ICSD_ADT_TONE_NUM2,
ICSD_ADT_TONE_NUM3,
ICSD_ADT_TONE_NUM4,
ICSD_ADT_TONE_NUM5,
ICSD_ADT_TONE_NUM6,
ICSD_ADT_TONE_NUM7,
ICSD_ADT_TONE_NUM8,
ICSD_ADT_TONE_NUM9,
ICSD_ADT_TONE_NORMAL,
ICSD_ADT_TONE_SPKCHAT_ON,
ICSD_ADT_TONE_SPKCHAT_OFF,
ICSD_ADT_TONE_WCLICK_ON,
ICSD_ADT_TONE_WCLICK_OFF,
ICSD_ADT_TONE_WINDDET_ON,
ICSD_ADT_TONE_WINDDET_OFF,
};
#define TCFG_AUDIO_ANCL_FF_MIC ANCL_FF_MIC
#define TCFG_AUDIO_ANCL_FB_MIC ANCL_FB_MIC
#define TCFG_AUDIO_ANCR_FF_MIC ANCR_FF_MIC
#define TCFG_AUDIO_ANCR_FB_MIC ANCR_FB_MIC
int audio_mic_en(u8 en, audio_mic_param_t *mic_param,
void (*data_handler)(void *priv, s16 *data, int len));
int icsd_adt_tone_play_callback(u8 index, void (*evt_handler)(void *priv), void *priv);
int icsd_adt_tone_play(u8 index);
void icsd_adt_clock_add();
void icsd_adt_clock_del();
void icsd_set_clk();
void icsd_anc_fade_set(int gain);
u8 esco_player_runing();
u8 bt_get_call_status();
u8 bt_a2dp_get_status();
void bt_cmd_prepare(u8 cmd, u16 param_len, u8 *param);
void *icsd_adt_src_init(int in_rate, int out_rate, int (*handler)(void *, void *, int));
void icsd_adt_src_write(void *data, int len, void *resample);
void icsd_adt_src_push(void *resample);
void icsd_adt_src_close(void *resample);
void icsd_set_tws_t_sniff(u16 slot);
void icsd_bt_sniff_set_enable(u8 en);
void icsd_adt_tx_unsniff_req();
u8 icsd_get_talk_mic_ch(void);
u8 icsd_get_ref_mic_ch(void);
u8 icsd_get_fb_mic_ch(void);
u8 icsd_get_esco_mic_en_map(void);
u8 audio_adc_file_get_esco_mic_num(void);
#endif

366
cpu/br28/iic_hw.c Normal file
View File

@ -0,0 +1,366 @@
#include "asm/iic_hw.h"
#include "system/generic/gpio.h"
#include "system/generic/log.h"
#include "asm/clock.h"
#include "asm/cpu.h"
/*
[[ 注意!!! ]]
* 适用于带cfg_done的硬件IIC另一种硬件IIC另作说明
* 硬件IIC的START / ACK(NACK)必须在发送或接收字节cfg_done前设置且不能
接cfg_done单独发送而STOP则应在发送或接收字节cfg_done后设置必须接
cfg_done单独发送
*/
static JL_IIC_TypeDef *const iic_regs[IIC_HW_NUM] = {
JL_IIC,
};
#define iic_get_id(iic) (iic)
#define iic_info_port(iic, x) (hw_iic_cfg[iic_get_id(iic)].port[x])
#define iic_info_baud(iic) (hw_iic_cfg[iic_get_id(iic)].baudrate)
#define iic_info_hdrive(iic) (hw_iic_cfg[iic_get_id(iic)].hdrive)
#define iic_info_io_filt(iic) (hw_iic_cfg[iic_get_id(iic)].io_filter)
#define iic_info_io_pu(iic) (hw_iic_cfg[iic_get_id(iic)].io_pu)
#define iic_info_role(iic) (hw_iic_cfg[iic_get_id(iic)].role)
static inline u32 iic_get_scl(hw_iic_dev iic)
{
u8 port = iic_info_port(iic, 0);
return port;
}
static inline u32 iic_get_sda(hw_iic_dev iic)
{
u8 port = iic_info_port(iic, 1);
return port;
}
static int iic_port_init(hw_iic_dev iic)
{
u32 reg;
int ret = 0;
u8 id = iic_get_id(iic);
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
if (id == 0) {
gpio_set_fun_output_port(scl, FO_IIC_SCL, 1, 1, LOW_POWER_FREE);
gpio_set_fun_output_port(sda, FO_IIC_SDA, 1, 1, LOW_POWER_FREE);
gpio_set_fun_input_port(scl, PFI_IIC_SCL, LOW_POWER_FREE);
gpio_set_fun_input_port(sda, PFI_IIC_SDA, LOW_POWER_FREE);
if (iic_info_hdrive(iic)) {
gpio_set_hd(scl, 1);
gpio_set_hd(sda, 1);
} else {
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
}
if (iic_info_io_pu(iic)) {
gpio_set_pull_up(scl, 1);
gpio_set_pull_up(sda, 1);
} else {
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
}
} else {
ret = -EINVAL;
}
return ret;
}
int hw_iic_set_baud(hw_iic_dev iic, u32 baud)
{
//f_iic = f_sys / ((IIC_BAUD + 1) * 2)
//=> IIC_BAUD = f_sys / (2 * f_iic) - 1
u32 sysclk;
u8 id = iic_get_id(iic);
sysclk = clk_get("lsb");
if (sysclk < 2 * baud) {
return -EINVAL;
}
iic_baud_reg(iic_regs[id]) = sysclk / (2 * baud) - 1;
return 0;
}
static void hw_iic_set_die(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
if (id == 0) {
gpio_set_die(scl, en);
gpio_set_die(sda, en);
} else {
//undefined
}
}
void hw_iic_suspend(hw_iic_dev iic)
{
hw_iic_set_die(iic, 0);
}
void hw_iic_resume(hw_iic_dev iic)
{
hw_iic_set_die(iic, 1);
}
int hw_iic_init(hw_iic_dev iic)
{
int ret;
u8 id = iic_get_id(iic);
if ((ret = iic_port_init(iic))) {
log_e("invalid hardware iic port\n");
return ret;
}
hw_iic_set_die(iic, 1);
if (iic_info_role(iic) == IIC_MASTER) {
iic_role_host(iic_regs[id]);
} else {
iic_role_slave(iic_regs[id]);
iic_si_mode_en(iic_regs[id]);
}
if (iic_info_io_filt(iic)) {
iic_isel_filter(iic_regs[id]);
} else {
iic_isel_direct(iic_regs[id]);
}
if ((ret = hw_iic_set_baud(iic, iic_info_baud(iic)))) {
log_e("iic baudrate is invalid\n");
return ret ;
}
iic_pnd_clr(iic_regs[id]);
iic_end_pnd_clr(iic_regs[id]);
iic_start_pnd_clr(iic_regs[id]);
iic_enable(iic_regs[id]);
#if 0
printf("info->scl = %d\n", iic_get_scl(iic));
printf("info->sda = %d\n", iic_get_sda(iic));
printf("info->baudrate = %d\n", iic_info_baud(iic));
printf("info->hdrive = %d\n", iic_info_hdrive(iic));
printf("info->io_filter = %d\n", iic_info_io_filt(iic));
printf("info->io_pu = %d\n", iic_info_io_pu(iic));
printf("info->role = %d\n", iic_info_role(iic));
printf("IIC_CON0 0x%04x\n", iic_regs[id]->CON0);
printf("IIC_CON1 0x%04x\n", iic_regs[id]->CON1);
printf("IIC_BAUD 0x%02x\n", iic_regs[id]->BAUD);
//printf("IIC_BUF %02x\n", iic_regs[id]->BUF);
printf("IOMC1 0x%08x\n", JL_IOMAP->CON1);
#endif
return 0;
}
void hw_iic_uninit(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
hw_iic_set_die(iic, 0);
if (id == 0) {
gpio_set_hd(scl, 0);
gpio_set_hd(sda, 0);
gpio_set_pull_up(scl, 0);
gpio_set_pull_up(sda, 0);
}
iic_disable(iic_regs[id]);
}
void hw_iic_start(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_preset_restart(iic_regs[id]);
//don't add iic_cfg_done() here, it must be used with send byte
}
void hw_iic_stop(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_preset_end(iic_regs[id]);
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte)
{
u8 id = iic_get_id(iic);
iic_dir_out(iic_regs[id]);
iic_buf_reg(iic_regs[id]) = byte;
iic_cfg_done(iic_regs[id]);
/* putchar('a'); */
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
/* putchar('b'); */
return iic_send_is_ack(iic_regs[id]);
}
u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack)
{
u8 id = iic_get_id(iic);
iic_dir_in(iic_regs[id]);
if (ack) {
iic_recv_ack(iic_regs[id]);
} else {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
/* putchar('c'); */
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
/* putchar('d'); */
return iic_buf_reg(iic_regs[id]);
}
int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len)
{
u8 id = iic_get_id(iic);
int i;
if (!buf || !len) {
return -1;
}
iic_dir_in(iic_regs[id]);
iic_recv_ack(iic_regs[id]);
for (i = 0; i < len; i++) {
if (i == len - 1) {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
((u8 *)buf)[i] = iic_buf_reg(iic_regs[id]);
}
return len;
}
int hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len)
{
u8 id = iic_get_id(iic);
int i = 0;
if (!buf || !len) {
return -1;
}
iic_dir_out(iic_regs[id]);
for (i = 0; i < len; i++) {
iic_buf_reg(iic_regs[id]) = ((u8 *)buf)[i];
iic_cfg_done(iic_regs[id]);
while (!iic_pnd(iic_regs[id]));
iic_pnd_clr(iic_regs[id]);
if (!iic_send_is_ack(iic_regs[id])) {
break;
}
}
return i;
}
void hw_iic_set_ie(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
if (en) {
iic_set_ie(iic_regs[id]);
} else {
iic_clr_ie(iic_regs[id]);
}
}
u8 hw_iic_get_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return !!iic_pnd(iic_regs[id]);
}
void hw_iic_clr_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_pnd_clr(iic_regs[id]);
}
void hw_iic_set_end_ie(hw_iic_dev iic, u8 en)
{
u8 id = iic_get_id(iic);
if (en) {
iic_set_end_ie(iic_regs[id]);
} else {
iic_clr_end_ie(iic_regs[id]);
}
}
u8 hw_iic_get_end_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return !!iic_end_pnd(iic_regs[id]);
}
void hw_iic_clr_end_pnd(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
iic_end_pnd_clr(iic_regs[id]);
}
void hw_iic_slave_set_addr(hw_iic_dev iic, u8 addr, u8 addr_ack)
{
u8 id = iic_get_id(iic);
iic_baud_reg(iic_regs[id]) = (addr & 0xfe) | !!addr_ack;
}
void hw_iic_slave_rx_prepare(hw_iic_dev iic, u8 ack)
{
u8 id = iic_get_id(iic);
iic_dir_in(iic_regs[id]);
if (ack) {
iic_recv_ack(iic_regs[id]);
} else {
iic_recv_nack(iic_regs[id]);
}
iic_buf_reg(iic_regs[id]) = 0xff;
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_slave_rx_byte(hw_iic_dev iic, bool *is_start_addr)
{
u8 id = iic_get_id(iic);
if (iic_start_pnd(iic_regs[id])) {
iic_start_pnd_clr(iic_regs[id]);
is_start_addr ? (*is_start_addr = 1) : 0;
} else {
is_start_addr ? (*is_start_addr = 0) : 0;
}
return iic_buf_reg(iic_regs[id]);
}
void hw_iic_slave_tx_byte(hw_iic_dev iic, u8 byte)
{
u8 id = iic_get_id(iic);
iic_dir_out(iic_regs[id]);
iic_buf_reg(iic_regs[id]) = byte;
iic_cfg_done(iic_regs[id]);
}
u8 hw_iic_slave_tx_check_ack(hw_iic_dev iic)
{
u8 id = iic_get_id(iic);
return iic_send_is_ack(iic_regs[id]);
}
void iic_disable_for_ota()
{
JL_IIC->CON0 = 0;
}

345
cpu/br28/iic_soft.c Normal file
View File

@ -0,0 +1,345 @@
//#include "system/init.h"
#include "asm/iic_soft.h"
#include "generic/gpio.h"
#define IIC_SCL_DIR(scl, val) \
gpio_set_direction(scl, val)
#define IIC_SCL_SET_PU(scl, on) \
gpio_set_pull_up(scl, on)
#define IIC_SCL_SET_PD(scl, on) \
gpio_set_pull_down(scl, on)
#define IIC_SCL_SET_DIE(scl, on) \
gpio_set_die(scl, on)
#define IIC_SCL_H(scl) \
gpio_set_direction(scl, 1)
#define IIC_SCL_L(scl) \
gpio_direction_output(scl, 0)
#define IIC_SDA_DIR(sda, val) \
gpio_set_direction(sda, val)
#define IIC_SDA_SET_PU(sda, on) \
gpio_set_pull_up(sda, on)
#define IIC_SDA_SET_PD(sda, on) \
gpio_set_pull_down(sda, on)
#define IIC_SDA_SET_DIE(sda, on) \
gpio_set_die(sda, on)
#define IIC_SDA_H(sda) \
gpio_set_direction(sda, 1)
#define IIC_SDA_L(sda) \
gpio_direction_output(sda, 0)
#define IIC_SDA_READ(sda) \
gpio_read(sda)
#define iic_get_id(iic) (iic)
static inline u32 iic_get_scl(soft_iic_dev iic)
{
u8 id = iic_get_id(iic);
return soft_iic_cfg[id].scl;
}
static inline u32 iic_get_sda(soft_iic_dev iic)
{
u8 id = iic_get_id(iic);
return soft_iic_cfg[id].sda;
}
static inline u32 iic_get_delay(soft_iic_dev iic)
{
u8 id = iic_get_id(iic);
return soft_iic_cfg[id].delay;
/* return soft_iic_real_delay[id]; */
}
static inline u32 iic_get_io_pu(soft_iic_dev iic)
{
u8 id = iic_get_id(iic);
return soft_iic_cfg[id].io_pu;
}
int soft_iic_init(soft_iic_dev iic)
{
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
if (iic_get_io_pu(iic)) {
IIC_SCL_SET_PU(scl, 1);
IIC_SDA_SET_PU(sda, 1);
} else {
IIC_SCL_SET_PU(scl, 0);
IIC_SDA_SET_PU(sda, 0);
}
gpio_set_hd(scl, 0);
gpio_set_hd0(scl, 1);
gpio_set_hd(sda, 0);
gpio_set_hd0(sda, 1);
IIC_SDA_H(sda);
IIC_SCL_H(scl);
IIC_SCL_SET_PD(scl, 0);
IIC_SCL_SET_DIE(scl, 1);
IIC_SDA_SET_PD(sda, 0);
IIC_SDA_SET_DIE(sda, 1);
return 0;
}
void soft_iic_uninit(soft_iic_dev iic)
{
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
IIC_SCL_DIR(scl, 1);
IIC_SCL_SET_PU(scl, 0);
IIC_SCL_SET_PD(scl, 0);
IIC_SCL_SET_DIE(scl, 0);
gpio_set_hd(scl, 0);
gpio_set_hd0(scl, 0);
IIC_SDA_DIR(sda, 1);
IIC_SDA_SET_PU(sda, 0);
IIC_SDA_SET_PD(sda, 0);
IIC_SDA_SET_DIE(sda, 0);
gpio_set_hd(sda, 0);
gpio_set_hd0(sda, 0);
}
void soft_iic_suspend(soft_iic_dev iic)
{
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
IIC_SCL_SET_DIE(scl, 0);
IIC_SDA_SET_DIE(sda, 0);
}
void soft_iic_resume(soft_iic_dev iic)
{
u32 scl, sda;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
IIC_SCL_SET_DIE(scl, 1);
IIC_SDA_SET_DIE(sda, 1);
}
void soft_iic_start(soft_iic_dev iic)
{
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_H(sda);
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t * 2);
IIC_SDA_L(sda);
delay(dly_t);
IIC_SCL_L(scl);
delay(dly_t);
}
void soft_iic_stop(soft_iic_dev iic)
{
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_L(sda);
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t * 2);
IIC_SDA_H(sda);
delay(dly_t);
}
static u8 soft_iic_check_ack(soft_iic_dev iic)
{
u8 ack;
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_DIR(sda, 1);
IIC_SCL_L(scl);
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t);
if (IIC_SDA_READ(sda) == 0) {
ack = 1;
} else {
ack = 0;
}
delay(dly_t);
IIC_SCL_L(scl);
delay(dly_t);
IIC_SDA_DIR(sda, 0);
IIC_SDA_L(sda);
return ack;
}
static void soft_iic_rx_ack(soft_iic_dev iic)
{
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_L(sda);
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t * 2);
IIC_SCL_L(scl);
delay(dly_t);
}
static void soft_iic_rx_nack(soft_iic_dev iic)
{
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_H(sda);
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t * 2);
IIC_SCL_L(scl);
delay(dly_t);
}
u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte)
{
u8 i, ret;
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SCL_L(scl);
for (i = 0; i < 8; i++) { //MSB FIRST
if ((byte << i) & 0x80) {
IIC_SDA_H(sda);
} else {
IIC_SDA_L(sda);
}
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t * 2);
IIC_SCL_L(scl);
delay(dly_t);
}
return soft_iic_check_ack(iic);
}
u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack)
{
u8 byte = 0, i;
u32 scl, sda, dly_t;
scl = iic_get_scl(iic);
sda = iic_get_sda(iic);
dly_t = iic_get_delay(iic);
IIC_SDA_DIR(sda, 1);
for (i = 0; i < 8; i++) {
delay(dly_t);
IIC_SCL_H(scl);
delay(dly_t);
byte = byte << 1;
if (IIC_SDA_READ(sda)) {
byte |= 1;
}
delay(dly_t);
IIC_SCL_L(scl);
delay(dly_t);
}
IIC_SDA_DIR(sda, 0);
if (ack) {
soft_iic_rx_ack(iic);
} else {
soft_iic_rx_nack(iic);
}
return byte;
}
int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len)
{
int i = 0;
if (!buf || !len) {
return -1;
}
for (i = 0; i < len - 1; i++) {
((u8 *)buf)[i] = soft_iic_rx_byte(iic, 1);
}
((u8 *)buf)[len - 1] = soft_iic_rx_byte(iic, 0);
return len;
}
int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len)
{
int i;
u8 ack;
if (!buf || !len) {
return -1;
}
for (i = 0; i < len; i++) {
ack = soft_iic_tx_byte(iic, ((u8 *)buf)[i]);
if (ack == 0) {
break;
}
}
return i;
}

234
cpu/br28/irflt.c Normal file
View File

@ -0,0 +1,234 @@
#include "asm/includes.h"
#include "asm/irflt.h"
#include "timer.h"
#include "generic/gpio.h"
#define ir_log printf
//红外定时器定义
#define IR_TIMER TIMER5
#define IR_IRQ_TIME_IDX IRQ_TIME5_IDX
#define IR_TIME_REG JL_TIMER5
#define USE_IRFLT_OUT 1
IR_CODE ir_code; ///<红外遥控信息
static u8 cmp_start = 0;
static const u16 timer_div[] = {
/*0000*/ 1,
/*0001*/ 4,
/*0010*/ 16,
/*0011*/ 64,
/*0100*/ 2,
/*0101*/ 8,
/*0110*/ 32,
/*0111*/ 128,
/*1000*/ 256,
/*1001*/ 4 * 256,
/*1010*/ 16 * 256,
/*1011*/ 64 * 256,
/*1100*/ 2 * 256,
/*1101*/ 8 * 256,
/*1110*/ 32 * 256,
/*1111*/ 128 * 256,
};
/*----------------------------------------------------------------------------*/
/**@brief time1红外中断服务函数
@param void
@param void
@return void
@note void timer1_ir_isr(void)
*/
/*----------------------------------------------------------------------------*/
___interrupt
void timer_ir_isr(void)
{
IR_TIME_REG->CON |= BIT(14);
u16 bCap1 = IR_TIME_REG->PRD;
IR_TIME_REG->CNT = 0;
u8 cap = bCap1 / ir_code.timer_pad;
ir_code.boverflow = 0;
if (cmp_start < 3) {
return;
}
/* putchar('0' + (cap/10)); */
/* putchar('0' + (cap%10)); */
if (cap <= 1) {
ir_code.wData >>= 1;
ir_code.bState++;
} else if (cap == 2) {
ir_code.wData >>= 1;
ir_code.wData |= 0x8000;
ir_code.bState++;
}
if (ir_code.bState == 16) {
ir_code.wUserCode = ir_code.wData;
}
if (ir_code.bState == 33) {
ir_code.bState = 1;
}
}
/*----------------------------------------------------------------------------*/
/**@brief ir按键初始化
@param void
@param void
@return void
@note void set_ir_clk(void)
((cnt - 1)* 分频数)/lsb_clk = 1ms
*/
/*----------------------------------------------------------------------------*/
#define TIMER_UNIT_MS 1
#define MAX_TIME_CNT 0x07ff //分频准确范围,更具实际情况调整
#define MIN_TIME_CNT 0x0030
void set_ir_clk(void)
{
u32 prd_cnt;
u8 index;
u32 app_timer_clk = 24000000;
for (index = 0; index < (sizeof(timer_div) / sizeof(timer_div[0])); index++) {
prd_cnt = TIMER_UNIT_MS * (app_timer_clk / 1000) / timer_div[index];
if (prd_cnt > MIN_TIME_CNT && prd_cnt < MAX_TIME_CNT) {
break;
}
}
ir_code.timer_pad = prd_cnt;
cmp_start = 0;
if (IR_IRQ_TIME_IDX == IRQ_TIME3_IDX) {
bit_clr_ie(IRQ_TIME3_IDX);
}
request_irq(IR_IRQ_TIME_IDX, 5, timer_ir_isr, 0);
#if USE_IRFLT_OUT
IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(2) | BIT(1) | BIT(0));
#else
IR_TIME_REG->CON = ((6 << 10) | (index << 4) | BIT(1) | BIT(0));
#endif
}
/*----------------------------------------------------------------------------*/
/**@brief 获取ir按键值
@param void
@param void
@return void
@note void get_irkey_value(void)
*/
/*----------------------------------------------------------------------------*/
u8 get_irflt_value(void)
{
u8 tkey = 0xff;
if (ir_code.bState != 32) {
return tkey;
}
if ((((u8 *)&ir_code.wData)[0] ^ ((u8 *)&ir_code.wData)[1]) == 0xff) {
tkey = (u8)ir_code.wData;
} else {
ir_code.bState = 0;
}
return tkey;
}
static u8 ir_io_level = 0;
static u8 ir_io = 0;
void ir_input_io_sel(u8 port)
{
ir_io = port;
#if USE_IRFLT_OUT
gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_IRFLT, INPUT_CH_TYPE_GP_ICH);
#else
gpio_ich_sel_iutput_signal(port, INPUT_CH_SIGNAL_TIMER0_CAPTURE + 2 * IR_TIMER, INPUT_CH_TYPE_GP_ICH);
#endif
gpio_set_direction(port, 1);
gpio_set_die(port, 1);
gpio_set_pull_up(port, 1);
gpio_set_pull_down(port, 0);
}
void ir_output_timer_sel()
{
}
static void ir_timeout(void *priv)
{
ir_code.boverflow++;
if (ir_code.boverflow > 56) { //56*2ms ~= 112ms
ir_code.boverflow = 56;
ir_code.bState = 0;
}
cmp_start ++;
if (cmp_start > 3) {
cmp_start = 3;
}
}
void ir_timeout_set(void)
{
sys_s_hi_timer_add(NULL, ir_timeout, 2); //2ms
}
static u8 ir_io_sus = 0;
u8 ir_io_suspend(void)
{
if (ir_io_sus) {
return 1;
}
if (ir_code.boverflow < 7) { //14ms内红外接收有可能在忙碌
return 1;
}
ir_io_level = gpio_read(ir_io);
IR_TIME_REG->CON |= BIT(14);
IR_TIME_REG->CON &= ~(0b11 << 0);
ir_io_sus = 1;
return 0;
}
u8 ir_io_resume(void)
{
if (!ir_io_sus) {
return 0;
}
ir_io_sus = 0;
gpio_set_direction(ir_io, 1);
gpio_set_die(ir_io, 1);
gpio_set_pull_up(ir_io, 1);
gpio_set_pull_down(ir_io, 0);
delay(10);
if ((ir_io_level) && (ir_io_level != (gpio_read(ir_io)))) {
ir_code.boverflow = 0;
}
cmp_start = 0;
IR_TIME_REG->CNT = 0;
IR_TIME_REG->CON |= BIT(14);
IR_TIME_REG->CON |= (0b11 << 0);
return 0;
}
void irflt_config()
{
JL_IR->RFLT_CON = 0;
/* JL_IR->RFLT_CON |= BIT(7); //256 div */
/* JL_IR->RFLT_CON |= BIT(3); //osc 24m */
JL_IR->RFLT_CON |= BIT(7) | BIT(4); //512 div
JL_IR->RFLT_CON |= BIT(3) | BIT(2); //PLL_48m兼容省晶振
JL_IR->RFLT_CON |= BIT(0); //irflt enable
set_ir_clk();
}
void log_irflt_info()
{
ir_log("RFLT_CON = 0x%x", JL_IR->RFLT_CON);
ir_log("IR_TIME_REG = 0x%x", IR_TIME_REG->CON);
}

BIN
cpu/br28/liba/SensorCalib.a Normal file

Binary file not shown.

Binary file not shown.

BIN
cpu/br28/liba/VirtualBass.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/aac_dec_lib.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/aec.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/agreement.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/amr_dec_lib.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/ape_dec_lib.a Normal file

Binary file not shown.

Binary file not shown.

BIN
cpu/br28/liba/bt_hash_enc.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/btctrler.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/btstack.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/compressor.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/cpu.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
cpu/br28/liba/drc.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/dts_dec_lib.a Normal file

Binary file not shown.

Binary file not shown.

BIN
cpu/br28/liba/google_fps.a Normal file

Binary file not shown.

BIN
cpu/br28/liba/howling.a Normal file

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