diff --git a/babblesim/core/src/cmsis.c b/babblesim/core/src/cmsis.c index 1ac6b2414c..319144c39f 100644 --- a/babblesim/core/src/cmsis.c +++ b/babblesim/core/src/cmsis.c @@ -78,3 +78,8 @@ void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) { systemVectors[(int32_t)IRQn + 16] = (void(*)(void))vector; } + +uint32_t NVIC_GetVector(IRQn_Type IRQn) +{ + return (uint32_t)systemVectors[(int32_t)IRQn + 16]; +} diff --git a/nimble/controller/include/controller/ble_phy.h b/nimble/controller/include/controller/ble_phy.h index fe70044234..e740e72ed3 100644 --- a/nimble/controller/include/controller/ble_phy.h +++ b/nimble/controller/include/controller/ble_phy.h @@ -60,12 +60,23 @@ struct os_mbuf; #define BLE_PHY_STATE_IDLE (0) #define BLE_PHY_STATE_RX (1) #define BLE_PHY_STATE_TX (2) +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define BLE_PHY_STATE_TX_CS_TONE (3) +#define BLE_PHY_STATE_RX_CS_TONE (4) +#endif /* BLE PHY transitions */ -#define BLE_PHY_TRANSITION_NONE (0) -#define BLE_PHY_TRANSITION_RX_TX (1) -#define BLE_PHY_TRANSITION_TX_RX (2) -#define BLE_PHY_TRANSITION_TX_TX (3) +#define BLE_PHY_TRANSITION_NONE (0) +#define BLE_PHY_TRANSITION_TO_TX (1) +#define BLE_PHY_TRANSITION_TO_RX (2) +#define BLE_PHY_TRANSITION_TO_TX_ISO_SUBEVENT (3) +#define BLE_PHY_TRANSITION_TO_RX_ISO_SUBEVENT (4) +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define BLE_PHY_TRANSITION_TO_TX_CS_SYNC (5) +#define BLE_PHY_TRANSITION_TO_RX_CS_SYNC (6) +#define BLE_PHY_TRANSITION_TO_TX_CS_TONE (7) +#define BLE_PHY_TRANSITION_TO_RX_CS_TONE (8) +#endif /* PHY error codes */ #define BLE_PHY_ERR_RADIO_STATE (1) @@ -78,6 +89,39 @@ struct os_mbuf; /* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */ #define BLE_PHY_MAX_PDU_LEN (257) +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define BLE_PHY_CS_TRANSM_MODE_SYNC (0) +#define BLE_PHY_CS_TRANSM_MODE_TONE (2) + +#define BLE_PHY_CS_TONE_MODE_FM (0) +#define BLE_PHY_CS_TONE_MODE_PM (1) + +struct ble_phy_cs_transmission { + struct ble_phy_cs_transmission *next; + uint32_t duration_usecs; + uint32_t aa; + uint16_t end_tifs; + uint8_t channel; + uint8_t mode; + uint8_t is_tx; + uint8_t tone_mode; +}; + +struct ble_phy_cs_sync_results { + uint32_t cputime; + uint32_t rem_us; + uint32_t rem_ns; + int16_t rssi; +}; + +struct ble_phy_cs_tone_results { + /* TODO */ +}; + +/* Configure the PHY for CS subevent sequence */ +int ble_phy_cs_subevent_start(struct ble_phy_cs_transmission *transm, uint32_t cputime, uint8_t rem_usecs); +#endif + /* Wait for response timer */ typedef void (*ble_phy_tx_end_func)(void *arg); @@ -88,14 +132,8 @@ int ble_phy_init(void); int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit); uint8_t ble_phy_chan_get(void); -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) -/* Set T_ifs time for next transition */ -void ble_phy_tifs_set(uint16_t tifs); -#endif - -/* Set T_ifs for tx-tx transitions. Anchor is 0 for start of previous PDU, - * non-zero for end of PDU */ -void ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor); +/* Set direction of the next transition */ +void ble_phy_transition_set(uint8_t trans, uint16_t usecs); /* Set transmit start time */ int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs); @@ -110,7 +148,7 @@ typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte); /* Place the PHY into transmit mode */ -int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans); +int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg); /* Copies the received PHY buffer into the allocated pdu */ void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu); diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index 3b36c87a53..caa7b1cf8f 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -1121,7 +1121,6 @@ static int ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) { int rc; - uint8_t end_trans; uint32_t txstart; struct ble_ll_adv_sm *advsm; @@ -1183,18 +1182,18 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) || (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE))) { - end_trans = BLE_PHY_TRANSITION_TX_RX; + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_RX, BLE_LL_IFS); ble_phy_set_txend_cb(NULL, NULL); } else { - end_trans = BLE_PHY_TRANSITION_NONE; + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); } /* Transmit advertisement */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - rc = ble_phy_tx(ble_ll_adv_pdu_make, advsm, end_trans); + rc = ble_phy_tx(ble_ll_adv_pdu_make, advsm); #else - rc = ble_phy_tx(ble_ll_adv_legacy_pdu_make, advsm, end_trans); + rc = ble_phy_tx(ble_ll_adv_legacy_pdu_make, advsm); #endif if (rc) { goto adv_tx_done; @@ -1268,7 +1267,6 @@ static int ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) { int rc; - uint8_t end_trans; uint32_t txstart; struct ble_ll_adv_sm *advsm; ble_phy_tx_pducb_t pducb; @@ -1319,22 +1317,22 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) /* Set phy mode based on type of advertisement */ if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - end_trans = BLE_PHY_TRANSITION_TX_RX; + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_RX, BLE_LL_IFS); ble_phy_set_txend_cb(NULL, NULL); pducb = ble_ll_adv_aux_pdu_make; } else if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) && advsm->aux_first_pdu) { - end_trans = BLE_PHY_TRANSITION_TX_RX; + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_RX, BLE_LL_IFS); ble_phy_set_txend_cb(NULL, NULL); pducb = ble_ll_adv_aux_scannable_pdu_make; } else { - end_trans = BLE_PHY_TRANSITION_NONE; + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); pducb = ble_ll_adv_aux_pdu_make; } /* Transmit advertisement */ - rc = ble_phy_tx(pducb, advsm, end_trans); + rc = ble_phy_tx(pducb, advsm); if (rc) { goto adv_aux_dropped; } @@ -2322,8 +2320,9 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) #endif /* Transmit advertisement */ + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); ble_phy_set_txend_cb(ble_ll_adv_sync_tx_end, advsm); - rc = ble_phy_tx(ble_ll_adv_sync_pdu_make, advsm, BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(ble_ll_adv_sync_pdu_make, advsm); if (rc) { goto adv_tx_done; } @@ -4547,6 +4546,8 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) */ ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (advsm->flags & BLE_LL_ADV_SM_FLAG_SCAN_REQ_NOTIF) { ble_ll_hci_ev_send_scan_req_recv(advsm->adv_instance, peer, @@ -4560,12 +4561,10 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) */ advsm->rx_ble_hdr = ble_hdr; - rc = ble_phy_tx(ble_ll_adv_scan_rsp_pdu_make, advsm, - BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(ble_ll_adv_scan_rsp_pdu_make, advsm); advsm->rx_ble_hdr = NULL; #else - rc = ble_phy_tx(ble_ll_adv_scan_rsp_legacy_pdu_make, advsm, - BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(ble_ll_adv_scan_rsp_legacy_pdu_make, advsm); #endif if (!rc) { @@ -4599,9 +4598,9 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) rsp_data.peer = rxbuf + BLE_LL_PDU_HDR_LEN; rsp_data.rxadd = rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK; + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); ble_phy_set_txend_cb(ble_ll_adv_tx_done, advsm); - rc = ble_phy_tx(ble_ll_adv_aux_conn_rsp_pdu_make, &rsp_data, - BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(ble_ll_adv_aux_conn_rsp_pdu_make, &rsp_data); if (!rc) { ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD); STATS_INC(ble_ll_stats, aux_conn_rsp_tx); @@ -4892,6 +4891,8 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type) */ if (rc < 0) { ble_ll_adv_tx_done(advsm); + } else if (rc > 0){ + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_TX, BLE_LL_IFS); } return rc; diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index 65ff4cb0d9..98b775a16d 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -1347,7 +1347,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) txend_func = ble_ll_conn_wait_txend; } else { /* Wait for a response here */ - end_transition = BLE_PHY_TRANSITION_TX_RX; + end_transition = BLE_PHY_TRANSITION_TO_RX; txend_func = NULL; } @@ -1435,9 +1435,11 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) } #endif + ble_phy_transition_set(end_transition, BLE_LL_IFS); + /* Set transmit end callback */ ble_phy_set_txend_cb(txend_func, connsm); - rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, m, end_transition); + rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, m); if (!rc) { /* Log transmit on connection state */ cur_txlen = ble_hdr->txinfo.pyld_len; @@ -3269,9 +3271,11 @@ ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu, ble_ll_conn_prepare_connect_ind(connsm, ble_ll_scan_get_pdu_data(), addrd, rxhdr->rxinfo.channel); + ble_phy_transition_set(ext ? BLE_PHY_TRANSITION_TO_RX : + BLE_PHY_TRANSITION_NONE, + BLE_LL_IFS); ble_phy_set_txend_cb(NULL, NULL); - rc = ble_phy_tx(ble_ll_conn_tx_connect_ind_pducb, connsm, - ext ? BLE_PHY_TRANSITION_TX_RX : BLE_PHY_TRANSITION_NONE); + rc = ble_phy_tx(ble_ll_conn_tx_connect_ind_pducb, connsm); if (rc) { ble_ll_conn_send_connect_req_cancel(); return -1; diff --git a/nimble/controller/src/ble_ll_dtm.c b/nimble/controller/src/ble_ll_dtm.c index c57a1357a1..b4c618513e 100644 --- a/nimble/controller/src/ble_ll_dtm.c +++ b/nimble/controller/src/ble_ll_dtm.c @@ -244,7 +244,8 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) goto resched; } - rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om, BLE_PHY_TRANSITION_NONE); + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); + rc = ble_phy_tx(ble_ll_tx_mbuf_pducb, ctx->om); if (rc) { goto resched; } diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c index 5aee5de123..52fc33b766 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -688,7 +688,8 @@ ble_ll_iso_big_control_tx(struct ble_ll_iso_big *big) ble_phy_set_txend_cb(ble_ll_iso_big_control_txend_cb, big); ble_phy_setchan(chan_idx, big->ctrl_aa, big->crc_init << 8); - rc = ble_phy_tx(ble_ll_iso_big_control_pdu_cb, big, BLE_PHY_TRANSITION_NONE); + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); + rc = ble_phy_tx(ble_ll_iso_big_control_pdu_cb, big); return rc; } @@ -773,9 +774,12 @@ ble_ll_iso_big_subevent_tx(struct ble_ll_iso_big *big) to_tx = (big->tx.subevents_rem > 1) || big->cstf; - rc = ble_phy_tx(ble_ll_iso_big_subevent_pdu_cb, big, - to_tx ? BLE_PHY_TRANSITION_TX_TX - : BLE_PHY_TRANSITION_NONE); + ble_phy_transition_set(to_tx ? BLE_PHY_TRANSITION_TO_TX_ISO_SUBEVENT : + BLE_PHY_TRANSITION_NONE, + big->interleaved ? big->bis_spacing : + big->sub_interval); + + rc = ble_phy_tx(ble_ll_iso_big_subevent_pdu_cb, big); return rc; } @@ -874,12 +878,6 @@ ble_ll_iso_big_event_sched_cb(struct ble_ll_sched_item *sch) big->tx.bis = STAILQ_FIRST(&big->bis_q); big->tx.bis->tx.subevent_num = 1; - if (big->interleaved) { - ble_phy_tifs_txtx_set(big->bis_spacing, 0); - } else { - ble_phy_tifs_txtx_set(big->sub_interval, 0); - } - rc = ble_phy_tx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, sch->remainder); if (rc) { diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c index 157ba94c1b..6ac826102a 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -1563,7 +1563,8 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, rpa_index); - rc = ble_phy_tx(ble_ll_scan_req_tx_pdu_cb, scansm, BLE_PHY_TRANSITION_TX_RX); + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_RX, BLE_LL_IFS); + rc = ble_phy_tx(ble_ll_scan_req_tx_pdu_cb, scansm); if (rc) { return false; } diff --git a/nimble/controller/src/ble_ll_scan_aux.c b/nimble/controller/src/ble_ll_scan_aux.c index b61f729db1..19ce440752 100644 --- a/nimble/controller/src/ble_ll_scan_aux.c +++ b/nimble/controller/src/ble_ll_scan_aux.c @@ -1226,8 +1226,8 @@ ble_ll_scan_aux_send_scan_req(struct ble_ll_scan_aux_data *aux, * interrupted if scheduler kicks in. */ - rc = ble_phy_tx(ble_ll_scan_aux_scan_req_tx_pdu_cb, aux, - BLE_PHY_TRANSITION_TX_RX); + ble_phy_transition_set(BLE_PHY_TRANSITION_TO_RX, BLE_LL_IFS); + rc = ble_phy_tx(ble_ll_scan_aux_scan_req_tx_pdu_cb, aux); if (rc) { return false; } diff --git a/nimble/drivers/dialog_cmac/src/ble_phy.c b/nimble/drivers/dialog_cmac/src/ble_phy.c index c077f25ff3..3fe68dddde 100644 --- a/nimble/drivers/dialog_cmac/src/ble_phy.c +++ b/nimble/drivers/dialog_cmac/src/ble_phy.c @@ -580,7 +580,7 @@ ble_phy_irq_field_tx_exc_bs_start_4this(void) { CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_BS_START_4THIS_Msk; - if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) { + if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TO_RX) { /* * Setup 2nd frame that will start after current one. * -2us offset to adjust for allowed active clock accuracy. @@ -642,7 +642,7 @@ ble_phy_irq_frame_tx_exc_bs_stop(void) /* Clear latched timestamp so we do not have error on next frame */ (void)CMAC->CM_TS1_REG; - if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) { + if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TO_RX) { #if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx); #endif @@ -665,7 +665,7 @@ ble_phy_irq_frame_tx_exc_phy_to_idle_4this(void) { CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk; - if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) { + if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TO_RX) { ble_phy_rx_setup_xcvr(); g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; @@ -1403,7 +1403,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) } int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) +ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg) { uint8_t *txbuf = g_ble_phy_tx_buf; int rc; @@ -1412,8 +1412,6 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) assert(CMAC->CM_FRAME_1_REG & CMAC_CM_FRAME_1_REG_FRAME_TX_Msk); - g_ble_phy_data.end_transition = end_trans; - /* * Program required fields now so in worst case TX can continue while we * are still preparing header and payload. @@ -1829,3 +1827,9 @@ ble_phy_dtm_carrier(uint8_t rf_channel) } #endif #endif + +void +ble_phy_transition_set(uint8_t trans, uint16_t usecs) +{ + g_ble_phy_data.end_transition = trans; +} diff --git a/nimble/drivers/native/src/ble_phy.c b/nimble/drivers/native/src/ble_phy.c index e1d2e4aa73..3ac326064c 100644 --- a/nimble/drivers/native/src/ble_phy.c +++ b/nimble/drivers/native/src/ble_phy.c @@ -241,7 +241,7 @@ ble_phy_isr(void) ble_xcvr_clear_irq(BLE_XCVR_IRQ_F_TX_END); transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { + if (transition == BLE_PHY_TRANSITION_TO_RX) { /* Disable the phy */ /* XXX: count no bufs? */ ble_phy_disable(); @@ -422,7 +422,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) +ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg) { uint8_t hdr_byte; int rc; @@ -440,9 +440,6 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) } else { } - /* Set the PHY transition */ - g_ble_phy_data.phy_transition = end_trans; - /* Set phy state to transmitting and count packet statistics */ g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; ++g_ble_phy_stats.tx_good; @@ -662,6 +659,7 @@ ble_phy_rfclk_disable(void) } void -ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor) +ble_phy_transition_set(uint8_t trans, uint16_t usecs) { + g_ble_phy_data.phy_transition = trans; } diff --git a/nimble/drivers/nrf51/src/ble_phy.c b/nimble/drivers/nrf51/src/ble_phy.c index 955db6351f..21e65906bf 100644 --- a/nimble/drivers/nrf51/src/ble_phy.c +++ b/nimble/drivers/nrf51/src/ble_phy.c @@ -585,7 +585,7 @@ ble_phy_tx_end_isr(void) } transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { + if (transition == BLE_PHY_TRANSITION_TO_RX) { /* Packet pointer needs to be reset. */ ble_phy_rx_xcvr_setup(); @@ -1127,7 +1127,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) } int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) +ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg) { int rc; uint8_t *dptr; @@ -1200,7 +1200,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) /* Enable shortcuts for transmit start/end. */ shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; - if (end_trans == BLE_PHY_TRANSITION_TX_RX) { + if (g_ble_phy_data.phy_transition == BLE_PHY_TRANSITION_TO_RX) { shortcuts |= RADIO_SHORTS_DISABLED_RXEN_Msk; } NRF_RADIO->SHORTS = shortcuts; @@ -1216,9 +1216,6 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) dptr[2] = 0; } - /* 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; @@ -1523,3 +1520,9 @@ ble_phy_rfclk_disable(void) NRF_CLOCK->TASKS_HFCLKSTOP = 1; #endif } + +void +ble_phy_transition_set(uint8_t trans, uint16_t usecs) +{ + g_ble_phy_data.phy_transition = trans; +} diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml index b99e669248..5780a654ce 100644 --- a/nimble/drivers/nrf5x/pkg.yml +++ b/nimble/drivers/nrf5x/pkg.yml @@ -30,7 +30,19 @@ pkg.deps: - nimble - nimble/controller -pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"': - - nrf52 -pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"': - - nrf53 +pkg.source_files: + - "src/ble_hw.c" + - "src/ble_phy.c" + - "src/ble_phy_trace.c" + +pkg.source_files.'MCU_TARGET=="nRF52810" || MCU_TARGET=="nRF52811" || MCU_TARGET=="nRF52832" || MCU_TARGET=="nRF52840"': + - "src/nrf52/phy.c" + +pkg.source_files.'MCU_TARGET=="nRF5340_NET"': + - "src/nrf53/phy.c" + +pkg.source_files.'MCU_TARGET=="nRF54L15"': + - "src/nrf54l15/phy.c" + +pkg.source_files.'BLE_CHANNEL_SOUNDING': + - "src/ble_phy_cs.c" diff --git a/nimble/drivers/nrf5x/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c index 9a46fa6c85..3b4c0210e1 100644 --- a/nimble/drivers/nrf5x/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -36,9 +36,27 @@ #include #endif #include "os/os_trace_api.h" +#ifndef NRF54L_SERIES #include +#endif #include "hal/nrf_ecb.h" +#ifdef NRF54L_SERIES +#include + +#define NRF_ECB NRF_ECB00 +#define NRF_AAR NRF_AAR00 + +/* ECB data structure */ +struct ecb_job_entry { + uint8_t *ptr; + uint32_t attr_and_length; +}; + +static struct ecb_job_entry ecb_input_job_list[2]; +static struct ecb_job_entry ecb_output_job_list[2]; +#endif + /* Total number of resolving list elements */ #define BLE_HW_RESOLV_LIST_SIZE (16) @@ -276,6 +294,43 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) uint32_t end; uint32_t err; +#ifdef NRF54L_SERIES + /* Stop ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOP); + + ecb_input_job_list[0].ptr = ecb->plain_text; + ecb_input_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); + ecb_output_job_list[0].ptr = ecb->cipher_text; + ecb_output_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); + + /* The end of a job list shall be 0 */ + ecb_input_job_list[1].ptr = 0; + ecb_input_job_list[1].attr_and_length = 0; + ecb_output_job_list[1].ptr = 0; + ecb_output_job_list[1].attr_and_length = 0; + + NRF_ECB->EVENTS_END = 0; + NRF_ECB->EVENTS_ERROR = 0; + NRF_ECB->IN.PTR = (uint32_t)ecb_input_job_list; + NRF_ECB->OUT.PTR = (uint32_t)ecb_output_job_list; + memcpy((void *)NRF_ECB->KEY.VALUE, ecb->key, sizeof(uint32_t) * 4); + + /* Start ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_START); + + /* Wait till error or done */ + rc = 0; + while (1) { + end = NRF_ECB->EVENTS_END; + err = NRF_ECB->EVENTS_ERROR; + if (end || err) { + if (err) { + rc = -1; + } + break; + } + } +#else /* Stop ECB */ nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB); /* XXX: does task stop clear these counters? Anyway to do this quicker? */ @@ -301,7 +356,7 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) tm_tick(); #endif } - +#endif return rc; } @@ -314,7 +369,25 @@ ble_rng_isr(void) uint8_t rnum; os_trace_isr_enter(); +#ifdef NRF54L_SERIES + /* No callback? Clear and disable interrupts */ + if (g_ble_rng_isr_cb == NULL) { + nrf_cracen_int_disable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL &= ~CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + NRF_CRACEN->EVENTS_RNG = 0; + os_trace_isr_exit(); + return; + } + if (g_ble_rng_isr_cb) { + /* If there is a value ready in the queue grab it */ + while ((NRF_CRACENCORE->RNGCONTROL.CONTROL & + CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk) && + (NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL > 0)) { + g_ble_rng_isr_cb(ble_hw_rng_read()); + } + } +#else /* No callback? Clear and disable interrupts */ if (g_ble_rng_isr_cb == NULL) { nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); @@ -330,7 +403,7 @@ ble_rng_isr(void) rnum = (uint8_t)NRF_RNG->VALUE; (*g_ble_rng_isr_cb)(rnum); } - +#endif os_trace_isr_exit(); } @@ -345,6 +418,24 @@ ble_rng_isr(void) int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) { +#ifdef NRF54L_SERIES + NRF_CRACEN->ENABLE = CRACEN_ENABLE_CRYPTOMASTER_Msk | + CRACEN_ENABLE_RNG_Msk | + CRACEN_ENABLE_PKEIKG_Msk; + + while (NRF_CRACENCORE->PK.STATUS & CRACENCORE_PK_STATUS_PKBUSY_Msk); + NRF_CRACENCORE->PK.CONTROL &= ~CRACENCORE_IKG_PKECONTROL_CLEARIRQ_Msk; + + NRF_CRACENCORE->RNGCONTROL.CONTROL = CRACENCORE_RNGCONTROL_CONTROL_ResetValue | + CRACENCORE_RNGCONTROL_CONTROL_ENABLE_Msk; + + /* If we were passed a function pointer we need to enable the interrupt */ + if (cb != NULL) { + NVIC_SetVector(CRACEN_IRQn, (uint32_t)ble_rng_isr); + NVIC_EnableIRQ(CRACEN_IRQn); + g_ble_rng_isr_cb = cb; + } +#else /* Set bias */ if (bias) { NRF_RNG->CONFIG = 1; @@ -365,6 +456,7 @@ ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) NVIC_EnableIRQ(RNG_IRQn); g_ble_rng_isr_cb = cb; } +#endif return 0; } @@ -381,12 +473,23 @@ ble_hw_rng_start(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); +#ifdef NRF54L_SERIES + NRF_CRACEN->EVENTS_RNG = 0; + + if (g_ble_rng_isr_cb) { + nrf_cracen_int_enable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL |= CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + /* Force regeneration of the samples */ + NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL = 0; + } +#else NRF_RNG->EVENTS_VALRDY = 0; if (g_ble_rng_isr_cb) { nrf_rng_int_enable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); } nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START); +#endif OS_EXIT_CRITICAL(sr); return 0; @@ -404,9 +507,15 @@ ble_hw_rng_stop(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); +#ifdef NRF54L_SERIES + nrf_cracen_int_disable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL &= ~CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + NRF_CRACEN->EVENTS_RNG = 0; +#else nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP); NRF_RNG->EVENTS_VALRDY = 0; +#endif OS_EXIT_CRITICAL(sr); return 0; @@ -421,14 +530,28 @@ uint8_t ble_hw_rng_read(void) { uint8_t rnum; +#ifdef NRF54L_SERIES + uint8_t slot_id; + /* Wait for a sample */ + while (NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL == 0) { + assert((NRF_CRACENCORE->RNGCONTROL.STATUS & + CRACENCORE_RNGCONTROL_STATUS_STATE_Msk) != + (CRACENCORE_RNGCONTROL_STATUS_STATE_ERROR << + CRACENCORE_RNGCONTROL_STATUS_STATE_Pos)); + } + + NRF_CRACEN->EVENTS_RNG = 0; + slot_id = NRF_CRACENCORE->RNGCONTROL.FIFODEPTH - NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL; + rnum = (uint8_t)NRF_CRACENCORE->RNGCONTROL.FIFO[slot_id]; +#else /* Wait for a sample */ while (NRF_RNG->EVENTS_VALRDY == 0) { } NRF_RNG->EVENTS_VALRDY = 0; rnum = (uint8_t)NRF_RNG->VALUE; - +#endif return rnum; } @@ -511,7 +634,11 @@ int ble_hw_resolv_list_match(void) { if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { +#ifdef NRF54L_SERIES + return (int)NRF_AAR->ERRORSTATUS; +#else return (int)NRF_AAR->STATUS; +#endif } return -1; diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c index 3deec7dd63..b475a9b965 100644 --- a/nimble/drivers/nrf5x/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -68,10 +68,6 @@ #endif #endif -#if BABBLESIM -extern void tm_tick(void); -#endif - #include /* @@ -102,37 +98,6 @@ extern void tm_tick(void); 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->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 { @@ -160,12 +125,9 @@ struct ble_phy_obj void *txend_arg; ble_phy_tx_end_func txend_cb; uint32_t phy_start_cputime; -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) - uint16_t tifs; -#endif - - uint16_t txtx_time_us; - uint8_t txtx_time_anchor; + uint16_t wfr_usecs; + uint16_t tifs_usecs; + uint8_t tifs_anchor; }; static struct ble_phy_obj g_ble_phy_data; @@ -204,25 +166,68 @@ static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { #if BABBLESIM /* delay between EVENTS_READY and start of tx */ -static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { +const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 1, [BLE_PHY_MODE_2M] = 1, }; +/* delay between EVENTS_ADDRESS and txd access address */ +const uint8_t g_ble_phy_t_txaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 1, + [BLE_PHY_MODE_2M] = 1, + [BLE_PHY_MODE_CODED_125KBPS] = 1, + [BLE_PHY_MODE_CODED_500KBPS] = 1, +}; /* delay between EVENTS_END and end of txd packet */ -static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { +const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 1, [BLE_PHY_MODE_2M] = 1, }; /* 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] = { +const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 9, [BLE_PHY_MODE_2M] = 5, }; /* delay between end of rxd packet and EVENTS_END */ -static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { +const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 9, [BLE_PHY_MODE_2M] = 5, }; +#elif defined(NRF54L_SERIES) +/* delay between EVENTS_READY and start of tx */ +const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 2, /* ~1.6us */ + [BLE_PHY_MODE_2M] = 5, + [BLE_PHY_MODE_CODED_125KBPS] = 5, + [BLE_PHY_MODE_CODED_500KBPS] = 5 +}; +/* delay between EVENTS_ADDRESS and txd access address */ +const uint8_t g_ble_phy_t_txaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 3, /* ~3.2us */ + [BLE_PHY_MODE_2M] = 5, + [BLE_PHY_MODE_CODED_125KBPS] = 17, + [BLE_PHY_MODE_CODED_500KBPS] = 17 +}; +/* delay between EVENTS_END and end of txd packet */ +const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 2, /* ~2.3us */ + [BLE_PHY_MODE_2M] = 4, + [BLE_PHY_MODE_CODED_125KBPS] = 9, + [BLE_PHY_MODE_CODED_500KBPS] = 3 +}; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, /* ~9.2us */ + [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 */ +const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, /* ~9.1us */ + [BLE_PHY_MODE_2M] = 1, + [BLE_PHY_MODE_CODED_125KBPS] = 27, + [BLE_PHY_MODE_CODED_500KBPS] = 22 +}; #else /* delay between EVENTS_READY and start of tx */ static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { @@ -588,7 +593,7 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) * disable states. We want to wait until that state is over before doing * anything to the radio */ -static void +void nrf_wait_disabled(void) { uint32_t state; @@ -609,19 +614,11 @@ nrf_wait_disabled(void) } } -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) -void -ble_phy_tifs_set(uint16_t tifs) -{ - g_ble_phy_data.tifs = tifs; -} -#endif - /** * * */ -static int +int ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) { uint32_t next_cc; @@ -819,6 +816,35 @@ ble_phy_set_start_now(void) return 0; } +void +ble_phy_wfr_enable_at(uint32_t end_time) +{ + /* wfr_secs is the time from rxen until timeout */ + nrf_timer_cc_set(NRF_TIMER0, 3, end_time); + NRF_TIMER0->EVENTS_COMPARE[3] = 0; + + /* Enable wait for response PPI */ + phy_ppi_wfr_enable(); + + /* + * 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { + phy_ppi_wfr_disable(); + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + } +} + /** * Function is used to set PPI so that we can time out waiting for a reception * to occur. This happens for two reasons: we have sent a packet and we are @@ -843,11 +869,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) phy = g_ble_phy_data.phy_cur_phy_mode; -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) - tifs = g_ble_phy_data.tifs; -#else - tifs = BLE_LL_IFS; -#endif + tifs = g_ble_phy_data.tifs_usecs; if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { /* RX shall start exactly T_IFS after TX end captured in CC[2] */ @@ -885,30 +907,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) /* 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_timer_cc_set(NRF_TIMER0, 3, end_time); - NRF_TIMER0->EVENTS_COMPARE[3] = 0; - - /* Enable wait for response PPI */ - phy_ppi_wfr_enable(); - - /* - * 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1); - if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { - phy_ppi_wfr_disable(); - nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); - } + ble_phy_wfr_enable_at(end_time); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) @@ -923,9 +922,17 @@ ble_phy_get_ccm_datarate(void) 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: +#ifdef NRF54L_SERIES + return CCM_MODE_DATARATE_125Kbit << CCM_MODE_DATARATE_Pos; +#else return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; +#endif case BLE_PHY_MODE_CODED_500KBPS: +#ifdef NRF54L_SERIES + return CCM_MODE_DATARATE_500Kbit << CCM_MODE_DATARATE_Pos; +#else return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; +#endif #endif } @@ -951,6 +958,19 @@ ble_phy_rx_xcvr_setup(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; +#ifdef NRF54L_SERIES + NRF_CCM->IN.PTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->OUT.PTR = (uint32_t)dptr; + /* TODO: Find replacement for removed registers like this one + * NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; + */ + NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | CCM_MODE_MODE_Decryption | + ble_phy_get_ccm_datarate(); + memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->EVENTS_END = 0; + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_START); +#else NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; NRF_CCM->OUTPTR = (uint32_t)dptr; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; @@ -961,6 +981,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); +#endif phy_ppi_radio_address_to_ccm_crypt_enable(); } else { NRF_RADIO->PACKETPTR = (uint32_t)dptr; @@ -972,8 +993,13 @@ ble_phy_rx_xcvr_setup(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (g_ble_phy_data.phy_privacy) { NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; + /* TODO: Find replacement for NRF_AAR->SCRATCHPTR */ +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; +#endif NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; NRF_AAR->EVENTS_NOTRESOLVED = 0; @@ -1012,16 +1038,213 @@ ble_phy_rx_xcvr_setup(void) NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->EVENTS_DEVMATCH = 0; NRF_RADIO->EVENTS_BCMATCH = 0; +#ifndef NRF54L_SERIES NRF_RADIO->EVENTS_RSSIEND = 0; +#endif NRF_RADIO->EVENTS_CRCOK = 0; - NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - + RADIO_SHORTS_ADDRESS_RSSISTART_Msk; +#ifdef NRF54L_SERIES + NRF_RADIO->SHORTS |= RADIO_SHORTS_PHYEND_DISABLE_Msk; +#else + NRF_RADIO->SHORTS |= RADIO_SHORTS_END_DISABLE_Msk | + RADIO_SHORTS_DISABLED_RSSISTOP_Msk; +#endif nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk | - RADIO_INTENSET_DISABLED_Msk); + RADIO_INTENSET_DISABLED_Msk); +} + +uint32_t +ble_phy_transition_anchor_get(uint8_t tifs_anchor, uint8_t phy_state, uint8_t phy_mode) +{ + uint32_t time; + + if (tifs_anchor == PHY_TRANS_ANCHOR_END) { + /* END timestamp is captured in CC[2] */ + time = NRF_TIMER0->CC[2]; + + /* Adjust for delay between EVENT_END and actual TX/RX end time */ + time += (phy_state == BLE_PHY_STATE_TX) + ? g_ble_phy_t_txenddelay[phy_mode] + : -g_ble_phy_t_rxenddelay[phy_mode]; + + } else { + /* ADDRESS timestamp is captured in CC[1] */ + time = NRF_TIMER0->CC[1]; + + /* Adjust for delay between EVENT_ADDRESS and actual AA time ota */ + time += (phy_state == BLE_PHY_STATE_TX) + ? g_ble_phy_t_txaddrdelay[phy_mode] + : -g_ble_phy_t_rxaddrdelay[phy_mode]; + + /* Adjust by sync word length to get TX/RX start time */ + time -= ble_ll_pdu_syncword_us(phy_mode); + } + + return time; +} + +static int +ble_transition_to_tx(uint8_t tifs_anchor, uint16_t tifs_usecs, uint8_t phy_state) +{ + uint32_t anchor_time; + uint32_t radio_time; + uint32_t start_time; + bool is_late; + uint8_t next_phy_mode; + uint8_t prev_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + +#if MYNEWT_VAL(BLE_LL_PHY) + ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); +#endif + next_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + + anchor_time = ble_phy_transition_anchor_get(tifs_anchor, phy_state, prev_phy_mode); + start_time = anchor_time + tifs_usecs; + radio_time = start_time; + +#if PHY_USE_FEM_PA + fem_time = anchor_time - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); +#endif + + /* Adjust for TX rump-up */ + radio_time -= BLE_PHY_T_TXENFAST; + /* Adjust for delay between EVENT_READY and actual TX start time */ + radio_time -= g_ble_phy_t_txdelay[next_phy_mode]; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + + /* 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); + 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] > NRF_TIMER0->CC[2]) && + !NRF_TIMER0->EVENTS_COMPARE[2]); +#endif + if (is_late) { + g_ble_phy_data.phy_transition_late = 1; + + return 1; + } + + return 0; +} + +static int +ble_transition_to_rx(uint8_t tifs_anchor, uint16_t tifs_usecs, uint16_t wfr_usecs, + uint8_t phy_state) +{ + uint32_t anchor_time; + uint32_t radio_time; + uint32_t start_time; + uint32_t wfr_time; + uint8_t next_phy_mode; + uint8_t prev_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + +#if MYNEWT_VAL(BLE_LL_PHY) + ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); +#endif + /* Packet pointer needs to be reset. */ + ble_phy_rx_xcvr_setup(); + next_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + + anchor_time = ble_phy_transition_anchor_get(tifs_anchor, phy_state, prev_phy_mode); + start_time = anchor_time + tifs_usecs; + radio_time = start_time; + +#if PHY_USE_FEM_LNA + fem_time = anchor_time - MYNEWT_VAL(BLE_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 + + /* Adjust for RX rump-up */ + radio_time -= BLE_PHY_T_RXENFAST; + /* Start listening a bit earlier due to allowed active clock accuracy */ + radio_time -= 2; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + + /* Setup wfr relative to expected radio/PDU start */ + wfr_time = start_time; + /* Add amount of usecs to wait */ + wfr_time += wfr_usecs; + /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ + wfr_time += ble_phy_mode_pdu_start_off(next_phy_mode); + /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ + wfr_time += g_ble_phy_t_rxaddrdelay[next_phy_mode]; + /* Wait a bit longer due to allowed active clock accuracy */ + wfr_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. + */ + wfr_time += 1; + wfr_time += MYNEWT_VAL(BLE_PHY_EXTENDED_TIFS); + ble_phy_wfr_enable_at(wfr_time); + + /* 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 + */ + + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + + return 0; +} + +static int +ble_transition_to_none(void) +{ + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES + NRF_TIMER0->TASKS_SHUTDOWN = 1; +#endif + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_rtc0_compare0_to_timer0_start_disable(); + ble_phy_disable(); + phy_ppi_fem_disable(); + + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); + + return 0; +} + +static int +ble_phy_transition(uint8_t transition, uint8_t tifs_anchor, uint16_t tifs_usecs, + uint16_t wfr_usecs, uint8_t phy_state) +{ + int rc = 1; + + if (transition == PHY_TRANS_TO_TX) { + rc = ble_transition_to_tx(tifs_anchor, tifs_usecs, phy_state); + } else if (transition == PHY_TRANS_TO_RX) { + rc = ble_transition_to_rx(tifs_anchor, tifs_usecs, wfr_usecs, phy_state); + } + + if (rc) { + ble_transition_to_none(); + } + + return 0; } /** @@ -1031,19 +1254,11 @@ ble_phy_rx_xcvr_setup(void) static void ble_phy_tx_end_isr(void) { - uint8_t tx_phy_mode; uint8_t was_encrypted; uint8_t transition; - uint32_t rx_time; - uint32_t tx_time; -#if PHY_USE_FEM - uint32_t fem_time; -#endif - uint32_t radio_time; - uint16_t tifs; - - /* Store PHY on which we've just transmitted smth */ - tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; + uint16_t wfr_usecs; + uint16_t tifs_usecs; + uint8_t tifs_anchor; /* If this transmission was encrypted we need to remember it */ was_encrypted = g_ble_phy_data.phy_encrypted; @@ -1065,110 +1280,18 @@ ble_phy_tx_end_isr(void) } #endif -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) - tifs = g_ble_phy_data.tifs; - g_ble_phy_data.tifs = BLE_LL_IFS; -#else - tifs = BLE_LL_IFS; -#endif transition = g_ble_phy_data.phy_transition; + wfr_usecs = g_ble_phy_data.wfr_usecs; + tifs_usecs = g_ble_phy_data.tifs_usecs; + tifs_anchor = g_ble_phy_data.tifs_anchor; + + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); if (g_ble_phy_data.txend_cb) { g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); } - if (transition == BLE_PHY_TRANSITION_TX_RX) { -#if MYNEWT_VAL(BLE_LL_PHY) - 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->CC[2] + tifs; - /* Adjust for delay between EVENT_END and actual TX end time */ - rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Start listening a bit earlier due to allowed active clock accuracy */ - rx_time -= 2; - -#if PHY_USE_FEM_LNA - fem_time = rx_time - MYNEWT_VAL(BLE_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 - - 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) { - if (g_ble_phy_data.txtx_time_anchor) { - /* Calculate TX anchor relative to current TX end */ - - /* TX end timestamp is captured in CC[2] */ - tx_time = NRF_TIMER0->CC[2]; - /* Adjust for delay between EVENT_END and actual TX end time */ - tx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - } else { - /* Calculate TX anchor relative to current TX start */ - - /* AA timestamp is captured in CC[1] */ - tx_time = NRF_TIMER0->CC[1]; - /* Adjust for delay between EVENT_ADDRESS and actual AA time ota */ - tx_time += g_ble_phy_t_txaddrdelay[tx_phy_mode]; - /* Adjust by sync word length to get TX start time */ - tx_time -= ble_ll_pdu_syncword_us(tx_phy_mode); - } - - tx_time += g_ble_phy_data.txtx_time_us; - -#if PHY_USE_FEM_PA - fem_time = tx_time - MYNEWT_VAL(BLE_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]; - - radio_time = tx_time - BLE_PHY_T_TXENFAST; - nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - phy_ppi_timer0_compare0_to_radio_txen_enable(); - -#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 - - nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3); - if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { - phy_ppi_timer0_compare0_to_radio_txen_disable(); - g_ble_phy_data.phy_transition_late = 1; - } - } else { - /* - * XXX: not sure we need to stop the timer here all the time. Or that - * it should be stopped here. - */ - nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); - NRF_TIMER0->TASKS_SHUTDOWN = 1; - 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); - } + ble_phy_transition(transition, tifs_anchor, tifs_usecs, wfr_usecs, BLE_PHY_STATE_TX); } static inline uint8_t @@ -1201,22 +1324,17 @@ ble_phy_rx_end_isr(void) { int rc; uint8_t *dptr; - uint8_t crcok; - uint32_t tx_time; -#if PHY_USE_FEM_PA - uint32_t fem_time; -#endif - uint32_t radio_time; - uint16_t tifs; struct ble_mbuf_hdr *ble_hdr; - bool is_late; + uint8_t crcok; /* Disable automatic RXEN */ phy_ppi_timer0_compare0_to_radio_rxen_disable(); /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; +#ifndef NRF54L_SERIES assert(NRF_RADIO->EVENTS_RSSIEND != 0); +#endif ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; @@ -1231,12 +1349,21 @@ ble_phy_rx_end_isr(void) 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) { +#ifdef NRF54L_SERIES + while (NRF_CCM->EVENTS_END == 0) { +#else while (NRF_CCM->EVENTS_ENDCRYPT == 0) { +#endif /* Make sure CCM finished */ }; /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { + if ((dptr[1] != 0) && +#ifdef NRF54L_SERIES + (NRF_CCM->MACSTATUS == 0)) { +#else + (NRF_CCM->MICSTATUS == 0)) { +#endif ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; } @@ -1254,10 +1381,6 @@ ble_phy_rx_end_isr(void) #endif } -#if MYNEWT_VAL(BLE_LL_PHY) - 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. @@ -1271,53 +1394,18 @@ ble_phy_rx_end_isr(void) * during radio ramp-up - this gives us extra 40 usecs which is more than * enough. */ + if (g_ble_phy_data.phy_transition == PHY_TRANS_NONE) { + /* XXX: Should be removed after finding all missing uses of ble_phy_transition_set */ + g_ble_phy_data.phy_transition = PHY_TRANS_TO_TX; + } -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) - tifs = g_ble_phy_data.tifs; - g_ble_phy_data.tifs = BLE_LL_IFS; -#else - tifs = BLE_LL_IFS; -#endif - - /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ - tx_time = NRF_TIMER0->CC[2] + tifs; - /* Adjust for delay between actual RX end time and EVENT_END */ - tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - -#if PHY_USE_FEM_PA - fem_time = tx_time - MYNEWT_VAL(BLE_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]; - - radio_time = tx_time - BLE_PHY_T_TXENFAST; - nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); - NRF_TIMER0->EVENTS_COMPARE[0] = 0; - phy_ppi_timer0_compare0_to_radio_txen_enable(); - -#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 + ble_phy_transition(g_ble_phy_data.phy_transition, + g_ble_phy_data.tifs_anchor, + g_ble_phy_data.tifs_usecs, + g_ble_phy_data.wfr_usecs, + BLE_PHY_STATE_RX); - /* 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); - 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; - } + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); /* * XXX: This is a horrible ugly hack to deal with the RAM S1 byte @@ -1431,7 +1519,11 @@ ble_phy_rx_start_isr(void) * octets for extended header. */ adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)(dptr + 3 + adva_offset); +#else NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); +#endif /* Trigger AAR after last bit of AdvA is received */ NRF_RADIO->EVENTS_BCMATCH = 0; @@ -1468,7 +1560,11 @@ ble_phy_isr(void) os_trace_isr_enter(); /* Read irq register to determine which interrupts are enabled */ +#ifdef NRF54L_SERIES + irq_en = NRF_RADIO->INTENSET00; +#else irq_en = NRF_RADIO->INTENSET; +#endif /* * NOTE: order of checking is important! Possible, if things get delayed, @@ -1571,13 +1667,13 @@ ble_phy_init(void) /* Set phy channel to an invalid channel so first set channel works */ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; -#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) - g_ble_phy_data.tifs = BLE_LL_IFS; -#endif + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); +#ifndef NRF54L_SERIES /* Toggle peripheral power to reset (just in case) */ nrf_radio_power_set(NRF_RADIO, false); nrf_radio_power_set(NRF_RADIO, true); +#endif #ifdef NRF53_SERIES /* Errata 158: load trim values after toggling power */ @@ -1614,8 +1710,13 @@ ble_phy_init(void) RADIO_PCNF1_WHITEEN_Msk; /* Enable radio fast ramp-up */ +#ifdef NRF54L_SERIES + NRF_RADIO->TIMING = (RADIO_TIMING_RU_Fast << RADIO_TIMING_RU_Pos) & + RADIO_TIMING_RU_Msk; +#else NRF_RADIO->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & RADIO_MODECNF0_RU_Msk; +#endif /* Set logical address 1 for TX and RX */ NRF_RADIO->TXADDRESS = 0; @@ -1632,7 +1733,9 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) nrf_ccm_int_disable(NRF_CCM, 0xffffffff); +#ifndef NRF54L_SERIES NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; +#endif NRF_CCM->EVENTS_ERROR = 0; memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); @@ -1645,20 +1748,34 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) g_ble_phy_data.phy_aar_scratch = 0; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; +#endif nrf_aar_int_disable(NRF_AAR, 0xffffffff); NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; NRF_AAR->EVENTS_NOTRESOLVED = 0; +#ifdef NRF54L_SERIES + NRF_AAR->MAXRESOLVED = 0; +#else NRF_AAR->NIRK = 0; +#endif #endif /* TIMER0 setup for PHY when using RTC */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES NRF_TIMER0->TASKS_SHUTDOWN = 1; +#endif NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ NRF_TIMER0->MODE = 0; /* Timer mode */ +#ifdef NRF54L_SERIES + NRF_TIMER0->PRESCALER = 5; /* gives us 1 MHz */ +#else NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ +#endif phy_ppi_init(); @@ -1719,7 +1836,7 @@ ble_phy_rx(void) */ nrf_wait_disabled(); if ((NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) && - ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { + ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { ble_phy_disable(); STATS_INC(ble_phy_stats, radio_state_errs); return BLE_PHY_ERR_RADIO_STATE; @@ -1899,7 +2016,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) } int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) +ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg) { int rc; uint8_t *dptr; @@ -1908,6 +2025,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) uint8_t hdr_byte; uint32_t state; uint32_t shortcuts; + uint8_t end_trans; if (g_ble_phy_data.phy_transition_late) { ble_phy_disable(); @@ -1915,6 +2033,8 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) return BLE_PHY_ERR_TX_LATE; } + end_trans = g_ble_phy_data.phy_transition; + /* * 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. @@ -1936,6 +2056,14 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) 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]; +#ifdef NRF54L_SERIES + NRF_CCM->IN.PTR = (uint32_t)dptr; + NRF_CCM->OUT.PTR = (uint32_t)pktptr; + /* NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; */ + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | ble_phy_get_ccm_datarate(); + memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); +#else NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->INPTR = (uint32_t)dptr; NRF_CCM->OUTPTR = (uint32_t)pktptr; @@ -1943,9 +2071,14 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate(); NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; +#endif } else { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; +#endif #endif dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; pktptr = dptr; @@ -1975,7 +2108,11 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) NRF_CCM->INTENSET = CCM_INTENSET_ENDKSGEN_Msk; } #endif +#ifdef NRF54L_SERIES + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_START); +#else nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); +#endif } #endif @@ -1983,11 +2120,17 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) /* Clear the ready, end and disabled events */ NRF_RADIO->EVENTS_READY = 0; + NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->EVENTS_END = 0; NRF_RADIO->EVENTS_DISABLED = 0; /* Enable shortcuts for transmit start/end. */ - shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; + shortcuts = RADIO_SHORTS_READY_START_Msk; +#ifdef NRF54L_SERIES + shortcuts |= RADIO_SHORTS_PHYEND_DISABLE_Msk; +#else + shortcuts |= RADIO_SHORTS_END_DISABLE_Msk; +#endif NRF_RADIO->SHORTS = shortcuts; nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); @@ -2135,7 +2278,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) /* Set the frequency and the data whitening initial value */ g_ble_phy_data.phy_chan = chan; NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan]; + +#ifdef NRF54L_SERIES + NRF_RADIO->DATAWHITE = RADIO_DATAWHITE_ResetValue | chan; +#else NRF_RADIO->DATAWHITEIV = chan; +#endif return 0; } @@ -2153,7 +2301,9 @@ static void ble_phy_stop_usec_timer(void) { nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES NRF_TIMER0->TASKS_SHUTDOWN = 1; +#endif nrf_rtc_event_disable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); } @@ -2209,6 +2359,7 @@ ble_phy_disable(void) ble_phy_disable_irq_and_ppi(); g_ble_phy_data.phy_transition_late = 0; + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); #if PHY_USE_FEM phy_fem_disable(); @@ -2273,7 +2424,12 @@ ble_phy_max_data_pdu_pyld(void) void ble_phy_resolv_list_enable(void) { +#ifdef NRF54L_SERIES + /* TODO: Is this the right replacement? */ + NRF_AAR->MAXRESOLVED = (uint32_t)g_nrf_num_irks; +#else NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks; +#endif g_ble_phy_data.phy_privacy = 1; } @@ -2347,8 +2503,35 @@ ble_phy_rfclk_disable(void) } void -ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor) +ble_phy_transition_set(uint8_t trans, uint16_t usecs) +{ + uint8_t transition; + uint8_t anchor; + + if (trans == BLE_PHY_TRANSITION_TO_TX_ISO_SUBEVENT || + trans == BLE_PHY_TRANSITION_TO_RX_ISO_SUBEVENT) { + anchor = PHY_TRANS_ANCHOR_START; + } else { + anchor = PHY_TRANS_ANCHOR_END; + } + + if (trans == BLE_PHY_TRANSITION_TO_RX || + trans == BLE_PHY_TRANSITION_TO_RX_ISO_SUBEVENT) { + transition = PHY_TRANS_TO_RX; + } else if (trans == BLE_PHY_TRANSITION_TO_TX || + trans == BLE_PHY_TRANSITION_TO_TX_ISO_SUBEVENT) { + transition = PHY_TRANS_TO_TX; + } else { + transition = PHY_TRANS_NONE; + } + + g_ble_phy_data.phy_transition = transition; + g_ble_phy_data.tifs_anchor = anchor; + g_ble_phy_data.tifs_usecs = usecs ? usecs : BLE_LL_IFS; +} + +void +ble_phy_wfr_set(uint16_t usecs) { - g_ble_phy_data.txtx_time_us = usecs; - g_ble_phy_data.txtx_time_anchor = anchor; + g_ble_phy_data.wfr_usecs = usecs; } diff --git a/nimble/drivers/nrf5x/src/ble_phy_cs.c b/nimble/drivers/nrf5x/src/ble_phy_cs.c new file mode 100644 index 0000000000..4b9ca747b5 --- /dev/null +++ b/nimble/drivers/nrf5x/src/ble_phy_cs.c @@ -0,0 +1,693 @@ +/* + * 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 "syscfg/syscfg.h" +#include "os/os.h" +#include "os/os_cputime.h" +#include "nimble/ble.h" +#include "controller/ble_phy.h" +#include "controller/ble_ll.h" +#include "nrfx.h" +#include "phy_priv.h" +#include +#include "bs_tracing.h" +#include + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +/* Various radio timings */ +/* Radio ramp-up times in usecs (fast mode) */ +#define BLE_PHY_T_TXENFAST (40) +#define BLE_PHY_T_RXENFAST (40) + +#define BLE_PHY_CS_MAX_SYNC_LEN (21) + +static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; + +struct ble_phy_cs_obj +{ + uint32_t prev_isr_handler; + uint32_t phy_start_cputime; + uint8_t phy_state; + uint8_t phy_mode; + uint8_t phy_transition_late; + uint8_t phy_rx_started; + struct ble_phy_cs_transmission *cs_transm; + struct ble_phy_cs_sync_results cs_sync_results; + struct ble_phy_cs_tone_results cs_tone_results; +}; + +static struct ble_phy_cs_obj g_ble_phy_cs; + +/* packet start offsets (in usecs) */ +static const uint16_t g_ble_phy_mode_aa_end_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 +}; + +/* delay between EVENTS_READY and start of tx */ +extern const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE]; +/* delay between EVENTS_ADDRESS and txd access address */ +extern const uint8_t g_ble_phy_t_txaddrdelay[BLE_PHY_NUM_MODE]; +/* delay between EVENTS_END and end of txd packet */ +extern const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE]; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +extern const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE]; +/* delay between end of rxd packet and EVENTS_END */ +extern const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE]; + +extern void nrf_wait_disabled(void); +extern int ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx); +extern void ble_phy_wfr_enable_at(uint32_t end_time); + +int +ble_phy_cs_tone_end_set(uint32_t duration_usecs, uint16_t end_tifs, + uint8_t phy_state, uint8_t phy_mode) +{ + uint32_t end_time; + + end_time = NRF_TIMER0->CC[0] + duration_usecs; + if (phy_state == BLE_PHY_STATE_TX) { + end_time += g_ble_phy_t_txdelay[phy_mode]; + } + + nrf_timer_cc_set(NRF_TIMER0, 3, end_time); + NRF_TIMER0->EVENTS_COMPARE[3] = 0; + + nrf_timer_int_enable(NRF_TIMER0, TIMER_INTENSET_COMPARE3_Msk); + if (end_tifs >= BLE_LL_IFS) { + phy_ppi_timer0_compare3_to_radio_disable_enable(); + } else { + phy_ppi_timer0_compare3_to_radio_stop_enable(); + } + + /* 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { + nrf_timer_int_disable(NRF_TIMER0, TIMER_INTENCLR_COMPARE3_Msk); + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + } + + return 0; +} + +static int +ble_phy_cs_channel_configure(struct ble_phy_cs_transmission *transm) +{ + uint8_t chan = transm->channel; + +#if BABBLESIM + ble_phy_setchan(transm->channel % 40, transm->aa, 0); +#else + assert(!(chan <= 1 || (23 <= chan && chan <= 25) || 77 <= chan)); + + /* Check for valid channel range */ + if (chan <= 1 || (23 <= chan && chan <= 25) || 77 <= chan) { + return BLE_PHY_ERR_INV_PARAM; + } + + NRF_RADIO->FREQUENCY = 2 + chan; +#endif + + return 0; +} + +static int +ble_phy_cs_sync_configure(struct ble_phy_cs_transmission *transm) +{ + uint8_t *dptr; + uint32_t interrupts; + uint8_t payload_len; + uint8_t hdr_byte; + +#if !BABBLESIM + /* CS SYNC packet has no PDU or CRC */ + NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); + /* CS_SYNC needs only PAYLOAD field, so do not transmit S0, LENGTH and S1 fields. */ + NRF_RADIO->PCNF0 = RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos; + /* Disable whitening */ + NRF_RADIO->PCNF1 = (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | + (NRF_BALEN << RADIO_PCNF1_BALEN_Pos); +// NRF_RADIO->RTT.CONFIG = RADIO_RTT_CONFIG_EN_Enabled << RADIO_RTT_CONFIG_EN_Pos | +// RADIO_RTT_CONFIG_ENFULLAA_Enabled << RADIO_RTT_CONFIG_ENFULLAA_Pos | +// RADIO_RTT_CONFIG_ROLE_Reflector << RADIO_RTT_CONFIG_ROLE_Pos | +// (256UL) << RADIO_RTT_CONFIG_EFSDELAY_Pos; +#endif + + /* No frames in CS tone */ + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; + if (transm->is_tx) { + payload_len = ble_ll_cs_rtt_tx_make(&dptr[3], &hdr_byte); + /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ + dptr[0] = hdr_byte; + dptr[1] = payload_len; + dptr[2] = 0; + interrupts = 0; + } else { + dptr += 3; + interrupts = RADIO_INTENSET_ADDRESS_Msk; + } + + NRF_RADIO->PACKETPTR = (uint32_t)dptr; + + if (transm->end_tifs >= BLE_LL_IFS) { +#ifdef NRF54L_SERIES + NRF_RADIO->SHORTS |= RADIO_SHORTS_PHYEND_DISABLE_Msk; +#else + NRF_RADIO->SHORTS |= RADIO_SHORTS_END_DISABLE_Msk; +#endif + interrupts |= RADIO_INTENSET_DISABLED_Msk; + } else { + interrupts |= RADIO_INTENSET_END_Msk; + } + + nrf_radio_int_enable(NRF_RADIO, interrupts); + + return 0; +} + +static int +ble_phy_cs_tone_configure(struct ble_phy_cs_transmission *transm) +{ +#if !BABBLESIM + NRF_RADIO->CSTONES.NEXTFREQUENCY = 2 + transm->channel; + NRF_RADIO->CSTONES.PHASESHIFT = 0; + NRF_RADIO->CSTONES.FFOIN = 1; + NRF_RADIO->CSTONES.FFOSOURCE = 0; + NRF_RADIO->CSTONES.NUMSAMPLES = 160; + NRF_RADIO->CSTONES.DOWNSAMPLE = 0; + + if (transm->tone_mode == BLE_PHY_CS_TONE_MODE_FM) { + NRF_RADIO->CSTONES.MODE = RADIO_CSTONES_MODE_TFM_Msk; + } else { + NRF_RADIO->CSTONES.MODE = RADIO_CSTONES_MODE_TPM_Msk; + } +#endif + + return 0; +} + +static int +ble_phy_cs_transition_to_tx(void) +{ + struct ble_phy_cs_transmission *prev_transm = g_ble_phy_cs.cs_transm; + struct ble_phy_cs_transmission *next_transm = prev_transm->next; + uint32_t anchor_time; + uint32_t radio_time; + bool is_late; + uint8_t phy_mode = g_ble_phy_cs.phy_mode; + uint8_t prev_phy_state = g_ble_phy_cs.phy_state; + + if (prev_transm->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + anchor_time = NRF_TIMER0->CC[3]; + } else { + /* END timestamp is captured in CC[2] */ + anchor_time = NRF_TIMER0->CC[2]; + + /* Adjust for delay between EVENT_END and actual TX/RX end time */ + anchor_time += (prev_phy_state == BLE_PHY_STATE_TX) + ? g_ble_phy_t_txenddelay[phy_mode] + : -g_ble_phy_t_rxenddelay[phy_mode]; + } + + radio_time = anchor_time + prev_transm->end_tifs; + + if (NRF_RADIO->STATE == RADIO_STATE_STATE_Disabled) { + /* Adjust for TX rump-up */ + radio_time -= BLE_PHY_T_TXENFAST; + /* Adjust for delay between EVENT_READY and actual TX start time */ + radio_time -= g_ble_phy_t_txdelay[phy_mode]; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + NRF_RADIO->SHORTS |= RADIO_SHORTS_READY_START_Msk; + } else { + /* Fast TX_TX transition */ + BLE_LL_ASSERT(NRF_RADIO->STATE == RADIO_STATE_STATE_TxIdle); + /* TODO: Adjust for delay between TASK_START and actual TX start time */ + radio_time -= g_ble_phy_t_txdelay[phy_mode]; + phy_ppi_timer0_compare0_to_radio_start_enable(); + } + + g_ble_phy_cs.phy_state = BLE_PHY_STATE_TX; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + + /* 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); + is_late = (NRF_TIMER0->CC[3] > radio_time) && !NRF_TIMER0->EVENTS_COMPARE[0]; + if (is_late) { + g_ble_phy_cs.phy_transition_late = 1; + + return 1; + } + + if (next_transm->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + ble_phy_cs_tone_end_set(next_transm->duration_usecs, next_transm->end_tifs, + BLE_PHY_STATE_TX, phy_mode); + } + + g_ble_phy_cs.cs_transm = next_transm; + + return 0; +} + +static int +ble_phy_cs_transition_to_rx(void) +{ + struct ble_phy_cs_transmission *prev_transm = g_ble_phy_cs.cs_transm; + struct ble_phy_cs_transmission *next_transm = prev_transm->next; + uint32_t anchor_time; + uint32_t radio_time; + uint32_t start_time; + uint32_t wfr_time; + uint8_t phy_mode = g_ble_phy_cs.phy_mode; + uint8_t prev_phy_state = g_ble_phy_cs.phy_state; + + if (prev_transm->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + anchor_time = NRF_TIMER0->CC[3]; + } else { + /* END timestamp is captured in CC[2] */ + anchor_time = NRF_TIMER0->CC[2]; + + /* Adjust for delay between EVENT_END and actual TX/RX end time */ + anchor_time += (prev_phy_state == BLE_PHY_STATE_TX) + ? g_ble_phy_t_txenddelay[phy_mode] + : -g_ble_phy_t_rxenddelay[phy_mode]; + } + + start_time = anchor_time + prev_transm->end_tifs; + radio_time = start_time; + + if (NRF_RADIO->STATE == RADIO_STATE_STATE_Disabled) { + /* Adjust for RX rump-up */ + radio_time -= BLE_PHY_T_RXENFAST; + /* Start listening a bit earlier due to allowed active clock accuracy */ + radio_time -= 2; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + NRF_RADIO->SHORTS |= RADIO_SHORTS_READY_START_Msk; + } else { + /* Fast RX_RX transition */ + BLE_LL_ASSERT(NRF_RADIO->STATE == RADIO_STATE_STATE_RxIdle); + /* Start listening a bit earlier due to allowed active clock accuracy */ + radio_time -= 2; + phy_ppi_timer0_compare0_to_radio_start_enable(); + } + + g_ble_phy_cs.phy_state = BLE_PHY_STATE_RX; + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + + if (next_transm->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + ble_phy_cs_tone_end_set(next_transm->duration_usecs, next_transm->end_tifs, + BLE_PHY_STATE_RX, phy_mode); + } else { + /* Setup wfr relative to expected radio/PDU start */ + wfr_time = start_time; + /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ + wfr_time += g_ble_phy_mode_aa_end_off[phy_mode]; + /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ + wfr_time += g_ble_phy_t_rxaddrdelay[phy_mode]; + /* Wait a bit longer due to allowed active clock accuracy */ + wfr_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. + */ + wfr_time += 1; + wfr_time += MYNEWT_VAL(BLE_PHY_EXTENDED_TIFS); + ble_phy_wfr_enable_at(wfr_time); + } + + g_ble_phy_cs.cs_transm = next_transm; + + return 0; +} + +static void +ble_phy_cs_transition_to_none(void) +{ +#ifdef NRF54L_SERIES + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_STOP); +#endif + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + phy_ppi_timer0_compare0_to_radio_start_disable(); + + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_rtc0_compare0_to_timer0_start_disable(); + ble_phy_disable(); + phy_ppi_fem_disable(); + + ble_phy_transition_set(BLE_PHY_TRANSITION_NONE, 0); + +#if !BABBLESIM + NRF_RADIO->CSTONES.MODE = 0; + NRF_RADIO->RTT.CONFIG = 0; + + /* Configure back the registers */ + NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three; + NRF_RADIO->PCNF0 = NRF_PCNF0; + NRF_RADIO->PCNF1 = NRF_MAXLEN | + (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | + (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | + RADIO_PCNF1_WHITEEN_Msk; + phy_ppi_debug_disable(); +#endif + + NVIC_SetVector(RADIO_IRQn, (uint32_t)g_ble_phy_cs.prev_isr_handler); +} + +static int +ble_phy_cs_transition(void) +{ + int rc = 0; + struct ble_phy_cs_transmission *prev_transm = g_ble_phy_cs.cs_transm; + struct ble_phy_cs_transmission *next_transm = prev_transm->next; + uint8_t is_tx; + uint8_t is_tone; + + /* Disable PPI */ + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + phy_ppi_timer0_compare0_to_radio_start_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_timer0_compare0_to_radio_rxen_disable(); + + /* Make sure all interrupts are disabled */ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + + if (next_transm == NULL) { + ble_phy_cs_transition_to_none(); + return 0; + } + + if (prev_transm->is_tx != next_transm->is_tx) { + nrf_wait_disabled(); + } + + /* Clear events */ +#ifdef NRF54L_SERIES + NRF_RADIO->EVENTS_PHYEND = 0; +#endif + NRF_RADIO->EVENTS_READY = 0; + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + NRF_RADIO->SHORTS = 0; + g_ble_phy_cs.phy_rx_started = 0; + + ble_phy_cs_channel_configure(next_transm); + + if (next_transm->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + rc = ble_phy_cs_tone_configure(next_transm); + } else { + rc = ble_phy_cs_sync_configure(next_transm); + } + + if (rc) { + ble_phy_cs_transition_to_none(); + return 1; + } + + if (next_transm->is_tx) { + rc = ble_phy_cs_transition_to_tx(); + } else { + rc = ble_phy_cs_transition_to_rx(); + } + + if (rc) { + ble_phy_cs_transition_to_none(); + return 1; + } + + return rc; +} + +static bool +ble_phy_cs_sync_rx_start_isr(void) +{ + int rc; + + BLE_LL_ASSERT(g_ble_phy_cs.phy_state == BLE_PHY_STATE_RX); + + /* Clear events and clear interrupt */ + NRF_RADIO->EVENTS_ADDRESS = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk); + + /* Clear wfr timer channels */ + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + phy_ppi_timer0_compare0_to_radio_start_disable(); + phy_ppi_timer0_compare0_to_radio_rxen_disable(); + g_ble_phy_cs.phy_rx_started = 1; + + return true; +} + +static void +ble_phy_cs_sync_tx_end_isr(void) +{ + assert(g_ble_phy_cs.phy_state == BLE_PHY_STATE_TX); + + g_ble_phy_cs.cs_sync_results.cputime = g_ble_phy_cs.phy_start_cputime; + g_ble_phy_cs.cs_sync_results.rem_us = NRF_TIMER0->CC[2] + + g_ble_phy_t_txenddelay[g_ble_phy_cs.phy_mode]; + g_ble_phy_cs.cs_sync_results.rem_ns = 0; + + ble_phy_cs_transition(); + ble_ll_cs_sync_tx_end(&g_ble_phy_cs.cs_sync_results); +} + +static void +ble_phy_cs_sync_rx_end_isr(void) +{ + assert(g_ble_phy_cs.phy_state == BLE_PHY_STATE_RX); + + g_ble_phy_cs.cs_sync_results.cputime = g_ble_phy_cs.phy_start_cputime; + g_ble_phy_cs.cs_sync_results.rem_us = NRF_TIMER0->CC[2] - + g_ble_phy_t_rxenddelay[g_ble_phy_cs.phy_mode]; + g_ble_phy_cs.cs_sync_results.rem_ns = 0; + + ble_phy_cs_transition(); + ble_ll_cs_sync_rx_end(&g_ble_phy_cs.cs_sync_results); +} + +static void +ble_phy_cs_tone_tx_end_isr(void) +{ + ble_phy_cs_transition(); + ble_ll_cs_tone_tx_end(&g_ble_phy_cs.cs_tone_results); +} + +static void +ble_phy_cs_tone_rx_end_isr(void) +{ + ble_phy_cs_transition(); + ble_ll_cs_tone_rx_end(&g_ble_phy_cs.cs_tone_results); +} + +static void +ble_phy_cs_isr(void) +{ + uint32_t irq_en; + + os_trace_isr_enter(); + + /* Read irq register to determine which interrupts are enabled */ +#ifdef NRF54L_SERIES + irq_en = NRF_RADIO->INTENSET00; +#else + irq_en = NRF_RADIO->INTENSET; +#endif + + if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) { + /* Access Address received */ + if (ble_phy_cs_sync_rx_start_isr()) { + irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; + } + } + + if (((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) || + ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END)) { + BLE_LL_ASSERT(NRF_RADIO->EVENTS_END || + ((g_ble_phy_cs.phy_state == BLE_PHY_STATE_RX) && + !g_ble_phy_cs.phy_rx_started)); +#ifdef NRF54L_SERIES + NRF_RADIO->EVENTS_PHYEND = 0; +#endif + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_END_Msk); + + switch (g_ble_phy_cs.phy_state) { + case BLE_PHY_STATE_RX: + if (g_ble_phy_cs.phy_rx_started) { + ble_phy_cs_sync_rx_end_isr(); + } else { + ble_ll_cs_sync_wfr_timer_exp(); + } + break; + case BLE_PHY_STATE_TX: + ble_phy_cs_sync_tx_end_isr(); + break; + default: + BLE_LL_ASSERT(0); + } + } + + g_ble_phy_cs.phy_transition_late = 0; + + os_trace_isr_exit(); +} + +static void +ble_phy_radio_timer_isr(void) +{ + os_trace_isr_enter(); + + nrf_timer_int_disable(NRF_TIMER0, TIMER_INTENCLR_COMPARE3_Msk); + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + phy_ppi_timer0_compare0_to_radio_start_disable(); + + switch (g_ble_phy_cs.phy_state) { + case BLE_PHY_STATE_RX: + ble_phy_cs_tone_rx_end_isr(); + break; + case BLE_PHY_STATE_TX: + ble_phy_cs_tone_tx_end_isr(); + break; + default: + BLE_LL_ASSERT(0); + } + + g_ble_phy_cs.phy_transition_late = 0; + + os_trace_isr_exit(); +} + +int +ble_phy_cs_subevent_start(struct ble_phy_cs_transmission *transm, + uint32_t cputime, uint8_t rem_usecs) +{ + int rc; + struct ble_phy_cs_transmission *next_transm = transm->next; + uint8_t *dptr; + + BLE_LL_ASSERT(transm->mode == BLE_PHY_CS_TRANSM_MODE_SYNC); + + g_ble_phy_cs.phy_mode = BLE_PHY_MODE_1M; + g_ble_phy_cs.cs_transm = transm; + + /* Disable all PPI */ + nrf_wait_disabled(); + phy_ppi_wfr_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + phy_ppi_radio_address_to_ccm_crypt_disable(); + phy_ppi_timer0_compare3_to_radio_disable_disable(); + phy_ppi_timer0_compare3_to_radio_stop_disable(); + phy_ppi_timer0_compare0_to_radio_start_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_timer0_compare0_to_radio_rxen_disable(); + + /* Make sure all interrupts are disabled */ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + + /* Set interrupt handler for Channel Sounding api */ + g_ble_phy_cs.prev_isr_handler = NVIC_GetVector(RADIO_IRQn); + NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_cs_isr); + + /* Clear events */ + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; +#ifdef NRF54L_SERIES + NRF_RADIO->EVENTS_PHYEND = 0; +#endif + + nrf_timer_int_disable(NRF_TIMER0, 0xFFFFFFFF); + NVIC_SetPriority(TIMER0_IRQn, 0); + NVIC_SetVector(TIMER0_IRQn, (uint32_t)ble_phy_radio_timer_isr); + NVIC_EnableIRQ(TIMER0_IRQn); + +#if !BABBLESIM + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_STOP); + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CLEAR); + NRF_TIMER00->BITMODE = 3; /* 32-bit timer */ + NRF_TIMER00->MODE = 0; /* Timer mode */ + NRF_TIMER00->PRESCALER = 0; /* gives us 128 MHz */ + phy_ppi_debug_enable(); +#endif + + /* Enable radio shortcuts */ + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk; + + ble_phy_cs_channel_configure(transm); + + rc = ble_phy_cs_sync_configure(transm); + if (rc) { + ble_phy_cs_transition_to_none(); + return 1; + } + + rc = ble_phy_set_start_time(cputime, rem_usecs, false); + if (rc) { + ble_phy_cs_transition_to_none(); + return 1; + } + + if (transm->is_tx) { + g_ble_phy_cs.phy_state = BLE_PHY_STATE_TX; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + } else { + g_ble_phy_cs.phy_state = BLE_PHY_STATE_RX; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, transm->duration_usecs); + } + + if (rc) { + ble_phy_cs_transition_to_none(); + return 1; + } + + return rc; +} +#endif diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c index 30a19966b7..2373a77a72 100644 --- a/nimble/drivers/nrf5x/src/nrf52/phy.c +++ b/nimble/drivers/nrf5x/src/nrf52/phy.c @@ -177,6 +177,17 @@ phy_ppi_init(void) 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_CHANNEL_SOUNDING) + /* Channel 8: TIMER0 CC[0] to TASKS_START on radio. + * Channel 9: TIMER0 CC[3] to TASKS_STOP on radio. This is the ToF measurement timer. + */ + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL8, + (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[0]), + (uint32_t)&(NRF_RADIO->TASKS_START)); + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL9, + (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]), + (uint32_t)&(NRF_RADIO->TASKS_STOP)); +#endif } void diff --git a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h index a77b718339..5eee86cc88 100644 --- a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h +++ b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h @@ -100,6 +100,44 @@ phy_ppi_fem_disable(void) nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); } +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +static inline void +phy_ppi_timer0_compare0_to_radio_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH8_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH8_Msk); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_stop_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH9_Msk); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_stop_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH9_Msk); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH5_Msk); +} +#endif + static inline void phy_ppi_disable(void) { @@ -108,6 +146,10 @@ phy_ppi_disable(void) PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk); + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH8_Msk | PPI_CHEN_CH9_Msk); +#endif } #endif /* H_PHY_PPI_ */ diff --git a/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h index 6412f32753..74dd5864cb 100644 --- a/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h +++ b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h @@ -142,6 +142,44 @@ phy_ppi_fem_disable(void) #endif } +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +static inline void +phy_ppi_timer0_compare0_to_radio_start_enable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_start_disable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_stop_enable(void) +{ + NRF_RADIO->SUBSCRIBE_STOP = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_stop_disable(void) +{ + NRF_RADIO->SUBSCRIBE_STOP = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_enable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_disable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} +#endif + static inline void phy_ppi_disable(void) { diff --git a/nimble/drivers/nrf5x/src/nrf54l15/phy.c b/nimble/drivers/nrf5x/src/nrf54l15/phy.c new file mode 100644 index 0000000000..6d706eeaed --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l15/phy.c @@ -0,0 +1,256 @@ +/* + * 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 "phy_priv.h" + +/* Create PPIB links between RADIO and PERI power domain. */ +#define PPIB_RADIO_PERI(_ch, _src, _dst) \ + NRF_PPIB11->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB21->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC20->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_RADIO_PERI_0(_src, _dst) PPIB_RADIO_PERI(0, _src, _dst) +#define PPIB_RADIO_PERI_1(_src, _dst) PPIB_RADIO_PERI(1, _src, _dst) +#define PPIB_RADIO_PERI_2(_src, _dst) PPIB_RADIO_PERI(2, _src, _dst) +#define PPIB_RADIO_PERI_3(_src, _dst) PPIB_RADIO_PERI(3, _src, _dst) + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +/* Create PPIB link from RADIO to MCU power domain. */ +#define PPIB_RADIO_MCU(_ch, _src, _dst) \ + NRF_PPIB10->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB00->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC00->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_RADIO_MCU_0(_src, _dst) PPIB_RADIO_MCU(0, _src, _dst) +#define PPIB_RADIO_MCU_1(_src, _dst) PPIB_RADIO_MCU(1, _src, _dst) +#endif + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_1); + + PPIB_RADIO_PERI_0(TIMER0_EVENTS_COMPARE_0, GPIOTE20_TASKS_SET_0); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_0); + + NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); + PPIB_RADIO_PERI_1(RADIO_EVENTS_READY, GPIOTE20_TASKS_CLR_0); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_0); +#endif + +#if PHY_USE_DEBUG_2 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_2); + + PPIB_RADIO_PERI_2(RADIO_EVENTS_ADDRESS, GPIOTE20_TASKS_SET_1); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_1); + + PPIB_RADIO_PERI_3(RADIO_EVENTS_END, GPIOTE20_TASKS_CLR_1); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_1); +#endif +} +#endif /* PHY_USE_DEBUG */ + +void +phy_ppi_init(void) +{ + NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); + NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); + + 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_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + /* Use TIMER00 for ToF measurements */ + NRF_RADIO->PUBLISH_PHYEND = DPPI_CH_PUB(RADIO_EVENTS_PHYEND); + PPIB_RADIO_MCU_0(RADIO_EVENTS_PHYEND, DPPIC00_RADIO_EVENTS_PHYEND); + PPIB_RADIO_MCU_1(RTC0_EVENTS_COMPARE_0, DPPIC00_RTC0_EVENTS_COMPARE_0); + NRF_TIMER00->SUBSCRIBE_CAPTURE[4] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_PHYEND); +#endif + + /* Enable channels we publish on */ + NRF_DPPIC10->CHENSET = DPPI_CH_ENABLE_ALL; +} + +void +phy_txpower_set(int8_t dbm) +{ + uint16_t val; + + switch (dbm) { + case 8: + val = RADIO_TXPOWER_TXPOWER_Pos8dBm; + break; + case 7: + val = RADIO_TXPOWER_TXPOWER_Pos7dBm; + break; + case 6: + val = RADIO_TXPOWER_TXPOWER_Pos6dBm; + break; + case 5: + val = RADIO_TXPOWER_TXPOWER_Pos5dBm; + break; + case 4: + val = RADIO_TXPOWER_TXPOWER_Pos4dBm; + break; + case 3: + val = RADIO_TXPOWER_TXPOWER_Pos3dBm; + break; + case 2: + val = RADIO_TXPOWER_TXPOWER_Pos2dBm; + break; + case 1: + val = RADIO_TXPOWER_TXPOWER_Pos1dBm; + break; + case 0: + val = RADIO_TXPOWER_TXPOWER_0dBm; + break; + case -1: + val = RADIO_TXPOWER_TXPOWER_Neg1dBm; + break; + case -2: + val = RADIO_TXPOWER_TXPOWER_Neg2dBm; + break; + case -3: + val = RADIO_TXPOWER_TXPOWER_Neg3dBm; + break; + case -4: + val = RADIO_TXPOWER_TXPOWER_Neg4dBm; + break; + case -5: + val = RADIO_TXPOWER_TXPOWER_Neg5dBm; + break; + case -6: + val = RADIO_TXPOWER_TXPOWER_Neg6dBm; + break; + case -7: + val = RADIO_TXPOWER_TXPOWER_Neg7dBm; + break; + case -8: + val = RADIO_TXPOWER_TXPOWER_Neg8dBm; + break; + case -9: + val = RADIO_TXPOWER_TXPOWER_Neg9dBm; + break; + case -10: + val = RADIO_TXPOWER_TXPOWER_Neg10dBm; + break; + case -12: + val = RADIO_TXPOWER_TXPOWER_Neg12dBm; + break; + case -14: + val = RADIO_TXPOWER_TXPOWER_Neg14dBm; + break; + case -16: + val = RADIO_TXPOWER_TXPOWER_Neg16dBm; + break; + case -18: + val = RADIO_TXPOWER_TXPOWER_Neg18dBm; + break; + case -20: + val = RADIO_TXPOWER_TXPOWER_Neg20dBm; + break; + case -22: + val = RADIO_TXPOWER_TXPOWER_Neg22dBm; + break; + case -28: + val = RADIO_TXPOWER_TXPOWER_Neg28dBm; + break; + case -40: + val = RADIO_TXPOWER_TXPOWER_Neg40dBm; + break; + case -46: + val = RADIO_TXPOWER_TXPOWER_Neg46dBm; + break; + default: + val = RADIO_TXPOWER_TXPOWER_0dBm; + } + + NRF_RADIO->TXPOWER = val; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)8) { + return (int8_t)8; + } + + if (dbm >= (int8_t)-10) { + return (int8_t)dbm; + } + + if (dbm >= (int8_t)-12) { + return (int8_t)-12; + } + + if (dbm >= (int8_t)-14) { + return (int8_t)-14; + } + + if (dbm >= (int8_t)-16) { + return (int8_t)-16; + } + + if (dbm >= (int8_t)-18) { + return (int8_t)-18; + } + + if (dbm >= (int8_t)-20) { + return (int8_t)-20; + } + + if (dbm >= (int8_t)-22) { + return (int8_t)-22; + } + + if (dbm >= (int8_t)-28) { + return (int8_t)-28; + } + + if (dbm >= (int8_t)-40) { + return (int8_t)-40; + } + + return (int8_t)-46; +} diff --git a/nimble/drivers/nrf5x/src/nrf54l15/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf54l15/phy_ppi.h new file mode 100644 index 0000000000..c4742d3d94 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l15/phy_ppi.h @@ -0,0 +1,219 @@ +/* + * 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)) + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +/* DPPIC00 [0:7] */ +#define DPPI_CH_DPPIC00_RADIO_EVENTS_PHYEND 0 +#define DPPI_CH_DPPIC00_RTC0_EVENTS_COMPARE_0 1 +#endif + +/* DPPIC10 [0:23] */ +#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 +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define DPPI_CH_RADIO_EVENTS_PHYEND 10 +#endif + +/* DPPIC20 [0:15] */ +#define DPPI_CH_GPIOTE20_TASKS_SET_0 0 +#define DPPI_CH_GPIOTE20_TASKS_CLR_0 1 +#define DPPI_CH_GPIOTE20_TASKS_SET_1 2 +#define DPPI_CH_GPIOTE20_TASKS_CLR_1 3 + +#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) +{ +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + NRF_TIMER00->SUBSCRIBE_START = DPPI_CH_SUB(DPPIC00_RTC0_EVENTS_COMPARE_0); +#endif + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + NRF_TIMER00->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RTC0_EVENTS_COMPARE_0); +#endif + 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_timer0_compare0_to_radio_start_enable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_start_disable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + NRF_CCM->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_START = 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); +} + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +static inline void +phy_ppi_timer0_compare3_to_radio_stop_enable(void) +{ + NRF_RADIO->SUBSCRIBE_STOP = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_stop_disable(void) +{ + NRF_RADIO->SUBSCRIBE_STOP = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_enable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare3_to_radio_disable_disable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} +#endif + +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) +{ +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + NRF_TIMER00->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RTC0_EVENTS_COMPARE_0); +#endif + 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_STOP = 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_RADIO->SUBSCRIBE_START = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + + phy_ppi_fem_disable(); +} + +#endif /* H_PHY_PPI_ */ diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h index db0664da2b..ad54096e79 100644 --- a/nimble/drivers/nrf5x/src/phy_priv.h +++ b/nimble/drivers/nrf5x/src/phy_priv.h @@ -25,6 +25,58 @@ #include +/* To disable all radio interrupts */ +#ifdef NRF54L_SERIES +#define NRF_RADIO_IRQ_MASK_ALL (RADIO_INTENSET00_READY_Msk | \ + RADIO_INTENSET00_ADDRESS_Msk | \ + RADIO_INTENSET00_PAYLOAD_Msk | \ + RADIO_INTENSET00_END_Msk | \ + RADIO_INTENSET00_PHYEND_Msk | \ + RADIO_INTENSET00_DISABLED_Msk | \ + RADIO_INTENSET00_DEVMATCH_Msk | \ + RADIO_INTENSET00_DEVMISS_Msk | \ + RADIO_INTENSET00_BCMATCH_Msk | \ + RADIO_INTENSET00_CRCOK_Msk | \ + RADIO_INTENSET00_CRCERROR_Msk) +#else +#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) +#endif + +/* + * 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->PCNF0 configuration values */ +#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ + (RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos) | \ + (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) + +#define PHY_TRANS_NONE (0) +#define PHY_TRANS_TO_TX (1) +#define PHY_TRANS_TO_RX (2) + +#define PHY_TRANS_ANCHOR_START (0) +#define PHY_TRANS_ANCHOR_END (1) + #if defined(NRF52840_XXAA) && MYNEWT_VAL(BLE_PHY_NRF52_HEADERMASK_WORKAROUND) #define PHY_USE_HEADERMASK_WORKAROUND 1 #endif @@ -53,6 +105,7 @@ #define PHY_GPIOTE_FEM_LNA (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA) #endif +#ifndef NRF54L_SERIES static inline void phy_gpiote_configure(int idx, int pin) { @@ -61,6 +114,7 @@ phy_gpiote_configure(int idx, int pin) NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_gpiote_task_enable(NRF_GPIOTE, idx); } +#endif #if PHY_USE_DEBUG void phy_debug_init(void); @@ -92,5 +146,38 @@ int8_t phy_txpower_round(int8_t dbm); #ifdef NRF53_SERIES #include "nrf53/phy_ppi.h" #endif +#ifdef NRF54L_SERIES +#define NRF_TIMER0 NRF_TIMER10 +#define TIMER0_IRQn TIMER10_IRQn +#define NRF_DPPIC NRF_DPPIC10 +#define NRF_RTC0 NRF_RTC10 +#define NRF_AAR NRF_AAR00 +#define NRF_CCM NRF_CCM00 +#define NRF_AAR NRF_AAR00 +#define NRF_GPIOTE NRF_GPIOTE20 +#define RADIO_IRQn RADIO_0_IRQn +#define RADIO_INTENCLR_ADDRESS_Msk RADIO_INTENCLR00_ADDRESS_Msk +#define RADIO_INTENSET_DISABLED_Msk RADIO_INTENSET00_DISABLED_Msk +#define RADIO_INTENCLR_DISABLED_Msk RADIO_INTENCLR00_DISABLED_Msk +#define RADIO_INTENSET_END_Msk RADIO_INTENSET00_END_Msk +#define RADIO_INTENCLR_END_Msk RADIO_INTENCLR00_END_Msk +#define RADIO_INTENCLR_PHYEND_Msk RADIO_INTENCLR00_PHYEND_Msk +#define RADIO_INTENSET_ADDRESS_Msk RADIO_INTENSET00_ADDRESS_Msk +#include "nrf54l15/phy_ppi.h" +#endif + +#if BABBLESIM +extern void tm_tick(void); +#undef RADIO_STATE_STATE_Tx +#undef RADIO_STATE_STATE_TxDisable +#define RADIO_STATE_STATE_TxStarting (11UL) /* An additional state used in bsim */ +#define RADIO_STATE_STATE_Tx (12UL) /* RADIO is in the TX state */ +#define RADIO_STATE_STATE_TxDisable (13UL) /* RADIO is in the TXDISABLED state */ +static inline uint32_t +ble_ll_tmr_t2u(uint32_t ticks) +{ + return ticks * (1000000.0 / 32768); +} +#endif #endif /* H_PHY_PRIV_ */