986 lines
30 KiB
C
986 lines
30 KiB
C
#ifdef RTOS
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
|
|
#include "hal_dma.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "heap_api.h"
|
|
|
|
#include "string.h"
|
|
#include "bt_drv.h"
|
|
#include "cmsis_os.h"
|
|
#include "hal_btdump.h"
|
|
#include "iqcorrect.h"
|
|
#include "nvrecord.h"
|
|
#include "nvrecord_env.h"
|
|
#include "nvrecord_dev.h"
|
|
#ifdef TX_IQ_CAL
|
|
#define LOG_MODULE HAL_TRACE_MODULE_APP
|
|
|
|
#define NTbl (1024)
|
|
#define fftSize 1024
|
|
|
|
#define bitshift 10
|
|
#define pi (3.1415926535898)
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
|
|
#define READ_REG(b,a) *(volatile uint32_t *)(b+a)
|
|
#define WRITE_REG(v,b,a) *(volatile uint32_t *)(b+a) = v
|
|
|
|
#define BUF_SIZE (1024)
|
|
|
|
#define MAX_COUNT 5
|
|
volatile int iqimb_dma_status = 0;
|
|
//short M0data[BUF_SIZE];
|
|
#define MED_MEM_POOL_SIZE (20*1024)
|
|
static uint8_t *g_medMemPool = NULL;
|
|
|
|
extern void *rt_malloc(unsigned int size);
|
|
extern void rt_free(void *rmem);
|
|
|
|
typedef struct ComplexInt_
|
|
{
|
|
int re;
|
|
int im;
|
|
} ComplexInt;
|
|
typedef struct Complexflt_
|
|
{
|
|
float re;
|
|
float im;
|
|
} ComplexFlt;
|
|
typedef struct ComplexShort_
|
|
{
|
|
short re;
|
|
short im;
|
|
} ComplexShort;
|
|
|
|
#ifdef DCCalib
|
|
static void Tblgen(ComplexShort*w0, ComplexShort*w1, ComplexShort*w2,int len)
|
|
{
|
|
for (int i=0; i<len; i++)
|
|
{
|
|
|
|
w0[i].re = (short)(cos(2*pi*i/(2048.0/32))*32767);
|
|
w0[i].im = (short)(sin(2*pi*i/(2048.0/32))*32767);
|
|
w1[i].re = (short)(cos(2*pi*i/(2048.0/31))*32767);
|
|
w1[i].im = (short)(sin(2*pi*i/(2048.0/31))*32767);
|
|
w2[i].re = (short)(cos(2*pi*i/(2048.0/33))*32767);
|
|
w2[i].im = (short)(sin(2*pi*i/(2048.0/33))*32767);
|
|
}
|
|
}
|
|
#endif
|
|
static void Tblgen_iq(ComplexShort*w0, ComplexShort*w1, ComplexShort*w2,int len)
|
|
{
|
|
for (int i=0; i<len; i++)
|
|
{
|
|
|
|
w0[i].re = (short)(cos(2*pi*i/(2048.0/64))*32767);
|
|
w0[i].im = (short)(sin(2*pi*i/(2048.0/64))*32767);
|
|
w1[i].re = (short)(cos(2*pi*i/(2048.0/63))*32767);
|
|
w1[i].im = (short)(sin(2*pi*i/(2048.0/63))*32767);
|
|
w2[i].re = (short)(cos(2*pi*i/(2048.0/65))*32767);
|
|
w2[i].im = (short)(sin(2*pi*i/(2048.0/65))*32767);
|
|
}
|
|
}
|
|
/*
|
|
typedef struct IQMismatchPreprocessState_
|
|
{
|
|
short *M0data;
|
|
ComplexShort *Table0;
|
|
ComplexShort *Table1;
|
|
ComplexShort *Table2;
|
|
} IQMismatchPreprocessState;
|
|
|
|
|
|
IQMismatchPreprocessState st_g;
|
|
short st_M0data[fftSize];
|
|
short st_Table0[2*NTbl];
|
|
short st_Table1[2*NTbl];
|
|
short st_Table2[2*NTbl];
|
|
|
|
IQMismatchPreprocessState *st;
|
|
|
|
|
|
IQMismatchPreprocessState *IQMismatchPreprocessState_init(int Cohcnt)
|
|
{
|
|
st_g.M0data = st_M0data;
|
|
st_g.Table0= st_Table0;
|
|
st_g.Table1= st_Table1;
|
|
st_g.Table2= st_Table2;
|
|
return &st_g;
|
|
}
|
|
*/
|
|
|
|
typedef struct IQMismatchPreprocessState_
|
|
{
|
|
short *M0data;
|
|
ComplexShort *Table0;
|
|
ComplexShort *Table1;
|
|
ComplexShort *Table2;
|
|
} IQMismatchPreprocessState;
|
|
|
|
IQMismatchPreprocessState *IQMismatchPreprocessState_init(int fft_size)
|
|
{
|
|
BT_DRV_TRACE(0,"malloc ini");
|
|
IQMismatchPreprocessState *st = (IQMismatchPreprocessState *)med_calloc(1, sizeof(IQMismatchPreprocessState));
|
|
st->M0data = (short*)med_calloc(fft_size, sizeof(short));
|
|
st->Table0 = (ComplexShort*)med_calloc(fft_size, sizeof(ComplexShort));
|
|
st->Table1 = (ComplexShort*)med_calloc(fft_size, sizeof(ComplexShort));
|
|
st->Table2 = (ComplexShort*)med_calloc(fft_size, sizeof(ComplexShort));
|
|
BT_DRV_TRACE(5,"st:%p, st->M0data:%p, st->Table0:%p, st->Table1:%p, st->Table2:%p", st, st->M0data, st->Table0, st->Table1, st->Table2);
|
|
BT_DRV_TRACE(0,"malloc ok");
|
|
return st;
|
|
}
|
|
|
|
int32_t IQMismatchPreprocessState_destroy(IQMismatchPreprocessState *st)
|
|
{
|
|
BT_DRV_TRACE(5,"st:%p, st->M0data:%p, st->Table0:%p, st->Table1:%p, st->Table2:%p", st, st->M0data, st->Table0, st->Table1, st->Table2);
|
|
med_free(st->M0data);
|
|
med_free(st->Table0);
|
|
med_free(st->Table1);
|
|
med_free(st->Table2);
|
|
med_free(st);
|
|
return 0;
|
|
}
|
|
|
|
int IQMismatchParameterCalc_ex(short *M0data,
|
|
short Cohcnt, ComplexShort *Table0, ComplexShort *Table1, ComplexShort *Table2,int fftsize)
|
|
{
|
|
int i,j,k;
|
|
float M0 = 0;
|
|
//ComplexInt tmp0;
|
|
ComplexFlt tmp0;
|
|
ComplexFlt tmp1;
|
|
ComplexFlt tmp2;
|
|
for (j = 0; j < Cohcnt; j++)
|
|
{
|
|
tmp0.re = 0.0f;
|
|
tmp0.im = 0.0f;
|
|
tmp1.re = 0.0f;
|
|
tmp1.im = 0.0f;
|
|
tmp2.re = 0.0f;
|
|
tmp2.im = 0.0f;
|
|
k = 0;
|
|
for (i=0; i<fftsize; i++)
|
|
{
|
|
if(k>=fftsize)
|
|
k = 0;
|
|
tmp0.re = tmp0.re + (((int)M0data[i] *(int)Table0[k].re) >> 15) ;
|
|
tmp0.im = tmp0.im + (((int)M0data[i] * (int)Table0[k].im) >> 15) ;
|
|
tmp1.re = tmp1.re + (((int)M0data[i] *(int)Table1[k].re) >> 15) ;
|
|
tmp1.im = tmp1.im + (((int)M0data[i] * (int)Table1[k].im) >> 15) ;
|
|
tmp2.re = tmp2.re + (((int)M0data[i] *(int)Table2[k].re) >> 15) ;
|
|
tmp2.im = tmp2.im + (((int)M0data[i] * (int)Table2[k].im) >> 15) ;
|
|
k = k + 1;
|
|
}
|
|
tmp0.re = tmp0.re/ fftsize;// >> bitshift;
|
|
tmp0.im = tmp0.im/ fftsize;// >>bitshift;
|
|
tmp1.re = tmp1.re/ fftsize;// >> bitshift;
|
|
tmp1.im = tmp1.im/ fftsize;// >>bitshift;
|
|
tmp2.re = tmp2.re/ fftsize;// >> bitshift;
|
|
tmp2.im = tmp2.im/ fftsize;// >>bitshift;
|
|
M0 = M0 + tmp0.re*tmp0.re + tmp0.im*tmp0.im;
|
|
M0 = M0 + tmp1.re*tmp1.re + tmp1.im*tmp1.im;
|
|
M0 = M0 + tmp2.re*tmp2.re + tmp2.im*tmp2.im;
|
|
}
|
|
return (int)(M0/Cohcnt);
|
|
}
|
|
|
|
|
|
void caculate_energy_main_test(IQMismatchPreprocessState *st,int* Energy,int* Energy1,int fftsize)
|
|
{
|
|
short Cohcnt = 1;
|
|
*Energy1 = IQMismatchParameterCalc_ex(st->M0data, Cohcnt, st->Table0, st->Table1, st->Table2,fftsize);
|
|
}
|
|
|
|
static struct HAL_DMA_DESC_T iqimb_dma_desc[1];
|
|
|
|
|
|
static void iqimb_dma_dout_handler(uint32_t remains, uint32_t error, struct HAL_DMA_DESC_T *lli)
|
|
{
|
|
hal_audma_free_chan(0);
|
|
hal_btdump_disable();
|
|
iqimb_dma_status = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
int bt_iqimb_dma_enable ( short * dma_dst_data, uint16_t size)
|
|
{
|
|
struct HAL_DMA_CH_CFG_T iqimb_dma_cfg;
|
|
// BT_DRV_TRACE(0,"bt_iqimb_dma_enable :");
|
|
|
|
iqimb_dma_status = 1;
|
|
|
|
memset(&iqimb_dma_cfg, 0, sizeof(iqimb_dma_cfg));
|
|
|
|
//iqimb_dma_cfg.ch = hal_audma_get_chan(HAL_AUDMA_DSD_RX,HAL_DMA_HIGH_PRIO);
|
|
|
|
iqimb_dma_cfg.ch = hal_audma_get_chan(HAL_AUDMA_BTDUMP,HAL_DMA_HIGH_PRIO);
|
|
iqimb_dma_cfg.dst_bsize = HAL_DMA_BSIZE_16;
|
|
iqimb_dma_cfg.dst_periph = 0; //useless
|
|
iqimb_dma_cfg.dst_width = HAL_DMA_WIDTH_WORD;
|
|
iqimb_dma_cfg.handler = (HAL_DMA_IRQ_HANDLER_T)iqimb_dma_dout_handler;
|
|
iqimb_dma_cfg.src = 0; // useless
|
|
iqimb_dma_cfg.src_bsize = HAL_DMA_BSIZE_4;
|
|
|
|
//iqimb_dma_cfg.src_periph = HAL_AUDMA_DSD_RX;
|
|
iqimb_dma_cfg.src_periph = HAL_AUDMA_BTDUMP;
|
|
iqimb_dma_cfg.src_tsize = size;//1600; //1600*2/26=123us
|
|
iqimb_dma_cfg.src_width = HAL_DMA_WIDTH_WORD;
|
|
//iqimb_dma_cfg.src_width = HAL_DMA_WIDTH_HALFWORD;
|
|
iqimb_dma_cfg.try_burst = 1;
|
|
iqimb_dma_cfg.type = HAL_DMA_FLOW_P2M_DMA;
|
|
iqimb_dma_cfg.dst = (uint32_t)(dma_dst_data);
|
|
|
|
hal_audma_init_desc(&iqimb_dma_desc[0], &iqimb_dma_cfg, 0, 1);
|
|
|
|
hal_audma_sg_start(&iqimb_dma_desc[0], &iqimb_dma_cfg);
|
|
|
|
//configed after mismatch parameter done, or apb clock muxed.
|
|
|
|
//wait
|
|
for(volatile int i=0; i<5000; i++);
|
|
hal_btdump_enable();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
int bt_iqimb_ini ()
|
|
{
|
|
uint32_t val;
|
|
|
|
BT_DRV_TRACE(0,"bt_iqimb_ini :");
|
|
//config gpadc 26m
|
|
val = READ_REG(0xd0350208,0x0);
|
|
val &= 0xffefffff; //bit20
|
|
val |= (1<<18); //reg_gclk_en(BTM_CLK_26RXNFMI)
|
|
val &= 0xffbfffff; //bit22
|
|
val |= (1<<20); //reg_gclk_en(BTM_CLK_26RXDUMP)
|
|
val &= 0xfdffffff; //bit25
|
|
val |= (1<<25); //reg_gclk_en(BTM_CLK_26RXADC)
|
|
WRITE_REG(val,0xd0350208,0x0);
|
|
BT_DRV_TRACE(1,"0xd0350208 : 0x%08x",val);
|
|
|
|
val = READ_REG(0xd0350228,0x0);
|
|
val &= 0xffefffff; //bit20
|
|
val |= (1<<18); //reg_gclk_mode(BTM_CLK_26RXNFMI)
|
|
val &= 0xffbfffff; //bit22
|
|
val |= (1<<20); //reg_gclk_mode(BTM_CLK_26RXDUMP)
|
|
val &= 0xfdffffff; //bit25
|
|
val |= (1<<25); //reg_gclk_mode(BTM_CLK_26RXADC)
|
|
WRITE_REG(val,0xd0350228,0x0);
|
|
BT_DRV_TRACE(1,"0xd0350228 : 0x%08x",val);
|
|
|
|
//for rx mux to gpadc
|
|
val = READ_REG(0xd0350218,0x0);
|
|
val &= 0xfffffff0; //bit3:0 1110 reg_diagcntl(3 downto 0)
|
|
val |= (0xe<<0);
|
|
val &= 0xfffffbff; //bit10 1 reg_diagcntl(10)
|
|
val |= (0x1<<10);
|
|
WRITE_REG(val,0xd0350218,0x0);
|
|
|
|
BT_DRV_TRACE(1,"0xd0350218 : 0x%08x",val);
|
|
|
|
|
|
val = READ_REG(0xd0330024,0x0);
|
|
val &= 0xfffffff7; //bit3:0 1110 reg_diagcntl(3 downto 0)
|
|
val |= (0x1<<15);
|
|
WRITE_REG(val,0xd0330024,0x0);
|
|
BT_DRV_TRACE(1,"0xd0330024 : 0x%08x",val);
|
|
|
|
|
|
val = READ_REG(0xd0330034,0x0);
|
|
val &= 0x03ffffff; //bit3:0 1110 reg_diagcntl(3 downto 0)
|
|
val |= (0x1b<<26);
|
|
WRITE_REG(val,0xd0330034,0x0);
|
|
|
|
BT_DRV_TRACE(1,"0xd0330034 : 0x%08x",val);
|
|
|
|
WRITE_REG(0x002eb948,0xd0350364,0x0);
|
|
|
|
|
|
val = READ_REG(0xd0330038,0x0);
|
|
|
|
val |= (0x1<<24);
|
|
WRITE_REG(val,0xd0330038,0x0);
|
|
|
|
|
|
WRITE_REG(0,0xc000033c,0x0);
|
|
return 1;
|
|
}
|
|
void check_mem_data(void* data, int len)
|
|
{
|
|
short* share_mem = (short*)data;
|
|
BT_DRV_TRACE(3,"check_mem_data :share_mem= %p, 0x%x, 0x%x",share_mem,share_mem[0],share_mem[1]);
|
|
|
|
int16_t i =0;
|
|
int16_t m =0;
|
|
int16_t remain = len;
|
|
for(m=0; m<32; m++)
|
|
{
|
|
for(i=0; i<32; i++)
|
|
{
|
|
|
|
if (remain >16)
|
|
{
|
|
DUMP16("%04x ",share_mem,16);
|
|
share_mem +=16;
|
|
remain -= 16;
|
|
}
|
|
else
|
|
{
|
|
DUMP16("%04x ",share_mem,remain);
|
|
|
|
remain =0;
|
|
return;
|
|
}
|
|
|
|
}
|
|
// BT_DRV_TRACE(0,"\n");
|
|
//BT_DRV_TRACE(1,"addr :0x%08x\n",share_mem);
|
|
hal_sys_timer_delay(MS_TO_TICKS(200));
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
int bt_Txdc_cal_set(int ch_num, int dc_add)
|
|
{
|
|
uint32_t val;
|
|
uint32_t tmp = (uint32_t)dc_add;
|
|
//sel apb clock
|
|
val = READ_REG(0xd0350348,0x0);
|
|
if(ch_num==0)
|
|
{
|
|
val &= 0xfffffc00; //bit31 1 int_en_mismatch
|
|
val |= tmp & 0x3ff;
|
|
}
|
|
else
|
|
{
|
|
// BT_DRV_TRACE(1,"bt_Txdc_cal_set, dcadd : 0x%08x",tmp);
|
|
val &= 0xfc00ffff; //bit31 1 int_en_mismatch
|
|
val |= (tmp & 0x3ff) <<16;
|
|
}
|
|
WRITE_REG(val,0xd0350348,0x0);
|
|
|
|
|
|
// BT_DRV_TRACE(1,"bt_Txdc_cal_set, 0xd0350348 : 0x%08x",val);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//g/p mismatch base addr 0xd0310000
|
|
//dc_i: 0xd0350348 9:0
|
|
//dc_q: 0xd0350348 25:16
|
|
int bt_iqimb_add_mismatch(int ch_num, int gain_mis, int phase_mis, int dc_i, int dc_q, uint32_t addr)
|
|
{
|
|
uint32_t val;
|
|
//sel apb clock
|
|
val = READ_REG(0xd0350348,0x0);
|
|
val &= 0x7fffffff; //bit31 1 int_en_mismatch
|
|
val |= (0x0<<31);
|
|
WRITE_REG(val,0xd0350348,0x0);
|
|
|
|
val = (phase_mis << 16) | (gain_mis & 0x0000ffff);
|
|
WRITE_REG(val,addr,ch_num*4);
|
|
//tval = READ_REG(addr,0x0);
|
|
//BT_DRV_TRACE(1,"bt_iqimb_add_mismatch, iq : 0x%08x",tval);
|
|
|
|
WRITE_REG(0x400000,0xd0350220,0);
|
|
WRITE_REG(0x400000,0xd0350224,0);
|
|
// bt_Txdc_cal_set(0,dc_i);
|
|
//bt_Txdc_cal_set(1,dc_q);
|
|
|
|
/*
|
|
val = READ_REG(0xd0350348,0x0);
|
|
val &= 0xfffffc00; //bit9:0
|
|
val |= dc_i;
|
|
val &= 0xfc00ffff; //bit25:16
|
|
val |= (dc_q<<16);
|
|
WRITE_REG(val,0xd0350348,0x0);
|
|
*/
|
|
//sel 26m clock
|
|
val = READ_REG(0xd0350348,0x0);
|
|
val &= 0x7fffffff; //bit31 1 int_en_mismatch
|
|
val |= (0x1<<31);
|
|
WRITE_REG(val,0xd0350348,0x0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void DC_correction(IQMismatchPreprocessState *st,int *dc_i_r,int *dc_q_r,int fftsize)
|
|
{
|
|
uint8_t k;
|
|
int Energy,Energy1,tmp;
|
|
int dc_iters = 2;
|
|
int dc_i;
|
|
int dc_q;
|
|
int dc_step = 4;
|
|
int dc_i_base;
|
|
int dc_q_base;
|
|
int P0,PIplus,PIneg,PQplus,PQneg,PIPQ;
|
|
int CI,CQ,tmp_D;
|
|
dc_i_base =0;
|
|
dc_q_base = 0;
|
|
for(k=0; k<dc_iters; k++)
|
|
{
|
|
dc_i = dc_i_base;
|
|
dc_q = dc_q_base;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
P0 = Energy1;
|
|
dc_i = dc_i_base + dc_step;
|
|
dc_q = dc_q_base;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
PIplus = Energy1;
|
|
dc_i = dc_i_base - dc_step;
|
|
dc_q = dc_q_base;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
PIneg = Energy1;
|
|
dc_i = dc_i_base;
|
|
dc_q = dc_q_base + dc_step;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
PQplus = Energy1;
|
|
dc_i = dc_i_base;
|
|
dc_q = dc_q_base - dc_step;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
PQneg = Energy1;
|
|
dc_i = dc_i_base + dc_step;
|
|
dc_q = dc_q_base + dc_step;
|
|
bt_Txdc_cal_set(0,dc_i);
|
|
bt_Txdc_cal_set(1,dc_q);
|
|
bt_iqimb_dma_enable(st->M0data,(BUF_SIZE/2));
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
PIPQ = Energy1;
|
|
tmp = 2*PIplus*PIplus + 2*PQplus*PQplus + 2*PIPQ*PIPQ;
|
|
tmp = tmp - 6*P0*P0;
|
|
tmp = tmp + 4*P0*(PIneg+PQneg+PIPQ);
|
|
tmp = tmp + 2*(PIplus*(PQplus - PQneg)-PIneg*(PQplus+PQneg));
|
|
tmp_D = tmp - 4*PIPQ*(PIplus+PQplus);
|
|
tmp = P0*(2*(PIplus - PIneg)+PQplus -PQneg);
|
|
tmp = tmp - PIPQ*(PQneg-PQplus)+PIneg*(PQplus+PQneg);
|
|
tmp = tmp + PQplus*(PQneg-PQplus-2*PIplus);
|
|
CI = -dc_step*tmp;
|
|
tmp = P0*(2*(PQplus - PQneg)+PIplus-PIneg);
|
|
tmp = tmp - PIPQ*(PIneg-PIplus)+PQneg*(PIplus+PIneg);
|
|
tmp = tmp + PIplus*(PIneg-PIplus-2*PQplus);
|
|
CQ = -dc_step*tmp;
|
|
dc_i_base = dc_i_base + CI/tmp_D;
|
|
dc_q_base = dc_q_base + CQ/tmp_D;
|
|
//dc_step = dc_step/2;
|
|
}
|
|
*dc_i_r = dc_i_base;
|
|
*dc_q_r = dc_q_base;
|
|
}
|
|
int IQ_GAIN_Mismatch_Correction(IQMismatchPreprocessState *st,int phase_mis_base,int fftsize,uint32_t addr)
|
|
{
|
|
uint8_t k = 0;
|
|
int phase_mis_tmp =0;
|
|
int gain_mis_tmp =0;
|
|
int tmp = 0;
|
|
int energy_ret0_last = 1048576;
|
|
int energy_ret0 = 0;
|
|
int energy_ret1 = 0;
|
|
int energy_ret2 = 0;
|
|
int Energy,Energy1 ;
|
|
int iters = 4;
|
|
int gainstep =8;
|
|
int gain_mis_base = 0;
|
|
|
|
phase_mis_tmp = phase_mis_base;
|
|
energy_ret0_last = 1048576;
|
|
for(k=0; k<iters+2; k++)
|
|
{
|
|
gain_mis_tmp = gain_mis_base;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret0 = Energy1;
|
|
if(energy_ret0<50)
|
|
break;
|
|
if(k>0)
|
|
{
|
|
if(energy_ret0_last < energy_ret0)
|
|
{
|
|
gain_mis_base = gain_mis_base + tmp;
|
|
gain_mis_tmp = gain_mis_base;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret0 = Energy1;
|
|
}
|
|
}
|
|
//BT_DRV_TRACE(1,"IQ gain correct energy_ret0 = %d",energy_ret0);
|
|
gainstep = 4;///////////////////
|
|
gain_mis_tmp = gain_mis_base + gainstep;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret2 = Energy1;
|
|
gain_mis_tmp = gain_mis_base - gainstep;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret1 = Energy1;
|
|
tmp = energy_ret2 -2*energy_ret0 + energy_ret1;
|
|
//BT_DRV_TRACE(1,"IQ gain correct energy_ret2 -2*energy_ret0 + energy_ret1 = %d",tmp);
|
|
if(tmp>0)
|
|
{
|
|
tmp = (energy_ret2-energy_ret1)*gainstep/tmp/2;
|
|
tmp = min(tmp,4*gainstep);
|
|
gainstep = gainstep/2;
|
|
}
|
|
else
|
|
{
|
|
tmp = 0;
|
|
iters = iters+1;
|
|
}
|
|
if(iters>8)
|
|
break;
|
|
if((gain_mis_base - tmp>60)||(gain_mis_base - tmp<-60))
|
|
tmp = 0;
|
|
//BT_DRV_TRACE(2,"IQ gain correct gain_mis = %d ,gain_adj = %d",gain_mis_base,tmp);
|
|
gain_mis_base = gain_mis_base - tmp;
|
|
energy_ret0_last = energy_ret0;
|
|
}
|
|
return gain_mis_base;
|
|
}
|
|
int IQ_Phase_Mismatch_Correction(IQMismatchPreprocessState *st,int gain_mis_base,int fftsize,uint32_t addr)
|
|
{
|
|
uint8_t k = 0;
|
|
int phase_mis_tmp =0;
|
|
int gain_mis_tmp =0;
|
|
int tmp = 0;
|
|
int energy_ret0_last = 1048576;
|
|
int energy_ret0 = 0;
|
|
int energy_ret1 = 0;
|
|
int energy_ret2 = 0;
|
|
int Energy,Energy1 ;
|
|
int iters = 4;
|
|
int phasestep =4;
|
|
int phase_mis_base = 0;
|
|
tmp = 0;
|
|
energy_ret0_last = 1048576;
|
|
gain_mis_tmp = gain_mis_base;
|
|
for(k=0; k<iters; k++)
|
|
{
|
|
phase_mis_tmp = phase_mis_base;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr); //no mismatch
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret0 = Energy1;
|
|
if(k>0)
|
|
{
|
|
if(energy_ret0_last < energy_ret0)
|
|
{
|
|
phase_mis_base = phase_mis_base + tmp;
|
|
phase_mis_tmp = phase_mis_base;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr); //no mismatch
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret0 = Energy1;
|
|
}
|
|
}
|
|
if(energy_ret0<50)
|
|
break;
|
|
// BT_DRV_TRACE(1,"IQ phase correct energy_ret0 = %d",energy_ret0);
|
|
phasestep = 4;//////////////////////////
|
|
phase_mis_tmp = phase_mis_base + phasestep;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr); //no mismatch
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret2 = Energy1;
|
|
// BT_DRV_TRACE(1,"IQ phase correct energy_ret2 = %d",energy_ret2);
|
|
phase_mis_tmp = phase_mis_base - phasestep;
|
|
bt_iqimb_add_mismatch(0,gain_mis_tmp,phase_mis_tmp,0,0,addr); //no mismatch
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
energy_ret1 = Energy1;
|
|
//BT_DRV_TRACE(1,"IQ phase correct energy_ret1 = %d",energy_ret1);
|
|
tmp = energy_ret2 -2*energy_ret0 + energy_ret1;
|
|
// BT_DRV_TRACE(1,"IQ phase correct energy_ret2 -2*energy_ret0 + energy_ret1 = %d",tmp);
|
|
if(tmp>0)
|
|
{
|
|
tmp = (energy_ret2-energy_ret1)*phasestep/tmp/2;
|
|
tmp = min(tmp,4*phasestep);
|
|
phasestep = phasestep/2;
|
|
}
|
|
else
|
|
{
|
|
tmp = 0;
|
|
iters = iters + 1;
|
|
}
|
|
if(iters>8)
|
|
break;
|
|
if((phase_mis_base - tmp>60)||(phase_mis_base - tmp<-60))
|
|
tmp = 0;
|
|
// BT_DRV_TRACE(2,"IQ phase correct phase_mis = %d ,phase_adj = %d",phase_mis_base,tmp);
|
|
phase_mis_base = phase_mis_base - tmp;
|
|
energy_ret0_last = energy_ret0;
|
|
|
|
}
|
|
return phase_mis_base;
|
|
}
|
|
|
|
static BT_IQ_CALIBRATION_CONFIG_T config;
|
|
|
|
static void bt_update_local_iq_calibration_val(uint32_t freq_range, uint16_t gain_cal_val, uint16_t phase_cal_val)
|
|
{
|
|
config.validityMagicNum = BT_IQ_VALID_MAGIC_NUM;
|
|
config.gain_cal_val[freq_range] = gain_cal_val;
|
|
config.phase_cal_val[freq_range] = phase_cal_val;
|
|
}
|
|
|
|
// do QA calibration and get the calibration value
|
|
static POSSIBLY_UNUSED void btIqCalibration(void)
|
|
{
|
|
btdrv_tx_iq_cal();
|
|
BT_DRV_TRACE(0,"Acquired calibration value:");
|
|
for (uint32_t range = 0;range < BT_FREQENCY_RANGE_NUM;range++)
|
|
{
|
|
BT_DRV_TRACE(3,"%d: 0x%x - 0x%x", range,
|
|
config.gain_cal_val[range],
|
|
config.phase_cal_val[range]);
|
|
}
|
|
}
|
|
|
|
// get IQ calibration from NV
|
|
static bool bt_get_iq_calibration_val_from_nv(BT_IQ_CALIBRATION_CONFIG_T* pConfig)
|
|
{
|
|
if (nv_record_get_extension_entry_ptr() &&
|
|
(BT_IQ_VALID_MAGIC_NUM ==
|
|
nv_record_get_extension_entry_ptr()->btIqCalConfig.validityMagicNum))
|
|
{
|
|
*pConfig = nv_record_get_extension_entry_ptr()->btIqCalConfig;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void bt_iq_calibration_setup(void)
|
|
{
|
|
if (bt_get_iq_calibration_val_from_nv(&config))
|
|
{
|
|
BT_DRV_TRACE(0,"Calibration value in NV:");
|
|
|
|
for (uint32_t range = 0;range < BT_FREQENCY_RANGE_NUM;range++)
|
|
{
|
|
BT_DRV_TRACE(3,"%d: 0x%x - 0x%x", range,
|
|
config.gain_cal_val[range],
|
|
config.phase_cal_val[range]);
|
|
}
|
|
uint32_t addr = 0xd0310000;
|
|
int chs = 27;
|
|
|
|
for (uint32_t range = 0;range < 3;range++)
|
|
{
|
|
if (0 == range)
|
|
{
|
|
addr = 0xd0310034;
|
|
chs= 27;
|
|
addr = addr-13*4;
|
|
}
|
|
|
|
for (uint32_t ch=0;ch < chs;ch++)
|
|
{
|
|
bt_iqimb_add_mismatch(0,
|
|
config.gain_cal_val[range],
|
|
config.phase_cal_val[range],
|
|
0,0,addr);
|
|
addr = addr +4;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
btIqCalibration();
|
|
uint32_t lock = nv_record_pre_write_operation();
|
|
nv_record_get_extension_entry_ptr()->btIqCalConfig = config;
|
|
nv_record_post_write_operation(lock);
|
|
|
|
nv_record_extension_update();
|
|
}
|
|
}
|
|
|
|
void bt_IQ_DC_Mismatch_Correction_Release()
|
|
{
|
|
int phase_mis_base;
|
|
int gain_mis_base;
|
|
int Energy,Energy1;
|
|
uint32_t time_start = hal_sys_timer_get();
|
|
int fftsize;
|
|
uint32_t addr = 0xd0310000;
|
|
int chs = 27;
|
|
IQMismatchPreprocessState *st;
|
|
syspool_init();
|
|
syspool_get_buff(&g_medMemPool, MED_MEM_POOL_SIZE);
|
|
med_heap_init(&g_medMemPool[0], MED_MEM_POOL_SIZE);
|
|
//config gpadc 26m
|
|
READ_REG(0xd0310000,0x0);
|
|
#ifdef DCCalib
|
|
int dc_i_base,dc_q_base;
|
|
fftsize = 1024;
|
|
st = IQMismatchPreprocessState_init(fftsize);
|
|
Tblgen(st->Table0,st->Table1,st->Table2,fftsize);
|
|
DC_correction(st,&dc_i_base,&dc_q_base,fftsize);
|
|
bt_Txdc_cal_set(0,dc_i_base); //set cal DC I
|
|
bt_Txdc_cal_set(1,dc_q_base);
|
|
//val = READ_REG(0xd0350348,0x0);
|
|
//BT_DRV_TRACE(1,"0xd0350348 = 0x%08x",val);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
// BT_DRV_TRACE(3,"dc cal done!!! dc_i = %d ,dc_q = %d,Energy1 = %d",dc_i_base,dc_q_base,Energy1);
|
|
if(Energy1>200)
|
|
{
|
|
DC_correction(st,&dc_i_base,&dc_q_base,fftsize);
|
|
bt_Txdc_cal_set(0,dc_i_base); //set cal DC I
|
|
bt_Txdc_cal_set(1,dc_q_base);
|
|
//val = READ_REG(0xd0350348,0x0);
|
|
//BT_DRV_TRACE(1,"0xd0350348 = 0x%08x",val);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
}
|
|
if(Energy1>200)
|
|
{
|
|
DC_correction(st,&dc_i_base,&dc_q_base,fftsize);
|
|
bt_Txdc_cal_set(0,dc_i_base); //set cal DC I
|
|
bt_Txdc_cal_set(1,dc_q_base);
|
|
//val = READ_REG(0xd0350348,0x0);
|
|
//BT_DRV_TRACE(1,"0xd0350348 = 0x%08x",val);
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
}
|
|
#endif
|
|
// BT_DRV_TRACE(1,"use time: %d ticks", (hal_sys_timer_get()-time_start));
|
|
// BT_DRV_TRACE(3,"dc cal done!!! dc_i = %d ,dc_q = %d,Energy1 = %d",dc_i_base,dc_q_base,Energy1);
|
|
fftsize = 1024;
|
|
st = IQMismatchPreprocessState_init(fftsize);
|
|
Tblgen_iq(st->Table0,st->Table1,st->Table2,fftsize);
|
|
BT_DRV_TRACE(1,"use time: %d ms", __TICKS_TO_MS(hal_sys_timer_get()-time_start));
|
|
for (int k = 0; k<3; k++)
|
|
{
|
|
if(k==0)
|
|
{
|
|
WRITE_REG(0x0,0xD02201E4,0x0);
|
|
WRITE_REG(0x000A000D,0xD02201E4,0x0);
|
|
//osDelay(1000);
|
|
addr = 0xd0310034;
|
|
}
|
|
else if(k==1)
|
|
{
|
|
WRITE_REG(0x0,0xD02201E4,0x0);
|
|
WRITE_REG(0x000A0027,0xD02201E4,0x0);
|
|
addr = 0xd031009c;
|
|
}
|
|
else
|
|
{
|
|
WRITE_REG(0x0,0xD02201E4,0x0);
|
|
WRITE_REG(0x000A0041,0xD02201E4,0x0);
|
|
addr = 0xd0310104;
|
|
}
|
|
gain_mis_base = IQ_GAIN_Mismatch_Correction(st,0,fftsize,addr);
|
|
phase_mis_base = IQ_Phase_Mismatch_Correction(st,gain_mis_base,fftsize,addr);
|
|
bt_iqimb_add_mismatch(0,gain_mis_base,phase_mis_base,0,0,addr); //no mismatch
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
// BT_DRV_TRACE(4,"IQ phase correct addr = 0x%08x,phase_mis = %d ,gain_mis = %d,Energy = %d",addr,phase_mis_base,gain_mis_base,Energy1);
|
|
if(Energy1>500)
|
|
{
|
|
if(ABS(gain_mis_base)>ABS(phase_mis_base))
|
|
{
|
|
gain_mis_base = IQ_GAIN_Mismatch_Correction(st,0,fftsize,addr);
|
|
phase_mis_base = IQ_Phase_Mismatch_Correction(st,gain_mis_base,fftsize,addr);
|
|
}
|
|
else
|
|
{
|
|
phase_mis_base = IQ_Phase_Mismatch_Correction(st,0,fftsize,addr);
|
|
gain_mis_base = IQ_GAIN_Mismatch_Correction(st,phase_mis_base,fftsize,addr);
|
|
}
|
|
|
|
bt_iqimb_add_mismatch(0,gain_mis_base,phase_mis_base,0,0,addr); //no mismatch
|
|
// BT_DRV_TRACE(1,"use time: %d ticks", (hal_sys_timer_get()-time_start));
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
// BT_DRV_TRACE(4,"IQ phase correct addr = 0x%08x,phase_mis = %d ,gain_mis = %d,Energy = %d",addr,phase_mis_base,gain_mis_base,Energy1);
|
|
}
|
|
|
|
if(Energy1>500)
|
|
{
|
|
if(ABS(gain_mis_base)>ABS(phase_mis_base))
|
|
{
|
|
gain_mis_base = IQ_GAIN_Mismatch_Correction(st,0,fftsize,addr);
|
|
phase_mis_base = IQ_Phase_Mismatch_Correction(st,gain_mis_base,fftsize,addr);
|
|
}
|
|
else
|
|
{
|
|
phase_mis_base = IQ_Phase_Mismatch_Correction(st,0,fftsize,addr);
|
|
gain_mis_base = IQ_GAIN_Mismatch_Correction(st,phase_mis_base,fftsize,addr);
|
|
}
|
|
// BT_DRV_TRACE(1,"use time: %d ticks", (hal_sys_timer_get()-time_start));
|
|
bt_iqimb_dma_enable(st->M0data,fftsize);
|
|
while(1)
|
|
{
|
|
if(iqimb_dma_status==0)
|
|
break;
|
|
}
|
|
caculate_energy_main_test(st,&Energy,&Energy1,fftsize);
|
|
// BT_DRV_TRACE(4,"IQ phase correct addr = 0x%08x,phase_mis = %d ,gain_mis = %d,Energy = %d",addr,phase_mis_base,gain_mis_base,Energy1);
|
|
}
|
|
if(k==0)
|
|
{
|
|
chs= 27;
|
|
addr = addr-13*4;
|
|
}
|
|
else if(k==1)
|
|
{
|
|
chs = 26;
|
|
addr = addr - 12*4;
|
|
}
|
|
else
|
|
{
|
|
chs = 26;
|
|
addr = addr -12*4;
|
|
}
|
|
|
|
bt_update_local_iq_calibration_val(k, gain_mis_base, phase_mis_base);
|
|
|
|
for (int ch=0; ch<chs; ch++)
|
|
{
|
|
bt_iqimb_add_mismatch(0,gain_mis_base,phase_mis_base,0,0,addr); //no mismatch
|
|
// osDelay(1);
|
|
// BT_DRV_TRACE(4,"IQ phase correct addr = 0x%08x,phase_mis = %d ,gain_mis = %d,Energy = %d",addr,phase_mis_base,gain_mis_base,Energy1);
|
|
addr = addr +4;
|
|
}
|
|
BT_DRV_TRACE(1,"use time: %d ms", __TICKS_TO_MS(hal_sys_timer_get()-time_start));
|
|
//BT_DRV_TRACE(4,"IQ phase correct addr = 0x%08x,phase_mis = %d ,gain_mis = %d,Energy = %d",addr-4,phase_mis_base,gain_mis_base,Energy1);
|
|
}
|
|
}
|
|
|
|
int bt_iqimb_test_ex (int mismatch_type)
|
|
{
|
|
|
|
bt_IQ_DC_Mismatch_Correction_Release();
|
|
|
|
return 1;
|
|
}
|
|
|
|
#endif//TX_IQ_CAL
|
|
#endif
|