1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/kw41zrf/kw41zrf_xcvr.c
Joakim Nohlgård 5bd67d88a8 drivers/kw41zrf: Transceiver driver for the KW41Z radio
This is the radio found in NXP Kinetis KW41Z, KW21Z. Only 802.15.4 mode
is implemented (KW41Z also supports BLE on the same transceiver).

The driver uses vendor supplied initialization code for the low level
XCVR hardware, these files were imported from KSDK 2.2.0 (framework_5.3.5)
2020-03-19 17:00:04 -05:00

914 lines
43 KiB
C

/*
* The Clear BSD License
* Copyright 2016-2017 NXP
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the
* disclaimer below) provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
* GRANTED BY THIS LICENSE. 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.
*/
/**
* @ingroup drivers_kw41zrf
* @{
* @file
* @brief NXP KW41Z XCVR module initialization and calibration of kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @}
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "log.h"
#include "bit.h"
#include "kw41zrf.h"
#include "vendor/XCVR/MKW41Z4/fsl_xcvr.h"
#include "vendor/XCVR/MKW41Z4/ifr_radio.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/* The implementations for these functions are taken from the vendor-provided
* XCVR driver from mcuxpresso.nxp.com (KSDK 2.2.0, framework_5.3.5)
* The code has been refactored to eliminate a lot of preprocessor
* conditionals. */
#define TsettleCal 10
#define DCOC_DAC_BBF_STEP (16)
#define RX_DC_EST_SAMPLES (64)
#define RX_DC_EST_TOTAL_SAMPLES (2 * (RX_DC_EST_SAMPLES))
/* Macros used by the calibration routine */
#define SAME_SIGN(a, b) (((a) ^ (b)) >= 0)
#define ABS(x) ((x) > 0 ? (x) : -(x))
/* dumb spin delay used in the calibration functions */
static void kw41zrf_xcvr_spin(uint32_t time)
{
time *= 32; /* Time delay is roughly in uSec. */
while (time > 0)
{
__asm__ volatile ("" ::: "memory");
--time;
}
}
/* Collect RX DC estimation samples */
static void rx_dc_est_samples(int32_t *i_sum, int32_t *q_sum, unsigned nsamples)
{
/* Wait for TSM to reach the end of warmup (unless you want to capture some samples during DCOC cal phase). */
uint32_t end_of_rx_wu = XCVR_CTRL_XCVR_STATUS_TSM_COUNT(
(XCVR_TSM->END_OF_SEQ & 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) != end_of_rx_wu) {};
int32_t sum_i = 0;
int32_t sum_q = 0;
/* Read DCOC DC EST register. */
for (unsigned k = 0; k < nsamples; k++)
{
uint32_t dc_temp = XCVR_RX_DIG->DCOC_DC_EST;
int16_t dc_meas_i = (dc_temp & XCVR_RX_DIG_DCOC_DC_EST_DC_EST_I_MASK) >> XCVR_RX_DIG_DCOC_DC_EST_DC_EST_I_SHIFT;
dc_meas_i = (int16_t)(dc_meas_i << 4) / 16; /* Sign extend from 12 to 16 bits. */
sum_i += dc_meas_i;
int16_t 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;
dc_meas_q = (int16_t)(dc_meas_q << 4) / 16; /* Sign extend from 12 to 16 bits. */
sum_q += dc_meas_q;
}
*i_sum = sum_i;
*q_sum = sum_q;
}
/* Unsigned integer division, rounded to nearest integer */
static inline uint32_t calc_div_rounded(uint32_t num, uint32_t den)
{
return (num + (den / 2)) / den;
}
int kw41zrf_rx_bba_dcoc_dac_trim_DCest(void)
{
/* Estimate the actual gain by measuring three points and approximating a line */
int status = 0;
/* Save register */
uint32_t dcoc_ctrl_0_stack = XCVR_RX_DIG->DCOC_CTRL_0; /* Save state of DCOC_CTRL_0 for later restore */
uint32_t dcoc_ctrl_1_stack = XCVR_RX_DIG->DCOC_CTRL_1; /* Save state of DCOC_CTRL_1 for later restore */
uint32_t rx_dig_ctrl_stack = XCVR_RX_DIG->RX_DIG_CTRL; /* Save state of RX_DIG_CTRL for later restore */
uint32_t agc_ctrl_1_stack = XCVR_RX_DIG->AGC_CTRL_1; /* Save state of RX_DIG_CTRL for later restore */
uint32_t 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 */
XCVR_RX_DIG->RX_DIG_CTRL = XCVR_RX_DIG->RX_DIG_CTRL &
~(XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN_MASK | /* Turn OFF AGC */
XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN_MASK | /* Disable for SW control of DCOC */
XCVR_RX_DIG_RX_DIG_CTRL_RX_DC_RESID_EN_MASK); /* Disable for SW control of DCOC */
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 */
XCVR_RX_DIG->DCOC_CTRL_0 = XCVR_RX_DIG->DCOC_CTRL_0 |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_MAN(1) | /* Enable Manual DCOC */
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(1) | /* Ensure DCOC Tracking is enabled */
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_TRK_EST_OVR(1) | /* Enable DC Estimator */
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_EN(1); /* Ensure DC correction is enabled */
/* Use reset defaults */
uint8_t bbf_dacinit_i = 0x20;
uint8_t bbf_dacinit_q = 0x20;
uint8_t tza_dacinit_i = 0x80;
uint8_t tza_dacinit_q = 0x80;
/* Set default DCOC DAC INIT Value */
XCVR_RX_DIG->DCOC_DAC_INIT =
XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i) |
XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q) |
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);
/* Store DCOC_DAC_INIT value */
uint32_t dcoc_init_reg_value_dcgain = XCVR_RX_DIG->DCOC_DAC_INIT;
kw41zrf_xcvr_spin(TsettleCal * 2);
uint32_t meas_sum = 0;
/* 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 - DCOC_DAC_BBF_STEP) |
XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q - DCOC_DAC_BBF_STEP) |
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);
kw41zrf_xcvr_spin(TsettleCal * 4);
int32_t dc_meas_im = 0;
int32_t dc_meas_qm = 0;
rx_dc_est_samples(&dc_meas_im, &dc_meas_qm, RX_DC_EST_SAMPLES);
/* BBF POS STEP */
XCVR_RX_DIG->DCOC_DAC_INIT = XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_I(bbf_dacinit_i + DCOC_DAC_BBF_STEP) |
XCVR_RX_DIG_DCOC_DAC_INIT_BBA_DCOC_INIT_Q(bbf_dacinit_q + DCOC_DAC_BBF_STEP) |
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);
kw41zrf_xcvr_spin(TsettleCal * 4);
int32_t dc_meas_ip = 0;
int32_t dc_meas_qp = 0;
rx_dc_est_samples(&dc_meas_ip, &dc_meas_qp, RX_DC_EST_SAMPLES);
DEBUG("dc_meas_i- = %" PRId32 "\n", dc_meas_im);
DEBUG("dc_meas_q- = %" PRId32 "\n", dc_meas_qm);
DEBUG("dc_meas_i+ = %" PRId32 "\n", dc_meas_ip);
DEBUG("dc_meas_q+ = %" PRId32 "\n", dc_meas_qp);
meas_sum += dc_meas_ip - dc_meas_im;
DEBUG("meas_sum = %" PRIu32 "\n", meas_sum);
meas_sum += dc_meas_qp - dc_meas_qm;
DEBUG("meas_sum = %" PRIu32 "\n", meas_sum);
meas_sum /= 2 * DCOC_DAC_BBF_STEP;
DEBUG("meas_sum = %" PRIu32 "\n", meas_sum);
XCVR_RX_DIG->DCOC_DAC_INIT = dcoc_init_reg_value_dcgain; /* Return DAC setting to initial */
/* Compute the average sampled gain for the measured steps */
/* Calculate BBF DCOC STEPS, RECIPROCALS */
/* meas_sum here is the average gain multiplied by (4 * RX_DC_EST_SAMPLES) */
/* Compute the gain average as a Q6.3 number */
/* rounded result, Q6.3 number */
uint16_t bbf_dcoc_gain_measured = calc_div_rounded(meas_sum, (RX_DC_EST_TOTAL_SAMPLES / (1u << 3)));
DEBUG("temp_step = %f\n", (float)meas_sum / RX_DC_EST_TOTAL_SAMPLES);
DEBUG("bbf_dcoc_gain_measured = %u\n", (unsigned)bbf_dcoc_gain_measured);
/* Check the measured value for validity. Should be in the range:
* 250 < bbf_dcoc_gain_measured < 305, according to NXP wireless framework v5.4.3 (MCUXpresso KW36 SDK)
*/
if ((250 < bbf_dcoc_gain_measured) & (bbf_dcoc_gain_measured < 305))
{
/* Compute reciprocal, as Q15 number, but only the 13 lowest bits are programmable */
/* rounded result, ((2**15) / slope) */
uint32_t bbf_dcoc_gain_measured_rcp = calc_div_rounded((1u << 15) * RX_DC_EST_TOTAL_SAMPLES, meas_sum);
DEBUG("bbf_dcoc_gain_measured_rcp = %"PRIu32"\n", bbf_dcoc_gain_measured_rcp);
uint32_t bbf_dcoc_gain_default =
(xcvr_common_config.dcoc_bba_step_init &
XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_MASK) >>
XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_SHIFT;
/* Rescale all default TZA DCOC gains according to the measured BBF gain,
* using (bbf_dcoc_gain_measured / bbf_dcoc_gain_default) as the implicit
* scale factor, but rewrite it to use
* (meas_sum / (bbf_dcoc_gain_default * RX_DC_EST_TOTAL_SAMPLES / (1u << 3))))
* for better numeric precision */
/* rounded result, Q9.3 number */
bbf_dcoc_gain_default *= (RX_DC_EST_TOTAL_SAMPLES / (1u << 3));
DEBUG("base gain = %u\n", (unsigned)bbf_dcoc_gain_default);
/* Make the trims active */
XCVR_RX_DIG->DCOC_BBA_STEP =
XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP(bbf_dcoc_gain_measured) |
XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_RECIP(bbf_dcoc_gain_measured_rcp);
const uint32_t *dcoc_tza_step_config_ptr = &xcvr_common_config.dcoc_tza_step_00_init;
/* All tza_step_* configuration registers use sequential memory addresses */
volatile uint32_t *xcvr_rx_dig_dcoc_tza_step_ptr = &XCVR_RX_DIG->DCOC_TZA_STEP_0;
for (unsigned k = 0; k <= 10; ++k)
{
/* Calculate TZA DCOC STEPSIZE & its RECIPROCAL */
uint16_t tza_gain_default =
(dcoc_tza_step_config_ptr[k] &
XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0_MASK) >>
XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0_SHIFT;
/* Using meas_sum for higher precision */
DEBUG("tza_gain_default[%u] = %u\n", k, (unsigned)tza_gain_default);
uint32_t dcoc_step = calc_div_rounded(tza_gain_default * meas_sum, bbf_dcoc_gain_default);
uint32_t dcoc_step_rcp = calc_div_rounded((0x8000ul << 3) * bbf_dcoc_gain_default, tza_gain_default * meas_sum);
DEBUG("tza_dcoc_step[%u].dcoc_step = %u\n", k, (unsigned)dcoc_step);
DEBUG("tza_dcoc_step[%u].dcoc_step_rcp = %u\n", k, (unsigned)dcoc_step_rcp);
xcvr_rx_dig_dcoc_tza_step_ptr[k] =
XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0(dcoc_step) |
XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_RCP_0(dcoc_step_rcp) ;
}
}
else
{
LOG_ERROR("!!! XCVR trim failed: bbf_dcoc_step = %u!\n", (unsigned)bbf_dcoc_gain_measured);
status = -EAGAIN; /* 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;
}
static void kw41zrf_dcoc_dac_init_cal(void)
{
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;
uint8_t TZA_I_OK = 0, TZA_Q_OK = 0, BBA_I_OK = 0, BBA_Q_OK = 0;
uint32_t temp;
/* Save registers */
uint32_t dcoc_ctrl_0_stack = XCVR_RX_DIG->DCOC_CTRL_0; /* Save state of DCOC_CTRL_0 for later restore */
uint32_t dcoc_ctrl_1_stack = XCVR_RX_DIG->DCOC_CTRL_1; /* Save state of DCOC_CTRL_1 for later restore */
uint32_t rx_dig_ctrl_stack = XCVR_RX_DIG->RX_DIG_CTRL; /* Save state of RX_DIG_CTRL for later restore */
uint32_t agc_ctrl_1_stack = XCVR_RX_DIG->AGC_CTRL_1; /* Save state of RX_DIG_CTRL for later restore */
uint32_t 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;
kw41zrf_xcvr_spin(TsettleCal);
/* Set default DCOC DAC INIT Value */
/* LNA and BBA DAC Sweep */
uint8_t curr_bba_dac_i = 0x20;
uint8_t curr_bba_dac_q = 0x20;
uint8_t curr_tza_dac_i = 0x80;
uint8_t 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);
int32_t dc_meas_i = 2000, dc_meas_i_p = 2000;
int32_t dc_meas_q = 2000, dc_meas_q_p = 2000;
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 */
kw41zrf_xcvr_spin(TsettleCal * 2);
rx_dc_est_samples(&dc_meas_i, &dc_meas_q, RX_DC_EST_SAMPLES);
DEBUG("rx i=%d q=%d\n", (int)dc_meas_i, (int)dc_meas_q);
dc_meas_i /= RX_DC_EST_SAMPLES;
dc_meas_q /= RX_DC_EST_SAMPLES;
DEBUG("rx i=%d q=%d\n", (int)dc_meas_i, (int)dc_meas_q);
DEBUG("[kw41zrf] bba_gain=%u, meas I=%" PRId32 ", Q=%" PRId32 "\n", (unsigned)bba_gain, dc_meas_i, dc_meas_q);
} while ((ABS(dc_meas_i) > 1900) || (ABS(dc_meas_q) > 1900));
for (i = 0; i < 0x0F; i++)
{
DEBUG("rx i=%d q=%d\n", (int)dc_meas_i, (int)dc_meas_q);
/* I channel : */
if (!TZA_I_OK) {
if ((i > 0) && (!SAME_SIGN(dc_meas_i, dc_meas_i_p))) {
if (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 (dc_meas_i > 0) {
curr_tza_dac_i--;
}
else {
curr_tza_dac_i++;
}
}
}
else if (!BBA_I_OK) {
/* Sweep BBA I */
if ((curr_bba_dac_i != 0x20) && (!SAME_SIGN(dc_meas_i, dc_meas_i_p))) {
if (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 (dc_meas_i > 0) {
curr_bba_dac_i--;
}
else {
curr_bba_dac_i++;
}
}
}
/* Q channel : */
if (!TZA_Q_OK) {
if ((i > 0) && (!SAME_SIGN(dc_meas_q, dc_meas_q_p))) {
if (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 (dc_meas_q > 0) {
curr_tza_dac_q--;
}
else {
curr_tza_dac_q++;
}
}
}
else if (!BBA_Q_OK) {
/* Sweep BBA Q */
if ((curr_bba_dac_q != 0x20) && (!SAME_SIGN(dc_meas_q, dc_meas_q_p))) {
if (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 (dc_meas_q > 0) {
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 */
DEBUG("curr_bba_dac i=%d q=%d\n", (int)curr_bba_dac_i, (int)curr_bba_dac_q);
DEBUG("curr_tza_dac i=%d q=%d\n", (int)curr_tza_dac_i, (int)curr_tza_dac_q);
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);
kw41zrf_xcvr_spin(TsettleCal * 2);
rx_dc_est_samples(&dc_meas_i, &dc_meas_q, RX_DC_EST_SAMPLES);
dc_meas_i /= RX_DC_EST_SAMPLES;
dc_meas_q /= RX_DC_EST_SAMPLES;
}
/* 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);
/* 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 */
}
static int kw41zrf_xcvr_configure(kw41zrf_t *dev,
const xcvr_common_config_t *com_config,
const xcvr_mode_config_t *mode_config,
const xcvr_mode_datarate_config_t *mode_datarate_config,
const xcvr_datarate_config_t *datarate_config)
{
(void)dev;
int config_status = 0;
uint32_t temp;
/* Turn on the module clocks before doing anything */
SIM->SCGC5 |= mode_config->scgc5_clock_ena_bits;
/* XCVR_ANA configs */
/* Configure PLL Loop Filter */
XCVR_ANA->SY_CTRL_1 &= ~com_config->ana_sy_ctrl1.mask;
XCVR_ANA->SY_CTRL_1 |= com_config->ana_sy_ctrl1.init;
/* Configure VCO KVM */
XCVR_ANA->SY_CTRL_2 &= ~mode_datarate_config->ana_sy_ctrl2.mask;
XCVR_ANA->SY_CTRL_2 |= mode_datarate_config->ana_sy_ctrl2.init;
/* Configure analog filter bandwidth */
XCVR_ANA->RX_BBA &= ~mode_datarate_config->ana_rx_bba.mask;
XCVR_ANA->RX_BBA |= mode_datarate_config->ana_rx_bba.init;
XCVR_ANA->RX_TZA &= ~mode_datarate_config->ana_rx_tza.mask;
XCVR_ANA->RX_TZA |= mode_datarate_config->ana_rx_tza.init;
temp = XCVR_ANA->TX_DAC_PA;
temp &= ~XCVR_ANALOG_TX_DAC_PA_TX_PA_BUMP_VBIAS_MASK;
temp |= XCVR_ANALOG_TX_DAC_PA_TX_PA_BUMP_VBIAS(4);
XCVR_ANA->TX_DAC_PA = temp;
temp = XCVR_ANA->BB_LDO_2;
temp &= ~XCVR_ANALOG_BB_LDO_2_BB_LDO_VCOLO_TRIM_MASK;
temp |= XCVR_ANALOG_BB_LDO_2_BB_LDO_VCOLO_TRIM(0);
XCVR_ANA->BB_LDO_2 = temp;
temp = XCVR_ANA->RX_LNA;
temp &= ~XCVR_ANALOG_RX_LNA_RX_LNA_BUMP_MASK;
temp |= XCVR_ANALOG_RX_LNA_RX_LNA_BUMP(1);
XCVR_ANA->RX_LNA = temp;
temp = XCVR_ANA->BB_LDO_1;
temp &= ~XCVR_ANALOG_BB_LDO_1_BB_LDO_FDBK_TRIM_MASK;
temp |= XCVR_ANALOG_BB_LDO_1_BB_LDO_FDBK_TRIM(1);
XCVR_ANA->BB_LDO_1 = temp;
/* XCVR_MISC configs */
temp = XCVR_MISC->XCVR_CTRL;
temp &= ~(mode_config->xcvr_ctrl.mask | XCVR_CTRL_XCVR_CTRL_REF_CLK_FREQ_MASK);
temp |= mode_config->xcvr_ctrl.init;
if (CLOCK_RADIOXTAL == 26000000ul) {
temp |= XCVR_CTRL_XCVR_CTRL_REF_CLK_FREQ(1);
}
XCVR_MISC->XCVR_CTRL = temp;
/* XCVR_PHY configs */
XCVR_PHY->PHY_PRE_REF0 = mode_config->phy_pre_ref0_init;
XCVR_PHY->PRE_REF1 = mode_config->phy_pre_ref1_init;
XCVR_PHY->PRE_REF2 = mode_config->phy_pre_ref2_init;
XCVR_PHY->CFG1 = mode_config->phy_cfg1_init;
XCVR_PHY->CFG2 = mode_datarate_config->phy_cfg2_init;
XCVR_PHY->EL_CFG = mode_config->phy_el_cfg_init | datarate_config->phy_el_cfg_init; /* EL_WIN_SIZE and EL_INTERVAL are datarate dependent, */
/* XCVR_PLL_DIG configs */
XCVR_PLL_DIG->HPM_BUMP = com_config->pll_hpm_bump;
XCVR_PLL_DIG->MOD_CTRL = com_config->pll_mod_ctrl;
XCVR_PLL_DIG->CHAN_MAP = com_config->pll_chan_map;
XCVR_PLL_DIG->LOCK_DETECT = com_config->pll_lock_detect;
XCVR_PLL_DIG->HPM_CTRL = com_config->pll_hpm_ctrl;
XCVR_PLL_DIG->HPMCAL_CTRL = com_config->pll_hpmcal_ctrl;
XCVR_PLL_DIG->HPM_SDM_RES = com_config->pll_hpm_sdm_res;
XCVR_PLL_DIG->LPM_CTRL = com_config->pll_lpm_ctrl;
XCVR_PLL_DIG->LPM_SDM_CTRL1 = com_config->pll_lpm_sdm_ctrl1;
XCVR_PLL_DIG->DELAY_MATCH = com_config->pll_delay_match;
XCVR_PLL_DIG->CTUNE_CTRL = com_config->pll_ctune_ctrl;
/* XCVR_RX_DIG configs */
/* Configure RF Aux PLL for proper operation based on external clock frequency */
temp = XCVR_ANA->RX_AUXPLL;
temp &= ~XCVR_ANALOG_RX_AUXPLL_VCO_DAC_REF_ADJUST_MASK;
if (CLOCK_RADIOXTAL == 26000000ul) {
temp |= XCVR_ANALOG_RX_AUXPLL_VCO_DAC_REF_ADJUST(4);
}
else {
temp |= XCVR_ANALOG_RX_AUXPLL_VCO_DAC_REF_ADJUST(7);
}
XCVR_ANA->RX_AUXPLL = temp;
/* Configure RX_DIG_CTRL */
if (CLOCK_RADIOXTAL == 26000000ul) {
temp = com_config->rx_dig_ctrl_init | /* Common portion of RX_DIG_CTRL init */
mode_config->rx_dig_ctrl_init_26mhz | /* Mode specific portion of RX_DIG_CTRL init */
datarate_config->rx_dig_ctrl_init_26mhz | /* Datarate specific portion of RX_DIG_CTRL init */
XCVR_RX_DIG_RX_DIG_CTRL_RX_SRC_EN_MASK; /* Always enable the sample rate converter for 26MHz */
}
else {
temp = com_config->rx_dig_ctrl_init | /* Common portion of RX_DIG_CTRL init */
mode_config->rx_dig_ctrl_init_32mhz | /* Mode specific portion of RX_DIG_CTRL init */
datarate_config->rx_dig_ctrl_init_32mhz | /* Datarate specific portion of RX_DIG_CTRL init */
0; /* Always disable the sample rate converter for 32MHz */
}
temp |= com_config->rx_dig_ctrl_init; /* Common portion of RX_DIG_CTRL init */
XCVR_RX_DIG->RX_DIG_CTRL = temp;
/* DCOC_CAL_IIR */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_RX_DIG->DCOC_CAL_IIR = datarate_config->dcoc_cal_iir_init_26mhz;
}
else {
XCVR_RX_DIG->DCOC_CAL_IIR = datarate_config->dcoc_cal_iir_init_32mhz;
}
/* DC_RESID_CTRL */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_RX_DIG->DC_RESID_CTRL = com_config->dc_resid_ctrl_init | datarate_config->dc_resid_ctrl_26mhz;
}
else {
XCVR_RX_DIG->DC_RESID_CTRL = com_config->dc_resid_ctrl_init | datarate_config->dc_resid_ctrl_32mhz;
}
/* DCOC_CTRL_0 & _1 */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_RX_DIG->DCOC_CTRL_0 = com_config->dcoc_ctrl_0_init_26mhz | datarate_config->dcoc_ctrl_0_init_26mhz; /* Combine common and datarate specific settings */
XCVR_RX_DIG->DCOC_CTRL_1 = com_config->dcoc_ctrl_1_init | datarate_config->dcoc_ctrl_1_init_26mhz; /* Combine common and datarate specific settings */
/* customize DCOC_CTRL_0 settings for Gen2 GFSK BT=0.5, h=0.32 */
if ((mode_config->radio_mode == ANT_MODE) || (mode_config->radio_mode == GFSK_BT_0p5_h_0p32))
{
if (datarate_config->data_rate == DR_1MBPS) /* only apply fix to 1Mbps data rates */
{
/* apply the changes to the DCOC_CTRL_0 register XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY & XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME */
temp = XCVR_RX_DIG->DCOC_CTRL_0;
temp &= ~XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY_MASK | XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME_MASK;
temp |= XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(0x10) | XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(0x0C);
XCVR_RX_DIG->DCOC_CTRL_0 = temp;
}
}
}
else {
XCVR_RX_DIG->DCOC_CTRL_0 = com_config->dcoc_ctrl_0_init_32mhz | datarate_config->dcoc_ctrl_0_init_32mhz; /* Combine common and datarate specific settings */
XCVR_RX_DIG->DCOC_CTRL_1 = com_config->dcoc_ctrl_1_init | datarate_config->dcoc_ctrl_1_init_32mhz; /* Combine common and datarate specific settings */
}
/* DCOC_CAL_GAIN */
XCVR_RX_DIG->DCOC_CAL_GAIN = com_config->dcoc_cal_gain_init;
/* DCOC_CAL_RCP */
XCVR_RX_DIG->DCOC_CAL_RCP = com_config->dcoc_cal_rcp_init;
XCVR_RX_DIG->LNA_GAIN_VAL_3_0 = com_config->lna_gain_val_3_0;
XCVR_RX_DIG->LNA_GAIN_VAL_7_4 = com_config->lna_gain_val_7_4;
XCVR_RX_DIG->LNA_GAIN_VAL_8 = com_config->lna_gain_val_8;
XCVR_RX_DIG->BBA_RES_TUNE_VAL_7_0 = com_config->bba_res_tune_val_7_0;
XCVR_RX_DIG->BBA_RES_TUNE_VAL_10_8 = com_config->bba_res_tune_val_10_8;
/* LNA_GAIN_LIN_VAL */
XCVR_RX_DIG->LNA_GAIN_LIN_VAL_2_0 = com_config->lna_gain_lin_val_2_0_init;
XCVR_RX_DIG->LNA_GAIN_LIN_VAL_5_3 = com_config->lna_gain_lin_val_5_3_init;
XCVR_RX_DIG->LNA_GAIN_LIN_VAL_8_6 = com_config->lna_gain_lin_val_8_6_init;
XCVR_RX_DIG->LNA_GAIN_LIN_VAL_9 = com_config->lna_gain_lin_val_9_init;
/* BBA_RES_TUNE_LIN_VAL */
XCVR_RX_DIG->BBA_RES_TUNE_LIN_VAL_3_0 = com_config->bba_res_tune_lin_val_3_0_init;
XCVR_RX_DIG->BBA_RES_TUNE_LIN_VAL_7_4 = com_config->bba_res_tune_lin_val_7_4_init;
XCVR_RX_DIG->BBA_RES_TUNE_LIN_VAL_10_8 = com_config->bba_res_tune_lin_val_10_8_init;
/* BBA_STEP */
XCVR_RX_DIG->DCOC_BBA_STEP = com_config->dcoc_bba_step_init;
/* DCOC_TZA_STEP */
XCVR_RX_DIG->DCOC_TZA_STEP_0 = com_config->dcoc_tza_step_00_init;
XCVR_RX_DIG->DCOC_TZA_STEP_1 = com_config->dcoc_tza_step_01_init;
XCVR_RX_DIG->DCOC_TZA_STEP_2 = com_config->dcoc_tza_step_02_init;
XCVR_RX_DIG->DCOC_TZA_STEP_3 = com_config->dcoc_tza_step_03_init;
XCVR_RX_DIG->DCOC_TZA_STEP_4 = com_config->dcoc_tza_step_04_init;
XCVR_RX_DIG->DCOC_TZA_STEP_5 = com_config->dcoc_tza_step_05_init;
XCVR_RX_DIG->DCOC_TZA_STEP_6 = com_config->dcoc_tza_step_06_init;
XCVR_RX_DIG->DCOC_TZA_STEP_7 = com_config->dcoc_tza_step_07_init;
XCVR_RX_DIG->DCOC_TZA_STEP_8 = com_config->dcoc_tza_step_08_init;
XCVR_RX_DIG->DCOC_TZA_STEP_9 = com_config->dcoc_tza_step_09_init;
XCVR_RX_DIG->DCOC_TZA_STEP_10 = com_config->dcoc_tza_step_10_init;
/* AGC_CTRL_0 .. _3 */
XCVR_RX_DIG->AGC_CTRL_0 = com_config->agc_ctrl_0_init | mode_config->agc_ctrl_0_init;
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_RX_DIG->AGC_CTRL_1 = com_config->agc_ctrl_1_init_26mhz | datarate_config->agc_ctrl_1_init_26mhz; /* Combine common and datarate specific settings */
XCVR_RX_DIG->AGC_CTRL_2 = mode_datarate_config->agc_ctrl_2_init_26mhz;
}
else {
XCVR_RX_DIG->AGC_CTRL_1 = com_config->agc_ctrl_1_init_32mhz | datarate_config->agc_ctrl_1_init_32mhz; /* Combine common and datarate specific settings */
XCVR_RX_DIG->AGC_CTRL_2 = mode_datarate_config->agc_ctrl_2_init_32mhz;
}
XCVR_RX_DIG->AGC_CTRL_3 = com_config->agc_ctrl_3_init;
/* AGC_GAIN_TBL_** */
XCVR_RX_DIG->AGC_GAIN_TBL_03_00 = com_config->agc_gain_tbl_03_00_init;
XCVR_RX_DIG->AGC_GAIN_TBL_07_04 = com_config->agc_gain_tbl_07_04_init;
XCVR_RX_DIG->AGC_GAIN_TBL_11_08 = com_config->agc_gain_tbl_11_08_init;
XCVR_RX_DIG->AGC_GAIN_TBL_15_12 = com_config->agc_gain_tbl_15_12_init;
XCVR_RX_DIG->AGC_GAIN_TBL_19_16 = com_config->agc_gain_tbl_19_16_init;
XCVR_RX_DIG->AGC_GAIN_TBL_23_20 = com_config->agc_gain_tbl_23_20_init;
XCVR_RX_DIG->AGC_GAIN_TBL_26_24 = com_config->agc_gain_tbl_26_24_init;
/* RSSI_CTRL_0 */
XCVR_RX_DIG->RSSI_CTRL_0 = com_config->rssi_ctrl_0_init;
/* CCA_ED_LQI_0 and _1 */
XCVR_RX_DIG->CCA_ED_LQI_CTRL_0 = com_config->cca_ed_lqi_ctrl_0_init;
XCVR_RX_DIG->CCA_ED_LQI_CTRL_1 = com_config->cca_ed_lqi_ctrl_1_init;
/* Channel filter coefficients */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_RX_DIG->RX_CHF_COEF_0 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_0;
XCVR_RX_DIG->RX_CHF_COEF_1 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_1;
XCVR_RX_DIG->RX_CHF_COEF_2 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_2;
XCVR_RX_DIG->RX_CHF_COEF_3 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_3;
XCVR_RX_DIG->RX_CHF_COEF_4 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_4;
XCVR_RX_DIG->RX_CHF_COEF_5 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_5;
XCVR_RX_DIG->RX_CHF_COEF_6 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_6;
XCVR_RX_DIG->RX_CHF_COEF_7 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_7;
XCVR_RX_DIG->RX_CHF_COEF_8 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_8;
XCVR_RX_DIG->RX_CHF_COEF_9 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_9;
XCVR_RX_DIG->RX_CHF_COEF_10 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_10;
XCVR_RX_DIG->RX_CHF_COEF_11 = mode_datarate_config->rx_chf_coeffs_26mhz.rx_chf_coef_11;
}
else {
XCVR_RX_DIG->RX_CHF_COEF_0 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_0;
XCVR_RX_DIG->RX_CHF_COEF_1 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_1;
XCVR_RX_DIG->RX_CHF_COEF_2 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_2;
XCVR_RX_DIG->RX_CHF_COEF_3 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_3;
XCVR_RX_DIG->RX_CHF_COEF_4 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_4;
XCVR_RX_DIG->RX_CHF_COEF_5 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_5;
XCVR_RX_DIG->RX_CHF_COEF_6 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_6;
XCVR_RX_DIG->RX_CHF_COEF_7 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_7;
XCVR_RX_DIG->RX_CHF_COEF_8 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_8;
XCVR_RX_DIG->RX_CHF_COEF_9 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_9;
XCVR_RX_DIG->RX_CHF_COEF_10 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_10;
XCVR_RX_DIG->RX_CHF_COEF_11 = mode_datarate_config->rx_chf_coeffs_32mhz.rx_chf_coef_11;
}
XCVR_RX_DIG->RX_RCCAL_CTRL0 = mode_datarate_config->rx_rccal_ctrl_0;
XCVR_RX_DIG->RX_RCCAL_CTRL1 = mode_datarate_config->rx_rccal_ctrl_1;
/* XCVR_TSM configs */
XCVR_TSM->CTRL = com_config->tsm_ctrl;
if ((mode_config->radio_mode != ZIGBEE_MODE) && (mode_config->radio_mode != BLE_MODE))
{
XCVR_TSM->CTRL &= ~XCVR_TSM_CTRL_DATA_PADDING_EN_MASK;
}
XCVR_MISC->LPPS_CTRL = com_config->lpps_ctrl_init; /* Register is in XCVR_MISC but grouped with TSM for initialization */
XCVR_TSM->OVRD2 = com_config->tsm_ovrd2_init;
/* TSM registers and timings - dependent upon clock frequency */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_TSM->END_OF_SEQ = com_config->end_of_seq_init_26mhz;
XCVR_TSM->FAST_CTRL2 = com_config->tsm_fast_ctrl2_init_26mhz;
XCVR_TSM->RECYCLE_COUNT = com_config->recycle_count_init_26mhz;
XCVR_TSM->TIMING14 = com_config->tsm_timing_14_init_26mhz;
XCVR_TSM->TIMING16 = com_config->tsm_timing_16_init_26mhz;
XCVR_TSM->TIMING25 = com_config->tsm_timing_25_init_26mhz;
XCVR_TSM->TIMING27 = com_config->tsm_timing_27_init_26mhz;
XCVR_TSM->TIMING28 = com_config->tsm_timing_28_init_26mhz;
XCVR_TSM->TIMING29 = com_config->tsm_timing_29_init_26mhz;
XCVR_TSM->TIMING30 = com_config->tsm_timing_30_init_26mhz;
XCVR_TSM->TIMING31 = com_config->tsm_timing_31_init_26mhz;
XCVR_TSM->TIMING32 = com_config->tsm_timing_32_init_26mhz;
XCVR_TSM->TIMING33 = com_config->tsm_timing_33_init_26mhz;
XCVR_TSM->TIMING36 = com_config->tsm_timing_36_init_26mhz;
XCVR_TSM->TIMING37 = com_config->tsm_timing_37_init_26mhz;
XCVR_TSM->TIMING39 = com_config->tsm_timing_39_init_26mhz;
XCVR_TSM->TIMING40 = com_config->tsm_timing_40_init_26mhz;
XCVR_TSM->TIMING41 = com_config->tsm_timing_41_init_26mhz;
XCVR_TSM->TIMING52 = com_config->tsm_timing_52_init_26mhz;
XCVR_TSM->TIMING54 = com_config->tsm_timing_54_init_26mhz;
XCVR_TSM->TIMING55 = com_config->tsm_timing_55_init_26mhz;
XCVR_TSM->TIMING56 = com_config->tsm_timing_56_init_26mhz;
}
else {
XCVR_TSM->END_OF_SEQ = com_config->end_of_seq_init_32mhz;
XCVR_TSM->FAST_CTRL2 = com_config->tsm_fast_ctrl2_init_32mhz;
XCVR_TSM->RECYCLE_COUNT = com_config->recycle_count_init_32mhz;
XCVR_TSM->TIMING14 = com_config->tsm_timing_14_init_32mhz;
XCVR_TSM->TIMING16 = com_config->tsm_timing_16_init_32mhz;
XCVR_TSM->TIMING25 = com_config->tsm_timing_25_init_32mhz;
XCVR_TSM->TIMING27 = com_config->tsm_timing_27_init_32mhz;
XCVR_TSM->TIMING28 = com_config->tsm_timing_28_init_32mhz;
XCVR_TSM->TIMING29 = com_config->tsm_timing_29_init_32mhz;
XCVR_TSM->TIMING30 = com_config->tsm_timing_30_init_32mhz;
XCVR_TSM->TIMING31 = com_config->tsm_timing_31_init_32mhz;
XCVR_TSM->TIMING32 = com_config->tsm_timing_32_init_32mhz;
XCVR_TSM->TIMING33 = com_config->tsm_timing_33_init_32mhz;
XCVR_TSM->TIMING36 = com_config->tsm_timing_36_init_32mhz;
XCVR_TSM->TIMING37 = com_config->tsm_timing_37_init_32mhz;
XCVR_TSM->TIMING39 = com_config->tsm_timing_39_init_32mhz;
XCVR_TSM->TIMING40 = com_config->tsm_timing_40_init_32mhz;
XCVR_TSM->TIMING41 = com_config->tsm_timing_41_init_32mhz;
XCVR_TSM->TIMING52 = com_config->tsm_timing_52_init_32mhz;
XCVR_TSM->TIMING54 = com_config->tsm_timing_54_init_32mhz;
XCVR_TSM->TIMING55 = com_config->tsm_timing_55_init_32mhz;
XCVR_TSM->TIMING56 = com_config->tsm_timing_56_init_32mhz;
}
/* TSM timings independent of clock frequency */
XCVR_TSM->TIMING00 = com_config->tsm_timing_00_init;
XCVR_TSM->TIMING01 = com_config->tsm_timing_01_init;
XCVR_TSM->TIMING02 = com_config->tsm_timing_02_init;
XCVR_TSM->TIMING03 = com_config->tsm_timing_03_init;
XCVR_TSM->TIMING04 = com_config->tsm_timing_04_init;
XCVR_TSM->TIMING05 = com_config->tsm_timing_05_init;
XCVR_TSM->TIMING06 = com_config->tsm_timing_06_init;
XCVR_TSM->TIMING07 = com_config->tsm_timing_07_init;
XCVR_TSM->TIMING08 = com_config->tsm_timing_08_init;
XCVR_TSM->TIMING09 = com_config->tsm_timing_09_init;
XCVR_TSM->TIMING10 = com_config->tsm_timing_10_init;
XCVR_TSM->TIMING11 = com_config->tsm_timing_11_init;
XCVR_TSM->TIMING12 = com_config->tsm_timing_12_init;
XCVR_TSM->TIMING13 = com_config->tsm_timing_13_init;
XCVR_TSM->TIMING15 = com_config->tsm_timing_15_init;
XCVR_TSM->TIMING17 = com_config->tsm_timing_17_init;
XCVR_TSM->TIMING18 = com_config->tsm_timing_18_init;
XCVR_TSM->TIMING19 = com_config->tsm_timing_19_init;
XCVR_TSM->TIMING20 = com_config->tsm_timing_20_init;
XCVR_TSM->TIMING21 = com_config->tsm_timing_21_init;
XCVR_TSM->TIMING22 = com_config->tsm_timing_22_init;
XCVR_TSM->TIMING23 = com_config->tsm_timing_23_init;
XCVR_TSM->TIMING24 = com_config->tsm_timing_24_init;
XCVR_TSM->TIMING26 = com_config->tsm_timing_26_init;
XCVR_TSM->TIMING34 = com_config->tsm_timing_34_init;
XCVR_TSM->TIMING35 = com_config->tsm_timing_35_init;
XCVR_TSM->TIMING38 = com_config->tsm_timing_38_init;
XCVR_TSM->TIMING51 = com_config->tsm_timing_51_init;
XCVR_TSM->TIMING53 = com_config->tsm_timing_53_init;
XCVR_TSM->TIMING57 = com_config->tsm_timing_57_init;
XCVR_TSM->TIMING58 = com_config->tsm_timing_58_init;
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_TSM->END_OF_SEQ = XCVR_TSM_END_OF_SEQ_END_OF_TX_WU(END_OF_TX_WU) |
XCVR_TSM_END_OF_SEQ_END_OF_TX_WD(END_OF_TX_WD) |
XCVR_TSM_END_OF_SEQ_END_OF_RX_WU(END_OF_RX_WU_26MHZ) |
XCVR_TSM_END_OF_SEQ_END_OF_RX_WD(END_OF_RX_WD_26MHZ);
}
else {
XCVR_TSM->END_OF_SEQ = XCVR_TSM_END_OF_SEQ_END_OF_TX_WU(END_OF_TX_WU) |
XCVR_TSM_END_OF_SEQ_END_OF_TX_WD(END_OF_TX_WD) |
XCVR_TSM_END_OF_SEQ_END_OF_RX_WU(END_OF_RX_WU) |
XCVR_TSM_END_OF_SEQ_END_OF_RX_WD(END_OF_RX_WD);
}
XCVR_TSM->PA_RAMP_TBL0 = com_config->pa_ramp_tbl_0_init;
XCVR_TSM->PA_RAMP_TBL1 = com_config->pa_ramp_tbl_1_init;
if ((mode_datarate_config->radio_mode == MSK) && ((mode_datarate_config->data_rate == DR_500KBPS) || (mode_datarate_config->data_rate == DR_250KBPS))) {
/* Apply a specific value of TX_DIG_EN which assumes no DATA PADDING */
XCVR_TSM->TIMING35 = com_config->tsm_timing_35_init | B0(TX_DIG_EN_ASSERT_MSK500); /* LSbyte is mode specific */
}
else {
XCVR_TSM->TIMING35 = com_config->tsm_timing_35_init | mode_config->tsm_timing_35_init; /* LSbyte is mode specific, other bytes are common */
}
/* XCVR_TX_DIG configs */
if (CLOCK_RADIOXTAL == 26000000ul) {
XCVR_TX_DIG->FSK_SCALE = mode_datarate_config->tx_fsk_scale_26mhz; /* Applies only to 802.15.4 & MSK but won't harm other protocols */
XCVR_TX_DIG->GFSK_COEFF1 = mode_config->tx_gfsk_coeff1_26mhz;
XCVR_TX_DIG->GFSK_COEFF2 = mode_config->tx_gfsk_coeff2_26mhz;
}
else {
XCVR_TX_DIG->FSK_SCALE = mode_datarate_config->tx_fsk_scale_32mhz; /* Applies only to 802.15.4 & MSK but won't harm other protocols */
XCVR_TX_DIG->GFSK_COEFF1 = mode_config->tx_gfsk_coeff1_32mhz;
XCVR_TX_DIG->GFSK_COEFF2 = mode_config->tx_gfsk_coeff2_32mhz;
}
XCVR_TX_DIG->CTRL = com_config->tx_ctrl;
XCVR_TX_DIG->DATA_PADDING = com_config->tx_data_padding;
XCVR_TX_DIG->DFT_PATTERN = com_config->tx_dft_pattern;
XCVR_TX_DIG->RF_DFT_BIST_1 = com_config->rf_dft_bist_1;
XCVR_TX_DIG->RF_DFT_BIST_2 = com_config->rf_dft_bist_2;
XCVR_TX_DIG->GFSK_CTRL = mode_config->tx_gfsk_ctrl;
/* Force receiver warmup */
bit_set32(&XCVR_TSM->CTRL, XCVR_TSM_CTRL_FORCE_RX_EN_SHIFT);
/* Wait for TSM to reach the end of warmup (unless you want to capture some samples during DCOC cal phase) */
uint32_t end_of_rx_wu = XCVR_CTRL_XCVR_STATUS_TSM_COUNT(
(XCVR_TSM->END_OF_SEQ & 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) != end_of_rx_wu) {};
int res = kw41zrf_rx_bba_dcoc_dac_trim_DCest();
if (res < 0) {
config_status = res;
}
//~ DCOC_DAC_INIT_Cal(0);
kw41zrf_dcoc_dac_init_cal();
/* Force receiver warmdown */
bit_clear32(&XCVR_TSM->CTRL, XCVR_TSM_CTRL_FORCE_RX_EN_SHIFT);
return config_status;
}
int kw41zrf_xcvr_init(kw41zrf_t *dev)
{
(void) dev;
uint8_t radio_id = ((RSIM->MISC & RSIM_MISC_RADIO_VERSION_MASK) >> RSIM_MISC_RADIO_VERSION_SHIFT);
switch (radio_id) {
case 0x3: /* KW41/31/21 v1 */
case 0xb: /* KW41/31/21 v1.1 */
break;
default:
return -ENODEV;
}
RSIM->RF_OSC_CTRL = (RSIM->RF_OSC_CTRL &
~(RSIM_RF_OSC_CTRL_RADIO_EXT_OSC_OVRD_MASK)) | /* Set EXT_OSC_OVRD value to zero */
RSIM_RF_OSC_CTRL_RADIO_EXT_OSC_OVRD_EN_MASK; /* Enable over-ride with zero value */
bit_set32(&SIM->SCGC5, SIM_SCGC5_PHYDIG_SHIFT); /* Enable PHY clock gate */
/* Load IFR trim values */
IFR_SW_TRIM_TBL_ENTRY_T sw_trim_tbl[] =
{
{TRIM_STATUS, 0, 0}, /*< Fetch the trim status word if available.*/
{TRIM_VERSION, 0, 0} /*< Fetch the trim version number if available.*/
};
handle_ifr(&sw_trim_tbl[0], ARRAY_SIZE(sw_trim_tbl));
DEBUG("[kw41zrf] sw_trim_tbl:\n");
for (unsigned k = 0; k < ARRAY_SIZE(sw_trim_tbl); ++k) {
DEBUG("[kw41zrf] [%u] id=0x%04x ", k, (unsigned)sw_trim_tbl[k].trim_id);
if (sw_trim_tbl[k].trim_id == TRIM_STATUS) {
DEBUG("(TRIM_STATUS) ");
}
else if (sw_trim_tbl[k].trim_id == TRIM_VERSION) {
DEBUG("(TRIM_VERSION) ");
}
DEBUG("value=%" PRIu32 ", valid=%u\n", sw_trim_tbl[k].trim_value,
(unsigned)sw_trim_tbl[k].valid);
}
/* We only use 802.15.4 mode in this driver */
xcvrStatus_t status = kw41zrf_xcvr_configure(dev, &xcvr_common_config,
&zgbe_mode_config, &xcvr_ZIGBEE_500kbps_config, &xcvr_802_15_4_500kbps_config);
if (status != gXcvrSuccess_c) {
return -EIO;
}
return 0;
}