From df1eeb8e3fe13133c4e243629c8a926342395f76 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Fri, 3 Apr 2020 17:12:41 +0200 Subject: [PATCH] arch/arm/src/nrf52: add initial interface to work with on-chip radio --- arch/arm/src/nrf52/Kconfig | 1 + arch/arm/src/nrf52/Make.defs | 5 + arch/arm/src/nrf52/hardware/nrf52_radio.h | 53 +- arch/arm/src/nrf52/nrf52_radio.c | 1204 +++++++++++++++++++++ arch/arm/src/nrf52/nrf52_radio.h | 281 +++++ 5 files changed, 1526 insertions(+), 18 deletions(-) create mode 100644 arch/arm/src/nrf52/nrf52_radio.c create mode 100644 arch/arm/src/nrf52/nrf52_radio.h diff --git a/arch/arm/src/nrf52/Kconfig b/arch/arm/src/nrf52/Kconfig index 2c92c39b05..e2daee4c41 100644 --- a/arch/arm/src/nrf52/Kconfig +++ b/arch/arm/src/nrf52/Kconfig @@ -160,6 +160,7 @@ config NRF52_WDT config NRF52_RADIO bool "RADIO" + depends on EXPERIMENTAL default n config NRF52_NFCT diff --git a/arch/arm/src/nrf52/Make.defs b/arch/arm/src/nrf52/Make.defs index 5d3b9d7747..57fb504208 100644 --- a/arch/arm/src/nrf52/Make.defs +++ b/arch/arm/src/nrf52/Make.defs @@ -128,3 +128,8 @@ endif ifeq ($(CONFIG_NRF52_I2C_MASTER),y) CHIP_CSRCS += nrf52_i2c.c endif + +ifeq ($(CONFIG_NRF52_RADIO),y) +CHIP_CSRCS += nrf52_radio.c + +endif diff --git a/arch/arm/src/nrf52/hardware/nrf52_radio.h b/arch/arm/src/nrf52/hardware/nrf52_radio.h index f368bb2f64..b28d00f95f 100644 --- a/arch/arm/src/nrf52/hardware/nrf52_radio.h +++ b/arch/arm/src/nrf52/hardware/nrf52_radio.h @@ -428,6 +428,7 @@ #define RADIO_TXPOWER_SHIFT (0) /* Bits 0-7: RADIO output power */ #define RADIO_TXPOWER_MASK (0xff << RADIO_TXPOWER_SHIFT) +#define RADIO_TXPOWER_MAX (0xff) /* MODE Register */ @@ -445,34 +446,47 @@ #define RADIO_PCNF0_LFLEN_SHIFT (0) /* Bits 0-3: Length on air of LENGTH field in number of bits */ #define RADIO_PCNF0_LFLEN_MASK (0xf << RADIO_PCNF0_LFLEN_SHIFT) -#define RADIO_PCNF0_S0LEN (1 << 8) /* Bit 8: Length on air of S0 field in number of bytes */ +#define RADIO_PCNF0_LFLEN_MAX (0xf) +#define RADIO_PCNF0_S0LEN_SHIFT (8) /* Bit 8: Length on air of S0 field in number of bytes */ +#define RADIO_PCNF0_S0LEN_MASK (1 << RADIO_PCNF0_S0LEN_SHIFT) +#define RADIO_PCNF0_S0LEN_MAX (1) #define RADIO_PCNF0_S1LEN_SHIFT (16) /* Bits 16-19: Length on air of S1 field in number of bits */ #define RADIO_PCNF0_S1LEN_MASK (0xf << RADIO_PCNF0_S1LEN_SHIFT) +#define RADIO_PCNF0_S1LEN_MAX (0xf) #define RADIO_PCNF0_S1INCL (1 << 20) /* Bit 20: Include or exclude S1 field in RAM */ #define RADIO_PCNF0_CILEN_SHIFT (22) /* Bits 22-23: Length of code indicator - long range */ #define RADIO_PCNF0_CILEN_MASK (0x3 << RADIO_PCNF0_CILEN_SHIFT) +#define RADIO_PCNF0_CILEN_MAX (0x3) #define RADIO_PCNF0_PLEN_SHIFT (24) /* Bits 24-25: Length of preamble on air */ #define RADIO_PCNF0_PLEN_MASK (0x3 << RADIO_PCNF0_PLEN_SHIFT) # define RADIO_PCNF0_PLEN_8BIT (0 << RADIO_PCNF0_PLEN_SHIFT) # define RADIO_PCNF0_PLEN_16BIT (1 << RADIO_PCNF0_PLEN_SHIFT) # define RADIO_PCNF0_PLEN_32BITZ (2 << RADIO_PCNF0_PLEN_SHIFT) # define RADIO_PCNF0_PLEN_LONGRANGE (3 << RADIO_PCNF0_PLEN_SHIFT) -#define RADIO_PCNF0_CRCINC (1 << 26) /* Bit 26: Indicates if LENGTH field contains CRC */ +#define RADIO_PCNF0_CRCINC_SHIFT (26) /* Bit 26: Indicates if LENGTH field contains CRC */ +#define RADIO_PCNF0_CRCINC (1 << RADIO_PCNF0_CRCINC_SHIFT) #define RADIO_PCNF0_TERMLEN_SHIFT (29) /* Bits 29-30: Length of TERM field in Long Range operation */ #define RADIO_PCNF0_TERMLEN_MASK (0x3 << RADIO_PCNF0_TERMLEN_SHIFT) +#define RADIO_PCNF0_TERMLEN_MAX (0x3) /* PCNF1 Register */ #define RADIO_PCNF1_MAXLEN_SHIFT (0) /* Bits 0-7: Maximum length of packet payload */ #define RADIO_PCNF1_MAXLEN_MASK (0xff << RADIO_PCNF1_MAXLEN_SHIFT) +#define RADIO_PCNF1_MAXLEN_MAX (0xff) #define RADIO_PCNF1_STATLEN_SHIFT (8) /* Bits 8-15: Static length in number of bytes */ #define RADIO_PCNF1_STATLEN_MASK (0xff << RADIO_PCNF1_STATLEN_SHIFT) +#define RADIO_PCNF1_STATLEN_MAX (0xff) #define RADIO_PCNF1_BALEN_SHIFT (16) /* Bits 16-18: Base address length in number of bytes */ #define RADIO_PCNF1_BALEN_MASK (0x7 << RADIO_PCNF1_BALEN_SHIFT) -#define RADIO_PCNF1_ENDIAN (1 << 24) /* Bit 24: On air endianness of packet */ +#define RADIO_PCNF1_BALEN_MIN (0x2) +#define RADIO_PCNF1_BALEN_MAX (0x4) +#define RADIO_PCNF1_ENDIAN_SHIFT (24) /* Bit 24: On air endianness of packet */ +#define RADIO_PCNF1_ENDIAN (1 << RADIO_PCNF1_ENDIAN_SHIFT) # define RADIO_PCNF1_ENDIAN_LITTLE (0 << 24) /* Least significant bit on air first */ # define RADIO_PCNF1_ENDIAN_BITG (1 << 24) /* Most significant bit on air first */ -#define RADIO_PCNF1_WHITEEN (1 << 25) /* Bit 25: Enable or disable packet whitening */ +#define RADIO_PCNF1_WHITEEN_SHIFT (25) /* Bit 25: Enable or disable packet whitening */ +#define RADIO_PCNF1_WHITEEN (1 << RADIO_PCNF1_WHITEEN_SHIFT) /* TXADDRESS Register */ @@ -492,10 +506,10 @@ # define RADIO_CRCCNF_LEN_2 (2 << RADIO_CRCCNF_LEN_SHIFT) # define RADIO_CRCCNF_LEN_3 (3 << RADIO_CRCCNF_LEN_SHIFT) #define RADIO_CRCCNF_SKIPADDR_SHIFT (8) /* Bit 8-9: Include or exclude packet address field out of CRC calculation */ -#define RADIO_CRCCNF_SKIPADDR_MASK (0x3 << RADIO_CRCCNF_SKIPADDR_SHIFT) -# define RADIO_CRCCNF_SKIPADDR_INCL (0x3 << RADIO_CRCCNF_SKIPADDR_SHIFT) -# define RADIO_CRCCNF_SKIPADDR_SKIP (0x3 << RADIO_CRCCNF_SKIPADDR_SHIFT) -# define RADIO_CRCCNF_SKIPADDR_IEEE (0x3 << RADIO_CRCCNF_SKIPADDR_SHIFT) +#define RADIO_CRCCNF_SKIPADDR_MASK (0 << RADIO_CRCCNF_SKIPADDR_SHIFT) +# define RADIO_CRCCNF_SKIPADDR_INCL (1 << RADIO_CRCCNF_SKIPADDR_SHIFT) +# define RADIO_CRCCNF_SKIPADDR_SKIP (2 << RADIO_CRCCNF_SKIPADDR_SHIFT) +# define RADIO_CRCCNF_SKIPADDR_IEEE (3 << RADIO_CRCCNF_SKIPADDR_SHIFT) /* CRCPOLY Register */ @@ -511,6 +525,7 @@ #define RADIO_TIFS_SHIFT (0) /* Bits 0-9: Interframe spacing in μs */ #define RADIO_TIFS_MASK (0x3ff << RADIO_TIFS_SHIFT) +#define RADIO_TIFS_MAX (0x3ff) /* RSSISAMPLE Register */ @@ -520,21 +535,22 @@ /* STATE Register */ #define RADIO_STATE_SHIFT (0) /* Bits 0-2: Current radio state */ -#define RADIO_STATE_MASK (0xf << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_DISABLED (0 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_RXRU (1 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_RXIDLE (2 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_RX (3 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_RXDISABLE (4 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_TXRU (9 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_TXIDLE 10 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_TX (11 << RADIO_STATE_STATE_SHIFT) -# define RADIO_STATE_TXDISABLE (12 << RADIO_STATE_STATE_SHIFT) +#define RADIO_STATE_MASK (0xf << RADIO_STATE_SHIFT) +# define RADIO_STATE_DISABLED (0 << RADIO_STATE_SHIFT) +# define RADIO_STATE_RXRU (1 << RADIO_STATE_SHIFT) +# define RADIO_STATE_RXIDLE (2 << RADIO_STATE_SHIFT) +# define RADIO_STATE_RX (3 << RADIO_STATE_SHIFT) +# define RADIO_STATE_RXDISABLE (4 << RADIO_STATE_SHIFT) +# define RADIO_STATE_TXRU (9 << RADIO_STATE_SHIFT) +# define RADIO_STATE_TXIDLE (10 << RADIO_STATE_SHIFT) +# define RADIO_STATE_TX (11 << RADIO_STATE_SHIFT) +# define RADIO_STATE_TXDISABLE (12 << RADIO_STATE_SHIFT) /* DATAWHITEIV Register */ #define RADIO_DATAWHITEIV_SHIFT (0) /* Bits 0-6: Data whitening initial value */ #define RADIO_DATAWHITEIV_MASK (0x3f << RADIO_DATAWHITEIV_SHIFT) +#define RADIO_DATAWHITEIV_MAX (0x3f) /* DAP Register */ @@ -583,5 +599,6 @@ /* POWER Register */ #define RADIO_POWER_ENABLE (1 << 0) /* Bit 0: Peripheral power control */ +#define RADIO_POWER_DISABLE (0 << 0) /* Bit 0: Peripheral power control */ #endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_RADIO_H */ diff --git a/arch/arm/src/nrf52/nrf52_radio.c b/arch/arm/src/nrf52/nrf52_radio.c new file mode 100644 index 0000000000..5431c70724 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_radio.c @@ -0,0 +1,1204 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_radio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "up_arch.h" + +#include "nrf52_gpio.h" +#include "nrf52_radio.h" + +#include "hardware/nrf52_radio.h" + +#warning NRF52 RADIO support is EXPERIMENTAL! + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NRF52_RADIO_RXBUFFER (255) +#define NRF52_RADIO_TXBUFFER (255) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Radio registers access ***************************************************/ + +static void nrf52_radio_putreg(FAR struct nrf52_radio_dev_s *dev, + uint32_t offset, + uint32_t value); +static uint32_t nrf52_radio_getreg(FAR struct nrf52_radio_dev_s *dev, + uint32_t offset); + +/* Radio operations *********************************************************/ + +static int nrf52_radio_power(FAR struct nrf52_radio_dev_s *dev, bool state); +static int nrf52_radio_mode_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t mode); +static int nrf52_radio_freq_set(FAR struct nrf52_radio_dev_s *dev, + uint32_t freq); +static int nrf52_radio_rssi_get(FAR struct nrf52_radio_dev_s *dev, + FAR int *rssi); +static int nrf52_radio_txpower_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t txpower); +static int nrf52_radio_tifs_set(FAR struct nrf52_radio_dev_s *dev, + uint16_t us); +static int nrf52_radio_pkt_cfg(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_pktcfg_s *cfg); +static int nrf52_radio_crc_cfg(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_crc_s *cfg); +static int nrf52_radio_white_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t init); +static int nrf52_radio_addr_set(FAR struct nrf52_radio_dev_s *dev, uint8_t i, + FAR struct nrf52_radio_addr_s *addr); +static int nrf52_radio_write(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len); +static int nrf52_radio_read(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len); +static void nrf52_radio_dumpregs(FAR struct nrf52_radio_dev_s *dev); + +/* Radio interrupts *********************************************************/ + +static int nrf52_radio_isr(int irq, FAR void *context, FAR void *arg); +static int nrf52_radio_isr_rx(FAR struct nrf52_radio_dev_s *dev); +static int nrf52_radio_isr_tx(FAR struct nrf52_radio_dev_s *dev); + +/* Radio configuration ******************************************************/ + +static int nrf52_radio_setup(FAR struct nrf52_radio_dev_s *dev); +static int nrf52_radio_reset(FAR struct nrf52_radio_dev_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* NRF52 radio operations */ + +struct nrf52_radio_dev_s; +struct nrf52_radio_ops_s g_nrf52_radio_ops = +{ + .power = nrf52_radio_power, + .mode_set = nrf52_radio_mode_set, + .freq_set = nrf52_radio_freq_set, + .rssi_get = nrf52_radio_rssi_get, + .txpower_set = nrf52_radio_txpower_set, + .tifs_set = nrf52_radio_tifs_set, + .pkt_cfg = nrf52_radio_pkt_cfg, + .white_set = nrf52_radio_white_set, + .crc_cfg = nrf52_radio_crc_cfg, + .addr_set = nrf52_radio_addr_set, + .read = nrf52_radio_read, + .write = nrf52_radio_write, + .dumpregs = nrf52_radio_dumpregs +}; + +/* RX buffer 1 */ + +uint8_t g_nrf52_radio_dev_rx1[NRF52_RADIO_RXBUFFER]; + +/* TX buffer 1 */ + +uint8_t g_nrf52_radio_dev_tx1[NRF52_RADIO_TXBUFFER]; + +/* Radio device 1 */ + +struct nrf52_radio_dev_s g_nrf52_radio_dev_1 = +{ + .ops = &g_nrf52_radio_ops, + .irq = NRF52_IRQ_RADIO, + .base = NRF52_RADIO_BASE, + .mode = 0, + .rxbuf_len = NRF52_RADIO_RXBUFFER, + .txbuf_len = NRF52_RADIO_TXBUFFER, + .rxbuf = g_nrf52_radio_dev_rx1, + .txbuf = g_nrf52_radio_dev_tx1, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radio_putreg + * + * Description: + * Put register value + * + ****************************************************************************/ + +static void nrf52_radio_putreg(FAR struct nrf52_radio_dev_s *dev, + uint32_t offset, + uint32_t value) +{ + putreg32(value, dev->base + offset); +} + +/**************************************************************************** + * Name: nrf52_radio_getreg + * + * Description: + * Get register value + * + ****************************************************************************/ + +static uint32_t nrf52_radio_getreg(FAR struct nrf52_radio_dev_s *dev, + uint32_t offset) +{ + return getreg32(dev->base + offset); +} + +/**************************************************************************** + * Name: nrf52_radio_power + * + * Description: + * Power on/off radio + * + ****************************************************************************/ + +static int nrf52_radio_power(FAR struct nrf52_radio_dev_s *dev, bool state) +{ + DEBUGASSERT(dev); + + if (state == true) + { + /* Turn on radio */ + + nrf52_radio_putreg(dev, NRF52_RADIO_POWER_OFFSET, RADIO_POWER_ENABLE); + } + else + { + /* Turn off radio */ + + nrf52_radio_putreg(dev, NRF52_RADIO_POWER_OFFSET, RADIO_POWER_DISABLE); + } + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radio_mode_set + * + * Description: + * Set radio mode + * + ****************************************************************************/ + +static int nrf52_radio_mode_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t mode) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Change mode if needed */ + + if (dev->mode == mode) + { + goto errout; + } + + /* Check if mode is valid */ + + if (mode > NRF52_RADIO_MODE_IEEE802154) + { + wlerr("ERROR: unsupported RADIO mode %d\n", mode); + ret = -EINVAL; + goto errout; + } + + regval = (mode << RADIO_MODE_SHIFT); + nrf52_radio_putreg(dev, NRF52_RADIO_MODE_OFFSET, regval); + + /* Store mode */ + + dev->mode = mode; + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_freq_set + * + * Description: + * Set radio frequency (in MHz) + * + ****************************************************************************/ + +static int nrf52_radio_freq_set(FAR struct nrf52_radio_dev_s *dev, + uint32_t freq) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Check input */ + + if (freq < 2360 || freq > 2500) + { + wlerr("ERROR: unsupported radio frequency %d MHz\n", freq); + ret = -EINVAL; + goto errout; + } + + /* Map frequency to lower band */ + + if (freq < 2400) + { + regval |= RADIO_FREQUENCY_MAP_2360MHZ; + } + + regval |= freq; + nrf52_radio_putreg(dev, NRF52_RADIO_FREQUENCY_OFFSET, regval); + +errout: + return ret; +}; + +/**************************************************************************** + * Name: nrf52_radio_rssi_get + * + * Description: + * Get RSSI sample + * + ****************************************************************************/ + +static int nrf52_radio_rssi_get(FAR struct nrf52_radio_dev_s *dev, + FAR int *rssi) +{ + uint32_t regval = 0; + + /* Start the RSSI meassurement */ + + nrf52_radio_putreg(dev, NRF52_RADIO_TASKS_RSSISTART_OFFSET, + RADIO_TASKS_RSSISTART); + + /* Wait for the RSSI sample */ + + while (nrf52_radio_getreg(dev, NRF52_RADIO_EVENTS_RSSIEND_OFFSET)); + + /* Get the RSSI sample */ + + regval = nrf52_radio_getreg(dev, NRF52_RADIO_RSSISAMPLE_OFFSET); + *rssi = -(int)regval; + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radio_addr_set + * + * Description: + * Set radio logical adress + * + ****************************************************************************/ + +static int nrf52_radio_addr_set(FAR struct nrf52_radio_dev_s *dev, uint8_t i, + FAR struct nrf52_radio_addr_s *addr) +{ + uint32_t basereg = 0; + uint32_t prefixreg = 0; + uint32_t base_now = 0; + uint32_t prefix_now = 0; + uint32_t base_new = 0; + uint32_t prefix_new = 0; + uint32_t prefix_shift = 0; + int ret = OK; + + /* Assert input */ + + if (i > NRF52_RADIO_LOGICAL_ADDRESS_MAX - 1) + { + ret = -EINVAL; + goto errout; + } + + /* Get data specific for given logical adress */ + + if (i == 0) + { + /* Logical address 0 - BASE0 and PREFIX0.AP0 */ + + basereg = NRF52_RADIO_BASE0_OFFSET; + prefixreg = NRF52_RADIO_PREFIX0_OFFSET; + + prefix_shift = 0; + } + else if (i < 4) + { + /* Logical addres 1-3 - BASE1 and PREFIX0 */ + + basereg = NRF52_RADIO_BASE1_OFFSET; + prefixreg = NRF52_RADIO_PREFIX0_OFFSET; + + prefix_shift = (i * 8); + } + else + { + /* Logical addres 1-3 - BASE1 and PREFIX1 */ + + basereg = NRF52_RADIO_BASE1_OFFSET; + prefixreg = NRF52_RADIO_PREFIX1_OFFSET; + + prefix_shift = (i - 4) * 8; + } + + /* Get current BASE and PREFIX registers */ + + base_now = nrf52_radio_getreg(dev, basereg); + prefix_now = nrf52_radio_getreg(dev, prefixreg); + + /* TODO: check if new address match to old BASE1 */ + + if (basereg == NRF52_RADIO_BASE1_OFFSET) + { +#warning missing logic! + } + + /* Get new BASE */ + + base_new = (addr->a1 | addr->a2 << 8 | addr->a3 << 16 | addr->a4 << 24); + + /* Write new base */ + + nrf52_radio_putreg(dev, basereg, base_new); + + /* Write new PREFIX */ + + prefix_new = prefix_now; + prefix_new &= ~(0xff << prefix_shift); + prefix_new |= (addr->a0 << prefix_shift); + + nrf52_radio_putreg(dev, prefixreg, prefix_new); + + /* Copy address */ + + memcpy(&dev->addr[i], addr, sizeof(struct nrf52_radio_addr_s)); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_txpower_set + * + * Description: + * Set TX power + * + ****************************************************************************/ + +static int nrf52_radio_txpower_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t txpower) +{ + int ret = OK; + + /* Do nothing if already configured */ + + if (dev->txpower == txpower) + { + goto errout; + } + + /* Verify input */ + + if (txpower > RADIO_TXPOWER_MAX) + { + ret = -EINVAL; + goto errout; + } + + nrf52_radio_putreg(dev, NRF52_RADIO_TXPOWER_OFFSET, txpower); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_tifs_set + * + * Description: + * Set interframe spacing in us + * + ****************************************************************************/ + +static int nrf52_radio_tifs_set(FAR struct nrf52_radio_dev_s *dev, + uint16_t us) +{ + int ret = OK; + + /* Do nothing if already configured */ + + if (dev->tifs == us) + { + goto errout; + } + + /* Verify input */ + + if (us > RADIO_TIFS_MAX) + { + ret = -EINVAL; + goto errout; + } + + nrf52_radio_putreg(dev, NRF52_RADIO_TIFS_OFFSET, us); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_pkt_cfg + * + * Description: + * Configure radio packet + * + ****************************************************************************/ + +static int nrf52_radio_pkt_cfg(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_pktcfg_s *cfg) +{ + uint32_t pcnf0 = 0; + uint32_t pcnf1 = 0; + int ret = OK; + + /* LENGTH field length */ + + if (cfg->lf_len > RADIO_PCNF0_LFLEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->lf_len << RADIO_PCNF0_LFLEN_SHIFT); + + /* Configure S0 field */ + + if (cfg->s0_len > RADIO_PCNF0_S0LEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->s0_len << RADIO_PCNF0_S0LEN_SHIFT); + + /* Configure S1 field */ + + if (cfg->s1_len > RADIO_PCNF0_S1LEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->s1_len << RADIO_PCNF0_S1LEN_SHIFT); + + /* S1 in RAM only if S1LEN > 0 */ + + pcnf0 &= (~RADIO_PCNF0_S1INCL); + + /* Configure code indicator length */ + + if (cfg->ci_len > RADIO_PCNF0_CILEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->ci_len << RADIO_PCNF0_CILEN_SHIFT); + + /* Configure preamble length */ + + if (cfg->pl_len > NRF52_RADIO_PREAMBLE_LONGRANGE) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->pl_len << RADIO_PCNF0_PLEN_SHIFT); + + /* Configure TERM length */ + + if (cfg->term_len > RADIO_PCNF0_TERMLEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf0 |= (cfg->term_len << RADIO_PCNF0_TERMLEN_SHIFT); + + /* Include CRC in LENGTH or not */ + + pcnf0 |= (cfg->crcinc << RADIO_PCNF0_CRCINC_SHIFT); + + /* Configure maximum payload length */ + + if (cfg->max_len > RADIO_PCNF1_MAXLEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf1 |= (cfg->max_len << RADIO_PCNF1_MAXLEN_SHIFT); + + /* Configure static payload length */ + + if (cfg->stat_len > RADIO_PCNF1_STATLEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf1 |= (cfg->stat_len << RADIO_PCNF1_STATLEN_SHIFT); + + /* Configure base address length */ + + if (cfg->bal_len < RADIO_PCNF1_BALEN_MIN || + cfg->bal_len > RADIO_PCNF1_BALEN_MAX) + { + ret = -EINVAL; + goto errout; + } + + pcnf1 |= (cfg->bal_len << RADIO_PCNF1_BALEN_SHIFT); + + /* Configure on-air endianess of packet */ + + pcnf1 |= (cfg->endian << RADIO_PCNF1_ENDIAN_SHIFT); + + /* Enable whitening */ + + pcnf1 |= (cfg->whiteen << RADIO_PCNF1_WHITEEN_SHIFT); + + /* Write registers */ + + nrf52_radio_putreg(dev, NRF52_RADIO_PCNF0_OFFSET, pcnf0); + nrf52_radio_putreg(dev, NRF52_RADIO_PCNF1_OFFSET, pcnf1); + + /* Copy packet configuration */ + + memcpy(&dev->pktcfg, cfg, sizeof(struct nrf52_radio_pktcfg_s)); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_white_set + * + * Description: + * Configure data whitening initial value + * + ****************************************************************************/ + +static int nrf52_radio_white_set(FAR struct nrf52_radio_dev_s *dev, + uint8_t init) +{ + uint32_t regval = 0; + int ret = OK; + + /* Return error if whitening is disabled */ + + if (dev->pktcfg.whiteen == false) + { + ret = -EACCES; + goto errout; + } + + /* Configure whitening initial value */ + + if (init > RADIO_DATAWHITEIV_MAX) + { + ret = -EINVAL; + goto errout; + } + + regval |= (init << RADIO_DATAWHITEIV_SHIFT); + nrf52_radio_putreg(dev, NRF52_RADIO_DATAWHITEIV_OFFSET, init); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_crc_cfg + * + * Description: + * Configure packet CRC + * + ****************************************************************************/ + +static int nrf52_radio_crc_cfg(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_crc_s *cfg) +{ + uint32_t regval = 0; + int ret = OK; + + /* Configure CRC length */ + + if (cfg->len > NRF52_RADIO_CRC_LEN_3B) + { + ret = -EINVAL; + goto errout; + } + + regval |= (cfg->len << RADIO_CRCCNF_LEN_SHIFT); + + /* Configure CRC SKIPADDR */ + + if (cfg->skip > NRF52_RADIO_CRC_SKIPADDR_IEEE802154) + { + ret = -EINVAL; + goto errout; + } + + regval |= (cfg->skip << RADIO_CRCCNF_SKIPADDR_SHIFT); + nrf52_radio_putreg(dev, NRF52_RADIO_CRCCNF_OFFSET, regval); + + /* Configure CRC POLY */ + + if (cfg->poly > RADIO_CRCPOLY_MASK) + { + ret = -EINVAL; + goto errout; + } + + nrf52_radio_putreg(dev, NRF52_RADIO_CRCPOLY_OFFSET, cfg->poly); + + /* Configure CRC INIT */ + + if (cfg->init > RADIO_CRCINIT_MASK) + { + ret = -EINVAL; + goto errout; + } + + nrf52_radio_putreg(dev, NRF52_RADIO_CRCINIT_OFFSET, cfg->init); + +errout: + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_write + * + * Description: + * Write radio packet + * + ****************************************************************************/ + +static int nrf52_radio_write(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len) +{ + int ret = OK; + + /* Lock device */ + + ret = nxsem_wait(&dev->sem_excl); + if (ret < 0) + { + return ret; + } + + /* */ + + if (len > dev->txbuf_len) + { + ret = -ENOMEM; + goto errout; + } + + /* Copy packet */ + + memcpy(dev->txbuf, buf, len); + + /* Set packet pointer */ + + nrf52_radio_putreg(dev, NRF52_RADIO_PACKETPTR_OFFSET, &dev->txbuf); + + /* Set state to TX */ + + dev->state = NRF52_RADIO_STATE_TX; + + /* Start TX. + * NOTE: shortcut between READ and START is enabled. + */ + + nrf52_radio_putreg(dev, NRF52_RADIO_TASKS_TXEN_OFFSET, RADIO_TASKS_TXEN); + + /* Wait for IRQ */ + + ret = nxsem_wait(&dev->sem_isr); + +errout: + + /* Unlock device */ + + nxsem_post(&dev->sem_excl); + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_read + * + * Description: + * Read radio packet + * + ****************************************************************************/ + +static int nrf52_radio_read(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len) +{ + int ret = OK; + + /* Lock radio */ + + ret = nxsem_wait(&dev->sem_excl); + if (ret < 0) + { + return ret; + } + + /* */ + + if (len > dev->rxbuf_len) + { + ret = -ENOMEM; + goto errout; + } + + /* Set packet pointer */ + + nrf52_radio_putreg(dev, NRF52_RADIO_PACKETPTR_OFFSET, &dev->rxbuf); + + /* Set state to RX */ + + dev->state = NRF52_RADIO_STATE_RX; + + /* Start RX. + * NOTE: shortcut between READ and START is enabled. + */ + + nrf52_radio_putreg(dev, NRF52_RADIO_TASKS_RXEN_OFFSET, RADIO_TASKS_RXEN); + + /* Wait for IRQ */ + + ret = nxsem_wait(&dev->sem_isr); + + /* Copy packet */ + + memcpy(buf, dev->rxbuf, len); + +errout: + + /* Unlock radio */ + + nxsem_post(&dev->sem_excl); + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_dumpregs + * + * Description: + * Dump radio registers + * + ****************************************************************************/ + +static void nrf52_radio_dumpregs(FAR struct nrf52_radio_dev_s *dev) +{ + printf("\nnrf52_radio_dumpregs:\n"); + + printf("SHORTS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_SHORTS_OFFSET)); + printf("INTENSET 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_INTENSET_OFFSET)); + printf("CRCSTATUS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_CRCSTATUS_OFFSET)); + printf("RXMATCH 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_RXMATCH_OFFSET)); + printf("RXCRC 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_RXCRC_OFFSET)); + printf("DAI 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAI_OFFSET)); + printf("PDUSTAT 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PDUSTAT_OFFSET)); + printf("PACKETPTR 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PACKETPTR_OFFSET)); + printf("FREQUENCY 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_FREQUENCY_OFFSET)); + printf("TXPOWER 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_TXPOWER_OFFSET)); + printf("MODE 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_MODE_OFFSET)); + printf("PCNF0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PCNF0_OFFSET)); + printf("PCNF1 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PCNF1_OFFSET)); + printf("BASE0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_BASE0_OFFSET)); + printf("BASE1 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_BASE1_OFFSET)); + printf("PREFIX0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PREFIX0_OFFSET)); + printf("PREFIX1 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_PREFIX1_OFFSET)); + printf("TXADDRESS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_TXADDRESS_OFFSET)); + printf("RXADDRESS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_RXADDRESS_OFFSET)); + printf("CRCCNF 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_CRCCNF_OFFSET)); + printf("CRCPOLY 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_CRCPOLY_OFFSET)); + printf("CRCINIT 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_CRCINIT_OFFSET)); + printf("TIFS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_TIFS_OFFSET)); + printf("RSSISAMPLE 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_RSSISAMPLE_OFFSET)); + printf("STATE 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_STATE_OFFSET)); + printf("DATAWHITEIV 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DATAWHITEIV_OFFSET)); + printf("BCC 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_BCC_OFFSET)); + printf("DAB0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(0))); + printf("DAB1 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(1))); + printf("DAB2 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(2))); + printf("DAB3 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(3))); + printf("DAB4 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(4))); + printf("DAB5 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(5))); + printf("DAB6 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(6))); + printf("DAB7 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAB_OFFSET(6))); + printf("DAP0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(0))); + printf("DAP1 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(1))); + printf("DAP2 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(2))); + printf("DAP3 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(3))); + printf("DAP4 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(4))); + printf("DAP5 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(5))); + printf("DAP6 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(6))); + printf("DAP7 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DAP_OFFSET(6))); + printf("DACNF 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_DACNF_OFFSET)); + printf("MHRMATCHCONF 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_MHRMATCHCONF_OFFSET)); + printf("MHRMATCHMAS 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_MHRMATCHMAS_OFFSET)); + printf("MODECNF0 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_MODECNF0_OFFSET)); + printf("SFD 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_SFD_OFFSET)); + printf("EDCNT 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_EDCNT_OFFSET)); + printf("EDSAMPLE 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_EDSAMPLE_OFFSET)); + printf("CCACTRL 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_CCACTRL_OFFSET)); + printf("POWER 0x%08x\n", + nrf52_radio_getreg(dev, NRF52_RADIO_POWER_OFFSET)); +} + +/**************************************************************************** + * Name: nrf52_radio_isr_rx + * + * Description: + * RX radio interrupt handler + * + ****************************************************************************/ + +static int nrf52_radio_isr_rx(FAR struct nrf52_radio_dev_s *dev) +{ + /* RX done */ + + nxsem_post(&dev->sem_isr); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radio_isr_tx + * + * Description: + * TX radio interrupt handler + * + ****************************************************************************/ + +static int nrf52_radio_isr_tx(FAR struct nrf52_radio_dev_s *dev) +{ + /* TX done */ + + nxsem_post(&dev->sem_isr); + + return OK; +} + +/**************************************************************************** + * Name: nrf52_radio_isr + * + * Description: + * Radio interrupt handler + * + ****************************************************************************/ + +static int nrf52_radio_isr(int irq, FAR void *context, FAR void *arg) +{ + FAR struct nrf52_radio_dev_s *dev = (FAR struct nrf52_radio_dev_s *)arg; + int ret = OK; + uint32_t state = 0; + + DEBUGASSERT(dev); + + /* Get radio state */ + + wlinfo("RADIO ISR STATE=%d\n", dev->state); + + /* Handle radio state */ + + switch (dev->state) + { + case NRF52_RADIO_STATE_RX: + { + /* Transmit DONE */ + + ret = nrf52_radio_isr_rx(dev); + + break; + } + + case NRF52_RADIO_STATE_TX: + { + /* Receive DONE */ + + ret = nrf52_radio_isr_tx(dev); + + break; + } + + case NRF52_RADIO_STATE_DISABLED: + { + break; + } + + default: + { + ASSERT(0); + break; + } + } + + /* Clear END event */ + + nrf52_radio_putreg(dev, NRF52_RADIO_EVENTS_END_OFFSET, 0); + + /* Update radio state + * NOTE: shortcut between END and DISABLE is enabled. + */ + + dev->state = NRF52_RADIO_STATE_DISABLED; + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_setup + * + * Description: + * Initial RADIO setup + * + ****************************************************************************/ + +static int nrf52_radio_setup(FAR struct nrf52_radio_dev_s *dev) +{ + uint32_t regval = 0; + int ret = OK; + + DEBUGASSERT(dev); + + /* Configure interrupts: + * 1. END - packet sent or received + */ + + regval = (RADIO_INT_END); + nrf52_radio_putreg(dev, NRF52_RADIO_INTENSET_OFFSET, regval); + + /* Configure shortucts: + * 1. shortcut between READY and START + * 2. shortcut between END and DISABLE + */ + + regval = RADIO_SHORTS_READY_START; + regval |= RADIO_SHORTS_END_DISABLE; + nrf52_radio_putreg(dev, NRF52_RADIO_SHORTS_OFFSET, regval); + + /* Power on radio */ + + nrf52_radio_power(dev, true); + + return ret; +} + +/**************************************************************************** + * Name: nrf52_radio_reset + * + * Description: + * Reset radio + * + ****************************************************************************/ + +static int nrf52_radio_reset(FAR struct nrf52_radio_dev_s *dev) +{ + /* Turn off radio power */ + + nrf52_radio_power(dev, false); + + /* Wait some time */ + + nxsig_usleep(100000); + + /* Turn on radio power */ + + nrf52_radio_power(dev, true); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radio_initialize + * + * Description: + * Initialize NRF52 radio device + * + ****************************************************************************/ + +FAR struct nrf52_radio_dev_s * +nrf52_radio_initialize(int intf, FAR struct nrf52_radio_board_s *board) +{ + struct nrf52_radio_dev_s *dev = NULL; + int ret = OK; + + /* Get radio interface */ + + switch (intf) + { + case 0: + { + wlinfo("radio0 selecred\n"); + dev = &g_nrf52_radio_dev_1; + break; + } + + /* For now only one radio interface is available */ + + default: + { + wlerr("ERROR: No radio interface defined\n"); + goto errout; + } + } + + /* Reset some data */ + + memset(&dev->pktcfg, 0, sizeof(struct nrf52_radio_pktcfg_s)); + memset(dev->rxbuf, 0, NRF52_RADIO_RXBUFFER); + memset(dev->txbuf, 0, NRF52_RADIO_TXBUFFER); + + /* Attach radio interrupt */ + + irq_attach(dev->irq, nrf52_radio_isr, dev); + up_enable_irq(dev->irq); + + /* Initialize semaphores */ + + nxsem_init(&dev->sem_excl, 0, 1); + + /* This semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + nxsem_init(&dev->sem_isr, 0, 0); + nxsem_setprotocol(&dev->sem_isr, SEM_PRIO_NONE); + + /* Connect board-specific data */ + + dev->board = board; + + /* Reset radio */ + + ret = nrf52_radio_reset(dev); + if (ret < 0) + { + wlerr("ERROR: failed to reset radio interface %d\n", ret); + errno = ret; + goto errout; + } + + /* Initial radio setup */ + + ret = nrf52_radio_setup(dev); + if (ret < 0) + { + wlerr("ERROR: failed to setup radio interface %d\n", ret); + errno = ret; + goto errout; + } + + return dev; + +errout: + return NULL; +} diff --git a/arch/arm/src/nrf52/nrf52_radio.h b/arch/arm/src/nrf52/nrf52_radio.h new file mode 100644 index 0000000000..2332738684 --- /dev/null +++ b/arch/arm/src/nrf52/nrf52_radio.h @@ -0,0 +1,281 @@ +/**************************************************************************** + * arch/arm/src/nrf52/nrf52_radio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_NRF52_NRF52_RADIO_H +#define __ARCH_ARM_SRC_NRF52_NRF52_RADIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define NRF52_RADIO_LOGICAL_ADDRESS_MAX (8) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Radio mode */ + +enum nrf52_radio_mode_e +{ + NRF52_RADIO_MODE_NRF1MBIT = 0, + NRF52_RADIO_MODE_NRF2MBIT = 1, + NRF52_RADIO_MODE_BLE1MBIT = 2, + NRF52_RADIO_MODE_BLE2MBIT = 3, + NRF52_RADIO_MODE_BLELR125KBIT = 4, + NRF52_RADIO_MODE_BLELR500KBIT = 5, + NRF52_RADIO_MODE_IEEE802154 = 6 +}; + +/* Radio state */ + +enum nrf52_radio_state_e +{ + NRF52_RADIO_STATE_DISABLED = 0, + NRF52_RADIO_STATE_TX = 1, + NRF52_RADIO_STATE_RX = 2, +}; + +/* Preamble configuration */ + +enum nrf52_radio_preamble_e +{ + NRF52_RADIO_PREAMBLE_8BIT = 0, + NRF52_RADIO_PREAMBLE_16BIT = 1, + NRF52_RADIO_PREAMBLE_32BITZERO = 2, + NRF52_RADIO_PREAMBLE_LONGRANGE = 3 +}; + +/* Radio packet CRC length */ + +enum nrf52_radio_crc_len_e +{ + NRF52_RADIO_CRC_LEN_DIS = 0, + NRF52_RADIO_CRC_LEN_1B = 1, + NRF52_RADIO_CRC_LEN_2B = 2, + NRF52_RADIO_CRC_LEN_3B = 3, +}; + +/* Radio packet CRC includes address */ + +enum nrf52_radio_crc_skipaddr_e +{ + NRF52_RADIO_CRC_SKIPADDR_INCLUDE = 0, + NRF52_RADIO_CRC_SKIPADDR_SKIP = 1, + NRF52_RADIO_CRC_SKIPADDR_IEEE802154 = 2, +}; + +/* On air packet layout: + * + * +---------------------------------------+ + * | FIRST | + * |----------+------+--------+----+-------+ + * | PREAMBLE | BASE | PREFIX | CI | TERM1 | + * | LSB | LSB | LSB | | | + * | | ADDRESS | | | + * +----------+---------------+----+-------+ + * + * + * +----------------------------+ + * | Stored on RAM | + * |----+--------+----+---------| + * | S0 | LENGTH | S1 | PAYLOAD | + * | | | | | + * | | | | | + * +----+--------+----+---------+ + * + * +---------------+ + * | LAST | + * |-------+-------| + * | CRC32 | TERM2 | + * | MSB | | + * | | | + * +-------+-------+ + * + */ + +/* Radio packet configuration */ + +struct nrf52_radio_pktcfg_s +{ + uint8_t max_len; /* Maximum length of payload */ + uint8_t stat_len; /* Static payload length */ + uint8_t bal_len; /* Base address length */ + uint8_t lf_len; /* LENGTH length */ + uint8_t s0_len; /* S0 length */ + uint8_t s1_len; /* S1 length */ + uint8_t ci_len; /* CI length */ + uint8_t pl_len; /* Preable lenght */ + uint8_t term_len; /* TERM length */ + bool crcinc; /* LENGTH includes CRC */ + bool endian; /* On air endianess of packet: + * 0 - little + * 1 - big + */ + bool whiteen; /* Whitening enabled */ +}; + +/* Radio packet CRC configuration */ + +struct nrf52_radio_crc_s +{ + uint8_t len; /* CRC length in number of bytes */ + uint8_t skip; /* Include or exclude address field out of CRC */ + uint32_t poly; /* CRC polynominal */ + uint32_t init; /* CRC initial value */ +}; + +/* NRF52 on air address */ + +struct nrf52_radio_addr_s +{ + uint8_t a0; /* PREFIX */ + uint8_t a1; /* BASE[0] */ + uint8_t a2; /* BASE[1] */ + uint8_t a3; /* BASE[2] */ + uint8_t a4; /* BASE[3] */ +}; + +/* NRF52 radio operations */ + +struct nrf52_radio_dev_s; +struct nrf52_radio_ops_s +{ + /* Turn-on/turn-off radio power */ + + CODE int (*power)(FAR struct nrf52_radio_dev_s *dev, bool state); + + /* Set radio mode */ + + CODE int (*mode_set)(FAR struct nrf52_radio_dev_s *dev, uint8_t mode); + + /* Set radio frequency (in MHz) */ + + CODE int (*freq_set)(FAR struct nrf52_radio_dev_s *dev, uint32_t freq); + + /* Get RSSI sample */ + + CODE int (*rssi_get)(FAR struct nrf52_radio_dev_s *dev, FAR int *rssi); + + /* Set TX power */ + + CODE int (*txpower_set)(FAR struct nrf52_radio_dev_s *dev, + uint8_t txpower); + + /* Set hardware interframe spacing time */ + + CODE int (*tifs_set)(FAR struct nrf52_radio_dev_s *dev, uint16_t us); + + /* Configure radio packet */ + + CODE int (*pkt_cfg)(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_pktcfg_s *cfg); + + /* Configure packet CRC */ + + CODE int (*crc_cfg)(FAR struct nrf52_radio_dev_s *dev, + FAR struct nrf52_radio_crc_s *cfg); + + /* Configure data whitening */ + + CODE int (*white_set)(FAR struct nrf52_radio_dev_s *dev, + uint8_t init); + + /* Configure logical address */ + + CODE int (*addr_set)(FAR struct nrf52_radio_dev_s *dev, uint8_t i, + FAR struct nrf52_radio_addr_s *addr); + + /* Read packet */ + + CODE int (*read)(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len); + + /* Write packet */ + + CODE int (*write)(FAR struct nrf52_radio_dev_s *dev, + FAR uint8_t *buf, int len); + + /* Dump radio registers */ + + CODE void (*dumpregs)(FAR struct nrf52_radio_dev_s *dev); +}; + +/* NRF52 radio board specific data */ + +struct nrf52_radio_board_s +{ + /* TODO: PA/LNA interface */ + + uint32_t reserved; +}; + +/* NRF52 radio device */ + +struct nrf52_radio_dev_s +{ + FAR struct nrf52_radio_ops_s *ops; /* Radio operations */ + FAR struct nrf52_radio_board_s *board; /* Radio board-specific */ + uint32_t base; /* Radio base */ + uint32_t irq; /* Radio IRQ number */ + uint8_t mode; /* Radio mode */ + uint8_t state; /* Radio state */ + struct nrf52_radio_pktcfg_s pktcfg; /* Current packet */ + uint16_t rxbuf_len; /* RX buffer length */ + uint16_t txbuf_len; /* TX buffer length */ + FAR uint8_t *rxbuf; /* RX buffer */ + FAR uint8_t *txbuf; /* TX buffer */ + sem_t sem_excl; /* Mutual exclusion semaphore */ + sem_t sem_isr; /* Interrupt wait semaphore */ + uint16_t tifs; /* Interframe spacing time */ + uint8_t txpower; /* TX power */ + uint8_t txaddr; /* TX address */ + uint8_t rxaddr; /* RX addresses */ + struct nrf52_radio_addr_s addr[NRF52_RADIO_LOGICAL_ADDRESS_MAX]; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: nrf52_radio_initialize + * + * Description: + * Initialize NRF52 radio device + * + ****************************************************************************/ + +FAR struct nrf52_radio_dev_s * +nrf52_radio_initialize(int intf, FAR struct nrf52_radio_board_s *board); + +#endif /* __ARCH_ARM_SRC_NRF52_NRF52_RADIO_H */