Igor Stepura / kw41z-rf-driver Featured

ARM mbed Nanostack RF driver for NXP KW41Z 802.15.4 wireless MCU

This driver is used with 6LoWPAN stack.

Code far from being stable yet, but basic functionality seems to be working. Two FRDM-KW41Z boards running code build from mbed-os-example-mesh-minimal and nanostack-border-router are able to build mesh.

Main repository is at https://github.com/istepura/kw41z-rf-driver

Revision:
0:bb6687c3a462
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/xcvr/fsl_xcvr_trim.c	Thu Jul 20 13:06:20 2017 -0400
@@ -0,0 +1,995 @@
+/*
+* Copyright 2016-2017 NXP
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* o Redistributions of source code must retain the above copyright notice, this list
+*   of conditions and the following disclaimer.
+*
+* o Redistributions in binary form must reproduce the above copyright notice, this
+*   list of conditions and the following disclaimer in the documentation and/or
+*   other materials provided with the distribution.
+*
+* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+*   contributors may be used to endorse or promote products derived from this
+*   software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "fsl_device_registers.h"
+#include "fsl_common.h"
+#include "fsl_xcvr.h"
+#include "fsl_xcvr_trim.h"
+#include "dbg_ram_capture.h"
+#include "math.h"
+
+/*******************************************************************************
+* Definitions
+******************************************************************************/
+
+
+/*******************************************************************************
+* Prototypes
+******************************************************************************/
+void DC_Measure_short(IQ_t chan, DAC_SWEEP_STEP2_t dcoc_init_val);
+float calc_dcoc_dac_step(GAIN_CALC_TBL_ENTRY2_T * meas_ptr, GAIN_CALC_TBL_ENTRY2_T * baseline_meas_ptr );
+extern float roundf (float);
+
+/*******************************************************************************
+* Variables
+******************************************************************************/
+const int8_t TsettleCal = 10;
+static GAIN_CALC_TBL_ENTRY2_T measurement_tbl2[NUM_I_Q_CHAN][NUM_SWEEP_STEP_ENTRIES2]; 
+static const int8_t sweep_step_values2[NUM_SWEEP_STEP_ENTRIES2] = 
+{ 
+    0, /* Baseline entry is first and not used in this table */
+    -16,
+    +16,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    -4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4,
+    +4
+};
+
+/*******************************************************************************
+ * Macros
+ ******************************************************************************/
+#define ISIGN(x) !((uint16_t)x & 0x8000)
+#define ABS(x) ((x) > 0 ? (x) : -(x))
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*! *********************************************************************************
+ * \brief  This function performs a trim of the BBA DCOC DAC on the DUT
+ *
+ * \return status - 1 if passed, 0 if failed.
+ *
+ * \ingroup PublicAPIs
+ *
+ * \details
+ *   Requires the RX to be warmed up before this function is called.
+ *   
+ ***********************************************************************************/
+uint8_t rx_bba_dcoc_dac_trim_shortIQ(void)
+{
+    uint8_t i;
+    float temp_mi = 0;
+    float temp_mq = 0;
+    float temp_pi = 0;
+    float temp_pq = 0;
+    float temp_step = 0;
+    uint8_t bbf_dacinit_i, bbf_dacinit_q;
+
+    uint32_t dcoc_init_reg_value_dcgain = 0x80802020; /* Used in 2nd & 3rd Generation DCOC Trims only. */
+    uint32_t bbf_dcoc_step;
+    uint32_t bbf_dcoc_step_rcp;
+    TZAdcocstep_t tza_dcoc_step[11];
+    uint8_t status = 0;
+    
+    /* Save register values. */  
+    uint32_t dcoc_ctrl_0_stack;
+    uint32_t dcoc_ctrl_1_stack;
+    uint32_t agc_ctrl_1_stack;
+    uint32_t rx_dig_ctrl_stack;
+    uint32_t dcoc_cal_gain_state;
+
+    XcvrCalDelay(1000);
+    dcoc_ctrl_0_stack = XCVR_RX_DIG->DCOC_CTRL_0; /* Save state of DCOC_CTRL_0 for later restore. */
+    dcoc_ctrl_1_stack = XCVR_RX_DIG->DCOC_CTRL_1; /* Save state of DCOC_CTRL_1 for later restore. */
+    rx_dig_ctrl_stack =  XCVR_RX_DIG->RX_DIG_CTRL; /* Save state of RX_DIG_CTRL for later restore. */
+    agc_ctrl_1_stack = XCVR_RX_DIG->AGC_CTRL_1; /* Save state of RX_DIG_CTRL for later restore. */
+    dcoc_cal_gain_state = XCVR_RX_DIG->DCOC_CAL_GAIN; /* Save state of DCOC_CAL_GAIN for later restore. */
+
+    /* Ensure AGC, DCOC and RX_DIG_CTRL is in correct mode. */
+    XCVR_RX_DIG->RX_DIG_CTRL = (XCVR_RX_DIG->RX_DIG_CTRL & ~XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN_MASK) | XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN(0); /* Turn OFF AGC */
+
+    XCVR_RX_DIG->AGC_CTRL_1 = (XCVR_RX_DIG->AGC_CTRL_1 & ~XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN_MASK) | XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN(1) ; /* Set LNA Manual Gain */
+    XCVR_RX_DIG->AGC_CTRL_1 = (XCVR_RX_DIG->AGC_CTRL_1 & ~XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN_MASK) | XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN(1) ; /* Set BBA Manual Gain */
+
+    XCVR_RX_DIG->RX_DIG_CTRL = (XCVR_RX_DIG->RX_DIG_CTRL & ~XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN_MASK) | XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN(0); /* Enable HW DC Calibration -- Disable for SW-DCOC */
+    XCVR_RX_DIG->DCOC_CTRL_0 = (XCVR_RX_DIG->DCOC_CTRL_0 & ~XCVR_RX_DIG_DCOC_CTRL_0_DCOC_MAN_MASK) | XCVR_RX_DIG_DCOC_CTRL_0_DCOC_MAN(1); /* Enable  Manual DCOC */
+    /* DCOC_CTRL_0 @ 4005_C02C -- Define default DCOC DAC settings in manual mode. */
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(0x20) | XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(0x20) |  XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(0x80) | XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(0x80);
+    /* Set DCOC Tracking State. */
+    XCVR_RX_DIG->DCOC_CTRL_0 = (XCVR_RX_DIG->DCOC_CTRL_0 & ~XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC_MASK) | XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(0); /* Disables DCOC Tracking when set to 0 */
+    /* Apply Manual Gain. */
+    XCVR_RX_DIG->AGC_CTRL_1 = XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN(1) | XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN(1) | XCVR_RX_DIG_AGC_CTRL_1_LNA_USER_GAIN(0x02) | XCVR_RX_DIG_AGC_CTRL_1_BBA_USER_GAIN(0x00) ;
+    XcvrCalDelay(TsettleCal);
+
+    dcoc_init_reg_value_dcgain = XCVR_RX_DIG->DCOC_DAC_INIT; /* Capture DC null setting. */
+
+    bbf_dacinit_i = (dcoc_init_reg_value_dcgain & 0x000000FFU);
+    bbf_dacinit_q = (dcoc_init_reg_value_dcgain & 0x0000FF00U) >> 8;
+
+    DC_Measure_short(I_CHANNEL, NOMINAL2);
+    DC_Measure_short(Q_CHANNEL, NOMINAL2);
+
+    /* SWEEP Q CHANNEL */
+    /* BBF NEG STEP */
+    XCVR_RX_DIG->DCOC_DAC_INIT = (XCVR_RX_DIG->DCOC_DAC_INIT & ~XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q_MASK) | XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q - 16);
+    XcvrCalDelay(TsettleCal);
+    DC_Measure_short(Q_CHANNEL, BBF_NEG);
+
+    /* BBF POS STEP */
+    XCVR_RX_DIG->DCOC_DAC_INIT = (XCVR_RX_DIG->DCOC_DAC_INIT & ~XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q_MASK) | XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q + 16);
+    XcvrCalDelay(TsettleCal);
+    DC_Measure_short(Q_CHANNEL, BBF_POS);
+
+    XCVR_RX_DIG->DCOC_DAC_INIT = dcoc_init_reg_value_dcgain; /* Return DAC setting to initial. */
+    XcvrCalDelay(TsettleCal);  
+
+    /* SWEEP I CHANNEL */
+    /* BBF NEG STEP */
+    XCVR_RX_DIG->DCOC_DAC_INIT = (XCVR_RX_DIG->DCOC_DAC_INIT & ~XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I_MASK) | XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i - 16); 
+    XcvrCalDelay(TsettleCal);
+    DC_Measure_short(I_CHANNEL, BBF_NEG);
+    /* BBF POS STEP  */
+    XCVR_RX_DIG->DCOC_DAC_INIT = (XCVR_RX_DIG->DCOC_DAC_INIT & ~XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I_MASK) | XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i + 16); 
+    XcvrCalDelay(TsettleCal);
+    DC_Measure_short(I_CHANNEL, BBF_POS);
+
+    XCVR_RX_DIG->DCOC_DAC_INIT = dcoc_init_reg_value_dcgain; /* Return DACs to initial. */
+    XcvrCalDelay(TsettleCal);
+
+    /* Calculate BBF DCOC STEPS, RECIPROCALS */
+    temp_mi = calc_dcoc_dac_step(&measurement_tbl2[I_CHANNEL][BBF_NEG], &measurement_tbl2[I_CHANNEL][NOMINAL2]);
+    temp_mq = calc_dcoc_dac_step(&measurement_tbl2[Q_CHANNEL][BBF_NEG], &measurement_tbl2[Q_CHANNEL][NOMINAL2]);
+    temp_pi = calc_dcoc_dac_step(&measurement_tbl2[I_CHANNEL][BBF_POS], &measurement_tbl2[I_CHANNEL][NOMINAL2]);
+    temp_pq = calc_dcoc_dac_step(&measurement_tbl2[Q_CHANNEL][BBF_POS], &measurement_tbl2[Q_CHANNEL][NOMINAL2]);
+
+    temp_step = (temp_mi+temp_pi + temp_mq+temp_pq) / 4;
+
+    bbf_dcoc_step = (uint32_t)roundf(temp_step * 8U);
+
+    if ((bbf_dcoc_step > 265) & (bbf_dcoc_step < 305)) 
+    {
+        bbf_dcoc_step_rcp = (uint32_t)roundf((float)0x8000U / temp_step);
+
+        /* Calculate TZA DCOC STEPS & RECIPROCALS and IQ_DC_GAIN_MISMATCH. */
+        for (i = TZA_STEP_N0; i <= TZA_STEP_N10; i++) /* Relying on enumeration ordering. */
+        {
+            /* Calculate TZA DCOC STEPSIZE & its RECIPROCAL. */
+            switch(i){
+            case TZA_STEP_N0: 
+                temp_step = (bbf_dcoc_step >> 3U) / 3.6F;
+                break;
+            case TZA_STEP_N1: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_01_init >> 16)/(xcvr_common_config.dcoc_tza_step_00_init >> 16); 
+                break;
+            case TZA_STEP_N2: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_02_init >> 16)/(xcvr_common_config.dcoc_tza_step_01_init >> 16); 
+                break;
+            case TZA_STEP_N3: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_03_init >> 16)/(xcvr_common_config.dcoc_tza_step_02_init >> 16); 
+                break;
+            case TZA_STEP_N4: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_04_init >> 16)/(xcvr_common_config.dcoc_tza_step_03_init >> 16); 
+                break;
+            case TZA_STEP_N5: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_05_init >> 16)/(xcvr_common_config.dcoc_tza_step_04_init >> 16); 
+                break;
+            case TZA_STEP_N6: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_06_init >> 16)/(xcvr_common_config.dcoc_tza_step_05_init >> 16);
+                break;
+            case TZA_STEP_N7: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_07_init >> 16)/(xcvr_common_config.dcoc_tza_step_06_init >> 16); 
+                break;
+            case TZA_STEP_N8: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_08_init >> 16)/(xcvr_common_config.dcoc_tza_step_07_init >> 16); 
+                break;
+            case TZA_STEP_N9: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_09_init >> 16)/(xcvr_common_config.dcoc_tza_step_08_init >> 16); 
+                break;
+            case TZA_STEP_N10: 
+                temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_10_init >> 16)/(xcvr_common_config.dcoc_tza_step_09_init >> 16); 
+                break;
+            default:
+                break;
+            }
+
+            tza_dcoc_step[i-TZA_STEP_N0].dcoc_step = (uint32_t)roundf(temp_step * 8);
+            tza_dcoc_step[i-TZA_STEP_N0].dcoc_step_rcp = (uint32_t)roundf((float)0x8000 / temp_step);
+        }
+
+        /* Make the trims active. */
+        XCVR_RX_DIG->DCOC_BBA_STEP = XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP(bbf_dcoc_step) | XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_RECIP(bbf_dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_0 = XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0(tza_dcoc_step[0].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_RCP_0(tza_dcoc_step[0].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_1 = XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_GAIN_1(tza_dcoc_step[1].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_RCP_1(tza_dcoc_step[1].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_2 = XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_GAIN_2(tza_dcoc_step[2].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_RCP_2(tza_dcoc_step[2].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_3 = XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_GAIN_3(tza_dcoc_step[3].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_RCP_3(tza_dcoc_step[3].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_4 = XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_GAIN_4(tza_dcoc_step[4].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_RCP_4(tza_dcoc_step[4].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_5 = XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_GAIN_5(tza_dcoc_step[5].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_RCP_5(tza_dcoc_step[5].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_6 = XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_GAIN_6(tza_dcoc_step[6].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_RCP_6(tza_dcoc_step[6].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_7 = XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_GAIN_7(tza_dcoc_step[7].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_RCP_7(tza_dcoc_step[7].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_8 = XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_GAIN_8(tza_dcoc_step[8].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_RCP_8(tza_dcoc_step[8].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_9 = XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_GAIN_9(tza_dcoc_step[9].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_RCP_9(tza_dcoc_step[9].dcoc_step_rcp) ;
+        XCVR_RX_DIG->DCOC_TZA_STEP_10 = XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_GAIN_10(tza_dcoc_step[10].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_RCP_10(tza_dcoc_step[10].dcoc_step_rcp) ;
+
+        status = 1; /* Success */
+    }
+    else
+    {
+        status = 0; /* Failure */
+    }
+
+    /* Restore Registers. */
+    XCVR_RX_DIG->DCOC_CTRL_0 = dcoc_ctrl_0_stack; /* Restore DCOC_CTRL_0 state to prior settings. */
+    XCVR_RX_DIG->DCOC_CTRL_1 = dcoc_ctrl_1_stack; /* Restore DCOC_CTRL_1 state to prior settings. */
+    XCVR_RX_DIG->RX_DIG_CTRL = rx_dig_ctrl_stack; /* Restore RX_DIG_CTRL state to prior settings. */
+    XCVR_RX_DIG->DCOC_CAL_GAIN = dcoc_cal_gain_state; /* Restore DCOC_CAL_GAIN state to prior setting. */
+    XCVR_RX_DIG->AGC_CTRL_1 = agc_ctrl_1_stack; /* Save state of RX_DIG_CTRL for later restore. */
+
+    return status;
+}
+
+/*! *********************************************************************************
+ * \brief  This function performs one point of the DC GAIN calibration process on the DUT
+ *
+ * \param[in] chan - whether the I or Q channel is being tested.
+ * \param[in] stage - whether the BBF or TZA gain stage is being tested.
+ * \param[in] dcoc_init_val - the value being set in the ***DCOC_INIT_* register by the parent.
+ * \param[in] ext_measmt - the external measurement (in milliVolts) captured by the parent after the ***DCOC_INIT_* register was setup.
+ *
+ * \ingroup PublicAPIs
+ *
+ * \details
+ *   Relies on a static array to store each point of data for later processing in ::DC_GainCalc().
+ *   
+ ***********************************************************************************/
+void DC_Measure_short(IQ_t chan, DAC_SWEEP_STEP2_t dcoc_init_val)
+{
+    int16_t dc_meas_i = 0;
+    int16_t dc_meas_q = 0;
+    int16_t sum_dc_meas_i = 0;
+    int16_t sum_dc_meas_q = 0;
+
+    {
+        int8_t i;
+        const int8_t iterations = 1;
+        sum_dc_meas_i = 0;
+        sum_dc_meas_q = 0;
+        
+        for (i = 0; i < iterations; i++)
+        {
+            rx_dc_sample_average(&dc_meas_i, &dc_meas_q);
+            sum_dc_meas_i = sum_dc_meas_i + dc_meas_i;
+            sum_dc_meas_q = sum_dc_meas_q + dc_meas_q;
+        }
+        sum_dc_meas_i = sum_dc_meas_i / iterations;
+        sum_dc_meas_q = sum_dc_meas_q / iterations;
+    }
+
+    measurement_tbl2[chan][dcoc_init_val].step_value = sweep_step_values2[dcoc_init_val];
+
+    if (chan == I_CHANNEL)
+    {
+        measurement_tbl2[chan][dcoc_init_val].internal_measurement = dc_meas_i;
+    }
+    else
+    {
+        measurement_tbl2[chan][dcoc_init_val].internal_measurement = dc_meas_q;
+    }
+}  
+
+/*! *********************************************************************************
+ * \brief  This function calculates one point of DC DAC step based on digital samples of I or Q.
+ *
+ * \param[in] meas_ptr - pointer to the structure containing the measured data from internal measurement.
+ * \param[in] baseline_meas_ptr - pointer to the structure containing the baseline measured data from internal measurement.
+ *
+ * \return result of the calculation, the measurement DCOC DAC step value for this measurement point.
+ *   
+ ***********************************************************************************/
+float calc_dcoc_dac_step(GAIN_CALC_TBL_ENTRY2_T * meas_ptr, GAIN_CALC_TBL_ENTRY2_T * baseline_meas_ptr )
+{
+    static int16_t norm_dc_code;
+    static float dc_step;
+
+    /* Normalize internal measurement */
+    norm_dc_code = meas_ptr->internal_measurement - baseline_meas_ptr->internal_measurement;
+    dc_step = (float)(norm_dc_code) / (float)(meas_ptr->step_value);
+    dc_step = (dc_step < 0)? -dc_step: dc_step;
+
+    return dc_step;
+}
+
+/*! *********************************************************************************
+ * \brief  Temporary delay function 
+ *
+ * \param[in] none.
+ *
+ * \return none.
+ *
+ * \details
+ *
+ ***********************************************************************************/
+void XcvrCalDelay(uint32_t time)
+{
+    while(time * 32 > 0) /* Time delay is roughly in uSec. */
+    {
+        time--;
+    }
+}
+
+/*! *********************************************************************************
+ * \brief  This function calculates the average (DC value) based on a smaller set of digital samples of I and Q.
+ *
+ * \param[in] i_avg - pointer to the location for storing the calculated average for I channel samples.
+ * \param[in] q_avg - pointer to the location for storing the calculated average for Q channel samples.
+ *
+ ***********************************************************************************/
+void rx_dc_sample_average(int16_t * i_avg, int16_t * q_avg)
+{
+    static uint32_t samples[128]; /* 544*2*2 (entire packet ram1/2 size) */
+    uint16_t i;
+    uint32_t rx_sample;
+    uint16_t * sample_ptr;
+    uint32_t temp, end_of_rx_wu;
+    uint32_t num_iq_samples;
+    float avg_i = 0;
+    float avg_q = 0;
+
+    num_iq_samples = 128;
+
+    /* Clear the entire allocated sample buffer */
+    for (i = 0; i < num_iq_samples; i++)
+    {
+        samples[i]=0;
+    }
+
+    /* Assume this has been called *AFTER* RxWu has completed. */
+    /* XCVR_ForceRxWu(); */
+
+    /* Wait for TSM to reach the end of warmup (unless you want to capture some samples during DCOC cal phase) */
+    temp = XCVR_TSM->END_OF_SEQ;
+    end_of_rx_wu = (temp & XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_MASK) >> XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_SHIFT;
+    while ((( XCVR_MISC->XCVR_STATUS & XCVR_CTRL_XCVR_STATUS_TSM_COUNT_MASK) >> XCVR_CTRL_XCVR_STATUS_TSM_COUNT_SHIFT ) != end_of_rx_wu) {};
+
+    dbg_ram_init();
+    /* Argument below is # of bytes, so *2 (I+Q) and *2 (2bytes/sample) */
+#if RADIO_IS_GEN_3P0
+    dbg_ram_start_capture(DBG_PAGE_RXDIGIQ, NO_START_TRIG, NO_STOP_TRIG);
+    dbg_ram_wait_for_complete();
+    dbg_ram_postproc_capture(DBG_PAGE_RXDIGIQ, num_iq_samples * 2 * 2, &samples[0]);
+    dbg_ram_release();
+#else
+    (void)dbg_ram_capture(DBG_PAGE_RXDIGIQ, num_iq_samples * 2 * 2, &samples[0]);
+#endif /* RADIO_IS_GEN_3P0 */
+
+    /* Sign extend the IQ samples in place in the sample buffer. */    
+    sample_ptr = (uint16_t *)(&samples[0]);
+    for (i = 0; i < num_iq_samples * 2; i++)
+    {
+        rx_sample = *sample_ptr;
+        rx_sample |= ((rx_sample & 0x800U) ? 0xF000U : 0x0U); /* Sign extend from 12 to 16 bits. */
+        *sample_ptr = rx_sample;
+        sample_ptr++;
+    }
+    
+    sample_ptr = (uint16_t *)(&samples[0]);
+    for (i = 0; i < num_iq_samples * 2; i += 2)
+    {
+        static int16_t i_value;
+        static int16_t q_value;
+
+        /* Average I & Q channels separately. */
+        i_value = *(sample_ptr + i); /* Sign extend from 12 to 16 bits. */
+        q_value = *(sample_ptr + i + 1); /* Sign extend from 12 to 16 bits. */
+        avg_i += ((float)i_value - avg_i) / (float)(i + 1);  /* Rolling average I */
+        avg_q += ((float)q_value - avg_q) / (float)(i + 1);  /* Rolling average Q */
+    }
+    XcvrCalDelay(10);
+    *i_avg = (int16_t)avg_i;
+    *q_avg = (int16_t)avg_q;
+}
+
+/*! *********************************************************************************
+ * \brief  This function calculates the average (DC value) based on a larger set of digital samples of I and Q.
+ *
+ * \param[in] i_avg - pointer to the location for storing the calculated average for I channel samples.
+ * \param[in] q_avg - pointer to the location for storing the calculated average for Q channel samples.
+ *
+ ***********************************************************************************/
+void rx_dc_sample_average_long(int16_t * i_avg, int16_t * q_avg) 
+{
+    static uint32_t samples[512]; /* 544*2*2 (entire packet ram1/2 size) */
+    uint16_t i;
+    uint32_t rx_sample;
+    uint16_t * sample_ptr;
+    uint32_t temp, end_of_rx_wu;
+    uint32_t num_iq_samples;
+    float avg_i = 0;
+    float avg_q = 0;
+
+    num_iq_samples = 512;
+
+    /* Clear the entire allocated sample buffer. */
+    for (i = 0; i < num_iq_samples; i++)
+    {
+        samples[i]=0;
+    }
+
+    /* Assume this has been called *AFTER* RxWu has completed. */
+    /* XCVR_ForceRxWu(); */
+
+    /* Wait for TSM to reach the end of warmup (unless you want to capture some samples during DCOC cal phase). */
+    temp = XCVR_TSM->END_OF_SEQ;
+    end_of_rx_wu = (temp & XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_MASK) >> XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_SHIFT;
+    while ((( XCVR_MISC->XCVR_STATUS & XCVR_CTRL_XCVR_STATUS_TSM_COUNT_MASK) >> XCVR_CTRL_XCVR_STATUS_TSM_COUNT_SHIFT ) != end_of_rx_wu) {};
+
+    dbg_ram_init();
+    /* Argument below is # of bytes, so *2 (I+Q) and *2 (2bytes/sample) */
+#if RADIO_IS_GEN_3P0
+    dbg_ram_start_capture(DBG_PAGE_RXDIGIQ, NO_START_TRIG, NO_STOP_TRIG);
+    dbg_ram_wait_for_complete();
+    dbg_ram_postproc_capture(DBG_PAGE_RXDIGIQ,num_iq_samples * 2 * 2, &samples[0]);
+    dbg_ram_release();
+#else
+    (void)dbg_ram_capture(DBG_PAGE_RXDIGIQ, num_iq_samples * 2 * 2, &samples[0]);
+#endif /* RADIO_IS_GEN_3P0 */
+
+    /* Sign extend the IQ samples in place in the sample buffer. */
+
+    sample_ptr = (uint16_t *)(&samples[0]);
+    for (i = 0; i < num_iq_samples * 2; i++)
+    {
+        rx_sample = *sample_ptr;
+        rx_sample |= ((rx_sample & 0x800U) ? 0xF000U : 0x0U); /* Sign extend from 12 to 16 bits. */
+        *sample_ptr = rx_sample;
+        sample_ptr++;
+    }
+    
+    sample_ptr = (uint16_t *)(&samples[0]);
+    for (i = 0; i < num_iq_samples * 2; i += 2)
+    {
+        static int16_t i_value;
+        static int16_t q_value;
+
+        /* Average I & Q channels separately. */
+        i_value = *(sample_ptr + i); /* Sign extend from 12 to 16 bits */
+        q_value = *(sample_ptr + i + 1); /* Sign extend from 12 to 16 bits */
+        avg_i += ((float)i_value - avg_i) / (float)(i + 1); /* Rolling average I */
+        avg_q += ((float)q_value - avg_q) / (float)(i + 1); /* Rolling average Q */
+    }
+
+    XcvrCalDelay(10);
+    *i_avg = (int16_t)avg_i;
+    *q_avg = (int16_t)avg_q;
+}
+
+/*! *********************************************************************************
+ * rx_dc_est_average : Get DC EST values and return the Average
+ ***********************************************************************************/
+void rx_dc_est_average(int16_t * i_avg, int16_t * q_avg, uint16_t SampleNumber)
+{
+    float avg_i = 0;
+    float avg_q = 0;
+    uint16_t i = 0;
+    static uint32_t dc_temp, temp;
+    uint32_t end_of_rx_wu = 0;
+    static int16_t dc_meas_i;
+    static int16_t dc_meas_q;
+
+     /* Wait for TSM to reach the end of warmup (unless you want to capture some samples during DCOC cal phase). */
+    temp = XCVR_TSM->END_OF_SEQ;
+    end_of_rx_wu = (temp & XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_MASK) >> XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_SHIFT;
+    while ((( XCVR_MISC->XCVR_STATUS & XCVR_CTRL_XCVR_STATUS_TSM_COUNT_MASK) >> XCVR_CTRL_XCVR_STATUS_TSM_COUNT_SHIFT ) != end_of_rx_wu) {};
+
+    /* Read DCOC DC EST register. */
+    for (i = 0; i < SampleNumber; i++)
+    {
+        dc_temp = XCVR_RX_DIG->DCOC_DC_EST;
+        dc_meas_i = dc_temp & XCVR_RX_DIG_DCOC_DC_EST_DC_EST_I_MASK;
+        temp = dc_meas_i;
+        temp |= ((temp & 0x800U) ? 0xF000U : 0x0U); /* Sign extend from 12 to 16 bits. */
+        dc_meas_i = temp;
+        avg_i += (float) dc_meas_i;
+
+        dc_meas_q = (dc_temp & XCVR_RX_DIG_DCOC_DC_EST_DC_EST_Q_MASK) >> XCVR_RX_DIG_DCOC_DC_EST_DC_EST_Q_SHIFT;
+        temp = dc_meas_q;
+        temp |= ((temp & 0x800U) ? 0xF000U : 0x0U); /* Sign extend from 12 to 16 bits. */
+        dc_meas_q = temp;
+        avg_q += (float) dc_meas_q;
+    }
+
+    avg_i /= (float) SampleNumber;
+    avg_q /= (float) SampleNumber;
+
+    *i_avg = (int16_t)avg_i;
+    *q_avg = (int16_t)avg_q;
+}
+
+/*! *********************************************************************************
+ * \brief  This function performs a trim of the BBA DCOC DAC on the DUT
+ *
+ * \return status - 1 if passed, 0 if failed.
+ *
+ * \ingroup PublicAPIs
+ *
+ * \details
+ *   Requires the RX to be warmed up before this function is called.
+ *   
+ ***********************************************************************************/
+uint8_t rx_bba_dcoc_dac_trim_DCest(void) 
+{
+    uint8_t i;
+    float temp_mi = 0;
+    float temp_mq = 0;
+    float temp_pi = 0;
+    float temp_pq = 0;
+    float temp_step = 0;
+
+    uint32_t bbf_dcoc_step;
+    uint32_t bbf_dcoc_step_rcp;
+    TZAdcocstep_t tza_dcoc_step[11];
+    uint8_t status = 0;
+
+    uint8_t bbf_dacinit_i, bbf_dacinit_q;
+    uint8_t tza_dacinit_i, tza_dacinit_q;
+    int16_t dc_meas_i;
+    int16_t dc_meas_q;
+    uint32_t dcoc_init_reg_value_dcgain = 0x80802020; /* Used in 2nd & 3rd Generation DCOC Trims only */
+    uint32_t temp;
+
+    uint32_t dcoc_ctrl_0_stack;
+    uint32_t dcoc_ctrl_1_stack;
+    uint32_t agc_ctrl_1_stack;
+    uint32_t rx_dig_ctrl_stack;
+    uint32_t dcoc_cal_gain_state;
+
+    /* Save register */
+    dcoc_ctrl_0_stack = XCVR_RX_DIG->DCOC_CTRL_0; /* Save state of DCOC_CTRL_0 for later restore */
+    dcoc_ctrl_1_stack = XCVR_RX_DIG->DCOC_CTRL_1; /* Save state of DCOC_CTRL_1 for later restore */
+    rx_dig_ctrl_stack =  XCVR_RX_DIG->RX_DIG_CTRL; /* Save state of RX_DIG_CTRL for later restore */
+    agc_ctrl_1_stack = XCVR_RX_DIG->AGC_CTRL_1; /* Save state of RX_DIG_CTRL for later restore */
+    dcoc_cal_gain_state = XCVR_RX_DIG->DCOC_CAL_GAIN; /* Save state of DCOC_CAL_GAIN for later restore */
+
+    /* Register config */
+    /* Ensure AGC, DCOC and RX_DIG_CTRL is in correct mode */
+    temp = XCVR_RX_DIG->RX_DIG_CTRL;
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN_MASK; /* Turn OFF AGC */
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN_MASK; /* Disable for SW control of DCOC */
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_DC_RESID_EN_MASK; /* Disable for SW control of DCOC */
+    XCVR_RX_DIG->RX_DIG_CTRL = temp;
+
+    XCVR_RX_DIG->AGC_CTRL_1 = XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN(1) | /* Enable LNA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN(1) | /* Enable BBA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_LNA_USER_GAIN(0x0) | /* Set LNA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_BBA_USER_GAIN(0x0); /* Set BBA Manual Gain */
+
+    /* DCOC_CTRL_0 @ 4005_C02C -- Define default DCOC DAC settings in manual mode */
+    temp = XCVR_RX_DIG->DCOC_CTRL_0;
+    temp |=  XCVR_RX_DIG_DCOC_CTRL_0_DCOC_MAN(1); /* Enable  Manual DCOC */
+    temp |=  XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(1); /* Ensure DCOC Tracking is enabled */
+    temp |=  XCVR_RX_DIG_DCOC_CTRL_0_DCOC_TRK_EST_OVR(1); /* Enable DC Estimator */
+    temp |=  XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_EN(1); /* Ensure DC correction is enabled */
+    XCVR_RX_DIG->DCOC_CTRL_0 = temp;
+
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(0x20) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(0x20) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(0x80) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(0x80);
+
+    XcvrCalDelay(TsettleCal);
+
+    /* Set default DCOC DAC INIT Value */
+    dcoc_init_reg_value_dcgain = XCVR_RX_DIG->DCOC_DAC_INIT; /* Store DCOC DAC INIT values */
+    bbf_dacinit_i = (dcoc_init_reg_value_dcgain & 0x000000FFU);
+    bbf_dacinit_q = (dcoc_init_reg_value_dcgain & 0x0000FF00U)>>8;
+    tza_dacinit_i = (dcoc_init_reg_value_dcgain & 0x00FF0000U)>>16;
+    tza_dacinit_q = dcoc_init_reg_value_dcgain >> 24;
+
+    XcvrCalDelay(TsettleCal * 4);
+    rx_dc_est_average(&dc_meas_i, &dc_meas_q, 64);
+    measurement_tbl2[I_CHANNEL][NOMINAL2].step_value = sweep_step_values2[NOMINAL2];
+    measurement_tbl2[Q_CHANNEL][NOMINAL2].step_value = sweep_step_values2[NOMINAL2];
+    measurement_tbl2[I_CHANNEL][NOMINAL2].internal_measurement = dc_meas_i;
+    measurement_tbl2[Q_CHANNEL][NOMINAL2].internal_measurement = dc_meas_q;
+
+    /* SWEEP I/Q CHANNEL */
+    /* BBF NEG STEP */
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i - 16) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q - 16) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(tza_dacinit_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(tza_dacinit_q);
+    XcvrCalDelay(TsettleCal * 2);
+
+    rx_dc_est_average(&dc_meas_i, &dc_meas_q, 64);
+    measurement_tbl2[I_CHANNEL][BBF_NEG].step_value = -16;
+    measurement_tbl2[Q_CHANNEL][BBF_NEG].step_value = -16;
+    measurement_tbl2[I_CHANNEL][BBF_NEG].internal_measurement = dc_meas_i;
+    measurement_tbl2[Q_CHANNEL][BBF_NEG].internal_measurement = dc_meas_q;
+
+
+    /* BBF POS STEP */
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i + 16) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q + 16) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(tza_dacinit_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(tza_dacinit_q);
+    XcvrCalDelay(TsettleCal * 2);
+    rx_dc_est_average(&dc_meas_i, &dc_meas_q, 64);
+    measurement_tbl2[I_CHANNEL][BBF_POS].step_value = +16;
+    measurement_tbl2[Q_CHANNEL][BBF_POS].step_value = +16;
+    measurement_tbl2[I_CHANNEL][BBF_POS].internal_measurement = dc_meas_i;
+    measurement_tbl2[Q_CHANNEL][BBF_POS].internal_measurement = dc_meas_q;
+
+    XCVR_RX_DIG->DCOC_DAC_INIT = dcoc_init_reg_value_dcgain; /* Return DAC setting to initial */
+
+    /* Calculate BBF DCOC STEPS, RECIPROCALS */
+    temp_mi = calc_dcoc_dac_step(&measurement_tbl2[I_CHANNEL][BBF_NEG], &measurement_tbl2[I_CHANNEL][NOMINAL2]);
+    temp_mq = calc_dcoc_dac_step(&measurement_tbl2[Q_CHANNEL][BBF_NEG], &measurement_tbl2[Q_CHANNEL][NOMINAL2]);
+    temp_pi = calc_dcoc_dac_step(&measurement_tbl2[I_CHANNEL][BBF_POS], &measurement_tbl2[I_CHANNEL][NOMINAL2]);
+    temp_pq = calc_dcoc_dac_step(&measurement_tbl2[Q_CHANNEL][BBF_POS], &measurement_tbl2[Q_CHANNEL][NOMINAL2]);
+
+	temp_step = (temp_mi + temp_pi + temp_mq + temp_pq) / 4;
+    bbf_dcoc_step = (uint32_t)roundf(temp_step * 8U);
+
+    if ((bbf_dcoc_step > 265) & (bbf_dcoc_step < 305))
+    {
+        bbf_dcoc_step_rcp = (uint32_t)roundf((float)0x8000U / temp_step);
+
+        /* Calculate TZA DCOC STEPS & RECIPROCALS and IQ_DC_GAIN_MISMATCH */
+        for (i = TZA_STEP_N0; i <= TZA_STEP_N10; i++)
+        {
+            /* Calculate TZA DCOC STEPSIZE & its RECIPROCAL */
+            switch(i){
+                case TZA_STEP_N0:
+                    temp_step = (bbf_dcoc_step>>3U) / 3.6F;
+                    break;
+                case TZA_STEP_N1:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_01_init >> 16) / (xcvr_common_config.dcoc_tza_step_00_init >> 16);
+                    break;
+                case TZA_STEP_N2:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_02_init >> 16) / (xcvr_common_config.dcoc_tza_step_01_init >> 16);
+                    break;
+                case TZA_STEP_N3:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_03_init >> 16) / (xcvr_common_config.dcoc_tza_step_02_init >> 16);
+                    break;
+                case TZA_STEP_N4:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_04_init >> 16) / (xcvr_common_config.dcoc_tza_step_03_init >> 16);
+                    break;
+                case TZA_STEP_N5:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_05_init >> 16) / (xcvr_common_config.dcoc_tza_step_04_init >> 16);
+                    break;
+                case TZA_STEP_N6:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_06_init >> 16) / (xcvr_common_config.dcoc_tza_step_05_init >> 16);
+                    break;
+                case TZA_STEP_N7:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_07_init >> 16) / (xcvr_common_config.dcoc_tza_step_06_init >> 16);
+                    break;
+                case TZA_STEP_N8:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_08_init >> 16) / (xcvr_common_config.dcoc_tza_step_07_init >> 16);
+                    break;
+                case TZA_STEP_N9:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_09_init >> 16) / (xcvr_common_config.dcoc_tza_step_08_init >> 16);
+                    break;
+                case TZA_STEP_N10:
+                    temp_step = temp_step * (xcvr_common_config.dcoc_tza_step_10_init >> 16) / (xcvr_common_config.dcoc_tza_step_09_init >> 16);
+                    break;
+                default:
+                    break;
+            }
+
+            tza_dcoc_step[i-TZA_STEP_N0].dcoc_step = (uint32_t)roundf(temp_step * 8);
+            tza_dcoc_step[i-TZA_STEP_N0].dcoc_step_rcp = (uint32_t)roundf((float)0x8000 / temp_step);
+        }
+
+        /* Make the trims active */
+        XCVR_RX_DIG->DCOC_BBA_STEP = XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP(bbf_dcoc_step) | XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_RECIP(bbf_dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_0 = XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0(tza_dcoc_step[0].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_RCP_0(tza_dcoc_step[0].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_1 = XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_GAIN_1(tza_dcoc_step[1].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_RCP_1(tza_dcoc_step[1].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_2 = XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_GAIN_2(tza_dcoc_step[2].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_RCP_2(tza_dcoc_step[2].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_3 = XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_GAIN_3(tza_dcoc_step[3].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_RCP_3(tza_dcoc_step[3].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_4 = XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_GAIN_4(tza_dcoc_step[4].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_RCP_4(tza_dcoc_step[4].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_5 = XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_GAIN_5(tza_dcoc_step[5].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_RCP_5(tza_dcoc_step[5].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_6 = XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_GAIN_6(tza_dcoc_step[6].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_RCP_6(tza_dcoc_step[6].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_7 = XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_GAIN_7(tza_dcoc_step[7].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_RCP_7(tza_dcoc_step[7].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_8 = XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_GAIN_8(tza_dcoc_step[8].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_RCP_8(tza_dcoc_step[8].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_9 = XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_GAIN_9(tza_dcoc_step[9].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_RCP_9(tza_dcoc_step[9].dcoc_step_rcp);
+        XCVR_RX_DIG->DCOC_TZA_STEP_10 = XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_GAIN_10(tza_dcoc_step[10].dcoc_step) | XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_RCP_10(tza_dcoc_step[10].dcoc_step_rcp);
+
+        status = 1; /* Success */
+    }
+    else
+    {
+        status = 0; /* Failure */
+    }
+
+    /* Restore Registers */
+    XCVR_RX_DIG->DCOC_CTRL_0 = dcoc_ctrl_0_stack; /* Restore DCOC_CTRL_0 state to prior settings */
+    XCVR_RX_DIG->DCOC_CTRL_1 = dcoc_ctrl_1_stack; /* Restore DCOC_CTRL_1 state to prior settings */
+    XCVR_RX_DIG->RX_DIG_CTRL = rx_dig_ctrl_stack; /* Restore RX_DIG_CTRL state to prior settings */
+    XCVR_RX_DIG->DCOC_CAL_GAIN = dcoc_cal_gain_state; /* Restore DCOC_CAL_GAIN state to prior setting */
+    XCVR_RX_DIG->AGC_CTRL_1 = agc_ctrl_1_stack; /* Save state of RX_DIG_CTRL for later restore */
+
+   return status;
+}
+
+/*! *********************************************************************************
+ * DCOC_DAC_INIT_Cal : slope sign seek depending on measure's sign
+ ***********************************************************************************/
+void DCOC_DAC_INIT_Cal(uint8_t standalone_operation)
+{
+    int16_t dc_meas_i = 2000, dc_meas_i_p = 2000;
+    int16_t dc_meas_q = 2000, dc_meas_q_p = 2000;
+    uint8_t curr_tza_dac_i, curr_tza_dac_q;
+    uint8_t curr_bba_dac_i, curr_bba_dac_q;
+    uint8_t p_tza_dac_i = 0, p_tza_dac_q = 0;
+    uint8_t p_bba_dac_i = 0, p_bba_dac_q = 0;
+    uint8_t i = 0;
+    uint8_t bba_gain = 11;
+    bool TZA_I_OK = 0, TZA_Q_OK = 0, BBA_I_OK = 0, BBA_Q_OK = 0;
+
+    uint32_t dcoc_ctrl_0_stack;
+    uint32_t dcoc_ctrl_1_stack;
+    uint32_t agc_ctrl_1_stack;
+    uint32_t rx_dig_ctrl_stack;
+    uint32_t dcoc_cal_gain_state;
+    uint32_t xcvr_ctrl_stack = 0;
+
+    uint32_t temp;
+
+    /* Save registers */
+    dcoc_ctrl_0_stack = XCVR_RX_DIG->DCOC_CTRL_0; /* Save state of DCOC_CTRL_0 for later restore */
+    dcoc_ctrl_1_stack = XCVR_RX_DIG->DCOC_CTRL_1; /* Save state of DCOC_CTRL_1 for later restore */
+    rx_dig_ctrl_stack =  XCVR_RX_DIG->RX_DIG_CTRL; /* Save state of RX_DIG_CTRL for later restore */
+    agc_ctrl_1_stack = XCVR_RX_DIG->AGC_CTRL_1; /* Save state of RX_DIG_CTRL for later restore */
+    dcoc_cal_gain_state = XCVR_RX_DIG->DCOC_CAL_GAIN; /* Save state of DCOC_CAL_GAIN for later restore */
+
+    /* WarmUp */
+    if (standalone_operation)
+    {
+        temp = XCVR_MISC->XCVR_CTRL;
+        xcvr_ctrl_stack = temp;
+        temp &= ~(XCVR_CTRL_XCVR_CTRL_PROTOCOL_MASK);
+        temp |= XCVR_CTRL_XCVR_CTRL_PROTOCOL(0);
+        XCVR_MISC->XCVR_CTRL = temp;
+        XCVR_OverrideChannel(12, 1); /* Calibrate on channel #12, 2.426 GHz in BLE map */
+        XCVR_ForceRxWu();
+        XcvrCalDelay(2000);
+    } 
+
+    /* Register config */
+    /* Ensure AGC, DCOC and RX_DIG_CTRL is in correct mode */
+    temp = XCVR_RX_DIG->RX_DIG_CTRL;
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN_MASK; /* Turn OFF AGC */
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN_MASK; /* Disable for SW control of DCOC */
+    temp &= ~XCVR_RX_DIG_RX_DIG_CTRL_RX_DC_RESID_EN_MASK; /* Disable for SW control of DCOC */
+    XCVR_RX_DIG->RX_DIG_CTRL = temp;
+
+    XCVR_RX_DIG->AGC_CTRL_1 = XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN(1) | /* Enable LNA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN(1) | /* Enable BBA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_LNA_USER_GAIN(0x0) | /* Set LNA Manual Gain */
+                              XCVR_RX_DIG_AGC_CTRL_1_BBA_USER_GAIN(0x0); /* Set BBA Manual Gain */
+
+    /* DCOC_CTRL_0 @ 4005_C02C -- Define default DCOC DAC settings in manual mode */
+    temp = XCVR_RX_DIG->DCOC_CTRL_0;
+    temp |= XCVR_RX_DIG_DCOC_CTRL_0_DCOC_MAN(1); /* Enable  Manual DCOC */
+    temp |= XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(1); /* Ensure DCOC Tracking is enabled */
+    temp |= XCVR_RX_DIG_DCOC_CTRL_0_DCOC_TRK_EST_OVR(1); /* Enable DC Estimator */
+    temp |= XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_EN(1); /* Ensure DC correction is enabled */
+    XCVR_RX_DIG->DCOC_CTRL_0 = temp;
+
+    XcvrCalDelay(TsettleCal);
+
+    /* Set default DCOC DAC INIT Value */        
+    /* LNA and BBA DAC Sweep */
+    curr_bba_dac_i = 0x20;
+    curr_bba_dac_q = 0x20;
+    curr_tza_dac_i = 0x80;
+    curr_tza_dac_q = 0x80;
+
+    /* Perform a first DC measurement to ensure that measurement is not clipping */
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(curr_bba_dac_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(curr_bba_dac_q) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(curr_tza_dac_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(curr_tza_dac_q);
+
+    do
+    {
+        bba_gain--;
+        /* Set DAC user gain */
+        XCVR_RX_DIG->AGC_CTRL_1 = XCVR_RX_DIG_AGC_CTRL_1_USER_LNA_GAIN_EN(1) |
+                                  XCVR_RX_DIG_AGC_CTRL_1_LNA_USER_GAIN(0) | /* 2 */
+                                  XCVR_RX_DIG_AGC_CTRL_1_USER_BBA_GAIN_EN(1) |
+                                  XCVR_RX_DIG_AGC_CTRL_1_BBA_USER_GAIN(bba_gain) ; /* 10 */
+        XcvrCalDelay(TsettleCal * 2);
+        rx_dc_est_average(&dc_meas_i, &dc_meas_q, 64);
+    } while ((ABS(dc_meas_i) > 1900) | (ABS(dc_meas_q) > 1900));
+
+    for (i = 0; i < 0x0F; i++)
+    {
+        /* I channel :  */
+        if (!TZA_I_OK)
+        {   
+            if ((ISIGN(dc_meas_i) != ISIGN(dc_meas_i_p)) && (i > 0))
+            {    
+                if (ABS(dc_meas_i) != MIN(ABS(dc_meas_i), ABS(dc_meas_i_p)))
+                {
+                    curr_tza_dac_i = p_tza_dac_i; 
+                }
+
+                TZA_I_OK = 1;
+            }
+            else 
+            {
+                p_tza_dac_i = curr_tza_dac_i;
+
+                if (ISIGN(dc_meas_i)) /* If positif */
+                {
+                    curr_tza_dac_i--;
+                }
+                else 
+                {
+                    curr_tza_dac_i++;
+                }
+            }
+        }
+        else /* Sweep BBA I */
+        {
+            if (!BBA_I_OK)
+            {  
+                if ((ISIGN(dc_meas_i) != ISIGN(dc_meas_i_p)) && (curr_bba_dac_i != 0x20))
+                {   
+                    if (ABS(dc_meas_i) != MIN(ABS(dc_meas_i), ABS(dc_meas_i_p)))
+                    {
+                        curr_bba_dac_i = p_bba_dac_i;
+                    }
+
+                    BBA_I_OK = 1;
+                }
+                else 
+                {
+                    p_bba_dac_i = curr_bba_dac_i;
+                    if (ISIGN(dc_meas_i)) /* If positif */
+                    {
+                        curr_bba_dac_i--;
+                    }
+                    else 
+                    {
+                        curr_bba_dac_i++;
+                    }
+                }
+            }
+        }
+
+        /* Q channel : */
+        if (!TZA_Q_OK)
+        {   
+            if ((ISIGN(dc_meas_q) != ISIGN(dc_meas_q_p)) && (i > 0))
+            {    
+                if (ABS(dc_meas_q) != MIN(ABS(dc_meas_q), ABS(dc_meas_q_p)))
+                {
+                    curr_tza_dac_q = p_tza_dac_q;
+                }
+                TZA_Q_OK = 1;
+            }
+            else
+            {
+                p_tza_dac_q = curr_tza_dac_q;
+                if (ISIGN(dc_meas_q)) /* If positif */
+                {
+                    curr_tza_dac_q--;
+                }
+                else 
+                {
+                    curr_tza_dac_q++;
+                } 
+            }
+        } 
+        else  /* Sweep BBA Q */
+        {
+            if (!BBA_Q_OK)
+            {  
+                if ((ISIGN(dc_meas_q) != ISIGN(dc_meas_q_p)) && (curr_bba_dac_q != 0x20))
+                {   
+                    if (ABS(dc_meas_q) != MIN(ABS(dc_meas_q), ABS(dc_meas_q_p)))
+                    {
+                        curr_bba_dac_q = p_bba_dac_q;
+                    }
+                    BBA_Q_OK = 1;
+                 }
+                 else 
+                 {
+                     p_bba_dac_q = curr_bba_dac_q;
+                     if (ISIGN(dc_meas_q)) /* If positif */
+                     { 
+                       curr_bba_dac_q--;
+                     }
+                     else 
+                     {
+                         curr_bba_dac_q++;
+                     }
+                 }
+            }
+        }
+
+        /* DC OK break : */
+        if (TZA_I_OK && TZA_Q_OK && BBA_I_OK && BBA_Q_OK)
+        {
+            break;
+        }
+
+        dc_meas_i_p = dc_meas_i; /* Store as previous value */
+        dc_meas_q_p = dc_meas_q; /* Store as previous value */
+        XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(curr_bba_dac_i) |
+                                     XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(curr_bba_dac_q) |
+                                     XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(curr_tza_dac_i) |
+                                     XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(curr_tza_dac_q);
+        XcvrCalDelay(TsettleCal * 2);
+        rx_dc_est_average(&dc_meas_i, &dc_meas_q, 64);
+    }
+
+    /* Apply optimized DCOC DAC INIT : */
+    XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(curr_bba_dac_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(curr_bba_dac_q) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_I(curr_tza_dac_i) |
+                                 XCVR_RX_DIG_DCOC_DAC_INIT_TZA_DCOC_INIT_Q(curr_tza_dac_q);
+
+    /* WarmDown */
+    if (standalone_operation)
+    {
+        XCVR_ForceRxWd(); /* Don't leave the receiver running. */
+        XcvrCalDelay(200);
+        XCVR_OverrideChannel(0xFF,1); /* Release channel overrides */
+        XCVR_MISC->XCVR_CTRL = xcvr_ctrl_stack;
+    }
+
+    /* Restore register */
+    XCVR_RX_DIG->DCOC_CTRL_0 = dcoc_ctrl_0_stack; /* Restore DCOC_CTRL_0 state to prior settings */
+    XCVR_RX_DIG->DCOC_CTRL_1 = dcoc_ctrl_1_stack; /* Restore DCOC_CTRL_1 state to prior settings */
+    XCVR_RX_DIG->RX_DIG_CTRL = rx_dig_ctrl_stack; /* Restore RX_DIG_CTRL state to prior settings */
+    XCVR_RX_DIG->DCOC_CAL_GAIN = dcoc_cal_gain_state; /* Restore DCOC_CAL_GAIN state to prior setting */
+    XCVR_RX_DIG->AGC_CTRL_1 = agc_ctrl_1_stack; /* Save state of RX_DIG_CTRL for later restore */
+}
+