Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers/at86rf2xx: add support for ATmegaRF MCUs #12537

Merged
merged 5 commits into from Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpu/atmega128rfa1/Makefile.dep
Expand Up @@ -3,4 +3,8 @@ ifneq (,$(filter atmega_pcint,$(USEMODULE)))
USEMODULE += atmega_pcint1
endif

ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE)))
USEMODULE += at86rfa1
endif

include $(RIOTCPU)/atmega_common/Makefile.dep
4 changes: 4 additions & 0 deletions cpu/atmega256rfr2/Makefile.dep
Expand Up @@ -3,4 +3,8 @@ ifneq (,$(filter atmega_pcint,$(USEMODULE)))
USEMODULE += atmega_pcint1
endif

ifneq (,$(filter gnrc_netdev_default netdev_default,$(USEMODULE)))
USEMODULE += at86rfr2
endif

include $(RIOTCPU)/atmega_common/Makefile.dep
12 changes: 8 additions & 4 deletions drivers/Makefile.dep
Expand Up @@ -41,16 +41,20 @@ ifneq (,$(filter at30tse75x,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
endif

ifneq (,$(filter at86rf2%,$(USEMODULE)))
ifneq (,$(filter at86rf%,$(USEMODULE)))
USEMODULE += at86rf2xx
USEMODULE += xtimer
USEMODULE += luid
USEMODULE += netif
USEMODULE += ieee802154
USEMODULE += netdev_ieee802154
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_gpio_irq
FEATURES_REQUIRED += periph_spi

# only needed for SPI based variants
ifeq (,$(filter at86rfa1 at86rfr2,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_gpio_irq
FEATURES_REQUIRED += periph_spi
endif
endif

ifneq (,$(filter ata8520e,$(USEMODULE)))
Expand Down
59 changes: 42 additions & 17 deletions drivers/at86rf2xx/at86rf2xx.c
Expand Up @@ -42,13 +42,49 @@ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params)
netdev_t *netdev = (netdev_t *)dev;

netdev->driver = &at86rf2xx_driver;
/* initialize device descriptor */
dev->params = *params;
/* State to return after receiving or transmitting */
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
/* radio state is P_ON when first powered-on */
dev->state = AT86RF2XX_STATE_P_ON;
dev->pending_tx = 0;

#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
(void) params;
/* set all interrupts off */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, 0x00);
#else
/* initialize device descriptor */
dev->params = *params;
#endif
}

static void at86rf2xx_disable_clock_output(at86rf2xx_t *dev)
{
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
(void) dev;
#else
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_0);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL);
tmp |= (AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_0, tmp);
#endif
}

static void at86rf2xx_enable_smart_idle(at86rf2xx_t *dev)
{
#if AT86RF2XX_SMART_IDLE_LISTENING
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_RPC);
tmp |= (AT86RF2XX_TRX_RPC_MASK__RX_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__PDT_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__PLL_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__XAH_TX_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__IPAN_RPC_EN);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_RPC, tmp);
at86rf2xx_set_rxsensitivity(dev, RSSI_BASE_VAL);
#else
(void) dev;
#endif
}

void at86rf2xx_reset(at86rf2xx_t *dev)
Expand Down Expand Up @@ -92,29 +128,18 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
at86rf2xx_set_page(dev, AT86RF2XX_DEFAULT_PAGE);
#endif

#if !defined(MODULE_AT86RFA1) && !defined(MODULE_AT86RFR2)
/* don't populate masked interrupt flags to IRQ_STATUS register */
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_1);
tmp &= ~(AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_1, tmp);
#endif

/* configure smart idle listening feature */
#if AT86RF2XX_SMART_IDLE_LISTENING
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_RPC);
tmp |= (AT86RF2XX_TRX_RPC_MASK__RX_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__PDT_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__PLL_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__XAH_TX_RPC_EN |
AT86RF2XX_TRX_RPC_MASK__IPAN_RPC_EN);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_RPC, tmp);
at86rf2xx_set_rxsensitivity(dev, RSSI_BASE_VAL);
#endif
at86rf2xx_enable_smart_idle(dev);
maribu marked this conversation as resolved.
Show resolved Hide resolved

/* disable clock output to save power */
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_0);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL);
tmp &= ~(AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL);
tmp |= (AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF);
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_0, tmp);
at86rf2xx_disable_clock_output(dev);
maribu marked this conversation as resolved.
Show resolved Hide resolved

/* enable interrupts */
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK,
Expand Down
7 changes: 7 additions & 0 deletions drivers/at86rf2xx/at86rf2xx_getset.c
Expand Up @@ -522,7 +522,14 @@ uint8_t at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
/* Discard all IRQ flags, framebuffer is lost anyway */
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
/* Go to SLEEP mode from TRX_OFF */
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
/* reset interrupts states in device */
dev->irq_status = 0;
/* Setting SLPTR bit brings radio transceiver to sleep in in TRX_OFF*/
*AT86RF2XX_REG__TRXPR |= (AT86RF2XX_TRXPR_SLPTR);
#else
gpio_set(dev->params.sleep_pin);
#endif
dev->state = state;
}
else {
Expand Down
21 changes: 18 additions & 3 deletions drivers/at86rf2xx/at86rf2xx_internal.c
Expand Up @@ -21,12 +21,14 @@
* @}
*/

#include "periph/spi.h"
#include "periph/gpio.h"
#include "xtimer.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_registers.h"

#if !defined(MODULE_AT86RFA1) && !defined(MODULE_AT86RFR2)
#include "periph/spi.h"
#include "periph/gpio.h"

#define SPIDEV (dev->params.spi)
#define CSPIN (dev->params.cs_pin)

Expand Down Expand Up @@ -101,6 +103,8 @@ void at86rf2xx_fb_stop(const at86rf2xx_t *dev)
spi_release(SPIDEV);
}

#endif /* SPI based transceiver */

uint8_t at86rf2xx_get_status(const at86rf2xx_t *dev)
{
/* if sleeping immediately return state */
Expand All @@ -116,7 +120,13 @@ void at86rf2xx_assert_awake(at86rf2xx_t *dev)
{
if (at86rf2xx_get_status(dev) == AT86RF2XX_STATE_SLEEP) {
/* wake up and wait for transition to TRX_OFF */
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
/* Setting SLPTR bit in TRXPR to 0 returns the radio transceiver
* to the TRX_OFF state */
*AT86RF2XX_REG__TRXPR &= ~(AT86RF2XX_TRXPR_SLPTR);
#else
gpio_clear(dev->params.sleep_pin);
#endif
xtimer_usleep(AT86RF2XX_WAKEUP_DELAY);

/* update state: on some platforms, the timer behind xtimer
Expand All @@ -134,9 +144,14 @@ void at86rf2xx_assert_awake(at86rf2xx_t *dev)
void at86rf2xx_hardware_reset(at86rf2xx_t *dev)
{
/* trigger hardware reset */
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
/* set reset Bit */
*(AT86RF2XX_REG__TRXPR) |= AT86RF2XX_TRXPR_TRXRST;
#else
gpio_clear(dev->params.reset_pin);
xtimer_usleep(AT86RF2XX_RESET_PULSE_WIDTH);
gpio_set(dev->params.reset_pin);
#endif
xtimer_usleep(AT86RF2XX_RESET_DELAY);

/* update state: if the radio state was P_ON (initialization phase),
Expand Down Expand Up @@ -205,7 +220,7 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev)
at86rf2xx_set_state(dev, prev_state);
}

#if defined(MODULE_AT86RF233) || defined(MODULE_AT86RF231)
#if AT86RF2XX_RANDOM_NUMBER_GENERATOR
void at86rf2xx_get_random(const at86rf2xx_t *dev, uint8_t *data, size_t len)
maribu marked this conversation as resolved.
Show resolved Hide resolved
{
for (size_t byteCount = 0; byteCount < len; ++byteCount) {
Expand Down
99 changes: 95 additions & 4 deletions drivers/at86rf2xx/at86rf2xx_netdev.c
Expand Up @@ -19,6 +19,7 @@
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Josua Arndt <jarndt@ias.rwth-aachen.de>
*
* @}
*/
Expand Down Expand Up @@ -58,6 +59,10 @@ const netdev_driver_t at86rf2xx_driver = {
.set = _set,
};

#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
/* SOC has radio interrupts, store reference to netdev */
static netdev_t *at86rfmega_dev;
#else
static void _irq_handler(void *arg)
{
netdev_t *dev = (netdev_t *) arg;
Expand All @@ -66,11 +71,15 @@ static void _irq_handler(void *arg)
dev->event_callback(dev, NETDEV_EVENT_ISR);
}
}
#endif

static int _init(netdev_t *netdev)
{
at86rf2xx_t *dev = (at86rf2xx_t *)netdev;

#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
at86rfmega_dev = netdev;
#else
/* initialize GPIOs */
spi_init_cs(dev->params.spi, dev->params.cs_pin);
gpio_init(dev->params.sleep_pin, GPIO_OUT);
Expand All @@ -87,6 +96,7 @@ static int _init(netdev_t *netdev)
return -EIO;
}
spi_release(dev->params.spi);
#endif

/* test if the device is responding */
if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) != AT86RF2XX_PARTNUM) {
Expand Down Expand Up @@ -136,16 +146,20 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
size_t pkt_len;

/* frame buffer protection will be unlocked as soon as at86rf2xx_fb_stop() is called,
* Set receiver to PLL_ON state to be able to free the SPI bus and avoid loosing data. */
* Set receiver to PLL_ON state to be able to free the SPI bus and avoid losing data. */
at86rf2xx_set_state(dev, AT86RF2XX_STATE_PLL_ON);

/* start frame buffer access */
at86rf2xx_fb_start(dev);

/* get the size of the received packet */
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
phr = TST_RX_LENGTH;
#else
at86rf2xx_fb_read(dev, &phr, 1);
#endif

/* ignore MSB (refer p.80) and substract length of FCS field */
/* ignore MSB (refer p.80) and subtract length of FCS field */
pkt_len = (phr & 0x7f) - 2;

/* return length when buf == NULL */
Expand Down Expand Up @@ -184,7 +198,8 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
* AT86RF232 RSSI_BASE_VAL + ED, base -91dBm
* AT86RF233 RSSI_BASE_VAL + ED, base -94dBm
* AT86RF231 RSSI_BASE_VAL + ED, base -91dBm
* AT***RFR2 RSSI_BASE_VAL + ED, base -90dBm
* AT86RFA1 RSSI_BASE_VAL + ED, base -90dBm
* AT86RFR2 RSSI_BASE_VAL + ED, base -90dBm
*
* AT86RF231 MAN. p.92, 8.4.3 Data Interpretation
* AT86RF232 MAN. p.91, 8.4.3 Data Interpretation
Expand All @@ -200,7 +215,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
netdev_ieee802154_rx_info_t *radio_info = info;
at86rf2xx_fb_read(dev, &(radio_info->lqi), 1);

#if defined(MODULE_AT86RF231)
#if defined(MODULE_AT86RF231) || defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
/* AT86RF231 does not provide ED at the end of the frame buffer, read
* from separate register instead */
at86rf2xx_fb_stop(dev);
Expand Down Expand Up @@ -628,7 +643,12 @@ static void _isr(netdev_t *netdev)
}

/* read (consume) device status */
#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)
irq_mask = dev->irq_status;
dev->irq_status = 0;
#else
irq_mask = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
#endif

trac_status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATE)
& AT86RF2XX_TRX_STATE_MASK__TRAC;
Expand Down Expand Up @@ -699,3 +719,74 @@ static void _isr(netdev_t *netdev)
}
}
}

#if defined(MODULE_AT86RFA1) || defined(MODULE_AT86RFR2)

/**
* @brief ISR for transceiver's receive end interrupt
*
* Is triggered when valid data is received. FCS check passed.
* Save IRQ status and inform upper layer of data reception.
*
* Flow Diagram Manual p. 52 / 63
*/
ISR(TRX24_RX_END_vect, ISR_BLOCK)
{
__enter_isr();

uint8_t status = *AT86RF2XX_REG__TRX_STATE & AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS;
DEBUG("TRX24_RX_END 0x%x\n", status);

((at86rf2xx_t *)at86rfmega_dev)->irq_status |= AT86RF2XX_IRQ_STATUS_MASK__RX_END;
/* Call upper layer to process received data */
at86rfmega_dev->event_callback(at86rfmega_dev, NETDEV_EVENT_ISR);

__exit_isr();
}

/**
* @brief Transceiver Frame Address Match, indicates incoming frame
*
* Is triggered when Frame with valid Address is received.
* Can be used to wake up MCU from sleep, etc.
*
* Flow Diagram Manual p. 52 / 63
*/
ISR(TRX24_XAH_AMI_vect, ISR_BLOCK)
{
__enter_isr();

DEBUG("TRX24_XAH_AMI\n");
((at86rf2xx_t *)at86rfmega_dev)->irq_status |= AT86RF2XX_IRQ_STATUS_MASK__AMI;

__exit_isr();
}

/**
* @brief ISR for transceiver's transmit end interrupt
*
* Is triggered when data or when acknowledge frames where send.
*
* Flow Diagram Manual p. 52 / 63
*/
ISR(TRX24_TX_END_vect, ISR_BLOCK)
{
__enter_isr();

at86rf2xx_t *dev = (at86rf2xx_t *) at86rfmega_dev;
uint8_t status = *AT86RF2XX_REG__TRX_STATE & AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS;
DEBUG("TRX24_TX_END 0x%x\n", status);

/* only inform upper layer when a transmission was done,
* not for sending acknowledge frames if data was received. */
if (status != AT86RF2XX_STATE_RX_AACK_ON) {
dev->irq_status |= AT86RF2XX_IRQ_STATUS_MASK__TX_END;

/* Call upper layer to process if data was send successful */
at86rfmega_dev->event_callback(at86rfmega_dev, NETDEV_EVENT_ISR);
}

__exit_isr();
}

#endif /* MODULE_AT86RFA1 || MODULE_AT86RFR2 */