diff --git a/nimble/drivers/nrf52/pkg.yml b/nimble/drivers/nrf52/pkg.yml index a1ff457e6f..c97452613a 100644 --- a/nimble/drivers/nrf52/pkg.yml +++ b/nimble/drivers/nrf52/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf52 -pkg.description: BLE driver for nRF52 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/nimble/drivers/nrf52/syscfg.yml b/nimble/drivers/nrf52/syscfg.yml deleted file mode 100644 index c3ef5ae1d1..0000000000 --- a/nimble/drivers/nrf52/syscfg.yml +++ /dev/null @@ -1,81 +0,0 @@ -# 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. -# - -syscfg.defs: - BLE_PHY_VARIABLE_TIFS: - description: > - Enables API to set custom T_ifs (inter-frame spacing) for each - transition. T_ifs is reset to default value after each transition. - When disabled, 150us is always used which enables some build-time - optimizations by compiler. - experimental: 1 - value: 0 - - BLE_PHY_SYSVIEW: - description: > - Enable SystemView tracing module for radio driver. - value: 0 - - BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: - description: > - When set to proper GPIO pin number, this pin will be set - to high state when radio is enabled using PPI channels - 20 or 21 and back to low state on radio EVENTS_READY. - This can be used to measure radio ram-up time. - value: -1 - - BLE_PHY_DBG_TIME_ADDRESS_END_PIN: - description: > - When set to proper GPIO pin number, this pin will be set - to high state on radio EVENTS_ADDRESS and back to low state - on radio EVENTS_END. - This can be used to measure radio pipeline delays. - value: -1 - - BLE_PHY_DBG_TIME_WFR_PIN: - description: > - When set to proper GPIO pin number, this pin will be set - to high state on radio EVENTS_RXREADY and back to low - state when wfr timer expires. - This can be used to check if wfr is calculated properly. - value: -1 - - BLE_PHY_NRF52840_ERRATA_164: - description: > - Enable workaround for anomaly 164 found in nRF52840. - "[164] RADIO: Low selectivity in long range mode" - This shall be only enabled for: - - nRF52840 Engineering A - value: 0 - - BLE_PHY_NRF52840_ERRATA_191: - description: > - Enable workaround for anomaly 191 found in nRF52840. - "[191] RADIO: High packet error rate in BLE Long Range mode" - This shall be only enabled for: - - nRF52840 Engineering B - - nRF52840 Engineering C - - nRF52840 Rev 1 (final silicon) - value: 1 - - BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR: - description: > - Ublox BMD-345 modules come with public address preprogrammed - in UICR register. If enabled public address will be read from - custom UICR instead of FICR register. - value: 0 diff --git a/nimble/drivers/nrf5340/include/ble/xcvr.h b/nimble/drivers/nrf5340/include/ble/xcvr.h deleted file mode 100644 index df6ef700d3..0000000000 --- a/nimble/drivers/nrf5340/include/ble/xcvr.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 H_BLE_XCVR_ -#define H_BLE_XCVR_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define XCVR_RX_RADIO_RAMPUP_USECS (40) -#define XCVR_TX_RADIO_RAMPUP_USECS (40) - -/* - * NOTE: we have to account for the RTC output compare issue. We want it to be - * 5 ticks. - */ -#define XCVR_PROC_DELAY_USECS (153) -#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) -#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) -#define XCVR_TX_SCHED_DELAY_USECS (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) -#define XCVR_RX_SCHED_DELAY_USECS (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) - -/* - * Define HW whitelist size. This is the total possible whitelist size; - * not necessarily the size that will be used (may be smaller) - */ -#define BLE_HW_WHITE_LIST_SIZE (8) - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_XCVR_ */ diff --git a/nimble/drivers/nrf5340/pkg.yml b/nimble/drivers/nrf5340/pkg.yml index 3ff442120b..794697e9b0 100644 --- a/nimble/drivers/nrf5340/pkg.yml +++ b/nimble/drivers/nrf5340/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf5340 -pkg.description: BLE driver for nRF5340 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/nimble/drivers/nrf5340/src/ble_hw.c b/nimble/drivers/nrf5340/src/ble_hw.c deleted file mode 100644 index e578fd05d2..0000000000 --- a/nimble/drivers/nrf5340/src/ble_hw.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Total number of resolving list elements */ -#define BLE_HW_RESOLV_LIST_SIZE (16) - -/* We use this to keep track of which entries are set to valid addresses */ -static uint8_t g_ble_hw_whitelist_mask; - -/* Random number generator isr callback */ -static ble_rng_isr_cb_t ble_rng_isr_cb; - -/* If LL privacy is enabled, allocate memory for AAR */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - -/* The NRF5340 supports up to 16 IRK entries */ -#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16) -#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) -#else -#define NRF_IRK_LIST_ENTRIES (16) -#endif - -/* NOTE: each entry is 16 bytes long. */ -uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4]; - -/* Current number of IRK entries */ -uint8_t g_nrf_num_irks; - -#endif - -/* Returns public device address or -1 if not present */ -int -ble_hw_get_public_addr(ble_addr_t *addr) -{ - uint32_t addr_high; - uint32_t addr_low; - - /* Does FICR have a public address */ - if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) != 0) { - return -1; - } - - /* Copy into device address. We can do this because we know platform */ - addr_low = NRF_FICR_NS->DEVICEADDR[0]; - addr_high = NRF_FICR_NS->DEVICEADDR[1]; - memcpy(addr->val, &addr_low, 4); - memcpy(&addr->val[4], &addr_high, 2); - addr->type = BLE_ADDR_PUBLIC; - - return 0; -} - -/* Returns random static address or -1 if not present */ -int -ble_hw_get_static_addr(ble_addr_t *addr) -{ - uint32_t addr_high; - uint32_t addr_low; - int rc; - - if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) == 1) { - addr_low = NRF_FICR_NS->DEVICEADDR[0]; - addr_high = NRF_FICR_NS->DEVICEADDR[1]; - - memcpy(addr->val, &addr_low, 4); - memcpy(&addr->val[4], &addr_high, 2); - - addr->val[5] |= 0xc0; - addr->type = BLE_ADDR_RANDOM; - rc = 0; - } else { - rc = -1; - } - - return rc; -} - -/** - * Clear the whitelist - * - * @return int - */ -void -ble_hw_whitelist_clear(void) -{ - NRF_RADIO_NS->DACNF = 0; - g_ble_hw_whitelist_mask = 0; -} - -/** - * Add a device to the hw whitelist - * - * @param addr - * @param addr_type - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint32_t mask; - - /* Find first ununsed device address match element */ - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if ((mask & g_ble_hw_whitelist_mask) == 0) { - NRF_RADIO_NS->DAB[i] = get_le32(addr); - NRF_RADIO_NS->DAP[i] = get_le16(addr + 4); - if (addr_type == BLE_ADDR_RANDOM) { - NRF_RADIO_NS->DACNF |= (mask << 8); - } - g_ble_hw_whitelist_mask |= mask; - return BLE_ERR_SUCCESS; - } - mask <<= 1; - } - - return BLE_ERR_MEM_CAPACITY; -} - -/** - * Remove a device from the hw whitelist - * - * @param addr - * @param addr_type - * - */ -void -ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint16_t dap; - uint16_t txadd; - uint32_t dab; - uint32_t mask; - - /* Find first ununsed device address match element */ - dab = get_le32(addr); - dap = get_le16(addr + 4); - txadd = NRF_RADIO_NS->DACNF >> 8; - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if (mask & g_ble_hw_whitelist_mask) { - if ((dab == NRF_RADIO_NS->DAB[i]) && (dap == NRF_RADIO_NS->DAP[i])) { - if (addr_type == !!(txadd & mask)) { - break; - } - } - } - mask <<= 1; - } - - if (i < BLE_HW_WHITE_LIST_SIZE) { - g_ble_hw_whitelist_mask &= ~mask; - NRF_RADIO_NS->DACNF &= ~mask; - } -} - -/** - * Returns the size of the whitelist in HW - * - * @return int Number of devices allowed in whitelist - */ -uint8_t -ble_hw_whitelist_size(void) -{ - return BLE_HW_WHITE_LIST_SIZE; -} - -/** - * Enable the whitelisted devices - */ -void -ble_hw_whitelist_enable(void) -{ - /* Enable the configured device addresses */ - NRF_RADIO_NS->DACNF |= g_ble_hw_whitelist_mask; -} - -/** - * Disables the whitelisted devices - */ -void -ble_hw_whitelist_disable(void) -{ - /* Disable all whitelist devices */ - NRF_RADIO_NS->DACNF &= 0x0000ff00; -} - -/** - * Boolean function which returns true ('1') if there is a match on the - * whitelist. - * - * @return int - */ -int -ble_hw_whitelist_match(void) -{ - return NRF_RADIO_NS->EVENTS_DEVMATCH; -} - -/* Encrypt data */ -int -ble_hw_encrypt_block(struct ble_encryption_block *ecb) -{ - int rc; - uint32_t end; - uint32_t err; - - /* Stop ECB */ - NRF_ECB_NS->TASKS_STOPECB = 1; - /* XXX: does task stop clear these counters? Anyway to do this quicker? */ - NRF_ECB_NS->EVENTS_ENDECB = 0; - NRF_ECB_NS->EVENTS_ERRORECB = 0; - NRF_ECB_NS->ECBDATAPTR = (uint32_t)ecb; - - /* Start ECB */ - NRF_ECB_NS->TASKS_STARTECB = 1; - - /* Wait till error or done */ - rc = 0; - while (1) { - end = NRF_ECB_NS->EVENTS_ENDECB; - err = NRF_ECB_NS->EVENTS_ERRORECB; - if (end || err) { - if (err) { - rc = -1; - } - break; - } - } - - return rc; -} - -/** - * Random number generator ISR. - */ -static void -ble_rng_isr(void) -{ - uint8_t rnum; - - os_trace_isr_enter(); - - /* No callback? Clear and disable interrupts */ - if (ble_rng_isr_cb == NULL) { - NRF_RNG_NS->INTENCLR = 1; - NRF_RNG_NS->EVENTS_VALRDY = 0; - (void)NRF_RNG_NS->SHORTS; - os_trace_isr_exit(); - return; - } - - /* If there is a value ready grab it */ - if (NRF_RNG_NS->EVENTS_VALRDY) { - NRF_RNG_NS->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG_NS->VALUE; - (*ble_rng_isr_cb)(rnum); - } - - os_trace_isr_exit(); -} - -/** - * Initialize the random number generator - * - * @param cb - * @param bias - * - * @return int - */ -int -ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) -{ - /* Set bias */ - if (bias) { - NRF_RNG_NS->CONFIG = 1; - } else { - NRF_RNG_NS->CONFIG = 0; - } - - /* If we were passed a function pointer we need to enable the interrupt */ - if (cb != NULL) { -#ifndef RIOT_VERSION - NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1); -#endif -#if MYNEWT - NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr); -#else - ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr); -#endif - NVIC_EnableIRQ(RNG_IRQn); - ble_rng_isr_cb = cb; - } - - return 0; -} - -/** - * Start the random number generator - * - * @return int - */ -int -ble_hw_rng_start(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG_NS->EVENTS_VALRDY = 0; - if (ble_rng_isr_cb) { - NRF_RNG_NS->INTENSET = 1; - } - NRF_RNG_NS->TASKS_START = 1; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Stop the random generator - * - * @return int - */ -int -ble_hw_rng_stop(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG_NS->INTENCLR = 1; - NRF_RNG_NS->TASKS_STOP = 1; - NRF_RNG_NS->EVENTS_VALRDY = 0; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Read the random number generator. - * - * @return uint8_t - */ -uint8_t -ble_hw_rng_read(void) -{ - uint8_t rnum; - - /* Wait for a sample */ - while (NRF_RNG_NS->EVENTS_VALRDY == 0) { - } - - NRF_RNG_NS->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG_NS->VALUE; - - return rnum; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -/** - * Clear the resolving list - * - * @return int - */ -void -ble_hw_resolv_list_clear(void) -{ - g_nrf_num_irks = 0; -} - -/** - * Add a device to the hw resolving list - * - * @param irk Pointer to IRK to add - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_resolv_list_add(uint8_t *irk) -{ - uint32_t *nrf_entry; - - /* Find first ununsed device address match element */ - if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Copy into irk list */ - nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks]; - memcpy(nrf_entry, irk, 16); - - /* Add to total */ - ++g_nrf_num_irks; - return BLE_ERR_SUCCESS; -} - -/** - * Remove a device from the hw resolving list - * - * @param index Index of IRK to remove - */ -void -ble_hw_resolv_list_rmv(int index) -{ - uint32_t *irk_entry; - - if (index < g_nrf_num_irks) { - --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; - if (g_nrf_num_irks > index) { - memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); - } - } -} - -/** - * Returns the size of the resolving list. NOTE: this returns the maximum - * allowable entries in the HW. Configuration options may limit this. - * - * @return int Number of devices allowed in resolving list - */ -uint8_t -ble_hw_resolv_list_size(void) -{ - return BLE_HW_RESOLV_LIST_SIZE; -} - -/** - * Called to determine if the address received was resolved. - * - * @return int Negative values indicate unresolved address; positive values - * indicate index in resolving list of resolved address. - */ -int -ble_hw_resolv_list_match(void) -{ - if (NRF_AAR_NS->ENABLE && NRF_AAR_NS->EVENTS_END && - NRF_AAR_NS->EVENTS_RESOLVED) { - return (int)NRF_AAR_NS->STATUS; - } - - return -1; -} -#endif diff --git a/nimble/drivers/nrf5340/src/ble_phy.c b/nimble/drivers/nrf5340/src/ble_phy.c deleted file mode 100644 index 76c0289e02..0000000000 --- a/nimble/drivers/nrf5340/src/ble_phy.c +++ /dev/null @@ -1,2079 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "controller/ble_ll_fem.h" - -#include -#include -#include -#include -#include - -#define DPPI_CH_PUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) -#define DPPI_CH_SUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) -#define DPPI_CH_UNSUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31)) -#define DPPI_CH_MASK(_ch) (1 << (DPPI_CH_ ## _ch)) - -/* Channels 0..5 are always used. - * Channels 6 and 7 are used for PA/LNA (optionally). - * Channels 7..9 are used for GPIO debugging (optionally). - */ - -#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 -#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1 -#define DPPI_CH_RADIO_EVENTS_END 2 -#define DPPI_CH_RADIO_EVENTS_BCMATCH 3 -#define DPPI_CH_RADIO_EVENTS_ADDRESS 4 -#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5 -#define DPPI_CH_TIMER0_EVENTS_COMPARE_4 6 -#define DPPI_CH_RADIO_EVENTS_DISABLED 7 -#define DPPI_CH_RADIO_EVENTS_READY 8 -#define DPPI_CH_RADIO_EVENTS_RXREADY 9 - -#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | DPPIC_CHEN_CH2_Msk | \ - DPPIC_CHEN_CH3_Msk | DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk) - -#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_4) | \ - DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) - -extern uint8_t g_nrf_num_irks; -extern uint32_t g_nrf_irk_list[]; - -/* To disable all radio interrupts */ -#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) - -/* - * We configure the nrf with a 1 byte S0 field, 8 bit length field, and - * zero bit S1 field. The preamble is 8 bits long. - */ -#define NRF_LFLEN_BITS (8) -#define NRF_S0LEN (1) -#define NRF_S1LEN_BITS (0) -#define NRF_CILEN_BITS (2) -#define NRF_TERMLEN_BITS (3) - -/* Maximum length of frames */ -#define NRF_MAXLEN (255) -#define NRF_BALEN (3) /* For base address of 3 bytes */ - -/* NRF_RADIO_NS->PCNF0 configuration values */ -#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ - (RADIO_PCNF0_S1INCL_Msk) | \ - (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \ - (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos) -#define NRF_PCNF0_1M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_2M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_CODED (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \ - (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \ - (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos) - -/* BLE PHY data structure */ -struct ble_phy_obj { - uint8_t phy_stats_initialized; - int8_t phy_txpwr_dbm; - uint8_t phy_chan; - uint8_t phy_state; - uint8_t phy_transition; - uint8_t phy_transition_late; - uint8_t phy_rx_started; - uint8_t phy_encrypted; - uint8_t phy_privacy; - uint8_t phy_tx_pyld_len; - uint8_t phy_cur_phy_mode; - uint8_t phy_tx_phy_mode; - uint8_t phy_rx_phy_mode; - uint8_t phy_bcc_offset; - int8_t rx_pwr_compensation; - uint32_t phy_aar_scratch; - uint32_t phy_access_address; - struct ble_mbuf_hdr rxhdr; - void *txend_arg; - ble_phy_tx_end_func txend_cb; - uint32_t phy_start_cputime; -}; -struct ble_phy_obj g_ble_phy_data; - -/* XXX: if 27 byte packets desired we can make this smaller */ -/* Global transmit/receive buffer */ -static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* Make sure word-aligned for faster copies */ -static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -#endif - -/* RF center frequency for each channel index (offset from 2400 MHz) */ -static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { - 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */ - 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */ - 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */ - 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ -}; - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/* packet start offsets (in usecs) */ -static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 40, - [BLE_PHY_MODE_2M] = 24, - [BLE_PHY_MODE_CODED_125KBPS] = 376, - [BLE_PHY_MODE_CODED_500KBPS] = 376 -}; -#endif - -/* Various radio timings */ -/* Radio ramp-up times in usecs (fast mode) */ -#define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS) -#define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS) - -/* delay between EVENTS_READY and start of tx */ -static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 5, - [BLE_PHY_MODE_CODED_500KBPS] = 5 -}; -/* delay between EVENTS_END and end of txd packet */ -static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 9, - [BLE_PHY_MODE_CODED_500KBPS] = 3 -}; -/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ -static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 17, - [BLE_PHY_MODE_CODED_500KBPS] = 17 -}; -/* delay between end of rxd packet and EVENTS_END */ -static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 27, - [BLE_PHY_MODE_CODED_500KBPS] = 22 -}; - -/* Statistics */ -STATS_SECT_START(ble_phy_stats) -STATS_SECT_ENTRY(phy_isrs) -STATS_SECT_ENTRY(tx_good) -STATS_SECT_ENTRY(tx_fail) -STATS_SECT_ENTRY(tx_late) -STATS_SECT_ENTRY(tx_bytes) -STATS_SECT_ENTRY(rx_starts) -STATS_SECT_ENTRY(rx_aborts) -STATS_SECT_ENTRY(rx_valid) -STATS_SECT_ENTRY(rx_crc_err) -STATS_SECT_ENTRY(rx_late) -STATS_SECT_ENTRY(radio_state_errs) -STATS_SECT_ENTRY(rx_hw_err) -STATS_SECT_ENTRY(tx_hw_err) -STATS_SECT_END -STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; - -STATS_NAME_START(ble_phy_stats) -STATS_NAME(ble_phy_stats, phy_isrs) -STATS_NAME(ble_phy_stats, tx_good) -STATS_NAME(ble_phy_stats, tx_fail) -STATS_NAME(ble_phy_stats, tx_late) -STATS_NAME(ble_phy_stats, tx_bytes) -STATS_NAME(ble_phy_stats, rx_starts) -STATS_NAME(ble_phy_stats, rx_aborts) -STATS_NAME(ble_phy_stats, rx_valid) -STATS_NAME(ble_phy_stats, rx_crc_err) -STATS_NAME(ble_phy_stats, rx_late) -STATS_NAME(ble_phy_stats, radio_state_errs) -STATS_NAME(ble_phy_stats, rx_hw_err) -STATS_NAME(ble_phy_stats, tx_hw_err) -STATS_NAME_END(ble_phy_stats) - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* - * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. - * However, when I used a smaller size it still overwrote the scratchpad. Until - * I figure this out I am just going to allocate 67 words so we have enough - * space for 267 bytes of scratch. I used 268 bytes since not sure if this - * needs to be aligned and burning a byte is no big deal. - * - *#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4) - */ -#define NRF_ENC_SCRATCH_WORDS (67) - -static uint32_t nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; - -struct nrf_ccm_data { - uint8_t key[16]; - uint64_t pkt_counter; - uint8_t dir_bit; - uint8_t iv[8]; -} __attribute__((packed)); - -static struct nrf_ccm_data nrf_ccm_data; -#endif - -static int g_ble_phy_gpiote_idx; - -#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA) - -#define FEM_SINGLE_GPIO \ - (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \ - (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO))) - -#if FEM_SINGLE_GPIO -static uint8_t fem_idx; -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) -static uint8_t fem_pa_idx; -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) -static uint8_t fem_lna_idx; -#endif -#endif - -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 -static uint8_t phy_dbg_txrxen_ready_idx; -#endif -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 -static uint8_t phy_dbg_address_end_idx; -#endif -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 -static uint8_t phy_dbg_wfr_idx; -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - -uint32_t -ble_phy_mode_pdu_start_off(int phy_mode) -{ - return g_ble_phy_mode_pkt_start_off[phy_mode]; -} - -static void -ble_phy_mode_apply(uint8_t phy_mode) -{ - if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) { - return; - } - - switch (phy_mode) { - case BLE_PHY_MODE_1M: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit; - *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_1M; - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_PHY_MODE_2M: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_2Mbit; - *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084); - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_2M; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; - *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED; - break; - case BLE_PHY_MODE_CODED_500KBPS: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; - *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED; - break; -#endif - default: - assert(0); - } - - g_ble_phy_data.phy_cur_phy_mode = phy_mode; -} -#endif - -void -ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) -{ - g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode; - g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode; -} - -static void -ble_phy_fem_enable_pa(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_PA) - ble_ll_fem_pa_enable(); - - /* CC[0] is set to radio enable */ - NRF_TIMER0_NS->CC[4] = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST - - MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US); - -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4); -#else - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4); -#endif -#endif -} - -static void -ble_phy_fem_disable_pa(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_PA) - ble_ll_fem_pa_disable(); - -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#else - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#endif -#endif -} - -static void -ble_phy_fem_enable_lna(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - ble_ll_fem_lna_enable(); - - /* CC[0] is set to radio enable */ - NRF_TIMER0_NS->CC[4] = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST - - MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US); - -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4); -#else - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4); -#endif -#endif -} - -static void -ble_phy_fem_disable_lna(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - ble_ll_fem_lna_disable(); - -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#else - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#endif -#endif -} - -static void -ble_phy_fem_force_disable(void) -{ -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->TASKS_CLR[fem_idx] = 1; -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) - NRF_GPIOTE_NS->TASKS_CLR[fem_pa_idx] = 1; -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - NRF_GPIOTE_NS->TASKS_CLR[fem_lna_idx] = 1; -#endif -#endif -} - -int -ble_phy_get_cur_phy(void) -{ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return BLE_PHY_1M; - case BLE_PHY_MODE_2M: - return BLE_PHY_2M; - case BLE_PHY_MODE_CODED_125KBPS: - case BLE_PHY_MODE_CODED_500KBPS: - return BLE_PHY_CODED; - default: - assert(0); - return -1; - } -#else - return BLE_PHY_1M; -#endif -} - -void -ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) -{ - uint32_t rem_len; - uint32_t copy_len; - uint32_t block_len; - uint32_t block_rem_len; - void *dst; - void *src; - struct os_mbuf * om; - - /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); - - block_len = rxpdu->om_omp->omp_databuf_len; - rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len; - src = dptr; - - /* - * Setup for copying from first mbuf which is shorter due to packet header - * and extra leading space - */ - copy_len = block_len - rxpdu->om_pkthdr_len - 4; - om = rxpdu; - dst = om->om_data; - - while (true) { - /* - * Always copy blocks of length aligned to word size, only last mbuf - * will have remaining non-word size bytes appended. - */ - block_rem_len = copy_len; - copy_len = min(copy_len, rem_len); - copy_len &= ~3; - - dst = om->om_data; - om->om_len = copy_len; - rem_len -= copy_len; - block_rem_len -= copy_len; - - __asm__ volatile (".syntax unified \n" - " mov r4, %[len] \n" - " b 2f \n" - "1: ldr r3, [%[src], %[len]] \n" - " str r3, [%[dst], %[len]] \n" - "2: subs %[len], #4 \n" - " bpl 1b \n" - " adds %[src], %[src], r4 \n" - " adds %[dst], %[dst], r4 \n" - : [dst] "+r" (dst), [src] "+r" (src), - [len] "+r" (copy_len) - : - : "r3", "r4", "memory" - ); - - if ((rem_len < 4) && (block_rem_len >= rem_len)) { - break; - } - - /* Move to next mbuf */ - om = SLIST_NEXT(om, om_next); - copy_len = block_len; - } - - /* Copy remaining bytes, if any, to last mbuf */ - om->om_len += rem_len; - __asm__ volatile (".syntax unified \n" - " b 2f \n" - "1: ldrb r3, [%[src], %[len]] \n" - " strb r3, [%[dst], %[len]] \n" - "2: subs %[len], #1 \n" - " bpl 1b \n" - : [len] "+r" (rem_len) - : [dst] "r" (dst), [src] "r" (src) - : "r3", "memory" - ); - - /* Copy header */ - memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, - sizeof(struct ble_mbuf_hdr)); -} - -/** - * Called when we want to wait if the radio is in either the rx or tx - * disable states. We want to wait until that state is over before doing - * anything to the radio - */ -static void -nrf_wait_disabled(void) -{ - uint32_t state; - - state = NRF_RADIO_NS->STATE; - if (state != RADIO_STATE_STATE_Disabled) { - if ((state == RADIO_STATE_STATE_RxDisable) || - (state == RADIO_STATE_STATE_TxDisable)) { - /* This will end within a short time (6 usecs). Just poll */ - while (NRF_RADIO_NS->STATE == state) { - /* If this fails, something is really wrong. Should last - * no more than 6 usecs - */ - } - } - } -} - -static int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) -{ - uint32_t next_cc; - uint32_t cur_cc; - uint32_t cntr; - uint32_t delta; - - /* - * We need to adjust start time to include radio ramp-up and TX pipeline - * delay (the latter only if applicable, so only for TX). - * - * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on - * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate - * using TIMER0 with 1 usec precision. - */ - - cputime -= 2; - rem_usecs += 61; - if (tx) { - rem_usecs -= BLE_PHY_T_TXENFAST; - rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - } else { - rem_usecs -= BLE_PHY_T_RXENFAST; - } - - /* - * rem_usecs will be no more than 2 ticks, but if it is more than single - * tick then we should better count one more low-power tick rather than - * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the - * compare won't occur. - */ - - if (rem_usecs > 30) { - cputime++; - rem_usecs -= 30; - } - - /* If PA/LNA is used, make sure CC[0] is set to more than turn-on time since - * it's used as a base for turn-on time calculation and thus cannot wrap - * around on subtraction. - */ - if (MYNEWT_VAL(BLE_LL_FEM_PA) && tx && - (rem_usecs + BLE_PHY_T_RXENFAST <= MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US))) { - cputime--; - rem_usecs += 30; - } - - if (MYNEWT_VAL(BLE_LL_FEM_LNA) && !tx && - (rem_usecs + BLE_PHY_T_RXENFAST <= MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US))) { - cputime--; - rem_usecs += 30; - } - - /* - * Can we set the RTC compare to start TIMER0? We can do it if: - * a) Current compare value is not N+1 or N+2 ticks from current - * counter. - * b) The value we want to set is not at least N+2 from current - * counter. - * - * NOTE: since the counter can tick 1 while we do these calculations we - * need to account for it. - */ - next_cc = cputime & 0xffffff; - cur_cc = NRF_RTC0_NS->CC[0]; - cntr = NRF_RTC0_NS->COUNTER; - - delta = (cur_cc - cntr) & 0xffffff; - if ((delta <= 3) && (delta != 0)) { - return -1; - } - delta = (next_cc - cntr) & 0xffffff; - if ((delta & 0x800000) || (delta < 3)) { - return -1; - } - - /* Clear and set TIMER0 to fire off at proper time */ - NRF_TIMER0_NS->TASKS_CLEAR = 1; - NRF_TIMER0_NS->CC[0] = rem_usecs; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Set RTC compare to start TIMER0 */ - NRF_RTC0_NS->EVENTS_COMPARE[0] = 0; - NRF_RTC0_NS->CC[0] = next_cc; - NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); - - /* Store the cputime at which we set the RTC */ - g_ble_phy_data.phy_start_cputime = cputime; - - return 0; -} - -static int -ble_phy_set_start_now(void) -{ - os_sr_t sr; - uint32_t now; - - OS_ENTER_CRITICAL(sr); - - /* - * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not - * occur in such case. - */ - NRF_TIMER0_NS->TASKS_CLEAR = 1; - NRF_TIMER0_NS->CC[0] = 1; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* - * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks - * from current value to guarantee triggering compare event, but let's set - * it to N+3 to account for possible extra tick on RTC0 during these - * operations. - */ - now = os_cputime_get32(); - NRF_RTC0_NS->EVENTS_COMPARE[0] = 0; - NRF_RTC0_NS->CC[0] = now + 3; - NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); - - /* - * Store the cputime at which we set the RTC - * - * XXX Compare event may be triggered on previous CC value (if it was set to - * less than N+2) so in rare cases actual start time may be 2 ticks earlier - * than what we expect. Since this is only used on RX, it may cause AUX scan - * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable - * for now. - */ - g_ble_phy_data.phy_start_cputime = now + 3; - - OS_EXIT_CRITICAL(sr); - - return 0; -} - -void -ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) -{ - uint32_t end_time; - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - - if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { - /* RX shall start exactly T_IFS after TX end captured in CC[2] */ - end_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - end_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Wait a bit longer due to allowed active clock accuracy */ - end_time += 2; - /* - * It's possible that we'll capture PDU start time at the end of timer - * cycle and since wfr expires at the beginning of calculated timer - * cycle it can be almost 1 usec too early. Let's compensate for this - * by waiting 1 usec more. - */ - end_time += 1; - } else { - /* - * RX shall start no later than wfr_usecs after RX enabled. - * CC[0] is the time of RXEN so adjust for radio ram-up. - * Do not add jitter since this is already covered by LL. - */ - end_time = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs; - } - - /* - * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so - * we are actually calculating relative to start of packet payload - * which is fine. - */ - - /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ - end_time += ble_phy_mode_pdu_start_off(phy); - /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ - end_time += g_ble_phy_t_rxaddrdelay[phy]; - - /* wfr_secs is the time from rxen until timeout */ - NRF_TIMER0_NS->CC[3] = end_time; - NRF_TIMER0_NS->EVENTS_COMPARE[3] = 0; - - /* Subscribe for wait for response events */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); - - /* - * It may happen that if CPU is halted for a brief moment (e.g. during flash - * erase or write), TIMER0 already counted past CC[3] and thus wfr will not - * fire as expected. In case this happened, let's just disable PPIs for wfr - * and trigger wfr manually (i.e. disable radio). - * - * Note that the same applies to RX start time set in CC[0] but since it - * should fire earlier than wfr, fixing wfr is enough. - * - * CC[1] is only used as a reference on RX start, we do not need it here so - * it can be used to read TIMER0 counter. - */ - NRF_TIMER0_NS->TASKS_CAPTURE[1] = 1; - if (NRF_TIMER0_NS->CC[1] > NRF_TIMER0_NS->CC[3]) { - /* Unsubscribe from wfr events */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); - - NRF_RADIO_NS->TASKS_DISABLE = 1; - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -static uint32_t -ble_phy_get_ccm_datarate(void) -{ -#if BLE_LL_BT5_PHY_SUPPORTED - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_2M: - return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_CODED_500KBPS: - return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; -#endif - } - - assert(0); - return 0; -#else - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; -#endif -} -#endif - -/** - * Setup transceiver for receive. - */ -static void -ble_phy_rx_xcvr_setup(void) -{ - uint8_t *dptr; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - NRF_RADIO_NS->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM_NS->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM_NS->OUTPTR = (uint32_t)dptr; - NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0]; - NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption | - ble_phy_get_ccm_datarate(); - NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data; - NRF_CCM_NS->SHORTS = 0; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->EVENTS_ENDCRYPT = 0; - NRF_CCM_NS->TASKS_KSGEN = 1; - - /* Subscribe to radio address event */ - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); - } else { - NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr; - } -#else - NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (g_ble_phy_data.phy_privacy) { - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Enabled; - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR_NS->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; - NRF_AAR_NS->EVENTS_END = 0; - NRF_AAR_NS->EVENTS_RESOLVED = 0; - NRF_AAR_NS->EVENTS_NOTRESOLVED = 0; - } else { - if (g_ble_phy_data.phy_encrypted == 0) { - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled; - } - } -#endif - - /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); - - /* Reset the rx started flag. Used for the wait for response */ - g_ble_phy_data.phy_rx_started = 0; - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; - -#if BLE_LL_BT5_PHY_SUPPORTED - /* - * On Coded PHY there are CI and TERM1 fields before PDU starts so we need - * to take this into account when setting up BCC. - */ - if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS || - g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - g_ble_phy_data.phy_bcc_offset = 5; - } else { - g_ble_phy_data.phy_bcc_offset = 0; - } -#else - g_ble_phy_data.phy_bcc_offset = 0; -#endif - - /* I want to know when 1st byte received (after address) */ - NRF_RADIO_NS->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */ - NRF_RADIO_NS->EVENTS_ADDRESS = 0; - NRF_RADIO_NS->EVENTS_DEVMATCH = 0; - NRF_RADIO_NS->EVENTS_BCMATCH = 0; - NRF_RADIO_NS->EVENTS_RSSIEND = 0; - NRF_RADIO_NS->EVENTS_CRCOK = 0; - NRF_RADIO_NS->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | - RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_ADDRESS_Msk | - RADIO_INTENSET_DISABLED_Msk; -} - -/** - * Called from interrupt context when the transmit ends - * - */ -static void -ble_phy_tx_end_isr(void) -{ - uint8_t tx_phy_mode; - uint8_t was_encrypted; - uint8_t transition; - uint32_t rx_time; - - /* Store PHY on which we've just transmitted smth */ - tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; - - /* If this transmission was encrypted we need to remember it */ - was_encrypted = g_ble_phy_data.phy_encrypted; - (void)was_encrypted; - - /* Better be in TX state! */ - assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: not sure what to do. We had a HW error during transmission. - * For now I just count a stat but continue on like all is good. - */ - if (was_encrypted) { - if (NRF_CCM_NS->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, tx_hw_err); - NRF_CCM_NS->EVENTS_ERROR = 0; - } - } -#endif - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } - - transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* Packet pointer needs to be reset. */ - ble_phy_rx_xcvr_setup(); - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0); - - /* Schedule RX exactly T_IFS after TX end captured in CC[2] */ - rx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - rx_time -= BLE_PHY_T_RXENFAST; - /* Start listening a bit earlier due to allowed active clock accuracy */ - rx_time -= 2; - - NRF_TIMER0_NS->CC[0] = rx_time; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Start radio on timer */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - - ble_phy_fem_enable_lna(); - } else { - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); - - assert(transition == BLE_PHY_TRANSITION_NONE); - } -} - -static inline uint8_t -ble_phy_get_cur_rx_phy_mode(void) -{ - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * For Coded PHY mode can be set to either codings since actual coding is - * set in packet header. However, here we need actual coding of received - * packet as this determines pipeline delays so need to figure this out - * using CI field. - */ - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - phy = NRF_RADIO_NS->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ? - BLE_PHY_MODE_CODED_500KBPS : BLE_PHY_MODE_CODED_125KBPS; - } -#endif - - return phy; -} - -static void -ble_phy_rx_end_isr(void) -{ - int rc; - uint8_t *dptr; - uint8_t crcok; - uint32_t tx_time; - struct ble_mbuf_hdr *ble_hdr; - - /* Disable automatic RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - - /* Set RSSI and CRC status flag in header */ - ble_hdr = &g_ble_phy_data.rxhdr; - assert(NRF_RADIO_NS->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO_NS->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - - /* Count PHY crc errors and valid packets */ - crcok = NRF_RADIO_NS->EVENTS_CRCOK; - if (!crcok) { - STATS_INC(ble_phy_stats, rx_crc_err); - } else { - STATS_INC(ble_phy_stats, rx_valid); - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - while (NRF_CCM_NS->EVENTS_ENDCRYPT == 0) { - /* Make sure CCM finished */ - }; - - /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM_NS->MICSTATUS == 0)) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; - } - - /* - * XXX: not sure how to deal with this. This should not - * be a MIC failure but we should not hand it up. I guess - * this is just some form of rx error and that is how we - * handle it? For now, just set CRC error flags - */ - if (NRF_CCM_NS->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - } -#endif - } - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* - * Let's schedule TX now and we will just cancel it after processing RXed - * packet if we don't need TX. - * - * We need this to initiate connection in case AUX_CONNECT_REQ was sent on - * LE Coded S8. In this case the time we process RXed packet is roughly the - * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI - * armed) so we may simply miss the slot and set the timer in the past. - * - * When TX is scheduled in advance, we may event process packet a bit longer - * during radio ramp-up - this gives us extra 40 usecs which is more than - * enough. - */ - - /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ - tx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between actual RX end time and EVENT_END */ - tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; - /* Adjust for delay between EVENT_READY and actual TX start time */ - tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - - NRF_TIMER0_NS->CC[0] = tx_time; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Enable automatic TX */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - - ble_phy_fem_enable_pa(); - - /* - * XXX: Hack warning! - * - * It may happen (during flash erase) that CPU is stopped for a moment and - * TIMER0 already counted past CC[0]. In such case we will be stuck waiting - * for TX to start since EVENTS_COMPARE[0] will not happen any time soon. - * For now let's set a flag denoting that we are late in RX-TX transition so - * ble_phy_tx() will fail - this allows everything to cleanup nicely without - * the need for extra handling in many places. - * - * Note: CC[3] is used only for wfr which we do not need here. - */ - NRF_TIMER0_NS->TASKS_CAPTURE[3] = 1; - if (NRF_TIMER0_NS->CC[3] > NRF_TIMER0_NS->CC[0]) { - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - - g_ble_phy_data.phy_transition_late = 1; - } - - /* - * XXX: This is a horrible ugly hack to deal with the RAM S1 byte - * that is not sent over the air but is present here. Simply move the - * data pointer to deal with it. Fix this later. - */ - dptr[2] = dptr[1]; - dptr[1] = dptr[0]; - rc = ble_ll_rx_end(dptr + 1, ble_hdr); - if (rc < 0) { - ble_phy_disable(); - } -} - -static bool -ble_phy_rx_start_isr(void) -{ - int rc; - uint32_t state; - uint32_t usecs; - uint32_t pdu_usecs; - uint32_t ticks; - struct ble_mbuf_hdr *ble_hdr; - uint8_t *dptr; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int adva_offset; -#endif - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - - /* Clear events and clear interrupt */ - NRF_RADIO_NS->EVENTS_ADDRESS = 0; - NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk; - - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); - - /* Initialize the ble mbuf header */ - ble_hdr = &g_ble_phy_data.rxhdr; - ble_hdr->rxinfo.flags = ble_ll_state_get(); - ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; - ble_hdr->rxinfo.handle = 0; - ble_hdr->rxinfo.phy = ble_phy_get_cur_phy(); - ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode(); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.user_data = NULL; -#endif - - /* - * Calculate accurate packets start time (with remainder) - * - * We may start receiving packet somewhere during preamble in which case - * it is possible that actual transmission started before TIMER0 was - * running - need to take this into account. - */ - ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime; - - usecs = NRF_TIMER0_NS->CC[1]; - pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) + - g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode]; - if (usecs < pdu_usecs) { - g_ble_phy_data.phy_start_cputime--; - usecs += 30; - } - usecs -= pdu_usecs; - - ticks = os_cputime_usecs_to_ticks(usecs); - usecs -= os_cputime_ticks_to_usecs(ticks); - if (usecs == 31) { - usecs = 0; - ++ticks; - } - - ble_hdr->beg_cputime += ticks; - ble_hdr->rem_usecs = usecs; - - /* Wait to get 1st byte of frame */ - while (1) { - state = NRF_RADIO_NS->STATE; - if (NRF_RADIO_NS->EVENTS_BCMATCH != 0) { - break; - } - - /* - * If state is disabled, we should have the BCMATCH. If not, - * something is wrong! - */ - if (state == RADIO_STATE_STATE_Disabled) { - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO_NS->SHORTS = 0; - return false; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * If privacy is enabled and received PDU has TxAdd bit set (i.e. random - * address) we try to resolve address using AAR. - */ - if (g_ble_phy_data.phy_privacy && (dptr[3] & 0x40)) { - /* - * AdvA is located at 4th octet in RX buffer (after S0, length an S1 - * fields). In case of extended advertising PDU we need to add 2 more - * octets for extended header. - */ - adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; - NRF_AAR_NS->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); - - /* Trigger AAR after last bit of AdvA is received */ - NRF_RADIO_NS->EVENTS_BCMATCH = 0; - NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH); - NRF_RADIO_NS->BCC = (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 + - g_ble_phy_data.phy_bcc_offset; - } -#endif - - /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(dptr + 3, - g_ble_phy_data.phy_chan, - &g_ble_phy_data.rxhdr); - if (rc >= 0) { - /* Set rx started flag and enable rx end ISR */ - g_ble_phy_data.phy_rx_started = 1; - } else { - /* Disable PHY */ - ble_phy_disable(); - STATS_INC(ble_phy_stats, rx_aborts); - } - - /* Count rx starts */ - STATS_INC(ble_phy_stats, rx_starts); - - return true; -} - -static void -ble_phy_isr(void) -{ - uint32_t irq_en; - - os_trace_isr_enter(); - - /* Read irq register to determine which interrupts are enabled */ - irq_en = NRF_RADIO_NS->INTENCLR; - - /* - * NOTE: order of checking is important! Possible, if things get delayed, - * we have both an ADDRESS and DISABLED interrupt in rx state. If we get - * an address, we disable the DISABLED interrupt. - */ - - /* We get this if we have started to receive a frame */ - if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO_NS->EVENTS_ADDRESS) { - /* - * wfr timer is calculated to expire at the exact time we should start - * receiving a packet (with 1 usec precision) so it is possible it will - * fire at the same time as EVENT_ADDRESS. If this happens, radio will - * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte - * of payload is received and ble_phy_rx_start_isr() will fail. In this - * case we should not clear DISABLED irq mask so it will be handled as - * regular radio disabled event below. In other case radio was disabled - * on purpose and there's nothing more to handle so we can clear mask. - */ - if (ble_phy_rx_start_isr()) { - irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; - } - } - - /* Handle disabled event. This is enabled for both TX and RX. On RX, we - * need to check phy_rx_started flag to make sure we actually were receiving - * a PDU, otherwise this is due to wfr. - */ - if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && - NRF_RADIO_NS->EVENTS_DISABLED) { - BLE_LL_ASSERT(NRF_RADIO_NS->EVENTS_END || - ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) && - !g_ble_phy_data.phy_rx_started)); - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->EVENTS_DISABLED = 0; - NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - - switch (g_ble_phy_data.phy_state) { - case BLE_PHY_STATE_RX: - ble_phy_fem_disable_lna(); - if (g_ble_phy_data.phy_rx_started) { - ble_phy_rx_end_isr(); - } else { - ble_ll_wfr_timer_exp(NULL); - } - break; - case BLE_PHY_STATE_TX: - ble_phy_fem_disable_pa(); - ble_phy_tx_end_isr(); - break; - default: - BLE_LL_ASSERT(0); - } - } - - g_ble_phy_data.phy_transition_late = 0; - /* Count # of interrupts */ - STATS_INC(ble_phy_stats, phy_isrs); - - os_trace_isr_exit(); -} - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \ - MYNEWT_VAL(BLE_LL_FEM_PA) || \ - MYNEWT_VAL(BLE_LL_FEM_LNA) -static int -ble_phy_gpiote_configure(int pin) -{ - NRF_GPIO_Type *port; - - g_ble_phy_gpiote_idx--; - - port = pin > 31 ? NRF_P1_NS : NRF_P0_NS; - pin &= 0x1f; - - /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */ - port->DIRSET = (1 << pin); - port->OUTCLR = (1 << pin); - - NRF_GPIOTE_NS->CONFIG[g_ble_phy_gpiote_idx] = - (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | - ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | - ((port == NRF_P1_NS) << GPIOTE_CONFIG_PORT_Pos); - - BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0); - - return g_ble_phy_gpiote_idx; -} -#endif - -static void -ble_phy_dbg_time_setup(void) -{ - int idx __attribute__((unused)) = 8; - - /* - * We setup GPIOTE starting from last configuration index to minimize risk - * of conflict with GPIO setup via hal. It's not great solution, but since - * this is just debugging code we can live with this. - */ - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); - phy_dbg_txrxen_ready_idx = idx; - - NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_READY); - - /* Publish RADIO->EVENTS_READY */ - NRF_RADIO_NS->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); - phy_dbg_address_end_idx = idx; - - NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_END); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); - phy_dbg_wfr_idx = idx; - - NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY); - - /* TODO figure out how (if?) to subscribe task to multiple DPPI channels - * Currently only last one is working. Also using multiple GPIOTE for same - * PIN doesn't work... - */ - NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); - - /* Publish RADIO->EVENTS_RXREADY */ - NRF_RADIO_NS->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY); - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY); - - /* Publish RADIO->EVENTS_DISABLED */ - NRF_RADIO_NS->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_DISABLED); -#endif -} - -int -ble_phy_init(void) -{ - int rc; - - g_ble_phy_gpiote_idx = 8; - - /* Default phy to use is 1M */ - g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M; - - g_ble_phy_data.rx_pwr_compensation = 0; - - /* Set phy channel to an invalid channel so first set channel works */ - g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - - /* Toggle peripheral power to reset (just in case) */ - NRF_RADIO_NS->POWER = 0; - NRF_RADIO_NS->POWER = 1; - *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) = (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000; - - /* Errata 16 - RADIO: POWER register is not functional - * Workaround: Reset all RADIO registers in firmware. - */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = 0; - NRF_RADIO_NS->SUBSCRIBE_RXEN = 0; - NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0; - - /* Disable all interrupts */ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Set configuration registers */ - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0; - - /* XXX: should maxlen be 251 for encryption? */ - NRF_RADIO_NS->PCNF1 = NRF_MAXLEN | - (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | - (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | - RADIO_PCNF1_WHITEEN_Msk; - - /* Enable radio fast ramp-up */ - NRF_RADIO_NS->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & RADIO_MODECNF0_RU_Msk; - - /* Set logical address 1 for TX and RX */ - NRF_RADIO_NS->TXADDRESS = 0; - NRF_RADIO_NS->RXADDRESSES = (1 << 0); - - /* Configure the CRC registers */ - NRF_RADIO_NS->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three; - - /* Configure BLE poly */ - NRF_RADIO_NS->CRCPOLY = 0x0000065B; - - /* Configure IFS */ - NRF_RADIO_NS->TIFS = BLE_LL_IFS; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - NRF_CCM_NS->INTENCLR = 0xffffffff; - NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM_NS->EVENTS_ERROR = 0; - memset(nrf_encrypt_scratchpad, 0, sizeof(nrf_encrypt_scratchpad)); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - g_ble_phy_data.phy_aar_scratch = 0; - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR_NS->INTENCLR = 0xffffffff; - NRF_AAR_NS->EVENTS_END = 0; - NRF_AAR_NS->EVENTS_RESOLVED = 0; - NRF_AAR_NS->EVENTS_NOTRESOLVED = 0; - NRF_AAR_NS->NIRK = 0; -#endif - - /* TIMER0 setup for PHY when using RTC */ - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - NRF_TIMER0_NS->BITMODE = 3; /* 32-bit timer */ - NRF_TIMER0_NS->MODE = 0; /* Timer mode */ - NRF_TIMER0_NS->PRESCALER = 4; /* gives us 1 MHz */ - - /* Publish events */ - NRF_TIMER0_NS->PUBLISH_COMPARE[0] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_0); - NRF_TIMER0_NS->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3); - NRF_RADIO_NS->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); - NRF_RADIO_NS->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); - NRF_RADIO_NS->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); - NRF_RTC0_NS->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); - - /* Enable channels we publish on */ - NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_ALL; - - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); - -#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA) - /* We keep both channels enabled and CLR task subscribed all the time. It's - * enough to just (un)subscribe SET task when needed. - * TODO: figure out if this affects power consumption - */ - - /* Publish TIMER0->EVENTS_COMPARE4 */ - NRF_TIMER0_NS->PUBLISH_COMPARE[4] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_4); - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_4); - /* Publish RADIO->EVENTS_DISABLED */ - NRF_RADIO_NS->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_DISABLED); - -#if FEM_SINGLE_GPIO - fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); - NRF_GPIOTE_NS->TASKS_CLR[fem_idx] = 1; -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) - fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_pa_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); - NRF_GPIOTE_NS->TASKS_CLR[fem_pa_idx] = 1; -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); - NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_lna_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); - NRF_GPIOTE_NS->TASKS_CLR[fem_lna_idx] = 1; -#endif -#endif - - NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK_FEM; -#endif - - /* Set isr in vector table and enable interrupt */ -#ifndef RIOT_VERSION - NVIC_SetPriority(RADIO_IRQn, 0); -#endif -#if MYNEWT - NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); -#else - ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr); -#endif - NVIC_EnableIRQ(RADIO_IRQn); - - /* Register phy statistics */ - if (!g_ble_phy_data.phy_stats_initialized) { - rc = stats_init_and_reg(STATS_HDR(ble_phy_stats), - STATS_SIZE_INIT_PARMS(ble_phy_stats, - STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_phy_stats), - "ble_phy"); - assert(rc == 0); - - g_ble_phy_data.phy_stats_initialized = 1; - } - - ble_phy_dbg_time_setup(); - - return 0; -} - -int -ble_phy_rx(void) -{ - /* - * Check radio state. - * - * In case radio is now disabling we'll wait for it to finish, but if for - * any reason it's just in idle state we proceed with RX as usual since - * nRF52 radio can ramp-up from idle state as well. - * - * Note that TX and RX states values are the same except for 3rd bit so we - * can make a shortcut here when checking for idle state. - */ - nrf_wait_disabled(); - if ((NRF_RADIO_NS->STATE != RADIO_STATE_STATE_Disabled) && - ((NRF_RADIO_NS->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, radio_state_errs); - return BLE_PHY_ERR_RADIO_STATE; - } - - /* Make sure all interrupts are disabled */ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Clear events prior to enabling receive */ - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->EVENTS_DISABLED = 0; - - /* Setup for rx */ - ble_phy_rx_xcvr_setup(); - - /* task to start RX should be subscribed here */ - assert(NRF_RADIO_NS->SUBSCRIBE_RXEN & DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0)); - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_central) -{ - memcpy(nrf_ccm_data.key, key, 16); - nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(nrf_ccm_data.iv, iv, 8); - nrf_ccm_data.dir_bit = is_central; - g_ble_phy_data.phy_encrypted = 1; - /* Enable the module (AAR cannot be on while CCM on) */ - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled; - NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Enabled; -} - -void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) -{ - nrf_ccm_data.pkt_counter = pkt_counter; - nrf_ccm_data.dir_bit = dir; -} - -void -ble_phy_encrypt_disable(void) -{ - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_CCM_NS->TASKS_STOP = 1; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Disabled; - - g_ble_phy_data.phy_encrypted = 0; -} -#endif - -void -ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) -{ - /* Set transmit end callback and arg */ - g_ble_phy_data.txend_cb = txend_cb; - g_ble_phy_data.txend_arg = arg; -} - -int -ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - int rc; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to RXEN since we are transmitting */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - - if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { - STATS_INC(ble_phy_stats, tx_late); - ble_phy_disable(); - rc = BLE_PHY_ERR_TX_LATE; - } else { - /* Enable PPI to automatically start TXEN */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - rc = 0; - - ble_phy_fem_enable_pa(); - } - return rc; -} - -int -ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - bool late = false; - int rc = 0; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to TXEN since we are transmitting */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - - if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { - STATS_INC(ble_phy_stats, rx_late); - - /* We're late so let's just try to start RX as soon as possible */ - ble_phy_set_start_now(); - - late = true; - } - - /* Enable PPI to automatically start RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - - ble_phy_fem_enable_lna(); - - /* Start rx */ - rc = ble_phy_rx(); - - /* - * If we enabled receiver but were late, let's return proper error code so - * caller can handle this. - */ - if (!rc && late) { - rc = BLE_PHY_ERR_RX_LATE; - } - - return rc; -} - -int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) -{ - int rc; - uint8_t *dptr; - uint8_t *pktptr; - uint8_t payload_len; - uint8_t hdr_byte; - uint32_t state; - uint32_t shortcuts; - - if (g_ble_phy_data.phy_transition_late) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - return BLE_PHY_ERR_TX_LATE; - } - - /* - * This check is to make sure that the radio is not in a state where - * it is moving to disabled state. If so, let it get there. - */ - nrf_wait_disabled(); - - /* - * XXX: Although we may not have to do this here, I clear all the PPI - * that should not be used when transmitting. Some of them are only enabled - * if encryption and/or privacy is on, but I dont care. Better to be - * paranoid, and if you are going to clear one, might as well clear them - * all. - */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; - pktptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM_NS->INPTR = (uint32_t)dptr; - NRF_CCM_NS->OUTPTR = (uint32_t)pktptr; - NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0]; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate(); - NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data; - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; -#endif - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; - } -#else - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; -#endif - - /* Set PDU payload */ - payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte); - - /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ - dptr[0] = hdr_byte; - dptr[1] = payload_len; - dptr[2] = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* Start key-stream generation and encryption (via short) */ - if (g_ble_phy_data.phy_encrypted) { - NRF_CCM_NS->TASKS_KSGEN = 1; - } -#endif - - NRF_RADIO_NS->PACKETPTR = (uint32_t)pktptr; - - /* Clear the ready, end and disabled events */ - NRF_RADIO_NS->EVENTS_READY = 0; - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->EVENTS_DISABLED = 0; - - /* Enable shortcuts for transmit start/end. */ - shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; - NRF_RADIO_NS->SHORTS = shortcuts; - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* Set the PHY transition */ - g_ble_phy_data.phy_transition = end_trans; - - /* Set transmitted payload length */ - g_ble_phy_data.phy_tx_pyld_len = payload_len; - - /* If we already started transmitting, abort it! */ - state = NRF_RADIO_NS->STATE; - if (state != RADIO_STATE_STATE_Tx) { - /* Set phy state to transmitting and count packet statistics */ - g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; - STATS_INC(ble_phy_stats, tx_good); - STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - rc = BLE_PHY_ERR_RADIO_STATE; - } - - return rc; -} - -int -ble_phy_txpwr_set(int dbm) -{ - /* "Rail" power level if outside supported range */ - dbm = ble_phy_txpower_round(dbm); - - NRF_RADIO_NS->TXPOWER = dbm; - g_ble_phy_data.phy_txpwr_dbm = dbm; - - return 0; -} - -int -ble_phy_txpower_round(int dbm) -{ - /* "Rail" power level if outside supported range */ - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; - } - - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; -} - -static int -ble_phy_set_access_addr(uint32_t access_addr) -{ - NRF_RADIO_NS->BASE0 = (access_addr << 8); - NRF_RADIO_NS->PREFIX0 = (NRF_RADIO_NS->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24); - - g_ble_phy_data.phy_access_address = access_addr; - - return 0; -} - -int -ble_phy_txpwr_get(void) -{ - return g_ble_phy_data.phy_txpwr_dbm; -} - -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - -int -ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) -{ - assert(chan < BLE_PHY_NUM_CHANS); - - /* Check for valid channel range */ - if (chan >= BLE_PHY_NUM_CHANS) { - return BLE_PHY_ERR_INV_PARAM; - } - - /* Set current access address */ - ble_phy_set_access_addr(access_addr); - - /* Configure crcinit */ - NRF_RADIO_NS->CRCINIT = crcinit; - - /* Set the frequency and the data whitening initial value */ - g_ble_phy_data.phy_chan = chan; - NRF_RADIO_NS->FREQUENCY = g_ble_phy_chan_freq[chan]; - NRF_RADIO_NS->DATAWHITEIV = chan; - - return 0; -} - -/** - * Stop the timer used to count microseconds when using RTC for cputime - */ -static void -ble_phy_stop_usec_timer(void) -{ - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - NRF_RTC0_NS->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; -} - -/** - * ble phy disable irq and ppi - * - * This routine is to be called when reception was stopped due to either a - * wait for response timeout or a packet being received and the phy is to be - * restarted in receive mode. Generally, the disable routine is called to stop - * the phy. - */ -static void -ble_phy_disable_irq_and_ppi(void) -{ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO_NS->SHORTS = 0; - NRF_RADIO_NS->TASKS_DISABLE = 1; - - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); - -#if FEM_SINGLE_GPIO - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(RADIO_EVENTS_READY); -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4); -#endif -#endif - - NVIC_ClearPendingIRQ(RADIO_IRQn); - g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; -} - -void -ble_phy_restart_rx(void) -{ - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); - - ble_phy_set_start_now(); - /* Enable PPI to automatically start RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); - - ble_phy_rx(); -} - -static void -ble_phy_dbg_clear_pins(void) -{ -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_txrxen_ready_idx] = 1; -#endif -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_address_end_idx] = 1; -#endif -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_wfr_idx] = 1; -#endif -} - -void -ble_phy_disable(void) -{ - ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); - - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); - ble_phy_fem_force_disable(); - ble_phy_dbg_clear_pins(); -} - -uint32_t -ble_phy_access_addr_get(void) -{ - return g_ble_phy_data.phy_access_address; -} - -int -ble_phy_state_get(void) -{ - return g_ble_phy_data.phy_state; -} - -int -ble_phy_rx_started(void) -{ - return g_ble_phy_data.phy_rx_started; -} - -uint8_t -ble_phy_xcvr_state_get(void) -{ - uint32_t state; - state = NRF_RADIO_NS->STATE; - return (uint8_t)state; -} - -uint8_t -ble_phy_max_data_pdu_pyld(void) -{ - return BLE_LL_DATA_PDU_MAX_PYLD; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -void -ble_phy_resolv_list_enable(void) -{ - NRF_AAR_NS->NIRK = (uint32_t)g_nrf_num_irks; - g_ble_phy_data.phy_privacy = 1; -} - -void -ble_phy_resolv_list_disable(void) -{ - g_ble_phy_data.phy_privacy = 0; -} -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -void -ble_phy_enable_dtm(void) -{ - /* When DTM is enabled we need to disable whitening as per - * Bluetooth v5.0 Vol 6. Part F. 4.1.1 - */ - NRF_RADIO_NS->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk; -} - -void -ble_phy_disable_dtm(void) -{ - /* Enable whitening */ - NRF_RADIO_NS->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk; -} -#endif - -void -ble_phy_rfclk_enable(void) -{ -#if MYNEWT - nrf5340_net_clock_hfxo_request(); -#else - NRF_CLOCK_NS->TASKS_HFCLKSTART = 1; -#endif -} - -void -ble_phy_rfclk_disable(void) -{ -#if MYNEWT - nrf5340_net_clock_hfxo_release(); -#else - NRF_CLOCK_NS->TASKS_HFCLKSTOP = 1; -#endif -} diff --git a/nimble/drivers/nrf5340/src/ble_phy_trace.c b/nimble/drivers/nrf5340/src/ble_phy_trace.c deleted file mode 100644 index dad7867907..0000000000 --- a/nimble/drivers/nrf5340/src/ble_phy_trace.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include "controller/ble_phy_trace.h" - -#if MYNEWT_VAL(BLE_PHY_SYSVIEW) - -static os_trace_module_t g_ble_phy_trace_mod; -uint32_t ble_phy_trace_off; - -static void -ble_phy_trace_module_send_desc(void) -{ - os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable"); -} - -void -ble_phy_trace_init(void) -{ - ble_phy_trace_off = - os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3, - ble_phy_trace_module_send_desc); -} -#endif diff --git a/nimble/drivers/nrf52/include/ble/xcvr.h b/nimble/drivers/nrf5x/include/ble/xcvr.h similarity index 75% rename from nimble/drivers/nrf52/include/ble/xcvr.h rename to nimble/drivers/nrf5x/include/ble/xcvr.h index 757bb80faa..829514b422 100644 --- a/nimble/drivers/nrf52/include/ble/xcvr.h +++ b/nimble/drivers/nrf5x/include/ble/xcvr.h @@ -24,14 +24,23 @@ extern "C" { #endif +#include + #define XCVR_RX_RADIO_RAMPUP_USECS (40) #define XCVR_TX_RADIO_RAMPUP_USECS (40) -/* - * NOTE: we have to account for the RTC output compare issue. We want it to be - * 5 ticks. +/* We need to account for the RTC compare issue, we want it to be 5 ticks. + * In case FEM turn on time is more than radio enable (i.e. 2 ticks) we want + * to add 1 more tick to compensate for additional delay. + * + * TODO this file should be refactored... */ +#if (MYNEWT_VAL(BLE_LL_FEM_PA) && (MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US) > 60)) || \ + (MYNEWT_VAL(BLE_LL_FEM_LNA) && (MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) > 60)) +#define XCVR_PROC_DELAY_USECS (183) +#else #define XCVR_PROC_DELAY_USECS (153) +#endif #define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) #define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) #define XCVR_TX_SCHED_DELAY_USECS \ diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml new file mode 100644 index 0000000000..b99e669248 --- /dev/null +++ b/nimble/drivers/nrf5x/pkg.yml @@ -0,0 +1,36 @@ +# +# 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. +# + +pkg.name: nimble/drivers/nrf5x +pkg.description: PHY for nRF52 and nRF53 series +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.apis: ble_driver +pkg.deps: + - nimble + - nimble/controller + +pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"': + - nrf52 +pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"': + - nrf53 diff --git a/nimble/drivers/nrf52/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c similarity index 100% rename from nimble/drivers/nrf52/src/ble_hw.c rename to nimble/drivers/nrf5x/src/ble_hw.c diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c similarity index 81% rename from nimble/drivers/nrf52/src/ble_phy.c rename to nimble/drivers/nrf5x/src/ble_phy.c index a94cb2a75a..52119d1ed3 100644 --- a/nimble/drivers/nrf52/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "syscfg/syscfg.h" #include "os/os.h" @@ -40,16 +39,25 @@ #include "controller/ble_ll.h" #include "nrfx.h" #if MYNEWT -#include "mcu/nrf52_clock.h" +#ifdef NRF52_SERIES +#include +#endif +#ifdef NRF53_SERIES +#include +#endif #include "mcu/cmsis_nvic.h" #include "hal/hal_gpio.h" #else #include "core_cm4.h" #endif +#include +#include "phy_priv.h" #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) -#error LE Coded PHY can only be enabled on nRF52811 or nRF52840 +#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_NET) +#error LE Coded PHY can only be enabled on nRF52811, nRF52840 or nRF5340 #endif #endif @@ -319,40 +327,6 @@ struct nrf_ccm_data struct nrf_ccm_data g_nrf_ccm_data; #endif -static int g_ble_phy_gpiote_idx; - -#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA) - -#define FEM_SINGLE_GPIO \ - (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \ - (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO))) - -#if FEM_SINGLE_GPIO -static uint8_t fem_idx; -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) -static uint8_t fem_pa_idx; -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) -static uint8_t fem_lna_idx; -#endif -#endif - -#endif - -#ifndef BABBLESIM -static void -ble_phy_apply_errata_102_106_107(void) -{ - /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS - * [106] RADIO: Higher CRC error rates for some access addresses - * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 - */ - *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) & - 0xfffffffe) | 0x01000000; -} -#endif - #if (BLE_LL_BT5_PHY_SUPPORTED == 1) /* Packet start offset (in usecs). This is the preamble plus access address. @@ -363,8 +337,8 @@ ble_phy_mode_pdu_start_off(int phy_mode) return g_ble_phy_mode_pkt_start_off[phy_mode]; } -#if NRF52840_XXAA -static inline bool +#if NRF52_ERRATA_191_ENABLE_WORKAROUND +static bool ble_phy_mode_is_coded(uint8_t phy_mode) { return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) || @@ -372,48 +346,26 @@ ble_phy_mode_is_coded(uint8_t phy_mode) } static void -ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode) +phy_nrf52_errata_191(uint8_t new_phy_mode) { - bool new_coded = ble_phy_mode_is_coded(new_phy_mode); - bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); + bool from_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); + bool to_coded = ble_phy_mode_is_coded(new_phy_mode); - /* - * Workarounds should be applied only when switching to/from LE Coded PHY - * so no need to apply them every time. - * - * nRF52840 Engineering A Errata v1.2 - * [164] RADIO: Low sensitivity in long range mode - * - * nRF52840 Rev 1 Errata - * [191] RADIO: High packet error rate in BLE Long Range mode + /* [191] RADIO: High packet error rate in BLE Long Range mode + * Should be applied only if switching to/from LE Coded, no need to apply + * on each mode change. */ - if (new_coded == cur_coded) { + if (from_coded == to_coded) { return; } - if (new_coded) { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C |= 0x80000000; - *(volatile uint32_t *)0x4000173C = - ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C); -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ - *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) | - 0x80000000 | (((uint32_t)(196)) << 8); -#endif + if (to_coded) { + *(volatile uint32_t *)0x40001740 = + ((*((volatile uint32_t *)0x40001740)) & 0x7fff00ff) | + 0x80000000 | (((uint32_t)(196)) << 8); } else { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C &= ~0x80000000; -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF); -#endif + ((*((volatile uint32_t *) 0x40001740)) & 0x7fffffff); } } #endif @@ -425,28 +377,42 @@ ble_phy_mode_apply(uint8_t phy_mode) return; } -#if NRF52840_XXAA - ble_phy_apply_nrf52840_errata(phy_mode); +#if NRF52_ERRATA_191_ENABLE_WORKAROUND + if (nrf52_errata_191()) { + phy_nrf52_errata_191(phy_mode); + } #endif switch (phy_mode) { case BLE_PHY_MODE_1M: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_1M; break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) case BLE_PHY_MODE_2M: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_2M; break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) case BLE_PHY_MODE_CODED_125KBPS: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; break; case BLE_PHY_MODE_CODED_500KBPS: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; break; #endif @@ -465,36 +431,6 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) } #endif -static void -ble_phy_fem_enable_pa(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_PA) - ble_ll_fem_pa_enable(); - -#if !FEM_SINGLE_GPIO - NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_pa_idx]); - NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_pa_idx]); -#endif - - NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; -#endif -} - -static void -ble_phy_fem_enable_lna(void) -{ -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - ble_ll_fem_lna_enable(); - -#if !FEM_SINGLE_GPIO - NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_lna_idx]); - NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_lna_idx]); -#endif - - NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; -#endif -} - int ble_phy_get_cur_phy(void) { @@ -670,41 +606,65 @@ ble_phy_tifs_get(void) * */ static int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) +ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) { uint32_t next_cc; uint32_t cur_cc; uint32_t cntr; uint32_t delta; + int radio_rem_us; +#if PHY_USE_FEM + int fem_rem_us = 0; +#endif + int rem_us_corr; + int min_rem_us; - /* - * We need to adjust start time to include radio ramp-up and TX pipeline - * delay (the latter only if applicable, so only for TX). - * - * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on - * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate - * using TIMER0 with 1 usec precision. + /* Calculate rem_us for radio and FEM enable. The result may be a negative + * value, but we'll adjust later. */ - - cputime -= 2; - rem_usecs += 61; if (tx) { - rem_usecs -= BLE_PHY_T_TXENFAST; - rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST - + g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; +#if PHY_USE_FEM_PA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US); +#endif } else { - rem_usecs -= BLE_PHY_T_RXENFAST; + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST; +#if PHY_USE_FEM_LNA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US); +#endif } - /* - * rem_usecs will be no more than 2 ticks, but if it is more than single - * tick then we should better count one more low-power tick rather than - * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the - * compare won't occur. +#if PHY_USE_FEM + min_rem_us = min(radio_rem_us, fem_rem_us); +#else + min_rem_us = radio_rem_us; +#endif + + /* We need to adjust rem_us values, so they are >=1 for TIMER0 compare + * event to be triggered. + * + * If FEM is not enabled, calculated rem_us is -45<=rem_us<=-15 since we + * only had to adjust earlier for ramp-up and txdelay, i.e. 40+5=45us in + * worst case, so we adjust by 1 or 2 tick(s) only. + * + * If FEM is enabled, turn on time may be a bit longer, so we also allow to + * adjust by 3 ticks so up to 90us which should be enough. If needed, we + * can extend this by another tick but having FEM with turn on time >90us + * means transition may become tricky. */ - if (rem_usecs > 30) { - cputime++; - rem_usecs -= 30; + if ((PHY_USE_FEM) && (min_rem_us <= -61)) { + cputime -= 3; + rem_us_corr = 91; + } else if (min_rem_us <= -30) { + /* rem_us is -60..-30 */ + cputime -= 2; + rem_us_corr = 61; + } else { + /* rem_us is -29..0 */ + cputime -= 1; + rem_us_corr = 30; } /* @@ -732,8 +692,14 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) /* Clear and set TIMER0 to fire off at proper time */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); - nrf_timer_cc_set(NRF_TIMER0, 0, rem_usecs); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us + rem_us_corr); NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM + if (fem_rem_us) { + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us + rem_us_corr); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + } +#endif /* Set RTC compare to start TIMER0 */ NRF_RTC0->EVENTS_COMPARE[0] = 0; @@ -741,7 +707,20 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); /* Enable PPI */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk); +#if PHY_USE_FEM + if (fem_rem_us) { + if (tx) { +#if PHY_USE_FEM_PA + phy_fem_enable_pa(); +#endif + } else { +#if PHY_USE_FEM_LNA + phy_fem_enable_lna(); +#endif + } + } +#endif + phy_ppi_rtc0_compare0_to_timer0_start_enable(); /* Store the cputime at which we set the RTC */ g_ble_phy_data.phy_start_cputime = cputime; @@ -754,16 +733,41 @@ ble_phy_set_start_now(void) { os_sr_t sr; uint32_t now; + uint32_t radio_rem_us; +#if PHY_USE_FEM_LNA + uint32_t fem_rem_us; +#endif OS_ENTER_CRITICAL(sr); - /* - * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not - * occur in such case. + /* We need to set TIMER0 compare registers to at least 1 as otherwise + * compare event won't be triggered. Event (FEM/radio) that have to be + * triggered first is set to 1, other event is set to 1+diff. + * + * Note that this is only used for rx, so only need to handle LNA. */ + +#if PHY_USE_FEM_LNA + if (MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) > BLE_PHY_T_RXENFAST) { + radio_rem_us = 1 + MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) - + BLE_PHY_T_RXENFAST; + fem_rem_us = 1; + } else { + radio_rem_us = 1; + fem_rem_us = 1 + BLE_PHY_T_RXENFAST - + MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US); + } +#else + radio_rem_us = 1; +#endif + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); - nrf_timer_cc_set(NRF_TIMER0, 0, 1); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us); NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM_LNA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; +#endif /* * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks @@ -777,7 +781,8 @@ ble_phy_set_start_now(void) nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); /* Enable PPI */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk); + phy_ppi_rtc0_compare0_to_timer0_start_enable(); + /* * Store the cputime at which we set the RTC * @@ -856,7 +861,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) NRF_TIMER0->EVENTS_COMPARE[3] = 0; /* Enable wait for response PPI */ - nrf_ppi_channels_enable(NRF_PPI, (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk)); + phy_ppi_wfr_enable(); /* * It may happen that if CPU is halted for a brief moment (e.g. during flash @@ -872,7 +877,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1); if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); + phy_ppi_wfr_disable(); nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); } } @@ -927,7 +932,7 @@ ble_phy_rx_xcvr_setup(void) NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->EVENTS_ENDCRYPT = 0; nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk); + phy_ppi_radio_address_to_ccm_crypt_enable(); } else { NRF_RADIO->PACKETPTR = (uint32_t)dptr; } @@ -951,7 +956,8 @@ ble_phy_rx_xcvr_setup(void) #endif /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); /* Reset the rx started flag. Used for the wait for response */ g_ble_phy_data.phy_rx_started = 0; @@ -1001,6 +1007,10 @@ ble_phy_tx_end_isr(void) uint8_t transition; uint32_t rx_time; uint32_t tx_time; +#if PHY_USE_FEM_LNA + uint32_t fem_time; +#endif + uint32_t radio_time; /* Store PHY on which we've just transmitted smth */ tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; @@ -1045,33 +1055,45 @@ ble_phy_tx_end_isr(void) rx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get(); /* Adjust for delay between EVENT_END and actual TX end time */ rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - rx_time -= BLE_PHY_T_RXENFAST; /* Start listening a bit earlier due to allowed active clock accuracy */ rx_time -= 2; - nrf_timer_cc_set(NRF_TIMER0, 0, rx_time); - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); +#if PHY_USE_FEM_LNA + fem_time = rx_time - MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_lna(); +#endif - ble_phy_fem_enable_lna(); + radio_time = rx_time - BLE_PHY_T_RXENFAST; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + + /* In case TIMER0 did already count past CC[0] and/or CC[2], radio + * and/or LNA may not be enabled. In any case we won't be stuck since + * wfr will cancel rx if needed. + * + * FIXME failing to enable LNA may result in unexpected RSSI drop in + * case we still rxd something, so perhaps we could check it here + */ } else if (transition == BLE_PHY_TRANSITION_TX_TX) { /* Schedule TX exactly T_IFS after TX end captured in CC[2] */ tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get(); /* Adjust for delay between EVENT_END and actual TX end time */ tx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; /* Adjust for delay between EVENT_READY and actual TX start time */ tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; nrf_timer_cc_set(NRF_TIMER0, 0, tx_time); NRF_TIMER0->EVENTS_COMPARE[0] = 0; - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); + phy_ppi_timer0_compare0_to_radio_txen_enable(); + + /* TODO handle PA */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3); if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); + phy_ppi_timer0_compare0_to_radio_txen_disable(); g_ble_phy_data.phy_transition_late = 1; } } else { @@ -1081,8 +1103,9 @@ ble_phy_tx_end_isr(void) */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); NRF_TIMER0->TASKS_SHUTDOWN = 1; - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk); + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_rtc0_compare0_to_timer0_start_disable(); assert(transition == BLE_PHY_TRANSITION_NONE); } } @@ -1119,10 +1142,15 @@ ble_phy_rx_end_isr(void) uint8_t *dptr; uint8_t crcok; uint32_t tx_time; +#if PHY_USE_FEM_PA + uint32_t fem_time; +#endif + uint32_t radio_time; struct ble_mbuf_hdr *ble_hdr; + bool is_late; /* Disable automatic RXEN */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk); + phy_ppi_timer0_compare0_to_radio_rxen_disable(); /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; @@ -1187,32 +1215,39 @@ ble_phy_rx_end_isr(void) tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get(); /* Adjust for delay between actual RX end time and EVENT_END */ tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; + +#if PHY_USE_FEM_PA + fem_time = tx_time - MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US); +#endif + /* Adjust for delay between EVENT_READY and actual TX start time */ tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - nrf_timer_cc_set(NRF_TIMER0, 0, tx_time); + radio_time = tx_time - BLE_PHY_T_TXENFAST; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); NRF_TIMER0->EVENTS_COMPARE[0] = 0; - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); + phy_ppi_timer0_compare0_to_radio_txen_enable(); - ble_phy_fem_enable_pa(); +#if PHY_USE_FEM_PA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); +#endif - /* - * XXX: Hack warning! - * - * It may happen (during flash erase) that CPU is stopped for a moment and - * TIMER0 already counted past CC[0]. In such case we will be stuck waiting - * for TX to start since EVENTS_COMPARE[0] will not happen any time soon. - * For now let's set a flag denoting that we are late in RX-TX transition so - * ble_phy_tx() will fail - this allows everything to cleanup nicely without - * the need for extra handling in many places. + /* Need to check if TIMER0 did not already count past CC[0] and/or CC[2], so + * we're not stuck waiting for events in case radio and/or PA was not + * started. If event was triggered we're fine regardless of timer value. * * Note: CC[3] is used only for wfr which we do not need here. */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3); - if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); + is_late = (NRF_TIMER0->CC[3] > radio_time) && !NRF_TIMER0->EVENTS_COMPARE[0]; +#if PHY_USE_FEM_PA + is_late = is_late || + ((NRF_TIMER0->CC[3] > fem_time) && !NRF_TIMER0->EVENTS_COMPARE[2]); +#endif + if (is_late) { + phy_ppi_timer0_compare0_to_radio_txen_disable(); g_ble_phy_data.phy_transition_late = 1; } @@ -1250,7 +1285,7 @@ ble_phy_rx_start_isr(void) nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk); /* Clear wfr timer channels */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); + phy_ppi_wfr_disable(); /* Initialize the ble mbuf header */ ble_hdr = &g_ble_phy_data.rxhdr; @@ -1332,7 +1367,7 @@ ble_phy_rx_start_isr(void) /* Trigger AAR after last bit of AdvA is received */ NRF_RADIO->EVENTS_BCMATCH = 0; - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk); + phy_ppi_radio_bcmatch_to_aar_start_enable(); nrf_radio_bcc_set(NRF_RADIO, (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 + g_ble_phy_data.phy_bcc_offset); } @@ -1409,7 +1444,7 @@ ble_phy_isr(void) switch (g_ble_phy_data.phy_state) { case BLE_PHY_STATE_RX: #if MYNEWT_VAL(BLE_LL_FEM_LNA) - NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; + phy_ppi_fem_disable(); ble_ll_fem_lna_disable(); #endif if (g_ble_phy_data.phy_rx_started) { @@ -1420,7 +1455,7 @@ ble_phy_isr(void) break; case BLE_PHY_STATE_TX: #if MYNEWT_VAL(BLE_LL_FEM_PA) - NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; + phy_ppi_fem_disable(); ble_ll_fem_pa_disable(); #endif ble_phy_tx_end_isr(); @@ -1438,95 +1473,6 @@ ble_phy_isr(void) os_trace_isr_exit(); } -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \ - MYNEWT_VAL(BLE_LL_FEM_PA) || \ - MYNEWT_VAL(BLE_LL_FEM_LNA) -static int -ble_phy_gpiote_configure(int pin) -{ - NRF_GPIO_Type *port; - - g_ble_phy_gpiote_idx--; - -#if NRF52840_XXAA - port = pin > 31 ? NRF_P1 : NRF_P0; - pin &= 0x1f; -#else - port = NRF_P0; -#endif - - /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */ - port->DIRSET = (1 << pin); - port->OUTCLR = (1 << pin); - - NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] = - (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | - ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | -#if NRF52840_XXAA - ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos); -#else - 0; -#endif - - BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0); - - return g_ble_phy_gpiote_idx; -} -#endif - -static void -ble_phy_dbg_time_setup(void) -{ - int idx __attribute__((unused)); - - /* - * We setup GPIOTE starting from last configuration index to minimize risk - * of conflict with GPIO setup via hal. It's not great solution, but since - * this is just debugging code we can live with this. - */ - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); - - nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, (uint32_t)&(NRF_RADIO->EVENTS_READY), - (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx])); - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk); - - /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ - nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx])); - nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx])); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); - - /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ - nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx])); - nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx])); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); - -#if NRF52840_XXAA - nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_RXREADY), - (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx])); -#else - nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_READY), - (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx])); -#endif - nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, (uint32_t)&(NRF_RADIO->EVENTS_DISABLED), - (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx])); - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk); - - /* CH[4] and CH[5] are always on for wfr */ - nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx])); - nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx])); -#endif -} - /** * ble phy init * @@ -1539,8 +1485,6 @@ ble_phy_init(void) { int rc; - g_ble_phy_gpiote_idx = 8; - /* Default phy to use is 1M */ g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; @@ -1559,6 +1503,19 @@ ble_phy_init(void) nrf_radio_power_set(NRF_RADIO, false); nrf_radio_power_set(NRF_RADIO, true); +#ifdef NRF53_SERIES + *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) = + (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000; +#if NRF53_ERRATA_16_ENABLE_WORKAROUND + if (nrf53_errata_16()) { + /* [16] RADIO: POWER register is not functional */ + NRF_RADIO_NS->SUBSCRIBE_TXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_RXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0; + } +#endif +#endif + /* Disable all interrupts */ nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); @@ -1589,9 +1546,6 @@ ble_phy_init(void) /* Configure IFS */ NRF_RADIO->TIFS = BLE_LL_IFS; - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) nrf_ccm_int_disable(NRF_CCM, 0xffffffff); NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; @@ -1616,39 +1570,13 @@ ble_phy_init(void) NRF_TIMER0->MODE = 0; /* Timer mode */ NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ - /* - * PPI setup. - * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used - * to cancel the wait for response timer. - * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait - * for response timer. - */ - nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4, - (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS), - (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3])); - nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5, - (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]), - (uint32_t)&(NRF_RADIO->TASKS_DISABLE)); - -#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA) -#if FEM_SINGLE_GPIO - fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); - NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_idx]); - NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_idx]); -#else -#if MYNEWT_VAL(BLE_LL_FEM_PA) - fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); - NRF_GPIOTE->TASKS_CLR[fem_pa_idx] = 1; -#endif -#if MYNEWT_VAL(BLE_LL_FEM_LNA) - fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); - NRF_GPIOTE->TASKS_CLR[fem_lna_idx] = 1; -#endif -#endif + phy_ppi_init(); - NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); - NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); - NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk; +#if PHY_USE_DEBUG + phy_debug_init(); +#endif +#if PHY_USE_FEM + phy_fem_init(); #endif /* Set isr in vector table and enable interrupt */ @@ -1674,8 +1602,6 @@ ble_phy_init(void) g_ble_phy_data.phy_stats_initialized = 1; } - ble_phy_dbg_time_setup(); - return 0; } @@ -1715,9 +1641,6 @@ ble_phy_rx(void) /* Setup for rx */ ble_phy_rx_xcvr_setup(); - /* PPI to start radio automatically shall be set here */ - assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk); - return 0; } @@ -1756,7 +1679,7 @@ ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) void ble_phy_encrypt_disable(void) { - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk); + phy_ppi_radio_address_to_ccm_crypt_disable(); nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP); NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled; @@ -1803,7 +1726,7 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) /* XXX: This should not be necessary, but paranoia is good! */ /* Clear timer0 compare to RXEN since we are transmitting */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk); + phy_ppi_timer0_compare0_to_radio_rxen_disable(); if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { STATS_INC(ble_phy_stats, tx_late); @@ -1811,10 +1734,8 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) rc = BLE_PHY_ERR_TX_LATE; } else { /* Enable PPI to automatically start TXEN */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); + phy_ppi_timer0_compare0_to_radio_txen_enable(); rc = 0; - - ble_phy_fem_enable_pa(); } return rc; @@ -1847,7 +1768,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) /* XXX: This should not be necessary, but paranoia is good! */ /* Clear timer0 compare to TXEN since we are transmitting */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); + phy_ppi_timer0_compare0_to_radio_txen_disable(); if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { STATS_INC(ble_phy_stats, rx_late); @@ -1859,9 +1780,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) } /* Enable PPI to automatically start RXEN */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); - - ble_phy_fem_enable_lna(); + phy_ppi_timer0_compare0_to_radio_rxen_enable(); /* Start rx */ rc = ble_phy_rx(); @@ -1907,8 +1826,9 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * paranoid, and if you are going to clear one, might as well clear them * all. */ - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk); + phy_ppi_wfr_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + phy_ppi_radio_address_to_ccm_crypt_disable(); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { @@ -1999,8 +1919,8 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) int ble_phy_txpwr_set(int dbm) { - /* "Rail" power level if outside supported range */ - dbm = ble_phy_txpower_round(dbm); + /* Get actual TX power supported by radio */ + dbm = phy_txpower_round(dbm); NRF_RADIO->TXPOWER = dbm; g_ble_phy_data.phy_txpwr_dbm = dbm; @@ -2017,40 +1937,10 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_txpower_round(int dbm) { - /* TODO this should be per nRF52XXX */ - - /* "Rail" power level if outside supported range */ - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; - } - - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; + return phy_txpower_round(dbm); } /** @@ -2070,9 +1960,21 @@ ble_phy_set_access_addr(uint32_t access_addr) g_ble_phy_data.phy_access_address = access_addr; +#if NRF52_ERRATA_102_ENABLE_WORKAROUND || \ + NRF52_ERRATA_106_ENABLE_WORKAROUND || \ + NRF52_ERRATA_107_ENABLE_WORKAROUND #ifndef BABBLESIM - ble_phy_apply_errata_102_106_107(); + if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) { + /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS + * [106] RADIO: Higher CRC error rates for some access addresses + * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 + */ + *(volatile uint32_t *)0x40001774 = + ((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000; + } #endif +#endif + return 0; } @@ -2158,10 +2060,7 @@ ble_phy_disable_irq_and_ppi(void) nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); NRF_RADIO->SHORTS = 0; nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk); - nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); + phy_ppi_disable(); NVIC_ClearPendingIRQ(RADIO_IRQn); g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; } @@ -2174,7 +2073,7 @@ ble_phy_restart_rx(void) ble_phy_set_start_now(); /* Enable PPI to automatically start RXEN */ - nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); + phy_ppi_timer0_compare0_to_radio_rxen_enable(); ble_phy_rx(); } @@ -2193,6 +2092,10 @@ ble_phy_disable(void) ble_phy_stop_usec_timer(); ble_phy_disable_irq_and_ppi(); + +#if PHY_USE_FEM + phy_fem_disable(); +#endif } /* Gets the current access address */ @@ -2284,7 +2187,12 @@ void ble_phy_rfclk_enable(void) { #if MYNEWT || defined(RIOT_VERSION) +#ifdef NRF52_SERIES nrf52_clock_hfxo_request(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_request(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); #endif @@ -2294,7 +2202,12 @@ void ble_phy_rfclk_disable(void) { #if MYNEWT || defined(RIOT_VERSION) +#ifdef NRF52_SERIES nrf52_clock_hfxo_release(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_release(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); #endif diff --git a/nimble/drivers/nrf52/src/ble_phy_trace.c b/nimble/drivers/nrf5x/src/ble_phy_trace.c similarity index 100% rename from nimble/drivers/nrf52/src/ble_phy_trace.c rename to nimble/drivers/nrf5x/src/ble_phy_trace.c diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c new file mode 100644 index 0000000000..188d157111 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf52/phy.c @@ -0,0 +1,214 @@ +/* + * 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. + */ + +#include +#include +#include +#include "../phy_priv.h" + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk); + + /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_2])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_2])); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + +#if NRF52840_XXAA + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_RXREADY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_3])); +#else + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[GIDX_DEBUG_3])); +#endif + nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, + (uint32_t)&(NRF_RADIO->EVENTS_DISABLED), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk); + + /* CH[4] and CH[5] are always on for wfr */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); +#endif + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM]); +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[2]); + NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); + + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +#if PHY_USE_FEM_PA +void +phy_fem_enable_pa(void) +{ + ble_ll_fem_pa_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control PA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_PA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +#if PHY_USE_FEM_LNA +void +phy_fem_enable_lna(void) +{ + ble_ll_fem_lna_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control LNA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_LNA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* radio_address_to_timer0_capture1 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk); + /* radio_end_to_timer0_capture2 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH27_Msk); + + /* + * PPI setup. + * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used + * to cancel the wait for response timer. + * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait + * for response timer. + */ + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4, + (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS), + (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3])); + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5, + (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]), + (uint32_t)&(NRF_RADIO->TASKS_DISABLE)); +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h new file mode 100644 index 0000000000..a77b718339 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h @@ -0,0 +1,113 @@ +/* + * 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 H_PHY_PPI_ +#define H_PHY_PPI_ + +#include + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_fem_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +static inline void +phy_ppi_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | + PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk | + PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | + PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk | + PPI_CHEN_CH31_Msk); +} + +#endif /* H_PHY_PPI_ */ diff --git a/nimble/drivers/nrf5x/src/nrf53/phy.c b/nimble/drivers/nrf5x/src/nrf53/phy.c new file mode 100644 index 0000000000..78b45578c5 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf53/phy.c @@ -0,0 +1,235 @@ +/* + * 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. + */ + +#include +#include +#include +#include "../phy_priv.h" + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(RADIO_EVENTS_READY); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_END); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + + NRF_RADIO->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY) | + DPPI_CH_MASK(RADIO_EVENTS_DISABLED); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY); + + /* TODO figure out how (if?) to subscribe task to multiple DPPI channels + * Currently only last one is working. Also using multiple GPIOTE for same + * PIN doesn't work... + */ + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); + +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init() +{ + /* We can keep clear tasks subscribed and published channels always enabled, + * it's enough to just (un)subscribe set tasks when needed. + * TODO: check if this affects power consumption + */ + + NRF_TIMER0->PUBLISH_COMPARE[2] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_2); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); +#endif + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_DPPIC->CHENSET = DPPI_CH_MASK_FEM; +} + +void +phy_fem_enable_pa(void) +{ + ble_ll_fem_pa_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} + +void +phy_fem_enable_lna(void) +{ + ble_ll_fem_lna_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* Publish events */ + NRF_TIMER0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_0); + NRF_TIMER0->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); + NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); + NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); + + /* Enable channels we publish on */ + NRF_DPPIC->CHENSET = DPPI_CH_ENABLE_ALL; + + /* radio_address_to_timer0_capture1 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + /* radio_end_to_timer0_capture2 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; + } + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h new file mode 100644 index 0000000000..6412f32753 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h @@ -0,0 +1,159 @@ +/* + * 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 H_PHY_PPI_ +#define H_PHY_PPI_ + +#define DPPI_CH_PUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_SUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_UNSUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31)) +#define DPPI_CH_MASK(_ch) (1 << (DPPI_CH_ ## _ch)) + +/* Channels 0..5 are always used. + * Channels 6 and 7 are used for PA/LNA (optionally). + * Channels 7..9 are used for GPIO debugging (optionally). + */ + +#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1 +#define DPPI_CH_RADIO_EVENTS_END 2 +#define DPPI_CH_RADIO_EVENTS_BCMATCH 3 +#define DPPI_CH_RADIO_EVENTS_ADDRESS 4 +#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_2 6 +#define DPPI_CH_RADIO_EVENTS_DISABLED 7 +#define DPPI_CH_RADIO_EVENTS_READY 8 +#define DPPI_CH_RADIO_EVENTS_RXREADY 9 + +#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | \ + DPPIC_CHEN_CH2_Msk | DPPIC_CHEN_CH3_Msk | \ + DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk) + +#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \ + DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#endif +} + +static inline void +phy_ppi_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + + phy_ppi_fem_disable(); +} + +#endif /* H_PHY_PPI_ */ \ No newline at end of file diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h new file mode 100644 index 0000000000..8cf140ee3d --- /dev/null +++ b/nimble/drivers/nrf5x/src/phy_priv.h @@ -0,0 +1,90 @@ +/* + * 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 H_PHY_PRIV_ +#define H_PHY_PRIV_ + +#include +#include +#include + +#define PHY_USE_DEBUG_1 (MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0) +#define PHY_USE_DEBUG_2 (MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0) +#define PHY_USE_DEBUG_3 (MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0) +#define PHY_USE_DEBUG (PHY_USE_DEBUG_1 || PHY_USE_DEBUG_2 || PHY_USE_DEBUG_3) + +#define PHY_USE_FEM_PA (MYNEWT_VAL(BLE_LL_FEM_PA) != 0) +#define PHY_USE_FEM_LNA (MYNEWT_VAL(BLE_LL_FEM_LNA) != 0) +#define PHY_USE_FEM (PHY_USE_FEM_PA || PHY_USE_FEM_LNA) +#define PHY_USE_FEM_SINGLE_GPIO \ + (PHY_USE_FEM && (!PHY_USE_FEM_PA || !PHY_USE_FEM_LNA || \ + (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == \ + MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)))) + +/* GPIOTE indexes, start assigning from last one */ +#define PHY_GPIOTE_DEBUG_1 (8 - PHY_USE_DEBUG_1) +#define PHY_GPIOTE_DEBUG_2 (PHY_GPIOTE_DEBUG_1 - PHY_USE_DEBUG_2) +#define PHY_GPIOTE_DEBUG_3 (PHY_GPIOTE_DEBUG_2 - PHY_USE_DEBUG_3) +#if PHY_USE_FEM_SINGLE_GPIO +#define PHY_GPIOTE_FEM (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM) +#else +#define PHY_GPIOTE_FEM_PA (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM_PA) +#define PHY_GPIOTE_FEM_LNA (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA) +#endif + +static inline void +phy_gpiote_configure(int idx, int pin) +{ + nrf_gpio_cfg_output(pin); + nrf_gpiote_task_configure(NRF_GPIOTE, idx, pin, NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE, idx); +} + +#if PHY_USE_DEBUG +void phy_debug_init(void); +#endif + +#if PHY_USE_FEM +void phy_fem_init(void); +#if PHY_USE_FEM_PA +void phy_fem_enable_pa(void); +#endif +#if PHY_USE_FEM_LNA +void phy_fem_enable_lna(void); +#endif +void phy_fem_disable(void); +#endif + +void phy_ppi_init(void); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif + +int8_t phy_txpower_round(int8_t dbm); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif +#ifdef NRF53_SERIES +#include "nrf53/phy_ppi.h" +#endif + +#endif /* H_PHY_PRIV_ */ diff --git a/nimble/drivers/nrf5340/syscfg.yml b/nimble/drivers/nrf5x/syscfg.yml similarity index 71% rename from nimble/drivers/nrf5340/syscfg.yml rename to nimble/drivers/nrf5x/syscfg.yml index ed82f6d604..1d4027f7d0 100644 --- a/nimble/drivers/nrf5340/syscfg.yml +++ b/nimble/drivers/nrf5x/syscfg.yml @@ -25,14 +25,9 @@ syscfg.defs: BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: description: > When set to proper GPIO pin number, this pin will be set - to high state when radio is enabled (TASKS_TXEN or TASKS_RXEN) - and back to low state on radio EVENTS_READY. + to high state when radio is enabled using PPI channels + 20 or 21 and back to low state on radio EVENTS_READY. This can be used to measure radio ram-up time. - - Note: - GPIO control for selected pin needs to be assigned to Network - Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on - Application Core. value: -1 BLE_PHY_DBG_TIME_ADDRESS_END_PIN: @@ -41,11 +36,6 @@ syscfg.defs: to high state on radio EVENTS_ADDRESS and back to low state on radio EVENTS_END. This can be used to measure radio pipeline delays. - - Note: - GPIO control for selected pin needs to be assigned to Network - Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on - Application Core. value: -1 BLE_PHY_DBG_TIME_WFR_PIN: @@ -54,9 +44,17 @@ syscfg.defs: to high state on radio EVENTS_RXREADY and back to low state when wfr timer expires. This can be used to check if wfr is calculated properly. - - Note: - GPIO control for selected pin needs to be assigned to Network - Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on - Application Core. value: -1 + + BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR: + description: > + Ublox BMD-345 modules come with public address preprogrammed + in UICR register. If enabled public address will be read from + custom UICR instead of FICR register. + value: 0 + +syscfg.restrictions: + # code supports turn on times up to 90us due to some optimizations, but it + # should be enough for most (all?) cases + - "!BLE_LL_FEM_PA || BLE_LL_FEM_PA_TURN_ON_US <= 90" + - "!BLE_LL_FEM_LNA || BLE_LL_FEM_LNA_TURN_ON_US <= 90"