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

Merge pull request #6453 from smlng/pr/5469-bis

drivers/kw2xrf: adapt to netdev2
This commit is contained in:
Peter Kietzmann 2017-02-07 15:58:54 +01:00 committed by GitHub
commit 5bf4882592
24 changed files with 3334 additions and 1543 deletions

View File

@ -65,14 +65,15 @@ extern "C"
/** @} */
/**
@name KW2XRF configuration
@{
*/
#define KW2XRF_SPI (SPI_DEV(1))
#define KW2XRF_CS (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_PCS0_PIN))
#define KW2XRF_INT (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_IRQ_PIN))
#define KW2XRF_SPI_SPEED (SPI_CLK_10MHZ)
#define KW2XRF_SHARED_SPI 0
* @name KW2XRF configuration
*
* {spi bus, cs pin, int pin, spi speed,}
*/
#define KW2XRF_PARAMS_BOARD {.spi = SPI_DEV(1), \
.spi_clk = SPI_CLK_10MHZ, \
.cs_pin = GPIO_PIN(KW2XDRF_PORT, KW2XDRF_PCS0_PIN), \
.int_pin = GPIO_PIN(KW2XDRF_PORT, KW2XDRF_IRQ_PIN) }
#define KW2XRF_SHARED_SPI 0
/** @}*/
/**

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2014 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 board_pba-d-01-kw2x
* @{
*
* @file
* @brief kw2xrf board specific configuration
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Jonas Remmert <j.remmert@phytec.de>
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef KW2XRF_PARAMS_H
#define KW2XRF_PARAMS_H
/**
* @name KW2XRF configuration
*/
static const kw2xrf_params_t kw2xrf_params[] =
{
{
.spi = KW2XRF_SPI,
.spi_speed = KW2XRF_SPI_SPEED,
.cs_pin = KW2XRF_CS,
.int_pin = KW2XRF_INT,
},
};
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_PARAMS_H */
/** @} */

View File

@ -826,6 +826,7 @@ EXCLUDE_PATTERNS = */board/*/tools/* \
*/cpu/cortexm_common/include/core_cm*.h \
*/cpu/stm32f*/include/stm32f* \
*/drivers/nrf24l01p/include/nrf24l01p_settings.h \
*/drivers/kw2xrf/include/overwrites.h \
*/cpu/nrf5*/include/nrf5*.h \
*/cpu/lpc1768/include/LPC17xx.h \
*/cpu/lpc11u34/include/LPC11Uxx.h \

View File

@ -114,11 +114,15 @@ ifneq (,$(filter jc42,$(USEMODULE)))
endif
ifneq (,$(filter kw2xrf,$(USEMODULE)))
USEMODULE += ieee802154
USEMODULE += netif
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
USEMODULE += gnrc_nomac
endif
USEMODULE += uuid
USEMODULE += netif
USEMODULE += ieee802154
USEMODULE += netdev2_ieee802154
ifneq (,$(filter gnrc_netdev_default,$(USEMODULE)))
# XXX: this can be modelled as a dependency for gnrc_netdev_default as soon
# as all drivers are ported to netdev2
USEMODULE += gnrc_netdev2
endif
endif
ifneq (,$(filter lis3dh,$(USEMODULE)))

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Phytec Messtechnik GmbH
* 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
@ -8,27 +8,29 @@
/**
* @defgroup drivers_kw2xrf kw2x radio-driver
* @ingroup drivers_netdev
* @brief Device driver for the Freescale KW2xD radio
* @ingroup drivers_netdev_netdev2
* @brief Device driver for the NXP CR20A and KW2xD radios
* @{
*
* @file
* @brief Interface definition for the KW2xD device driver
* @brief Interface definition for the kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
* @author Jonas Remmert <j.remmert@phytec.de>
* @author Sebastian Meiling <s@mlng.net>
*/
#ifndef MKW2XDRF_H
#define MKW2XDRF_H
#ifndef KW2XDRF_H
#define KW2XDRF_H
#include <stdint.h>
#include "board.h"
#include "periph/spi.h"
#include "periph/gpio.h"
#include "net/gnrc/netdev.h"
#include "net/ieee802154.h"
#include "net/netdev2.h"
#include "net/netdev2/ieee802154.h"
#include "net/gnrc/nettype.h"
#ifdef __cplusplus
extern "C" {
@ -37,127 +39,136 @@ extern "C" {
/**
* @brief Maximum packet length
*/
#define KW2XRF_MAX_PKT_LENGTH (IEEE802154_FRAME_LEN_MAX)
/**
* @brief Default protocol for data that is coming in
*/
#ifdef MODULE_GNRC_SIXLOWPAN
#define KW2XRF_DEFAULT_PROTOCOL GNRC_NETTYPE_SIXLOWPAN
#else
#define KW2XRF_DEFAULT_PROTOCOL GNRC_NETTYPE_UNDEF
#endif
/**
* @brief Default short address used after initialization
*/
#define KW2XRF_DEFAULT_SHORT_ADDR (0x0002)
/**
* @brief Default short address used after initialization
*/
#define KW2XRF_DEFAULT_ADDR_LONG (0x0000000000000000)
#define KW2XRF_MAX_PKT_LENGTH (IEEE802154_FRAME_LEN_MAX)
/**
* @brief Default PAN ID used after initialization
*/
#define KW2XRF_DEFAULT_PANID (IEEE802154_DEFAULT_PANID)
#define KW2XRF_DEFAULT_PANID (IEEE802154_DEFAULT_PANID)
/**
* @brief Default channel used after initialization
*
* @{
*/
#ifdef DEFAULT_CHANNEL
#define KW2XRF_DEFAULT_CHANNEL (DEFAULT_CHANNEL)
#endif
#ifndef KW2XRF_DEFAULT_CHANNEL
#define KW2XRF_DEFAULT_CHANNEL (IEEE802154_DEFAULT_CHANNEL)
#define KW2XRF_DEFAULT_CHANNEL (IEEE802154_DEFAULT_CHANNEL)
#endif
/** @} */
/**
* @brief Allowed range of channels
*
* @{
*/
#define KW2XRF_MIN_CHANNEL (11U)
#define KW2XRF_MAX_CHANNEL (26U)
/** @} */
/**
* @brief Default TX_POWER in dbm used after initialization
*/
#define KW2XRF_DEFAULT_TX_POWER (IEEE802154_DEFAULT_TXPOWER)
#define KW2XRF_DEFAULT_TX_POWER (IEEE802154_DEFAULT_TXPOWER)
/**
* @brief Maximum output power of the kw2x device in dBm
*/
#define MKW2XDRF_OUTPUT_POWER_MAX (8)
#define KW2XDRF_OUTPUT_POWER_MAX (8)
/**
* @brief Minimum output power of the kw2x device in dBm
*/
#define MKW2XDRF_OUTPUT_POWER_MIN (-35)
#define KW2XDRF_OUTPUT_POWER_MIN (-35)
/**
* @brief Internal device option flags
*
* `0x00ff` is reserved for general IEEE 802.15.4 flags
* (see @ref netdev2_ieee802154_t)
*
* @{
*/
#define KW2XRF_OPT_AUTOACK (0x0001) /**< auto ACKs active */
#define KW2XRF_OPT_CSMA (0x0002) /**< CSMA active */
#define KW2XRF_OPT_PROMISCUOUS (0x0004) /**< promiscuous mode active */
#define KW2XRF_OPT_PRELOADING (0x0008) /**< preloading enabled */
#define KW2XRF_OPT_TELL_TX_START (0x0010) /**< notify MAC layer on TX start */
#define KW2XRF_OPT_TELL_TX_END (0x0020) /**< notify MAC layer on TX finished */
#define KW2XRF_OPT_TELL_RX_START (0x0040) /**< notify MAC layer on RX start */
#define KW2XRF_OPT_TELL_RX_END (0x0080) /**< notify MAC layer on RX finished */
#define KW2XRF_OPT_RAWDUMP (0x0100) /**< pass RAW frame data to upper layer */
#define KW2XRF_OPT_SRC_ADDR_LONG (0x0200) /**< send data using long source address */
#define KW2XRF_OPT_USE_SRC_PAN (0x0400) /**< do not compress source PAN ID */
#define KW2XRF_OPT_SRC_ADDR_LONG (NETDEV2_IEEE802154_SRC_MODE_LONG) /**< legacy define */
#define KW2XRF_OPT_RAWDUMP (NETDEV2_IEEE802154_RAW) /**< legacy define */
#define KW2XRF_OPT_ACK_REQ (NETDEV2_IEEE802154_ACK_REQ) /**< legacy define */
#define KW2XRF_OPT_AUTOCCA (0x0100) /**< CCA befor TX active */
#define KW2XRF_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode
* active */
#define KW2XRF_OPT_PRELOADING (0x0400) /**< preloading enabled */
#define KW2XRF_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX
* start */
#define KW2XRF_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX
* finished */
#define KW2XRF_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX
* start */
#define KW2XRF_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX
* finished */
#define KW2XRF_OPT_AUTOACK (0x8000) /**< enable automatically ACK
* for incommint packet */
/** @} */
/**
* @brief kw2xrf device descriptor
*/
typedef struct {
/* netdev fields */
gnrc_netdev_driver_t const *driver; /**< Pointer to the devices interface */
gnrc_netdev_event_cb_t event_cb; /**< Netdev event callback */
kernel_pid_t mac_pid; /**< The driver's thread's PID */
/* driver specific fields */
uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */
netopt_state_t state; /**< Variable to keep radio driver's state */
uint8_t seq_nr; /**< Next packets sequence number */
uint16_t radio_pan; /**< The PAN the radio device is using */
uint8_t radio_channel; /**< The channel the radio device is using */
uint8_t addr_short[2]; /**< The short address the radio device is using */
uint8_t addr_long[8]; /**< The long address the radio device is using */
uint16_t option; /**< Bit field to save enable/disable options */
int8_t tx_power; /**< The current tx-power setting of the device */
gnrc_nettype_t proto; /**< Protocol the interface speaks */
} kw2xrf_t;
/**
* @brief Initialize the given KW2XRF device
* @param[out] dev device descriptor
* @param[in] spi SPI bus the device is connected to
* @param[in] spi_clk SPI bus clock speed to use
* @param[in] cs_pin GPIO pin connected to chip select
* @param[in] int_pin GPIO pin connected to the interrupt pin
*
* @return 0 on success
* @return <0 on error
*/
int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk,
gpio_t cs_pin, gpio_t int_pin);
/**
* @brief struct holding all params needed for device initialization
*/
typedef struct kw2xrf_params {
spi_t spi; /**< SPI bus the device is connected to */
spi_clk_t spi_speed; /**< SPI speed to use */
gpio_t cs_pin; /**< GPIO pin connected to chip select */
gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */
spi_t spi; /**< SPI bus the device is connected to */
spi_clk_t spi_clk; /**< SPI clock speed to use */
gpio_t cs_pin; /**< GPIO pin connected to chip select */
gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */
} kw2xrf_params_t;
/**
* @brief Reference to the KW2XRF driver interface
* @brief Device descriptor for KW2XRF radio devices
*
* @extends netdev2_ieee802154_t
*/
extern const gnrc_netdev_driver_t kw2xrf_driver;
typedef struct {
netdev2_ieee802154_t netdev; /**< netdev2 parent struct */
/**
* @brief device specific fields
* @{
*/
kw2xrf_params_t params; /**< parameters for initialization */
uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */
uint8_t state; /**< current state of the radio */
uint8_t tx_frame_len; /**< length of the current TX frame */
uint8_t idle_state; /**< state to return to after sending */
uint8_t pending_tx; /**< keep track of pending TX calls
this is required to know when to
return to @ref kw2xrf_t::idle_state */
int16_t tx_power; /**< The current tx-power setting of the device */
/** @} */
} kw2xrf_t;
/**
* @brief Setup an KW2XRF based device state
*
* @param[out] dev device descriptor
* @param[in] params parameters for device initialization
*/
void kw2xrf_setup(kw2xrf_t *dev, const kw2xrf_params_t *params);
/**
* @brief Initialize the given KW2XRF device
* @param[out] dev device descriptor
* @param[in] cb irq callback
*
* @return 0 on success
* @return <0 on error
*/
int kw2xrf_init(kw2xrf_t *dev, gpio_cb_t cb);
/**
* @brief Configure radio with default values
*
* @param[in] dev device to reset
*/
void kw2xrf_reset_phy(kw2xrf_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* MKW2XDRF_H */
#endif /* KW2XDRF_H */
/** @} */

View File

@ -0,0 +1,204 @@
/*
* 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_kw2xrf
* @{
*
* @file
* @brief get/set interfaces for kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef KW2XRF_GETSET_H
#define KW2XRF_GETSET_H
#include "kw2xrf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set tx power of given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] txpower transmit power in dBm
*/
void kw2xrf_set_tx_power(kw2xrf_t *dev, int16_t txpower);
/**
* @brief Get tx power value of given device
*
* @param[in] dev kw2xrf device descriptor
*
* @return current tx power value
*/
uint16_t kw2xrf_get_txpower(kw2xrf_t *dev);
/**
* @brief Set channel of given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] val channel
*/
int kw2xrf_set_channel(kw2xrf_t *dev, uint8_t val);
/**
* @brief Get channel of given device
*
* @param[in] dev kw2xrf device descriptor
*
* @return current channel
*/
uint8_t kw2xrf_get_channel(kw2xrf_t *dev);
/**
* @brief Abort current sequence of device
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_abort_sequence(kw2xrf_t *dev);
/**
* @brief Set idle sequence state of device
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_set_idle_sequence(kw2xrf_t *dev);
/**
* @brief Set sequence state of device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] seq sequence
*/
void kw2xrf_set_sequence(kw2xrf_t *dev, kw2xrf_physeq_t seq);
/**
* @brief Set PAN ID of a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] pan PAN ID value
*/
void kw2xrf_set_pan(kw2xrf_t *dev, uint16_t pan);
/**
* @brief Set short address of a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] addr short address
*/
void kw2xrf_set_addr_short(kw2xrf_t *dev, uint16_t addr);
/**
* @brief Set long address of a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] addr long address
*/
void kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr);
/**
* @brief Get short address of a given device
*
* @param[in] dev kw2xrf device descriptor
* @return current short address
*/
uint16_t kw2xrf_get_addr_short(kw2xrf_t *dev);
/**
* @brief Get long address of a given device
*
* @param[in] dev kw2xrf device descriptor
* @return current long address
*/
uint64_t kw2xrf_get_addr_long(kw2xrf_t *dev);
/**
* @brief Get CCA threshhold of a given device
*
* @param[in] dev kw2xrf device descriptor
* @return current CCA threshhold
*/
int8_t kw2xrf_get_cca_threshold(kw2xrf_t *dev);
/**
* @brief Set CCA threshold of a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] value CCA threshold
*/
void kw2xrf_set_cca_threshold(kw2xrf_t *dev, int8_t value);
/**
* @brief Set CCA mode of a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] mode CCA mode
*/
void kw2xrf_set_cca_mode(kw2xrf_t *dev, uint8_t mode);
/**
* @brief Get CCA mode of a given device
*
* @param[in] dev kw2xrf device descriptor
* @return current CCA mode
*/
uint8_t kw2xrf_get_cca_mode(kw2xrf_t *dev);
/**
* @brief Get RSSI from LQI value
*
* @param[in] value Current LQI value
*
* @return deduced RSSI in dBm
*/
uint32_t kw2xrf_get_rssi(uint32_t value);
/**
* @brief Get state of a given device
*
* @param[in] dev kw2xrf device descriptor
* @return current state
*/
netopt_state_t kw2xrf_get_status(kw2xrf_t *dev);
/**
* @brief Enable continous CCA
*
* @param[in] dev kw2xrf device descriptor
*
* @return CCA value
*/
int kw2xrf_cca(kw2xrf_t *dev);
/**
* @brief Set receive watermark
*
* @param[in] dev kw2xrf device descriptor
* @param[in] value watermark
*/
void kw2xrf_set_rx_watermark(kw2xrf_t *dev, uint8_t value);
/**
* @brief Set netopt a given device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] option Netopt option type
* @param[in] state state
*/
void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state);
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_GETSET_H */
/** @} */

View File

@ -0,0 +1,237 @@
/*
* 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_kw2xrf
* @{
*
* @file
* @brief Internal function interfaces for kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef KW2XRF_INTERN_H
#define KW2XRF_INTERN_H
#include <stdint.h>
#include "kw2xrf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Power Modes
*/
typedef enum {
KW2XRF_HIBERNATE = 0,
KW2XRF_DOZE,
KW2XRF_IDLE,
KW2XRF_AUTODOZE,
} kw2xrf_powermode_t;
/**
* @brief Set a certain bit of a kw2xrf register
*
* @param[in] dev kw2xrf device descriptor
* @param[in] reg address of register
* @param[in] bit set this bit
*/
inline void kw2xrf_set_dreg_bit(kw2xrf_t *dev, uint8_t reg, uint8_t bit)
{
uint8_t tmp = kw2xrf_read_dreg(dev, reg);
tmp |= bit;
kw2xrf_write_dreg(dev, reg, tmp);
}
/**
* @brief Clear a certain bit of a kw2xrf register
*
* @param[in] dev kw2xrf device descriptor
* @param[in] reg address of register
* @param[in] bit set this bit
*/
inline void kw2xrf_clear_dreg_bit(kw2xrf_t *dev, uint8_t reg, uint8_t bit)
{
uint8_t tmp = kw2xrf_read_dreg(dev, reg);
tmp &= ~bit;
kw2xrf_write_dreg(dev, reg, tmp);
}
/**
* @brief Enable any transceiver interrupt to assert IRQ_B
*
* @param[in] dev kw2xrf device descriptor
*/
inline void kw2xrf_enable_irq_b(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TRCV_MSK);
}
/**
* @brief Mask all transceiver interrupts to assert IRQ_B
*
* @param[in] dev kw2xrf device descriptor
*/
inline void kw2xrf_mask_irq_b(kw2xrf_t *dev)
{
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TRCV_MSK);
}
/**
* @brief Disable all interrupts on transceiver
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_disable_interrupts(kw2xrf_t *dev);
/**
* @brief
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_update_overwrites(kw2xrf_t *dev);
/**
* @brief
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_set_out_clk(kw2xrf_t *dev);
/**
* @brief Set power mode for device
*
* @param[in] dev kw2xrf device descriptor
* @param[in] pm power mode value
*/
void kw2xrf_set_power_mode(kw2xrf_t *dev, kw2xrf_powermode_t pm);
/**
* @brief
*
* @param[in] dev
*
* @return
*/
int kw2xrf_can_switch_to_idle(kw2xrf_t *dev);
/**
* @brief Timebase values
*/
typedef enum kw2xrf_timer_timebase {
KW2XRF_TIMEBASE_500000HZ = 2,
KW2XRF_TIMEBASE_250000HZ,
KW2XRF_TIMEBASE_125000HZ,
KW2XRF_TIMEBASE_62500HZ,
KW2XRF_TIMEBASE_31250HZ,
KW2XRF_TIMEBASE_15625HZ,
} kw2xrf_timer_timebase_t;
/**
* @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 kw2xrf device descriptor
* @param[in] tb timer base value
*/
void kw2xrf_timer_init(kw2xrf_t *dev, kw2xrf_timer_timebase_t tb);
/**
* @brief Enable start sequence time
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_timer2_seq_start_on(kw2xrf_t *dev);
/**
* @brief Disable start sequence timer
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_timer2_seq_start_off(kw2xrf_t *dev);
/**
* @brief Enable abort sequence timer
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_timer3_seq_abort_on(kw2xrf_t *dev);
/**
* @brief Disable abort sequence timer
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_timer3_seq_abort_off(kw2xrf_t *dev);
/**
* @brief Use T2CMP or T2PRIMECMP to Trigger Transceiver Operations
*
* @param[in] dev kw2xrf device descriptor
* @param[in] timeout timeout value
*/
void kw2xrf_trigger_tx_ops_enable(kw2xrf_t *dev, uint32_t timeout);
/**
* @brief Disable Trigger for Transceiver Operations
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_trigger_tx_ops_disable(kw2xrf_t *dev);
/**
* @brief Use T3CMP to Abort an RX operation
*
* @param[in] dev kw2xrf device descriptor
* @param[in] timeout timeout value
*/
void kw2xrf_abort_rx_ops_enable(kw2xrf_t *dev, uint32_t timeout);
/**
* @brief Disable Trigger to Abort an RX operation
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_abort_rx_ops_disable(kw2xrf_t *dev);
/**
* @brief Enable sequence timeout
*
* @param[in] dev kw2xrf device descriptor
* @param[in] timeout timeout value
*/
void kw2xrf_seq_timeout_on(kw2xrf_t *dev, uint32_t timeout);
/**
* @brief Disable sequence timeout
*
* @param[in] dev kw2xrf device descriptor
*/
void kw2xrf_seq_timeout_off(kw2xrf_t *dev);
/**
* @brief Returns Timestamp of the actual received packet
*
* @param[in] dev kw2xrf device descriptor
*
* @return timestamp value
*/
uint32_t kw2xrf_get_timestamp(kw2xrf_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_INTERN_H */
/** @} */

View File

@ -0,0 +1,36 @@
/*
* 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_kw2xrf
* @{
*
* @file
* @brief Netdev interface for kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef KW2XRF_NETDEV_H
#define KW2XRF_NETDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Reference to the netdev device driver struct
*/
extern const netdev2_driver_t kw2xrf_driver;
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_NETDEV_H */
/** @} */

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2017 Hamburg University of Applied Sciences
*
* 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_kw2xrf
*
* @{
* @file
* @brief Default configuration for the KW2XRF driver
*
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
*/
#ifndef KW2XRF_PARAMS_H
#define KW2XRF_PARAMS_H
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the KW2XRF driver
* @{
*/
#ifndef KW2XRF_PARAM_SPI
#define KW2XRF_PARAM_SPI (SPI_DEV(0))
#endif
#ifndef KW2XRF_PARAM_SPI_CLK
#define KW2XRF_PARAM_SPI_CLK (SPI_CLK_10MHZ)
#endif
#ifndef KW2XRF_PARAM_CS
#define KW2XRF_PARAM_CS (GPIO_PIN(0, 0))
#endif
#ifndef KW2XRF_PARAM_INT
#define KW2XRF_PARAM_INT (GPIO_PIN(0, 1))
#endif
#ifndef KW2XRF_PARAM_SLEEP
#define KW2XRF_PARAM_SLEEP (GPIO_PIN(0, 2))
#endif
#ifndef KW2XRF_PARAM_RESET
#define KW2XRF_PARAM_RESET (GPIO_PIN(0, 3))
#endif
#define KW2XRF_PARAMS_DEFAULT {.spi = KW2XRF_PARAM_SPI, \
.spi_clk = KW2XRF_PARAM_SPI_CLK, \
.cs_pin = KW2XRF_PARAM_CS, \
.int_pin = KW2XRF_PARAM_INT }
/**@}*/
/**
* @brief KW2XRF configuration
*/
static const kw2xrf_params_t kw2xrf_params[] =
{
#ifdef KW2XRF_PARAMS_BOARD
KW2XRF_PARAMS_BOARD,
#else
KW2XRF_PARAMS_DEFAULT,
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_PARAMS_H */
/** @} */

View File

@ -1,9 +1,43 @@
/*
* Copyright (C) 2015 Phytec Messtechnik GmbH
* 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.
*
* The description of the registers was extracted from the
* Reference Manual MKW2xDxxxRM.pdf. After the release of MCR20A Device,
* it was extended by the undocumented registers from the file MCR20reg.h.
*
* Portions of this file are derived from material that is
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
@ -92,6 +126,24 @@ enum mkw2xdrf_dregister {
MKW2XDM_SEQ_STATE = 0x24, /**< Sequence Manager State */
MKW2XDM_LQI_VALUE = 0x25, /**< Link Quality Indicator */
MKW2XDM_RSSI_CCA_CNT = 0x26, /**< RSSI CCA CNT */
MKW2XDM_ASM_CTRL1 = 0x28,
MKW2XDM_ASM_CTRL2 = 0x29,
MKW2XDM_ASM_DATA_0 = 0x2A,
MKW2XDM_ASM_DATA_1 = 0x2B,
MKW2XDM_ASM_DATA_2 = 0x2C,
MKW2XDM_ASM_DATA_3 = 0x2D,
MKW2XDM_ASM_DATA_4 = 0x2E,
MKW2XDM_ASM_DATA_5 = 0x2F,
MKW2XDM_ASM_DATA_6 = 0x30,
MKW2XDM_ASM_DATA_7 = 0x31,
MKW2XDM_ASM_DATA_8 = 0x32,
MKW2XDM_ASM_DATA_9 = 0x33,
MKW2XDM_ASM_DATA_A = 0x34,
MKW2XDM_ASM_DATA_B = 0x35,
MKW2XDM_ASM_DATA_C = 0x36,
MKW2XDM_ASM_DATA_D = 0x37,
MKW2XDM_ASM_DATA_E = 0x38,
MKW2XDM_ASM_DATA_F = 0x39,
MKW2XDM_OVERWRITE_VER = 0x3b, /**< Overwrite Version Number */
MKW2XDM_CLK_OUT_CTRL = 0x3c, /**< CLK_OUT Control */
MKW2XDM_PWR_MODES = 0x3d, /**< Power Modes */
@ -124,13 +176,16 @@ enum mkw2xdrf_dregister {
#define MKW2XDM_IRQSTS3_TMR3IRQ (1 << 2)
#define MKW2XDM_IRQSTS3_TMR2IRQ (1 << 1)
#define MKW2XDM_IRQSTS3_TMR1IRQ (1 << 0)
#define MKW2XDM_IRQSTS3_TMR_IRQ_MASK 0xfu
#define MKW2XDM_IRQSTS3_TMR_IRQ_SHIFT 0x0u
#define MKW2XDM_IRQSTS3_TMR_IRQ(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDM_IRQSTS3_TMR_IRQ_SHIFT))&MKW2XDM_IRQSTS3_TMR_IRQ_MASK)
#define MKW2XDM_PHY_CTRL1_TMRTRIGEN (1 << 7)
#define MKW2XDM_PHY_CTRL1_SLOTTED (1 << 6)
#define MKW2XDM_PHY_CTRL1_CCABFRTX (1 << 5)
#define MKW2XDM_PHY_CTRL1_RXACKRQD (1 << 4)
#define MKW2XDM_PHY_CTRL1_AUTOACK (1 << 3)
#define MKW2XDM_PHY_CTRL1_XCVSEQ_MASK 0x03u
#define MKW2XDM_PHY_CTRL1_XCVSEQ_MASK 0x07u
#define MKW2XDM_PHY_CTRL1_XCVSEQ(x) (((uint8_t)(((uint8_t)(x))<<0))&MKW2XDM_PHY_CTRL1_XCVSEQ_MASK)
#define MKW2XDM_PHY_CTRL2_CRC_MSK (1 << 7)
@ -227,6 +282,7 @@ enum mkw2xdrf_iregister {
MKW2XDMI_CCA_CTRL = 0x25, /**< CCA Control */
MKW2XDMI_CCA2_CORR_PEAKS = 0x26, /**< Clear Channel Assessment 2 Threshold Peak Compare */
MKW2XDMI_CCA2_THRESH = 0x27, /**< Clear Channel Assessment 2 Threshold */
MKW2XDMI_TMR_PRESCALE = 0x28, /**< Event Timer Time Base */
MKW2XDMI_GPIO_DATA = 0x2a, /**< GPIO Data */
MKW2XDMI_GPIO_DIR = 0x2b, /**< GPIO Direction Control */
MKW2XDMI_GPIO_PUL_EN = 0x2c, /**< GPIO Pullup Enable */
@ -234,8 +290,110 @@ enum mkw2xdrf_iregister {
MKW2XDMI_GPIO_DS = 0x2e, /**< GPIO Drive Strength */
MKW2XDMI_ANT_PAD_CTRL = 0x30, /**< Antenna Control */
MKW2XDMI_MISC_PAD_CTRL = 0x31, /**< Miscellaneous Pad Control */
MKW2XDMI_BSM_CTRL = 0x32,
MKW2XDMI__RNG = 0x34,
MKW2XDMI_RX_BYTE_COUNT = 0x35,
MKW2XDMI_RX_WTR_MARK = 0x36,
MKW2XDMI_SOFT_RESET = 0x37,
MKW2XDMI_TXDELAY = 0x38,
MKW2XDMI_ACKDELAY = 0x39,
MKW2XDMI_SEQ_MGR_CTRL = 0x3A,
MKW2XDMI_SEQ_MGR_STS = 0x3B,
MKW2XDMI_SEQ_T_STS = 0x3C,
MKW2XDMI_ABORT_STS = 0x3D,
MKW2XDMI_CCCA_BUSY_CNT = 0x3E,
MKW2XDMI_SRC_ADDR_CHECKSUM1 = 0x3F,
MKW2XDMI_SRC_ADDR_CHECKSUM2 = 0x40,
MKW2XDMI_SRC_TBL_VALID1 = 0x41,
MKW2XDMI_SRC_TBL_VALID2 = 0x42,
MKW2XDMI_FILTERFAIL_CODE1 = 0x43,
MKW2XDMI_FILTERFAIL_CODE2 = 0x44,
MKW2XDMI_SLOT_PRELOAD = 0x45,
MKW2XDMI_CORR_VT = 0x47,
MKW2XDMI_SYNC_CTRL = 0x48,
MKW2XDMI_PN_LSB_0 = 0x49,
MKW2XDMI_PN_LSB_1 = 0x4A,
MKW2XDMI_PN_MSB_0 = 0x4B,
MKW2XDMI_PN_MSB_1 = 0x4C,
MKW2XDMI_CORR_NVAL = 0x4D,
MKW2XDMI_TX_MODE_CTRL = 0x4E,
MKW2XDMI_SNF_THR = 0x4F,
MKW2XDMI_FAD_THR = 0x50,
MKW2XDMI_ANT_AGC_CTRL = 0x51, /**< Antenna AGC and FAD Control */
MKW2XDMI_AGC_THR1 = 0x52,
MKW2XDMI_AGC_THR2 = 0x53,
MKW2XDMI_AGC_HYS = 0x54,
MKW2XDMI_AFC = 0x55,
MKW2XDMI_LPPS_CTRL = 0x56, /**< LPPS_CTRL */
MKW2XDMI_PHY_STS = 0x58,
MKW2XDMI_RX_MAX_CORR = 0x59,
MKW2XDMI_RX_MAX_PREAMBLE = 0x5A,
MKW2XDMI_RSSI = 0x5B,
MKW2XDMI_PLL_DIG_CTRL = 0x5E,
MKW2XDMI_VCO_CAL = 0x5F,
MKW2XDMI_VCO_BEST_DIFF = 0x60,
MKW2XDMI_VCO_BIAS = 0x61,
MKW2XDMI_KMOD_CTRL = 0x62,
MKW2XDMI_KMOD_CAL = 0x63,
MKW2XDMI_PA_CAL = 0x64,
MKW2XDMI_PA_PWRCAL = 0x65,
MKW2XDMI_ATT_RSSI1 = 0x66,
MKW2XDMI_ATT_RSSI2 = 0x67,
MKW2XDMI_RSSI_OFFSET = 0x68,
MKW2XDMI_RSSI_SLOPE = 0x69,
MKW2XDMI_RSSI_CAL1 = 0x6A,
MKW2XDMI_RSSI_CAL2 = 0x6B,
MKW2XDMI_XTAL_CTRL = 0x6E,
MKW2XDMI_XTAL_COMP_MIN = 0x6F,
MKW2XDMI_XTAL_COMP_MAX = 0x70,
MKW2XDMI_XTAL_GM = 0x71,
MKW2XDMI_LNA_TUNE = 0x74,
MKW2XDMI_LNA_AGCGAIN = 0x75,
MKW2XDMI_CHF_PMA_GAIN = 0x78,
MKW2XDMI_CHF_IBUF = 0x79,
MKW2XDMI_CHF_QBUF = 0x7A,
MKW2XDMI_CHF_IRIN = 0x7B,
MKW2XDMI_CHF_QRIN = 0x7C,
MKW2XDMI_CHF_IL = 0x7D,
MKW2XDMI_CHF_QL = 0x7E,
MKW2XDMI_CHF_CC1 = 0x7F,
MKW2XDMI_CHF_CCL = 0x80,
MKW2XDMI_CHF_CC2 = 0x81,
MKW2XDMI_CHF_IROUT = 0x82,
MKW2XDMI_CHF_QROUT = 0x83,
MKW2XDMI_RSSI_CTRL = 0x86,
MKW2XDMI_PA_BIAS = 0x89,
MKW2XDMI_PA_TUNING = 0x8A,
MKW2XDMI_PMC_HP_TRIM = 0x8D,
MKW2XDMI_VREGA_TRIM = 0x8E,
MKW2XDMI_VCO_CTRL1 = 0x91,
MKW2XDMI_VCO_CTRL2 = 0x92,
MKW2XDMI_ANA_SPARE_OUT1 = 0x95,
MKW2XDMI_ANA_SPARE_OUT2 = 0x96,
MKW2XDMI_ANA_SPARE_IN = 0x97,
MKW2XDMI_MISCELLANEOUS = 0x98,
MKW2XDMI_SEQ_MGR_OVRD0 = 0x9A,
MKW2XDMI_SEQ_MGR_OVRD1 = 0x9B,
MKW2XDMI_SEQ_MGR_OVRD2 = 0x9C,
MKW2XDMI_SEQ_MGR_OVRD3 = 0x9D,
MKW2XDMI_SEQ_MGR_OVRD4 = 0x9E,
MKW2XDMI_SEQ_MGR_OVRD5 = 0x9F,
MKW2XDMI_SEQ_MGR_OVRD6 = 0xA0,
MKW2XDMI_SEQ_MGR_OVRD7 = 0xA1,
MKW2XDMI_TESTMODE_CTRL = 0xA3,
MKW2XDMI_DTM_CTRL1= 0xA4,
MKW2XDMI_DTM_CTRL2= 0xA5,
MKW2XDMI_ATM_CTRL1= 0xA6,
MKW2XDMI_ATM_CTRL2= 0xA7,
MKW2XDMI_ATM_CTRL3= 0xA8,
MKW2XDMI_LIM_FE_TEST_CTRL = 0xAA,
MKW2XDMI_CHF_TEST_CTRL = 0xAB,
MKW2XDMI_VCO_TEST_CTRL = 0xAC,
MKW2XDMI_PLL_TEST_CTRL = 0xAD,
MKW2XDMI_PA_TEST_CTRL = 0xAE,
MKW2XDMI_PMC_TEST_CTRL = 0xAF,
MKW2XDMI_SCAN_DTM_PROTECT_1 = 0xFE,
MKW2XDMI_SCAN_DTM_PROTECT_0 = 0xFF,
};
#define MKW2XDMI_PART_ID_MANUF_ID_MASK 0x60u
@ -279,6 +437,10 @@ enum mkw2xdrf_iregister {
#define MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_SHIFT))&MKW2XDMI_CCA2_CORR_PEAKS_CCA2_MIN_NUM_CORR_TH_MASK)
#define MKW2XDMI_CCA2_CORR_PEAKS_CCA2_NUM_CORR_PEAKS_MASK 0x0Fu
#define MKW2XDMI_TMR_PRESCALE_MASK 0x7u
#define MKW2XDMI_TMR_PRESCALE_SHIFT 0x0u
#define MKW2XDMI_TMR_PRESCALE_SET(x) (((uint8_t)(((uint8_t)(x))<<MKW2XDMI_TMR_PRESCALE_SHIFT))&MKW2XDMI_TMR_PRESCALE_MASK)
#define MKW2XDMI_GPIO_DATA8 (1 << 7)
#define MKW2XDMI_GPIO_DATA7 (1 << 6)
#define MKW2XDMI_GPIO_DATA6 (1 << 5)
@ -348,9 +510,59 @@ enum mkw2xdrf_iregister {
#define MKW2XDMI_LPPS_CTRL_LPPS_EN (1 << 0)
#define MKW2XDMI_SOFT_RESET_SOG_RST (1 << 7)
#define MKW2XDMI_SOFT_RESET_REGS_RST (1 << 4)
#define MKW2XDMI_SOFT_RESET_PLL_RST (1 << 3)
#define MKW2XDMI_SOFT_RESET_TX_RST (1 << 2)
#define MKW2XDMI_SOFT_RESET_RX_RST (1 << 1)
#define MKW2XDMI_SOFT_RESET_SEQ_MGR_RST (1 << 0)
#define MKW2XDMI_SEQ_MGR_CTRL_SEQ_STATE_CTRL_MASK 0x3
#define MKW2XDMI_SEQ_MGR_CTRL_SEQ_STATE_CTRL_SHIFT 6
#define MKW2XDMI_SEQ_MGR_CTRL_NO_RX_RECYCLE (1 << 5)
#define MKW2XDMI_SEQ_MGR_CTRL_LATCH_PREAMBLE (1 << 4)
#define MKW2XDMI_SEQ_MGR_CTRL_EVENT_TMR_DO_NOT_LATCH (1 << 3)
#define MKW2XDMI_SEQ_MGR_CTRL_CLR_NEW_SEQ_INHIBIT (1 << 2)
#define MKW2XDMI_SEQ_MGR_CTRL_PSM_LOCK_DIS (1 << 1)
#define MKW2XDMI_SEQ_MGR_CTRL_PLL_ABORT_OVRD (1 << 0)
#define MKW2XDMI_SEQ_MGR_STS_TMR2_SEQ_TRIG_ARMED (1 << 7)
#define MKW2XDMI_SEQ_MGR_STS_RX_MODE (1 << 6)
#define MKW2XDMI_SEQ_MGR_STS_RX_TIMEOUT_PENDING (1 << 5)
#define MKW2XDMI_SEQ_MGR_STS_NEW_SEQ_INHIBIT (1 << 4)
#define MKW2XDMI_SEQ_MGR_STS_SEQ_IDLE (1 << 3)
#define MKW2XDMI_SEQ_MGR_STS_XCVSEQ_ACTUAL_MASK 7
#define MKW2XDMI_ABORT_STS_PLL_ABORTED (1 << 2)
#define MKW2XDMI_ABORT_STS_TC3_ABORTED (1 << 1)
#define MKW2XDMI_ABORT_STS_SW_ABORTED (1 << 0)
#define MKW2XDMI_TESTMODE_CTRL_HOT_ANT (1 << 4)
#define MKW2XDMI_TESTMODE_CTRL_IDEAL_RSSI_EN (1 << 3)
#define MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN (1 << 2)
#define MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN (1 << 1)
#define MKW2XDMI_TESTMODE_CTRL_FPGA_EN (1 << 0)
#define MKW2XDMI_DTM_CTRL1_ATM_LOCKED (1 << 7)
#define MKW2XDMI_DTM_CTRL1_DTM_EN (1 << 6)
#define MKW2XDMI_DTM_CTRL1_PAGE5 (1 << 5)
#define MKW2XDMI_DTM_CTRL1_PAGE4 (1 << 4)
#define MKW2XDMI_DTM_CTRL1_PAGE3 (1 << 3)
#define MKW2XDMI_DTM_CTRL1_PAGE2 (1 << 2)
#define MKW2XDMI_DTM_CTRL1_PAGE1 (1 << 1)
#define MKW2XDMI_DTM_CTRL1_PAGE0 (1 << 0)
#define MKW2XDMI_TX_MODE_CTRL_TX_INV (1 << 4)
#define MKW2XDMI_TX_MODE_CTRL_BT_EN (1 << 3)
#define MKW2XDMI_TX_MODE_CTRL_DTS2 (1 << 2)
#define MKW2XDMI_TX_MODE_CTRL_DTS1 (1 << 1)
#define MKW2XDMI_TX_MODE_CTRL_DTS0 (1 << 0)
#define MKW2XDMI_TX_MODE_CTRL_DTS_MASK 7
#ifdef __cplusplus
}
#endif
#endif
#endif /* MKW2XD_MODEM_REG_H */
/** @} */

View File

@ -14,6 +14,7 @@
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef KW2XRF_SPI_H
#define KW2XRF_SPI_H
@ -29,89 +30,115 @@ extern "C" {
/**
* @brief SPI interface initialization
* @param[in] spi SPI bus the device is connected to
* @param[in] spi_clk SPI clock speed to use
* @param[in] cs_pin GPIO pin connected to chip select
* @param[in] dev device descriptor
*
* @return 0 on success
* @return -1 on error
*/
int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin);
int kw2xrf_spi_init(kw2xrf_t *dev);
/**
* @brief Writes a byte to the kw2xrf register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to write.
* @param[in] value The value to write in the register.
*/
void kw2xrf_write_dreg(uint8_t addr, uint8_t value);
void kw2xrf_write_dreg(kw2xrf_t *dev, uint8_t addr, uint8_t value);
/**
* @brief Reads a byte from the kw2xrf register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to read.
* @return Value of the register.
*/
uint8_t kw2xrf_read_dreg(uint8_t addr);
uint8_t kw2xrf_read_dreg(kw2xrf_t *dev, uint8_t addr);
/**
* @brief Writes to a byte from the kw2xrf indirect register.
*
* @param[in] addr Address of the register to write into.
* @param[in] value Value that shall be written.
*/
void kw2xrf_write_ireg(uint8_t addr, uint8_t value);
/**
* @brief Reads a byte from the kw2xrf indirect register.
*
* @param[in] addr Address of the register to read.
*
* @return value in the register
*/
uint8_t kw2xrf_read_ireg(uint8_t addr);
/**
* @brief Writes to kw2xrf indirect registers.
* @brief Writes to kw2xrf direct registers.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to write into.
* @param[in] buf Value that shall be written.
* @param[in] length Length of the register.
*/
void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length);
void kw2xrf_write_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length);
/**
* @brief Reads a byte from the kw2xrf indirect register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to read.
* @param[in] buf Buffer, where the content of the reg shall be written to.
* @param[in] length Length of the register.
*/
void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length);
void kw2xrf_read_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length);
/**
* @brief Writes to a byte from the kw2xrf indirect register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to write into.
* @param[in] value Value that shall be written.
*/
void kw2xrf_write_ireg(kw2xrf_t *dev, uint8_t addr, uint8_t value);
/**
* @brief Reads a byte from the kw2xrf indirect register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to read.
*
* @return value in the register
*/
uint8_t kw2xrf_read_ireg(kw2xrf_t *dev, uint8_t addr);
/**
* @brief Writes to kw2xrf indirect registers.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to write into.
* @param[in] buf Value that shall be written.
* @param[in] length Length of the register.
*/
void kw2xrf_write_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length);
/**
* @brief Reads a byte from the kw2xrf indirect register.
*
* @param[in] dev device descriptor
* @param[in] addr Address of the register to read.
* @param[in] buf Buffer, where the content of the reg shall be written to.
* @param[in] length Length of the register.
*/
void kw2xrf_read_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length);
/**
* @brief Writes multiple bytes to the kw2xrf fifo.
*
* @param[in] dev device descriptor
* @param[in] data A buffer with the value to write to the fifo.
* @param[in] data_length The count of bytes which should be written.
*
* @return number of bytes written.
*/
void kw2xrf_write_fifo(uint8_t *data, uint8_t data_length);
void kw2xrf_write_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t data_length);
/**
* @brief Reads multiple bytes from the kw2xrf fifo.
*
* @param[in] dev device descriptor
* @param[out] data A buffer to store the value of the fifo.
* @param[in] data_length The count of bytes which should be read.
*
* @return number of bytes read.
*/
void kw2xrf_read_fifo(uint8_t *data, uint8_t data_length);
void kw2xrf_read_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t data_length);
#ifdef __cplusplus
}
#endif
#endif
#endif /* KW2XRF_SPI_H */
/** @} */

View File

@ -0,0 +1,52 @@
/*
* 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 tests_kw2xrf
* @{
*
* @file
* @brief Testing interfaces for kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#ifndef KW2XRF_TM_H
#define KW2XRF_TM_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef KW2XRF_TESTMODE
#include "kw2xrf.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_getset.h"
#include "net/netopt.h"
enum mkw2xrf_testmode {
KW2XRF_TM_CTX_PREAMBLE = NETOPT_RF_TESTMODE_CTX_PRBS9 + 1,
KW2XRF_TM_CTX_2MHZ,
KW2XRF_TM_CTX_200KHZ,
KW2XRF_TM_CTX_1MBPS_PRBS9,
KW2XRF_TM_CTX_EXT,
KW2XRF_TM_CTX_NM0,
KW2XRF_TM_CTX_NM1,
};
int kw2xrf_set_test_mode(kw2xrf_t *dev, uint8_t mode);
#endif
#ifdef __cplusplus
}
#endif
#endif /* KW2XRF_TM_H */
/** @} */

View File

@ -0,0 +1,314 @@
/*!
* Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved.
*
* \file MCR20Overwrites.h
* Description: Overwrites header file for MCR20 Register values
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OVERWRITES_H_
#define OVERWRITES_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct overwrites_tag {
char address;
char data;
} overwrites_t;
/*****************************************************************************************************************/
// This file is created exclusively for use with the transceiver 2.0 silicon
// and is provided for the world to use. It contains a list of all
// known overwrite values. Overwrite values are non-default register
// values that configure the transceiver device to a more optimally performing
// posture. It is expected that low level software (i.e. PHY) will
// consume this file as a #include, and transfer the contents to the
// the indicated addresses in the transceiver's memory space. This file has
// at least one required entry, that being its own version current version
// number, to be stored at transceiver's location 0x3B the
// OVERWRITES_VERSION_NUMBER register. The RAM register is provided in
// the transceiver address space to assist in future debug efforts. The
// analyst may read this location (once device has been booted with
// mysterious software) and have a good indication of what register
// overwrites were performed (with all versions of the overwrites.h file
// being archived forever at the Compass location shown above.
//
// The transceiver has an indirect register (IAR) space. Write access to this space
// requires 3 or more writes:
// 1st) the first write is an index value to the indirect (write Bit7=0, register access Bit 6=0) + 0x3E
// 2nd) IAR Register #0x00 - 0xFF.
// 3rd) The data to write
// nth) Burst mode additional data if required.
//
// Write access to direct space requires only a single address, data pair.
overwrites_t const overwrites_direct[] ={
{0x3B, 0x0C}, //version 0C: new value for ACKDELAY targeting 198us (23 May, 2013, Larry Roshak)
{0x23, 0x17} //PA_PWR new default Power Step is "23"
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration
{0x52, 0x55}, //AGC_THR1 RSSI tune up
{0x53, 0x2D}, //AGC_THR2 RSSI tune up
{0x66, 0x5F}, //ATT_RSSI1 tune up
{0x67, 0x8F}, //ATT_RSSI2 tune up
{0x68, 0x61}, //RSSI_OFFSET
{0x78, 0x03}, //CHF_PMAGAIN
{0x22, 0x50}, //CCA1_THRESH
{0x4D, 0x13}, //CORR_NVAL moved from 0x14 to 0x13 for 0.5 dB improved Rx Sensitivity
{0x39, 0x3D} //ACKDELAY new value targeting a delay of 198us (23 May, 2013, Larry Roshak)
};
/* begin of deprecated versions
==VERSION 1==
(version 1 is empty)
==VERSION 2==
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02} //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
};
==VERSION 3==
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3
{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
};
==VERSION 4==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x04} //version 04 is the current version: update PA_COILTUNING default
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1: override VCOALC_REF_TX to 3
{0x92, 0x07} //VCO_CTRL2: override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71} //PA_TUNING: override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
};
==VERSION 5==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x05} //version 05: updates Channel Filter Register set (21 Dec 2012, on behalf of S. Soca)
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
};
==VERSION 6==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x06} //version 06: disable PA calibration
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07} //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71} //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F} //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F} //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24} //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24} //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24} //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24} //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24} //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24} //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32} //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D} //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D} //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28} //PA_CAL_DIS=1 Disabled PA calibration
};
==VERSION 7==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x07} //version 07: updated registers for ED/RSSI
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration
{0x52, 0x73}, //AGC_THR1 RSSI tune up
{0x53, 0x2D}, //AGC_THR2 RSSI tune up
{0x66, 0x5F}, //ATT_RSSI1 tune up
{0x67, 0x8F}, //ATT_RSSI2 tune up
{0x68, 0x60}, //RSSI_OFFSET
{0x69, 0x65} //RSSI_SLOPE
};
==VERSION 8==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x08} //version 08: updated registers for ED/RSSI
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration
{0x52, 0x73}, //AGC_THR1 RSSI tune up
{0x53, 0x2D}, //AGC_THR2 RSSI tune up
{0x66, 0x5F}, //ATT_RSSI1 tune up
{0x67, 0x8F}, //ATT_RSSI2 tune up
{0x69, 0x65} //RSSI_SLOPE
{0x68, 0x61}, //RSSI_OFFSET
{0x78, 0x03} //CHF_PMAGAIN
};
==VERSION 9==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x09} //version 09: updated registers for ED/RSSI and PowerStep
{0x23, 0x17} //PA_PWR new default value
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration
{0x52, 0x55}, //AGC_THR1 RSSI tune up
{0x53, 0x2D}, //AGC_THR2 RSSI tune up
{0x66, 0x5F}, //ATT_RSSI1 tune up
{0x67, 0x8F}, //ATT_RSSI2 tune up
{0x68, 0x61}, //RSSI_OFFSET
{0x78, 0x03} //CHF_PMAGAIN
};
==VERSION A==
overwrites_t const overwrites_direct[] ={
{0x3B, 0x0A} //version 0A: updated registers for CCA
{0x23, 0x17} //PA_PWR new default Power Step is "23"
};
overwrites_t const overwrites_indirect[] ={
{0x31, 0x02}, //clear MISO_HIZ_EN (for single SPI master/slave pair) and SPI_PUL_EN (minimize HIB currents)
{0x91, 0xB3}, //VCO_CTRL1 override VCOALC_REF_TX to 3
{0x92, 0x07}, //VCO_CTRL2 override VCOALC_REF_RX to 3, keep VCO_BUF_BOOST = 1
{0x8A, 0x71}, //PA_TUNING override PA_COILTUNING to 001 (27 Nov 2012, D. Brown, on behalf of S. Eid)
{0x79, 0x2F}, //CHF_IBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7A, 0x2F}, //CHF_QBUF Adjust the gm-C filter gain (+/- 6dB) (21 Dec, 2012, on behalf of S. Soca)
{0x7B, 0x24}, //CHF_IRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7C, 0x24}, //CHF_QRIN Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7D, 0x24}, //CHF_IL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7E, 0x24}, //CHF_QL Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x7F, 0x32}, //CHF_CC1 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x80, 0x1D}, //CHF_CCL Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x81, 0x2D}, //CHF_CC2 Adjust the filter center frequency (+/- 1MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x82, 0x24}, //CHF_IROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x83, 0x24}, //CHF_QROUT Adjust the filter bandwidth (+/- 0.5MHz) (21 Dec, 2012, on behalf of S. Soca)
{0x64, 0x28}, //PA_CAL_DIS=1 Disabled PA calibration
{0x52, 0x55}, //AGC_THR1 RSSI tune up
{0x53, 0x2D}, //AGC_THR2 RSSI tune up
{0x66, 0x5F}, //ATT_RSSI1 tune up
{0x67, 0x8F}, //ATT_RSSI2 tune up
{0x68, 0x61}, //RSSI_OFFSET
{0x78, 0x03} //CHF_PMAGAIN
{0x22, 0x50} //CCA1_THRESH
};
end of deprecated versions */
#ifdef __cplusplus
}
#endif
#endif //OVERWRITES_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,521 @@
/*
* 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_kw2xrf
* @{
* @file
* @brief get/set functionality of kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
* @author Jonas Remmert <j.remmert@phytec.de>
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Sebastian Meiling <s@mlng.net>
* @}
*/
#include "log.h"
#include "kw2xrf.h"
#include "kw2xrf_spi.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_getset.h"
#include "kw2xrf_intern.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define KW2XRF_LQI_HW_MAX 230 /**< LQI Saturation Level */
/* Modem_PA_PWR Register (PA Power Control) has a valid range from 3-31 */
#define KW2XRF_PA_RANGE_MAX 31 /**< Maximum value of PA Power Control Register */
#define KW2XRF_PA_RANGE_MIN 3 /**< Minimum value of PA Power Control Register */
#define KW2XRF_NUM_CHANNEL (KW2XRF_MAX_CHANNEL - KW2XRF_MIN_CHANNEL + 1)
/* PLL integer and fractional lookup tables
*
* Fc = 2405 + 5(k - 11) , k = 11,12,...,26
*
* Equation for PLL frequency, MKW2xD Reference Manual, p.255 :
* F = ((PLL_INT0 + 64) + (PLL_FRAC0/65536))32MHz
*
*/
static const uint8_t pll_int_lt[16] = {
11, 11, 11, 11,
11, 11, 12, 12,
12, 12, 12, 12,
13, 13, 13, 13
};
static const uint16_t pll_frac_lt[16] = {
10240, 20480, 30720, 40960,
51200, 61440, 6144, 16384,
26624, 36864, 47104, 57344,
2048, 12288, 22528, 32768
};
static const uint8_t pow_lt[44] = {
3, 4, 4, 5,
6, 6, 7, 7,
8, 9, 9, 10,
11, 11, 12, 13,
13, 14, 14, 15,
16, 16, 17, 18,
18, 19, 20, 20,
21, 21, 22, 23,
23, 24, 25, 25,
26, 27, 27, 28,
28, 29, 30, 31
};
void kw2xrf_set_tx_power(kw2xrf_t *dev, int16_t txpower)
{
if (txpower > KW2XDRF_OUTPUT_POWER_MAX) {
txpower = KW2XDRF_OUTPUT_POWER_MAX;
}
if (txpower < KW2XDRF_OUTPUT_POWER_MIN) {
txpower = KW2XDRF_OUTPUT_POWER_MIN;
}
uint8_t level = pow_lt[txpower - KW2XDRF_OUTPUT_POWER_MIN];
kw2xrf_write_dreg(dev, MKW2XDM_PA_PWR, MKW2XDM_PA_PWR(level));
LOG_DEBUG("[kw2xrf] set txpower to: %d\n", txpower);
dev->tx_power = txpower;
}
uint16_t kw2xrf_get_txpower(kw2xrf_t *dev)
{
return dev->tx_power;
}
uint8_t kw2xrf_get_channel(kw2xrf_t *dev)
{
uint8_t pll_int = kw2xrf_read_dreg(dev, MKW2XDM_PLL_INT0);
uint16_t pll_frac = kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_LSB);
pll_frac |= ((uint16_t)kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_MSB) << 8);
for (unsigned i = 0; i < KW2XRF_NUM_CHANNEL; i++) {
if ((pll_frac_lt[i] == pll_frac) && (pll_int_lt[i] == pll_int)) {
return i + 11;
}
}
return 0;
}
static int kw2xrf_get_sequence(kw2xrf_t *dev)
{
int reg = 0;
reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1);
reg &= MKW2XDM_PHY_CTRL1_XCVSEQ_MASK;
return reg;
}
int kw2xrf_set_channel(kw2xrf_t *dev, uint8_t channel)
{
/* Save old sequence to restore this state later */
uint8_t old_seq = kw2xrf_get_sequence(dev);
if (channel < KW2XRF_MIN_CHANNEL || channel > KW2XRF_MAX_CHANNEL) {
LOG_ERROR("[kw2xrf] Invalid channel %u\n", channel);
return -1;
}
if (old_seq) {
kw2xrf_abort_sequence(dev);
}
uint8_t tmp = channel - 11;
kw2xrf_write_dreg(dev, MKW2XDM_PLL_INT0, MKW2XDM_PLL_INT0_VAL(pll_int_lt[tmp]));
kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_LSB, (uint8_t)pll_frac_lt[tmp]);
kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_MSB, (uint8_t)(pll_frac_lt[tmp] >> 8));
dev->netdev.chan = channel;
if (old_seq) {
kw2xrf_set_sequence(dev, old_seq);
}
LOG_DEBUG("[kw2xrf] set channel to %u\n", channel);
return 0;
}
void kw2xrf_abort_sequence(kw2xrf_t *dev)
{
uint8_t regs[MKW2XDM_PHY_CTRL4 + 1];
kw2xrf_mask_irq_b(dev);
kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, regs, (MKW2XDM_PHY_CTRL4 + 1));
if ((regs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) != XCVSEQ_IDLE) {
/* abort any ongoing sequence */
regs[MKW2XDM_PHY_CTRL1] &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK);
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, regs[MKW2XDM_PHY_CTRL1]);
}
uint8_t state;
do {
state = kw2xrf_read_dreg(dev, MKW2XDM_SEQ_STATE);
DEBUG("[kw2xrf] abort SEQ_STATE: %x\n", state);
} while ((state & 0x1F) != 0);
/* clear all IRQ bits */
regs[MKW2XDM_IRQSTS1] = 0x7f;
regs[MKW2XDM_IRQSTS2] = 0x03;
regs[MKW2XDM_IRQSTS3] |= 0x0f;
kw2xrf_write_dregs(dev, MKW2XDM_IRQSTS1, regs, 3);
kw2xrf_enable_irq_b(dev);
}
/*
* Simplified version for irq handling where the state of
* the sequenz manager is known.
*/
void kw2xrf_set_idle_sequence(kw2xrf_t *dev)
{
kw2xrf_mask_irq_b(dev);
uint8_t reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1);
/* reset sequenz manager */
reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK);
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg);
if (dev->pending_tx) {
DEBUG("[kw2xrf] pending tx, cannot set idle sequenz\n");
return;
}
/* start new sequenz */
reg |= MKW2XDM_PHY_CTRL1_XCVSEQ(dev->idle_state);
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg);
switch (dev->idle_state) {
case XCVSEQ_IDLE:
/* for inexplicable reasons, the receive mode is also idle mode */
case XCVSEQ_RECEIVE:
dev->state = NETOPT_STATE_IDLE;
break;
case XCVSEQ_CONTINUOUS_CCA:
case XCVSEQ_CCA:
dev->state = NETOPT_STATE_RX;
break;
case XCVSEQ_TRANSMIT:
case XCVSEQ_TX_RX:
dev->state = NETOPT_STATE_TX;
break;
default:
dev->state = NETOPT_STATE_IDLE;
}
kw2xrf_enable_irq_b(dev);
}
void kw2xrf_set_sequence(kw2xrf_t *dev, kw2xrf_physeq_t seq)
{
uint8_t reg = 0;
kw2xrf_abort_sequence(dev);
switch (seq) {
case XCVSEQ_IDLE:
/* for inexplicable reasons, the receive mode is also idle mode */
case XCVSEQ_RECEIVE:
dev->state = NETOPT_STATE_IDLE;
break;
case XCVSEQ_CONTINUOUS_CCA:
case XCVSEQ_CCA:
dev->state = NETOPT_STATE_RX;
break;
case XCVSEQ_TRANSMIT:
case XCVSEQ_TX_RX:
dev->state = NETOPT_STATE_TX;
break;
default:
DEBUG("[kw2xrf] undefined state assigned to phy\n");
dev->state = NETOPT_STATE_IDLE;
}
DEBUG("[kw2xrf] set sequence to %i\n", seq);
reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1);
reg &= ~(MKW2XDM_PHY_CTRL1_XCVSEQ_MASK);
reg |= MKW2XDM_PHY_CTRL1_XCVSEQ(seq);
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL1, reg);
}
void kw2xrf_set_pan(kw2xrf_t *dev, uint16_t pan)
{
dev->netdev.pan = pan;
uint8_t val_ar[2];
val_ar[1] = (pan >> 8);
val_ar[0] = (uint8_t)pan;
kw2xrf_write_iregs(dev, MKW2XDMI_MACPANID0_LSB, val_ar, 2);
LOG_DEBUG("[kw2xrf] set pan to: 0x%x\n", pan);
dev->netdev.pan = pan;
}
void kw2xrf_set_addr_short(kw2xrf_t *dev, uint16_t addr)
{
uint8_t val_ar[2];
val_ar[0] = (addr >> 8);
val_ar[1] = (uint8_t)addr;
dev->netdev.short_addr[0] = val_ar[1];
dev->netdev.short_addr[1] = val_ar[0];
#ifdef MODULE_SIXLOWPAN
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
* 0 for unicast addresses */
dev->netdev.short_addr[1] &= 0x7F;
#endif
kw2xrf_write_iregs(dev, MKW2XDMI_MACSHORTADDRS0_LSB, val_ar,
IEEE802154_SHORT_ADDRESS_LEN);
}
void kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr)
{
uint64_t tmp;
uint8_t *ap = (uint8_t *)(&tmp);
for (unsigned i = 0; i < IEEE802154_LONG_ADDRESS_LEN; i++) {
dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8));
ap[i] = (addr >> ((IEEE802154_LONG_ADDRESS_LEN - 1 - i) * 8));
}
kw2xrf_write_iregs(dev, MKW2XDMI_MACLONGADDRS0_0, ap,
IEEE802154_LONG_ADDRESS_LEN);
}
uint16_t kw2xrf_get_addr_short(kw2xrf_t *dev)
{
return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1];
}
uint64_t kw2xrf_get_addr_long(kw2xrf_t *dev)
{
uint64_t addr;
uint8_t *ap = (uint8_t *)(&addr);
kw2xrf_read_iregs(dev, MKW2XDMI_MACLONGADDRS0_0, ap,
IEEE802154_LONG_ADDRESS_LEN);
return addr;
}
int8_t kw2xrf_get_cca_threshold(kw2xrf_t *dev)
{
uint8_t tmp;
kw2xrf_read_iregs(dev, MKW2XDMI_CCA1_THRESH, &tmp, 1);
/* KW2x register value represents absolute value in dBm
* default value: -75 dBm
*/
return (-tmp);
}
void kw2xrf_set_cca_threshold(kw2xrf_t *dev, int8_t value)
{
/* normalize to absolute value */
if (value < 0) {
value = -value;
}
kw2xrf_write_iregs(dev, MKW2XDMI_CCA1_THRESH, (uint8_t*)&value, 1);
}
void kw2xrf_set_cca_mode(kw2xrf_t *dev, uint8_t mode)
{
uint8_t tmp;
tmp = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL4);
tmp &= ~MKW2XDM_PHY_CTRL4_CCATYPE_MASK;
tmp |= MKW2XDM_PHY_CTRL4_CCATYPE(mode);
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL4, tmp);
}
uint8_t kw2xrf_get_cca_mode(kw2xrf_t *dev)
{
uint8_t tmp;
tmp = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL4);
return (tmp & MKW2XDM_PHY_CTRL4_CCATYPE_MASK) >> MKW2XDM_PHY_CTRL4_CCATYPE_SHIFT;
}
uint32_t kw2xrf_get_rssi(uint32_t value)
{
/* Get rssi (Received Signal Strength Indicator, unit is dBm)
* from lqi (Link Quality Indicator) value.
* There are two different equations for RSSI:
* RF = (LQI 286.6) / 2.69333 (MKW2xD Reference Manual)
* RF = (LQI 295.4) / 2.84 (MCR20A Reference Manual)
* The last appears more to match the graphic (Figure 3-10).
* Since RSSI value is always positive and we want to
* avoid the floating point computation:
* -RF * 65536 = (LQI / 2.84 - 295.4 / 2.84) * 65536
* RF * 65536 = (295.4 * 65536 / 2.84) - (LQI * 65536 / 2.84)
*/
uint32_t a = (uint32_t)(295.4 * 65536 / 2.84);
uint32_t b = (uint32_t)(65536 / 2.84);
return (a - (b * value)) >> 16;
}
void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state)
{
DEBUG("[kw2xrf] set option %i to %i\n", option, state);
/* set option field */
if (state) {
dev->netdev.flags |= option;
/* trigger option specific actions */
switch (option) {
case KW2XRF_OPT_AUTOCCA:
LOG_DEBUG("[kw2xrf] opt: enabling CCA before TX mode\n");
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_CCABFRTX);
break;
case KW2XRF_OPT_PROMISCUOUS:
LOG_DEBUG("[kw2xrf] opt: enabling PROMISCUOUS mode\n");
/* disable auto ACKs in promiscuous mode */
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_AUTOACK | MKW2XDM_PHY_CTRL1_RXACKRQD);
/* enable promiscuous mode */
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4,
MKW2XDM_PHY_CTRL4_PROMISCUOUS);
break;
case KW2XRF_OPT_AUTOACK:
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_AUTOACK);
break;
case KW2XRF_OPT_ACK_REQ:
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_RXACKRQD);
break;
case KW2XRF_OPT_TELL_RX_START:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_RX_WMRK_MSK);
break;
case KW2XRF_OPT_TELL_RX_END:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_RXMSK);
break;
case KW2XRF_OPT_TELL_TX_END:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_TXMSK);
break;
case KW2XRF_OPT_TELL_TX_START:
default:
/* do nothing */
break;
}
}
else {
dev->netdev.flags &= ~(option);
/* trigger option specific actions */
switch (option) {
case KW2XRF_OPT_AUTOCCA:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_CCABFRTX);
break;
case KW2XRF_OPT_PROMISCUOUS:
/* disable promiscuous mode */
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4,
MKW2XDM_PHY_CTRL4_PROMISCUOUS);
/* re-enable AUTOACK only if the option is set */
if (dev->netdev.flags & KW2XRF_OPT_AUTOACK) {
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_AUTOACK);
}
if (dev->netdev.flags & KW2XRF_OPT_ACK_REQ) {
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_RXACKRQD);
}
break;
case KW2XRF_OPT_AUTOACK:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_AUTOACK);
break;
case KW2XRF_OPT_ACK_REQ:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_RXACKRQD);
break;
case KW2XRF_OPT_TELL_RX_START:
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_RX_WMRK_MSK);
break;
case KW2XRF_OPT_TELL_RX_END:
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_RXMSK);
break;
case KW2XRF_OPT_TELL_TX_END:
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL2,
MKW2XDM_PHY_CTRL2_TXMSK);
break;
case KW2XRF_OPT_TELL_TX_START:
default:
/* do nothing */
break;
}
}
}
netopt_state_t kw2xrf_get_status(kw2xrf_t *dev)
{
uint8_t reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1);
switch (reg & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) {
case XCVSEQ_RECEIVE:
return NETOPT_STATE_RX;
case XCVSEQ_TRANSMIT:
return NETOPT_STATE_TX;
case XCVSEQ_CCA:
return NETOPT_STATE_RX;
case XCVSEQ_TX_RX:
return NETOPT_STATE_TX;
case XCVSEQ_CONTINUOUS_CCA:
return NETOPT_STATE_RX;
case XCVSEQ_IDLE:
return NETOPT_STATE_IDLE;
default:
break;
}
return NETOPT_STATE_IDLE;
}
int kw2xrf_cca(kw2xrf_t *dev)
{
/* TODO: add Standalone CCA here */
kw2xrf_seq_timeout_on(dev, 0x3ffff);
kw2xrf_set_sequence(dev, XCVSEQ_CONTINUOUS_CCA);
return 0;
}
void kw2xrf_set_rx_watermark(kw2xrf_t *dev, uint8_t value)
{
kw2xrf_write_iregs(dev, MKW2XDMI_RX_WTR_MARK, &value, 1);
}

View File

@ -0,0 +1,222 @@
/*
* 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_kw2xrf
* @{
* @file
* @brief Internal function of kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
* @}
*/
#include "panic.h"
#include "kw2xrf.h"
#include "kw2xrf_spi.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_getset.h"
#include "kw2xrf_intern.h"
#include "overwrites.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
void kw2xrf_disable_interrupts(kw2xrf_t *dev)
{
DEBUG("[kw2xrf] disable interrupts\n");
/* Clear and disable all interrupts */
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL2, 0xff);
int reg = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL3);
reg |= MKW2XDM_PHY_CTRL3_WAKE_MSK | MKW2XDM_PHY_CTRL3_PB_ERR_MSK;
kw2xrf_write_dreg(dev, MKW2XDM_PHY_CTRL3, reg);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, 0x7f);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS2, 0x03);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, 0xff);
}
/* update overwrites register */
void kw2xrf_update_overwrites(kw2xrf_t *dev)
{
kw2xrf_write_dreg(dev, MKW2XDM_OVERWRITE_VER, overwrites_direct[0].data);
for (uint8_t i = 0; i < sizeof(overwrites_indirect)/sizeof(overwrites_t); i++) {
kw2xrf_write_iregs(dev, overwrites_indirect[i].address,
(uint8_t *)&(overwrites_indirect[i].data), 1);
}
}
void kw2xrf_set_out_clk(kw2xrf_t *dev)
{
/* TODO: add clock select */
/* check modem's crystal oscillator, CLK_OUT shall be 4MHz */
uint8_t tmp = kw2xrf_read_dreg(dev, MKW2XDM_CLK_OUT_CTRL);
if (tmp != 0x8Bu) {
core_panic(PANIC_GENERAL_ERROR, "Could not start MKW2XD radio transceiver");
}
}
void kw2xrf_set_power_mode(kw2xrf_t *dev, kw2xrf_powermode_t pm)
{
DEBUG("[kw2xrf] set power mode to %d\n", pm);
uint8_t reg = 0;
switch (pm) {
case KW2XRF_HIBERNATE:
/* VREG off, XTAL off, Timer off, Current cons. < 1uA */
reg = 0;
dev->state = NETOPT_STATE_SLEEP;
break;
case KW2XRF_DOZE:
/* VREG off, XTAL on, Timer on/off, Current cons. 600uA */
reg = MKW2XDM_PWR_MODES_XTALEN;
dev->state = NETOPT_STATE_SLEEP;
break;
case KW2XRF_IDLE:
/* VREG on, XTAL on, Timer on, Current cons. 700uA */
reg = MKW2XDM_PWR_MODES_XTALEN | MKW2XDM_PWR_MODES_PMC_MODE;
dev->state = NETOPT_STATE_IDLE;
break;
case KW2XRF_AUTODOZE:
reg = MKW2XDM_PWR_MODES_XTALEN | MKW2XDM_PWR_MODES_AUTODOZE;
dev->state = NETOPT_STATE_IDLE;
break;
}
kw2xrf_write_dreg(dev, MKW2XDM_PWR_MODES, reg);
}
int kw2xrf_can_switch_to_idle(kw2xrf_t *dev)
{
uint8_t state = kw2xrf_read_dreg(dev, MKW2XDM_SEQ_STATE);
uint8_t seq = kw2xrf_read_dreg(dev, MKW2XDM_PHY_CTRL1) & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK;
DEBUG("[kw2xrf] state 0x%0x, seq 0x%0x\n", state, seq);
if ((seq != XCVSEQ_TRANSMIT) && (seq != XCVSEQ_TX_RX)) {
return 1;
}
if (state != 0) {
return 0;
}
return 0;
}
/** Load the timer value (Setting Current Time) */
static void kw2xrf_timer_load(kw2xrf_t *dev, uint32_t value)
{
kw2xrf_write_dregs(dev, MKW2XDM_T1CMP_LSB, (uint8_t *)&value, sizeof(value));
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TMRLOAD);
}
static uint32_t kw2xrf_timer_get(kw2xrf_t *dev)
{
uint32_t tmp;
kw2xrf_read_dregs(dev, MKW2XDM_EVENT_TIMER_LSB, (uint8_t*)&tmp, sizeof(tmp));
return tmp;
}
/** Set an absolute timeout value for the given compare register of the Event Timer */
static void kw2xrf_timer_set_absolute(kw2xrf_t *dev, uint8_t cmp_reg, uint32_t value)
{
kw2xrf_write_dregs(dev, cmp_reg, (uint8_t *)&value, 3);
}
/** Set an timeout value for the given compare register of the Event Timer */
static void kw2xrf_timer_set(kw2xrf_t *dev, uint8_t cmp_reg, uint32_t timeout)
{
uint32_t now = kw2xrf_timer_get(dev);
DEBUG("[kw2xrf] timer now: %" PRIx32 ", set %" PRIx32 "\n", now, now + timeout);
kw2xrf_timer_set_absolute(dev, cmp_reg, now + timeout);
}
void kw2xrf_timer_init(kw2xrf_t *dev, kw2xrf_timer_timebase_t tb)
{
uint8_t tmp = MKW2XDMI_TMR_PRESCALE_SET(tb);
kw2xrf_write_iregs(dev, MKW2XDMI_TMR_PRESCALE, &tmp, 1);
kw2xrf_timer_load(dev, 0);
}
void kw2xrf_timer2_seq_start_on(kw2xrf_t *dev)
{
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1, MKW2XDM_PHY_CTRL1_TMRTRIGEN);
}
void kw2xrf_timer2_seq_start_off(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1, MKW2XDM_PHY_CTRL1_TMRTRIGEN);
}
void kw2xrf_timer3_seq_abort_on(kw2xrf_t *dev)
{
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TC3TMOUT);
}
void kw2xrf_timer3_seq_abort_off(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL4, MKW2XDM_PHY_CTRL4_TC3TMOUT);
}
void kw2xrf_trigger_tx_ops_enable(kw2xrf_t *dev, uint32_t timeout)
{
kw2xrf_timer_set(dev, MKW2XDM_T2CMP_LSB, timeout);
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR2CMP_EN);
}
void kw2xrf_trigger_tx_ops_disable(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR2CMP_EN);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR2IRQ);
DEBUG("[kw2xrf] trigger_tx_ops_disable, now: %" PRIx32 "\n", kw2xrf_timer_get(dev));
}
void kw2xrf_abort_rx_ops_enable(kw2xrf_t *dev, uint32_t timeout)
{
kw2xrf_timer_set(dev, MKW2XDM_T3CMP_LSB, timeout);
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR3CMP_EN);
}
void kw2xrf_abort_rx_ops_disable(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR3CMP_EN);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR3IRQ);
DEBUG("[kw2xrf] abort_rx_ops_disable, now: %" PRIx32 "\n", kw2xrf_timer_get(dev));
}
void kw2xrf_seq_timeout_on(kw2xrf_t *dev, uint32_t timeout)
{
kw2xrf_mask_irq_b(dev);
kw2xrf_timer_set(dev, MKW2XDM_T4CMP_LSB, timeout);
/* enable and clear irq for timer 3 */
uint8_t irqsts3 = kw2xrf_read_dreg(dev, MKW2XDM_IRQSTS3) & 0xf0;
irqsts3 &= ~MKW2XDM_IRQSTS3_TMR4MSK;
irqsts3 |= MKW2XDM_IRQSTS3_TMR4IRQ;
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, irqsts3);
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR4CMP_EN);
kw2xrf_enable_irq_b(dev);
}
void kw2xrf_seq_timeout_off(kw2xrf_t *dev)
{
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL3, MKW2XDM_PHY_CTRL3_TMR4CMP_EN);
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS3, MKW2XDM_IRQSTS3_TMR4IRQ);
DEBUG("[kw2xrf] seq_timeout_off, now: %" PRIx32 "\n", kw2xrf_timer_get(dev));
}
uint32_t kw2xrf_get_timestamp(kw2xrf_t *dev)
{
uint32_t tmp;
kw2xrf_read_dregs(dev, MKW2XDM_TIMESTAMP_LSB, (uint8_t*)&tmp, sizeof(tmp));
return tmp;
}

View File

@ -0,0 +1,766 @@
/*
* 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_kw2xrf
* @{
*
* @file
* @brief Netdev interface for kw2xrf drivers
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "log.h"
#include "net/eui64.h"
#include "net/ieee802154.h"
#include "net/netdev2.h"
#include "net/netdev2/ieee802154.h"
#include "kw2xrf.h"
#include "kw2xrf_spi.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_netdev.h"
#include "kw2xrf_getset.h"
#include "kw2xrf_tm.h"
#include "kw2xrf_intern.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define _MAX_MHR_OVERHEAD (25)
#define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */
static uint8_t _send_last_fcf;
static void _irq_handler(void *arg)
{
netdev2_t *dev = (netdev2_t *) arg;
if (dev->event_callback) {
dev->event_callback(dev, NETDEV2_EVENT_ISR);
}
}
static int _init(netdev2_t *netdev)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
/* initialise SPI and GPIOs */
if (kw2xrf_init(dev, &_irq_handler)) {
LOG_ERROR("[kw2xrf] unable to initialize device\n");
return -1;
}
#ifdef MODULE_NETSTATS_L2
memset(&netdev->stats, 0, sizeof(netstats_t));
#endif
/* reset device to default values and put it into RX state */
kw2xrf_reset_phy(dev);
return 0;
}
static size_t kw2xrf_tx_load(uint8_t *pkt_buf, uint8_t *buf, size_t len, size_t offset)
{
for (unsigned i = 0; i < len; i++) {
pkt_buf[i + offset] = buf[i];
}
return offset + len;
}
static void kw2xrf_tx_exec(kw2xrf_t *dev)
{
if ((dev->netdev.flags & KW2XRF_OPT_AUTOACK) &&
(_send_last_fcf & IEEE802154_FCF_ACK_REQ)) {
kw2xrf_set_sequence(dev, XCVSEQ_TX_RX);
}
else {
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
}
}
static int _send(netdev2_t *netdev, const struct iovec *vector, unsigned count)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
const struct iovec *ptr = vector;
uint8_t *pkt_buf = &(dev->buf[1]);
size_t len = 0;
/* load packet data into buffer */
for (unsigned i = 0; i < count; i++, ptr++) {
/* current packet data + FCS too long */
if ((len + ptr->iov_len + IEEE802154_FCS_LEN) > KW2XRF_MAX_PKT_LENGTH) {
LOG_ERROR("[kw2xrf] packet too large (%u byte) to be send\n",
(unsigned)len + IEEE802154_FCS_LEN);
return -EOVERFLOW;
}
len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len);
}
/* make sure ongoing t or tr sequenz are finished */
if (kw2xrf_can_switch_to_idle(dev)) {
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
dev->pending_tx++;
}
else {
/* do not wait, this can lead to a dead lock */
return 0;
}
/*
* Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2
* MKW2xD Reference Manual, P.192
*/
dev->buf[0] = len + IEEE802154_FCS_LEN;
/* Help for decision to use T or TR sequenz */
_send_last_fcf = dev->buf[1];
kw2xrf_write_fifo(dev, dev->buf, dev->buf[0]);
#ifdef MODULE_NETSTATS_L2
netdev->stats.tx_bytes += len;
#endif
/* send data out directly if pre-loading id disabled */
if (!(dev->netdev.flags & KW2XRF_OPT_PRELOADING)) {
kw2xrf_tx_exec(dev);
}
return (int)len;
}
static int _recv(netdev2_t *netdev, void *buf, size_t len, void *info)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
size_t pkt_len = 0;
/* get size of the received packet */
pkt_len = kw2xrf_read_dreg(dev, MKW2XDM_RX_FRM_LEN);
/* just return length when buf == NULL */
if (buf == NULL) {
return pkt_len + 1;
}
#ifdef MODULE_NETSTATS_L2
netdev->stats.rx_count++;
netdev->stats.rx_bytes += pkt_len;
#endif
if (pkt_len > len) {
/* not enough space in buf */
return -ENOBUFS;
}
kw2xrf_read_fifo(dev, (uint8_t *)buf, pkt_len + 1);
if (info != NULL) {
netdev2_ieee802154_rx_info_t *radio_info = info;
radio_info->lqi = ((uint8_t*)buf)[pkt_len];
radio_info->rssi = (uint8_t)kw2xrf_get_rssi(radio_info->lqi);
}
/* skip FCS and LQI */
return pkt_len - 2;
}
static int _set_state(kw2xrf_t *dev, netopt_state_t state)
{
switch (state) {
case NETOPT_STATE_SLEEP:
kw2xrf_set_power_mode(dev, KW2XRF_DOZE);
break;
case NETOPT_STATE_IDLE:
kw2xrf_set_power_mode(dev, KW2XRF_AUTODOZE);
kw2xrf_set_sequence(dev, dev->idle_state);
break;
case NETOPT_STATE_TX:
if (dev->netdev.flags & KW2XRF_OPT_PRELOADING) {
kw2xrf_tx_exec(dev);
}
break;
case NETOPT_STATE_RESET:
kw2xrf_reset_phy(dev);
break;
case NETOPT_STATE_OFF:
/* TODO: Replace with powerdown (set reset input low) */
kw2xrf_set_power_mode(dev, KW2XRF_HIBERNATE);
default:
return -ENOTSUP;
}
return sizeof(netopt_state_t);
}
static netopt_state_t _get_state(kw2xrf_t *dev)
{
return dev->state;
}
int _get(netdev2_t *netdev, netopt_t opt, void *value, size_t len)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
if (dev == NULL) {
return -ENODEV;
}
switch (opt) {
case NETOPT_MAX_PACKET_SIZE:
if (len < sizeof(int16_t)) {
return -EOVERFLOW;
}
*((uint16_t *)value) = KW2XRF_MAX_PKT_LENGTH - _MAX_MHR_OVERHEAD;
return sizeof(uint16_t);
case NETOPT_STATE:
if (len < sizeof(netopt_state_t)) {
return -EOVERFLOW;
}
*((netopt_state_t *)value) = _get_state(dev);
return sizeof(netopt_state_t);
case NETOPT_PRELOADING:
if (dev->netdev.flags & KW2XRF_OPT_PRELOADING) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
return sizeof(netopt_enable_t);
case NETOPT_PROMISCUOUSMODE:
if (dev->netdev.flags & KW2XRF_OPT_PROMISCUOUS) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
return sizeof(netopt_enable_t);
case NETOPT_RX_START_IRQ:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_TELL_RX_START);
return sizeof(netopt_enable_t);
case NETOPT_RX_END_IRQ:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_TELL_RX_END);
return sizeof(netopt_enable_t);
case NETOPT_TX_START_IRQ:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_TELL_TX_START);
return sizeof(netopt_enable_t);
case NETOPT_TX_END_IRQ:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_TELL_TX_END);
return sizeof(netopt_enable_t);
case NETOPT_AUTOCCA:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_AUTOCCA);
return sizeof(netopt_enable_t);
case NETOPT_TX_POWER:
if (len < sizeof(int16_t)) {
return -EOVERFLOW;
}
*((uint16_t *)value) = kw2xrf_get_txpower(dev);
return sizeof(uint16_t);
case NETOPT_IS_CHANNEL_CLR:
if (kw2xrf_cca(dev)) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
return sizeof(netopt_enable_t);
case NETOPT_CCA_THRESHOLD:
if (len < sizeof(uint8_t)) {
return -EOVERFLOW;
}
else {
*(int8_t *)value = kw2xrf_get_cca_threshold(dev);
}
return sizeof(int8_t);
case NETOPT_CCA_MODE:
if (len < sizeof(uint8_t)) {
return -EOVERFLOW;
}
else {
*(uint8_t *)value = kw2xrf_get_cca_mode(dev);
switch (*((int8_t *)value)) {
case NETDEV2_IEEE802154_CCA_MODE_1:
case NETDEV2_IEEE802154_CCA_MODE_2:
case NETDEV2_IEEE802154_CCA_MODE_3:
return sizeof(uint8_t);
default:
break;
}
return -EOVERFLOW;
}
break;
case NETOPT_CHANNEL_PAGE:
default:
break;
}
return netdev2_ieee802154_get((netdev2_ieee802154_t *)netdev, opt, value, len);
}
static int _set(netdev2_t *netdev, netopt_t opt, void *value, size_t len)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
int res = -ENOTSUP;
if (dev == NULL) {
return -ENODEV;
}
switch (opt) {
case NETOPT_ADDRESS:
if (len > sizeof(uint16_t)) {
res = -EOVERFLOW;
}
else {
kw2xrf_set_addr_short(dev, *((uint16_t *)value));
/* don't set res to set netdev2_ieee802154_t::short_addr */
}
break;
case NETOPT_ADDRESS_LONG:
if (len > sizeof(uint64_t)) {
return -EOVERFLOW;
}
else {
kw2xrf_set_addr_long(dev, *((uint64_t *)value));
/* don't set res to set netdev2_ieee802154_t::short_addr */
}
break;
case NETOPT_NID:
if (len > sizeof(uint16_t)) {
return -EOVERFLOW;
}
else {
kw2xrf_set_pan(dev, *((uint16_t *)value));
/* don't set res to set netdev2_ieee802154_t::pan */
}
break;
case NETOPT_CHANNEL:
if (len != sizeof(uint16_t)) {
res = -EINVAL;
}
else {
uint8_t chan = ((uint8_t *)value)[0];
if (kw2xrf_set_channel(dev, chan)) {
res = -EINVAL;
break;
}
dev->netdev.chan = chan;
/* don't set res to set netdev2_ieee802154_t::chan */
}
break;
case NETOPT_CHANNEL_PAGE:
res = -EINVAL;
break;
case NETOPT_TX_POWER:
if (len < sizeof(uint16_t)) {
res = -EOVERFLOW;
}
else {
kw2xrf_set_tx_power(dev, *(int16_t *)value);
res = sizeof(uint16_t);
}
break;
case NETOPT_STATE:
if (len > sizeof(netopt_state_t)) {
res = -EOVERFLOW;
}
else {
res = _set_state(dev, *((netopt_state_t *)value));
}
break;
case NETOPT_AUTOACK:
/* Set up HW generated automatic ACK after Receive */
kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK,
((bool *)value)[0]);
break;
case NETOPT_ACK_REQ:
kw2xrf_set_option(dev, KW2XRF_OPT_ACK_REQ,
((bool *)value)[0]);
break;
case NETOPT_PRELOADING:
kw2xrf_set_option(dev, KW2XRF_OPT_PRELOADING,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_PROMISCUOUSMODE:
kw2xrf_set_option(dev, KW2XRF_OPT_PROMISCUOUS,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RX_START_IRQ:
kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_START,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RX_END_IRQ:
kw2xrf_set_option(dev, KW2XRF_OPT_TELL_RX_END,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_TX_START_IRQ:
kw2xrf_set_option(dev, KW2XRF_OPT_TELL_TX_START,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_TX_END_IRQ:
kw2xrf_set_option(dev, KW2XRF_OPT_TELL_TX_END,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_AUTOCCA:
kw2xrf_set_option(dev, KW2XRF_OPT_AUTOCCA,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;
case NETOPT_CCA_THRESHOLD:
if (len < sizeof(uint8_t)) {
res = -EOVERFLOW;
}
else {
kw2xrf_set_cca_threshold(dev, *((int8_t*)value));
res = sizeof(uint8_t);
}
break;
case NETOPT_CCA_MODE:
if (len < sizeof(uint8_t)) {
res = -EOVERFLOW;
}
else {
switch (*((int8_t*)value)) {
case NETDEV2_IEEE802154_CCA_MODE_1:
case NETDEV2_IEEE802154_CCA_MODE_2:
case NETDEV2_IEEE802154_CCA_MODE_3:
kw2xrf_set_cca_mode(dev, *((int8_t*)value));
res = sizeof(uint8_t);
break;
case NETDEV2_IEEE802154_CCA_MODE_4:
case NETDEV2_IEEE802154_CCA_MODE_5:
case NETDEV2_IEEE802154_CCA_MODE_6:
default:
break;
}
}
break;
case NETOPT_RF_TESTMODE:
#ifdef KW2XRF_TESTMODE
if (len < sizeof(uint8_t)) {
res = -EOVERFLOW;
}
else {
kw2xrf_set_test_mode(dev, *((uint8_t *)value));
res = sizeof(uint8_t);
}
#endif
break;
default:
break;
}
if (res == -ENOTSUP) {
res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt,
value, len);
}
return res;
}
static void _isr_event_seq_r(netdev2_t *netdev, uint8_t *dregs)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
uint8_t irqsts1 = 0;
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXWTRMRKIRQ) {
DEBUG("[kw2xrf] got RXWTRMRKIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_RXWTRMRKIRQ;
netdev->event_callback(netdev, NETDEV2_EVENT_RX_STARTED);
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXIRQ) {
DEBUG("[kw2xrf] finished RXSEQ\n");
dev->state = NETOPT_STATE_RX;
irqsts1 |= MKW2XDM_IRQSTS1_RXIRQ;
netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE);
if (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_AUTOACK) {
DEBUG("[kw2xrf]: perform TX ACK\n");
}
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) {
DEBUG("[kw2xrf] finished (ACK) TXSEQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ;
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) {
DEBUG("[kw2xrf] SEQIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
kw2xrf_set_idle_sequence(dev);
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
dregs[MKW2XDM_IRQSTS1] &= ~irqsts1;
}
static void _isr_event_seq_t(netdev2_t *netdev, uint8_t *dregs)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
uint8_t irqsts1 = 0;
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) {
DEBUG("[kw2xrf] finished TXSEQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ;
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) {
DEBUG("[kw2xrf] SEQIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ;
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) {
DEBUG("[kw2xrf] CCA CH busy\n");
netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY);
}
else {
netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE);
}
}
assert(dev->pending_tx != 0);
dev->pending_tx--;
kw2xrf_set_idle_sequence(dev);
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
dregs[MKW2XDM_IRQSTS1] &= ~irqsts1;
}
/* Standalone CCA */
static void _isr_event_seq_cca(netdev2_t *netdev, uint8_t *dregs)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
uint8_t irqsts1 = 0;
if ((dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) &&
(dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ)) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ;
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) {
DEBUG("[kw2xrf] SEQIRQ, CCA CH busy\n");
}
else {
DEBUG("[kw2xrf] SEQIRQ, CCA CH idle\n");
}
kw2xrf_set_idle_sequence(dev);
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
dregs[MKW2XDM_IRQSTS1] &= ~irqsts1;
}
static void _isr_event_seq_tr(netdev2_t *netdev, uint8_t *dregs)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
uint8_t irqsts1 = 0;
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_TXIRQ) {
DEBUG("[kw2xrf] finished TXSEQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_TXIRQ;
if (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_RXACKRQD) {
DEBUG("[kw2xrf] wait for RX ACK\n");
kw2xrf_seq_timeout_on(dev, _MACACKWAITDURATION);
}
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXWTRMRKIRQ) {
DEBUG("[kw2xrf] got RXWTRMRKIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_RXWTRMRKIRQ;
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_FILTERFAIL_IRQ) {
DEBUG("[kw2xrf] got FILTERFAILIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_FILTERFAIL_IRQ;
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_RXIRQ) {
DEBUG("[kw2xrf] got RX ACK\n");
irqsts1 |= MKW2XDM_IRQSTS1_RXIRQ;
}
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) {
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ;
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) {
DEBUG("[kw2xrf] CCA CH busy\n");
netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY);
}
}
DEBUG("[kw2xrf] SEQIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
assert(dev->pending_tx != 0);
dev->pending_tx--;
netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE);
kw2xrf_seq_timeout_off(dev);
kw2xrf_set_idle_sequence(dev);
}
else if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR4IRQ) {
DEBUG("[kw2xrf] TC4TMOUT, no SEQIRQ, TX failed\n");
assert(dev->pending_tx != 0);
dev->pending_tx--;
netdev->event_callback(netdev, NETDEV2_EVENT_TX_NOACK);
kw2xrf_seq_timeout_off(dev);
kw2xrf_set_sequence(dev, dev->idle_state);
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
dregs[MKW2XDM_IRQSTS1] &= ~irqsts1;
}
static void _isr_event_seq_ccca(netdev2_t *netdev, uint8_t *dregs)
{
kw2xrf_t *dev = (kw2xrf_t *)netdev;
uint8_t irqsts1 = 0;
if ((dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) &&
(dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ)) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ;
DEBUG("[kw2xrf] CCCA CH idle\n");
kw2xrf_seq_timeout_off(dev);
kw2xrf_set_sequence(dev, dev->idle_state);
}
else if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR4IRQ) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ | MKW2XDM_IRQSTS1_SEQIRQ;
DEBUG("[kw2xrf] CCCA timeout\n");
kw2xrf_seq_timeout_off(dev);
kw2xrf_set_sequence(dev, dev->idle_state);
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
dregs[MKW2XDM_IRQSTS1] &= ~irqsts1;
}
static void _isr(netdev2_t *netdev)
{
uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1];
kw2xrf_t *dev = (kw2xrf_t *)netdev;
kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_PHY_CTRL4 + 1);
kw2xrf_mask_irq_b(dev);
DEBUG("[kw2xrf] CTRL1 %0x, IRQSTS1 %0x, IRQSTS2 %0x\n",
dregs[MKW2XDM_PHY_CTRL1], dregs[MKW2XDM_IRQSTS1], dregs[MKW2XDM_IRQSTS2]);
switch (dregs[MKW2XDM_PHY_CTRL1] & MKW2XDM_PHY_CTRL1_XCVSEQ_MASK) {
case XCVSEQ_RECEIVE:
_isr_event_seq_r(netdev, dregs);
break;
case XCVSEQ_TRANSMIT:
_isr_event_seq_t(netdev, dregs);
break;
case XCVSEQ_CCA:
_isr_event_seq_cca(netdev, dregs);
break;
case XCVSEQ_TX_RX:
_isr_event_seq_tr(netdev, dregs);
break;
case XCVSEQ_CONTINUOUS_CCA:
_isr_event_seq_ccca(netdev, dregs);
break;
case XCVSEQ_IDLE:
default:
DEBUG("[kw2xrf] undefined seq state in isr\n");
break;
}
uint8_t irqsts2 = 0;
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_PB_ERR_IRQ) {
DEBUG("[kw2xrf] untreated PB_ERR_IRQ\n");
irqsts2 |= MKW2XDM_IRQSTS2_PB_ERR_IRQ;
}
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_WAKE_IRQ) {
DEBUG("[kw2xrf] untreated WAKE_IRQ\n");
irqsts2 |= MKW2XDM_IRQSTS2_WAKE_IRQ;
}
kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS2, irqsts2);
if (ENABLE_DEBUG) {
/* for debugging only */
kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_IRQSTS1 + 3);
if (dregs[MKW2XDM_IRQSTS1] & 0x7f) {
DEBUG("[kw2xrf] IRQSTS1 contains untreated IRQs: 0x%02x\n",
dregs[MKW2XDM_IRQSTS1]);
}
if (dregs[MKW2XDM_IRQSTS2] & 0x02) {
DEBUG("[kw2xrf] IRQSTS2 contains untreated IRQs: 0x%02x\n",
dregs[MKW2XDM_IRQSTS2]);
}
if (dregs[MKW2XDM_IRQSTS3] & 0x0f) {
DEBUG("[kw2xrf] IRQSTS3 contains untreated IRQs: 0x%02x\n",
dregs[MKW2XDM_IRQSTS3]);
}
}
kw2xrf_enable_irq_b(dev);
}
const netdev2_driver_t kw2xrf_driver = {
.init = _init,
.send = _send,
.recv = _recv,
.get = _get,
.set = _set,
.isr = _isr,
};
/** @} */

View File

@ -14,8 +14,11 @@
*
* @author Johann Fischer <j.fischer@phytec.de>
* @author Jonas Remmert <j.remmert@phytec.de>
* @author Sebastian Meiling <s@mlng.net>
* @}
*/
#include "log.h"
#include "kw2xrf.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_spi.h"
@ -27,62 +30,108 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
#define SPI_MODE (SPI_MODE_0)
#define SPIDEV (dev->params.spi)
#define SPICLK (dev->params.spi_clk)
#define CSPIN (dev->params.cs_pin)
#define SPIMODE (SPI_MODE_0)
#define KW2XRF_IBUF_LENGTH (9)
static uint8_t ibuf[KW2XRF_IBUF_LENGTH];
/** Set up in kw2xrf_spi_init during initialization */
static spi_t kw2xrf_spi;
static spi_clk_t kw2xrf_clk;
static spi_cs_t kw2xrf_cs_pin;
static inline void kw2xrf_spi_transfer_head(void)
void kw2xrf_spi_transfer_head(kw2xrf_t *dev)
{
spi_acquire(kw2xrf_spi, kw2xrf_cs_pin, SPI_MODE, kw2xrf_clk);
spi_acquire(SPIDEV, CSPIN, SPIMODE, SPICLK);
#if KW2XRF_SHARED_SPI
gpio_clear(CSPIN);
#endif
}
static inline void kw2xrf_spi_transfer_tail(void)
void kw2xrf_spi_transfer_tail(kw2xrf_t *dev)
{
spi_release(kw2xrf_spi);
#if KW2XRF_SHARED_SPI
gpio_set(CSPIN);
#endif
spi_release(SPIDEV);
}
int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin)
int kw2xrf_spi_init(kw2xrf_t *dev)
{
DEBUG("[kw2xrf_spi] kw2xrf_spi_init\n");
int res;
kw2xrf_spi = spi;
kw2xrf_clk = spi_clk;
kw2xrf_cs_pin = cs_pin; /**< for later reference */
#if KW2XRF_SHARED_SPI
spi_acquire(SPIDEV, CSPIN, SPIMODE, SPICLK);
#endif
res = spi_init_cs(SPIDEV, CSPIN);
#if KW2XRF_SHARED_SPI
spi_release(SPIDEV);
gpio_init(CSPIN, GPIO_OUT);
gpio_set(CSPIN);
#endif
res = spi_init_cs(kw2xrf_spi, kw2xrf_cs_pin);
if (res != SPI_OK) {
DEBUG("kw2xrf_spi_init: error initializing SPI_DEV(%i) (code %i)\n",
kw2xrf_spi, res);
return -1;
LOG_ERROR("[kw2xrf_spi] failed to init SPI_%i device (code %i)\n",
SPIDEV, res);
return 1;
}
/* verify SPI params */
res = spi_acquire(SPIDEV, CSPIN, SPIMODE, SPICLK);
if (res == SPI_NOMODE) {
LOG_ERROR("[kw2xrf_spi] given SPI mode is not supported");
return 1;
}
else if (res == SPI_NOCLK) {
LOG_ERROR("[kw2xrf_spi] targeted clock speed is not supported");
return 1;
}
else if (res != SPI_OK) {
LOG_ERROR("[kw2xrf_spi] unable to acquire bus with given parameters");
return 1;
}
spi_release(SPIDEV);
DEBUG("[kw2xrf_spi] SPI_DEV(%i) initialized: mode: %i, clk: %i, cs_pin: %i\n",
SPIDEV, SPIMODE, SPICLK, CSPIN);
return 0;
}
void kw2xrf_write_dreg(uint8_t addr, uint8_t value)
void kw2xrf_write_dreg(kw2xrf_t *dev, uint8_t addr, uint8_t value)
{
kw2xrf_spi_transfer_head();
spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, addr, value);
kw2xrf_spi_transfer_tail();
DEBUG("[kw2xrf_spi] kw2xrf_write_dreg, addr %u, value %u\n", addr, value);
kw2xrf_spi_transfer_head(dev);
spi_transfer_reg(SPIDEV, CSPIN, addr, value);
kw2xrf_spi_transfer_tail(dev);
return;
}
uint8_t kw2xrf_read_dreg(uint8_t addr)
uint8_t kw2xrf_read_dreg(kw2xrf_t *dev, uint8_t addr)
{
uint8_t value;
kw2xrf_spi_transfer_head();
value = spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin,
(addr | MKW2XDRF_REG_READ), 0x0);
kw2xrf_spi_transfer_tail();
kw2xrf_spi_transfer_head(dev);
value = spi_transfer_reg(SPIDEV, CSPIN, (addr | MKW2XDRF_REG_READ), 0x0);
kw2xrf_spi_transfer_tail(dev);
DEBUG("[kw2xrf_spi] kw2xrf_read_dreg, addr %u, value %u\n", addr, value);
return value;
}
void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
void kw2xrf_write_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length)
{
DEBUG("[kw2xrf_spi] kw2xrf_write_dregs, addr %u, length %u\n", addr, length);
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, addr, buf, NULL, length);
kw2xrf_spi_transfer_tail(dev);
}
void kw2xrf_read_dregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length)
{
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, (addr | MKW2XDRF_REG_READ), NULL, buf, length);
DEBUG("[kw2xrf_spi] kw2xrf_read_dregs, addr %u, length %u\n", addr, length);
kw2xrf_spi_transfer_tail(dev);
}
void kw2xrf_write_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length)
{
if (length > (KW2XRF_IBUF_LENGTH - 1)) {
length = KW2XRF_IBUF_LENGTH - 1;
@ -94,15 +143,14 @@ void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
ibuf[i + 1] = buf[i];
}
kw2xrf_spi_transfer_head();
spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDM_IAR_INDEX,
ibuf, NULL, length + 1);
kw2xrf_spi_transfer_tail();
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, MKW2XDM_IAR_INDEX, ibuf, NULL, length + 1);
kw2xrf_spi_transfer_tail(dev);
return;
}
void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
void kw2xrf_read_iregs(kw2xrf_t *dev, uint8_t addr, uint8_t *buf, uint8_t length)
{
if (length > (KW2XRF_IBUF_LENGTH - 1)) {
length = KW2XRF_IBUF_LENGTH - 1;
@ -110,11 +158,10 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
ibuf[0] = addr;
kw2xrf_spi_transfer_head();
spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin,
MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ,
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, (MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ),
ibuf, ibuf, length + 1);
kw2xrf_spi_transfer_tail();
kw2xrf_spi_transfer_tail(dev);
for (uint8_t i = 0; i < length; i++) {
buf[i] = ibuf[i + 1];
@ -123,18 +170,16 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length)
return;
}
void kw2xrf_write_fifo(uint8_t *data, uint8_t length)
void kw2xrf_write_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t length)
{
kw2xrf_spi_transfer_head();
spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_WRITE,
data, NULL, length);
kw2xrf_spi_transfer_tail();
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, MKW2XDRF_BUF_WRITE, data, NULL, length);
kw2xrf_spi_transfer_tail(dev);
}
void kw2xrf_read_fifo(uint8_t *data, uint8_t length)
void kw2xrf_read_fifo(kw2xrf_t *dev, uint8_t *data, uint8_t length)
{
kw2xrf_spi_transfer_head();
spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_READ,
NULL, data, length);
kw2xrf_spi_transfer_tail();
kw2xrf_spi_transfer_head(dev);
spi_transfer_regs(SPIDEV, CSPIN, MKW2XDRF_BUF_READ, NULL, data, length);
kw2xrf_spi_transfer_tail(dev);
}

181
drivers/kw2xrf/kw2xrf_tm.c Normal file
View File

@ -0,0 +1,181 @@
/*
* 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_kw2xrf
* @{
*
* @file
* @brief Testing function of kw2xrf driver
*
* @author Johann Fischer <j.fischer@phytec.de>
*/
#include "kw2xrf.h"
#include "kw2xrf_spi.h"
#include "kw2xrf_reg.h"
#include "kw2xrf_tm.h"
#ifdef KW2XRF_TESTMODE
inline static void enable_xcvr_test_mode(kw2xrf_t *dev)
{
uint8_t reg;
kw2xrf_read_iregs(dev, MKW2XDMI_DTM_CTRL1, &reg, 1);
reg |= MKW2XDMI_DTM_CTRL1_DTM_EN;
kw2xrf_write_iregs(dev, MKW2XDMI_DTM_CTRL1, &reg, 1);
kw2xrf_read_iregs(dev, MKW2XDMI_TESTMODE_CTRL, &reg, 1);
reg |= MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN | MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN;
kw2xrf_write_iregs(dev, MKW2XDMI_TESTMODE_CTRL, &reg, 1);
}
inline static void disable_xcvr_test_mode(kw2xrf_t *dev)
{
uint8_t reg;
kw2xrf_read_iregs(dev, MKW2XDMI_DTM_CTRL1, &reg, 1);
reg &= MKW2XDMI_DTM_CTRL1_DTM_EN;
kw2xrf_write_iregs(dev, MKW2XDMI_DTM_CTRL1, &reg, 1);
kw2xrf_read_iregs(dev, MKW2XDMI_TESTMODE_CTRL, &reg, 1);
reg &= ~(MKW2XDMI_TESTMODE_CTRL_CONTINUOUS_EN | MKW2XDMI_TESTMODE_CTRL_IDEAL_PFC_EN);
kw2xrf_write_iregs(dev, MKW2XDMI_TESTMODE_CTRL, &reg, 1);
}
int kw2xrf_set_test_mode(kw2xrf_t *dev, uint8_t mode)
{
uint8_t reg = 0;
uint8_t buf[2];
kw2xrf_abort_sequence(dev);
disable_xcvr_test_mode(dev);
kw2xrf_set_channel(dev, dev->netdev.chan);
switch(mode) {
case NETOPT_RF_TESTMODE_IDLE:
reg = 0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
break;
case NETOPT_RF_TESTMODE_CRX:
/* set continuous RX mode */
reg = 0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
/* set data length */
reg = 127;
kw2xrf_write_iregs(dev, MKW2XDMI_DUAL_PAN_DWELL, &reg, 1);
kw2xrf_set_sequence(dev, XCVSEQ_RECEIVE);
break;
case KW2XRF_TM_CTX_PREAMBLE:
/* set continuous TX mode, transmit 10101010 pattern */
reg = 0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
buf[0] = 1;
buf[1] = 0xaa;
kw2xrf_write_fifo(dev, buf, buf[0] + 1);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case NETOPT_RF_TESTMODE_CTX_CW:
/* set continuous TX mode, transmit unmodulated carrier */
reg = MKW2XDMI_TX_MODE_CTRL_DTS0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
/* fix pll frequency for cw mode */
uint16_t pll_frac = kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_LSB);
pll_frac |= ((uint16_t)kw2xrf_read_dreg(dev, MKW2XDM_PLL_FRAC0_MSB) << 8);
pll_frac -= 0x400;
kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_LSB, (uint8_t)pll_frac);
kw2xrf_write_dreg(dev, MKW2XDM_PLL_FRAC0_MSB, (uint8_t)(pll_frac >> 8));
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_NM1:
/* set continuous TX mode */
reg = MKW2XDMI_TX_MODE_CTRL_DTS0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_NM0:
/* set continuous TX mode */
reg = MKW2XDMI_TX_MODE_CTRL_DTS1;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_2MHZ:
/* set continuous TX mode */
reg = MKW2XDMI_TX_MODE_CTRL_DTS1 | MKW2XDMI_TX_MODE_CTRL_DTS0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_200KHZ:
/* set continuous TX mode */
reg = MKW2XDMI_TX_MODE_CTRL_DTS2;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_1MBPS_PRBS9:
/* set continuous TX mode, transmit PRBS9 pattern */
reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case KW2XRF_TM_CTX_EXT:
/* set continuous TX mode */
reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS1;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
case NETOPT_RF_TESTMODE_CTX_PRBS9:
/* set continuous TX mode, transmit PRBS9 pattern */
reg = MKW2XDMI_TX_MODE_CTRL_DTS2 | MKW2XDMI_TX_MODE_CTRL_DTS1
| MKW2XDMI_TX_MODE_CTRL_DTS0;
kw2xrf_write_iregs(dev, MKW2XDMI_TX_MODE_CTRL, &reg, 1);
enable_xcvr_test_mode(dev);
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
break;
}
return 1;
}
#endif
/** @} */

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
* Copyright (C) 2015 PHYTEC Messtechnik GmbH
* 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
@ -17,6 +17,7 @@
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Jonas Remmert <j.remmert@phytec.de>
* @author Sebastian Meiling <s@mlng.net>
*/
#ifdef MODULE_KW2XRF
@ -24,7 +25,7 @@
#include "log.h"
#include "board.h"
#include "net/gnrc/netdev2.h"
#include "net/gnrc/nomac.h"
#include "net/gnrc/netdev2/ieee802154.h"
#include "net/gnrc.h"
#include "kw2xrf.h"
@ -42,7 +43,8 @@
#define KW2XRF_NUM (sizeof(kw2xrf_params)/sizeof(kw2xrf_params[0]))
static kw2xrf_t kw2xrf_devs[KW2XRF_NUM];
static char _nomac_stacks[KW2XRF_NUM][KW2XRF_MAC_STACKSIZE];
static gnrc_netdev2_t gnrc_adpt[KW2XRF_NUM];
static char _kw2xrf_stacks[KW2XRF_NUM][KW2XRF_MAC_STACKSIZE];
void auto_init_kw2xrf(void)
{
@ -50,25 +52,18 @@ void auto_init_kw2xrf(void)
const kw2xrf_params_t *p = &kw2xrf_params[i];
LOG_DEBUG("[auto_init_netif] initializing kw2xrf #%u\n", i);
int res = kw2xrf_init(&kw2xrf_devs[i],
p->spi,
p->spi_speed,
p->cs_pin,
p->int_pin);
if (res < 0) {
LOG_ERROR("[auto_init_netif] initializing kw2xrf #%u\n", i);
kw2xrf_setup(&kw2xrf_devs[i], (kw2xrf_params_t*) p);
if (gnrc_netdev2_ieee802154_init(&gnrc_adpt[i], (netdev2_ieee802154_t *)&kw2xrf_devs[i]) < 0) {
LOG_ERROR("[auto_init_netif] error, initializing kw2xrf #%u\n", i);
}
else {
gnrc_nomac_init(_nomac_stacks[i],
KW2XRF_MAC_STACKSIZE, KW2XRF_MAC_PRIO,
"kw2xrf", (gnrc_netdev_t *)&kw2xrf_devs[i]);
gnrc_netdev2_init(_kw2xrf_stacks[i], KW2XRF_MAC_STACKSIZE,
KW2XRF_MAC_PRIO, "kw2xrf", &gnrc_adpt[i]);
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_GNRC_KW2XRF */
#endif /* MODULE_KW2XRF */
/** @} */

View File

@ -6,45 +6,12 @@ FEATURES_REQUIRED = periph_spi periph_gpio
BOARD_INSUFFICIENT_MEMORY := stm32f0discovery nucleo-f334 weio
USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_netif
USEMODULE += gnrc_txtsnd
USEMODULE += gnrc_nomac
USEMODULE += gnrc_pktdump
USEMODULE += gnrc_netdev_default
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# define parameters for selected boards
ifneq (,$(filter pba-d-01-kw2x,$(BOARD)))
DRIVER := kw2xrf
USE_BOARD_PARAMETERS := true
endif
# only set specific parameters if not using board configuration
ifneq (true,$(USE_BOARD_PARAMETERS))
# set default device parameters in case they are undefined
DRIVER ?= kw2xrf
KW2XRF_SHARED_SPI ?= 1
KWRF_SPI ?= SPI_DEV\(0\)
KWRF_SPI_SPEED ?= SPI_CLK_5MHZ
KWRF_CS ?= GPIO_PIN\(0,0\)
KWRF_INT ?= GPIO_PIN\(0,1\)
# export parameters
CFLAGS += -DKW2XRF_SHARED_SPI=$(KW2XRF_SHARED_SPI)
CFLAGS += -DKWRF_SPI=$(KWRF_SPI)
CFLAGS += -DKWRF_SPI_SPEED=$(KWRF_SPI_SPEED)
CFLAGS += -DKWRF_CS=$(KWRF_CS)
CFLAGS += -DKWRF_INT=$(KWRF_INT)
# This adds . to include path so generic kw2xrf_params.h gets picked
# up. All boards actually having such a device on board should define
# USE_BOARD_PARAMETERS=true above to skip this step, as the board provides
# this header.
CFLAGS += -I$(CURDIR)
endif
DRIVER ?= kw2xrf
# finally include the actual chosen driver
USEMODULE += $(DRIVER)

View File

@ -1,12 +1,9 @@
# About
This is a manual test application for testing the KW2xrf network device driver.
This is a manual test application for testing the KW2XRF device driver. It enables several shell commands, allowing for special test modes of that device. Without deeper knowledge about the hardware, this application might be useless except for compile tests. If you want an example to use this radio, check the [examples](../../examples) folder.
For running this test, you need to connect/configure the following pins of your
radio device:
radio device. If you are running on a phyNODE, this is already the on-board default.
- SPI DEV
- CS (chip select)
- INT (external interrupt)
# Usage
For testing the radio driver you can use the netif and txtsnd shell commands
that are included in this application.

View File

@ -39,23 +39,22 @@ extern "C" {
#ifndef KWRF_INT
#error "Interrupt pin not defined"
#endif
#ifndef KWRF_SPI_SPEED
#define KWRF_SPI_SPEED (SPI_CLK_10MHZ)
#ifndef KWRF_SPI_CLK
#define KWRF_SPI_CLK (SPI_CLK_10MHZ)
#endif
/**@}*/
/**
* @name KW2XRF configuration
*/
static const kw2xrf_params_t kw2xrf_params[] =
static const kw2xrf_params_t kw2xrf_params[] = {
{
{
.spi = KWRF_SPI,
.spi_speed = KWRF_SPI_SPEED,
.cs_pin = KWRF_CS,
.int_pin = KWRF_INT,
},
};
.spi = KWRF_SPI,
.spi_clk = KWRF_SPI_CLK,
.cs_pin = KWRF_CS,
.int_pin = KWRF_INT,
},
};
/** @} */
#ifdef __cplusplus

View File

@ -20,26 +20,154 @@
#include <stdio.h>
#include "shell.h"
#include "kw2xrf.h"
#include "shell_commands.h"
#include "net/gnrc.h"
#include "net/gnrc/pktdump.h"
#include "net/gnrc/netif.h"
#include "net/gnrc/netapi.h"
#include "net/netopt.h"
#define KW2XRF_TESTMODE (1)
#ifdef KW2XRF_TESTMODE
#include "kw2xrf_tm.h"
/* utility functions */
static bool _is_number(char *str)
{
for (; *str; str++) {
if (*str < '0' || *str > '9') {
return false;
}
}
return true;
}
static bool _is_iface(kernel_pid_t dev)
{
kernel_pid_t ifs[GNRC_NETIF_NUMOF];
size_t numof = gnrc_netif_get(ifs);
for (size_t i = 0; i < numof && i < GNRC_NETIF_NUMOF; i++) {
if (ifs[i] == dev) {
return true;
}
}
return false;
}
static void _set_test_mode(int argc, char **argv, uint8_t mode)
{
(void) argc;
if (_is_number(argv[1])) {
kernel_pid_t dev = (kernel_pid_t)atoi(argv[1]);
if (_is_iface(dev)) {
gnrc_netapi_set(dev, NETOPT_RF_TESTMODE, 0, (void *)&mode, sizeof(mode));
return;
}
}
printf("usage: %s <if_id>\n", argv[0]);
return;
}
static int _tm_idle(int argc, char **argv)
{
_set_test_mode(argc, argv, NETOPT_RF_TESTMODE_IDLE);
return 0;
}
static int _tm_crx(int argc, char **argv)
{
_set_test_mode(argc, argv, NETOPT_RF_TESTMODE_CRX);
return 0;
}
static int _tm_ctx_cw(int argc, char **argv)
{
_set_test_mode(argc, argv, NETOPT_RF_TESTMODE_CTX_CW);
return 0;
}
static int _tm_ctx_prbs9(int argc, char **argv)
{
_set_test_mode(argc, argv, NETOPT_RF_TESTMODE_CTX_PRBS9);
return 0;
}
static int _tm_ctx_preamble(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_PREAMBLE);
return 0;
}
static int _tm_ctx_2mhz(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_2MHZ);
return 0;
}
static int _tm_ctx_200khz(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_200KHZ);
return 0;
}
static int _tm_ctx_1mbps_prbs9(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_1MBPS_PRBS9);
return 0;
}
static int _tm_ctx_ext(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_EXT);
return 0;
}
static int _tm_ctx_nm0(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_NM0);
return 0;
}
static int _tm_ctx_nm1(int argc, char **argv)
{
_set_test_mode(argc, argv, KW2XRF_TM_CTX_NM1);
return 0;
}
#endif
static const shell_command_t shell_commands[] = {
#ifdef KW2XRF_TESTMODE
{ "idle", "xcvr idle mode", _tm_idle },
{ "ctx_prbs9", "continues transmit the prbs9 pattern", _tm_ctx_prbs9 },
{ "crx", "continues receive mode, useful for current measuring", _tm_crx },
{ "ctx_preamble", "continues transmit the 10101010 pattern", _tm_ctx_preamble },
{ "ctx_cw", "continues transmit carrier wave", _tm_ctx_cw },
{ "ctx_2mhz", "continues transmit modulated carrier", _tm_ctx_2mhz },
{ "ctx_200khz", "continues transmit modulated carrier", _tm_ctx_200khz },
{ "ctx_1mbps_prbs9", "continues transmit the prbs9 pattern", _tm_ctx_1mbps_prbs9 },
{ "ctx_ext", "continues transmit modulated carrier", _tm_ctx_ext },
{ "ctx_nm0", "continues transmit modulated carrier", _tm_ctx_nm0 },
{ "ctx_nm1", "continues transmit modulated carrier", _tm_ctx_nm1 },
#endif
{ NULL, NULL, NULL }
};
int main(void)
{
gnrc_netreg_entry_t dump = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
gnrc_pktdump_pid);
puts("KW2XRF device driver test");
/* register the pktdump thread */
puts("Register the packet dump thread for GNRC_NETTYPE_UNDEF packets");
gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump);
/* start the shell */
puts("Initialization successful - starting the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}