#ifdef RTOS #include #include #include "hal_dma.h" #include "hal_timer.h" #include "hal_trace.h" #include "heap_api.h" #include "bt_drv.h" #include "cmsis_os.h" #include "hal_btdump.h" #include "iqcorrect.h" #include "nvrecord.h" #include "nvrecord_dev.h" #include "nvrecord_env.h" #include "string.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