You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2022/09/14 10:52:39 UTC
[mynewt-nimble] 06/09: nimble/phy/nrf5x: Add nRF53 support
This is an automated email from the ASF dual-hosted git repository.
andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 9ea411fbe637ca4b0e40d32a9741e6ac8cb57a3f
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 8 12:13:15 2022 +0200
nimble/phy/nrf5x: Add nRF53 support
This adds code for nRF5340 net core.
---
nimble/drivers/nrf5x/pkg.yml | 5 +
nimble/drivers/nrf5x/src/ble_phy.c | 48 ++++++-
nimble/drivers/nrf5x/src/nrf53/phy.c | 235 +++++++++++++++++++++++++++++++
nimble/drivers/nrf5x/src/nrf53/phy_ppi.h | 159 +++++++++++++++++++++
nimble/drivers/nrf5x/src/phy_priv.h | 8 ++
5 files changed, 452 insertions(+), 3 deletions(-)
diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml
index e0b314ea..b99e6692 100644
--- a/nimble/drivers/nrf5x/pkg.yml
+++ b/nimble/drivers/nrf5x/pkg.yml
@@ -29,3 +29,8 @@ 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/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index 36f209c5..0d9b363f 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -39,7 +39,12 @@
#include "controller/ble_ll.h"
#include "nrfx.h"
#if MYNEWT
-#include "mcu/nrf52_clock.h"
+#ifdef NRF52_SERIES
+#include <mcu/nrf52_clock.h>
+#endif
+#ifdef NRF53_SERIES
+#include <mcu/nrf5340_net_clock.h>
+#endif
#include "mcu/cmsis_nvic.h"
#include "hal/hal_gpio.h"
#else
@@ -49,8 +54,10 @@
#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
@@ -379,21 +386,33 @@ ble_phy_mode_apply(uint8_t phy_mode)
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
@@ -1392,6 +1411,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);
@@ -2071,7 +2103,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
@@ -2081,7 +2118,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/nrf5x/src/nrf53/phy.c b/nimble/drivers/nrf5x/src/nrf53/phy.c
new file mode 100644
index 00000000..78b45578
--- /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 <stdint.h>
+#include <nrfx.h>
+#include <controller/ble_ll_fem.h>
+#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 00000000..6412f327
--- /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
index 1a026a6d..8cf140ee 100644
--- a/nimble/drivers/nrf5x/src/phy_priv.h
+++ b/nimble/drivers/nrf5x/src/phy_priv.h
@@ -20,6 +20,7 @@
#ifndef H_PHY_PRIV_
#define H_PHY_PRIV_
+#include <stdint.h>
#include <nrf_gpio.h>
#include <nrf_gpiote.h>
@@ -79,4 +80,11 @@ void phy_ppi_init(void);
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_ */