1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

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)
This commit is contained in:
Joakim Nohlgård 2017-05-02 19:33:05 +02:00 committed by Thomas Stilwell
parent 7be303f12f
commit 5bd67d88a8
26 changed files with 7179 additions and 4 deletions

View File

@ -2,3 +2,7 @@ ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_adc
USEMODULE += saul_gpio
endif
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
USEMODULE += kw41zrf
endif

View File

@ -3,7 +3,6 @@ ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif
# TODO uncomment after #12277 (add support for kw41zrf) is merged
# ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
# USEMODULE += kw41zrf
# endif
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
USEMODULE += kw41zrf
endif

View File

@ -340,6 +340,16 @@ ifneq (,$(filter kw2xrf,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio_irq
endif
ifneq (,$(filter kw41zrf,$(USEMODULE)))
USEMODULE += luid
USEMODULE += netif
USEMODULE += ieee802154
USEMODULE += netdev_ieee802154
USEMODULE += core_thread_flags
USEMODULE += random
USEMODULE += mcux_xcvr_mkw41z
endif
ifneq (,$(filter l3g4200d,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif

View File

@ -180,6 +180,10 @@ ifneq (,$(filter kw2xrf,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/kw2xrf/include
endif
ifneq (,$(filter kw41zrf,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/kw41zrf/include
endif
ifneq (,$(filter l3g4200d,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/l3g4200d/include
endif

170
drivers/include/kw41zrf.h Normal file
View File

@ -0,0 +1,170 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_kw41zrf KW41Z radio-driver
* @ingroup drivers_netdev
* @brief Device driver for the NXP KW41Z, KW21Z in-cpu transceiver
* @{
*
* @file
* @brief Interface definition for the kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef KW41ZRF_H
#define KW41ZRF_H
#include <stdint.h>
#include "mutex.h"
#include "board.h"
#include "net/netdev.h"
#include "net/netdev/ieee802154.h"
#include "net/gnrc/nettype.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Maximum packet length
*/
#define KW41ZRF_MAX_PKT_LENGTH (IEEE802154_FRAME_LEN_MAX)
/**
* @brief Default channel used after initialization
*
* @{
*/
#ifndef KW41ZRF_DEFAULT_CHANNEL
#define KW41ZRF_DEFAULT_CHANNEL (IEEE802154_DEFAULT_CHANNEL)
#endif
/** @} */
/**
* @brief Default CCA threshold
*
* @{
*/
#ifndef KW41ZRF_DEFAULT_CCA_THRESHOLD
#define KW41ZRF_DEFAULT_CCA_THRESHOLD (-60)
#endif
/** @} */
/**
* @brief Default LQI compensation
*
* @{
*/
#ifndef KW41ZRF_DEFAULT_LQI_COMPENSATION
#define KW41ZRF_DEFAULT_LQI_COMPENSATION (102)
#endif
/** @} */
/**
* @brief Allowed range of channels
*
* @{
*/
#define KW41ZRF_MIN_CHANNEL (11U)
#define KW41ZRF_MAX_CHANNEL (26U)
/** @} */
/**
* @brief Default TX_POWER in dbm used after initialization
*/
#define KW41ZRF_DEFAULT_TX_POWER (IEEE802154_DEFAULT_TXPOWER)
/**
* @brief Maximum output power of the kw41z device in dBm
*/
#define KW41ZRF_OUTPUT_POWER_MAX (4)
/**
* @brief Minimum output power of the kw41z device in dBm
*/
#define KW41ZRF_OUTPUT_POWER_MIN (-19)
/**
* @brief ISR callback function type
*/
typedef void (*kw41zrf_cb_t)(void *arg);
/**
* @brief Device descriptor for KW41ZRF radio devices
*
* @extends netdev_ieee802154_t
*/
typedef struct {
netdev_ieee802154_t netdev; /**< netdev parent struct */
/**
* @name device specific fields
* @{
*/
thread_t *thread; /**< Network driver thread, for providing feedback from IRQ handler */
uint32_t tx_warmup_time; /**< TX warmup time, in event timer ticks */
uint32_t rx_warmup_time; /**< RX warmup time, in event timer ticks */
uint32_t rf_osc_en_idle; /**< RF_OSC_EN bits setting when RF module is in standby */
int16_t tx_power; /**< The current tx-power setting of the device */
uint8_t flags; /**< Internal driver option flags */
uint8_t max_retrans; /**< Maximum number of frame retransmissions
* when no Ack frame is received (macMaxFrameRetries) */
uint8_t csma_max_backoffs; /**< Maximum number of CSMA backoffs when
* waiting for channel clear (macMaxCsmaBackoffs) */
uint8_t csma_min_be; /**< Minimum backoff exponent (macMinBe) */
uint8_t csma_max_be; /**< Maximum backoff exponent (macMaxBe) */
uint8_t idle_seq; /**< state to return to after sending */
uint8_t cca_result; /**< Used for passing CCA result from ISR to user */
uint8_t csma_be; /**< Counter used internally by send implementation */
uint8_t csma_num_backoffs; /**< Counter used internally by send implementation */
uint8_t num_retrans; /**< Counter used internally by send implementation */
uint32_t backoff_delay; /**< CSMA delay for the current TX operation */
uint32_t tx_timeout; /**< Used to timeout waiting for ACK during TRX */
uint8_t pm_blocked; /**< true if we have blocked a low power mode in the CPU */
uint8_t recv_blocked; /**< blocks moving to XCVSEQ_RECEIVE to prevent
* overwriting the RX buffer before the higher
* layers have copied it to system RAM */
/** @} */
} kw41zrf_t;
/**
* @brief Setup an KW41ZRF based device state
*
* @param[out] dev device descriptor
*/
void kw41zrf_setup(kw41zrf_t *dev);
/**
* @brief Initialize the given KW41ZRF device
*
* @param[out] dev device descriptor
* @param[in] cb irq callback
*
* @return 0 on success
* @return <0 on error
*/
int kw41zrf_init(kw41zrf_t *dev, kw41zrf_cb_t cb);
/**
* @brief Reset radio hardware and restore default settings
*
* @param[in] dev device to reset
*
* @return 0 on success
* @return <0 on initialization failure
*/
int kw41zrf_reset(kw41zrf_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* KW41ZRF_H */
/** @} */

4
drivers/kw41zrf/Makefile Normal file
View File

@ -0,0 +1,4 @@
# Use vendor-supplied low level XCVR hardware initialization
DIRS += vendor/XCVR/MKW41Z4
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,212 @@
/*
* Copyright (C) 2017 SKF AB
* Copyright (C) 2016 Phytec Messtechnik GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
*
* @file
* @brief get/set interfaces for kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef KW41ZRF_GETSET_H
#define KW41ZRF_GETSET_H
#include "kw41zrf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Internal device option flags
* @{
*/
#define KW41ZRF_OPT_CSMA (0x01u) /**< use CSMA/CA algorithm for sending */
#define KW41ZRF_OPT_PROMISCUOUS (0x02u) /**< promiscuous mode active */
#define KW41ZRF_OPT_PRELOADING (0x04u) /**< preloading enabled */
#define KW41ZRF_OPT_TELL_TX_START (0x08u) /**< notify MAC layer on TX start */
#define KW41ZRF_OPT_TELL_TX_END (0x10u) /**< notify MAC layer on TX finished */
#define KW41ZRF_OPT_TELL_RX_START (0x20u) /**< notify MAC layer on RX start */
#define KW41ZRF_OPT_TELL_RX_END (0x40u) /**< notify MAC layer on RX finished */
#define KW41ZRF_OPT_AUTOACK (0x80u) /**< automatic sending of ACKs */
#define KW41ZRF_OPT_ACK_PENDING (0x81u) /**< set pending bit on auto ACKs */
/** @} */
/** @brief Transceiver sequence identifiers */
enum kw41zrf_xcvseq {
XCVSEQ_IDLE = 0b000,
XCVSEQ_RECEIVE = 0b001,
XCVSEQ_TRANSMIT = 0b010,
XCVSEQ_CCA = 0b011,
XCVSEQ_TX_RX = 0b100,
XCVSEQ_CONTINUOUS_CCA = 0b101,
/* Other values are reserved */
/* Special value for idle_seq when sleeping */
XCVSEQ_DSM_IDLE = 0b1000,
};
/**
* @brief Set tx power of given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] txpower transmit power in dBm
*/
void kw41zrf_set_tx_power(kw41zrf_t *dev, int16_t txpower);
/**
* @brief Get tx power value of given device
*
* @param[in] dev kw41zrf device descriptor
*
* @return current tx power value
*/
int16_t kw41zrf_get_txpower(kw41zrf_t *dev);
/**
* @brief Set channel of given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] val channel
*/
int kw41zrf_set_channel(kw41zrf_t *dev, uint8_t val);
/**
* @brief Get channel of given device
*
* @param[in] dev kw41zrf device descriptor
*
* @return current channel
*/
uint8_t kw41zrf_get_channel(kw41zrf_t *dev);
/**
* @brief Set PAN ID of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] pan PAN ID value
*/
void kw41zrf_set_pan(kw41zrf_t *dev, uint16_t pan);
/**
* @brief Get PAN ID of given device
*
* @param[in] dev kw41zrf device descriptor
*
* @return current PAN ID
*/
uint16_t kw41zrf_get_pan(kw41zrf_t *dev);
/**
* @brief Set short address of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] addr short address
*/
void kw41zrf_set_addr_short(kw41zrf_t *dev, const network_uint16_t *addr);
/**
* @brief Set long address of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] addr long address
*/
void kw41zrf_set_addr_long(kw41zrf_t *dev, const eui64_t *addr);
/**
* @brief Get short address of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[out] addr current short address
*/
void kw41zrf_get_addr_short(kw41zrf_t *dev, network_uint16_t *addr);
/**
* @brief Get long address of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[out] addr current long address
*/
void kw41zrf_get_addr_long(kw41zrf_t *dev, eui64_t *addr);
/**
* @brief Get CCA threshold of a given device
*
* @param[in] dev kw41zrf device descriptor
* @return current CCA threshold
*/
int8_t kw41zrf_get_cca_threshold(kw41zrf_t *dev);
/**
* @brief Set CCA threshold of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] value CCA threshold
*/
void kw41zrf_set_cca_threshold(kw41zrf_t *dev, int8_t value);
/**
* @brief Set CCA mode of a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] mode CCA mode
*/
void kw41zrf_set_cca_mode(kw41zrf_t *dev, uint8_t mode);
/**
* @brief Get CCA mode of a given device
*
* @param[in] dev kw41zrf device descriptor
* @return current CCA mode
*/
uint8_t kw41zrf_get_cca_mode(kw41zrf_t *dev);
/**
* @brief Get latest ED measurement from the device
*
* @param[in] dev kw41zrf device descriptor
* @return most recent ED level
*/
int8_t kw41zrf_get_ed_level(kw41zrf_t *dev);
/**
* @brief Perform one CCA measurement and return the result
*
* @param[in] dev kw41zrf device descriptor
*
* @return 0 if channel is idle
* @return 1 if channel is busy
*/
int kw41zrf_cca(kw41zrf_t *dev);
/**
* @brief Set receive watermark to signal when the packet buffer is part full
*
* @param[in] dev kw41zrf device descriptor
* @param[in] value watermark
*/
void kw41zrf_set_rx_watermark(kw41zrf_t *dev, uint8_t value);
/**
* @brief Set netopt a given device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] option Netopt option type
* @param[in] state state
*/
void kw41zrf_set_option(kw41zrf_t *dev, uint8_t option, uint8_t state);
#ifdef __cplusplus
}
#endif
#endif /* KW41ZRF_GETSET_H */
/** @} */

View File

@ -0,0 +1,293 @@
/*
* Copyright (C) 2017 SKF AB
* Copyright (C) 2016 Phytec Messtechnik GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
*
* @file
* @brief Internal function interfaces for kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef KW41ZRF_INTERN_H
#define KW41ZRF_INTERN_H
#include <stdint.h>
#include "kw41zrf.h"
/* For XCVSEQ_IDLE */
#include "kw41zrf_getset.h"
/* For ZLL CPU registers */
#include "cpu.h"
#ifdef MODULE_PM_LAYERED
#include "pm_layered.h"
#define PM_BLOCK(x) pm_block(x)
#define PM_UNBLOCK(x) pm_unblock(x)
/* When the transceiver is not in DSM, this power mode will be blocked.
* TODO: Change this to symbolic name KINETIS_PM_VLPS when Kinetis power
* management is merged (https://github.com/RIOT-OS/RIOT/pull/7897) */
#define KW41ZRF_PM_BLOCKER 1
#else
#define PM_BLOCK(x)
#define PM_UNBLOCK(x)
#endif
/* Set to 1 to use on board LEDs to show RX/TX activity */
#ifndef KW41ZRF_ENABLE_LEDS
#define KW41ZRF_ENABLE_LEDS (0)
#endif
#if KW41ZRF_ENABLE_LEDS
/* For LED macros */
#include "board.h"
#if !defined(KW41ZRF_LED_RX_ON)
#if defined(LED0_ON)
#define KW41ZRF_LED_RX_ON LED0_ON
#define KW41ZRF_LED_RX_OFF LED0_OFF
#else /* defined(LED0_ON) */
#define KW41ZRF_LED_RX_ON
#define KW41ZRF_LED_RX_OFF
#endif /* defined(LED0_ON) */
#endif /* !defined(KW41ZRF_LED_RX_ON) */
#if !defined(KW41ZRF_LED_TX_ON)
#if defined(LED1_ON)
/* Separate TX LED */
#define KW41ZRF_LED_TX_ON LED1_ON
#define KW41ZRF_LED_TX_OFF LED1_OFF
#elif defined(LED0_ON)
/* Combined RX+TX in one LED */
#define KW41ZRF_LED_TX_ON LED0_ON
#define KW41ZRF_LED_TX_OFF LED0_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_TX_ON
#define KW41ZRF_LED_TX_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_TX_ON) */
#if !defined(KW41ZRF_LED_NDSM_ON)
#if defined(LED2_ON)
#define KW41ZRF_LED_NDSM_ON LED2_ON
#define KW41ZRF_LED_NDSM_OFF LED2_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_NDSM_ON
#define KW41ZRF_LED_NDSM_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_NDSM_ON) */
#if !defined(KW41ZRF_LED_IRQ_ON)
#if defined(LED3_ON)
#define KW41ZRF_LED_IRQ_ON LED3_ON
#define KW41ZRF_LED_IRQ_OFF LED3_OFF
#else /* defined(LEDx_ON) */
#define KW41ZRF_LED_IRQ_ON
#define KW41ZRF_LED_IRQ_OFF
#endif /* defined(LEDx_ON) */
#endif /* !defined(KW41ZRF_LED_IRQ_ON) */
#else /* KW41ZRF_ENABLE_LEDS */
#define KW41ZRF_LED_NDSM_ON
#define KW41ZRF_LED_NDSM_OFF
#define KW41ZRF_LED_TX_ON
#define KW41ZRF_LED_TX_OFF
#define KW41ZRF_LED_RX_ON
#define KW41ZRF_LED_RX_OFF
#define KW41ZRF_LED_IRQ_ON
#define KW41ZRF_LED_IRQ_OFF
#endif /* KW41ZRF_ENABLE_LEDS */
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief KW41Z transceiver power modes
*/
typedef enum {
KW41ZRF_POWER_IDLE = 0, /**< All parts powered */
KW41ZRF_POWER_DSM, /**< Deep sleep mode */
} kw41zrf_powermode_t;
/**
* @brief Timebase settings
*/
typedef enum kw41zrf_timer_timebase {
KW41ZRF_TIMEBASE_500000HZ = 0b010,
KW41ZRF_TIMEBASE_250000HZ = 0b011,
KW41ZRF_TIMEBASE_125000HZ = 0b100,
KW41ZRF_TIMEBASE_62500HZ = 0b101,
KW41ZRF_TIMEBASE_31250HZ = 0b110,
KW41ZRF_TIMEBASE_15625HZ = 0b111,
} kw41zrf_timer_timebase_t;
/**
* @brief Mask all transceiver interrupts
*/
static inline void kw41zrf_mask_irqs(void)
{
NVIC_DisableIRQ(Radio_1_IRQn);
NVIC_ClearPendingIRQ(Radio_1_IRQn);
}
/**
* @brief Unmask all transceiver interrupts
*/
static inline void kw41zrf_unmask_irqs(void)
{
KW41ZRF_LED_IRQ_OFF;
NVIC_EnableIRQ(Radio_1_IRQn);
}
/**
* @brief Set the callback function for the radio ISR
*
* This callback will be called from ISR context when a radio_1 interrupt occurs
*
* @param[in] cb Pointer to callback function
* @param[in] arg Argument that will be passed to the callback
*/
void kw41zrf_set_irq_callback(void (*cb)(void *arg), void *arg);
/**
* @brief Set power mode for device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] pm power mode value
*/
void kw41zrf_set_power_mode(kw41zrf_t *dev, kw41zrf_powermode_t pm);
/**
* @brief Determine if the transceiver is busy doing TX or RX
*
* @param[in] dev kw41zrf device descriptor
*
* @return 0 if transceiver is in progress transmitting a packet
* @return 1 otherwise
*/
int kw41zrf_can_switch_to_idle(kw41zrf_t *dev);
/**
* @brief Set sequence state of device
*
* @param[in] dev kw41zrf device descriptor
* @param[in] seq sequence
*/
void kw41zrf_set_sequence(kw41zrf_t *dev, uint32_t seq);
/**
* @brief Abort the current autosequence
*
* @param[in] dev kw41zrf device descriptor
*/
static inline void kw41zrf_abort_sequence(kw41zrf_t *dev)
{
(void) dev;
/* Writing IDLE to XCVSEQ aborts any ongoing sequence */
ZLL->PHY_CTRL = (ZLL->PHY_CTRL &
~(ZLL_PHY_CTRL_XCVSEQ_MASK |
ZLL_PHY_CTRL_TC3TMOUT_MASK | ZLL_PHY_CTRL_TMRTRIGEN_MASK)) |
ZLL_PHY_CTRL_XCVSEQ(XCVSEQ_IDLE) | ZLL_PHY_CTRL_SEQMSK_MASK;
/* Spin until the sequence manager has acknowledged the sequence abort, this
* should not take many cycles */
while (!(ZLL->SEQ_CTRL_STS & ZLL_SEQ_CTRL_STS_SEQ_IDLE_MASK)) {}
/* Clear interrupt flags */
uint32_t irqsts = ZLL->IRQSTS;
ZLL->IRQSTS = irqsts;
}
/**
* @brief Check if the radio is in deep sleep mode
*
* @return non-zero if radio is in deep sleep
* @return 0 if radio is not in deep sleep mode
*/
static inline uint32_t kw41zrf_is_dsm(void)
{
return (RSIM->DSM_CONTROL & RSIM_DSM_CONTROL_ZIG_DEEP_SLEEP_STATUS_MASK);
}
/**
* @brief Set event timer counter value
*
* @param[in] dev kw41zrf device descriptor
* @param[in] value new time
*/
static inline void kw41zrf_timer_load(kw41zrf_t *dev, uint32_t value)
{
(void) dev;
ZLL->EVENT_TMR = ZLL_EVENT_TMR_EVENT_TMR(value) | ZLL_EVENT_TMR_EVENT_TMR_LD_MASK;
}
/**
* @brief Get current event timer counter value
*
* @param[in] dev kw41zrf device descriptor
*
* @return Current timer value
*/
static inline uint32_t kw41zrf_timer_get(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->EVENT_TMR & ZLL_EVENT_TMR_EVENT_TMR_MASK) >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
}
/**
* @brief Set a timeout value for the given compare register of the Event Timer
*
* @param[in] dev kw41zrf device descriptor
* @param[out] cmp_reg pointer to timer compare register, &ZLL->TxCMP
* @param[in] timeout timer offset from current time
*/
static inline void kw41zrf_timer_set(kw41zrf_t *dev, volatile uint32_t *cmp_reg, uint32_t timeout)
{
uint32_t now = kw41zrf_timer_get(dev);
*cmp_reg = now + timeout;
}
/**
* @brief Initialize the Event Timer Block (up counter)
*
* The Event Timer Block provides:
* - Abort an RX and CCA sequence at pre-determined time
* - Latches "timestamp" value during packet reception
* - Initiates timer-triggered sequences
*
* @param[in] dev kw41zrf device descriptor
* @param[in] tb timer base value
*/
static inline void kw41zrf_timer_init(kw41zrf_t *dev, kw41zrf_timer_timebase_t tb)
{
ZLL->TMR_PRESCALE = (ZLL->TMR_PRESCALE & ~ZLL_TMR_PRESCALE_TMR_PRESCALE_MASK) |
ZLL_TMR_PRESCALE_TMR_PRESCALE(tb);
kw41zrf_timer_load(dev, 0);
}
/**
* @brief Returns timestamp of the beginning of the most recently received packet
*
* The latched timestamp corresponds to the point where the SFD detection was
* triggered for the most recent packet, i.e. right before the first byte of the
* packet.
*
* @param[in] dev kw41zrf device descriptor
*
* @return timestamp value
*/
static inline uint32_t kw41zrf_get_timestamp(kw41zrf_t *dev)
{
(void) dev;
return ZLL->TIMESTAMP;
}
#ifdef __cplusplus
}
#endif
#endif /* KW41ZRF_INTERN_H */
/** @} */

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
*
* @file
* @brief Netdev interface for kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/
#ifndef KW41ZRF_NETDEV_H
#define KW41ZRF_NETDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev_driver_t kw41zrf_driver;
#ifdef __cplusplus
}
#endif
#endif /* KW41ZRF_NETDEV_H */
/** @} */

263
drivers/kw41zrf/kw41zrf.c Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
* @file
* @brief Basic functionality of kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @}
*/
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include "log.h"
#include "msg.h"
#include "luid.h"
#include "net/gnrc.h"
#include "net/ieee802154.h"
#include "kw41zrf.h"
#include "kw41zrf_netdev.h"
#include "kw41zrf_getset.h"
#include "kw41zrf_intern.h"
#include "vendor/XCVR/MKW41Z4/fsl_xcvr.h"
#include "vendor/XCVR/MKW41Z4/ifr_radio.h"
#include "vendor/MKW41Z4.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
static void kw41zrf_set_address(kw41zrf_t *dev)
{
DEBUG("[kw41zrf] Set MAC address\n");
eui64_t addr_long;
network_uint16_t addr_short;
/* get unique IDs to use as hardware addresses */
luid_get_eui64(&addr_long);
luid_get_short(&addr_short);
/* set short and long address */
kw41zrf_set_addr_long(dev, &addr_long);
kw41zrf_set_addr_short(dev, &addr_short);
}
void kw41zrf_setup(kw41zrf_t *dev)
{
netdev_t *netdev = (netdev_t *)dev;
netdev->driver = &kw41zrf_driver;
/* initialize device descriptor */
dev->idle_seq = XCVSEQ_RECEIVE;
dev->pm_blocked = 0;
dev->recv_blocked = 0;
/* Set default parameters according to STD IEEE802.15.4-2015 */
dev->csma_max_be = 5;
dev->csma_min_be = 3;
dev->max_retrans = 3;
dev->csma_max_backoffs = 4;
DEBUG("[kw41zrf] setup finished\n");
}
/* vendor routine to initialize the radio core */
int kw41zrf_xcvr_init(kw41zrf_t *dev);
int kw41zrf_init(kw41zrf_t *dev, kw41zrf_cb_t cb)
{
if (dev == NULL) {
return -EINVAL;
}
/* Save a copy of the RF_OSC_EN setting to use when the radio is in deep sleep */
dev->rf_osc_en_idle = RSIM->CONTROL & RSIM_CONTROL_RF_OSC_EN_MASK;
kw41zrf_mask_irqs();
kw41zrf_set_irq_callback(cb, dev);
/* Perform clean reset of the radio modules. */
int res = kw41zrf_reset(dev);
if (res < 0) {
/* initialization error signaled from vendor driver */
/* Restore saved RF_OSC_EN setting */
RSIM->CONTROL = (RSIM->CONTROL & ~RSIM_CONTROL_RF_OSC_EN_MASK) | dev->rf_osc_en_idle;
return res;
}
/* Radio is now on and idle */
/* Allow radio interrupts */
kw41zrf_unmask_irqs();
DEBUG("[kw41zrf] init finished\n");
return 0;
}
int kw41zrf_reset_hardware(kw41zrf_t *dev)
{
/* Enable RSIM oscillator in RUN and WAIT modes, in order to be able to
* access the XCVR and ZLL registers when using the internal reference clock
* for the CPU core */
RSIM->CONTROL |= RSIM_CONTROL_RF_OSC_EN(1);
/* Wait for oscillator ready signal */
while ((RSIM->CONTROL & RSIM_CONTROL_RF_OSC_READY_MASK) == 0) {}
/* Assert radio software reset */
RSIM->CONTROL |= RSIM_CONTROL_RADIO_RESET_BIT_MASK;
/* De-assert radio software reset twice to follow recommendations in the
* reference manual */
RSIM->CONTROL &= ~RSIM_CONTROL_RADIO_RESET_BIT_MASK;
RSIM->CONTROL &= ~RSIM_CONTROL_RADIO_RESET_BIT_MASK;
DEBUG("[kw41zrf] start xcvr init\n");
int res = kw41zrf_xcvr_init(dev);
if (res < 0) {
return res;
}
/* Configure DSM exit oscillator stabilization delay */
uint32_t tmp = (RSIM->RF_OSC_CTRL & RSIM_RF_OSC_CTRL_BB_XTAL_READY_COUNT_SEL_MASK) >>
RSIM_RF_OSC_CTRL_BB_XTAL_READY_COUNT_SEL_SHIFT;
/* Stabilization time is 1024 * 2^x radio crystal clocks, 0 <= x <= 3 */
RSIM->DSM_OSC_OFFSET = (1024ul << tmp) / (CLOCK_RADIOXTAL / 32768u) + 1u; /* round up */
/* Clear and disable all interrupts */
/* Reset PHY_CTRL to the default values, mask all interrupts,
* enable RXACKRQD, we only use TR mode for receiving acknowledgements */
ZLL->PHY_CTRL =
ZLL_PHY_CTRL_CCATYPE(1) |
ZLL_PHY_CTRL_TSM_MSK_MASK |
ZLL_PHY_CTRL_WAKE_MSK_MASK |
ZLL_PHY_CTRL_CRC_MSK_MASK |
ZLL_PHY_CTRL_PLL_UNLOCK_MSK_MASK |
ZLL_PHY_CTRL_FILTERFAIL_MSK_MASK |
ZLL_PHY_CTRL_RX_WMRK_MSK_MASK |
ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
ZLL_PHY_CTRL_SEQMSK_MASK |
ZLL_PHY_CTRL_RXACKRQD_MASK |
ZLL_PHY_CTRL_XCVSEQ(XCVSEQ_IDLE);
/* Mask all unused timer interrupts and clear all interrupt flags */
ZLL->IRQSTS =
ZLL_IRQSTS_TMR1MSK_MASK |
ZLL_IRQSTS_TMR4MSK_MASK |
ZLL_IRQSTS_TMR1IRQ_MASK |
ZLL_IRQSTS_TMR2IRQ_MASK |
ZLL_IRQSTS_TMR3IRQ_MASK |
ZLL_IRQSTS_TMR4IRQ_MASK |
ZLL_IRQSTS_WAKE_IRQ_MASK |
ZLL_IRQSTS_PLL_UNLOCK_IRQ_MASK |
ZLL_IRQSTS_FILTERFAIL_IRQ_MASK |
ZLL_IRQSTS_RXWTRMRKIRQ_MASK |
ZLL_IRQSTS_CCAIRQ_MASK |
ZLL_IRQSTS_RXIRQ_MASK |
ZLL_IRQSTS_TXIRQ_MASK |
ZLL_IRQSTS_SEQIRQ_MASK;
/* Clear source address cache */
ZLL->SAM_TABLE |= ZLL_SAM_TABLE_INVALIDATE_ALL_MASK;
/* Accept FrameVersion 0 and 1, data, command, and beacon frames */
ZLL->RX_FRAME_FILTER = ZLL_RX_FRAME_FILTER_FRM_VER_FILTER(3) |
ZLL_RX_FRAME_FILTER_BEACON_FT_MASK |
ZLL_RX_FRAME_FILTER_CMD_FT_MASK |
ZLL_RX_FRAME_FILTER_DATA_FT_MASK;
/* Set prescaler to obtain 1 symbol (16us) timebase */
kw41zrf_timer_init(dev, KW41ZRF_TIMEBASE_62500HZ);
/* Set CCA threshold to KW41ZRF_DEFAULT_CCA_THRESHOLD dBm */
/* The hardware default for this register is +75 dBm (0x4b), which is nonsense */
ZLL->CCA_LQI_CTRL = (ZLL->CCA_LQI_CTRL & ~ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK) |
ZLL_CCA_LQI_CTRL_CCA1_THRESH(KW41ZRF_DEFAULT_CCA_THRESHOLD);
/* Set default LQI compensation */
/* Hardware reset default is 102 */
ZLL->CCA_LQI_CTRL = (ZLL->CCA_LQI_CTRL & ~ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP_MASK) |
ZLL_CCA_LQI_CTRL_LQI_OFFSET_COMP(KW41ZRF_DEFAULT_LQI_COMPENSATION);
/* set defaults */
ZLL->SEQ_CTRL_STS = ZLL_SEQ_CTRL_STS_EVENT_TMR_DO_NOT_LATCH_MASK;
return 0;
}
int kw41zrf_reset(kw41zrf_t *dev)
{
kw41zrf_mask_irqs();
/* Sometimes (maybe 1 in 30 reboots) there is a failure in the vendor
* routines in kw41zrf_rx_bba_dcoc_dac_trim_DCest() that can be worked
* around by retrying. Clearly this is not ideal.
*/
for (int retries = 0; ; retries++) {
int res = kw41zrf_reset_hardware(dev);
if (!res) {
if (retries) {
LOG_WARNING("kw41zrf_reset_hardware() needed %i retries\n",
retries);
}
break;
}
if (retries == 9) {
LOG_ERROR("kw41zrf_reset_hardware() returned %i\n", res);
kw41zrf_unmask_irqs();
return res;
}
}
/* Compute warmup times (scaled to 16us) */
dev->rx_warmup_time =
(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;
dev->tx_warmup_time =
(XCVR_TSM->END_OF_SEQ & XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_MASK) >>
XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_SHIFT;
/* divide by 16 and round up */
dev->rx_warmup_time = (dev->rx_warmup_time + 15) / 16;
dev->tx_warmup_time = (dev->tx_warmup_time + 15) / 16;
/* Reset software link layer driver state */
netdev_ieee802154_reset(&dev->netdev);
dev->tx_power = KW41ZRF_DEFAULT_TX_POWER;
dev->idle_seq = XCVSEQ_RECEIVE;
kw41zrf_set_power_mode(dev, KW41ZRF_POWER_IDLE);
kw41zrf_abort_sequence(dev);
kw41zrf_set_tx_power(dev, dev->tx_power);
kw41zrf_set_channel(dev, KW41ZRF_DEFAULT_CHANNEL);
kw41zrf_set_address(dev);
kw41zrf_set_cca_mode(dev, 1);
kw41zrf_set_rx_watermark(dev, 1);
kw41zrf_set_option(dev, KW41ZRF_OPT_AUTOACK, 1);
kw41zrf_set_option(dev, KW41ZRF_OPT_CSMA, 1);
static const netopt_enable_t enable = NETOPT_ENABLE;
netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ,
&enable, sizeof(enable));
kw41zrf_abort_sequence(dev);
kw41zrf_set_sequence(dev, dev->idle_seq);
kw41zrf_unmask_irqs();
DEBUG("[kw41zrf] reset radio and set to channel %d.\n",
KW41ZRF_DEFAULT_CHANNEL);
return 0;
}

View File

@ -0,0 +1,304 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
* @file
* @brief get/set functionality of kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @}
*/
#include <errno.h>
#include <string.h>
#include "log.h"
#include "cpu.h"
#include "byteorder.h"
#include "kw41zrf.h"
#include "kw41zrf_intern.h"
#include "kw41zrf_getset.h"
#include "vendor/MKW41Z4.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define KW41ZRF_NUM_CHANNEL (KW41ZRF_MAX_CHANNEL - KW41ZRF_MIN_CHANNEL + 1)
/* Lookup table for PA_PWR register */
/* Source: KW41Z data sheet, 5.3 Transmit and PLL Feature Summary,
* Table 8. Transmit Output Power as a function of PA_POWER[5:0] */
static const uint8_t tx_power_dbm_to_pa_pwr[29] = {
4, 4, 4, 4, /* -19:-16 dBm */
6, 6, /* -15:-14 dBm */
8, 8, /* -13:-12 dBm */
10, 10, /* -11:-10 dBm */
12, /* -9 dBm */
14, /* -8 dBm */
16, /* -7 dBm */
18, /* -6 dBm */
20, /* -5 dBm */
22, /* -4 dBm */
26, /* -3 dBm */
28, /* -2 dBm */
34, /* -1 dBm */
38, /* 0 dBm */
42, /* 1 dBm */
48, /* 2 dBm */
56, /* 3 dBm */
62, /* 4 dBm */
};
void kw41zrf_set_tx_power(kw41zrf_t *dev, int16_t txpower_dbm)
{
if (txpower_dbm < KW41ZRF_OUTPUT_POWER_MIN) {
txpower_dbm = KW41ZRF_OUTPUT_POWER_MIN;
}
else if (txpower_dbm > KW41ZRF_OUTPUT_POWER_MAX) {
txpower_dbm = KW41ZRF_OUTPUT_POWER_MAX;
}
ZLL->PA_PWR = tx_power_dbm_to_pa_pwr[txpower_dbm - KW41ZRF_OUTPUT_POWER_MIN];
DEBUG("[kw41zrf] set txpower to: %d\n", txpower_dbm);
dev->tx_power = txpower_dbm;
}
int16_t kw41zrf_get_txpower(kw41zrf_t *dev)
{
return dev->tx_power;
}
uint8_t kw41zrf_get_channel(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->CHANNEL_NUM0 & ZLL_CHANNEL_NUM0_CHANNEL_NUM0_MASK)
>> ZLL_CHANNEL_NUM0_CHANNEL_NUM0_SHIFT;
}
uint16_t kw41zrf_get_pan(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->MACSHORTADDRS0 & ZLL_MACSHORTADDRS0_MACPANID0_MASK)
>> ZLL_MACSHORTADDRS0_MACPANID0_SHIFT;
}
int kw41zrf_set_channel(kw41zrf_t *dev, uint8_t channel)
{
(void) dev;
if (channel < KW41ZRF_MIN_CHANNEL || channel > KW41ZRF_MAX_CHANNEL) {
LOG_ERROR("[kw41zrf] Invalid channel %u\n", channel);
return -EINVAL;
}
ZLL->CHANNEL_NUM0 = channel;
DEBUG("[kw41zrf] set channel to %u\n", channel);
return 0;
}
void kw41zrf_set_pan(kw41zrf_t *dev, uint16_t pan)
{
(void) dev;
ZLL->MACSHORTADDRS0 = (ZLL->MACSHORTADDRS0
& ~ZLL_MACSHORTADDRS0_MACPANID0_MASK) |
ZLL_MACSHORTADDRS0_MACPANID0(pan);
DEBUG("[kw41zrf] set pan to: 0x%x\n", pan);
}
void kw41zrf_set_addr_short(kw41zrf_t *dev, const network_uint16_t *addr)
{
(void) dev;
ZLL->MACSHORTADDRS0 = (ZLL->MACSHORTADDRS0
& ~ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK) |
ZLL_MACSHORTADDRS0_MACSHORTADDRS0(addr->u16);
}
void kw41zrf_set_addr_long(kw41zrf_t *dev, const eui64_t *addr)
{
(void) dev;
ZLL->MACLONGADDRS0_LSB = addr->uint32[0].u32;
ZLL->MACLONGADDRS0_MSB = addr->uint32[1].u32;
}
void kw41zrf_get_addr_short(kw41zrf_t *dev, network_uint16_t *addr)
{
(void) dev;
addr->u16 = (ZLL->MACSHORTADDRS0 & ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK) >>
ZLL_MACSHORTADDRS0_MACSHORTADDRS0_SHIFT;
}
void kw41zrf_get_addr_long(kw41zrf_t *dev, eui64_t *addr)
{
(void) dev;
addr->uint32[0] = (network_uint32_t)ZLL->MACLONGADDRS0_LSB;
addr->uint32[1] = (network_uint32_t)ZLL->MACLONGADDRS0_MSB;
}
int8_t kw41zrf_get_cca_threshold(kw41zrf_t *dev)
{
(void) dev;
uint8_t tmp = (ZLL->CCA_LQI_CTRL & ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK) >>
ZLL_CCA_LQI_CTRL_CCA1_THRESH_SHIFT;
return (int8_t)tmp;
}
void kw41zrf_set_cca_threshold(kw41zrf_t *dev, int8_t value)
{
(void) dev;
ZLL->CCA_LQI_CTRL = (ZLL->CCA_LQI_CTRL & ~ZLL_CCA_LQI_CTRL_CCA1_THRESH_MASK) |
ZLL_CCA_LQI_CTRL_CCA1_THRESH(value);
}
void kw41zrf_set_cca_mode(kw41zrf_t *dev, uint8_t mode)
{
(void) dev;
ZLL->PHY_CTRL = (ZLL->PHY_CTRL & ~ZLL_PHY_CTRL_CCATYPE_MASK) |
ZLL_PHY_CTRL_CCATYPE(mode);
}
uint8_t kw41zrf_get_cca_mode(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCATYPE_MASK) >> ZLL_PHY_CTRL_CCATYPE_SHIFT;
}
int8_t kw41zrf_get_ed_level(kw41zrf_t *dev)
{
(void) dev;
return (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_CCA1_ED_FNL_MASK)
>> ZLL_LQI_AND_RSSI_CCA1_ED_FNL_SHIFT;
}
void kw41zrf_set_option(kw41zrf_t *dev, uint8_t option, uint8_t state)
{
DEBUG("[kw41zrf] set option 0x%04x to %x\n", option, state);
if (kw41zrf_is_dsm()) {
/* Transceiver is sleeping */
switch (option) {
/* Modifying these options require that the transceiver is not in
* deep sleep mode */
case KW41ZRF_OPT_CSMA:
case KW41ZRF_OPT_PROMISCUOUS:
case KW41ZRF_OPT_AUTOACK:
case KW41ZRF_OPT_ACK_PENDING:
case KW41ZRF_OPT_TELL_RX_START:
LOG_ERROR("[kw41zrf] Attempt to modify option %04x while radio is sleeping\n",
(unsigned) option);
assert(0);
return;
default:
break;
}
}
/* set option field */
if (state) {
dev->flags |= option;
/* trigger option specific actions */
switch (option) {
case KW41ZRF_OPT_CSMA:
DEBUG("[kw41zrf] enable: CSMA\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_CCABFRTX_SHIFT);
break;
case KW41ZRF_OPT_PROMISCUOUS:
DEBUG("[kw41zrf] enable: PROMISCUOUS\n");
/* enable promiscuous mode */
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_PROMISCUOUS_SHIFT);
/* auto ACK is always disabled in promiscuous mode by the hardware */
break;
case KW41ZRF_OPT_AUTOACK:
DEBUG("[kw41zrf] enable: AUTOACK\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_AUTOACK_SHIFT);
break;
case KW41ZRF_OPT_ACK_PENDING:
DEBUG("[kw41zrf] enable: PENDING_BIT\n");
bit_set32(&ZLL->SAM_TABLE, ZLL_SAM_TABLE_ACK_FRM_PND_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_START:
DEBUG("[kw41zrf] enable: TELL_RX_START\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_RX_WMRK_MSK_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_END:
DEBUG("[kw41zrf] enable: TELL_RX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_END:
DEBUG("[kw41zrf] enable: TELL_TX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_START:
DEBUG("[kw41zrf] enable: TELL_TX_START (ignored)\n");
default:
/* do nothing */
break;
}
}
else {
dev->flags &= ~(option);
/* trigger option specific actions */
switch (option) {
case KW41ZRF_OPT_CSMA:
DEBUG("[kw41zrf] disable: CSMA\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_CCABFRTX_SHIFT);
break;
case KW41ZRF_OPT_PROMISCUOUS:
DEBUG("[kw41zrf] disable: PROMISCUOUS\n");
/* disable promiscuous mode */
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_PROMISCUOUS_SHIFT);
break;
case KW41ZRF_OPT_AUTOACK:
DEBUG("[kw41zrf] disable: AUTOACK\n");
bit_clear32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_AUTOACK_SHIFT);
break;
case KW41ZRF_OPT_ACK_PENDING:
DEBUG("[kw41zrf] disable: PENDING_BIT\n");
bit_clear32(&ZLL->SAM_TABLE, ZLL_SAM_TABLE_ACK_FRM_PND_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_START:
DEBUG("[kw41zrf] disable: TELL_RX_START\n");
bit_set32(&ZLL->PHY_CTRL, ZLL_PHY_CTRL_RX_WMRK_MSK_SHIFT);
break;
case KW41ZRF_OPT_TELL_RX_END:
DEBUG("[kw41zrf] disable: TELL_RX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_END:
DEBUG("[kw41zrf] disable: TELL_TX_END\n");
break;
case KW41ZRF_OPT_TELL_TX_START:
DEBUG("[kw41zrf] disable: TELL_TX_START (ignored)\n");
default:
/* do nothing */
break;
}
}
}
void kw41zrf_set_rx_watermark(kw41zrf_t *dev, uint8_t value)
{
(void) dev;
ZLL->RX_WTR_MARK = ZLL_RX_WTR_MARK_RX_WTR_MARK(value);
}

View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup drivers_kw41zrf
* @{
* @file
* @brief Internal function of kw41zrf driver
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @}
*/
#include "log.h"
#include "irq.h"
#include "panic.h"
#include "kw41zrf.h"
#include "kw41zrf_getset.h"
#include "kw41zrf_intern.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Delay before entering deep sleep mode, in DSM_TIMER ticks (32.768 kHz)
*
* @attention must be >= 4 according to SoC ref. manual
*/
#define KW41ZRF_DSM_ENTER_DELAY 5
/**
* @brief Delay before leaving deep sleep mode, in DSM_TIMER ticks (32.768 kHz)
*
* @attention must be >= 4 according to SoC ref. manual
*/
#define KW41ZRF_DSM_EXIT_DELAY 5
struct {
void (*cb)(void *arg); /**< Callback function called from radio ISR */
void *arg; /**< Argument to callback */
} isr_config;
void kw41zrf_set_irq_callback(void (*cb)(void *arg), void *arg)
{
unsigned int mask = irq_disable();
isr_config.cb = cb;
isr_config.arg = arg;
irq_restore(mask);
}
void kw41zrf_set_power_mode(kw41zrf_t *dev, kw41zrf_powermode_t pm)
{
DEBUG("[kw41zrf] set power mode to %u\n", pm);
unsigned state = irq_disable();
switch (pm) {
case KW41ZRF_POWER_IDLE:
{
/* Disable some CPU power management if we need to be active, otherwise the
* radio will be stuck in state retention mode. */
if (!dev->pm_blocked) {
PM_BLOCK(KW41ZRF_PM_BLOCKER);
dev->pm_blocked = 1;
}
/* Restore saved RF oscillator settings, enable oscillator in RUN mode
* to allow register access */
/* This is also where the oscillator is enabled during kw41zrf_init:
* kw41zrf_init -> kw41zrf_reset_phy -> kw41zrf_set_power_mode
* => Do not return before this line during init */
RSIM->CONTROL |= RSIM_CONTROL_RF_OSC_EN(1);
/* Assume DSM timer has been running since we entered sleep mode */
/* In case it was not already running, however, we still set the
* enable flag here. */
/* RSIM_DSM_CONTROL_ZIG_SYSCLK_REQUEST_EN lets the link layer
* request the RF oscillator to remain on during STOP and VLPS, to
* allow stopping the CPU core without affecting TX or RX operations */
RSIM->DSM_CONTROL = (RSIM_DSM_CONTROL_DSM_TIMER_EN_MASK |
RSIM_DSM_CONTROL_ZIG_SYSCLK_REQUEST_EN_MASK);
/* Wait for oscillator ready signal before attempting to recover from DSM */
while ((RSIM->CONTROL & RSIM_CONTROL_RF_OSC_READY_MASK) == 0) {}
KW41ZRF_LED_NDSM_ON;
/* If we are already awake we can just return now. */
if (!(kw41zrf_is_dsm())) {
/* Already awake */
break;
}
/* The wake target must be at least (4 + RSIM_DSM_OSC_OFFSET) ticks
* into the future, to let the oscillator stabilize before switching
* on the clocks */
RSIM->ZIG_WAKE = KW41ZRF_DSM_EXIT_DELAY + RSIM->DSM_TIMER + RSIM->DSM_OSC_OFFSET;
/* Wait to come out of DSM */
while (kw41zrf_is_dsm()) {}
/* Convert DSM ticks (32.768 kHz) to event timer ticks (1 MHz) */
uint64_t tmp = (uint64_t)(RSIM->ZIG_WAKE - RSIM->ZIG_SLEEP) * 15625ul;
uint32_t usec = (tmp >> 9); /* equivalent to (usec / 512) */
/* Add the offset */
ZLL->EVENT_TMR = ZLL_EVENT_TMR_EVENT_TMR_ADD_MASK |
ZLL_EVENT_TMR_EVENT_TMR(usec);
/* Clear IRQ flags */
uint32_t irqsts = ZLL->IRQSTS;
DEBUG("[kw41zrf] wake IRQSTS=%" PRIx32 "\n", irqsts);
ZLL->IRQSTS = irqsts;
/* Disable DSM timer triggered sleep */
ZLL->DSM_CTRL = 0;
break;
}
case KW41ZRF_POWER_DSM:
{
if (kw41zrf_is_dsm()) {
/* Already asleep */
break;
}
if (dev->pm_blocked) {
PM_UNBLOCK(KW41ZRF_PM_BLOCKER);
dev->pm_blocked = 0;
}
/* Race condition: if sleep is re-triggered after wake before the
* DSM_ZIG_FINISHED flag has been switched off, then the RSIM
* becomes stuck and never enters DSM.
* The time from ZIG_WAKE until DSM_ZIG_FINISHED is turned off seem
* to be constant at 2 DSM ticks */
while (RSIM->DSM_CONTROL & RSIM_DSM_CONTROL_DSM_ZIG_FINISHED_MASK) {}
/* Clear IRQ flags */
uint32_t irqsts = RSIM->DSM_CONTROL;
RSIM->DSM_CONTROL = irqsts;
irqsts = ZLL->IRQSTS;
DEBUG("[kw41zrf] sleep IRQSTS=%" PRIx32 "\n", irqsts);
ZLL->IRQSTS = irqsts;
NVIC_ClearPendingIRQ(Radio_1_IRQn);
/* Enable timer triggered sleep */
ZLL->DSM_CTRL = ZLL_DSM_CTRL_ZIGBEE_SLEEP_EN_MASK;
/* The device will automatically wake up 8.5 minutes from now if not
* awoken sooner by software */
/* TODO handle automatic wake in the ISR if it becomes an issue */
RSIM->ZIG_WAKE = RSIM->DSM_TIMER - KW41ZRF_DSM_EXIT_DELAY - RSIM->DSM_OSC_OFFSET;
/* Set sleep start time */
/* The target time must be at least 4 DSM_TIMER ticks into the future */
RSIM->ZIG_SLEEP = RSIM->DSM_TIMER + KW41ZRF_DSM_ENTER_DELAY;
/* Start the 32.768 kHz DSM timer in case it was not already running */
/* If ZIG_SYSCLK_REQUEST_EN is not set then the hardware will not
* enter DSM and we get stuck in the while() below */
RSIM->DSM_CONTROL = (RSIM_DSM_CONTROL_DSM_TIMER_EN_MASK |
RSIM_DSM_CONTROL_ZIG_SYSCLK_REQUEST_EN_MASK);
while (!(kw41zrf_is_dsm())) {}
KW41ZRF_LED_NDSM_OFF;
/* Restore saved RF_OSC_EN bits (from kw41zrf_init)
* This will disable the RF oscillator unless the system was
* configured to use the RF oscillator before kw41zrf_init() was
* called, for example when using the RF oscillator for the CPU core
* clock. */
RSIM->CONTROL = (RSIM->CONTROL & ~RSIM_CONTROL_RF_OSC_EN_MASK) |
dev->rf_osc_en_idle;
/* Let the DSM timer run until we exit deep sleep mode */
break;
}
default:
LOG_ERROR("[kw41zrf] Unknown power mode %u\n", pm);
break;
}
irq_restore(state);
}
void kw41zrf_set_sequence(kw41zrf_t *dev, uint32_t seq)
{
(void) dev;
DEBUG("[kw41zrf] set sequence to %x\n", (unsigned)seq);
assert(!kw41zrf_is_dsm());
unsigned back_to_sleep = 0;
if (seq == XCVSEQ_DSM_IDLE) {
back_to_sleep = 1;
seq = XCVSEQ_IDLE;
}
else if ((seq == XCVSEQ_RECEIVE) && dev->recv_blocked) {
/* Wait in standby until recv has been called to avoid corrupting the RX
* buffer before the frame has been received by the higher layers */
seq = XCVSEQ_IDLE;
}
uint32_t seq_old = ZLL->PHY_CTRL & ZLL_PHY_CTRL_XCVSEQ_MASK;
if (seq_old != XCVSEQ_IDLE && seq_old != XCVSEQ_RECEIVE) {
LOG_ERROR("[kw41zrf] seq not idle: 0x%" PRIu32 "\n", seq_old);
assert(0);
}
kw41zrf_abort_sequence(dev);
ZLL->PHY_CTRL = (ZLL->PHY_CTRL & ~(ZLL_PHY_CTRL_XCVSEQ_MASK | ZLL_PHY_CTRL_SEQMSK_MASK)) | seq;
while (((ZLL->SEQ_CTRL_STS & ZLL_SEQ_CTRL_STS_XCVSEQ_ACTUAL_MASK) >>
ZLL_SEQ_CTRL_STS_XCVSEQ_ACTUAL_SHIFT) != (ZLL_PHY_CTRL_XCVSEQ_MASK & seq)) {}
if (back_to_sleep) {
kw41zrf_set_power_mode(dev, KW41ZRF_POWER_DSM);
}
}
int kw41zrf_can_switch_to_idle(kw41zrf_t *dev)
{
(void) dev;
if (!kw41zrf_is_dsm()) {
uint8_t seq = (ZLL->PHY_CTRL & ZLL_PHY_CTRL_XCVSEQ_MASK) >> ZLL_PHY_CTRL_XCVSEQ_SHIFT;
DEBUG("[kw41zrf] XCVSEQ=0x%x, SEQ_STATE=0x%" PRIx32 ", SEQ_CTRL_STS=0x%" PRIx32 "\n", seq,
ZLL->SEQ_STATE, ZLL->SEQ_CTRL_STS);
switch (seq)
{
case XCVSEQ_TRANSMIT:
case XCVSEQ_TX_RX:
case XCVSEQ_CCA:
/* We should wait until TX or CCA has finished before moving to
* another mode */
return 0;
default:
break;
}
}
return 1;
}
void isr_radio_1(void)
{
DEBUG("[kw41zrf] INT1\n");
if (isr_config.cb != NULL) {
isr_config.cb(isr_config.arg);
}
cortexm_isr_end();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,913 @@
/*
* 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;
}

View File

@ -0,0 +1,616 @@
/*!
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* 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.
*/
#ifndef _FSL_OS_ABSTRACTION_H_
#define _FSL_OS_ABSTRACTION_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "fsl_os_abstraction_config.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*! *********************************************************************************
*************************************************************************************
* Public type definitions
*************************************************************************************
********************************************************************************** */
/*! @brief Type for the Task Priority*/
typedef uint16_t osaTaskPriority_t;
/*! @brief Type for the timer definition*/
typedef enum {
osaTimer_Once = 0, /*!< one-shot timer*/
osaTimer_Periodic = 1 /*!< repeating timer*/
} osaTimer_t;
/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */
typedef void* osaTaskId_t;
/*! @brief Type for the parameter to be passed to the task at its creation */
typedef void* osaTaskParam_t;
/*! @brief Type for task pointer. Task prototype declaration */
typedef void (*osaTaskPtr_t) (osaTaskParam_t task_param);
/*! @brief Type for the semaphore handler, returned by the OSA_SemaphoreCreate function. */
typedef void* osaSemaphoreId_t;
/*! @brief Type for the mutex handler, returned by the OSA_MutexCreate function. */
typedef void* osaMutexId_t;
/*! @brief Type for the event handler, returned by the OSA_EventCreate function. */
typedef void* osaEventId_t;
/*! @brief Type for an event flags group, bit 32 is reserved. */
typedef uint32_t osaEventFlags_t;
/*! @brief Message definition. */
typedef void* osaMsg_t;
/*! @brief Type for the message queue handler, returned by the OSA_MsgQCreate function. */
typedef void* osaMsgQId_t;
/*! @brief Type for the Timer handler, returned by the OSA_TimerCreate function. */
typedef void *osaTimerId_t;
/*! @brief Type for the Timer callback function pointer. */
typedef void (*osaTimerFctPtr_t) (void const *argument);
/*! @brief Thread Definition structure contains startup information of a thread.*/
typedef struct osaThreadDef_tag {
osaTaskPtr_t pthread; /*!< start address of thread function*/
uint32_t tpriority; /*!< initial thread priority*/
uint32_t instances; /*!< maximum number of instances of that thread function*/
uint32_t stacksize; /*!< stack size requirements in bytes; 0 is default stack size*/
uint32_t *tstack;
void *tlink;
uint8_t *tname;
bool useFloat;
} osaThreadDef_t;
/*! @brief Thread Link Definition structure .*/
typedef struct osaThreadLink_tag{
uint8_t link[12];
osaTaskId_t osThreadId;
osaThreadDef_t *osThreadDefHandle;
uint32_t *osThreadStackHandle;
}osaThreadLink_t, *osaThreadLinkHandle_t;
/*! @Timer Definition structure contains timer parameters.*/
typedef struct osaTimerDef_tag {
osaTimerFctPtr_t pfCallback; /* < start address of a timer function */
void *argument;
} osaTimerDef_t;
/*! @brief Defines the return status of OSA's functions */
typedef enum osaStatus_tag
{
osaStatus_Success = 0U, /*!< Success */
osaStatus_Error = 1U, /*!< Failed */
osaStatus_Timeout = 2U, /*!< Timeout occurs while waiting */
osaStatus_Idle = 3U /*!< Used for bare metal only, the wait object is not ready
and timeout still not occur */
}osaStatus_t;
/*! *********************************************************************************
*************************************************************************************
* Public macros
*************************************************************************************
********************************************************************************** */
#if defined (FSL_RTOS_MQX)
#define USE_RTOS 1
#elif defined (FSL_RTOS_FREE_RTOS)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSII)
#define USE_RTOS 1
#elif defined (FSL_RTOS_UCOSIII)
#define USE_RTOS 1
#else
#define USE_RTOS 0
#endif
#define OSA_PRIORITY_IDLE (6)
#define OSA_PRIORITY_LOW (5)
#define OSA_PRIORITY_BELOW_NORMAL (4)
#define OSA_PRIORITY_NORMAL (3)
#define OSA_PRIORITY_ABOVE_NORMAL (2)
#define OSA_PRIORITY_HIGH (1)
#define OSA_PRIORITY_REAL_TIME (0)
#define OSA_TASK_PRIORITY_MAX (0)
#define OSA_TASK_PRIORITY_MIN (15)
#define SIZE_IN_UINT32_UNITS(size) (((size) + sizeof(uint32_t) - 1) / sizeof(uint32_t))
/*! @brief Constant to pass as timeout value in order to wait indefinitely. */
#define osaWaitForever_c ((uint32_t)(-1))
#define osaEventFlagsAll_c ((osaEventFlags_t)(0x00FFFFFF))
#define osThreadStackArray(name) osThread_##name##_stack
#define osThreadStackDef(name, stacksize, instances) \
uint32_t osThreadStackArray(name)[SIZE_IN_UINT32_UNITS(stacksize)*(instances)];
/* ==== Thread Management ==== */
/* Create a Thread Definition with function, priority, and stack requirements.
* \param name name of the thread function.
* \param priority initial priority of the thread function.
* \param instances number of possible thread instances.
* \param stackSz stack size (in bytes) requirements for the thread function.
* \param useFloat
*/
#if defined(FSL_RTOS_MQX)
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#elif defined (FSL_RTOS_UCOSII)
#if gTaskMultipleInstancesManagement_c
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadLink_t osThreadLink_##name[instances] = {0}; \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
osThreadLink_##name, \
(uint8_t*) #name,\
(useFloat)}
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osThreadStackDef(name, stackSz, instances) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
osThreadStackArray(name), \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
#else
#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \
osaThreadDef_t os_thread_def_##name = { (name), \
(priority), \
(instances), \
(stackSz), \
NULL, \
NULL, \
(uint8_t*) #name,\
(useFloat)}
#endif
/* Access a Thread defintion.
* \param name name of the thread definition object.
*/
#define OSA_TASK(name) \
&os_thread_def_##name
#define OSA_TASK_PROTO(name) \
extern osaThreadDef_t os_thread_def_##name
/* ==== Timer Management ====
* Define a Timer object.
* \param name name of the timer object.
* \param function name of the timer call back function.
*/
#define OSA_TIMER_DEF(name, function) \
osaTimerDef_t os_timer_def_##name = \
{ (function), NULL }
/* Access a Timer definition.
* \param name name of the timer object.
*/
#define OSA_TIMER(name) \
&os_timer_def_##name
/*****************************************************************************
******************************************************************************
* Public memory declarations
******************************************************************************
*****************************************************************************/
extern const uint8_t gUseRtos_c;
/*! *********************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
********************************************************************************** */
/*!
* @name Task management
* @{
*/
/*!
* @brief Creates a task.
*
* This function is used to create task based on the resources defined
* by the macro OSA_TASK_DEFINE.
*
* @param thread_def pointer to the osaThreadDef_t structure which defines the task.
* @param task_param Pointer to be passed to the task when it is created.
*
* @retval taskId The task is successfully created.
* @retval NULL The task can not be created..
*
* Example:
@code
osaTaskId_t taskId;
OSA_TASK_DEFINE( Job1, OSA_PRIORITY_HIGH, 1, 800, 0);;
taskId = OSA__TaskCreate(OSA__TASK(Job1), (osaTaskParam_t)NULL);
@endcode
*/
osaTaskId_t OSA_TaskCreate(osaThreadDef_t *thread_def, osaTaskParam_t task_param);
/*!
* @brief Gets the handler of active task.
*
* @return Handler to current active task.
*/
osaTaskId_t OSA_TaskGetId(void);
/*!
* @brief Puts the active task to the end of scheduler's queue.
*
* When a task calls this function, it gives up the CPU and puts itself to the
* end of a task ready list.
*
* @retval osaStatus_Success The function is called successfully.
* @retval osaStatus_Error Error occurs with this function.
*/
osaStatus_t OSA_TaskYield(void);
/*!
* @brief Gets the priority of a task.
*
* @param taskId The handler of the task whose priority is received.
*
* @return Task's priority.
*/
osaTaskPriority_t OSA_TaskGetPriority(osaTaskId_t taskId);
/*!
* @brief Sets the priority of a task.
*
* @param taskId The handler of the task whose priority is set.
* @param taskPriority The priority to set.
*
* @retval osaStatus_Success Task's priority is set successfully.
* @retval osaStatus_Error Task's priority can not be set.
*/
osaStatus_t OSA_TaskSetPriority(osaTaskId_t taskId, osaTaskPriority_t taskPriority);
/*!
* @brief Destroys a previously created task.
*
* @param taskId The handler of the task to destroy. Returned by the OSA_TaskCreate function.
*
* @retval osaStatus_Success The task was successfully destroyed.
* @retval osaStatus_Error Task destruction failed or invalid parameter.
*/
osaStatus_t OSA_TaskDestroy(osaTaskId_t taskId);
/*!
* @brief Creates a semaphore with a given value.
*
* This function creates a semaphore and sets the value to the parameter
* initValue.
*
* @param initValue Initial value the semaphore will be set to.
*
* @retval handler to the new semaphore if the semaphore is created successfully.
* @retval NULL if the semaphore can not be created.
*
*
*/
osaSemaphoreId_t OSA_SemaphoreCreate(uint32_t initValue);
/*!
* @brief Destroys a previously created semaphore.
*
* @param semId Pointer to the semaphore to destroy.
*
* @retval osaStatus_Success The semaphore is successfully destroyed.
* @retval osaStatus_Error The semaphore can not be destroyed.
*/
osaStatus_t OSA_SemaphoreDestroy(osaSemaphoreId_t semId);
/*!
* @brief Pending a semaphore with timeout.
*
* This function checks the semaphore's counting value. If it is positive,
* decreases it and returns osaStatus_Success. Otherwise, a timeout is used
* to wait.
*
* @param semId Pointer to the semaphore.
* @param millisec The maximum number of milliseconds to wait if semaphore is not
* positive. Pass osaWaitForever_c to wait indefinitely, pass 0
* will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success The semaphore is received.
* @retval osaStatus_Timeout The semaphore is not received within the specified 'timeout'.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_SemaphoreWait(osaSemaphoreId_t semId, uint32_t millisec);
/*!
* @brief Signals for someone waiting on the semaphore to wake up.
*
* Wakes up one task that is waiting on the semaphore. If no task is waiting, increases
* the semaphore's counting value.
*
* @param semId Pointer to the semaphore to signal.
*
* @retval osaStatus_Success The semaphore is successfully signaled.
* @retval osaStatus_Error The object can not be signaled or invalid parameter.
*
*/
osaStatus_t OSA_SemaphorePost(osaSemaphoreId_t semId);
/*!
* @brief Create an unlocked mutex.
*
* This function creates a non-recursive mutex and sets it to unlocked status.
*
* @param none.
*
* @retval handler to the new mutex if the mutex is created successfully.
* @retval NULL if the mutex can not be created.
*/
osaMutexId_t OSA_MutexCreate(void);
/*!
* @brief Waits for a mutex and locks it.
*
* This function checks the mutex's status. If it is unlocked, locks it and returns the
* osaStatus_Success. Otherwise, waits for a timeout in milliseconds to lock.
*
* @param mutexId Pointer to the Mutex.
* @param millisec The maximum number of milliseconds to wait for the mutex.
* If the mutex is locked, Pass the value osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
*
* @retval osaStatus_Success The mutex is locked successfully.
* @retval osaStatus_Timeout Timeout occurred.
* @retval osaStatus_Error Incorrect parameter was passed.
*
* @note This is non-recursive mutex, a task can not try to lock the mutex it has locked.
*/
osaStatus_t OSA_MutexLock(osaMutexId_t mutexId, uint32_t millisec);
/*!
* @brief Unlocks a previously locked mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully unlocked.
* @retval osaStatus_Error The mutex can not be unlocked or invalid parameter.
*/
osaStatus_t OSA_MutexUnlock(osaMutexId_t mutexId);
/*!
* @brief Destroys a previously created mutex.
*
* @param mutexId Pointer to the Mutex.
*
* @retval osaStatus_Success The mutex is successfully destroyed.
* @retval osaStatus_Error The mutex can not be destroyed.
*
*/
osaStatus_t OSA_MutexDestroy(osaMutexId_t mutexId);
/*!
* @brief Initializes an event object with all flags cleared.
*
* This function creates an event object and set its clear mode. If autoClear
* is TRUE, when a task gets the event flags, these flags will be
* cleared automatically. Otherwise these flags must
* be cleared manually.
*
* @param autoClear TRUE The event is auto-clear.
* FALSE The event manual-clear
* @retval handler to the new event if the event is created successfully.
* @retval NULL if the event can not be created.
*/
osaEventId_t OSA_EventCreate(bool autoClear);
/*!
* @brief Sets one or more event flags.
*
* Sets specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToSet Flags to be set.
*
* @retval osaStatus_Success The flags were successfully set.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventSet(osaEventId_t eventId, osaEventFlags_t flagsToSet);
/*!
* @brief Clears one or more flags.
*
* Clears specified flags of an event object.
*
* @param eventId Pointer to the event.
* @param flagsToClear Flags to be clear.
*
* @retval osaStatus_Success The flags were successfully cleared.
* @retval osaStatus_Error An incorrect parameter was passed.
*/
osaStatus_t OSA_EventClear(osaEventId_t eventId, osaEventFlags_t flagsToClear);
/*!
* @brief Waits for specified event flags to be set.
*
* This function waits for a combination of flags to be set in an event object.
* Applications can wait for any/all bits to be set. Also this function could
* obtain the flags who wakeup the waiting task.
*
* @param eventId Pointer to the event.
* @param flagsToWait Flags that to wait.
* @param waitAll Wait all flags or any flag to be set.
* @param millisec The maximum number of milliseconds to wait for the event.
* If the wait condition is not met, pass osaWaitForever_c will
* wait indefinitely, pass 0 will return osaStatus_Timeout
* immediately.
* @param setFlags Flags that wakeup the waiting task are obtained by this parameter.
*
* @retval osaStatus_Success The wait condition met and function returns successfully.
* @retval osaStatus_Timeout Has not met wait condition within timeout.
* @retval osaStatus_Error An incorrect parameter was passed.
*
* @note Please pay attention to the flags bit width, FreeRTOS uses the most
* significant 8 bis as control bits, so do not wait these bits while using
* FreeRTOS.
*
*/
osaStatus_t OSA_EventWait(osaEventId_t eventId, osaEventFlags_t flagsToWait, bool waitAll, uint32_t millisec, osaEventFlags_t *pSetFlags);
/*!
* @brief Destroys a previously created event object.
*
* @param eventId Pointer to the event.
*
* @retval osaStatus_Success The event is successfully destroyed.
* @retval osaStatus_Error Event destruction failed.
*/
osaStatus_t OSA_EventDestroy(osaEventId_t eventId);
/*!
* @brief Initializes a message queue.
*
* This function allocates memory for and initializes a message queue. Message queue elements are hardcoded as void*.
*
* @param msgNo :number of messages the message queue should accommodate.
* This parameter should not exceed osNumberOfMessages defined in OSAbstractionConfig.h.
*
* @return: Handler to access the queue for put and get operations. If message queue
* creation failed, return NULL.
*/
osaMsgQId_t OSA_MsgQCreate(uint32_t msgNo);
/*!
* @brief Puts a message at the end of the queue.
*
* This function puts a message to the end of the message queue. If the queue
* is full, this function returns the osaStatus_Error;
*
* @param msgQId pointer to queue returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to the message to be put into the queue.
*
* @retval osaStatus_Success Message successfully put into the queue.
* @retval osaStatus_Error The queue was full or an invalid parameter was passed.
*/
osaStatus_t OSA_MsgQPut(osaMsgQId_t msgQId, osaMsg_t pMessage);
/*!
* @brief Reads and remove a message at the head of the queue.
*
* This function gets a message from the head of the message queue. If the
* queue is empty, timeout is used to wait.
*
* @param msgQId Queue handler returned by the OSA_MsgQCreate function.
* @param pMessage Pointer to a memory to save the message.
* @param millisec The number of milliseconds to wait for a message. If the
* queue is empty, pass osaWaitForever_c will wait indefinitely,
* pass 0 will return osaStatus_Timeout immediately.
*
* @retval osaStatus_Success Message successfully obtained from the queue.
* @retval osaStatus_Timeout The queue remains empty after timeout.
* @retval osaStatus_Error Invalid parameter.
*/
osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, osaMsg_t pMessage, uint32_t millisec);
/*!
* @brief Destroys a previously created queue.
*
* @param msgQId queue handler returned by the OSA_MsgQCreate function.
*
* @retval osaStatus_Success The queue was successfully destroyed.
* @retval osaStatus_Error Message queue destruction failed.
*/
osaStatus_t OSA_MsgQDestroy(osaMsgQId_t msgQId);
/*!
* @brief Enable all interrupts.
*/
void OSA_InterruptEnable(void);
/*!
* @brief Disable all interrupts.
*/
void OSA_InterruptDisable(void);
/*!
* @brief Enable all interrupts using PRIMASK.
*/
void OSA_EnableIRQGlobal(void);
/*!
* @brief Disable all interrupts using PRIMASK.
*/
void OSA_DisableIRQGlobal(void);
/*!
* @brief Delays execution for a number of milliseconds.
*
* @param millisec The time in milliseconds to wait.
*/
void OSA_TimeDelay(uint32_t millisec);
/*!
* @brief This function gets current time in milliseconds.
*
* @retval current time in milliseconds
*/
uint32_t OSA_TimeGetMsec(void);
/*!
* @brief Installs the interrupt handler.
*
* @param IRQNumber IRQ number of the interrupt.
* @param handler The interrupt handler to install.
*/
void OSA_InstallIntHandler(uint32_t IRQNumber, void (*handler)(void));
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,78 @@
/*!
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* \file
*
* 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.
*/
#ifndef _FSL_OS_ABSTRACTION_CONFIG_H_
#define _FSL_OS_ABSTRACTION_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef osNumberOfSemaphores
#define osNumberOfSemaphores 5
#endif
#ifndef osNumberOfMutexes
#define osNumberOfMutexes 5
#endif
#ifndef osNumberOfMessageQs
#define osNumberOfMessageQs 0
#endif
#ifndef osNumberOfMessages
#define osNumberOfMessages 10
#endif
#ifndef osNumberOfEvents
#define osNumberOfEvents 5
#endif
#ifndef gMainThreadStackSize_c
#define gMainThreadStackSize_c 1024
#endif
#ifndef gMainThreadPriority_c
#define gMainThreadPriority_c 7
#endif
#ifndef gTaskMultipleInstancesManagement_c
#define gTaskMultipleInstancesManagement_c 0
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FSL_OS_ABSTRACTION_CONFIG_H_ */

View File

@ -0,0 +1,8 @@
MODULE = mcux_xcvr_mkw41z
# This vendor code expect all the vendor headers to also be in the include path
# These include paths are only added when building this particular directory and
# should not be available to the rest of the system.
INCLUDES += -I../../OSAbstraction/Interface
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,27 @@
#include "irq.h"
#include "fsl_os_abstraction.h"
static unsigned int irq_mask;
/*FUNCTION**********************************************************************
*
* Function Name : OSA_InterruptEnable
* Description : self explanatory.
*
*END**************************************************************************/
void OSA_InterruptEnable(void)
{
irq_restore(irq_mask);
}
/*FUNCTION**********************************************************************
*
* Function Name : OSA_InterruptDisable
* Description : self explanatory.
*
*END**************************************************************************/
void OSA_InterruptDisable(void)
{
irq_mask = irq_disable();
}

View File

@ -0,0 +1,833 @@
/*
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* 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.
*/
#ifndef _FSL_XCVR_H_
/* clang-format off */
#define _FSL_XCVR_H_
/* clang-format on */
#include "cpu.h"
/*!
* @addtogroup xcvr
* @{
*/
/*! @file*/
/*******************************************************************************
* Definitions
******************************************************************************/
/* KW4xZ/KW3xZ/KW2xZ Radio type */
#define RADIO_IS_GEN_2P0 (1)
#if (CLOCK_RADIOXTAL == 26000000ul)
#define RF_OSC_26MHZ 1
#endif
#define TBD_ZERO (0)
#define FSL_XCVR_DRIVER_VERSION (MAKE_VERSION(0, 1, 0))
#define B0(x) (((uint32_t)(((uint32_t)(x)) << 0)) & 0xFFU)
#define B1(x) (((uint32_t)(((uint32_t)(x)) << 8)) & 0xFF00U)
#define B2(x) (((uint32_t)(((uint32_t)(x)) << 16)) & 0xFF0000U)
#define B3(x) (((uint32_t)(((uint32_t)(x)) << 24)) & 0xFF000000U)
#define USE_DEFAULT_PRE_REF (0)
#define TRIM_BBA_DCOC_DAC_AT_INIT (1)
#define PRESLOW_ENA (1)
/* GEN3 TSM defines */
#if RADIO_IS_GEN_3P0
/* TSM timings initializations for Gen3 radio */
/* NOTE: These timings are stored in 32MHz or 26MHz "baseline" settings, selected by conditional compile below */
/* The init structures for 32Mhz and 26MHz are made identical to allow the same code in fsl_xcvr.c to apply the */
/* settings for all radio generations. The Gen2 radio init value storage had a different structure so this preserves compatibility */
#if RF_OSC_26MHZ == 1
#define TSM_TIMING00init (0x6d006f00U) /* (bb_ldo_hf_en) */
#define TSM_TIMING01init (0x6d006f00U) /* (bb_ldo_adcdac_en) */
#define TSM_TIMING02init (0x6d00ffffU) /* (bb_ldo_bba_en) */
#define TSM_TIMING03init (0x6d006f00U) /* (bb_ldo_pd_en) */
#define TSM_TIMING04init (0x6d006f00U) /* (bb_ldo_fdbk_en) */
#define TSM_TIMING05init (0x6d006f00U) /* (bb_ldo_vcolo_en) */
#define TSM_TIMING06init (0x6d006f00U) /* (bb_ldo_vtref_en) */
#define TSM_TIMING07init (0x05000500U) /* (bb_ldo_fdbk_bleed_en) */
#define TSM_TIMING08init (0x03000300U) /* (bb_ldo_vcolo_bleed_en) */
#define TSM_TIMING09init (0x03000300U) /* (bb_ldo_vcolo_fastcharge_en) */
#define TSM_TIMING10init (0x6d036f03U) /* (bb_xtal_pll_ref_clk_en) */
#define TSM_TIMING11init (0xffff6f03U) /* (bb_xtal_dac_ref_clk_en) */
#define TSM_TIMING12init (0x6d03ffffU) /* (rxtx_auxpll_vco_ref_clk_en) */
#define TSM_TIMING13init (0x18004c00U) /* (sy_vco_autotune_en) */
#define TSM_TIMING14init (0x6d356863U) /* (sy_pd_cycle_slip_ld_ft_en) */
#define TSM_TIMING15init (0x6d036f03U) /* (sy_vco_en) */
#define TSM_TIMING16init (0x6d20ffffU) /* (sy_lo_rx_buf_en) */
#define TSM_TIMING17init (0xffff6f58U) /* (sy_lo_tx_buf_en) */
#define TSM_TIMING18init (0x6d056f05U) /* (sy_divn_en) */
#define TSM_TIMING19init (0x18034c03U) /* (sy_pd_filter_charge_en) */
#define TSM_TIMING20init (0x6d036f03U) /* (sy_pd_en) */
#define TSM_TIMING21init (0x6d046f04U) /* (sy_lo_divn_en) */
#define TSM_TIMING22init (0x6d04ffffU) /* (sy_lo_rx_en) */
#define TSM_TIMING23init (0xffff6f04U) /* (sy_lo_tx_en) */
#define TSM_TIMING24init (0x18004c00U) /* (sy_divn_cal_en) */
#define TSM_TIMING25init (0x6d21ffffU) /* (rx_lna_mixer_en) */
#define TSM_TIMING26init (0xffff6e58U) /* (tx_pa_en) */
#define TSM_TIMING27init (0x6d24ffffU) /* (rx_adc_i_q_en) */
#define TSM_TIMING28init (0x2524ffffU) /* (rx_adc_reset_en) */
#define TSM_TIMING29init (0x6d22ffffU) /* (rx_bba_i_q_en) */
#define TSM_TIMING30init (0x6d24ffffU) /* (rx_bba_pdet_en) */
#define TSM_TIMING31init (0x6d23ffffU) /* (rx_bba_tza_dcoc_en) */
#define TSM_TIMING32init (0x6d21ffffU) /* (rx_tza_i_q_en) */
#define TSM_TIMING33init (0x6d24ffffU) /* (rx_tza_pdet_en) */
#define TSM_TIMING34init (0x6d076f07U) /* (pll_dig_en) */
#define TSM_TIMING35init (0xffff6f5fU) /* (tx_dig_en) */
#define TSM_TIMING36init (0x6d6affffU) /* (rx_dig_en) */
#define TSM_TIMING37init (0x6b6affffU) /* (rx_init) */
#define TSM_TIMING38init (0x6d0e6f42U) /* (sigma_delta_en) */
#define TSM_TIMING39init (0x6d6affffU) /* (rx_phy_en) */
#define TSM_TIMING40init (0x6d2affffU) /* (dcoc_en) */
#define TSM_TIMING41init (0x2b2affffU) /* (dcoc_init) */
#define TSM_TIMING42init (0xffffffffU) /* (sar_adc_trig_en) */
#define TSM_TIMING43init (0xffffffffU) /* (tsm_spare0_en) */
#define TSM_TIMING44init (0xffffffffU) /* (tsm_spare1_en) */
#define TSM_TIMING45init (0xffffffffU) /* (tsm_spare2_en) */
#define TSM_TIMING46init (0xffffffffU) /* (tsm_spare3_en) */
#define TSM_TIMING47init (0xffffffffU) /* (gpio0_trig_en) */
#define TSM_TIMING48init (0xffffffffU) /* (gpio1_trig_en) */
#define TSM_TIMING49init (0xffffffffU) /* (gpio2_trig_en) */
#define TSM_TIMING50init (0xffffffffU) /* (gpio3_trig_en) */
#define TSM_TIMING51init (0x6d03ffffU) /* (rxtx_auxpll_bias_en) */
#define TSM_TIMING52init (0x1b06ffffU) /* (rxtx_auxpll_fcal_en) */
#define TSM_TIMING53init (0x6d03ffffU) /* (rxtx_auxpll_lf_pd_en) */
#define TSM_TIMING54init (0x1b03ffffU) /* (rxtx_auxpll_pd_lf_filter_charge_en) */
#define TSM_TIMING55init (0x6d24ffffU) /* (rxtx_auxpll_adc_buf_en) */
#define TSM_TIMING56init (0x6d24ffffU) /* (rxtx_auxpll_dig_buf_en) */
#define TSM_TIMING57init (0x1a03ffffU) /* (rxtx_rccal_en) */
#define TSM_TIMING58init (0xffff6f03U) /* (tx_hpm_dac_en) */
#define END_OF_SEQinit (0x6d6c6f67U) /* */
#define TX_RX_ON_DELinit (0x00008a86U) /* */
#define TX_RX_SYNTH_init (0x00002318U) /* */
#else
#define TSM_TIMING00init (0x69006f00U) /* (bb_ldo_hf_en) */
#define TSM_TIMING01init (0x69006f00U) /* (bb_ldo_adcdac_en) */
#define TSM_TIMING02init (0x6900ffffU) /* (bb_ldo_bba_en) */
#define TSM_TIMING03init (0x69006f00U) /* (bb_ldo_pd_en) */
#define TSM_TIMING04init (0x69006f00U) /* (bb_ldo_fdbk_en) */
#define TSM_TIMING05init (0x69006f00U) /* (bb_ldo_vcolo_en) */
#define TSM_TIMING06init (0x69006f00U) /* (bb_ldo_vtref_en) */
#define TSM_TIMING07init (0x05000500U) /* (bb_ldo_fdbk_bleed_en) */
#define TSM_TIMING08init (0x03000300U) /* (bb_ldo_vcolo_bleed_en) */
#define TSM_TIMING09init (0x03000300U) /* (bb_ldo_vcolo_fastcharge_en) */
#define TSM_TIMING10init (0x69036f03U) /* (bb_xtal_pll_ref_clk_en) */
#define TSM_TIMING11init (0xffff6f03U) /* (bb_xtal_dac_ref_clk_en) */
#define TSM_TIMING12init (0x6903ffffU) /* (rxtx_auxpll_vco_ref_clk_en) */
#define TSM_TIMING13init (0x18004c00U) /* (sy_vco_autotune_en) */
#define TSM_TIMING14init (0x69316863U) /* (sy_pd_cycle_slip_ld_ft_en) */
#define TSM_TIMING15init (0x69036f03U) /* (sy_vco_en) */
#define TSM_TIMING16init (0x691cffffU) /* (sy_lo_rx_buf_en) */
#define TSM_TIMING17init (0xffff6f58U) /* (sy_lo_tx_buf_en) */
#define TSM_TIMING18init (0x69056f05U) /* (sy_divn_en) */
#define TSM_TIMING19init (0x18034c03U) /* (sy_pd_filter_charge_en) */
#define TSM_TIMING20init (0x69036f03U) /* (sy_pd_en) */
#define TSM_TIMING21init (0x69046f04U) /* (sy_lo_divn_en) */
#define TSM_TIMING22init (0x6904ffffU) /* (sy_lo_rx_en) */
#define TSM_TIMING23init (0xffff6f04U) /* (sy_lo_tx_en) */
#define TSM_TIMING24init (0x18004c00U) /* (sy_divn_cal_en) */
#define TSM_TIMING25init (0x691dffffU) /* (rx_lna_mixer_en) */
#define TSM_TIMING26init (0xffff6e58U) /* (tx_pa_en) */
#define TSM_TIMING27init (0x6920ffffU) /* (rx_adc_i_q_en) */
#define TSM_TIMING28init (0x2120ffffU) /* (rx_adc_reset_en) */
#define TSM_TIMING29init (0x691effffU) /* (rx_bba_i_q_en) */
#define TSM_TIMING30init (0x6920ffffU) /* (rx_bba_pdet_en) */
#define TSM_TIMING31init (0x691fffffU) /* (rx_bba_tza_dcoc_en) */
#define TSM_TIMING32init (0x691dffffU) /* (rx_tza_i_q_en) */
#define TSM_TIMING33init (0x6920ffffU) /* (rx_tza_pdet_en) */
#define TSM_TIMING34init (0x69076f07U) /* (pll_dig_en) */
#define TSM_TIMING35init (0xffff6f5fU) /* (tx_dig_en) */
#define TSM_TIMING36init (0x6966ffffU) /* (rx_dig_en) */
#define TSM_TIMING37init (0x6766ffffU) /* (rx_init) */
#define TSM_TIMING38init (0x690e6f42U) /* (sigma_delta_en) */
#define TSM_TIMING39init (0x6966ffffU) /* (rx_phy_en) */
#define TSM_TIMING40init (0x6926ffffU) /* (dcoc_en) */
#define TSM_TIMING41init (0x2726ffffU) /* (dcoc_init) */
#define TSM_TIMING42init (0xffffffffU) /* (sar_adc_trig_en) */
#define TSM_TIMING43init (0xffffffffU) /* (tsm_spare0_en) */
#define TSM_TIMING44init (0xffffffffU) /* (tsm_spare1_en) */
#define TSM_TIMING45init (0xffffffffU) /* (tsm_spare2_en) */
#define TSM_TIMING46init (0xffffffffU) /* (tsm_spare3_en) */
#define TSM_TIMING47init (0xffffffffU) /* (gpio0_trig_en) */
#define TSM_TIMING48init (0xffffffffU) /* (gpio1_trig_en) */
#define TSM_TIMING49init (0xffffffffU) /* (gpio2_trig_en) */
#define TSM_TIMING50init (0xffffffffU) /* (gpio3_trig_en) */
#define TSM_TIMING51init (0x6903ffffU) /* (rxtx_auxpll_bias_en) */
#define TSM_TIMING52init (0x1706ffffU) /* (rxtx_auxpll_fcal_en) */
#define TSM_TIMING53init (0x6903ffffU) /* (rxtx_auxpll_lf_pd_en) */
#define TSM_TIMING54init (0x1703ffffU) /* (rxtx_auxpll_pd_lf_filter_charge_en) */
#define TSM_TIMING55init (0x6920ffffU) /* (rxtx_auxpll_adc_buf_en) */
#define TSM_TIMING56init (0x6920ffffU) /* (rxtx_auxpll_dig_buf_en) */
#define TSM_TIMING57init (0x1a03ffffU) /* (rxtx_rccal_en) */
#define TSM_TIMING58init (0xffff6f03U) /* (tx_hpm_dac_en) */
#define END_OF_SEQinit (0x69686f67U) /* */
#define TX_RX_ON_DELinit (0x00008a86U) /* */
#define TX_RX_SYNTH_init (0x00002318U) /* */
#endif /* RF_OSC_26MHZ == 1 */
#define AUX_PLL_DELAY (0)
/* TSM bitfield shift and value definitions */
#define TX_DIG_EN_ASSERT (95) /* Assertion time for TX_DIG_EN, used in mode specific settings */
#define ZGBE_TX_DIG_EN_ASSERT (TX_DIG_EN_ASSERT - 1) /* Zigbee TX_DIG_EN must assert 1 tick sooner, see adjustment below based on data padding */
/* EDIT THIS LINE TO CONTROL PA_RAMP! */
#define PA_RAMP_TIME (2) /* Only allowable values are [0, 1, 2, or 4] in Gen3 */
#define PA_RAMP_SEL_0US (0)
#define PA_RAMP_SEL_1US (1)
#define PA_RAMP_SEL_2US (2)
#define PA_RAMP_SEL_4US (3)
#if !((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 1) || (PA_RAMP_TIME == 2) || (PA_RAMP_TIME == 4))
#error "Invalid value for PA_RAMP_TIME macro"
#endif /* Error check of PA RAMP TIME */
#define ADD_FOR_26MHZ (4)
#define END_OF_TX_WU_NORAMP (103) /* NOTE: NORAMP and 2us ramp time behaviors are identical for TX WU and WD */
#define END_OF_TX_WD_NORAMP (111) /* NOTE: NORAMP and 2us ramp time behaviors are identical for TX WU and WD */
/* Redefine the values of END_OF_TX_WU and END_OF_TX_WD based on whether DATA PADDING is enabled and the selection of ramp time */
/* These two constants are then used on both common configuration and mode specific configuration files to define the TSM timing values */
#if ((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 1) || (PA_RAMP_TIME == 2))
#define END_OF_TX_WU (END_OF_TX_WU_NORAMP)
#define END_OF_TX_WD (END_OF_TX_WD_NORAMP)
#if (PA_RAMP_TIME == 0)
#define PA_RAMP_SEL PA_RAMP_SEL_0US
#define DATA_PADDING_EN (0)
#else
#define DATA_PADDING_EN (1)
#if (PA_RAMP_TIME == 1)
#define PA_RAMP_SEL PA_RAMP_SEL_1US
#else
#define PA_RAMP_SEL PA_RAMP_SEL_2US
#endif /* (PA_RAMP_TIME == 1) */
#endif /* (PA_RAMP_TIME == 0) */
#else /* ((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 1) || (PA_RAMP_TIME == 2)) */
#if (PA_RAMP_TIME == 4)
#define END_OF_TX_WU (END_OF_TX_WU_NORAMP + 2)
#define END_OF_TX_WD (END_OF_TX_WD_NORAMP + 4)
#define PA_RAMP_SEL PA_RAMP_SEL_4US
#define DATA_PADDING_EN (1)
#else /* (PA_RAMP_TIME == 4) */
#error "Invalid value for PA_RAMP_TIME macro"
#endif /* (PA_RAMP_TIME == 4) */
#endif/* (PA_RAMP_TIME == 4) */
#define END_OF_RX_WU (104 + AUX_PLL_DELAY)
#if RF_OSC_26MHZ == 1
#define END_OF_RX_WD (END_OF_RX_WU + 1 + ADD_FOR_26MHZ) /* Need to handle normal signals extending when 26MHZ warmdown is extended */
#else
#define END_OF_RX_WD (END_OF_RX_WU + 1)
#endif /* RF_OSC_26MHZ == 1 */
#define END_OF_RX_WU_26MHZ (END_OF_RX_WU + ADD_FOR_26MHZ)
#define END_OF_RX_WD_26MHZ (END_OF_RX_WU + 1 + ADD_FOR_26MHZ)
/* PA Bias Table - Gen3 version */
#define PA_RAMP_0 0x1
#define PA_RAMP_1 0x2
#define PA_RAMP_2 0x4
#define PA_RAMP_3 0x6
#define PA_RAMP_4 0x8
#define PA_RAMP_5 0xc
#define PA_RAMP_6 0x10
#define PA_RAMP_7 0x14
#define PA_RAMP_8 0x18
#define PA_RAMP_9 0x1c
#define PA_RAMP_10 0x22
#define PA_RAMP_11 0x28
#define PA_RAMP_12 0x2c
#define PA_RAMP_13 0x30
#define PA_RAMP_14 0x36
#define PA_RAMP_15 0x3c
#else /* Gen2 TSM definitions */
/* GEN2 TSM defines */
#define AUX_PLL_DELAY (0)
/* TSM bitfield shift and value definitions */
#define TX_DIG_EN_ASSERT (95) /* Assertion time for TX_DIG_EN, used in mode specific settings */
#define ZGBE_TX_DIG_EN_ASSERT (TX_DIG_EN_ASSERT - 1) /* Zigbee TX_DIG_EN must assert 1 tick sooner, see adjustment below based on data padding */
/* EDIT THIS LINE TO CONTROL PA_RAMP! */
#define PA_RAMP_TIME (2) /* Only allowable values are [0, 2, 4, or 8] for PA RAMP times in Gen2.0 */
#define PA_RAMP_SEL_0US (0)
#define PA_RAMP_SEL_2US (1)
#define PA_RAMP_SEL_4US (2)
#define PA_RAMP_SEL_8US (3)
#if !((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 2) || (PA_RAMP_TIME == 4) || (PA_RAMP_TIME == 8))
#error "Invalid value for PA_RAMP_TIME macro"
#endif /* Error check of PA RAMP TIME */
#define ADD_FOR_26MHZ (4)
#define END_OF_TX_WU_NORAMP (103) /* NOTE: NORAMP and 2us ramp time behaviors are identical for TX WU and WD */
#define END_OF_TX_WD_NORAMP (111) /* NOTE: NORAMP and 2us ramp time behaviors are identical for TX WU and WD */
/* Redefine the values of END_OF_TX_WU and END_OF_TX_WD based on whether DATA PADDING is enabled and the selection of ramp time */
/* These two constants are then used on both common configuration and mode specific configuration files to define the TSM timing values */
#if ((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 2))
#define END_OF_TX_WU (END_OF_TX_WU_NORAMP)
#define END_OF_TX_WD (END_OF_TX_WD_NORAMP)
#define TX_SYNTH_DELAY_ADJ (0)
#define PD_CYCLE_SLIP_TX_HI_ADJ (0)
#define PD_CYCLE_SLIP_TX_LO_ADJ (1)
#define ZGBE_TX_DIG_EN_TX_HI_ADJ (-5) /* Only applies to Zigbee mode */
#if (PA_RAMP_TIME == 0)
#define PA_RAMP_SEL PA_RAMP_SEL_0US
#define DATA_PADDING_EN (0)
#define TX_DIG_EN_TX_HI_ADJ (-2)
#else
#define DATA_PADDING_EN (1)
#define TX_DIG_EN_TX_HI_ADJ (0)
#define PA_RAMP_SEL PA_RAMP_SEL_2US
#endif /* (PA_RAMP_TIME == 0) */
#else /* ((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 2)) */
#if (PA_RAMP_TIME == 4)
#define END_OF_TX_WU (END_OF_TX_WU_NORAMP + 2)
#define END_OF_TX_WD (END_OF_TX_WD_NORAMP + 4)
#define TX_SYNTH_DELAY_ADJ (2)
#define PD_CYCLE_SLIP_TX_HI_ADJ (2)
#define PD_CYCLE_SLIP_TX_LO_ADJ (1)
#define TX_DIG_EN_TX_HI_ADJ (0)
#define ZGBE_TX_DIG_EN_TX_HI_ADJ (-3) /* Only applies to Zigbee mode */
#define PA_RAMP_SEL PA_RAMP_SEL_4US
#define DATA_PADDING_EN (1)
#else /* (PA_RAMP_TIME==4) */
#if ((PA_RAMP_TIME == 8) && (!RADIO_IS_GEN_3P0))
#define END_OF_TX_WU (END_OF_TX_WU_NORAMP + 6)
#define END_OF_TX_WD (END_OF_TX_WD_NORAMP + 12)
#define TX_SYNTH_DELAY_ADJ (6)
#define PD_CYCLE_SLIP_TX_HI_ADJ (6)
#define PD_CYCLE_SLIP_TX_LO_ADJ (1)
#define TX_DIG_EN_TX_HI_ADJ (4)
#define ZGBE_TX_DIG_EN_TX_HI_ADJ (1) /* Only applies to Zigbee mode */
#define PA_RAMP_SEL PA_RAMP_SEL_8US
#define DATA_PADDING_EN (1)
#else /* (PA_RAMP_TIME == 8) */
#error "Invalid value for PA_RAMP_TIME macro"
#endif /* (PA_RAMP_TIME == 8) */
#endif/* (PA_RAMP_TIME == 4) */
#endif /* ((PA_RAMP_TIME == 0) || (PA_RAMP_TIME == 2)) */
#define TX_DIG_EN_ASSERT_MSK500 (END_OF_TX_WU - 3)
#define END_OF_RX_WU (104 + AUX_PLL_DELAY)
#if RF_OSC_26MHZ == 1
#define END_OF_RX_WD (END_OF_RX_WU + 1 + ADD_FOR_26MHZ) /* Need to handle normal signals extending when 26MHZ warmdown is extended */
#else
#define END_OF_RX_WD (END_OF_RX_WU + 1)
#endif /* RF_OSC_26MHZ == 1 */
#define END_OF_RX_WU_26MHZ (END_OF_RX_WU + ADD_FOR_26MHZ)
#define END_OF_RX_WD_26MHZ (END_OF_RX_WU + 1 + ADD_FOR_26MHZ)
/* PA Bias Table */
#define PA_RAMP_0 0x1
#define PA_RAMP_1 0x2
#define PA_RAMP_2 0x4
#define PA_RAMP_3 0x8
#define PA_RAMP_4 0xe
#define PA_RAMP_5 0x16
#define PA_RAMP_6 0x22
#define PA_RAMP_7 0x2e
/* BLE LL timing definitions */
#define TX_ON_DELAY (0x85) /* Adjusted TX_ON_DELAY to make turnaround time 150usec */
#define RX_ON_DELAY (29 + END_OF_RX_WU+4)
#define RX_ON_DELAY_26MHZ (29 + END_OF_RX_WU_26MHZ+4)
#define TX_RX_ON_DELAY_VAL (TX_ON_DELAY << 8 | RX_ON_DELAY)
#define TX_RX_ON_DELAY_VAL_26MHZ (TX_ON_DELAY << 8 | RX_ON_DELAY_26MHZ)
#define TX_SYNTH_DELAY (TX_ON_DELAY - END_OF_TX_WU - TX_SYNTH_DELAY_ADJ) /* Adjustment to TX_SYNTH_DELAY due to DATA_PADDING */
#define RX_SYNTH_DELAY (0x18)
#define TX_RX_SYNTH_DELAY_VAL (TX_SYNTH_DELAY << 8 | RX_SYNTH_DELAY)
/* PHY reference waveform assembly */
#define RW0PS(loc, val) (((val) & 0x1F) << ((loc) * 5)) /* Ref Word 0 - loc is the phase info symbol number, val is the value of the phase info */
#define RW1PS(loc, val) (((val) & 0x1F) << (((loc) * 5) - 32)) /* Ref Word 1 - loc is the phase info symbol number, val is the value of the phase info */
#define RW2PS(loc, val) (((val) & 0x1F) << (((loc) * 5) - 64)) /* Ref Word 2 - loc is the phase info symbol number, val is the value of the phase info */
#endif /* RADIO_IS_GEN_3P0 */
/*! @brief Error codes for the XCVR driver. */
typedef enum _xcvrStatus
{
gXcvrSuccess_c = 0,
gXcvrInvalidParameters_c,
gXcvrUnsupportedOperation_c,
gXcvrTrimFailure_c
} xcvrStatus_t;
/*! @brief Health status returned from PHY upon status check function return. */
typedef enum _healthStatus
{
NO_ERRORS = 0,
PLL_CTUNE_FAIL = 1,
PLL_CYCLE_SLIP_FAIL = 2,
PLL_FREQ_TARG_FAIL = 4,
PLL_TSM_ABORT_FAIL = 8,
} healthStatus_t;
/*! @brief Health status returned from PHY upon status check function return. */
typedef enum _ext_clock_config
{
EXT_CLK_32_MHZ = 0,
EXT_CLK_26_MHZ = 1,
} ext_clock_config_t;
/*! @brief Radio operating mode setting types. */
typedef enum
{
BLE_MODE = 0,
ZIGBEE_MODE = 1,
ANT_MODE = 2,
/* BT=0.5, h=** */
GFSK_BT_0p5_h_0p5 = 3, /* < BT=0.5, h=0.5 [BLE at 1MBPS data rate; CS4 at 250KBPS data rate] */
GFSK_BT_0p5_h_0p32 = 4, /* < BT=0.5, h=0.32*/
GFSK_BT_0p5_h_0p7 = 5, /* < BT=0.5, h=0.7 [ CS1 at 500KBPS data rate] */
GFSK_BT_0p5_h_1p0 = 6, /* < BT=0.5, h=1.0 [ CS4 at 250KBPS data rate] */
/* BT=** h=0.5 */
GFSK_BT_0p3_h_0p5 = 7, /* < BT=0.3, h=0.5 [ CS2 at 1MBPS data rate] */
GFSK_BT_0p7_h_0p5 = 8, /* < BT=0.7, h=0.5 */
MSK = 9,
NUM_RADIO_MODES = 10,
} radio_mode_t;
/*! @brief Link layer types. */
typedef enum
{
BLE_LL = 0, /* Must match bit assignment in RADIO1_IRQ_SEL */
ZIGBEE_LL = 1, /* Must match bit assignment in RADIO1_IRQ_SEL */
ANT_LL = 2, /* Must match bit assignment in RADIO1_IRQ_SEL */
GENFSK_LL = 3, /* Must match bit assignment in RADIO1_IRQ_SEL */
UNASSIGNED_LL = 4, /* Must match bit assignment in RADIO1_IRQ_SEL */
} link_layer_t;
/*! @brief Data rate selections. */
typedef enum
{
DR_1MBPS = 0, /* Must match bit assignment in BITRATE field */
DR_500KBPS = 1, /* Must match bit assignment in BITRATE field */
DR_250KBPS = 2, /* Must match bit assignment in BITRATE field */
#if RADIO_IS_GEN_3P0
DR_2MBPS = 3, /* Must match bit assignment in BITRATE field */
#endif /* RADIO_IS_GEN_3P0 */
DR_UNASSIGNED = 4, /* Must match bit assignment in BITRATE field */
} data_rate_t;
/*!
* @brief XCVR RX_DIG channel filter coefficient storage
* Storage of the coefficients varies from 6 bits to 10 bits so all use int16_t for storage.
*/
typedef struct
{
uint16_t rx_chf_coef_0; /* < 6 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_1; /* < 6 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_2; /* < 7 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_3; /* < 7 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_4; /* < 7 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_5; /* < 7 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_6; /* < 8 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_7; /* < 8 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_8; /* < 9 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_9; /* < 9 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_10; /* < 10 bit two's complement stored in a uint16_t */
uint16_t rx_chf_coef_11; /* < 10 bit two's complement stored in a uint16_t */
} xcvr_rx_chf_coeffs_t;
/*!
* @brief XCVR masked init type for 32 bit registers
* Initialization uses the mask to clear selected fields of the register and then OR's in the init value. All init values must be in their proper field position.
*/
typedef struct
{
uint32_t mask;
uint32_t init;
} xcvr_masked_init_32_t;
/*!
* @brief XCVR common configure structure
*/
typedef struct
{
/* XCVR_ANA configs */
xcvr_masked_init_32_t ana_sy_ctrl1;
/* XCVR_PLL_DIG configs */
uint32_t pll_hpm_bump;
uint32_t pll_mod_ctrl;
uint32_t pll_chan_map;
uint32_t pll_lock_detect;
uint32_t pll_hpm_ctrl;
#if !RADIO_IS_GEN_2P1
uint32_t pll_hpmcal_ctrl;
#endif /* !RADIO_IS_GEN_2P1 */
uint32_t pll_hpm_sdm_res;
uint32_t pll_lpm_ctrl;
uint32_t pll_lpm_sdm_ctrl1;
uint32_t pll_delay_match;
uint32_t pll_ctune_ctrl;
/* XCVR_RX_DIG configs */
uint32_t rx_dig_ctrl_init; /* NOTE: Common init, mode init, and datarate init will be OR'd together for RX_DIG_CTRL to form complete register initialization */
uint32_t dcoc_ctrl_0_init_26mhz; /* NOTE: This will be OR'd with mode specific init for DCOC_CTRL_0 to form complete register initialization */
uint32_t dcoc_ctrl_0_init_32mhz; /* NOTE: This will be OR'd with mode specific init for DCOC_CTRL_0 to form complete register initialization */
uint32_t dcoc_ctrl_1_init;
uint32_t dcoc_cal_gain_init;
uint32_t dc_resid_ctrl_init; /* NOTE: This will be OR'd with datarate specific init for DCOC_RESID_CTRL to form complete register initialization */
uint32_t dcoc_cal_rcp_init;
uint32_t lna_gain_val_3_0;
uint32_t lna_gain_val_7_4;
uint32_t lna_gain_val_8;
uint32_t bba_res_tune_val_7_0;
uint32_t bba_res_tune_val_10_8;
uint32_t lna_gain_lin_val_2_0_init;
uint32_t lna_gain_lin_val_5_3_init;
uint32_t lna_gain_lin_val_8_6_init;
uint32_t lna_gain_lin_val_9_init;
uint32_t bba_res_tune_lin_val_3_0_init;
uint32_t bba_res_tune_lin_val_7_4_init;
uint32_t bba_res_tune_lin_val_10_8_init;
uint32_t dcoc_bba_step_init;
uint32_t dcoc_tza_step_00_init;
uint32_t dcoc_tza_step_01_init;
uint32_t dcoc_tza_step_02_init;
uint32_t dcoc_tza_step_03_init;
uint32_t dcoc_tza_step_04_init;
uint32_t dcoc_tza_step_05_init;
uint32_t dcoc_tza_step_06_init;
uint32_t dcoc_tza_step_07_init;
uint32_t dcoc_tza_step_08_init;
uint32_t dcoc_tza_step_09_init;
uint32_t dcoc_tza_step_10_init;
#if (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1)
uint32_t dcoc_cal_fail_th_init;
uint32_t dcoc_cal_pass_th_init;
#endif /* (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1) */
uint32_t agc_ctrl_0_init; /* NOTE: Common init and mode init will be OR'd together for AGC_CTRL_0 to form complete register initialization */
uint32_t agc_ctrl_1_init_26mhz; /* NOTE: This will be OR'd with datarate specific init to form complete register initialization */
uint32_t agc_ctrl_1_init_32mhz; /* NOTE: This will be OR'd with datarate specific init to form complete register initialization */
uint32_t agc_ctrl_3_init;
/* Other agc config inits are in the modeXdatarate config table */
uint32_t agc_gain_tbl_03_00_init;
uint32_t agc_gain_tbl_07_04_init;
uint32_t agc_gain_tbl_11_08_init;
uint32_t agc_gain_tbl_15_12_init;
uint32_t agc_gain_tbl_19_16_init;
uint32_t agc_gain_tbl_23_20_init;
uint32_t agc_gain_tbl_26_24_init;
uint32_t rssi_ctrl_0_init;
#if RADIO_IS_GEN_3P0
uint32_t rssi_ctrl_1_init;
#endif /* RADIO_IS_GEN_3P0 */
uint32_t cca_ed_lqi_ctrl_0_init;
uint32_t cca_ed_lqi_ctrl_1_init;
/* XCVR_TSM configs */
uint32_t tsm_ctrl;
uint32_t tsm_ovrd2_init;
uint32_t end_of_seq_init_26mhz;
uint32_t end_of_seq_init_32mhz;
#if !RADIO_IS_GEN_2P1
uint32_t lpps_ctrl_init;
#endif /* !RADIO_IS_GEN_2P1 */
uint32_t tsm_fast_ctrl2_init_26mhz;
uint32_t tsm_fast_ctrl2_init_32mhz;
uint32_t recycle_count_init_26mhz;
uint32_t recycle_count_init_32mhz;
uint32_t pa_ramp_tbl_0_init;
uint32_t pa_ramp_tbl_1_init;
#if RADIO_IS_GEN_3P0
uint32_t pa_ramp_tbl_2_init;
uint32_t pa_ramp_tbl_3_init;
#endif /* RADIO_IS_GEN_3P0 */
uint32_t tsm_timing_00_init;
uint32_t tsm_timing_01_init;
uint32_t tsm_timing_02_init;
uint32_t tsm_timing_03_init;
uint32_t tsm_timing_04_init;
uint32_t tsm_timing_05_init;
uint32_t tsm_timing_06_init;
uint32_t tsm_timing_07_init;
uint32_t tsm_timing_08_init;
uint32_t tsm_timing_09_init;
uint32_t tsm_timing_10_init;
uint32_t tsm_timing_11_init;
uint32_t tsm_timing_12_init;
uint32_t tsm_timing_13_init;
uint32_t tsm_timing_14_init_26mhz; /* tsm_timing_14 has mode specific LSbyte (both LS bytes) */
uint32_t tsm_timing_14_init_32mhz; /* tsm_timing_14 has mode specific LSbyte (both LS bytes) */
uint32_t tsm_timing_15_init;
uint32_t tsm_timing_16_init_26mhz;
uint32_t tsm_timing_16_init_32mhz;
uint32_t tsm_timing_17_init;
uint32_t tsm_timing_18_init;
uint32_t tsm_timing_19_init;
uint32_t tsm_timing_20_init;
uint32_t tsm_timing_21_init;
uint32_t tsm_timing_22_init;
uint32_t tsm_timing_23_init;
uint32_t tsm_timing_24_init;
uint32_t tsm_timing_25_init_26mhz;
uint32_t tsm_timing_25_init_32mhz;
uint32_t tsm_timing_26_init;
uint32_t tsm_timing_27_init_26mhz;
uint32_t tsm_timing_27_init_32mhz;
uint32_t tsm_timing_28_init_26mhz;
uint32_t tsm_timing_28_init_32mhz;
uint32_t tsm_timing_29_init_26mhz;
uint32_t tsm_timing_29_init_32mhz;
uint32_t tsm_timing_30_init_26mhz;
uint32_t tsm_timing_30_init_32mhz;
uint32_t tsm_timing_31_init_26mhz;
uint32_t tsm_timing_31_init_32mhz;
uint32_t tsm_timing_32_init_26mhz;
uint32_t tsm_timing_32_init_32mhz;
uint32_t tsm_timing_33_init_26mhz;
uint32_t tsm_timing_33_init_32mhz;
uint32_t tsm_timing_34_init;
uint32_t tsm_timing_35_init; /* tsm_timing_35 has a mode specific LSbyte*/
uint32_t tsm_timing_36_init_26mhz;
uint32_t tsm_timing_36_init_32mhz;
uint32_t tsm_timing_37_init_26mhz;
uint32_t tsm_timing_37_init_32mhz;
uint32_t tsm_timing_38_init;
uint32_t tsm_timing_39_init_26mhz;
uint32_t tsm_timing_39_init_32mhz;
uint32_t tsm_timing_40_init_26mhz;
uint32_t tsm_timing_40_init_32mhz;
uint32_t tsm_timing_41_init_26mhz;
uint32_t tsm_timing_41_init_32mhz;
uint32_t tsm_timing_51_init;
uint32_t tsm_timing_52_init_26mhz;
uint32_t tsm_timing_52_init_32mhz;
uint32_t tsm_timing_53_init;
uint32_t tsm_timing_54_init_26mhz;
uint32_t tsm_timing_54_init_32mhz;
uint32_t tsm_timing_55_init_26mhz;
uint32_t tsm_timing_55_init_32mhz;
uint32_t tsm_timing_56_init_26mhz;
uint32_t tsm_timing_56_init_32mhz;
uint32_t tsm_timing_57_init;
uint32_t tsm_timing_58_init;
/* XCVR_TX_DIG configs */
uint32_t tx_ctrl;
uint32_t tx_data_padding;
uint32_t tx_dft_pattern;
#if !RADIO_IS_GEN_2P1
uint32_t rf_dft_bist_1;
uint32_t rf_dft_bist_2;
#endif /* !RADIO_IS_GEN_2P1 */
} xcvr_common_config_t;
/*! @brief XCVR mode specific configure structure (varies by radio mode) */
typedef struct
{
radio_mode_t radio_mode;
uint32_t scgc5_clock_ena_bits;
/* XCVR_MISC configs */
xcvr_masked_init_32_t xcvr_ctrl;
/* XCVR_PHY configs */
#if RADIO_IS_GEN_3P0
uint32_t phy_fsk_pd_cfg0;
uint32_t phy_fsk_pd_cfg1;
uint32_t phy_fsk_cfg;
uint32_t phy_fsk_misc;
uint32_t phy_fad_ctrl;
#else
uint32_t phy_pre_ref0_init;
uint32_t phy_pre_ref1_init;
uint32_t phy_pre_ref2_init;
uint32_t phy_cfg1_init;
uint32_t phy_el_cfg_init; /* EL_WIN_SIZE and EL_INTERVAL are in the data_rate specific configuration */
#endif /* RADIO_IS_GEN_3P0 */
/* XCVR_RX_DIG configs */
uint32_t rx_dig_ctrl_init_26mhz; /* NOTE: Common init, mode init, and datarate init will be OR'd together for RX_DIG_CTRL to form complete register initialization */
uint32_t rx_dig_ctrl_init_32mhz; /* NOTE: Common init, mode init, and datarate init will be OR'd together for RX_DIG_CTRL to form complete register initialization */
uint32_t agc_ctrl_0_init; /* NOTE: Common init and mode init will be OR'd together for AGC_CTRL_0 to form complete register initialization */
/* XCVR_TSM configs */
#if (RADIO_IS_GEN_2P0 || RADIO_IS_GEN_2P1)
uint32_t tsm_timing_35_init; /* Only the LSbyte is mode specific */
#endif /* (RADIO_IS_GEN_2P0 || RADIO_IS_GEN_2P1) */
/* XCVR_TX_DIG configs */
uint32_t tx_gfsk_ctrl;
uint32_t tx_gfsk_coeff1_26mhz;
uint32_t tx_gfsk_coeff2_26mhz;
uint32_t tx_gfsk_coeff1_32mhz;
uint32_t tx_gfsk_coeff2_32mhz;
} xcvr_mode_config_t;
/*!
* @brief XCVR modeXdatarate specific configure structure (varies by radio mode AND data rate)
* This structure is used to store all of the XCVR settings which are dependent upon both radio mode and data rate. It is used as an overlay
* on top of the xcvr_mode_config_t structure to supply definitions which are either not in that table or which must be overridden for data rate.
*/
typedef struct
{
radio_mode_t radio_mode;
data_rate_t data_rate;
/* XCVR_ANA configs */
xcvr_masked_init_32_t ana_sy_ctrl2;
xcvr_masked_init_32_t ana_rx_bba;
xcvr_masked_init_32_t ana_rx_tza;
/* XCVR_PHY configs */
#if RADIO_IS_GEN_3P0
uint32_t phy_fsk_misc_mode_datarate;
#else
uint32_t phy_cfg2_init;
#endif /* RADIO_IS_GEN_3P0 */
uint32_t agc_ctrl_2_init_26mhz;
uint32_t agc_ctrl_2_init_32mhz;
xcvr_rx_chf_coeffs_t rx_chf_coeffs_26mhz; /* 26MHz ext clk */
xcvr_rx_chf_coeffs_t rx_chf_coeffs_32mhz; /* 32MHz ext clk */
uint32_t rx_rccal_ctrl_0;
uint32_t rx_rccal_ctrl_1;
/* XCVR_TX_DIG configs */
uint32_t tx_fsk_scale_26mhz; /* Only used by MSK mode, but dependent on datarate */
uint32_t tx_fsk_scale_32mhz; /* Only used by MSK mode, but dependent on datarate */
} xcvr_mode_datarate_config_t;
/*!
* @brief XCVR datarate specific configure structure (varies by data rate)
* This structure is used to store all of the XCVR settings which are dependent upon data rate. It is used as an overlay
* on top of the xcvr_mode_config_t structure to supply definitions which are either not in that table or which must be overridden for data rate.
*/
typedef struct
{
data_rate_t data_rate;
/* XCVR_PHY configs */
uint32_t phy_el_cfg_init; /* Note: EL_ENABLE is set in xcvr_mode_config_t settings */
/* XCVR_RX_DIG configs */
uint32_t rx_dig_ctrl_init_26mhz; /* NOTE: Common init, mode init, and datarate init will be OR'd together for RX_DIG_CTRL to form complete register initialization */
uint32_t rx_dig_ctrl_init_32mhz; /* NOTE: Common init, mode init, and datarate init will be OR'd together for RX_DIG_CTRL to form complete register initialization */
uint32_t agc_ctrl_1_init_26mhz;
uint32_t agc_ctrl_1_init_32mhz;
uint32_t dcoc_ctrl_0_init_26mhz; /* NOTE: This will be OR'd with common init for DCOC_CTRL_0 to form complete register initialization */
uint32_t dcoc_ctrl_0_init_32mhz; /* NOTE: This will be OR'd with common init for DCOC_CTRL_0 to form complete register initialization */
uint32_t dcoc_ctrl_1_init_26mhz; /* NOTE: This will be OR'd with common init for DCOC_CTRL_1 to form complete register initialization */
uint32_t dcoc_ctrl_1_init_32mhz; /* NOTE: This will be OR'd with common init for DCOC_CTRL_1 to form complete register initialization */
uint32_t dcoc_ctrl_2_init_26mhz;
uint32_t dcoc_ctrl_2_init_32mhz;
uint32_t dcoc_cal_iir_init_26mhz;
uint32_t dcoc_cal_iir_init_32mhz;
uint32_t dc_resid_ctrl_26mhz;/* NOTE: This will be OR'd with common init for DCOC_RESID_CTRL to form complete register initialization */
uint32_t dc_resid_ctrl_32mhz;/* NOTE: This will be OR'd with common init for DCOC_RESID_CTRL to form complete register initialization */
} xcvr_datarate_config_t;
/*!
* @brief LPUART callback function type
*
* The panic callback function is defined by system if system need to be informed of XCVR fatal errors.
* refer to #XCVR_RegisterPanicCb
*/
typedef void (*panic_fptr)(uint32_t panic_id, uint32_t location, uint32_t extra1, uint32_t extra2);
/* Make available const structures from config files */
extern const xcvr_common_config_t xcvr_common_config;
extern const xcvr_mode_config_t zgbe_mode_config;
extern const xcvr_mode_config_t ble_mode_config;
extern const xcvr_mode_config_t ant_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p5_h_0p5_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p5_h_0p7_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p5_h_0p32_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p5_h_1p0_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p3_h_0p5_mode_config;
extern const xcvr_mode_config_t gfsk_bt_0p7_h_0p5_mode_config;
extern const xcvr_mode_config_t msk_mode_config;
#if RADIO_IS_GEN_3P0
extern const xcvr_datarate_config_t xcvr_2mbps_config;
#endif /* RADIO_IS_GEN_3P0 */
extern const xcvr_datarate_config_t xcvr_1mbps_config;
extern const xcvr_datarate_config_t xcvr_500kbps_config;
extern const xcvr_datarate_config_t xcvr_250kbps_config;
extern const xcvr_datarate_config_t xcvr_802_15_4_500kbps_config; /* Custom datarate settings for 802.15.4 since it is 2MChips/sec */
#if RADIO_IS_GEN_3P0
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p5_2mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p32_2mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p3_h_0p5_2mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p7_h_0p5_2mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_MSK_2mbps_config;
#endif /* RADIO_IS_GEN_3P0 */
extern const xcvr_mode_datarate_config_t xcvr_BLE_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_ZIGBEE_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_ANT_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p5_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p5_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p5_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p32_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p32_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p32_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p7_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p7_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_0p7_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_1p0_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_1p0_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p5_h_1p0_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p3_h_0p5_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p3_h_0p5_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p3_h_0p5_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p7_h_0p5_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p7_h_0p5_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_GFSK_BT_0p7_h_0p5_250kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_MSK_1mbps_config;
extern const xcvr_mode_datarate_config_t xcvr_MSK_500kbps_config;
extern const xcvr_mode_datarate_config_t xcvr_MSK_250kbps_config;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
/*! @}*/
#endif /* _FSL_XCVR_H_ */

View File

@ -0,0 +1,628 @@
/*
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* 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.
*/
#include "fsl_xcvr.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
const xcvr_common_config_t xcvr_common_config =
{
/* XCVR_ANA configs */
.ana_sy_ctrl1.mask = XCVR_ANALOG_SY_CTRL_1_SY_LPF_FILT_CTRL_MASK,
.ana_sy_ctrl1.init = XCVR_ANALOG_SY_CTRL_1_SY_LPF_FILT_CTRL(3), /* PLL Analog Loop Filter */
#define hpm_vcm_tx 0
#define hpm_vcm_cal 1
#define hpm_fdb_res_tx 0
#define hpm_fdb_res_cal 1
#define modulation_word_manual 0
#define mod_disable 0
#define hpm_mod_manual 0
#define hpm_mod_disable 0
#define hpm_sdm_out_manual 0
#define hpm_sdm_out_disable 0
#define channel_num 0
#define boc 0
#define bmr 1
#define zoc 0
#define ctune_ldf_lev 8
#define ftf_rx_thrsh 33
#define ftw_rx 0
#define ftf_tx_thrsh 6
#define ftw_tx 0
#define freq_count_go 0
#define freq_count_time 0
#define hpm_sdm_in_manual 0
#define hpm_sdm_out_invert 0
#define hpm_sdm_in_disable 0
#define hpm_lfsr_size 4
#define hpm_dth_scl 0
#define hpm_dth_en 1
#define hpm_integer_scale 0
#define hpm_integer_invert 0
#define hpm_cal_invert 1
#define hpm_mod_in_invert 1
#define hpm_cal_not_bumped 0
#define hpm_cal_count_scale 0
#define hp_cal_disable 0
#define hpm_cal_factor_manual 0
#define hpm_cal_array_size 1
#define hpm_cal_time 0
#define hpm_sdm_denom 256
#define hpm_count_adjust 0
#define pll_ld_manual 0
#define pll_ld_disable 0
#define lpm_sdm_inv 0
#define lpm_disable 0
#define lpm_dth_scl 8
#define lpm_d_ctrl 1
#define lpm_d_ovrd 1
#define lpm_scale 8
#define lpm_sdm_use_neg 0
#define hpm_array_bias 0
#define lpm_intg 38
#define sdm_map_disable 0
#define lpm_sdm_delay 4
#define hpm_sdm_delay 0
#define hpm_integer_delay 0
#define ctune_target_manual 0
#define ctune_target_disable 0
#define ctune_adjust 0
#define ctune_manual 0
#define ctune_disable 0
/*-------------------------------------------------------------------------------------------------*/
.pll_hpm_bump = XCVR_PLL_DIG_HPM_BUMP_HPM_FDB_RES_CAL(hpm_fdb_res_cal) |
XCVR_PLL_DIG_HPM_BUMP_HPM_FDB_RES_TX(hpm_fdb_res_tx) |
XCVR_PLL_DIG_HPM_BUMP_HPM_VCM_CAL(hpm_vcm_cal) |
XCVR_PLL_DIG_HPM_BUMP_HPM_VCM_TX(hpm_vcm_tx),
/*-------------------------------------------------------------------------------------------------*/
.pll_mod_ctrl = XCVR_PLL_DIG_MOD_CTRL_HPM_MOD_DISABLE(hpm_mod_disable) |
XCVR_PLL_DIG_MOD_CTRL_HPM_MOD_MANUAL(hpm_mod_manual) |
XCVR_PLL_DIG_MOD_CTRL_HPM_SDM_OUT_DISABLE(hpm_sdm_out_disable) |
XCVR_PLL_DIG_MOD_CTRL_HPM_SDM_OUT_MANUAL(hpm_sdm_out_manual) |
XCVR_PLL_DIG_MOD_CTRL_MOD_DISABLE(mod_disable) |
XCVR_PLL_DIG_MOD_CTRL_MODULATION_WORD_MANUAL(modulation_word_manual),
/*-------------------------------------------------------------------------------------------------*/
.pll_chan_map = XCVR_PLL_DIG_CHAN_MAP_BMR(bmr) |
XCVR_PLL_DIG_CHAN_MAP_BOC(boc) |
XCVR_PLL_DIG_CHAN_MAP_CHANNEL_NUM(channel_num)
#if !RADIO_IS_GEN_2P1
| XCVR_PLL_DIG_CHAN_MAP_ZOC(zoc)
#endif /* !RADIO_IS_GEN_2P1 */
,
/*-------------------------------------------------------------------------------------------------*/
.pll_lock_detect = XCVR_PLL_DIG_LOCK_DETECT_CTUNE_LDF_LEV(ctune_ldf_lev) |
XCVR_PLL_DIG_LOCK_DETECT_FREQ_COUNT_GO(freq_count_go) |
XCVR_PLL_DIG_LOCK_DETECT_FREQ_COUNT_TIME(freq_count_time) |
XCVR_PLL_DIG_LOCK_DETECT_FTF_RX_THRSH(ftf_rx_thrsh) |
XCVR_PLL_DIG_LOCK_DETECT_FTF_TX_THRSH(ftf_tx_thrsh) |
XCVR_PLL_DIG_LOCK_DETECT_FTW_RX(ftw_rx) |
XCVR_PLL_DIG_LOCK_DETECT_FTW_TX(ftw_tx),
/*-------------------------------------------------------------------------------------------------*/
.pll_hpm_ctrl = XCVR_PLL_DIG_HPM_CTRL_HPM_CAL_INVERT(hpm_cal_invert) |
XCVR_PLL_DIG_HPM_CTRL_HPM_DTH_EN(hpm_dth_en) |
XCVR_PLL_DIG_HPM_CTRL_HPM_DTH_SCL(hpm_dth_scl) |
XCVR_PLL_DIG_HPM_CTRL_HPM_INTEGER_INVERT(hpm_integer_invert) |
XCVR_PLL_DIG_HPM_CTRL_HPM_INTEGER_SCALE(hpm_integer_scale) |
XCVR_PLL_DIG_HPM_CTRL_HPM_LFSR_SIZE(hpm_lfsr_size) |
XCVR_PLL_DIG_HPM_CTRL_HPM_MOD_IN_INVERT(hpm_mod_in_invert) |
XCVR_PLL_DIG_HPM_CTRL_HPM_SDM_IN_DISABLE(hpm_sdm_in_disable) |
XCVR_PLL_DIG_HPM_CTRL_HPM_SDM_IN_MANUAL(hpm_sdm_in_manual) |
XCVR_PLL_DIG_HPM_CTRL_HPM_SDM_OUT_INVERT(hpm_sdm_out_invert),
/*-------------------------------------------------------------------------------------------------*/
#if !RADIO_IS_GEN_2P1
.pll_hpmcal_ctrl = XCVR_PLL_DIG_HPMCAL_CTRL_HP_CAL_DISABLE(hp_cal_disable) |
XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_ARRAY_SIZE(hpm_cal_array_size) |
XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_COUNT_SCALE(hpm_cal_count_scale) |
XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_FACTOR_MANUAL(hpm_cal_factor_manual) |
XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_NOT_BUMPED(hpm_cal_not_bumped) |
XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_TIME(hpm_cal_time),
#endif /* !RADIO_IS_GEN_2P1 */
/*-------------------------------------------------------------------------------------------------*/
.pll_hpm_sdm_res = XCVR_PLL_DIG_HPM_SDM_RES_HPM_COUNT_ADJUST(hpm_count_adjust) |
XCVR_PLL_DIG_HPM_SDM_RES_HPM_DENOM(hpm_sdm_denom),
/*-------------------------------------------------------------------------------------------------*/
.pll_lpm_ctrl = XCVR_PLL_DIG_LPM_CTRL_LPM_D_CTRL(lpm_d_ctrl) |
XCVR_PLL_DIG_LPM_CTRL_LPM_D_OVRD(lpm_d_ovrd) |
XCVR_PLL_DIG_LPM_CTRL_LPM_DISABLE(lpm_disable) |
XCVR_PLL_DIG_LPM_CTRL_LPM_DTH_SCL(lpm_dth_scl) |
XCVR_PLL_DIG_LPM_CTRL_LPM_SCALE(lpm_scale) |
XCVR_PLL_DIG_LPM_CTRL_LPM_SDM_INV(lpm_sdm_inv) |
XCVR_PLL_DIG_LPM_CTRL_LPM_SDM_USE_NEG(lpm_sdm_use_neg) |
XCVR_PLL_DIG_LPM_CTRL_PLL_LD_DISABLE(pll_ld_disable) |
XCVR_PLL_DIG_LPM_CTRL_PLL_LD_MANUAL(pll_ld_manual),
/*-------------------------------------------------------------------------------------------------*/
.pll_lpm_sdm_ctrl1 = XCVR_PLL_DIG_LPM_SDM_CTRL1_HPM_ARRAY_BIAS(hpm_array_bias) |
XCVR_PLL_DIG_LPM_SDM_CTRL1_LPM_INTG(lpm_intg) |
XCVR_PLL_DIG_LPM_SDM_CTRL1_SDM_MAP_DISABLE(sdm_map_disable),
/*-------------------------------------------------------------------------------------------------*/
.pll_delay_match = XCVR_PLL_DIG_DELAY_MATCH_HPM_INTEGER_DELAY(hpm_integer_delay) |
XCVR_PLL_DIG_DELAY_MATCH_HPM_SDM_DELAY(hpm_sdm_delay) |
XCVR_PLL_DIG_DELAY_MATCH_LPM_SDM_DELAY(lpm_sdm_delay),
/*-------------------------------------------------------------------------------------------------*/
.pll_ctune_ctrl = XCVR_PLL_DIG_CTUNE_CTRL_CTUNE_ADJUST(ctune_adjust) |
XCVR_PLL_DIG_CTUNE_CTRL_CTUNE_DISABLE(ctune_disable) |
XCVR_PLL_DIG_CTUNE_CTRL_CTUNE_MANUAL(ctune_manual) |
XCVR_PLL_DIG_CTUNE_CTRL_CTUNE_TARGET_DISABLE(ctune_target_disable) |
XCVR_PLL_DIG_CTUNE_CTRL_CTUNE_TARGET_MANUAL(ctune_target_manual),
/*-------------------------------------------------------------------------------------------------*/
/* XCVR_RX_DIG configs */
/* NOTE: Clock specific settings are embedded in the mode dependent configs */
.rx_dig_ctrl_init = XCVR_RX_DIG_RX_DIG_CTRL_RX_ADC_NEGEDGE(0) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_CH_FILT_BYPASS(0) |
#if !RADIO_IS_GEN_2P1
XCVR_RX_DIG_RX_DIG_CTRL_RX_ADC_RAW_EN(0) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_RX_DIG_RX_DIG_CTRL_RX_ADC_POL(0) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_NORM_EN(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_RSSI_EN(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_AGC_EN(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_EN(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DCOC_CAL_EN(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_IQ_SWAP(0) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DMA_DTEST_EN(0) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_HZD_CORR_DIS(1),
.agc_ctrl_0_init = XCVR_RX_DIG_AGC_CTRL_0_SLOW_AGC_EN(1) |
XCVR_RX_DIG_AGC_CTRL_0_SLOW_AGC_SRC(2) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_FREEZE_EN(1) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_FREEZE_PRE_OR_AA(0) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_UP_EN(1) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_UP_SRC(0) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_DOWN_BBA_STEP_SZ(2) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_DOWN_LNA_STEP_SZ(2) |
XCVR_RX_DIG_AGC_CTRL_0_AGC_UP_RSSI_THRESH(0xe7),
.agc_ctrl_3_init = XCVR_RX_DIG_AGC_CTRL_3_AGC_UNFREEZE_TIME(21) |
XCVR_RX_DIG_AGC_CTRL_3_AGC_PDET_LO_DLY(2) |
XCVR_RX_DIG_AGC_CTRL_3_AGC_RSSI_DELT_H2S(20) |
XCVR_RX_DIG_AGC_CTRL_3_AGC_H2S_STEP_SZ(6) |
XCVR_RX_DIG_AGC_CTRL_3_AGC_UP_STEP_SZ(2),
/* DCOC configs */
.dcoc_ctrl_0_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CAL_DURATION(16) | /* Only the duration changes between 26MHz and 32MHz ref osc settings */
#if (RADIO_IS_GEN_2P1)
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CAL_CHECK_EN(0) |
#endif /* (RADIO_IS_GEN_2P1) */
XCVR_RX_DIG_DCOC_CTRL_0_TRACK_FROM_ZERO(0) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_EN(1) |
XCVR_RX_DIG_DCOC_CTRL_0_TZA_CORR_POL(0) |
XCVR_RX_DIG_DCOC_CTRL_0_BBA_CORR_POL(0) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(1),
.dcoc_ctrl_0_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CAL_DURATION(20) | /* Only the duration changes between 26MHz and 32MHz ref osc settings */
#if (RADIO_IS_GEN_2P1)
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CAL_CHECK_EN(0) |
#endif /* (RADIO_IS_GEN_2P1) */
XCVR_RX_DIG_DCOC_CTRL_0_TRACK_FROM_ZERO(0) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_EN(1) |
XCVR_RX_DIG_DCOC_CTRL_0_TZA_CORR_POL(0) |
XCVR_RX_DIG_DCOC_CTRL_0_BBA_CORR_POL(0) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORRECT_SRC(1),
.dcoc_ctrl_1_init = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_MIN_AGC_IDX(26),
.dc_resid_ctrl_init = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_ITER_FREEZE(5) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_ALPHA(1) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_EXT_DC_EN(1) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_MIN_AGC_IDX(26),
.dcoc_cal_gain_init = XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_BBA_CAL_GAIN1(1) |
XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_LNA_CAL_GAIN1(1) |
XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_BBA_CAL_GAIN2(1) |
XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_LNA_CAL_GAIN2(2) |
XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_BBA_CAL_GAIN3(3) |
XCVR_RX_DIG_DCOC_CAL_GAIN_DCOC_LNA_CAL_GAIN3(1) ,
.dcoc_cal_rcp_init = XCVR_RX_DIG_DCOC_CAL_RCP_ALPHA_CALC_RECIP(1) |
XCVR_RX_DIG_DCOC_CAL_RCP_DCOC_TMP_CALC_RECIP(711),
.lna_gain_val_3_0 = XCVR_RX_DIG_LNA_GAIN_VAL_3_0_LNA_GAIN_VAL_0(0x1DU) |
XCVR_RX_DIG_LNA_GAIN_VAL_3_0_LNA_GAIN_VAL_1(0x32U) |
XCVR_RX_DIG_LNA_GAIN_VAL_3_0_LNA_GAIN_VAL_2(0x09U) |
XCVR_RX_DIG_LNA_GAIN_VAL_3_0_LNA_GAIN_VAL_3(0x38U),
.lna_gain_val_7_4 = XCVR_RX_DIG_LNA_GAIN_VAL_7_4_LNA_GAIN_VAL_4(0x4FU) |
XCVR_RX_DIG_LNA_GAIN_VAL_7_4_LNA_GAIN_VAL_5(0x5BU) |
XCVR_RX_DIG_LNA_GAIN_VAL_7_4_LNA_GAIN_VAL_6(0x72U) |
XCVR_RX_DIG_LNA_GAIN_VAL_7_4_LNA_GAIN_VAL_7(0x8AU),
.lna_gain_val_8 = XCVR_RX_DIG_LNA_GAIN_VAL_8_LNA_GAIN_VAL_8(0xA0U) |
XCVR_RX_DIG_LNA_GAIN_VAL_8_LNA_GAIN_VAL_9(0xB6U),
.bba_res_tune_val_7_0 = XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_0(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_1(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_2(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_3(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_4(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_5(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_6(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_7_0_BBA_RES_TUNE_VAL_7(0xF),
.bba_res_tune_val_10_8 = XCVR_RX_DIG_BBA_RES_TUNE_VAL_10_8_BBA_RES_TUNE_VAL_8(0x0) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_10_8_BBA_RES_TUNE_VAL_9(0x1) |
XCVR_RX_DIG_BBA_RES_TUNE_VAL_10_8_BBA_RES_TUNE_VAL_10(0x2),
.lna_gain_lin_val_2_0_init = XCVR_RX_DIG_LNA_GAIN_LIN_VAL_2_0_LNA_GAIN_LIN_VAL_0(0) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_2_0_LNA_GAIN_LIN_VAL_1(0) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_2_0_LNA_GAIN_LIN_VAL_2(1),
.lna_gain_lin_val_5_3_init = XCVR_RX_DIG_LNA_GAIN_LIN_VAL_5_3_LNA_GAIN_LIN_VAL_3(3) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_5_3_LNA_GAIN_LIN_VAL_4(5) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_5_3_LNA_GAIN_LIN_VAL_5(7),
.lna_gain_lin_val_8_6_init = XCVR_RX_DIG_LNA_GAIN_LIN_VAL_8_6_LNA_GAIN_LIN_VAL_6(14) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_8_6_LNA_GAIN_LIN_VAL_7(27) |
XCVR_RX_DIG_LNA_GAIN_LIN_VAL_8_6_LNA_GAIN_LIN_VAL_8(50),
.lna_gain_lin_val_9_init = XCVR_RX_DIG_LNA_GAIN_LIN_VAL_9_LNA_GAIN_LIN_VAL_9(91),
.bba_res_tune_lin_val_3_0_init = XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_3_0_BBA_RES_TUNE_LIN_VAL_0(8) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_3_0_BBA_RES_TUNE_LIN_VAL_1(11) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_3_0_BBA_RES_TUNE_LIN_VAL_2(16) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_3_0_BBA_RES_TUNE_LIN_VAL_3(22),
.bba_res_tune_lin_val_7_4_init = XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_7_4_BBA_RES_TUNE_LIN_VAL_4(31) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_7_4_BBA_RES_TUNE_LIN_VAL_5(44) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_7_4_BBA_RES_TUNE_LIN_VAL_6(62) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_7_4_BBA_RES_TUNE_LIN_VAL_7(42), /* Has 2 fractional bits unlike other BBA_RES_TUNE_LIN_VALs */
.bba_res_tune_lin_val_10_8_init = XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_10_8_BBA_RES_TUNE_LIN_VAL_8(128) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_10_8_BBA_RES_TUNE_LIN_VAL_9(188) |
XCVR_RX_DIG_BBA_RES_TUNE_LIN_VAL_10_8_BBA_RES_TUNE_LIN_VAL_10(288),
.dcoc_bba_step_init = XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP_RECIP(939) |
XCVR_RX_DIG_DCOC_BBA_STEP_BBA_DCOC_STEP(279),
.dcoc_tza_step_00_init = XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_GAIN_0(77) |
XCVR_RX_DIG_DCOC_TZA_STEP_0_DCOC_TZA_STEP_RCP_0(3404),
.dcoc_tza_step_01_init = XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_GAIN_1(108) |
XCVR_RX_DIG_DCOC_TZA_STEP_1_DCOC_TZA_STEP_RCP_1(2439),
.dcoc_tza_step_02_init = XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_GAIN_2(155) |
XCVR_RX_DIG_DCOC_TZA_STEP_2_DCOC_TZA_STEP_RCP_2(1691),
.dcoc_tza_step_03_init = XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_GAIN_3(220) |
XCVR_RX_DIG_DCOC_TZA_STEP_3_DCOC_TZA_STEP_RCP_3(1192),
.dcoc_tza_step_04_init = XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_GAIN_4(314) |
XCVR_RX_DIG_DCOC_TZA_STEP_4_DCOC_TZA_STEP_RCP_4(835),
.dcoc_tza_step_05_init = XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_GAIN_5(436) |
XCVR_RX_DIG_DCOC_TZA_STEP_5_DCOC_TZA_STEP_RCP_5(601),
.dcoc_tza_step_06_init = XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_GAIN_6(614) |
XCVR_RX_DIG_DCOC_TZA_STEP_6_DCOC_TZA_STEP_RCP_6(427),
.dcoc_tza_step_07_init = XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_GAIN_7(845) |
XCVR_RX_DIG_DCOC_TZA_STEP_7_DCOC_TZA_STEP_RCP_7(310),
.dcoc_tza_step_08_init = XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_GAIN_8(1256) |
XCVR_RX_DIG_DCOC_TZA_STEP_8_DCOC_TZA_STEP_RCP_8(209),
.dcoc_tza_step_09_init = XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_GAIN_9(1805) |
XCVR_RX_DIG_DCOC_TZA_STEP_9_DCOC_TZA_STEP_RCP_9(145),
.dcoc_tza_step_10_init = XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_GAIN_10(2653) |
XCVR_RX_DIG_DCOC_TZA_STEP_10_DCOC_TZA_STEP_RCP_10(99),
#if (RADIO_IS_GEN_2P1)
.dcoc_cal_fail_th_init = XCVR_RX_DIG_DCOC_CAL_FAIL_TH_DCOC_CAL_BETA_F_TH(20) |
XCVR_RX_DIG_DCOC_CAL_FAIL_TH_DCOC_CAL_ALPHA_F_TH(10),
.dcoc_cal_pass_th_init = XCVR_RX_DIG_DCOC_CAL_PASS_TH_DCOC_CAL_BETA_P_TH(16) |
XCVR_RX_DIG_DCOC_CAL_PASS_TH_DCOC_CAL_ALPHA_P_TH(2),
#endif /* (RADIO_IS_GEN_2P1) */
/* AGC Configs */
.agc_gain_tbl_03_00_init = XCVR_RX_DIG_AGC_GAIN_TBL_03_00_LNA_GAIN_00(0) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_BBA_GAIN_00(0) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_LNA_GAIN_01(1) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_BBA_GAIN_01(1) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_LNA_GAIN_02(2) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_BBA_GAIN_02(1) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_LNA_GAIN_03(2) |
XCVR_RX_DIG_AGC_GAIN_TBL_03_00_BBA_GAIN_03(2),
.agc_gain_tbl_07_04_init = XCVR_RX_DIG_AGC_GAIN_TBL_07_04_LNA_GAIN_04(2) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_BBA_GAIN_04(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_LNA_GAIN_05(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_BBA_GAIN_05(0) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_LNA_GAIN_06(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_BBA_GAIN_06(1) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_LNA_GAIN_07(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_07_04_BBA_GAIN_07(2),
.agc_gain_tbl_11_08_init = XCVR_RX_DIG_AGC_GAIN_TBL_11_08_LNA_GAIN_08(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_BBA_GAIN_08(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_LNA_GAIN_09(4) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_BBA_GAIN_09(2) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_LNA_GAIN_10(4) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_BBA_GAIN_10(3) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_LNA_GAIN_11(4) |
XCVR_RX_DIG_AGC_GAIN_TBL_11_08_BBA_GAIN_11(4),
.agc_gain_tbl_15_12_init = XCVR_RX_DIG_AGC_GAIN_TBL_15_12_LNA_GAIN_12(5) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_BBA_GAIN_12(4) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_LNA_GAIN_13(5) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_BBA_GAIN_13(5) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_LNA_GAIN_14(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_BBA_GAIN_14(4) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_LNA_GAIN_15(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_15_12_BBA_GAIN_15(5),
.agc_gain_tbl_19_16_init = XCVR_RX_DIG_AGC_GAIN_TBL_19_16_LNA_GAIN_16(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_BBA_GAIN_16(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_LNA_GAIN_17(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_BBA_GAIN_17(7) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_LNA_GAIN_18(7) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_BBA_GAIN_18(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_LNA_GAIN_19(7) |
XCVR_RX_DIG_AGC_GAIN_TBL_19_16_BBA_GAIN_19(7),
.agc_gain_tbl_23_20_init = XCVR_RX_DIG_AGC_GAIN_TBL_23_20_LNA_GAIN_20(8) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_BBA_GAIN_20(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_LNA_GAIN_21(8) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_BBA_GAIN_21(7) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_LNA_GAIN_22(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_BBA_GAIN_22(6) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_LNA_GAIN_23(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_23_20_BBA_GAIN_23(7),
.agc_gain_tbl_26_24_init = XCVR_RX_DIG_AGC_GAIN_TBL_26_24_LNA_GAIN_24(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_26_24_BBA_GAIN_24(8) |
XCVR_RX_DIG_AGC_GAIN_TBL_26_24_LNA_GAIN_25(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_26_24_BBA_GAIN_25(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_26_24_LNA_GAIN_26(9) |
XCVR_RX_DIG_AGC_GAIN_TBL_26_24_BBA_GAIN_26(10),
.rssi_ctrl_0_init = XCVR_RX_DIG_RSSI_CTRL_0_RSSI_USE_VALS(1) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_HOLD_SRC(0) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_HOLD_EN(1) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_IIR_CW_WEIGHT(0) |
#if !RADIO_IS_GEN_2P1
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_N_WINDOW_AVG(1) |
#else
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_N_WINDOW_NB(1) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_HOLD_DELAY(4) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_IIR_WEIGHT(3) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_VLD_SETTLE(3) |
XCVR_RX_DIG_RSSI_CTRL_0_RSSI_ADJ(0xE8) ,
.cca_ed_lqi_ctrl_0_init = XCVR_RX_DIG_CCA_ED_LQI_CTRL_0_LQI_CORR_THRESH(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_0_CORR_CNTR_THRESH(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_0_LQI_CNTR(0x1A) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_0_SNR_ADJ(0),
.cca_ed_lqi_ctrl_1_init = XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_RSSI_NOISE_AVG_DELAY(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_RSSI_NOISE_AVG_FACTOR(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_LQI_RSSI_WEIGHT(0x4) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_LQI_RSSI_SENS(0x7) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_SNR_LQI_DIS(0) |
#if !RADIO_IS_GEN_2P1
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_SEL_SNR_MODE(0) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_MEAS_TRANS_TO_IDLE(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_CCA1_ED_EN_DIS(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_MAN_MEAS_COMPLETE(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_MAN_AA_MATCH(0) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_SNR_LQI_WEIGHT(0x5) |
XCVR_RX_DIG_CCA_ED_LQI_CTRL_1_LQI_BIAS(0x2),
/* XCVR_TSM configs */
.tsm_ctrl = XCVR_TSM_CTRL_PA_RAMP_SEL(PA_RAMP_SEL) |
XCVR_TSM_CTRL_DATA_PADDING_EN(DATA_PADDING_EN) |
XCVR_TSM_CTRL_TSM_IRQ0_EN(0) |
XCVR_TSM_CTRL_TSM_IRQ1_EN(0) |
XCVR_TSM_CTRL_RAMP_DN_DELAY(0x4) |
XCVR_TSM_CTRL_TX_ABORT_DIS(0) |
XCVR_TSM_CTRL_RX_ABORT_DIS(0) |
XCVR_TSM_CTRL_ABORT_ON_CTUNE(0) |
XCVR_TSM_CTRL_ABORT_ON_CYCLE_SLIP(0) |
XCVR_TSM_CTRL_ABORT_ON_FREQ_TARG(0) |
XCVR_TSM_CTRL_BKPT(0xFF) ,
.tsm_ovrd2_init = XCVR_TSM_OVRD2_FREQ_TARG_LD_EN_OVRD(0) | XCVR_TSM_OVRD2_FREQ_TARG_LD_EN_OVRD_EN_MASK,
.end_of_seq_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(END_OF_RX_WU_26MHZ) | B1(END_OF_TX_WD) | B0(END_OF_TX_WU),
.end_of_seq_init_32mhz = B3(END_OF_RX_WD) | B2(END_OF_RX_WU) | B1(END_OF_TX_WD) | B0(END_OF_TX_WU),
#if !RADIO_IS_GEN_2P1
.lpps_ctrl_init = B3(102) | B2(40) | B1(0) | B0(0),
#endif /* !RADIO_IS_GEN_2P1 */
.tsm_fast_ctrl2_init_26mhz = B3(102 + ADD_FOR_26MHZ) | B2(40 + ADD_FOR_26MHZ) | B1(66) | B0(8),
.tsm_fast_ctrl2_init_32mhz = B3(102) | B2(40) | B1(66) | B0(8),
.pa_ramp_tbl_0_init = XCVR_TSM_PA_RAMP_TBL0_PA_RAMP0(PA_RAMP_0) | XCVR_TSM_PA_RAMP_TBL0_PA_RAMP1(PA_RAMP_1) |
XCVR_TSM_PA_RAMP_TBL0_PA_RAMP2(PA_RAMP_2) | XCVR_TSM_PA_RAMP_TBL0_PA_RAMP3(PA_RAMP_3),
.pa_ramp_tbl_1_init = XCVR_TSM_PA_RAMP_TBL1_PA_RAMP4(PA_RAMP_4) | XCVR_TSM_PA_RAMP_TBL1_PA_RAMP5(PA_RAMP_5) |
XCVR_TSM_PA_RAMP_TBL1_PA_RAMP6(PA_RAMP_6) | XCVR_TSM_PA_RAMP_TBL1_PA_RAMP7(PA_RAMP_7),
.recycle_count_init_26mhz = B3(0) | B2(0x1C + ADD_FOR_26MHZ) | B1(0x06) | B0(0x66 + ADD_FOR_26MHZ),
.recycle_count_init_32mhz = B3(0) | B2(0x1C) | B1(0x06) | B0(0x66),
.tsm_timing_00_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_hf_en */
.tsm_timing_01_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_adcdac_en */
.tsm_timing_02_init = B3(END_OF_RX_WD) | B2(0x00) | B1(0xFF) | B0(0xFF), /* bb_ldo_bba_en */
.tsm_timing_03_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_pd_en */
.tsm_timing_04_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_fdbk_en */
.tsm_timing_05_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_vcolo_en */
.tsm_timing_06_init = B3(END_OF_RX_WD) | B2(0x00) | B1(END_OF_TX_WD) | B0(0x00), /* bb_ldo_vtref_en */
.tsm_timing_07_init = B3(0x05) | B2(0x00) | B1(0x05) | B0(0x00), /* bb_ldo_fdbk_bleed_en */
.tsm_timing_08_init = B3(0x03) | B2(0x00) | B1(0x03) | B0(0x00), /* bb_ldo_vcolo_bleed_en */
.tsm_timing_09_init = B3(0x03) | B2(0x00) | B1(0x03) | B0(0x00), /* bb_ldo_vcolo_fastcharge_en */
.tsm_timing_10_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x03), /* bb_xtal_pll_ref_clk_en */
.tsm_timing_11_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD) | B0(0x03), /* bb_xtal_dac_ref_clk_en */
.tsm_timing_12_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_vco_ref_clk_en */
.tsm_timing_13_init = B3(0x18) | B2(0x00) | B1(0x4C) | B0(0x00), /* sy_vco_autotune_en */
.tsm_timing_14_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x31+ADD_FOR_26MHZ) | B1(END_OF_TX_WU + PD_CYCLE_SLIP_TX_LO_ADJ) | B0(0x63 + PD_CYCLE_SLIP_TX_HI_ADJ), /* sy_pd_cycle_slip_ld_ft_en */
.tsm_timing_14_init_32mhz = B3(END_OF_RX_WD) | B2(0x31 + AUX_PLL_DELAY) | B1(END_OF_TX_WU + PD_CYCLE_SLIP_TX_LO_ADJ) | B0(0x63 + PD_CYCLE_SLIP_TX_HI_ADJ),
.tsm_timing_15_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x03), /* sy_vco_en */
.tsm_timing_16_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x1C + ADD_FOR_26MHZ) | B1(0xFF) | B0(0xFF), /* sy_lo_rx_buf_en */
.tsm_timing_16_init_32mhz = B3(END_OF_RX_WD) | B2(0x1C + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_17_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD) | B0(0x55), /* sy_lo_tx_buf_en */
.tsm_timing_18_init = B3(END_OF_RX_WD) | B2(0x05 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x05), /* sy_divn_en */
.tsm_timing_19_init = B3(0x18+AUX_PLL_DELAY) | B2(0x03 + AUX_PLL_DELAY) | B1(0x4C) | B0(0x03), /* sy_pd_filter_charge_en */
.tsm_timing_20_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x03), /* sy_pd_en */
.tsm_timing_21_init = B3(END_OF_RX_WD) | B2(0x04 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x04), /* sy_lo_divn_en */
.tsm_timing_22_init = B3(END_OF_RX_WD) | B2(0x04 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* sy_lo_rx_en */
.tsm_timing_23_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD) | B0(0x04), /*sy_lo_tx_en */
.tsm_timing_24_init = B3(0x18) | B2(0x00) | B1(0x4C) | B0(0x00), /* sy_divn_cal_en */
.tsm_timing_25_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x1D + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_lna_mixer_en */
.tsm_timing_25_init_32mhz = B3(END_OF_RX_WD) | B2(0x1D + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_26_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD) | B0(0x58), /* tx_pa_en */
.tsm_timing_27_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_adc_i_q_en */
.tsm_timing_27_init_32mhz = B3(END_OF_RX_WD) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_28_init_26mhz = B3(0x21 + ADD_FOR_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_adc_reset_en */
.tsm_timing_28_init_32mhz = B3(0x21 + AUX_PLL_DELAY) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_29_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x1E + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_bba_i_q_en */
.tsm_timing_29_init_32mhz = B3(END_OF_RX_WD) | B2(0x1E + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_30_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_bba_pdet_en */
.tsm_timing_30_init_32mhz = B3(END_OF_RX_WD) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_31_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x1F + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_bba_tza_dcoc_en */
.tsm_timing_31_init_32mhz = B3(END_OF_RX_WD) | B2(0x1F + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_32_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x1D + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_tza_i_q_en */
.tsm_timing_32_init_32mhz = B3(END_OF_RX_WD) | B2(0x1D + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_33_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_tza_pdet_en */
.tsm_timing_33_init_32mhz = B3(END_OF_RX_WD) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_34_init = B3(END_OF_RX_WD) | B2(0x07 + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x07), /* pll_dig_en */
.tsm_timing_35_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD), /* tx_dig_en - Byte 0 comes from mode specific settings */
.tsm_timing_36_init_26mhz = B3(END_OF_RX_WD) | B2(0x66 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_dig_en */
.tsm_timing_36_init_32mhz = B3(END_OF_RX_WD) | B2(0x66 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_37_init_26mhz = B3(0x67 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B2(0x66 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_init */
.tsm_timing_37_init_32mhz = B3(0x67 + AUX_PLL_DELAY) | B2(0x66 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_38_init = B3(END_OF_RX_WD) | B2(0x0E + AUX_PLL_DELAY) | B1(END_OF_TX_WD) | B0(0x42), /* sigma_delta_en */
.tsm_timing_39_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x66 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rx_phy_en */
.tsm_timing_39_init_32mhz = B3(END_OF_RX_WD) | B2(0x66 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_40_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x26 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* dcoc_en */
.tsm_timing_40_init_32mhz = B3(END_OF_RX_WD) | B2(0x26 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_41_init_26mhz = B3(0x27 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B2(0x26 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* dcoc_init */
.tsm_timing_41_init_32mhz = B3(0x27 + AUX_PLL_DELAY) | B2(0x26 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_51_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_bias_en */
.tsm_timing_52_init_26mhz = B3(0x17 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B2(0x06 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_fcal_en */
.tsm_timing_52_init_32mhz = B3(0x17 + AUX_PLL_DELAY) | B2(0x06 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_53_init = B3(END_OF_RX_WD) | B2(0x03 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_lf_pd_en */
.tsm_timing_54_init_26mhz = B3(0x17 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B2(0x03 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_pd_lf_filter_charge_en */
.tsm_timing_54_init_32mhz = B3(0x17 + AUX_PLL_DELAY) | B2(0x03 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_55_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_adc_buf_en */
.tsm_timing_55_init_32mhz = B3(END_OF_RX_WD) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_56_init_26mhz = B3(END_OF_RX_WD_26MHZ) | B2(0x20 + ADD_FOR_26MHZ + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /* rxtx_auxpll_dig_buf_en */
.tsm_timing_56_init_32mhz = B3(END_OF_RX_WD) | B2(0x20 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF),
.tsm_timing_57_init = B3(0x1A + AUX_PLL_DELAY) | B2(0x03 + AUX_PLL_DELAY) | B1(0xFF) | B0(0xFF), /*rxtx_rccal_en */
.tsm_timing_58_init = B3(0xFF) | B2(0xFF) | B1(END_OF_TX_WD) | B0(0x03), /* tx_hpm_dac_en */
/* XCVR_TX_DIG configs */
#define radio_dft_mode 0
#define lfsr_length 4
#define lfsr_en 0
#define dft_clk_sel 4
#define tx_dft_en 0
#define soc_test_sel 0
#define tx_capture_pol 0
#define freq_word_adj 0
#define lrm 0
#define data_padding_pat_1 0x55
#define data_padding_pat_0 0xAA
#define gfsk_multiply_table_manual 0
#define gfsk_mi 1
#define gfsk_mld 0
#define gfsk_fld 0
#define gfsk_mod_index_scaling 0
#define tx_image_filter_ovrd_en 0
#define tx_image_filter_0_ovrd 0
#define tx_image_filter_1_ovrd 0
#define tx_image_filter_2_ovrd 0
#define gfsk_filter_coeff_manual2 0xC0630401
#define gfsk_filter_coeff_manual1 0xBB29960D
#define fsk_modulation_scale_0 0x1800
#define fsk_modulation_scale_1 0x0800
#define dft_mod_patternval 0
#define ctune_bist_go 0
#define ctune_bist_thrshld 0
#define pa_am_mod_freq 0
#define pa_am_mod_entries 0
#define pa_am_mod_en 0
#define syn_bist_go 0
#define syn_bist_all_channels 0
#define freq_count_threshold 0
#define hpm_inl_bist_go 0
#define hpm_dnl_bist_go 0
#define dft_max_ram_size 0
.tx_ctrl = XCVR_TX_DIG_CTRL_RADIO_DFT_MODE(radio_dft_mode) |
XCVR_TX_DIG_CTRL_LFSR_LENGTH(lfsr_length) |
XCVR_TX_DIG_CTRL_LFSR_EN(lfsr_en) |
XCVR_TX_DIG_CTRL_DFT_CLK_SEL(dft_clk_sel) |
XCVR_TX_DIG_CTRL_TX_DFT_EN(tx_dft_en) |
XCVR_TX_DIG_CTRL_SOC_TEST_SEL(soc_test_sel) |
XCVR_TX_DIG_CTRL_TX_CAPTURE_POL(tx_capture_pol) |
XCVR_TX_DIG_CTRL_FREQ_WORD_ADJ(freq_word_adj),
/*-------------------------------------------------------------------------------------------------*/
.tx_data_padding = XCVR_TX_DIG_DATA_PADDING_LRM(lrm) |
XCVR_TX_DIG_DATA_PADDING_DATA_PADDING_PAT_1(data_padding_pat_1) |
XCVR_TX_DIG_DATA_PADDING_DATA_PADDING_PAT_0(data_padding_pat_0),
/*-------------------------------------------------------------------------------------------------*/
.tx_dft_pattern = XCVR_TX_DIG_DFT_PATTERN_DFT_MOD_PATTERN(dft_mod_patternval),
#if !RADIO_IS_GEN_2P1
/*-------------------------------------------------------------------------------------------------*/
.rf_dft_bist_1 = XCVR_TX_DIG_RF_DFT_BIST_1_CTUNE_BIST_GO(ctune_bist_go) |
XCVR_TX_DIG_RF_DFT_BIST_1_CTUNE_BIST_THRSHLD(ctune_bist_thrshld) |
XCVR_TX_DIG_RF_DFT_BIST_1_PA_AM_MOD_FREQ(pa_am_mod_freq) |
XCVR_TX_DIG_RF_DFT_BIST_1_PA_AM_MOD_ENTRIES(pa_am_mod_entries) |
XCVR_TX_DIG_RF_DFT_BIST_1_PA_AM_MOD_EN(pa_am_mod_en),
/*-------------------------------------------------------------------------------------------------*/
.rf_dft_bist_2 = XCVR_TX_DIG_RF_DFT_BIST_2_SYN_BIST_GO(syn_bist_go) |
XCVR_TX_DIG_RF_DFT_BIST_2_SYN_BIST_ALL_CHANNELS(syn_bist_all_channels) |
XCVR_TX_DIG_RF_DFT_BIST_2_FREQ_COUNT_THRESHOLD(freq_count_threshold) |
XCVR_TX_DIG_RF_DFT_BIST_2_HPM_INL_BIST_GO(hpm_inl_bist_go) |
XCVR_TX_DIG_RF_DFT_BIST_2_HPM_DNL_BIST_GO(hpm_dnl_bist_go) |
XCVR_TX_DIG_RF_DFT_BIST_2_DFT_MAX_RAM_SIZE(dft_max_ram_size),
#endif /* !RADIO_IS_GEN_2P1 */
};

View File

@ -0,0 +1,217 @@
/*
* 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.
*/
#include "fsl_xcvr.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/* ========================= DATA RATE ONLY settings ===============*/
/*!
* @brief XCVR 1Mbps DATA RATE specific configure structure
*/
const xcvr_datarate_config_t xcvr_1mbps_config =
{
.data_rate = DR_1MBPS,
.phy_el_cfg_init = XCVR_PHY_EL_CFG_EL_WIN_SIZE(0xF) |
#if !RADIO_IS_GEN_2P1
XCVR_PHY_EL_CFG_EL_ZB_WIN_SIZE(0) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_PHY_EL_CFG_EL_INTERVAL(0x20) ,
.rx_dig_ctrl_init_26mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(0) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.rx_dig_ctrl_init_32mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.agc_ctrl_1_init_26mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(10) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.agc_ctrl_1_init_32mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(12) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.dcoc_ctrl_0_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(10) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(3),
.dcoc_ctrl_0_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(12) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(4),
.dcoc_ctrl_1_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(3),
.dcoc_ctrl_1_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(3),
.dcoc_cal_iir_init_26mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(2),
.dcoc_cal_iir_init_32mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(3) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(2),
.dc_resid_ctrl_26mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(48) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(5),
.dc_resid_ctrl_32mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(48) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(6),
};
/*!
* @brief XCVR 500K bps DATA RATE specific configure structure
*/
const xcvr_datarate_config_t xcvr_500kbps_config =
{
.data_rate = DR_500KBPS,
.phy_el_cfg_init = XCVR_PHY_EL_CFG_EL_WIN_SIZE(0x8) |
#if !RADIO_IS_GEN_2P1
XCVR_PHY_EL_CFG_EL_ZB_WIN_SIZE(0) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_PHY_EL_CFG_EL_INTERVAL(0x10),
.rx_dig_ctrl_init_26mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.rx_dig_ctrl_init_32mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(2) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.agc_ctrl_1_init_26mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(15) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.agc_ctrl_1_init_32mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(18) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.dcoc_ctrl_0_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(13) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(29),
.dcoc_ctrl_0_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(16) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(36),
.dcoc_ctrl_1_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(2) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_ctrl_1_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(2) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_cal_iir_init_26mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(2),
.dcoc_cal_iir_init_32mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(2),
.dc_resid_ctrl_26mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(32) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(4),
.dc_resid_ctrl_32mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(32) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(4),
};
/*!
* @brief XCVR 250K bps DATA RATE specific configure structure
*/
const xcvr_datarate_config_t xcvr_250kbps_config =
{
.data_rate = DR_250KBPS,
.phy_el_cfg_init = XCVR_PHY_EL_CFG_EL_WIN_SIZE(0x4) |
#if !RADIO_IS_GEN_2P1
XCVR_PHY_EL_CFG_EL_ZB_WIN_SIZE(0) |
#endif /* !RADIO_IS_GEN_2P1 */
XCVR_PHY_EL_CFG_EL_INTERVAL(0x8) ,
.rx_dig_ctrl_init_26mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(2) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.rx_dig_ctrl_init_32mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(4) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.agc_ctrl_1_init_26mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(18) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.agc_ctrl_1_init_32mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(22) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.dcoc_ctrl_0_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(16) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(34),
.dcoc_ctrl_0_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(20) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(42),
.dcoc_ctrl_1_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_ctrl_1_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_cal_iir_init_26mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(0) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(1) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(1),
.dcoc_cal_iir_init_32mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(0) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(1) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(1),
.dc_resid_ctrl_26mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(16) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(4),
.dc_resid_ctrl_32mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(16) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(4),
};

View File

@ -0,0 +1,249 @@
/*
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* 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.
*/
#include "fsl_xcvr.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
const xcvr_mode_config_t zgbe_mode_config =
{
.radio_mode = ZIGBEE_MODE,
.scgc5_clock_ena_bits = SIM_SCGC5_PHYDIG_MASK | SIM_SCGC5_ZigBee_MASK,
/* XCVR_MISC configs */
.xcvr_ctrl.mask = XCVR_CTRL_XCVR_CTRL_PROTOCOL_MASK |
XCVR_CTRL_XCVR_CTRL_TGT_PWR_SRC_MASK |
XCVR_CTRL_XCVR_CTRL_DEMOD_SEL_MASK,
.xcvr_ctrl.init = XCVR_CTRL_XCVR_CTRL_PROTOCOL(4) |
XCVR_CTRL_XCVR_CTRL_TGT_PWR_SRC(7) |
XCVR_CTRL_XCVR_CTRL_DEMOD_SEL(2),
/* XCVR_PHY configs */
.phy_pre_ref0_init = 0x0, /* Not used in Zigbee */
.phy_pre_ref1_init = 0x0, /* Not used in Zigbee */
.phy_pre_ref2_init = 0x0, /* Not used in Zigbee */
.phy_cfg1_init = XCVR_PHY_CFG1_AA_PLAYBACK(0) |
XCVR_PHY_CFG1_AA_OUTPUT_SEL(1) |
XCVR_PHY_CFG1_FSK_BIT_INVERT(0) |
XCVR_PHY_CFG1_BSM_EN_BLE(0) |
XCVR_PHY_CFG1_DEMOD_CLK_MODE(0) |
XCVR_PHY_CFG1_CTS_THRESH(0xC0) |
XCVR_PHY_CFG1_FSK_FTS_TIMEOUT(2),
.phy_el_cfg_init = XCVR_PHY_EL_CFG_EL_ENABLE(1)
#if !RADIO_IS_GEN_2P1
| XCVR_PHY_EL_CFG_EL_ZB_ENABLE(0)
#endif /* !RADIO_IS_GEN_2P1 */
,
/* XCVR_PLL_DIG configs */
/* XCVR_RX_DIG configs */
.rx_dig_ctrl_init_26mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_FSK_ZB_SEL(1) | /* Depends on protocol */
XCVR_RX_DIG_RX_DIG_CTRL_RX_DC_RESID_EN(1) | /* Depends on protocol */
XCVR_RX_DIG_RX_DIG_CTRL_RX_SRC_RATE(0),
.rx_dig_ctrl_init_32mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_FSK_ZB_SEL(1) | /* Depends on protocol */
XCVR_RX_DIG_RX_DIG_CTRL_RX_DC_RESID_EN(1), /* Depends on protocol */
.agc_ctrl_0_init = XCVR_RX_DIG_AGC_CTRL_0_AGC_DOWN_RSSI_THRESH(0xFF),
/* XCVR_TSM configs */
#if (DATA_PADDING_EN)
.tsm_timing_35_init = B0(TX_DIG_EN_ASSERT+ZGBE_TX_DIG_EN_TX_HI_ADJ), /* DATA_PADDING adjustments are specified relative to the non-Zigbee base timing */
#else
.tsm_timing_35_init = B0(ZGBE_TX_DIG_EN_ASSERT),
#endif /* (DATA_PADDING_EN) */
/* XCVR_TX_DIG configs */
.tx_gfsk_ctrl = XCVR_TX_DIG_GFSK_CTRL_GFSK_MULTIPLY_TABLE_MANUAL(0x4000) |
XCVR_TX_DIG_GFSK_CTRL_GFSK_MI(1) |
XCVR_TX_DIG_GFSK_CTRL_GFSK_MLD(0) |
XCVR_TX_DIG_GFSK_CTRL_GFSK_FLD(0) |
XCVR_TX_DIG_GFSK_CTRL_GFSK_MOD_INDEX_SCALING(0) |
XCVR_TX_DIG_GFSK_CTRL_TX_IMAGE_FILTER_OVRD_EN(0) |
XCVR_TX_DIG_GFSK_CTRL_TX_IMAGE_FILTER_0_OVRD(0) |
XCVR_TX_DIG_GFSK_CTRL_TX_IMAGE_FILTER_1_OVRD(0) |
XCVR_TX_DIG_GFSK_CTRL_TX_IMAGE_FILTER_2_OVRD(0) ,
.tx_gfsk_coeff1_26mhz = 0,
.tx_gfsk_coeff2_26mhz = 0,
.tx_gfsk_coeff1_32mhz = 0,
.tx_gfsk_coeff2_32mhz = 0,
};
const xcvr_mode_datarate_config_t xcvr_ZIGBEE_500kbps_config =
{
.radio_mode = ZIGBEE_MODE,
.data_rate = DR_500KBPS,
.ana_sy_ctrl2.mask = XCVR_ANALOG_SY_CTRL_2_SY_VCO_KVM_MASK,
.ana_sy_ctrl2.init = XCVR_ANALOG_SY_CTRL_2_SY_VCO_KVM(1), /* VCO KVM */
.ana_rx_bba.mask = XCVR_ANALOG_RX_BBA_RX_BBA_BW_SEL_MASK | XCVR_ANALOG_RX_BBA_RX_BBA2_BW_SEL_MASK,
.ana_rx_bba.init = XCVR_ANALOG_RX_BBA_RX_BBA_BW_SEL(1) | XCVR_ANALOG_RX_BBA_RX_BBA2_BW_SEL(1), /* BBA_BW_SEL and BBA2_BW_SEL */
.ana_rx_tza.mask = XCVR_ANALOG_RX_TZA_RX_TZA_BW_SEL_MASK,
.ana_rx_tza.init = XCVR_ANALOG_RX_TZA_RX_TZA_BW_SEL(1), /*TZA_BW_SEL */
.phy_cfg2_init = XCVR_PHY_CFG2_PHY_FIFO_PRECHG(8) |
XCVR_PHY_CFG2_X2_DEMOD_GAIN(0xA) ,
/* AGC configs */
.agc_ctrl_2_init_26mhz = XCVR_RX_DIG_AGC_CTRL_2_BBA_GAIN_SETTLE_TIME(8) |
XCVR_RX_DIG_AGC_CTRL_2_BBA_PDET_SEL_LO(5) |
XCVR_RX_DIG_AGC_CTRL_2_BBA_PDET_SEL_HI(6) |
XCVR_RX_DIG_AGC_CTRL_2_TZA_PDET_SEL_LO(3) |
XCVR_RX_DIG_AGC_CTRL_2_TZA_PDET_SEL_HI(5) |
XCVR_RX_DIG_AGC_CTRL_2_AGC_FAST_EXPIRE(5),
.agc_ctrl_2_init_32mhz = XCVR_RX_DIG_AGC_CTRL_2_BBA_GAIN_SETTLE_TIME(10) |
XCVR_RX_DIG_AGC_CTRL_2_BBA_PDET_SEL_LO(5) |
XCVR_RX_DIG_AGC_CTRL_2_BBA_PDET_SEL_HI(6) |
XCVR_RX_DIG_AGC_CTRL_2_TZA_PDET_SEL_LO(3) |
XCVR_RX_DIG_AGC_CTRL_2_TZA_PDET_SEL_HI(5) |
XCVR_RX_DIG_AGC_CTRL_2_AGC_FAST_EXPIRE(5),
/* All constant values are represented as 16 bits, register writes will remove unused bits */
.rx_chf_coeffs_26mhz.rx_chf_coef_0 = 0xFFFF,
.rx_chf_coeffs_26mhz.rx_chf_coef_1 = 0xFFFF,
.rx_chf_coeffs_26mhz.rx_chf_coef_2 = 0x0002,
.rx_chf_coeffs_26mhz.rx_chf_coef_3 = 0x0008,
.rx_chf_coeffs_26mhz.rx_chf_coef_4 = 0x000A,
.rx_chf_coeffs_26mhz.rx_chf_coef_5 = 0x0000,
.rx_chf_coeffs_26mhz.rx_chf_coef_6 = 0xFFE8,
.rx_chf_coeffs_26mhz.rx_chf_coef_7 = 0xFFD7,
.rx_chf_coeffs_26mhz.rx_chf_coef_8 = 0xFFE6,
.rx_chf_coeffs_26mhz.rx_chf_coef_9 = 0x0022,
.rx_chf_coeffs_26mhz.rx_chf_coef_10 = 0x0075,
.rx_chf_coeffs_26mhz.rx_chf_coef_11 = 0x00B2,
/* IEEE 802.15.4 32MHz Channel Filter -- 1.55/1.25/5/0.97/B5 */
.rx_chf_coeffs_32mhz.rx_chf_coef_0 = 0xFFFF,
.rx_chf_coeffs_32mhz.rx_chf_coef_1 = 0xFFFF,
.rx_chf_coeffs_32mhz.rx_chf_coef_2 = 0x0005,
.rx_chf_coeffs_32mhz.rx_chf_coef_3 = 0x0004,
.rx_chf_coeffs_32mhz.rx_chf_coef_4 = 0xFFF2,
.rx_chf_coeffs_32mhz.rx_chf_coef_5 = 0xFFF2,
.rx_chf_coeffs_32mhz.rx_chf_coef_6 = 0x001D,
.rx_chf_coeffs_32mhz.rx_chf_coef_7 = 0x0025,
.rx_chf_coeffs_32mhz.rx_chf_coef_8 = 0xFFCE,
.rx_chf_coeffs_32mhz.rx_chf_coef_9 = 0xFFA1,
.rx_chf_coeffs_32mhz.rx_chf_coef_10 = 0x0040,
.rx_chf_coeffs_32mhz.rx_chf_coef_11 = 0x0124,
.rx_rccal_ctrl_0 = XCVR_RX_DIG_RX_RCCAL_CTRL0_BBA_RCCAL_OFFSET(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_BBA_RCCAL_MANUAL(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_BBA_RCCAL_DIS(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_RCCAL_SMP_DLY(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_RCCAL_COMP_INV(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_TZA_RCCAL_OFFSET(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_TZA_RCCAL_MANUAL(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL0_TZA_RCCAL_DIS(0) ,
.rx_rccal_ctrl_1 = XCVR_RX_DIG_RX_RCCAL_CTRL1_ADC_RCCAL_OFFSET(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL1_ADC_RCCAL_MANUAL(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL1_ADC_RCCAL_DIS(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL1_BBA2_RCCAL_OFFSET(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL1_BBA2_RCCAL_MANUAL(0) |
XCVR_RX_DIG_RX_RCCAL_CTRL1_BBA2_RCCAL_DIS(0) ,
.tx_fsk_scale_26mhz = XCVR_TX_DIG_FSK_SCALE_FSK_MODULATION_SCALE_0(0x1627) | XCVR_TX_DIG_FSK_SCALE_FSK_MODULATION_SCALE_1(0x09d9),
.tx_fsk_scale_32mhz = XCVR_TX_DIG_FSK_SCALE_FSK_MODULATION_SCALE_0(0x1800) | XCVR_TX_DIG_FSK_SCALE_FSK_MODULATION_SCALE_1(0x0800),
};
/* CUSTOM datarate dependent config structure for ONLY 802.15.4 */
/*!
* @brief XCVR 500K bps DATA RATE specific configure structure
*/
const xcvr_datarate_config_t xcvr_802_15_4_500kbps_config =
{
.data_rate = DR_500KBPS,
.phy_el_cfg_init = XCVR_PHY_EL_CFG_EL_ZB_WIN_SIZE(0) |
XCVR_PHY_EL_CFG_EL_WIN_SIZE(0x8) |
XCVR_PHY_EL_CFG_EL_INTERVAL(0x10) ,
.rx_dig_ctrl_init_26mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(1) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.rx_dig_ctrl_init_32mhz = XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_OSR(2) |
XCVR_RX_DIG_RX_DIG_CTRL_RX_DEC_FILT_GAIN(16),
.agc_ctrl_1_init_26mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(13) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.agc_ctrl_1_init_32mhz = XCVR_RX_DIG_AGC_CTRL_1_LNA_GAIN_SETTLE_TIME(10) |
XCVR_RX_DIG_AGC_CTRL_1_PRESLOW_EN(PRESLOW_ENA),
.dcoc_ctrl_0_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(13) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(29),
.dcoc_ctrl_0_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_DLY(21) |
XCVR_RX_DIG_DCOC_CTRL_0_DCOC_CORR_HOLD_TIME(47),
.dcoc_ctrl_1_init_26mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(2) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_ctrl_1_init_32mhz = XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_IDX(2) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_TRK_EST_GS_CNT(0) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_SIGN_SCALE_GS_IDX(1) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHAC_SCALE_GS_IDX(3) |
XCVR_RX_DIG_DCOC_CTRL_1_DCOC_ALPHA_RADIUS_GS_IDX(2),
.dcoc_cal_iir_init_26mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(2),
.dcoc_cal_iir_init_32mhz = XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR3A_IDX(1) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR2A_IDX(2) |
XCVR_RX_DIG_DCOC_CAL_IIR_DCOC_CAL_IIR1A_IDX(1),
.dc_resid_ctrl_26mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(26) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(4),
.dc_resid_ctrl_32mhz = XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_NWIN(40) |
XCVR_RX_DIG_DC_RESID_CTRL_DC_RESID_DLY(0),
};

View File

@ -0,0 +1,535 @@
/*
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* 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.
*/
#include "cpu.h"
#include "fsl_xcvr.h"
#include "ifr_radio.h"
#include "fsl_os_abstraction.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define IFR_RAM (0)
#if RADIO_IS_GEN_3P0
#define RDINDX (0x41U)
#define K3_BASE_INDEX (0x11U) /* Based for read index */
#else
#define RDRSRC (0x03U)
#define KW4x_512_BASE (0x20000U)
#define KW4x_256_BASE (0x10000U)
#endif /* RADIO_IS_GEN_3P0 */
#if RADIO_IS_GEN_2P1
#define FTFA (FTFE)
#endif /* RADIO_IS_GEN_2P1 */
/*******************************************************************************
* Prototypes
******************************************************************************/
static uint32_t read_another_ifr_word(void);
static uint32_t read_first_ifr_word(uint32_t read_addr);
#if RADIO_IS_GEN_3P0
static uint64_t read_index_ifr(uint32_t read_addr);
#else
/*! *********************************************************************************
* @brief Reads a location in block 1 IFR for use by the radio.
*
* This function handles reading IFR data from flash memory for trim loading.
*
* @param read_addr the address in the IFR to be read.
*
* @details This function wraps both the Gen2 read_resource command and the Gen2.1 and Gen3 read_index
***********************************************************************************/
#if RADIO_IS_GEN_2P1
static uint64_t read_resource_ifr(uint32_t read_addr);
#else
static uint32_t read_resource_ifr(uint32_t read_addr);
#endif /* RADIO_IS_GEN_2P1 */
#endif /* RADIO_IS_GEN_3P0 */
static void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data);
/*******************************************************************************
* Variables
******************************************************************************/
static uint32_t ifr_read_addr;
#if RADIO_IS_GEN_3P0
static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */
static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */
const uint32_t BLOCK_1_IFR[]=
{
/* Revised fallback table which should work with untrimmed parts */
0xABCDFFFEU, /* Version #FFFE indicates default trim values */
/* Trim table is empty for Gen3 by default */
/* No TRIM_STATUS in SW fallback array. */
0xFEED0E0FU /* End of File */
};
#else
#if RADIO_IS_GEN_2P0
const uint32_t BLOCK_1_IFR[]=
{
/* Revised fallback table which should work with untrimmed parts */
0xABCDFFFEU, /* Version #FFFE indicates default trim values */
0x4005912CU, /* RSIM_ANA_TRIM address */
0x784B0000U, /* RSIM_ANA_TRIM default value */
/* No TRIM_STATUS in SW fallback array. */
0xFEED0E0FU /* End of File */
};
#else
static uint64_t packed_data_long; /* Storage for 2 32 bit values to be read by read_index */
static uint8_t num_words_avail; /* Number of 32 bit words available in packed_data_long storage */
const uint32_t BLOCK_1_IFR[]=
{
/* Revised fallback table which should work with untrimmed parts */
0xABCDFFFEU, /* Version #FFFE indicates default trim values */
0x4005912CU, /* RSIM_ANA_TRIM address */
0x784B0000U, /* RSIM_ANA_TRIM default value */
/* No TRIM_STATUS in SW fallback array. */
0xFEED0E0FU /* End of File */
};
#endif /* RADIO_IS_GEN_2P0 */
#endif /* RADIO_IS_GEN_3P0 */
/*******************************************************************************
* Code
******************************************************************************/
/*! *********************************************************************************
* \brief Read command for reading the first 32bit word from IFR, encapsulates different
* flash IFR read mechanisms for multiple generations of SOC
*
* \param read_addr flash address
*
* \return 8 bytes of packed data containing radio trims only
*
***********************************************************************************/
static uint32_t read_first_ifr_word(uint32_t read_addr)
{
ifr_read_addr = read_addr;
return read_another_ifr_word();
}
/*! *********************************************************************************
* \brief Read command for reading additional 32bit words from IFR. Encapsulates multiple IFR read mechanisms.
*
* \param read_addr flash address
*
* \return 8 bytes of packed data containing radio trims only
*
* \remarks PRE-CONDITIONS:
* The function read_first_ifr_word() must have been called so that the ifr_read_addr variable is setup prior to use.
*
***********************************************************************************/
static uint32_t read_another_ifr_word(void)
{
uint32_t packed_data;
#if (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1)
/* Using some static storage and alternating reads to read_index_ifr to replace read_resource_ifr */
if (num_words_avail == 0)
{
#if RADIO_IS_GEN_3P0
packed_data_long = read_index_ifr(ifr_read_addr);
#else /* Use 64 bit return version of read_resource */
packed_data_long = read_resource_ifr(ifr_read_addr);
#endif /* RADIO_IS_GEN_3P0 */
num_words_avail = 2;
ifr_read_addr++; /* Read index addresses increment by 1 */
}
packed_data = (uint32_t)(packed_data_long & 0xFFFFFFFF);
packed_data_long = packed_data_long >> 32;
num_words_avail--;
#else
packed_data = read_resource_ifr(ifr_read_addr);
ifr_read_addr += 4; /* Read resource addresses increment by 4 */
#endif /* (RADIO_IS_GEN_3P0 || RADIO_IS_GEN_2P1) */
return packed_data;
}
#if RADIO_IS_GEN_3P0
/*! *********************************************************************************
* \brief Read command for reading from IFR using RDINDEX command
*
* \param read_addr flash address
*
* \return 8 bytes of packed data containing radio trims only
*
***********************************************************************************/
static uint64_t read_index_ifr(uint32_t read_addr)
{
uint8_t rdindex = read_addr;
uint64_t read_data;
uint8_t i;
while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 to make sure not interrupting a prior operation */
if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK )
{
FTFE->FSTAT = (1 << FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
}
FTFE->FCCOB[0] = RDINDX;
FTFE->FCCOB[1] = rdindex;
OSA_InterrupDisable();
FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK;
while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
OSA_InterruptEnable();
/* Pack read data back into 64 bit type */
read_data = FTFE->FCCOB[11]; /* MSB goes in first, will be shifted left sequentially */
for (i = 10; i > 3; i--)
{
read_data = read_data << 8;
read_data |= FTFE->FCCOB[i];
}
return read_data;
}
#else
/*! *********************************************************************************
* \brief Read command for reading from IFR
*
* \param read_addr flash address
*
* \return packed data containing radio trims only
*
***********************************************************************************/
#if RADIO_IS_GEN_2P0
static uint32_t read_resource_ifr(uint32_t read_addr)
{
uint32_t packed_data;
uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0;
uint32_t read_data31_24, read_data23_16, read_data15_8, read_data7_0;
flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16);
flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8);
flash_addr7_0 = (uint8_t)(read_addr & 0xFF);
while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */
if ((FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) == FTFA_FSTAT_ACCERR_MASK )
{
FTFA->FSTAT = (1<<FTFA_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
}
FTFA->FCCOB0 = RDRSRC;
FTFA->FCCOB1 = flash_addr23_16;
FTFA->FCCOB2 = flash_addr15_8;
FTFA->FCCOB3 = flash_addr7_0;
FTFA->FCCOB8 = 0x00;
OSA_InterruptDisable();
FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK;
while ((FTFA_FSTAT_CCIF_MASK & FTFA->FSTAT) == 0); /* Wait till CCIF=1 */
OSA_InterruptEnable();
/* Start reading */
read_data31_24 = FTFA->FCCOB4; /* FTFA->FCCOB[4] */
read_data23_16 = FTFA->FCCOB5; /* FTFA->FCCOB[5] */
read_data15_8 = FTFA->FCCOB6; /* FTFA->FCCOB[6] */
read_data7_0 = FTFA->FCCOB7; /* FTFA->FCCOB[7] */
packed_data = (read_data31_24 << 24) | (read_data23_16 << 16) | (read_data15_8 << 8) | (read_data7_0 << 0);
return packed_data;
}
#else
static uint64_t read_resource_ifr(uint32_t read_addr)
{
uint64_t packed_data;
uint8_t flash_addr23_16, flash_addr15_8, flash_addr7_0;
uint8_t read_data[8];
uint64_t temp_64;
uint8_t i;
flash_addr23_16 = (uint8_t)((read_addr & 0xFF0000) >> 16);
flash_addr15_8 = (uint8_t)((read_addr & 0x00FF00) >> 8);
flash_addr7_0 = (uint8_t)(read_addr & 0xFF);
while((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
if ((FTFE->FSTAT & FTFE_FSTAT_ACCERR_MASK) == FTFE_FSTAT_ACCERR_MASK )
{
FTFE->FSTAT = (1<<FTFE_FSTAT_ACCERR_SHIFT); /* Write 1 to ACCEER to clear errors */
}
FTFE->FCCOB0 = RDRSRC;
FTFE->FCCOB1 = flash_addr23_16;
FTFE->FCCOB2 = flash_addr15_8;
FTFE->FCCOB3 = flash_addr7_0;
FTFE->FCCOB4 = 0x00;
OSA_InterruptDisable();
FTFE->FSTAT = FTFE_FSTAT_CCIF_MASK;
while ((FTFE_FSTAT_CCIF_MASK & FTFE->FSTAT) == 0); /* Wait till CCIF=1 */
OSA_InterruptEnable();
/* Start reading */
read_data[7] = FTFE->FCCOB4;
read_data[6] = FTFE->FCCOB5;
read_data[5] = FTFE->FCCOB6;
read_data[4] = FTFE->FCCOB7;
read_data[3] = FTFE->FCCOB8;
read_data[2] = FTFE->FCCOB9;
read_data[1] = FTFE->FCCOBA;
read_data[0] = FTFE->FCCOBB;
packed_data = 0;
for (i = 0; i < 8; i++)
{
temp_64 = read_data[i];
packed_data |= temp_64 << (i * 8);
}
return packed_data;
}
#endif /* RADIO_IS_GEN_2P0 */
#endif /* RADIO_IS_GEN_3P0 */
/*! *********************************************************************************
* \brief Store a SW trim value in the table passed in from calling function.
*
* \param sw_trim_tbl pointer to the software trim table to hold SW trim values
* \param num_entries the number of entries in the SW trim table
* \param addr the software trim ID
* \param data the value of the software trim
*
***********************************************************************************/
static void store_sw_trim(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries, uint32_t addr, uint32_t data)
{
uint16_t i;
if (sw_trim_tbl != NULL)
{
for (i = 0; i < num_entries; i++)
{
if (addr == sw_trim_tbl[i].trim_id)
{
sw_trim_tbl[i].trim_value = data;
sw_trim_tbl[i].valid = 1;
break; /* Don't need to scan the array any further... */
}
}
}
}
/*! *********************************************************************************
* \brief Process block 1 IFR data.
*
* \param sw_trim_tbl pointer to the software trim table to hold SW trim values
* \param num_entries the number of entries in the SW trim table
*
* \remarks
* Uses a IFR v2 formatted default array if the IFR is blank or corrupted.
* Stores SW trim values to an array passed into this function.
*
***********************************************************************************/
void handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries)
{
uint32_t dest_addr;
uint32_t read_addr;
uint32_t dest_data;
uint32_t packed_data;
const uint32_t *ifr_ptr;
#if RADIO_IS_GEN_3P0
num_words_avail = 0; /* Prep for handling 64 bit words from flash */
#endif /* RADIO_IS_GEN_3P0 */
#if RADIO_IS_GEN_3P0
read_addr = K3_BASE_INDEX;
#else
#ifdef CPU_MODEL_MKW41Z256VHT4
read_addr = KW4x_256_BASE;
#else
read_addr = KW4x_512_BASE;
#endif /* CPU_MODEL_MKW41Z256VHT4 */
#endif /* RADIO_IS_GEN_3P0 */
/* Read first entry in IFR table */
packed_data = read_first_ifr_word(read_addr);
if ((packed_data&~IFR_VERSION_MASK) == IFR_VERSION_HDR)
{
/* Valid header was found, process real IFR data */
XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK);
store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array*/
packed_data = read_another_ifr_word();
while (packed_data !=IFR_EOF_SYMBOL)
{
if (IS_A_SW_ID(packed_data)) /* SW Trim case (non_reg writes) */
{
dest_addr = packed_data;
packed_data = read_another_ifr_word();
dest_data = packed_data;
/* Place SW trim in array for driver SW to use */
store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
}
else
{
if (IS_VALID_REG_ADDR(packed_data)) /* Valid register write address */
{
dest_addr = packed_data;
packed_data = read_another_ifr_word();
dest_data = packed_data;
*(uint32_t *)(dest_addr) = dest_data;
}
else
{ /* Invalid address case */
}
}
packed_data=read_another_ifr_word();
}
}
else
{
/* Valid header is not present, use blind IFR trim table */
ifr_ptr = BLOCK_1_IFR;
packed_data = *ifr_ptr;
XCVR_MISC->OVERWRITE_VER = (packed_data & IFR_VERSION_MASK);
store_sw_trim(sw_trim_tbl, num_entries, 0xABCD, (packed_data & IFR_VERSION_MASK)); /* Place IFR version # in SW trim array */
ifr_ptr++;
packed_data= *ifr_ptr;
while (packed_data != IFR_EOF_SYMBOL)
{
if (IS_A_SW_ID(packed_data))
{
/* SW Trim case (non_reg writes) */
dest_addr = packed_data;
ifr_ptr++;
packed_data = *(ifr_ptr);
dest_data = packed_data;
/* Place SW trim in array for driver SW to use */
store_sw_trim(sw_trim_tbl, num_entries, dest_addr, dest_data);
}
else
{
dest_addr = packed_data;
ifr_ptr++;
packed_data = *ifr_ptr;
dest_data = packed_data;
/* Valid register write address */
if (IS_VALID_REG_ADDR(dest_addr))
{
*(uint32_t *)(dest_addr) = dest_data;
}
else
{
/* Invalid address case */
}
}
ifr_ptr++;
packed_data= *ifr_ptr;
}
}
}
#if RADIO_IS_GEN_3P0
#else
uint32_t handle_ifr_die_id(void)
{
uint32_t id_x, id_y;
uint32_t id;
id = read_resource_ifr(0x90);
id_x = id & 0x00FF0000;
id_y = id & 0x000000FF;
return (id_x | id_y);
}
uint32_t handle_ifr_die_kw_type(void)
{
uint32_t zb, ble;
zb = read_resource_ifr(0x80) & 0x8000;
ble= read_resource_ifr(0x88) & 0x100000;
return (zb | ble);
}
#endif /* RADIO_IS_GEN_3P0 */
/*! *********************************************************************************
* \brief Dumps block 1 IFR data to an array.
*
* \param dump_tbl pointer to the table to hold the dumped IFR values
* \param num_entries the number of entries to dump
*
* \remarks
* Starts at the first address in IFR and dumps sequential entries.
*
***********************************************************************************/
void dump_ifr(uint32_t * dump_tbl, uint8_t num_entries)
{
#if RADIO_IS_GEN_3P0
uint32_t ifr_address = 0x20000;
#else
uint32_t ifr_address = 0x20000;
#endif /* RADIO_IS_GEN_3P0 */
uint32_t * dump_ptr = dump_tbl;
uint8_t i;
*dump_ptr = read_first_ifr_word(ifr_address);
dump_ptr++;
for (i = 0; i < num_entries - 1; i++)
{
*dump_ptr = read_another_ifr_word();
dump_ptr++;
}
}

View File

@ -0,0 +1,193 @@
/*
* The Clear BSD License
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* 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.
*/
#ifndef __IFR_RADIO_H__
/* clang-format off */
#define __IFR_RADIO_H__
/* clang-format on */
#include <stdint.h>
#include "fsl_xcvr.h"
#ifdef __cplusplus
extern "C" {
#endif
/*!
* @addtogroup xcvr
* @{
*/
/*! @file*/
/*******************************************************************************
* Definitions
******************************************************************************/
#define IFR_EOF_SYMBOL (0xFEED0E0FU) /* < Denotes the "End of File" for IFR data */
#define IFR_VERSION_HDR (0xABCD0000U) /* < Constant value for upper 16 bits of IFR data header */
#define IFR_VERSION_MASK (0x0000FFFFU) /* < Mask for version number (lower 16 bits) of IFR data header */
#define IFR_SW_ID_MIN (0x00000000U) /* < Lower limit of SW trim IDs */
#define IFR_SW_ID_MAX (0x0000FFFFU) /* < Lower limit of SW trim IDs */
#define IS_A_SW_ID(x) ((IFR_SW_ID_MIN < (x)) && (IFR_SW_ID_MAX >= (x)))
/* K3 valid registers support */
#if (defined(CPU_MODEL_K32W042S1M2CAx_M0P) || defined(CPU_MODEL_K32W042S1M2VPJ_M0P))
#define IS_VALID_REG_ADDR(x) (((x) & 0xFFFF0000U) == 0x41000000U) /* Valid addresses are 0x410xxxxx */
#endif /* (defined(CPU_MODEL_K32W042S1M2CAx_M0P) || defined(CPU_MODEL_K32W042S1M2VPJ_M0P)) */
/* KW41 and KW35/36 valid registers support */
#if (defined(CPU_MODEL_MKW41Z256VHT4) || defined(CPU_MODEL_MKW41Z512VHT4) || \
defined(CPU_MODEL_MKW31Z256VHT4) || defined(CPU_MODEL_MKW31Z512VHT4) || \
defined(CPU_MODEL_MKW21Z256VHT4) || defined(CPU_MODEL_MKW21Z512VHT4) || \
defined(CPU_MODEL_MKW35A512VFP4) || defined(CPU_MODEL_MKW36A512VFP4) )
#define IS_VALID_REG_ADDR(x) (((x) & 0xFFFF0000U) == 0x40050000U) /* Valid addresses are 0x4005xxxx */
#endif
#define MAKE_MASK(size) ((1 << (size)) - 1)
#define MAKE_MASKSHFT(size, bitpos) (MAKE_MASK(size) << (bitpos))
#define IFR_TZA_CAP_TUNE_MASK (0x0000000FU)
#define IFR_TZA_CAP_TUNE_SHIFT (0)
#define IFR_BBF_CAP_TUNE_MASK (0x000F0000U)
#define IFR_BBF_CAP_TUNE_SHIFT (16)
#define IFR_RES_TUNE2_MASK (0x00F00000U)
#define IFR_RES_TUNE2_SHIFT (20)
/* \var typedef uint8_t IFR_ERROR_T */
/* \brief The IFR error reporting type. */
/* See #IFR_ERROR_T_enum for the enumeration definitions. */
typedef uint8_t IFR_ERROR_T;
/* \brief The enumerations used to describe IFR errors. */
enum IFR_ERROR_T_enum
{
IFR_SUCCESS = 0,
INVALID_POINTER = 1, /* < NULL pointer error */
INVALID_DEST_SIZE_SHIFT = 2, /* < the bits won't fit as specified in the destination */
};
/* \var typedef uint16_t SW_TRIM_ID_T */
/* \brief The SW trim ID type. */
/* See #SW_TRIM_ID_T_enum for the enumeration definitions. */
typedef uint16_t SW_TRIM_ID_T;
/* \brief The enumerations used to define SW trim IDs. */
enum SW_TRIM_ID_T_enum
{
Q_RELATIVE_GAIN_BY_PART = 0, /* < Q vs I relative gain trim ID */
ADC_GAIN = 1, /* < ADC gain trim ID */
ZB_FILT_TRIM = 2, /* < Baseband Bandwidth filter trim ID for BLE */
BLE_FILT_TRIM = 3, /* < Baseband Bandwidth filter trim ID for BLE */
TRIM_STATUS = 4, /* < Status result of the trim process (error indications) */
TRIM_VERSION = 0xABCD, /* < Version number of the IFR trim algorithm/format. */
};
/* \var typedef uint32_t IFR_TRIM_STATUS_T */
/* \brief The definition of failure bits stored in IFR trim status word. */
/* See #IFR_TRIM_STATUS_T_enum for the enumeration definitions. */
typedef uint32_t IFR_TRIM_STATUS_T;
/* \brief The enumerations used to describe trim algorithm failures in the status entry in IFR. */
/* This enum represents multiple values which can be OR'd together in a single status word. */
enum IFR_TRIM_STATUS_T_enum
{
TRIM_ALGORITHM_SUCCESS = 0,
BGAP_VOLTAGE_TRIM_FAILED = 1, /* < algorithm failure in BGAP voltagetrim */
IQMC_GAIN_ADJ_FAILED = 2, /* < algorithm failure in IQMC gain trim */
IQMC_PHASE_ADJ_FAILED = 4, /* < algorithm failure in IQMC phase trim */
IQMC_DC_GAIN_ADJ_FAILED = 8, /* < IQMC DC gain trim failure */
ADC_GAIN_TRIM_FAILED = 10, /* < Trim failure for ADC Gain Trim */
ZB_FILT_TRIM_FAILED = 20, /* < Filter trim failure for 802.15.4 */
BLE_FILT_TRIM_FAILED = 40, /* < Filter trim failure for BLE */
};
/* \var typedef struct IFR_SW_TRIM_TBL_ENTRY_T */
/* \brief Structure defining an entry in a table used to contain values to be passed back from IFR */
/* handling routine to XCVR driver software. */
typedef struct
{
SW_TRIM_ID_T trim_id; /* < The assigned ID */
uint32_t trim_value; /* < The value fetched from IFR.*/
uint8_t valid; /* < validity of the trim_value field after IFR processing is complete (TRUE/FALSE).*/
} IFR_SW_TRIM_TBL_ENTRY_T;
/*******************************************************************************
* API
******************************************************************************/
/*!
* @brief Main IFR handler function called by XCVR driver software to process trim table.
*
* This function handles reading data from IFR and either loading to registers or storing to a SW trim values table.
*
* @param sw_trim_tbl pointer to the table used to store software trim values.
* @param num_entries the number of entries that can be stored in the SW trim table.
*/
void handle_ifr(IFR_SW_TRIM_TBL_ENTRY_T * sw_trim_tbl, uint16_t num_entries);
/*!
* @brief Handler function to read die_id from IFR locations..
*
* This function handles reading die ID value for debug and testing usage.
*
* @return the value of the die ID field.
*/
uint32_t handle_ifr_die_id(void);
/*!
* @brief Handler function to read KW chip version from IFR locations..
*
* This function handles reading KW chip version for debug and testing usage.
*
* @return the value of the KW version field.
*/
uint32_t handle_ifr_die_kw_type(void);
/*!
* @brief Debug function to dump the IFR contents to a RAM array.
*
* This function handles reading data from IFR and storing to a RAM array for debug.
*
* @param dump_tbl pointer to the table used to store IFR entry values.
* @param num_entries the number of entries that can be stored in the dump table.
*/
void dump_ifr(uint32_t * dump_tbl, uint8_t num_entries);
#ifdef __cplusplus
}
#endif
#endif /*__IFR_RADIO_H__ */

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2017 SKF AB
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/**
* @ingroup sys_auto_init_gnrc_netif
* @{
*
* @file
* @brief Auto initialization for kw41zrf network interfaces
*
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Thomas Stilwell <stilwellt@openlabs.co>
*/
#ifdef MODULE_KW41ZRF
#include "log.h"
#include "board.h"
#include "net/gnrc.h"
#include "net/gnrc/netif/ieee802154.h"
#ifdef MODULE_GNRC_LWMAC
#include "net/gnrc/lwmac/lwmac.h"
#endif
#ifdef MODULE_GNRC_GOMACH
#include "net/gnrc/gomach/gomach.h"
#endif
#include "kw41zrf.h"
/**
* @name Stack parameters for the MAC layer thread
* @{
*/
#ifndef KW41ZRF_NETIF_STACKSIZE
#define KW41ZRF_NETIF_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif
#ifndef KW41ZRF_NETIF_PRIO
#define KW41ZRF_NETIF_PRIO (GNRC_NETIF_PRIO)
#endif
/** @} */
/* There is only one memory mapped transceiver in the supported SoCs, the driver
* does not try to take into account multiple instances of the hardware module */
#define KW41ZRF_NUMOF 1
static kw41zrf_t kw41zrf_devs[KW41ZRF_NUMOF];
static char _kw41zrf_stacks[KW41ZRF_NUMOF][KW41ZRF_NETIF_STACKSIZE];
void auto_init_kw41zrf(void)
{
for (unsigned i = 0; i < KW41ZRF_NUMOF; i++) {
LOG_DEBUG("[auto_init_netif] initializing kw41zrf #%u\n", i);
kw41zrf_setup(&kw41zrf_devs[i]);
#if defined(MODULE_GNRC_GOMACH)
gnrc_netif_gomach_create(_kw41zrf_stacks[i], KW41ZRF_NETIF_STACKSIZE,
KW41ZRF_NETIF_PRIO, "kw41zrf-gomach",
(netdev_t *)&kw41zrf_devs[i]);
#elif defined(MODULE_GNRC_LWMAC)
gnrc_netif_lwmac_create(_kw41zrf_stacks[i], KW41ZRF_NETIF_STACKSIZE,
KW41ZRF_NETIF_PRIO, "kw41zrf-lwmac",
(netdev_t *)&kw41zrf_devs[i]);
#else
gnrc_netif_ieee802154_create(_kw41zrf_stacks[i], KW41ZRF_NETIF_STACKSIZE,
KW41ZRF_NETIF_PRIO, "kw41zrf",
(netdev_t *)&kw41zrf_devs[i]);
#endif
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_KW41ZRF */
/** @} */

View File

@ -109,6 +109,11 @@ void gnrc_netif_init_devs(void)
auto_init_kw2xrf();
}
if (IS_USED(MODULE_KW41ZRF)) {
extern void auto_init_kw41zrf(void);
auto_init_kw41zrf();
}
if (IS_USED(MODULE_USBUS_CDC_ECM)) {
extern void auto_init_netdev_cdcecm(void);
auto_init_netdev_cdcecm();