drivers: ieee802154: rf2xx: Add initial driver

Add initial Atmel at86rf2xx transceiver driver. This driver uses device
tree to configure the physical interface. The driver had capability to
use multiple transceiver and systems with multiple bands can be used.
With this, 2.4GHz ISM and Sub-Giga can be used simultaneous.

Below a valid DT example. This samples assume same SPI port with two
transceivers.

&spi0 {
    status = "okay";
    label = "SPI_RF2XX";
    cs-gpios = <&porta 31 0 &porta 30 0>;

    rf2xx@0 {
        compatible = "atmel,rf2xx";
        reg = <0x0>;
        label = "RF2XX_0";
        spi-max-frequency = <7800000>;
        irq-gpios = <&portb 2 0>;
        reset-gpios = <&porta 3 0>;
        slptr-gpios = <&portb 3 0>;
        status = "okay";
    };

    rf2xx@1 {
        compatible = "atmel,rf2xx";
        reg = <0x1>;
        label = "RF2XX_1";
        spi-max-frequency = <7800000>;
        irq-gpios = <&portb 4 0>;
        reset-gpios = <&porta 4 0>;
        slptr-gpios = <&portb 4 0>;
        status = "okay";
    };
};

At the moment driver assume two transceiver are enouth for majority of
appications. Sub-Giga band will be enabled in future.

Signed-off-by: Gerson Fernando Budke <nandojve@gmail.com>
This commit is contained in:
Gerson Fernando Budke 2019-10-24 19:59:35 -03:00 committed by Jukka Rissanen
commit 67289d07fe
8 changed files with 1694 additions and 0 deletions

View file

@ -7,6 +7,8 @@ zephyr_sources_ifdef(CONFIG_IEEE802154_MCR20A ieee802154_mcr20a.c)
zephyr_sources_ifdef(CONFIG_IEEE802154_NRF5 ieee802154_nrf5.c) zephyr_sources_ifdef(CONFIG_IEEE802154_NRF5 ieee802154_nrf5.c)
zephyr_sources_ifdef(CONFIG_IEEE802154_CC1200 ieee802154_cc1200.c) zephyr_sources_ifdef(CONFIG_IEEE802154_CC1200 ieee802154_cc1200.c)
zephyr_sources_ifdef(CONFIG_IEEE802154_CC13XX_CC26XX ieee802154_cc13xx_cc26xx.c) zephyr_sources_ifdef(CONFIG_IEEE802154_CC13XX_CC26XX ieee802154_cc13xx_cc26xx.c)
zephyr_sources_ifdef(CONFIG_IEEE802154_RF2XX ieee802154_rf2xx.c)
zephyr_sources_ifdef(CONFIG_IEEE802154_RF2XX ieee802154_rf2xx_iface.c)
if(CONFIG_NET_L2_OPENTHREAD) if(CONFIG_NET_L2_OPENTHREAD)
# This driver calls DEVICE_INIT with the context of openthread. The # This driver calls DEVICE_INIT with the context of openthread. The

View file

@ -33,6 +33,8 @@ source "drivers/ieee802154/Kconfig.cc1200"
source "drivers/ieee802154/Kconfig.cc13xx_cc26xx" source "drivers/ieee802154/Kconfig.cc13xx_cc26xx"
source "drivers/ieee802154/Kconfig.rf2xx"
menuconfig IEEE802154_UPIPE menuconfig IEEE802154_UPIPE
bool "UART PIPE fake radio driver support for QEMU" bool "UART PIPE fake radio driver support for QEMU"
depends on (BOARD_QEMU_X86 || BOARD_QEMU_CORTEX_M3) && NETWORKING depends on (BOARD_QEMU_X86 || BOARD_QEMU_CORTEX_M3) && NETWORKING

View file

@ -0,0 +1,40 @@
# Kconfig.rf2xx - ATMEL AT86RF23x/212x configuration options
#
#
# Copyright (c) 2019 Gerson Fernando Budke
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig IEEE802154_RF2XX
bool "ATMEL RF2XX Driver support"
depends on NETWORKING
select SPI
select NET_L2_IEEE802154_SUB_GHZ
if IEEE802154_RF2XX
config IEEE802154_RF2XX_DRV_NAME
string "ATMEL RF2XX Driver's name"
default "IEEE802154_rf2xx"
help
This option sets the driver name
config IEEE802154_RF2XX_RX_STACK_SIZE
int "Driver's internal RX thread stack size"
default 800
help
This option sets the driver's stack size for its internal RX thread.
The default value should be sufficient, but in case it proves to be
a too little one, this option makes it easy to play with the size.
config IEEE802154_RF2XX_INIT_PRIO
int "RF2X initialization priority"
default 80
help
Set the initialization priority number. Do not mess with it unless
you know what you are doing. Beware rf2xx requires gpio and spi to
be ready first (and sometime gpio should be the very first as spi
might need it too). And of course it has to start before the net stack.
endif

View file

@ -0,0 +1,859 @@
/* ieee802154_rf2xx.c - ATMEL RF2XX IEEE 802.15.4 Driver */
/*
* Copyright (c) 2019 Gerson Fernando Budke
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_MODULE_NAME ieee802154_rf2xx
#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <errno.h>
#include <assert.h>
#include <stdio.h>
#include <kernel.h>
#include <arch/cpu.h>
#include <device.h>
#include <init.h>
#include <net/net_if.h>
#include <net/net_pkt.h>
#include <sys/byteorder.h>
#include <string.h>
#include <random/rand32.h>
#include <linker/sections.h>
#include <sys/atomic.h>
#include <drivers/spi.h>
#include <drivers/gpio.h>
#include <net/ieee802154_radio.h>
#include "ieee802154_rf2xx.h"
#include "ieee802154_rf2xx_regs.h"
#include "ieee802154_rf2xx_iface.h"
#define RF2XX_OT_PSDU_LENGTH 1280
/* Radio Transceiver ISR */
static inline void trx_isr_handler(struct device *port,
struct gpio_callback *cb,
u32_t pins)
{
struct rf2xx_context *ctx = CONTAINER_OF(cb,
struct rf2xx_context,
irq_cb);
ARG_UNUSED(port);
ARG_UNUSED(pins);
k_sem_give(&ctx->trx_isr_lock);
}
static void trx_isr_timeout(struct k_timer *timer_id)
{
struct rf2xx_context *ctx = (struct rf2xx_context *)
k_timer_user_data_get(timer_id);
k_mutex_lock(&ctx->phy_mutex, K_FOREVER);
ctx->trx_state = RF2XX_TRX_PHY_STATE_IDLE;
k_mutex_unlock(&ctx->phy_mutex);
}
static void rf2xx_trx_set_state(struct device *dev,
enum rf2xx_trx_state_cmd_t state)
{
do {
rf2xx_iface_reg_write(dev, RF2XX_TRX_STATE_REG,
RF2XX_TRX_PHY_STATE_CMD_FORCE_TRX_OFF);
} while (RF2XX_TRX_PHY_STATUS_TRX_OFF !=
(rf2xx_iface_reg_read(dev, RF2XX_TRX_STATUS_REG) &
RF2XX_TRX_PHY_STATUS_MASK));
do {
rf2xx_iface_reg_write(dev, RF2XX_TRX_STATE_REG, state);
} while (state !=
(rf2xx_iface_reg_read(dev, RF2XX_TRX_STATUS_REG) &
RF2XX_TRX_PHY_STATUS_MASK));
}
static void rf2xx_trx_set_rx_state(struct device *dev)
{
rf2xx_trx_set_state(dev, RF2XX_TRX_PHY_STATE_CMD_TRX_OFF);
rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG);
/**
* Set extended RX mode
* Datasheet: chapter 7.2 Extended Operating Mode
*/
rf2xx_trx_set_state(dev, RF2XX_TRX_PHY_STATE_CMD_RX_AACK_ON);
}
static void rf2xx_trx_rx(struct device *dev)
{
struct rf2xx_context *ctx = dev->driver_data;
struct net_pkt *pkt = NULL;
u8_t rx_buf[RX2XX_MAX_FRAME_SIZE];
u8_t pkt_len;
u8_t frame_len;
u8_t trac;
/*
* The rf2xx frame buffer can have length > 128 bytes. The
* net_pkt_alloc_with_buffer allocates max value of 128 bytes.
*
* This obligate the driver to have rx_buf statically allocated with
* RX2XX_MAX_FRAME_SIZE.
*/
rf2xx_iface_frame_read(dev, rx_buf, RX2XX_FRAME_HEADER_SIZE);
pkt_len = rx_buf[RX2XX_FRAME_PHR_INDEX];
if (pkt_len < RX2XX_FRAME_MIN_PHR_SIZE) {
LOG_ERR("invalid RX frame length");
return;
}
frame_len = RX2XX_FRAME_HEADER_SIZE + pkt_len +
RX2XX_FRAME_FOOTER_SIZE;
rf2xx_iface_frame_read(dev, rx_buf, frame_len);
trac = rx_buf[pkt_len + RX2XX_FRAME_TRAC_INDEX];
trac = (trac >> RF2XX_RX_TRAC_STATUS) & RF2XX_RX_TRAC_BIT_MASK;
if (trac == RF2XX_TRX_PHY_STATE_TRAC_INVALID) {
LOG_ERR("invalid RX frame");
return;
}
ctx->pkt_lqi = rx_buf[pkt_len + RX2XX_FRAME_LQI_INDEX];
ctx->pkt_ed = rx_buf[pkt_len + RX2XX_FRAME_ED_INDEX];
if (!IS_ENABLED(CONFIG_IEEE802154_RAW_MODE) &&
!IS_ENABLED(CONFIG_NET_L2_OPENTHREAD)) {
pkt_len -= RX2XX_FRAME_FCS_LENGTH;
}
pkt = net_pkt_alloc_with_buffer(ctx->iface, pkt_len,
AF_UNSPEC, 0, K_NO_WAIT);
if (!pkt) {
LOG_ERR("No buf available");
return;
}
memcpy(pkt->buffer->data, rx_buf + RX2XX_FRAME_HEADER_SIZE, pkt_len);
net_buf_add(pkt->buffer, pkt_len);
net_pkt_set_ieee802154_lqi(pkt, ctx->pkt_lqi);
net_pkt_set_ieee802154_rssi(pkt, ctx->pkt_ed + ctx->trx_rssi_base);
LOG_DBG("Caught a packet (%02X) (LQI: %02X, RSSI: %d, ED: %02X)",
pkt_len, ctx->pkt_lqi, ctx->trx_rssi_base + ctx->pkt_ed,
ctx->pkt_ed);
if (net_recv_data(ctx->iface, pkt) < 0) {
LOG_DBG("Packet dropped by NET stack");
net_pkt_unref(pkt);
return;
}
if (LOG_LEVEL >= LOG_LEVEL_DBG) {
net_analyze_stack("RF2XX Rx stack",
Z_THREAD_STACK_BUFFER(ctx->trx_stack),
K_THREAD_STACK_SIZEOF(ctx->trx_stack));
}
}
static void rf2xx_thread_main(void *arg)
{
struct device *dev = INT_TO_POINTER(arg);
struct rf2xx_context *ctx = dev->driver_data;
u8_t isr_status;
while (true) {
k_sem_take(&ctx->trx_isr_lock, K_FOREVER);
k_mutex_lock(&ctx->phy_mutex, K_FOREVER);
isr_status = rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG);
/*
* IRQ_7 (BAT_LOW) Indicates a supply voltage below the
* programmed threshold. 9.5.4
* IRQ_6 (TRX_UR) Indicates a Frame Buffer access
* violation. 9.3.3
* IRQ_5 (AMI) Indicates address matching. 8.2
* IRQ_4 (CCA_ED_DONE) Multi-functional interrupt:
* 1. AWAKE_END: 7.1.2.5
* Indicates finished transition to TRX_OFF state
* from P_ON, SLEEP, DEEP_SLEEP, or RESET state.
* 2. CCA_ED_DONE: 8.5.4
* Indicates the end of a CCA or ED
* measurement. 8.6.4
* IRQ_3 (TRX_END)
* RX: Indicates the completion of a frame
* reception. 7.1.3
* TX: Indicates the completion of a frame
* transmission. 7.1.3
* IRQ_2 (RX_START) Indicates the start of a PSDU
* reception; the AT86RF233 state changed to BUSY_RX;
* the PHR can be read from Frame Buffer. 7.1.3
* IRQ_1 (PLL_UNLOCK) Indicates PLL unlock. If the radio
* transceiver is in BUSY_TX / BUSY_TX_ARET state, the
* PA is turned off immediately. 9.7.5
* IRQ_0 (PLL_LOCK) Indicates PLL lock.
*/
if (isr_status & (1 << RF2XX_RX_START)) {
ctx->trx_state = RF2XX_TRX_PHY_BUSY_RX;
k_timer_start(&ctx->trx_isr_timeout, K_MSEC(10), 0);
} else if (isr_status & (1 << RF2XX_TRX_END)) {
if (ctx->trx_state == RF2XX_TRX_PHY_BUSY_RX) {
/* Set PLL_ON to avoid transceiver receive
* new data until finish reading process
*/
rf2xx_trx_set_state(dev,
RF2XX_TRX_PHY_STATE_CMD_PLL_ON);
k_timer_stop(&ctx->trx_isr_timeout);
rf2xx_trx_rx(dev);
rf2xx_trx_set_state(dev,
RF2XX_TRX_PHY_STATE_CMD_RX_AACK_ON);
/*if (ctx->trx_state == RF2XX_TRX_PHY_BUSY_TX)*/
} else {
ctx->trx_trac =
(rf2xx_iface_reg_read(dev,
RF2XX_TRX_STATE_REG) >>
RF2XX_TRAC_STATUS) & 7;
k_sem_give(&ctx->trx_tx_sync);
rf2xx_trx_set_rx_state(dev);
}
ctx->trx_state = RF2XX_TRX_PHY_STATE_IDLE;
}
k_mutex_unlock(&ctx->phy_mutex);
}
}
static inline u8_t *get_mac(struct device *dev)
{
struct rf2xx_context *ctx = dev->driver_data;
u32_t *ptr = (u32_t *)(ctx->mac_addr);
UNALIGNED_PUT(sys_rand32_get(), ptr);
ptr = (u32_t *)(ctx->mac_addr + 4);
UNALIGNED_PUT(sys_rand32_get(), ptr);
/*
* Clear bit 0 to ensure it isn't a multicast address and set
* bit 1 to indicate address is locally administrered and may
* not be globally unique.
*/
ctx->mac_addr[0] = (ctx->mac_addr[0] & ~0x01) | 0x02;
return ctx->mac_addr;
}
static enum ieee802154_hw_caps rf2xx_get_capabilities(struct device *dev)
{
ARG_UNUSED(dev);
return IEEE802154_HW_FCS |
IEEE802154_HW_PROMISC |
IEEE802154_HW_FILTER |
IEEE802154_HW_CSMA |
IEEE802154_HW_TX_RX_ACK |
IEEE802154_HW_2_4_GHZ;
}
static int rf2xx_cca(struct device *dev)
{
ARG_UNUSED(dev);
return 0;
}
static int rf2xx_set_channel(struct device *dev, u16_t channel)
{
u8_t reg;
if (channel < 11 || channel > 26) {
LOG_ERR("Unsupported channel %u", channel);
return -EINVAL;
}
reg = rf2xx_iface_reg_read(dev, RF2XX_PHY_CC_CCA_REG) & ~0x1f;
rf2xx_iface_reg_write(dev, RF2XX_PHY_CC_CCA_REG, reg | channel);
return 0;
}
static int rf2xx_set_txpower(struct device *dev, s16_t dbm)
{
u8_t reg;
ARG_UNUSED(dbm);
/* TODO: Add look-up table
* Now will max power
*/
reg = rf2xx_iface_reg_read(dev, RF2XX_PHY_TX_PWR_REG) & ~0x0f;
rf2xx_iface_reg_write(dev, RF2XX_PHY_TX_PWR_REG, reg);
return 0;
}
static int rf2xx_set_ieee_addr(struct device *dev, bool set,
const u8_t *ieee_addr)
{
const u8_t *ptr_to_reg = ieee_addr;
LOG_DBG("IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
ieee_addr[7], ieee_addr[6], ieee_addr[5], ieee_addr[4],
ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]);
if (set) {
for (u8_t i = 0; i < 8; i++, ptr_to_reg++) {
rf2xx_iface_reg_write(dev, (RF2XX_IEEE_ADDR_0_REG + i),
*ptr_to_reg);
}
} else {
for (u8_t i = 0; i < 8; i++) {
rf2xx_iface_reg_write(dev, (RF2XX_IEEE_ADDR_0_REG + i),
0);
}
}
return 0;
}
static int rf2xx_set_short_addr(struct device *dev, bool set,
u16_t short_addr)
{
u8_t short_addr_le[2] = { 0xFF, 0xFF };
if (set) {
sys_put_le16(short_addr, short_addr_le);
}
rf2xx_iface_reg_write(dev, RF2XX_SHORT_ADDR_0_REG, short_addr_le[0]);
rf2xx_iface_reg_write(dev, RF2XX_SHORT_ADDR_1_REG, short_addr_le[1]);
rf2xx_iface_reg_write(dev, RF2XX_CSMA_SEED_0_REG,
short_addr_le[0] + short_addr_le[1]);
LOG_DBG("Short Address: 0x%02X%02X", short_addr_le[1],
short_addr_le[0]);
return 0;
}
static int rf2xx_set_pan_id(struct device *dev, bool set, u16_t pan_id)
{
u8_t pan_id_le[2] = { 0xFF, 0xFF };
if (set) {
sys_put_le16(pan_id, pan_id_le);
}
rf2xx_iface_reg_write(dev, RF2XX_PAN_ID_0_REG, pan_id_le[0]);
rf2xx_iface_reg_write(dev, RF2XX_PAN_ID_1_REG, pan_id_le[1]);
LOG_DBG("Pan Id: 0x%02X%02X", pan_id_le[1], pan_id_le[0]);
return 0;
}
static int rf2xx_filter(struct device *dev,
bool set, enum ieee802154_filter_type type,
const struct ieee802154_filter *filter)
{
LOG_DBG("Applying filter %u", type);
if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) {
return rf2xx_set_ieee_addr(dev, set, filter->ieee_addr);
} else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) {
return rf2xx_set_short_addr(dev, set, filter->short_addr);
} else if (type == IEEE802154_FILTER_TYPE_PAN_ID) {
return rf2xx_set_pan_id(dev, set, filter->pan_id);
}
return -ENOTSUP;
}
static int rf2xx_tx(struct device *dev,
struct net_pkt *pkt,
struct net_buf *frag)
{
struct rf2xx_context *ctx = dev->driver_data;
bool abort = true;
int response;
k_mutex_lock(&ctx->phy_mutex, K_FOREVER);
/* Reset semaphore in case ACK was received after timeout */
k_sem_reset(&ctx->trx_tx_sync);
if (ctx->trx_state == RF2XX_TRX_PHY_STATE_IDLE) {
ctx->trx_state = RF2XX_TRX_PHY_BUSY_TX;
abort = false;
/**
* Set extended TX mode
* Datasheet: chapter 7.2 Extended Operating Mode
*/
rf2xx_trx_set_state(dev, RF2XX_TRX_PHY_STATE_CMD_TX_ARET_ON);
rf2xx_iface_reg_read(dev, RF2XX_IRQ_STATUS_REG);
rf2xx_iface_frame_write(dev, frag->data, frag->len);
rf2xx_iface_phy_tx_start(dev);
}
k_mutex_unlock(&ctx->phy_mutex);
if (abort) {
LOG_DBG("TX Abort, TRX isn't idle!");
return -EBUSY;
}
/**
* Wait transceiver...
*/
k_sem_take(&ctx->trx_tx_sync, K_FOREVER);
switch (ctx->trx_trac) {
/* Channel is still busy after attempting MAX_CSMA_RETRIES of
* CSMA-CA
*/
case RF2XX_TRX_PHY_STATE_TRAC_CHANNEL_ACCESS_FAILED:
response = -EBUSY;
break;
/* No acknowledgment frames were received during all retry
* attempts
*/
case RF2XX_TRX_PHY_STATE_TRAC_NO_ACK:
response = -EAGAIN;
break;
/* Transaction not yet finished */
case RF2XX_TRX_PHY_STATE_TRAC_INVALID:
response = -EINTR;
break;
/* RF2XX_TRX_PHY_STATE_TRAC_SUCCESS:
* The transaction was responded to by a valid ACK, or, if no
* ACK is requested, after a successful frame transmission.
*
* RF2XX_TRX_PHY_STATE_TRAC_SUCCESS_DATA_PENDING:
* Equivalent to SUCCESS and indicating that the Frame
* Pending bit (see Section 8.1.2.2) of the received
* acknowledgment frame was set.
*/
default:
response = 0;
}
return response;
}
static int rf2xx_start(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
struct rf2xx_context *ctx = dev->driver_data;
k_mutex_lock(&ctx->phy_mutex, K_FOREVER);
gpio_pin_enable_callback(ctx->irq_gpio, conf->irq.pin);
rf2xx_trx_set_rx_state(dev);
k_mutex_unlock(&ctx->phy_mutex);
return 0;
}
static int rf2xx_stop(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
struct rf2xx_context *ctx = dev->driver_data;
k_mutex_lock(&ctx->phy_mutex, K_FOREVER);
gpio_pin_disable_callback(ctx->irq_gpio, conf->irq.pin);
rf2xx_trx_set_state(dev, RF2XX_TRX_PHY_STATE_CMD_TRX_OFF);
k_mutex_unlock(&ctx->phy_mutex);
return 0;
}
int rf2xx_configure(struct device *dev, enum ieee802154_config_type type,
const struct ieee802154_config *config)
{
ARG_UNUSED(dev);
ARG_UNUSED(type);
ARG_UNUSED(config);
return 0;
}
static int power_on_and_setup(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
struct rf2xx_context *ctx = dev->driver_data;
u8_t config;
ctx->trx_state = RF2XX_TRX_PHY_STATE_IDLE;
rf2xx_iface_phy_rst(dev);
/* Sync transceiver state */
do {
rf2xx_iface_reg_write(dev, RF2XX_TRX_STATE_REG,
RF2XX_TRX_PHY_STATE_CMD_TRX_OFF);
} while (RF2XX_TRX_PHY_STATUS_TRX_OFF !=
(rf2xx_iface_reg_read(dev, RF2XX_TRX_STATUS_REG) &
RF2XX_TRX_PHY_STATUS_MASK));
/* get device identification */
ctx->trx_model = rf2xx_iface_reg_read(dev, RF2XX_PART_NUM_REG);
ctx->trx_version = rf2xx_iface_reg_read(dev, RF2XX_VERSION_NUM_REG);
/**
* Valid transceiver are:
* 231-Rev-A (Version 0x02)
* 232-Rev-A (Version 0x02)
* 233-Rev-A (Version 0x01) (Warning)
* 233-Rev-B (Version 0x02)
*/
if (ctx->trx_model != RF2XX_TRX_MODEL_231 &&
ctx->trx_model != RF2XX_TRX_MODEL_232 &&
ctx->trx_model != RF2XX_TRX_MODEL_233) {
LOG_DBG("Invalid or not supported transceiver");
return -ENODEV;
}
if (ctx->trx_version < 0x02) {
LOG_DBG("Transceiver is old and unstable release");
}
/* Set RSSI base */
if (ctx->trx_model == RF2XX_TRX_MODEL_233) {
ctx->trx_rssi_base = -94;
} else if (ctx->trx_model == RF2XX_TRX_MODEL_231) {
ctx->trx_rssi_base = -91;
} else {
ctx->trx_rssi_base = -90;
}
/* Configure PHY behaviour */
config = (1 << RF2XX_TX_AUTO_CRC_ON) |
(3 << RF2XX_SPI_CMD_MODE) |
(1 << RF2XX_IRQ_MASK_MODE);
rf2xx_iface_reg_write(dev, RF2XX_TRX_CTRL_1_REG, config);
config = (1 << RF2XX_RX_SAFE_MODE);
if (ctx->trx_model != RF2XX_TRX_MODEL_232) {
config |= (1 << RF2XX_OQPSK_SCRAM_EN);
}
rf2xx_iface_reg_write(dev, RF2XX_TRX_CTRL_2_REG, config);
/* Configure INT behaviour */
config = (1 << RF2XX_RX_START) |
(1 << RF2XX_TRX_END);
rf2xx_iface_reg_write(dev, RF2XX_IRQ_MASK_REG, config);
gpio_init_callback(&ctx->irq_cb, trx_isr_handler, BIT(conf->irq.pin));
gpio_add_callback(ctx->irq_gpio, &ctx->irq_cb);
return 0;
}
static inline int configure_gpios(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
struct rf2xx_context *ctx = dev->driver_data;
/* Chip IRQ line */
ctx->irq_gpio = device_get_binding(conf->irq.devname);
if (ctx->irq_gpio == NULL) {
LOG_ERR("Failed to get instance of %s device",
conf->irq.devname);
return -EINVAL;
}
gpio_pin_configure(ctx->irq_gpio, conf->irq.pin,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_PUD_PULL_DOWN | GPIO_INT_ACTIVE_HIGH);
/* Chip RESET line */
ctx->reset_gpio = device_get_binding(conf->reset.devname);
if (ctx->reset_gpio == NULL) {
LOG_ERR("Failed to get instance of %s device",
conf->reset.devname);
return -EINVAL;
}
gpio_pin_configure(ctx->reset_gpio, conf->reset.pin,
GPIO_DIR_OUT | GPIO_PUD_NORMAL | GPIO_POL_NORMAL);
/* Chip SLPTR line */
ctx->slptr_gpio = device_get_binding(conf->slptr.devname);
if (ctx->slptr_gpio == NULL) {
LOG_ERR("Failed to get instance of %s device",
conf->slptr.devname);
return -EINVAL;
}
gpio_pin_configure(ctx->slptr_gpio, conf->slptr.pin,
GPIO_DIR_OUT | GPIO_PUD_NORMAL | GPIO_POL_NORMAL);
/* Chip DIG2 line (Optional feature) */
ctx->dig2_gpio = device_get_binding(conf->dig2.devname);
if (ctx->dig2_gpio != NULL) {
LOG_INF("Optional instance of %s device activated",
conf->dig2.devname);
gpio_pin_configure(ctx->dig2_gpio, conf->dig2.pin,
GPIO_DIR_IN |
GPIO_PUD_PULL_DOWN |
GPIO_INT_ACTIVE_HIGH);
}
/* Chip CLKM line (Optional feature) */
ctx->clkm_gpio = device_get_binding(conf->clkm.devname);
if (ctx->clkm_gpio != NULL) {
LOG_INF("Optional instance of %s device activated",
conf->clkm.devname);
gpio_pin_configure(ctx->clkm_gpio, conf->clkm.pin,
GPIO_DIR_IN | GPIO_PUD_NORMAL);
}
return 0;
}
static inline int configure_spi(struct device *dev)
{
struct rf2xx_context *ctx = dev->driver_data;
const struct rf2xx_config *conf = dev->config->config_info;
/* Get SPI Driver Instance*/
ctx->spi = device_get_binding(conf->spi.devname);
if (!ctx->spi) {
LOG_ERR("Failed to get instance of %s device",
conf->spi.devname);
return -ENODEV;
}
/* Apply SPI Config: 8-bit, MSB First, MODE-0 */
ctx->spi_cfg.operation = SPI_WORD_SET(8) |
SPI_TRANSFER_MSB;
ctx->spi_cfg.slave = conf->spi.addr;
ctx->spi_cfg.frequency = conf->spi.freq;
ctx->spi_cfg.cs = NULL;
/*
* Get SPI Chip Select Instance
*
* This is an optinal feature configured on DTS. Some SPI controllers
* automatically set CS line by device slave address. Check your SPI
* device driver to understand if you need this option enabled.
*/
ctx->spi_cs.gpio_dev = device_get_binding(conf->spi.cs.devname);
if (ctx->spi_cs.gpio_dev) {
ctx->spi_cs.gpio_pin = conf->spi.cs.pin;
ctx->spi_cs.delay = 0U;
ctx->spi_cfg.cs = &ctx->spi_cs;
LOG_DBG("SPI GPIO CS configured on %s:%u",
conf->spi.cs.devname, conf->spi.cs.pin);
}
return 0;
}
static int rf2xx_init(struct device *dev)
{
struct rf2xx_context *ctx = dev->driver_data;
const struct rf2xx_config *conf = dev->config->config_info;
char thread_name[20];
LOG_DBG("\nInitialize RF2XX Transceiver\n");
k_mutex_init(&ctx->phy_mutex);
k_sem_init(&ctx->trx_tx_sync, 0, 1);
k_sem_init(&ctx->trx_isr_lock, 0, 1);
k_timer_init(&ctx->trx_isr_timeout, trx_isr_timeout, NULL);
k_timer_user_data_set(&ctx->trx_isr_timeout, ctx);
if (configure_gpios(dev) != 0) {
LOG_ERR("Configuring GPIOS failed");
return -EIO;
}
if (configure_spi(dev) != 0) {
LOG_ERR("Configuring SPI failed");
return -EIO;
}
LOG_DBG("GPIO and SPI configured");
if (power_on_and_setup(dev) != 0) {
LOG_ERR("Configuring RF2XX failed");
return -EIO;
}
k_thread_create(&ctx->trx_thread,
ctx->trx_stack,
CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE,
(k_thread_entry_t) rf2xx_thread_main,
dev, NULL, NULL,
K_PRIO_COOP(2), 0, K_NO_WAIT);
sprintf(thread_name, "802.15.4 main [%d]", conf->inst);
k_thread_name_set(&ctx->trx_thread, thread_name);
return 0;
}
static void rf2xx_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct rf2xx_context *ctx = dev->driver_data;
u8_t *mac = get_mac(dev);
net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154);
ctx->iface = iface;
ieee802154_init(iface);
}
static struct ieee802154_radio_api rf2xx_radio_api = {
.iface_api.init = rf2xx_iface_init,
.get_capabilities = rf2xx_get_capabilities,
.cca = rf2xx_cca,
.set_channel = rf2xx_set_channel,
.filter = rf2xx_filter,
.set_txpower = rf2xx_set_txpower,
.tx = rf2xx_tx,
.start = rf2xx_start,
.stop = rf2xx_stop,
.configure = rf2xx_configure,
};
#if !defined(CONFIG_IEEE802154_RAW_MODE)
#if defined(CONFIG_NET_L2_IEEE802154)
#define L2 IEEE802154_L2
#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(IEEE802154_L2)
#define MTU RF2XX_MAX_PSDU_LENGTH
#elif defined(CONFIG_NET_L2_OPENTHREAD)
#define L2 OPENTHREAD_L2
#define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2)
#define MTU RF2XX_OT_PSDU_LENGTH
#endif
#endif /* CONFIG_IEEE802154_RAW_MODE */
/*
* Optional features place holders
*/
#ifndef DT_INST_0_ATMEL_RF2XX_DIG2_GPIOS_CONTROLLER
#define DT_INST_0_ATMEL_RF2XX_DIG2_GPIOS_CONTROLLER 0
#define DT_INST_0_ATMEL_RF2XX_DIG2_GPIOS_PIN 0
#define DT_INST_0_ATMEL_RF2XX_DIG2_GPIOS_FLAGS 0
#endif
#ifndef DT_INST_1_ATMEL_RF2XX_DIG2_GPIOS_CONTROLLER
#define DT_INST_1_ATMEL_RF2XX_DIG2_GPIOS_CONTROLLER 0
#define DT_INST_1_ATMEL_RF2XX_DIG2_GPIOS_PIN 0
#define DT_INST_1_ATMEL_RF2XX_DIG2_GPIOS_FLAGS 0
#endif
#ifndef DT_INST_0_ATMEL_RF2XX_CLKM_GPIOS_CONTROLLER
#define DT_INST_0_ATMEL_RF2XX_CLKM_GPIOS_CONTROLLER 0
#define DT_INST_0_ATMEL_RF2XX_CLKM_GPIOS_PIN 0
#define DT_INST_0_ATMEL_RF2XX_CLKM_GPIOS_FLAGS 0
#endif
#ifndef DT_INST_1_ATMEL_RF2XX_CLKM_GPIOS_CONTROLLER
#define DT_INST_1_ATMEL_RF2XX_CLKM_GPIOS_CONTROLLER 0
#define DT_INST_1_ATMEL_RF2XX_CLKM_GPIOS_PIN 0
#define DT_INST_1_ATMEL_RF2XX_CLKM_GPIOS_FLAGS 0
#endif
#ifndef DT_INST_0_ATMEL_RF2XX_CS_GPIOS_CONTROLLER
#define DT_INST_0_ATMEL_RF2XX_CS_GPIOS_CONTROLLER 0
#define DT_INST_0_ATMEL_RF2XX_CS_GPIOS_PIN 0
#define DT_INST_0_ATMEL_RF2XX_CS_GPIOS_FLAGS 0
#endif
#ifndef DT_INST_1_ATMEL_RF2XX_CS_GPIOS_CONTROLLER
#define DT_INST_1_ATMEL_RF2XX_CS_GPIOS_CONTROLLER 0
#define DT_INST_1_ATMEL_RF2XX_CS_GPIOS_PIN 0
#define DT_INST_1_ATMEL_RF2XX_CS_GPIOS_FLAGS 0
#endif
#define IEEE802154_RF2XX_DEVICE_CONFIG(n) \
static const struct rf2xx_config rf2xx_ctx_config_##n = { \
.inst = n, \
\
.irq.devname = DT_INST_##n##_ATMEL_RF2XX_IRQ_GPIOS_CONTROLLER, \
.irq.pin = DT_INST_##n##_ATMEL_RF2XX_IRQ_GPIOS_PIN, \
.irq.flags = DT_INST_##n##_ATMEL_RF2XX_IRQ_GPIOS_FLAGS, \
\
.reset.devname = DT_INST_##n##_ATMEL_RF2XX_RESET_GPIOS_CONTROLLER, \
.reset.pin = DT_INST_##n##_ATMEL_RF2XX_RESET_GPIOS_PIN, \
.reset.flags = DT_INST_##n##_ATMEL_RF2XX_RESET_GPIOS_FLAGS, \
\
.slptr.devname = DT_INST_##n##_ATMEL_RF2XX_SLPTR_GPIOS_CONTROLLER, \
.slptr.pin = DT_INST_##n##_ATMEL_RF2XX_SLPTR_GPIOS_PIN, \
.slptr.flags = DT_INST_##n##_ATMEL_RF2XX_SLPTR_GPIOS_FLAGS, \
\
.dig2.devname = DT_INST_##n##_ATMEL_RF2XX_DIG2_GPIOS_CONTROLLER, \
.dig2.pin = DT_INST_##n##_ATMEL_RF2XX_DIG2_GPIOS_PIN, \
.dig2.flags = DT_INST_##n##_ATMEL_RF2XX_DIG2_GPIOS_FLAGS, \
\
.clkm.devname = DT_INST_##n##_ATMEL_RF2XX_CLKM_GPIOS_CONTROLLER, \
.clkm.pin = DT_INST_##n##_ATMEL_RF2XX_CLKM_GPIOS_PIN, \
.clkm.flags = DT_INST_##n##_ATMEL_RF2XX_CLKM_GPIOS_FLAGS, \
\
.spi.devname = DT_INST_##n##_ATMEL_RF2XX_BUS_NAME, \
.spi.addr = DT_INST_##n##_ATMEL_RF2XX_BASE_ADDRESS, \
.spi.freq = DT_INST_##n##_ATMEL_RF2XX_SPI_MAX_FREQUENCY, \
.spi.cs.devname = DT_INST_##n##_ATMEL_RF2XX_CS_GPIOS_CONTROLLER, \
.spi.cs.pin = DT_INST_##n##_ATMEL_RF2XX_CS_GPIOS_PIN, \
.spi.cs.flags = DT_INST_##n##_ATMEL_RF2XX_CS_GPIOS_FLAGS, \
}
#define IEEE802154_RF2XX_DEVICE_DATA(n) \
static struct rf2xx_context rf2xx_ctx_data_##n = { \
.trx_state = RF2XX_TRX_PHY_STATE_INITIAL, \
}
#define IEEE802154_RF2XX_RAW_DEVICE_INIT(n) \
DEVICE_AND_API_INIT( \
rf2xx_##n, \
DT_INST_##n##_ATMEL_RF2XX_LABEL, \
&rf2xx_init, \
&rf2xx_ctx_data_##n, \
&rf2xx_ctx_config_##n, \
POST_KERNEL, \
CONFIG_IEEE802154_RF2XX_INIT_PRIO, \
&rf2xx_radio_api)
#define IEEE802154_RF2XX_NET_DEVICE_INIT(n) \
NET_DEVICE_INIT( \
rf2xx_##n, \
DT_INST_##n##_ATMEL_RF2XX_LABEL, \
&rf2xx_init, \
&rf2xx_ctx_data_##n, \
&rf2xx_ctx_config_##n, \
CONFIG_IEEE802154_RF2XX_INIT_PRIO, \
&rf2xx_radio_api, \
L2, \
L2_CTX_TYPE, \
MTU)
#if DT_INST_0_ATMEL_RF2XX
IEEE802154_RF2XX_DEVICE_CONFIG(0);
IEEE802154_RF2XX_DEVICE_DATA(0);
#if defined(CONFIG_IEEE802154_RAW_MODE)
IEEE802154_RF2XX_RAW_DEVICE_INIT(0);
#else
IEEE802154_RF2XX_NET_DEVICE_INIT(0);
#endif /* CONFIG_IEEE802154_RAW_MODE */
#endif
#if DT_INST_1_ATMEL_RF2XX
IEEE802154_RF2XX_DEVICE_CONFIG(1);
IEEE802154_RF2XX_DEVICE_DATA(1);
#if defined(CONFIG_IEEE802154_RAW_MODE)
IEEE802154_RF2XX_RAW_DEVICE_INIT(1);
#else
IEEE802154_RF2XX_NET_DEVICE_INIT(1);
#endif /* CONFIG_IEEE802154_RAW_MODE */
#endif

View file

@ -0,0 +1,144 @@
/* ieee802154_rf2xx.h - IEEE 802.15.4 Driver definition for ATMEL RF2XX */
/*
* Copyright (c) 2019 Gerson Fernando Budke
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_H_
#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_H_
/* Runtime context structure
***************************
*/
enum rf2xx_trx_state_cmd_t {
RF2XX_TRX_PHY_STATE_CMD_NOP = 0x00,
RF2XX_TRX_PHY_STATE_CMD_TX_START = 0x02,
RF2XX_TRX_PHY_STATE_CMD_FORCE_TRX_OFF = 0x03,
RF2XX_TRX_PHY_STATE_CMD_FORCE_PLL_ON = 0x04,
RF2XX_TRX_PHY_STATE_CMD_RX_ON = 0x06,
RF2XX_TRX_PHY_STATE_CMD_TRX_OFF = 0x08,
RF2XX_TRX_PHY_STATE_CMD_PLL_ON = 0x09,
RF2XX_TRX_PHY_STATE_CMD_PREP_DEEP_SLEEP = 0x10,
RF2XX_TRX_PHY_STATE_CMD_RX_AACK_ON = 0x16,
RF2XX_TRX_PHY_STATE_CMD_TX_ARET_ON = 0x19,
/* Implemented by Software */
RF2XX_TRX_PHY_STATE_CMD_SLEEP = 0x0f,
RF2XX_TRX_PHY_STATE_CMD_DEEP_SLEEP = 0x20,
};
enum rf2xx_trx_state_status_t {
RF2XX_TRX_PHY_STATUS_P_ON = 0x00,
RF2XX_TRX_PHY_STATUS_BUSY_RX = 0x01,
RF2XX_TRX_PHY_STATUS_BUSY_TX = 0x02,
RF2XX_TRX_PHY_STATUS_RX_ON = 0x06,
RF2XX_TRX_PHY_STATUS_TRX_OFF = 0x08,
RF2XX_TRX_PHY_STATUS_PLL_ON = 0x09,
RF2XX_TRX_PHY_STATUS_SLEEP = 0x0f,
RF2XX_TRX_PHY_STATUS_BUSY_RX_AACK = 0x11,
RF2XX_TRX_PHY_STATUS_BUSY_TX_ARET = 0x12,
RF2XX_TRX_PHY_STATUS_RX_AACK_ON = 0x16,
RF2XX_TRX_PHY_STATUS_TX_ARET_ON = 0x19,
RF2XX_TRX_PHY_STATUS_RX_ON_NOCLK = 0x1c,
RF2XX_TRX_PHY_STATUS_RX_AACK_ON_NOCLK = 0x1d,
RF2XX_TRX_PHY_STATUS_BUSY_RX_AACK_NOCLK = 0x1e,
RF2XX_TRX_PHY_STATUS_STATE_TRANSITION = 0x1f,
RF2XX_TRX_PHY_STATUS_MASK = 0x1f
};
/**
* TRAC STATE RX_AACK TX_ARET
* SUCCESS X X
* SUCCESS_DATA_PENDING X
* SUCCESS_WAIT_FOR_ACK X
* CHANNEL_ACCESS_FAILED X
* NO_ACK X
* INVALID X X
*/
enum rf2xx_trx_state_trac_t {
RF2XX_TRX_PHY_STATE_TRAC_SUCCESS = 0x00,
RF2XX_TRX_PHY_STATE_TRAC_SUCCESS_DATA_PENDING = 0x01,
RF2XX_TRX_PHY_STATE_TRAC_SUCCESS_WAIT_FOR_ACK = 0x02,
RF2XX_TRX_PHY_STATE_TRAC_CHANNEL_ACCESS_FAILED = 0x03,
RF2XX_TRX_PHY_STATE_TRAC_NO_ACK = 0x05,
RF2XX_TRX_PHY_STATE_TRAC_INVALID = 0x07,
};
enum rf2xx_trx_state_t {
RF2XX_TRX_PHY_STATE_INITIAL,
RF2XX_TRX_PHY_STATE_IDLE,
RF2XX_TRX_PHY_STATE_SLEEP,
RF2XX_TRX_PHY_BUSY_RX,
RF2XX_TRX_PHY_BUSY_TX,
};
enum rf2xx_trx_model_t {
RF2XX_TRX_MODEL_INV = 0x00,
RF2XX_TRX_MODEL_230 = 0x02,
RF2XX_TRX_MODEL_231 = 0x03,
RF2XX_TRX_MODEL_212 = 0x07,
RF2XX_TRX_MODEL_232 = 0x0A,
RF2XX_TRX_MODEL_233 = 0x0B,
};
struct rf2xx_dt_gpio_t {
const char *devname;
u32_t pin;
u32_t flags;
};
struct rf2xx_dt_spi_t {
const char *devname;
u32_t freq;
u32_t addr;
struct rf2xx_dt_gpio_t cs;
};
struct rf2xx_config {
u8_t inst;
struct rf2xx_dt_gpio_t irq;
struct rf2xx_dt_gpio_t reset;
struct rf2xx_dt_gpio_t slptr;
struct rf2xx_dt_gpio_t dig2;
struct rf2xx_dt_gpio_t clkm;
struct rf2xx_dt_spi_t spi;
};
struct rf2xx_context {
struct net_if *iface;
struct device *irq_gpio;
struct device *reset_gpio;
struct device *slptr_gpio;
struct device *dig2_gpio;
struct device *clkm_gpio;
struct device *spi;
struct spi_config spi_cfg;
struct spi_cs_control spi_cs;
struct gpio_callback irq_cb;
struct k_thread trx_thread;
K_THREAD_STACK_MEMBER(trx_stack,
CONFIG_IEEE802154_RF2XX_RX_STACK_SIZE);
struct k_sem trx_isr_lock;
struct k_sem trx_tx_sync;
struct k_timer trx_isr_timeout;
struct k_mutex phy_mutex;
enum rf2xx_trx_model_t trx_model;
enum rf2xx_trx_state_t trx_state;
enum rf2xx_trx_state_trac_t trx_trac;
u8_t mac_addr[8];
u8_t pkt_lqi;
u8_t pkt_ed;
s8_t trx_rssi_base;
u8_t trx_version;
};
#endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_H_ */

View file

@ -0,0 +1,250 @@
/* ieee802154_rf2xx_iface.c - ATMEL RF2XX IEEE 802.15.4 Interface */
/*
* Copyright (c) 2019 Gerson Fernando Budke
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_MODULE_NAME ieee802154_rf2xx_iface
#define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <errno.h>
#include <assert.h>
#include <device.h>
#include <drivers/spi.h>
#include <drivers/gpio.h>
#include "ieee802154_rf2xx.h"
#include "ieee802154_rf2xx_regs.h"
#include "ieee802154_rf2xx_iface.h"
void rf2xx_iface_phy_rst(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
const struct rf2xx_context *ctx = dev->driver_data;
/* Ensure control lines have correct levels. */
gpio_pin_write(ctx->reset_gpio, conf->reset.pin, 1);
gpio_pin_write(ctx->slptr_gpio, conf->slptr.pin, 0);
/* Wait typical time of timer TR1. */
k_busy_wait(330);
gpio_pin_write(ctx->reset_gpio, conf->reset.pin, 0);
k_busy_wait(10);
gpio_pin_write(ctx->reset_gpio, conf->reset.pin, 1);
}
void rf2xx_iface_phy_tx_start(struct device *dev)
{
const struct rf2xx_config *conf = dev->config->config_info;
const struct rf2xx_context *ctx = dev->driver_data;
/* Start TX transmission at rise edge */
gpio_pin_write(ctx->slptr_gpio, conf->slptr.pin, 1);
/* 16.125[μs] delay to detect signal */
k_busy_wait(20);
/* restore initial pin state */
gpio_pin_write(ctx->slptr_gpio, conf->slptr.pin, 0);
}
u8_t rf2xx_iface_reg_read(struct device *dev,
u8_t addr)
{
const struct rf2xx_context *ctx = dev->driver_data;
u8_t status;
u8_t regval = 0;
addr |= RF2XX_RF_CMD_REG_R;
const struct spi_buf tx_buf = {
.buf = &addr,
.len = 1
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
const struct spi_buf rx_buf[2] = {
{
.buf = &status,
.len = 1
},
{
.buf = &regval,
.len = 1
},
};
const struct spi_buf_set rx = {
.buffers = rx_buf,
.count = 2
};
if (spi_transceive(ctx->spi, &ctx->spi_cfg, &tx, &rx) != 0) {
LOG_ERR("Failed to exec rf2xx_reg_read CMD at address %d",
addr);
}
LOG_DBG("Read Address: %02X, PhyStatus: %02X, RegVal: %02X",
(addr & ~(RF2XX_RF_CMD_REG_R)), status, regval);
return regval;
}
void rf2xx_iface_reg_write(struct device *dev,
u8_t addr,
u8_t data)
{
const struct rf2xx_context *ctx = dev->driver_data;
u8_t status;
addr |= RF2XX_RF_CMD_REG_W;
const struct spi_buf tx_buf[2] = {
{
.buf = &addr,
.len = 1
},
{
.buf = &data,
.len = 1
}
};
const struct spi_buf_set tx = {
.buffers = tx_buf,
.count = 2
};
const struct spi_buf rx_buf = {
.buf = &status,
.len = 1
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1
};
if (spi_transceive(ctx->spi, &ctx->spi_cfg, &tx, &rx) != 0) {
LOG_ERR("Failed to exec rf2xx_reg_write at address %d",
addr);
}
LOG_DBG("Write Address: %02X, PhyStatus: %02X, RegVal: %02X",
(addr & ~(RF2XX_RF_CMD_REG_W)), status, data);
}
u8_t rf2xx_iface_bit_read(struct device *dev,
u8_t addr,
u8_t mask,
u8_t pos)
{
u8_t ret;
ret = rf2xx_iface_reg_read(dev, addr);
ret &= mask;
ret >>= pos;
return ret;
}
void rf2xx_iface_bit_write(struct device *dev,
u8_t reg_addr,
u8_t mask,
u8_t pos,
u8_t new_value)
{
u8_t current_reg_value;
current_reg_value = rf2xx_iface_reg_read(dev, reg_addr);
current_reg_value &= ~mask;
new_value <<= pos;
new_value &= mask;
new_value |= current_reg_value;
rf2xx_iface_reg_write(dev, reg_addr, new_value);
}
void rf2xx_iface_frame_read(struct device *dev,
u8_t *data,
u8_t length)
{
const struct rf2xx_context *ctx = dev->driver_data;
u8_t cmd = RF2XX_RF_CMD_FRAME_R;
const struct spi_buf tx_buf = {
.buf = &cmd,
.len = 1
};
const struct spi_buf_set tx = {
.buffers = &tx_buf,
.count = 1
};
const struct spi_buf rx_buf = {
.buf = data,
.len = length
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1
};
if (spi_transceive(ctx->spi, &ctx->spi_cfg, &tx, &rx) != 0) {
LOG_ERR("Failed to exec rf2xx_frame_read PHR");
}
LOG_DBG("Frame R: PhyStatus: %02X. length: %02X", data[0], length);
LOG_HEXDUMP_DBG(data + RX2XX_FRAME_HEADER_SIZE, length, "payload");
}
void rf2xx_iface_frame_write(struct device *dev,
u8_t *data,
u8_t length)
{
const struct rf2xx_context *ctx = dev->driver_data;
u8_t cmd = RF2XX_RF_CMD_FRAME_W;
u8_t status;
u8_t phr;
/* Sanity check */
if (length > 125) {
length = 125;
}
phr = length + RX2XX_FRAME_FCS_LENGTH;
const struct spi_buf tx_buf[3] = {
{
.buf = &cmd,
.len = 1
},
{
.buf = &phr, /* PHR */
.len = 1
},
{
.buf = data, /* PSDU */
.len = length
},
};
const struct spi_buf_set tx = {
.buffers = tx_buf,
.count = 3
};
const struct spi_buf rx_buf = {
.buf = &status,
.len = 1
};
const struct spi_buf_set rx = {
.buffers = &rx_buf,
.count = 1
};
if (spi_transceive(ctx->spi, &ctx->spi_cfg, &tx, &rx) != 0) {
LOG_ERR("Failed to exec rf2xx_frame_write");
}
LOG_DBG("Frame W: PhyStatus: %02X. length: %02X", status, length);
LOG_HEXDUMP_DBG(data, length, "payload");
}

View file

@ -0,0 +1,110 @@
/* ieee802154_rf2xx_iface.h - ATMEL RF2XX transceiver interface */
/*
* Copyright (c) 2019 Gerson Fernando Budke
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_IFACE_H_
#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_IFACE_H_
/**
* @brief Resets the TRX radio
*
* @param[in] dev Transceiver device instance
*/
void rf2xx_iface_phy_rst(struct device *dev);
/**
* @brief Start TX transmition
*
* @param[in] dev Transceiver device instance
*/
void rf2xx_iface_phy_tx_start(struct device *dev);
/**
* @brief Reads current value from a transceiver register
*
* This function reads the current value from a transceiver register.
*
* @param[in] dev Transceiver device instance
* @param[in] addr Specifies the address of the trx register
* from which the data shall be read
*
* @return value of the register read
*/
u8_t rf2xx_iface_reg_read(struct device *dev,
u8_t addr);
/**
* @brief Writes data into a transceiver register
*
* This function writes a value into transceiver register.
*
* @param[in] dev Transceiver device instance
* @param[in] addr Address of the trx register
* @param[in] data Data to be written to trx register
*
*/
void rf2xx_iface_reg_write(struct device *dev,
u8_t addr,
u8_t data);
/**
* @brief Subregister read
*
* @param[in] dev Transceiver device instance
* @param[in] addr offset of the register
* @param[in] mask bit mask of the subregister
* @param[in] pos bit position of the subregister
*
* @return value of the read bit(s)
*/
u8_t rf2xx_iface_bit_read(struct device *dev,
u8_t addr,
u8_t mask,
u8_t pos);
/**
* @brief Subregister write
*
* @param[in] dev Transceiver device instance
* @param[in] reg_addr Offset of the register
* @param[in] mask Bit mask of the subregister
* @param[in] pos Bit position of the subregister
* @param[out] new_value Data, which is muxed into the register
*/
void rf2xx_iface_bit_write(struct device *dev,
u8_t reg_addr,
u8_t mask,
u8_t pos,
u8_t new_value);
/**
* @brief Reads frame buffer of the transceiver
*
* This function reads the frame buffer of the transceiver.
*
* @param[in] dev Transceiver device instance
* @param[out] data Pointer to the location to store frame
* @param[in] length Number of bytes to be read from the frame
*/
void rf2xx_iface_frame_read(struct device *dev,
u8_t *data,
u8_t length);
/**
* @brief Writes data into frame buffer of the transceiver
*
* This function writes data into the frame buffer of the transceiver
*
* @param[in] dev Transceiver device instance
* @param[in] data Pointer to data to be written into frame buffer
* @param[in] length Number of bytes to be written into frame buffer
*/
void rf2xx_iface_frame_write(struct device *dev,
u8_t *data,
u8_t length);
#endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_IFACE_H_ */

View file

@ -0,0 +1,287 @@
/* ieee802154_rf2xx_regs.h - ATMEL RF2XX transceicer registers */
/*
* Copyright (c) 2019 Gerson Fernando Budke
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_REGS_H_
#define ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_REGS_H_
/*- Definitions ------------------------------------------------------------*/
#define RF2XX_AES_BLOCK_SIZE 16
#define RF2XX_AES_CORE_CYCLE_TIME 24 /* us */
#define RF2XX_RANDOM_NUMBER_UPDATE_INTERVAL 1 /* us */
#define RX2XX_FRAME_HEADER_SIZE 2
#define RX2XX_FRAME_FOOTER_SIZE 3
#define RX2XX_FRAME_FCS_LENGTH 2
#define RX2XX_FRAME_MIN_PHR_SIZE 5
#define RX2XX_FRAME_PHR_INDEX 1
#define RX2XX_FRAME_LQI_INDEX 2
#define RX2XX_FRAME_ED_INDEX 3
#define RX2XX_FRAME_TRAC_INDEX 4
#define RF2XX_MAX_PSDU_LENGTH 127
#define RX2XX_MAX_FRAME_SIZE 132
/*- Types ------------------------------------------------------------------*/
#define RF2XX_TRX_STATUS_REG 0x01
#define RF2XX_TRX_STATE_REG 0x02
#define RF2XX_TRX_CTRL_0_REG 0x03
#define RF2XX_TRX_CTRL_1_REG 0x04
#define RF2XX_PHY_TX_PWR_REG 0x05
#define RF2XX_PHY_RSSI_REG 0x06
#define RF2XX_PHY_ED_LEVEL_REG 0x07
#define RF2XX_PHY_CC_CCA_REG 0x08
#define RF2XX_CCA_THRES_REG 0x09
#define RF2XX_RX_CTRL_REG 0x0a
#define RF2XX_SFD_VALUE_REG 0x0b
#define RF2XX_TRX_CTRL_2_REG 0x0c
#define RF2XX_ANT_DIV_REG 0x0d
#define RF2XX_IRQ_MASK_REG 0x0e
#define RF2XX_IRQ_STATUS_REG 0x0f
#define RF2XX_VREG_CTRL_REG 0x10
#define RF2XX_BATMON_REG 0x11
#define RF2XX_XOSC_CTRL_REG 0x12
#define RF2XX_CC_CTRL_0_REG 0x13
#define RF2XX_CC_CTRL_1_REG 0x14
#define RF2XX_RX_SYN_REG 0x15
#define RF2XX_TRX_RPC_REG 0x16
#define RF2XX_RF_CTRL_0_REG 0x16
#define RF2XX_XAH_CTRL_1_REG 0x17
#define RF2XX_FTN_CTRL_REG 0x18
#define RF2XX_RF_CTRL_1_REG 0x19
#define RF2XX_XAH_CTRL_2_REG 0x19
#define RF2XX_PLL_CF_REG 0x1a
#define RF2XX_PLL_DCU_REG 0x1b
#define RF2XX_PART_NUM_REG 0x1c
#define RF2XX_VERSION_NUM_REG 0x1d
#define RF2XX_MAN_ID_0_REG 0x1e
#define RF2XX_MAN_ID_1_REG 0x1f
#define RF2XX_SHORT_ADDR_0_REG 0x20
#define RF2XX_SHORT_ADDR_1_REG 0x21
#define RF2XX_PAN_ID_0_REG 0x22
#define RF2XX_PAN_ID_1_REG 0x23
#define RF2XX_IEEE_ADDR_0_REG 0x24
#define RF2XX_IEEE_ADDR_1_REG 0x25
#define RF2XX_IEEE_ADDR_2_REG 0x26
#define RF2XX_IEEE_ADDR_3_REG 0x27
#define RF2XX_IEEE_ADDR_4_REG 0x28
#define RF2XX_IEEE_ADDR_5_REG 0x29
#define RF2XX_IEEE_ADDR_6_REG 0x2a
#define RF2XX_IEEE_ADDR_7_REG 0x2b
#define RF2XX_XAH_CTRL_0_REG 0x2c
#define RF2XX_CSMA_SEED_0_REG 0x2d
#define RF2XX_CSMA_SEED_1_REG 0x2e
#define RF2XX_CSMA_BE_REG 0x2f
#define RF2XX_TST_CTRL_DIGI_REG 0x36
#define RF2XX_PHY_TX_TIME_REG 0x3b
#define RF2XX_PHY_PMU_VALUE_REG 0x3b
#define RF2XX_TST_AGC_REG 0x3c
#define RF2XX_TST_SDM_REG 0x3d
#define RF2XX_AES_STATUS_REG 0x82
#define RF2XX_AES_CTRL_REG 0x83
#define RF2XX_AES_KEY_REG 0x84
#define RF2XX_AES_STATE_REG 0x84
#define RF2XX_AES_CTRL_M_REG 0x94
/* TRX_STATUS */
#define RF2XX_CCA_DONE 7
#define RF2XX_CCA_STATUS 6
#define RF2XX_TRX_STATUS 0
/* TRX_STATE */
#define RF2XX_TRAC_STATUS 5
#define RF2XX_TRX_CMD 0
/* TRX_CTRL_0 */
#define RF2XX_TOM_EN 7
#define RF2XX_PAD_IO 6
#define RF2XX_PAD_IO_CLKM 4
#define RF2XX_PMU_EN 4
#define RF2XX_PMU_IF_INVERSE 4
#define RF2XX_CLKM_SHA_SEL 3
#define RF2XX_CLKM_CTRL 0
/* TRX_CTRL_1 */
#define RF2XX_PA_EXT_EN 7
#define RF2XX_IRQ_2_EXT_EN 6
#define RF2XX_TX_AUTO_CRC_ON 5
#define RF2XX_RX_BL_CTRL 4
#define RF2XX_SPI_CMD_MODE 2
#define RF2XX_IRQ_MASK_MODE 1
#define RF2XX_IRQ_POLARITY 0
/* PHY_TX_PWR */
#define RF2XX_PA_BOOST 7
#define RF2XX_PA_BUF_LT 6
#define RF2XX_GC_PA 5
#define RF2XX_PA_SHR_LT 4
#define RF2XX_TX_PWR 0
/* PHY_RSSI */
#define RF2XX_RX_CRC_VALID 7
#define RF2XX_RND_VALUE 5
#define RF2XX_RSSI 0
/* PHY_CC_CCA */
#define RF2XX_CCA_REQUEST 7
#define RF2XX_CCA_MODE 5
#define RF2XX_CHANNEL 0
/* CCA_THRES */
#define RF2XX_CCA_CS_THRES 4
#define RF2XX_CCA_ED_THRES 0
/* RX_CTRL_REG */
#define RF2XX_PEL_SHIFT_VALUE 6
#define RF2XX_JCM_EN 5
#define RF2XX_PDT_THRES 0
/* TRX_CTRL_2 */
#define RF2XX_RX_SAFE_MODE 7
#define RF2XX_TRX_OFF_AVDD_EN 6
#define RF2XX_OQPSK_SCRAM_EN 5
#define RF2XX_OQPSK_SUB1_RC_EN 4
#define RF2XX_ALT_SPECTRUM 4
#define RF2XX_BPSK_OQPSK 3
#define RF2XX_SUB_MODE 2
#define RF2XX_OQPSK_DATA_RATE 0
/* ANT_DIV */
#define RF2XX_ANT_SEL 7
#define RF2XX_ANT_DIV_EN 3
#define RF2XX_ANT_EXT_SW_EN 2
#define RF2XX_ANT_CTRL 0
/* IRQ_MASK, IRQ_STATUS */
#define RF2XX_BAT_LOW 7
#define RF2XX_TRX_UR 6
#define RF2XX_AMI 5
#define RF2XX_CCA_ED_DONE 4
#define RF2XX_TRX_END 3
#define RF2XX_RX_START 2
#define RF2XX_PLL_UNLOCK 1
#define RF2XX_PLL_LOCK 0
/* VREG_CTRL */
#define RF2XX_AVREG_EXT 7
#define RF2XX_AVDD_OK 6
#define RF2XX_DVREG_EXT 3
#define RF2XX_DVDD_OK 2
/* BATMON */
#define RF2XX_PLL_LOCK_CP 7
#define RF2XX_BATMON_OK 5
#define RF2XX_BATMON_HR 4
#define RF2XX_BATMON_VTH 0
/* XOSC_CTRL */
#define RF2XX_XTAL_MODE 4
#define RF2XX_XTAL_TRIM 0
/* CC_CTRL_1 */
#define RF2XX_CC_BAND 0
/* RX_SYN */
#define RF2XX_RX_PDT_DIS 7
#define RF2XX_RX_OVERRIDE 4
#define RF2XX_RX_PDT_LEVEL 0
/* TRX_RPC */
#define RF2XX_RX_RPC_CTRL 6
#define RF2XX_RX_RPC_EN 5
#define RF2XX_PDT_RPC_EN 4
#define RF2XX_PLL_RPC_EN 3
#define RF2XX_XAH_TX_RPC_EN 2
#define RF2XX_IPAN_RPC_EN 1
/* RF_CTRL_0 */
#define RF2XX_PA_CHIP_LT 6
#define RF2XX_F_SHIFT_MODE 2
#define RF2XX_GC_TX_OFFS 0
/* XAH_CTRL_1 */
#define RF2XX_ARET_TX_TS_EN 7
#define RF2XX_CSMA_LBT_MODE 6
#define RF2XX_AACK_FLTR_RES_FT 5
#define RF2XX_AACK_UPLD_RES_FT 4
#define RF2XX_AACK_ACK_TIME 2
#define RF2XX_AACK_PROM_MODE 1
#define RF2XX_AACK_SPC_EN 0
/* FTN_CTRL */
#define RF2XX_FTN_START 7
#define RF2XX_FTNV 0
/* RF_CTRL_1 */
#define RF2XX_RF_MC 4
/* XAH_CTRL_2 */
#define RF2XX_ARET_FRAME_RETRIES 4
#define RF2XX_ARET_CSMA_RETRIES 1
/* PLL_CF */
#define RF2XX_PLL_CF_START 7
#define RF2XX_PLL_CF 0
/* PLL_DCU */
#define RF2XX_PLL_DCU_START 7
/* XAH_CTRL_0 */
#define RF2XX_MAX_FRAME_RETRES 4
#define RF2XX_MAX_CSMA_RETRES 1
#define RF2XX_SLOTTED_OPERATION 0
/* CSMA_SEED_1 */
#define RF2XX_AACK_FVN_MODE 6
#define RF2XX_AACK_SET_PD 5
#define RF2XX_AACK_DIS_ACK 4
#define RF2XX_AACK_I_AM_COORD 3
#define RF2XX_CSMA_SEED_1 0
/* CSMA_BE */
#define RF2XX_MAX_BE 4
#define RF2XX_MIN_BE 0
/* TST_CTRL_DIGI */
#define RF2XX_TST_CTRL_DIG 0
/* PHY_TX_TIME_REG */
#define RF2XX_IRC_TX_TIME 0
/* TST_AGC_REG */
#define RF2XX_AGC_HOLD_SEL 5
#define RF2XX_AGC_RST 4
#define RF2XX_AGC_OFF 3
#define RF2XX_AGC_HOLD 2
#define RF2XX_GC 0
/* TST_SDM_REG */
#define RF2XX_MOD_SEL 7
#define RF2XX_MOD 6
#define RF2XX_TX_RX 5
#define RF2XX_TX_RX_SEL 4
/* AES_CTRL */
#define RF2XX_AES_CTRL_DIR 3
#define RF2XX_AES_CTRL_MODE 4
#define RF2XX_AES_CTRL_REQUEST 7
/* AES_STATUS */
#define RF2XX_AES_STATUS_DONE 0
#define RF2XX_AES_STATUS_ER 7
#define RF2XX_RF_CMD_REG_W ((1 << 7) | (1 << 6))
#define RF2XX_RF_CMD_REG_R ((1 << 7) | (0 << 6))
#define RF2XX_RF_CMD_FRAME_W ((0 << 7) | (1 << 6) | (1 << 5))
#define RF2XX_RF_CMD_FRAME_R ((0 << 7) | (0 << 6) | (1 << 5))
#define RF2XX_RF_CMD_SRAM_W ((0 << 7) | (1 << 6) | (0 << 5))
#define RF2XX_RF_CMD_SRAM_R ((0 << 7) | (0 << 6) | (0 << 5))
/* RX_STATUS */
#define RF2XX_RX_TRAC_STATUS 4
#define RF2XX_RX_TRAC_BIT_MASK 0x03
#endif /* ZEPHYR_DRIVERS_IEEE802154_IEEE802154_RF2XX_REGS_H_ */