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..306de1a814 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,51 @@ 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 (1) + +#define BLE_PHY_CS_TONE_MODE_FM (0) +#define BLE_PHY_CS_TONE_MODE_PM (1) + +#define BLE_PHY_CS_STATUS_CONTINUE (0) +#define BLE_PHY_CS_STATUS_COMPLETE (1) +#define BLE_PHY_CS_STATUS_SYNC_LOST (2) + +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 { + uint64_t rem_ns; + uint32_t cputime; + int16_t rssi; +}; + +struct ble_phy_cs_tone_results { + int16_t measured_freq_offset; + int16_t I16; + int16_t Q16; + uint16_t PHASE; +}; + +struct ble_phy_cs_subevent_results { + uint64_t rem_ns; + uint32_t cputime; + uint8_t status; +}; + +/* 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 +144,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 +160,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 84f6e789d6..4416fb89af 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -1122,7 +1122,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; @@ -1184,18 +1183,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; @@ -1269,7 +1268,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; @@ -1320,22 +1318,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; } @@ -2323,8 +2321,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; } @@ -4546,6 +4545,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, @@ -4559,12 +4560,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) { @@ -4598,9 +4597,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); @@ -4891,6 +4890,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 52446b6471..2e032a5b8b 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; @@ -3275,9 +3277,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 c7823e0f1a..2ee6024b29 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 1454ed6a5c..045abf0f0d 100644 --- a/nimble/controller/src/ble_ll_iso_big.c +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -652,7 +652,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; } @@ -737,9 +738,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; } @@ -836,12 +840,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 0f73fd2e8c..11f9d4faa9 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -1569,7 +1569,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 0cb734a240..2071c62198 100644 --- a/nimble/controller/src/ble_ll_scan_aux.c +++ b/nimble/controller/src/ble_ll_scan_aux.c @@ -1206,8 +1206,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..c4a5ed8dbd 100644 --- a/nimble/drivers/nrf5x/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -36,9 +36,25 @@ #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 + +struct nrf_ecb_job_list { + nrf_vdma_job_t in[2]; + nrf_vdma_job_t out[2]; +}; + +static struct nrf_ecb_job_list g_ecb_job_list; +#endif + /* Total number of resolving list elements */ #define BLE_HW_RESOLV_LIST_SIZE (16) @@ -276,6 +292,47 @@ 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); + + /* Init job lists */ + g_ecb_job_list.in[0].p_buffer = ecb->plain_text; + g_ecb_job_list.in[0].attributes = NRF_VDMA_ATTRIBUTE_CRC; + g_ecb_job_list.in[0].size = BLE_ENC_BLOCK_SIZE; + memset(&g_ecb_job_list.in[1], 0, sizeof(g_ecb_job_list.in[1])); + + g_ecb_job_list.out[0].p_buffer = ecb->cipher_text; + g_ecb_job_list.out[0].attributes = NRF_VDMA_ATTRIBUTE_CRC; + g_ecb_job_list.out[0].size = BLE_ENC_BLOCK_SIZE; + memset(&g_ecb_job_list.out[1], 0, sizeof(g_ecb_job_list.out[1])); + + NRF_ECB->KEY.VALUE[3] = get_be32(&ecb->key[0]); + NRF_ECB->KEY.VALUE[2] = get_be32(&ecb->key[4]); + NRF_ECB->KEY.VALUE[1] = get_be32(&ecb->key[8]); + NRF_ECB->KEY.VALUE[0] = get_be32(&ecb->key[12]); + + NRF_ECB->EVENTS_END = 0; + NRF_ECB->EVENTS_ERROR = 0; + NRF_ECB->IN.PTR = (uint32_t)g_ecb_job_list.in; + NRF_ECB->OUT.PTR = (uint32_t)g_ecb_job_list.out; + + /* 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 +358,7 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) tm_tick(); #endif } - +#endif return rc; } @@ -314,7 +371,27 @@ ble_rng_isr(void) uint8_t rnum; os_trace_isr_enter(); +#ifdef NRF54L_SERIES + (void)rnum; + /* 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 +407,7 @@ ble_rng_isr(void) rnum = (uint8_t)NRF_RNG->VALUE; (*g_ble_rng_isr_cb)(rnum); } - +#endif os_trace_isr_exit(); } @@ -345,6 +422,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 +460,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 +477,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 +511,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 +534,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 +638,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..be2a5a5712 100644 --- a/nimble/drivers/nrf5x/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -45,6 +45,9 @@ #ifdef NRF53_SERIES #include #endif +#ifdef NRF54L_SERIES +#include +#endif #include "mcu/cmsis_nvic.h" #include "hal/hal_gpio.h" #else @@ -68,6 +71,21 @@ #endif #endif +#ifdef NRF54L_SERIES +#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 +#define EVENTS_ENDCRYPT EVENTS_END +#define MICSTATUS MACSTATUS +#define INTENSET INTENSET00 +#define HEADERMASK ADATAMASK +#endif + #if BABBLESIM extern void tm_tick(void); #endif @@ -102,37 +120,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 +147,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 +188,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] = { @@ -325,7 +352,19 @@ STATS_NAME_END(ble_phy_stats) */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#ifdef NRF54L_SERIES +struct nrf_ccm_job_list { + uint16_t in_alen; + uint16_t in_mlen; + uint8_t in_mlen_msb; + uint8_t out_mlen_msb; + uint16_t out_alen; + nrf_vdma_job_t in[6]; + nrf_vdma_job_t out[6]; +}; +struct nrf_ccm_job_list g_ccm_job_list; +#else /* * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. * However, when I used a smaller size it still overwrote the scratchpad. Until @@ -348,6 +387,7 @@ struct nrf_ccm_data struct nrf_ccm_data g_nrf_ccm_data; #endif +#endif #if MYNEWT_VAL(BLE_LL_PHY) @@ -588,7 +628,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 +649,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 +851,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 +904,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 +942,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 +957,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 } @@ -950,6 +992,74 @@ ble_phy_rx_xcvr_setup(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { +#ifdef NRF54L_SERIES + /* AAD length */ + g_ccm_job_list.in_alen = 1; + g_ccm_job_list.in[0].p_buffer = (uint8_t *) &g_ccm_job_list.in_alen; + g_ccm_job_list.in[0].size = sizeof(g_ccm_job_list.in_alen); + g_ccm_job_list.in[0].attributes = 11; + + /* Encrypted message length LSB */ + g_ccm_job_list.in[1].p_buffer = ((uint8_t *)g_ble_phy_enc_buf) + 1; + g_ccm_job_list.in[1].size = 1; + g_ccm_job_list.in[1].attributes = 12; + + /* Encrypted message length MSB */ + g_ccm_job_list.in[2].p_buffer = &g_ccm_job_list.in_mlen_msb; + g_ccm_job_list.in[2].size = sizeof(g_ccm_job_list.in_mlen_msb); + g_ccm_job_list.in[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.in[3].p_buffer = ((uint8_t *)g_ble_phy_enc_buf); + g_ccm_job_list.in[3].size = 1; + g_ccm_job_list.in[3].attributes = 13; + + /* Encrypted message */ + g_ccm_job_list.in[4].p_buffer = ((uint8_t *)g_ble_phy_enc_buf) + 3; + g_ccm_job_list.in[4].size = NRF_MAXLEN; + g_ccm_job_list.in[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.in[5], 0, sizeof(g_ccm_job_list.in[5])); + + /* AAD length */ + g_ccm_job_list.out[0].p_buffer = (uint8_t *) &g_ccm_job_list.out_alen; + g_ccm_job_list.out[0].size = sizeof(g_ccm_job_list.out_alen); + g_ccm_job_list.out[0].attributes = 11; + + /* Decrypted message length LSB */ + g_ccm_job_list.out[1].p_buffer = &dptr[1]; + g_ccm_job_list.out[1].size = 1; + g_ccm_job_list.out[1].attributes = 12; + + /* Decrypted message length MSB */ + g_ccm_job_list.out[2].p_buffer = &g_ccm_job_list.out_mlen_msb; + g_ccm_job_list.out[2].size = sizeof(g_ccm_job_list.out_mlen_msb); + g_ccm_job_list.out[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.out[3].p_buffer = &dptr[0]; + g_ccm_job_list.out[3].size = 1; + g_ccm_job_list.out[3].attributes = 13; + + /* Decrypted message */ + g_ccm_job_list.out[4].p_buffer = &dptr[3]; + g_ccm_job_list.out[4].size = NRF_MAXLEN - 4; + g_ccm_job_list.out[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.out[5], 0, sizeof(g_ccm_job_list.out[5])); + + NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->IN.PTR = (uint32_t)g_ccm_job_list.in; + NRF_CCM->OUT.PTR = (uint32_t)g_ccm_job_list.out; + + NRF_CCM->MODE = (CCM_MODE_MACLEN_M4 << CCM_MODE_MACLEN_Pos) | CCM_MODE_MODE_Decryption | + ble_phy_get_ccm_datarate(); + + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->EVENTS_END = 0; +#else NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; NRF_CCM->OUTPTR = (uint32_t)dptr; @@ -961,6 +1071,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 +1083,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(m): 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; @@ -986,7 +1102,7 @@ ble_phy_rx_xcvr_setup(void) /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ phy_ppi_timer0_compare0_to_radio_txen_disable(); - phy_ppi_radio_bcmatch_to_aar_start_disable(); + //phy_ppi_radio_bcmatch_to_aar_start_disable(); TODO(m): this was disabling CCM RADIO SUBSCRIBTION because peripherals share memory. think later what to do with it /* Reset the rx started flag. Used for the wait for response */ g_ble_phy_data.phy_rx_started = 0; @@ -1012,16 +1128,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 +1344,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 +1370,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 +1414,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]; @@ -1254,10 +1462,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 +1475,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(); + 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); -#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 - - /* 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 +1600,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; @@ -1571,13 +1744,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 +1787,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,9 +1810,11 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) nrf_ccm_int_disable(NRF_CCM, 0xffffffff); - NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->EVENTS_ERROR = 0; +#ifndef NRF54L_SERIES + NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); +#endif #if PHY_USE_HEADERMASK_WORKAROUND NVIC_SetVector(CCM_AAR_IRQn, (uint32_t)ble_phy_ccm_isr); @@ -1645,20 +1825,32 @@ 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; + NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ +#else + NRF_TIMER0->PRESCALER = 5; /* gives us 1 MHz */ +#endif NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ NRF_TIMER0->MODE = 0; /* Timer mode */ - NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ phy_ppi_init(); @@ -1719,7 +1911,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; @@ -1742,11 +1934,19 @@ ble_phy_rx(void) void ble_phy_encrypt_enable(const uint8_t *key) { - memcpy(g_nrf_ccm_data.key, key, 16); - g_ble_phy_data.phy_encrypted = 1; NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; -#ifdef NRF5340_XXAA + g_ble_phy_data.phy_encrypted = 1; + +#ifdef NRF54L_SERIES + NRF_CCM->KEY.VALUE[0] = get_be32(&key[12]); + NRF_CCM->KEY.VALUE[1] = get_be32(&key[8]); + NRF_CCM->KEY.VALUE[2] = get_be32(&key[4]); + NRF_CCM->KEY.VALUE[3] = get_be32(&key[0]); +#else + memcpy(g_nrf_ccm_data.key, key, 16); +#endif +#if defined(NRF5340_XXAA) || defined(NRF54L_SERIES) NRF_CCM->HEADERMASK = BLE_LL_PDU_HEADERMASK_DATA; #endif #if PHY_USE_HEADERMASK_WORKAROUND @@ -1757,7 +1957,7 @@ ble_phy_encrypt_enable(const uint8_t *key) void ble_phy_encrypt_header_mask_set(uint8_t mask) { -#ifdef NRF5340_XXAA +#if defined(NRF5340_XXAA) || defined(NRF54L_SERIES) NRF_CCM->HEADERMASK = mask; #endif #if PHY_USE_HEADERMASK_WORKAROUND @@ -1768,14 +1968,24 @@ ble_phy_encrypt_header_mask_set(uint8_t mask) void ble_phy_encrypt_iv_set(const uint8_t *iv) { +#ifdef NRF54L_SERIES + NRF_CCM->NONCE.VALUE[1] = get_be32(iv); + NRF_CCM->NONCE.VALUE[0] = get_be32(iv + 4); +#else memcpy(g_nrf_ccm_data.iv, iv, 8); +#endif } void ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { +#ifdef NRF54L_SERIES + NRF_CCM->NONCE.VALUE[3] = ((uint8_t *)&counter)[0]; + NRF_CCM->NONCE.VALUE[2] = get_be32(&((uint8_t *)&counter)[1]) | ((!!dir_bit) << 7); +#else g_nrf_ccm_data.pkt_counter = counter; g_nrf_ccm_data.dir_bit = dir_bit; +#endif } void @@ -1899,7 +2109,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 +2118,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 +2126,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 +2149,12 @@ 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)&g_ccm_job_list.in; + NRF_CCM->OUT.PTR = (uint32_t)&g_ccm_job_list.out; + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->MODE = CCM_MODE_MODE_Encryption | (CCM_MODE_MACLEN_M4 << CCM_MODE_MACLEN_Pos) | ble_phy_get_ccm_datarate(); +#else NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->INPTR = (uint32_t)dptr; NRF_CCM->OUTPTR = (uint32_t)pktptr; @@ -1943,9 +2162,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 +2199,65 @@ 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 + /* AAD length */ + g_ccm_job_list.in_alen = 1; + g_ccm_job_list.in[0].p_buffer = (uint8_t *) &g_ccm_job_list.in_alen; + g_ccm_job_list.in[0].size = sizeof(g_ccm_job_list.in_alen); + g_ccm_job_list.in[0].attributes = 11; + + /* Unencrypted message length */ + g_ccm_job_list.in_mlen = payload_len; + g_ccm_job_list.in[1].p_buffer = (uint8_t *) &g_ccm_job_list.in_mlen; + g_ccm_job_list.in[1].size = sizeof(g_ccm_job_list.in_mlen); + g_ccm_job_list.in[1].attributes = 12; + + /* AAD */ + g_ccm_job_list.in[2].p_buffer = (uint8_t *) &dptr[0]; + g_ccm_job_list.in[2].size = 1; + g_ccm_job_list.in[2].attributes = 13; + + /* Unencrypted message */ + g_ccm_job_list.in[3].p_buffer = (uint8_t *) &dptr[3]; + g_ccm_job_list.in[3].size = payload_len; + g_ccm_job_list.in[3].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.in[4], 0, sizeof(g_ccm_job_list.in[4])); + + /* AAD length */ + g_ccm_job_list.out[0].p_buffer = (uint8_t *) &g_ccm_job_list.out_alen; + g_ccm_job_list.out[0].size = sizeof(g_ccm_job_list.out_alen); + g_ccm_job_list.out[0].attributes = 11; + + /* Encrypted message length LSB */ + g_ccm_job_list.out[1].p_buffer = (uint8_t *) &pktptr[1]; + g_ccm_job_list.out[1].size = 1; + g_ccm_job_list.out[1].attributes = 12; + + /* Encrypted message length MSB */ + g_ccm_job_list.out[2].p_buffer = (uint8_t *) &g_ccm_job_list.out_mlen_msb; + g_ccm_job_list.out[2].size = sizeof(g_ccm_job_list.out_mlen_msb); + g_ccm_job_list.out[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.out[3].p_buffer = (uint8_t *) &pktptr[0]; + g_ccm_job_list.out[3].size = 1; + g_ccm_job_list.out[3].attributes = 13; + + /* Encrypted message */ + g_ccm_job_list.out[4].p_buffer = (uint8_t *) &pktptr[3]; + g_ccm_job_list.out[4].size = payload_len + 4; + g_ccm_job_list.out[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.out[5], 0, sizeof(g_ccm_job_list.out[5])); + + /* Start encryption */ + 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 +2265,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 +2423,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 +2446,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 +2504,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 +2569,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; } @@ -2326,6 +2627,9 @@ ble_phy_rfclk_enable(void) #ifdef NRF53_SERIES nrf5340_net_clock_hfxo_request(); #endif +#ifdef NRF54L_SERIES + nrf54l_clock_hfxo_request(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); #endif @@ -2341,14 +2645,44 @@ ble_phy_rfclk_disable(void) #ifdef NRF53_SERIES nrf5340_net_clock_hfxo_release(); #endif +#ifdef NRF54L_SERIES + nrf54l_clock_hfxo_release(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); #endif } 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..2928ac9712 --- /dev/null +++ b/nimble/drivers/nrf5x/src/ble_phy_cs.c @@ -0,0 +1,948 @@ +/* + * 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 + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + +#if BABBLESIM +#define NRF_TIMER00 NRF_TIMER0 +#define TIMER00_IRQn TIMER0_IRQn +#endif + +/* 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) + +#define CSSYNC_TRAILER_NS (4000) + +#define PENDING_TRANSM_COUNT_MAX (6) +#define TONE_RESULT_COUNT_MAX (5) + +#define BLE_PHY_CS_ROLE_INITIATOR (0) +#define BLE_PHY_CS_ROLE_REFLECTOR (1) + +static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; +static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; + +struct ble_phy_cs_obj +{ + uint32_t prev_isr_handler; + uint32_t phy_start_cputime; + uint32_t tone_end_anchor; + uint8_t phy_state; + uint8_t phy_mode; + uint16_t phase_shift; + uint8_t role; + uint8_t tone_offset_usecs; + struct ble_phy_cs_transmission *pending_transm[PENDING_TRANSM_COUNT_MAX]; + struct ble_phy_cs_sync_results sync_results; + struct ble_phy_cs_tone_results tone_results[TONE_RESULT_COUNT_MAX]; + struct ble_phy_cs_subevent_results subevent_results; +}; + +static struct ble_phy_cs_obj g_ble_phy_cs; +extern void nrf_wait_disabled(void); + +/* delay between EVENTS_READY and start of tx */ +const uint16_t txdelay_ns[BLE_PHY_NUM_MODE] = { +#if BABBLESIM + [BLE_PHY_MODE_1M] = 1000, +#else + [BLE_PHY_MODE_1M] = 1600, /* ~1.6us */ +#endif +}; +/* delay between EVENTS_ADDRESS and txd access address */ +const uint16_t txaddrdelay_ns[BLE_PHY_NUM_MODE] = { +#if BABBLESIM + [BLE_PHY_MODE_1M] = 1000, +#else + [BLE_PHY_MODE_1M] = 3200, /* ~3.2us */ +#endif +}; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +const uint16_t rxaddrdelay_ns[BLE_PHY_NUM_MODE] = { +#if BABBLESIM + [BLE_PHY_MODE_1M] = 9000, +#else + [BLE_PHY_MODE_1M] = 9200, /* ~9.2us */ +#endif +}; + +static uint32_t +ticks_to_ns(uint32_t ticks) { +#if BABBLESIM + return ticks * 1000; +#else + return (uint32_t)(((uint64_t)ticks * 1000000000ULL) / 128000000ULL); +#endif +} + +static uint32_t +ns_to_ticks(uint32_t ns) { +#if BABBLESIM + return ns / 1000; +#else + return (uint32_t)(((uint64_t)ns * 128) / 1000); +#endif +} + +static uint32_t +usecs_to_ticks(uint32_t usecs) { +#if BABBLESIM + return usecs; +#else + return usecs * 128; +#endif +} + +static uint32_t +ticks_to_usecs(uint32_t ticks) { +#if BABBLESIM + return ticks; +#else + return (uint32_t)(((uint64_t)ticks * 1000000ULL) / 128000000ULL); +#endif +} + +static uint32_t +usecs_to_ns(uint32_t usecs) { + return usecs * 1000; +} + +static uint32_t +ns_to_usecs(uint32_t ns) { + return ns / 1000; +} + +static int +ble_phy_cs_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) +{ + uint32_t next_cc; + uint32_t cur_cc; + uint32_t cntr; + uint32_t delta; + int radio_rem_ns; + int rem_ns_corr; + + /* Calculate rem_us for radio and FEM enable. The result may be a negative + * value, but we'll adjust later. + */ + if (tx) { + radio_rem_ns = usecs_to_ns(rem_us - BLE_PHY_T_TXENFAST) - + txdelay_ns[g_ble_phy_cs.phy_mode]; + } else { + radio_rem_ns = usecs_to_ns(rem_us - BLE_PHY_T_TXENFAST); + } + + /* We need to adjust rem_us values, so they are >=1 for TIMER0 compare + * event to be triggered. + */ + if (radio_rem_ns <= -30518) { + /* rem_ns is -61035..-30518 */ + cputime -= 2; + rem_ns_corr = 61035; + } else { + /* rem_us is -30517..0 */ + cputime -= 1; + rem_ns_corr = 30517; + } + + /* + * Can we set the RTC compare to start TIMER0? We can do it if: + * a) Current compare value is not N+1 or N+2 ticks from current + * counter. + * b) The value we want to set is not at least N+2 from current + * counter. + * + * NOTE: since the counter can tick 1 while we do these calculations we + * need to account for it. + */ + next_cc = cputime & 0xffffff; + cur_cc = NRF_RTC0->CC[0]; + cntr = NRF_RTC0->COUNTER; + + delta = (cur_cc - cntr) & 0xffffff; + if ((delta <= 3) && (delta != 0)) { + return -1; + } + delta = (next_cc - cntr) & 0xffffff; + if ((delta & 0x800000) || (delta < 3)) { + return -1; + } + + /* Clear and set TIMER0 to fire off at proper time */ + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CLEAR); + nrf_timer_cc_set(NRF_TIMER00, 0, ns_to_ticks(radio_rem_ns + rem_ns_corr)); + NRF_TIMER00->EVENTS_COMPARE[0] = 0; + + /* Set RTC compare to start TIMER0 */ + NRF_RTC0->EVENTS_COMPARE[0] = 0; + nrf_rtc_cc_set(NRF_RTC0, 0, next_cc); + nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); + + phy_ppi_rtc0_compare0_to_timer00_start_enable(); + + /* Store the cputime at which we set the RTC */ + g_ble_phy_cs.phy_start_cputime = cputime; + g_ble_phy_cs.subevent_results.cputime = cputime; + + return 0; +} + +static int +ble_phy_cs_wfr_enable_at(uint32_t end_time) +{ + /* wfr_secs is the time from rxen until timeout */ + nrf_timer_cc_set(NRF_TIMER00, 3, end_time); + NRF_TIMER00->EVENTS_COMPARE[3] = 0; + + /* Enable wait for response PPI */ + phy_ppi_cs_wfr_enable(); + + /* CC[1] is only used as a reference on ADDRESS event, we do not need it here. */ + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER00->CC[1] > NRF_TIMER00->CC[3]) { + phy_ppi_cs_wfr_disable(); + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + return 1; + } + + return 0; +} + +static int +ble_phy_cs_channel_configure(uint32_t aa, uint8_t chan) +{ +#if BABBLESIM + ble_phy_setchan(chan % 40, 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->BASE0 = (aa << 8); + NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (aa >> 24); + NRF_RADIO->FREQUENCY = 2 + chan; +#endif + + return 0; +} + +//#define NRF_S1LEN_BITS 4 + +static inline int +ble_phy_cs_sync_configure(struct ble_phy_cs_transmission *transm) +{ + uint8_t *dptr; + uint8_t hdr_byte; + +#if !BABBLESIM + /* CS SYNC packet has no PDU or CRC */ + NRF_RADIO->CRCCNF = 0; //(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 = 0; +// (4 << RADIO_PCNF0_S1LEN_Pos) | +// (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 + + if (transm->is_tx) { + dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; +#if BABBLESIM + memset(dptr, 0, 4); +#else + if (NRF_RADIO->PREFIX0 & 0x80) { + dptr[0] = 0b10101010; + dptr[1] = 0b10101010; + dptr[2] = 0b10101010; + dptr[3] = 0b10101010; + } else { + dptr[0] = 0b01010101; + dptr[1] = 0b01010101; + dptr[2] = 0b01010101; + dptr[3] = 0b01010101; + } +#endif + } else { + dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; + } + + NRF_RADIO->PACKETPTR = (uint32_t)dptr; + + return 0; +} + +static int +ble_phy_cs_tone_configure(struct ble_phy_cs_transmission *transm) +{ +#if !BABBLESIM + uint16_t phase_shift = 0; + uint8_t numsamples; + + NRF_RADIO->CSTONES.NEXTFREQUENCY = 2 + transm->channel; + NRF_RADIO->CSTONES.FFOIN = RADIO_CSTONES_FFOIN_ResetValue; + NRF_RADIO->CSTONES.FFOSOURCE = RADIO_CSTONES_FFOSOURCE_ResetValue; + + if (transm->is_tx) { + NRF_RADIO->CSTONES.NUMSAMPLES = RADIO_CSTONES_NUMSAMPLES_ResetValue; + } else { + assert(transm->duration_usecs <= 80); + g_ble_phy_cs.tone_offset_usecs = 1; + numsamples = (transm->duration_usecs - 2 * g_ble_phy_cs.tone_offset_usecs) * 160 / 80; + NRF_RADIO->CSTONES.NUMSAMPLES = numsamples; + NRF_RADIO->CSTONES.NUMSAMPLESCOEFF = (65536 * 16) / numsamples; + } + 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; + if (transm->is_tx && g_ble_phy_cs.role == BLE_PHY_CS_ROLE_REFLECTOR) { + phase_shift = g_ble_phy_cs.phase_shift; + } + } + + NRF_RADIO->CSTONES.PHASESHIFT = phase_shift; +#endif + + return 0; +} + +static void +ble_phy_cs_disable(void) +{ +#ifdef NRF54L_SERIES + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_STOP); +#endif + phy_ppi_timer00_compare3_to_radio_disable_disable(); + phy_ppi_timer00_compare2_to_radio_start_disable(); + phy_ppi_timer00_compare4_to_radio_cstonesstart_disable(); + phy_ppi_cs_mode_disable(); + + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_STOP); + phy_ppi_cs_wfr_disable(); + phy_ppi_timer00_compare0_to_radio_txen_disable(); + phy_ppi_timer00_compare0_to_radio_rxen_disable(); + phy_ppi_rtc0_compare0_to_timer00_start_disable(); + ble_phy_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); + + memset(g_ble_phy_cs.pending_transm, 0, sizeof(g_ble_phy_cs.pending_transm)); + g_ble_phy_cs.phase_shift = 0; +} + +static void +ble_phy_cs_subevent_end(int status) +{ + ble_phy_cs_disable(); + g_ble_phy_cs.subevent_results.status = status; + ble_ll_cs_subevent_end(&g_ble_phy_cs.subevent_results); +} + +static inline void +ble_phy_cs_prepare_radio(struct ble_phy_cs_transmission *prev_transm, + uint32_t *anchor_ticks, + uint32_t *start_offset_ns, + uint8_t is_tx) +{ + uint32_t radio_offset_ns; + uint8_t phy_mode = g_ble_phy_cs.phy_mode; + uint8_t prev_phy_state = g_ble_phy_cs.phy_state; + + *start_offset_ns = usecs_to_ns(prev_transm->end_tifs); + + if (prev_transm->mode == BLE_PHY_CS_TRANSM_MODE_SYNC) { + *anchor_ticks = NRF_TIMER00->CC[1]; + *start_offset_ns += (prev_phy_state == BLE_PHY_STATE_TX) + ? txaddrdelay_ns[phy_mode] + : -rxaddrdelay_ns[phy_mode]; + *start_offset_ns += CSSYNC_TRAILER_NS; + } else { + *anchor_ticks = g_ble_phy_cs.tone_end_anchor; + } + + /* Enable radio based on TX/RX state */ + if (NRF_RADIO->STATE == RADIO_STATE_STATE_Disabled) { + radio_offset_ns = *start_offset_ns; + if (is_tx) { + radio_offset_ns -= usecs_to_ns(BLE_PHY_T_TXENFAST); + radio_offset_ns -= txdelay_ns[phy_mode]; + phy_ppi_timer00_compare0_to_radio_txen_enable(); + } else { + radio_offset_ns -= usecs_to_ns(BLE_PHY_T_RXENFAST); + radio_offset_ns -= 10000; + phy_ppi_timer00_compare0_to_radio_rxen_enable(); + } + + nrf_timer_cc_set(NRF_TIMER00, 0, *anchor_ticks + ns_to_ticks(radio_offset_ns)); + NRF_TIMER00->EVENTS_COMPARE[0] = 0; + } + + g_ble_phy_cs.phy_state = is_tx ? BLE_PHY_STATE_TX : BLE_PHY_STATE_RX; +} + +static inline uint32_t +ble_phy_cs_calc_tone_chain_offset(struct ble_phy_cs_transmission *first_tone) +{ + struct ble_phy_cs_transmission *t; + uint32_t offset_ns = 0; + + t = first_tone; + while (t && t->mode == BLE_PHY_CS_TRANSM_MODE_TONE) { + offset_ns += usecs_to_ns(t->duration_usecs); + offset_ns += usecs_to_ns(t->end_tifs); + t = t->next; + } + + return offset_ns; +} + +static int myiqcount = 0; +static int myphaseshiftcount = 0; +static int16_t my_tone_results_I16[30]; +static int16_t my_tone_results_Q16[30]; +static uint16_t my_tone_results_PHASE[30]; +static uint16_t myphaseshift[30]; + +static inline void +ble_phy_cs_handle_tones(struct ble_phy_cs_transmission *first_tone, + uint32_t anchor_ticks, uint32_t tone_offset_ns, + uint8_t handle_tx_end) +{ + uint32_t pct16_reg; + struct ble_phy_cs_transmission *t = first_tone; + uint8_t is_tx = t->is_tx; + uint8_t tone_mode = first_tone->tone_mode; + uint8_t i; + + for (i = 0; i < TONE_RESULT_COUNT_MAX; i++) { + if (!is_tx) { + RADIO_EVENTS_CSTONESEND = 0; + nrf_timer_cc_set(NRF_TIMER00, 4, anchor_ticks + ns_to_ticks(tone_offset_ns) + + usecs_to_ticks(g_ble_phy_cs.tone_offset_usecs)); + NRF_TIMER00->EVENTS_COMPARE[4] = 0; + + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER00->CC[1] > NRF_TIMER00->CC[4] && NRF_TIMER00->EVENTS_COMPARE[4] == 0) { + BLE_LL_ASSERT(0); + break; + } + + while (NRF_TIMER00->EVENTS_COMPARE[4] == 0); + RADIO_TASKS_CSTONESSTART = 1; + RADIO_TASKS_CSTONESSTART = 1; + while (RADIO_EVENTS_CSTONESEND == 0); + + if (tone_mode == BLE_PHY_CS_TONE_MODE_FM) { + /* Made an assumption that FREQOFFSET is in the same units as FFOEST, 62.5ppb + * (only FFOEST specified in spec). + */ + g_ble_phy_cs.tone_results[i].measured_freq_offset = + NRF_RADIO->CSTONES.FREQOFFSET & RADIO_CSTONES_FREQOFFSET_FREQOFFSET_Msk; + } else { + pct16_reg = NRF_RADIO->CSTONES.PCT16; + g_ble_phy_cs.tone_results[i].I16 = (int16_t)(pct16_reg & 0xFFFF); + g_ble_phy_cs.tone_results[i].Q16 = (int16_t)((pct16_reg >> 16) & 0xFFFF); + + if (myiqcount < 30) { + my_tone_results_PHASE[myiqcount] = NRF_RADIO->CSTONES.MAGPHASEMEAN & 0xFFFF; + my_tone_results_I16[myiqcount] = g_ble_phy_cs.tone_results[i].I16; + my_tone_results_Q16[myiqcount++] = g_ble_phy_cs.tone_results[i].Q16; + myphaseshift[myphaseshiftcount++] = NRF_RADIO->CSTONES.MAGPHASEMEAN & 0xFFFF; + } + } + } + + tone_offset_ns += usecs_to_ns(t->duration_usecs); + first_tone = t; + t = t->next; + + if (!(t && t->is_tx == is_tx && t->mode == BLE_PHY_CS_TRANSM_MODE_TONE)) { + break; + } + + tone_offset_ns += usecs_to_ns(first_tone->end_tifs); + } + + g_ble_phy_cs.tone_end_anchor = anchor_ticks + ns_to_ticks(tone_offset_ns); + + if (is_tx) { + nrf_timer_cc_set(NRF_TIMER00, 4, g_ble_phy_cs.tone_end_anchor); + NRF_TIMER00->EVENTS_COMPARE[4] = 0; + + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER00->CC[1] < NRF_TIMER00->CC[4]) { + while (handle_tx_end && NRF_TIMER00->EVENTS_COMPARE[4] == 0); + } + } else if (tone_mode == BLE_PHY_CS_TONE_MODE_PM && g_ble_phy_cs.role == BLE_PHY_CS_ROLE_REFLECTOR) { + g_ble_phy_cs.phase_shift = NRF_RADIO->CSTONES.MAGPHASEMEAN & 0xFFFF; + } + + if (handle_tx_end) { + NRF_RADIO->TASKS_DISABLE = 1; + } +} + +static volatile uint32_t myconsumed_sync_ns = 0; +static volatile uint32_t mysync_offset_ns = 0; +static volatile uint32_t mytone_offset_ns = 0; + +static int +ble_phy_cs_transition(void) +{ + int rc = 0; + struct ble_phy_cs_transmission *prev_transm; + struct ble_phy_cs_transmission *first_transm; + struct ble_phy_cs_transmission *sync_transm = NULL; + struct ble_phy_cs_transmission *tone_transm = NULL; + struct ble_phy_cs_transmission *t; + uint32_t anchor_ticks = 0; + uint32_t start_offset_ns = 0; + uint32_t tone_chain_ns = 0; + uint32_t consumed_sync_ns = 0; + uint32_t sync_offset_ns = 0; + uint32_t tone_offset_ns = 0; + uint32_t wfr_ns; + uint32_t channel = 0; + uint8_t aa = 0; + uint8_t is_tx; + uint8_t i; + + for (i = PENDING_TRANSM_COUNT_MAX; i > 0; i--) { + prev_transm = g_ble_phy_cs.pending_transm[i - 1]; + if (prev_transm != NULL) { + break; + } + } + memset(g_ble_phy_cs.pending_transm, 0, sizeof(g_ble_phy_cs.pending_transm)); + + BLE_LL_ASSERT(prev_transm != NULL); + + first_transm = prev_transm->next; + if (first_transm == NULL) { + ble_phy_cs_subevent_end(BLE_PHY_CS_STATUS_COMPLETE); + return 0; + } + + if (prev_transm->is_tx != first_transm->is_tx) { + nrf_wait_disabled(); + } + + is_tx = first_transm->is_tx; + + /* Clear radio events */ +#ifdef NRF54L_SERIES + NRF_RADIO->EVENTS_PHYEND = 0; +#endif + NRF_RADIO->EVENTS_READY = 0; + NRF_RADIO->EVENTS_TXREADY = 0; + NRF_RADIO->EVENTS_RXREADY = 0; + NRF_RADIO->EVENTS_ADDRESS = 0; + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + RADIO_EVENTS_CSTONESEND = 0; + NRF_RADIO->CSTONES.MODE = 0; + NRF_RADIO->RTT.CONFIG = 0; + NRF_RADIO->SHORTS = 0; + RADIO_EVENTS_CSTONESEND = 0; + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); + + t = first_transm; + i = 0; + /* Find SYNC and first TONE */ + while (t && t->is_tx == is_tx) { + assert(i < PENDING_TRANSM_COUNT_MAX); + g_ble_phy_cs.pending_transm[i++] = t; + + if (t->mode == BLE_PHY_CS_TRANSM_MODE_SYNC) { + sync_transm = t; + } else if (t->mode == BLE_PHY_CS_TRANSM_MODE_TONE && !tone_transm) { + tone_transm = t; + } + + t = t->next; + } + + if (sync_transm) { + ble_phy_cs_sync_configure(sync_transm); + aa = sync_transm->aa; + channel = sync_transm->channel; + } + + if (tone_transm) { + ble_phy_cs_tone_configure(tone_transm); + channel = tone_transm->channel; + } + + ble_phy_cs_channel_configure(aa, channel); + + ble_phy_cs_prepare_radio(prev_transm, &anchor_ticks, &start_offset_ns, is_tx); + tone_offset_ns = start_offset_ns; + sync_offset_ns = start_offset_ns; + + if (sync_transm) { + if (first_transm == tone_transm) { + /* If TONEs are before SYNC, add their total time (ns) to sync offset */ + tone_chain_ns = ble_phy_cs_calc_tone_chain_offset(tone_transm); + sync_offset_ns += tone_chain_ns; + + nrf_timer_cc_set(NRF_TIMER00, 2, anchor_ticks + ns_to_ticks(sync_offset_ns)); + NRF_TIMER00->EVENTS_COMPARE[2] = 0; + phy_ppi_timer00_compare2_to_radio_start_enable(); + + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER00->CC[1] > NRF_TIMER00->CC[2]) { + return 1; + } + } else { + NRF_RADIO->SHORTS |= RADIO_SHORTS_READY_START_Msk; + nrf_timer_task_trigger(NRF_TIMER00, NRF_TIMER_TASK_CAPTURE1); + if (NRF_TIMER00->CC[1] > NRF_TIMER00->CC[0]) { + return 1; + } + } + + if (!is_tx) { + wfr_ns = sync_offset_ns + + usecs_to_ns(sync_transm->duration_usecs) + + rxaddrdelay_ns[g_ble_phy_cs.phy_mode] + + 50000; + rc = ble_phy_cs_wfr_enable_at(anchor_ticks + ns_to_ticks(wfr_ns)); + if (rc) { + return rc; + } + } + + consumed_sync_ns = usecs_to_ns(sync_transm->duration_usecs) + usecs_to_ns(sync_transm->end_tifs); + myconsumed_sync_ns = consumed_sync_ns; + + if (!sync_transm->next || sync_transm->next->is_tx != is_tx) { + /* If SYNC is at the end, use SHORTS to disable the radio */ + NRF_RADIO->SHORTS |= RADIO_SHORTS_PHYEND_DISABLE_Msk; + } + + if (tone_transm && first_transm == sync_transm) { + /* If TONEs are after SYNC, set tone_transm and tone_offset_ns accordingly */ + tone_offset_ns = sync_offset_ns + consumed_sync_ns; + } + } + + tone_offset_ns += 3000; + mysync_offset_ns = sync_offset_ns; + mytone_offset_ns = tone_offset_ns; + + if (tone_transm) { + ble_phy_cs_handle_tones(tone_transm, anchor_ticks, tone_offset_ns, + sync_offset_ns <= tone_offset_ns); + } + + return 0; +} + +static void +ble_phy_cs_sync_tx_end_isr(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_sync_results *results) +{ + assert(g_ble_phy_cs.phy_state == BLE_PHY_STATE_TX); + + g_ble_phy_cs.sync_results.cputime = g_ble_phy_cs.phy_start_cputime; + g_ble_phy_cs.sync_results.rem_ns = ticks_to_ns(NRF_TIMER00->CC[1]) + + txaddrdelay_ns[g_ble_phy_cs.phy_mode] + CSSYNC_TRAILER_NS; + + g_ble_phy_cs.subevent_results.rem_ns = g_ble_phy_cs.sync_results.rem_ns; + + ble_ll_cs_sync_tx_end(transm, results); +} + +static void +ble_phy_cs_sync_rx_end_isr(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_sync_results *results) +{ + assert(g_ble_phy_cs.phy_state == BLE_PHY_STATE_RX); + + g_ble_phy_cs.sync_results.cputime = g_ble_phy_cs.phy_start_cputime; + g_ble_phy_cs.sync_results.rem_ns = ticks_to_ns(NRF_TIMER00->CC[1]) - + rxaddrdelay_ns[g_ble_phy_cs.phy_mode] + CSSYNC_TRAILER_NS; + + g_ble_phy_cs.subevent_results.rem_ns = g_ble_phy_cs.sync_results.rem_ns; + + ble_ll_cs_sync_rx_end(transm, results); +} + +static void +ble_phy_cs_tone_tx_end_isr(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_tone_results *results) +{ + g_ble_phy_cs.subevent_results.rem_ns = ticks_to_ns(NRF_TIMER00->CC[5]); + + ble_ll_cs_tone_tx_end(transm, results); +} + +static void +ble_phy_cs_tone_rx_end_isr(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_tone_results *results) +{ + g_ble_phy_cs.subevent_results.rem_ns = ticks_to_ns(NRF_TIMER00->CC[5]); + + ble_ll_cs_tone_rx_end(transm, results); +} + +static int +ble_phy_cs_sync_end(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_sync_results *results) +{ + switch (g_ble_phy_cs.phy_state) { + case BLE_PHY_STATE_RX: + if (NRF_RADIO->EVENTS_ADDRESS) { + ble_phy_cs_sync_rx_end_isr(transm, results); + } else { + g_ble_phy_cs.subevent_results.rem_ns = ticks_to_ns(NRF_TIMER00->CC[3]); + ble_phy_cs_subevent_end(BLE_PHY_CS_STATUS_SYNC_LOST); + return 1; + } + break; + case BLE_PHY_STATE_TX: + ble_phy_cs_sync_tx_end_isr(transm, results); + break; + default: + BLE_LL_ASSERT(0); + } + + return 0; +} + +static int +ble_phy_cs_tone_end(struct ble_phy_cs_transmission *transm, + struct ble_phy_cs_tone_results *results) +{ + switch (g_ble_phy_cs.phy_state) { + case BLE_PHY_STATE_RX: + if (RADIO_EVENTS_CSTONESEND) { + ble_phy_cs_tone_rx_end_isr(transm, results); + } else { + ble_phy_cs_subevent_end(BLE_PHY_CS_STATUS_SYNC_LOST); + return 1; + } + break; + case BLE_PHY_STATE_TX: + ble_phy_cs_tone_tx_end_isr(transm, results); + break; + default: + BLE_LL_ASSERT(0); + } + + return 0; +} + +static void +ble_phy_cs_isr(void) +{ + int rc = 0; + struct ble_phy_cs_transmission *transm; + struct ble_phy_cs_tone_results *tone_result; + uint8_t i; + + os_trace_isr_enter(); + + /* Disable PPI */ + phy_ppi_cs_wfr_disable(); + phy_ppi_timer00_compare3_to_radio_disable_disable(); + phy_ppi_timer00_compare2_to_radio_start_disable(); + phy_ppi_timer00_compare0_to_radio_txen_disable(); + phy_ppi_timer00_compare0_to_radio_rxen_disable(); + phy_ppi_timer00_compare4_to_radio_cstonesstart_disable(); + + /* Make sure all interrupts are disabled */ + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); + + NRF_RADIO->SHORTS = 0; +#ifdef NRF54L_SERIES + NRF_RADIO->EVENTS_PHYEND = 0; +#endif + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + + tone_result = &g_ble_phy_cs.tone_results[0]; + + for (i = 0; i < PENDING_TRANSM_COUNT_MAX; i++) { + transm = g_ble_phy_cs.pending_transm[i]; + if (transm == NULL) { + break; + } + + if (transm->mode == BLE_PHY_CS_TRANSM_MODE_SYNC) { + rc = ble_phy_cs_sync_end(transm, &g_ble_phy_cs.sync_results); + } else { + rc = ble_phy_cs_tone_end(transm, tone_result++); + } + } + + if (rc == 0) { + rc = ble_phy_cs_transition(); + if (rc) { + memset(g_ble_phy_cs.pending_transm, 0, sizeof(g_ble_phy_cs.pending_transm)); + ble_phy_cs_subevent_end(BLE_PHY_CS_STATUS_COMPLETE); + } + } + + 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; + uint32_t wfr_ns; + + BLE_LL_ASSERT(transm->mode == BLE_PHY_CS_TRANSM_MODE_SYNC); + + g_ble_phy_cs.phase_shift = 0; + g_ble_phy_cs.phy_mode = BLE_PHY_MODE_1M; + memset(g_ble_phy_cs.pending_transm, 0, sizeof(g_ble_phy_cs.pending_transm)); + g_ble_phy_cs.pending_transm[0] = transm; + + /* Disable all PPI */ + nrf_wait_disabled(); + phy_ppi_cs_wfr_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + phy_ppi_radio_address_to_ccm_crypt_disable(); + phy_ppi_timer00_compare3_to_radio_disable_disable(); + phy_ppi_timer00_compare2_to_radio_start_disable(); + phy_ppi_timer00_compare0_to_radio_txen_disable(); + phy_ppi_timer00_compare0_to_radio_rxen_disable(); + phy_ppi_timer00_compare4_to_radio_cstonesstart_disable(); + + phy_ppi_cs_mode_enable(); + + /* 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; + RADIO_EVENTS_CSTONESEND = 0; + NRF_RADIO->CSTONES.PHASESHIFT = 0; +#endif + +#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 + + ble_phy_cs_channel_configure(transm->aa, transm->channel); + + rc = ble_phy_cs_sync_configure(transm); + if (rc) { + ble_phy_cs_disable(); + return 1; + } + + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_PHYEND_DISABLE_Msk; + + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); + + rc = ble_phy_cs_set_start_time(cputime, rem_usecs, false); + if (rc) { + ble_phy_cs_disable(); + return 1; + } + + if (transm->is_tx) { + g_ble_phy_cs.role = BLE_PHY_CS_ROLE_INITIATOR; + g_ble_phy_cs.phy_state = BLE_PHY_STATE_TX; + phy_ppi_timer00_compare0_to_radio_txen_enable(); + } else { + g_ble_phy_cs.role = BLE_PHY_CS_ROLE_REFLECTOR; + g_ble_phy_cs.phy_state = BLE_PHY_STATE_RX; + phy_ppi_timer00_compare0_to_radio_rxen_enable(); + + wfr_ns = usecs_to_ns(BLE_PHY_T_RXENFAST + transm->duration_usecs + 50); + /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ + wfr_ns += rxaddrdelay_ns[g_ble_phy_cs.phy_mode]; + + ble_phy_cs_wfr_enable_at(NRF_TIMER00->CC[0] + ns_to_ticks(wfr_ns)); + } + + if (rc) { + ble_phy_cs_disable(); + 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..49b7e0b975 100644 --- a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h +++ b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h @@ -108,6 +108,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/nrf54l15/phy.c b/nimble/drivers/nrf5x/src/nrf54l15/phy.c new file mode 100644 index 0000000000..d6b3c2297b --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l15/phy.c @@ -0,0 +1,338 @@ +/* + * 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) + +/* 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) +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define PPIB_RADIO_MCU_1(_src, _dst) PPIB_RADIO_MCU(1, _src, _dst) +#define PPIB_RADIO_MCU_2(_src, _dst) PPIB_RADIO_MCU(2, _src, _dst) +#define PPIB_RADIO_MCU_3(_src, _dst) PPIB_RADIO_MCU(3, _src, _dst) + +/* Create PPIB link from MCU to RADIO power domain. */ +#define PPIB_MCU_RADIO(_ch, _src, _dst) \ + NRF_PPIB00->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB10->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC00->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_MCU_RADIO_0(_src, _dst) PPIB_MCU_RADIO(0, _src, _dst) +#define PPIB_MCU_RADIO_1(_src, _dst) PPIB_MCU_RADIO(1, _src, _dst) +#define PPIB_MCU_RADIO_2(_src, _dst) PPIB_MCU_RADIO(2, _src, _dst) +#define PPIB_MCU_RADIO_3(_src, _dst) PPIB_MCU_RADIO(3, _src, _dst) + +/* Create PPIB link from MCU to PERI power domain. */ +#define PPIB_MCU_PERI(_ch, _src, _dst) \ + NRF_PPIB01->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB20->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC00->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC20->CHENSET |= 1 << DPPI_CH_ ## _dst; +#endif + +#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) +#define PPIB_RADIO_PERI_4(_src, _dst) PPIB_RADIO_PERI(4, _src, _dst) +#define PPIB_RADIO_PERI_5(_src, _dst) PPIB_RADIO_PERI(5, _src, _dst) +#define PPIB_RADIO_PERI_6(_src, _dst) PPIB_RADIO_PERI(6, _src, _dst) +#define PPIB_RADIO_PERI_7(_src, _dst) PPIB_RADIO_PERI(7, _src, _dst) +#define PPIB_RADIO_PERI_8(_src, _dst) PPIB_RADIO_PERI(8, _src, _dst) + +#define PPIB_MCU_PERI_0(_src, _dst) PPIB_MCU_PERI(0, _src, _dst) +#define PPIB_MCU_PERI_1(_src, _dst) PPIB_MCU_PERI(1, _src, _dst) +#define PPIB_MCU_PERI_2(_src, _dst) PPIB_MCU_PERI(2, _src, _dst) +#define PPIB_MCU_PERI_3(_src, _dst) PPIB_MCU_PERI(3, _src, _dst) + +#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); + PPIB_MCU_PERI_2(DPPIC00_TIMER00_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); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + PPIB_RADIO_PERI_1(RADIO_EVENTS_READY, GPIOTE20_TASKS_CLR_0); + PPIB_RADIO_PERI_4(RADIO_EVENTS_DISABLED, GPIOTE20_TASKS_CLR_0); +// PPIB_RADIO_PERI_5(TIMER0_EVENTS_COMPARE_3, GPIOTE20_TASKS_CLR_0); + PPIB_MCU_PERI_3(DPPIC00_TIMER00_EVENTS_COMPARE_3, 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_8(RADIO_EVENTS_STOP, GPIOTE20_TASKS_CLR_1); + PPIB_RADIO_PERI_3(RADIO_EVENTS_DISABLED, GPIOTE20_TASKS_CLR_1); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_1); +#endif + +#if PHY_USE_DEBUG_3 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_3, + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_3); + +// PPIB_RADIO_PERI_6(TIMER0_EVENTS_COMPARE_0, GPIOTE20_TASKS_SET_2); + PPIB_MCU_PERI_0(DPPIC00_TIMER00_EVENTS_COMPARE_3, GPIOTE20_TASKS_SET_2); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_2); + +// PPIB_RADIO_PERI_7(TIMER0_EVENTS_COMPARE_3, GPIOTE20_TASKS_CLR_2); + PPIB_MCU_PERI_1(DPPIC00_TIMER00_EVENTS_COMPARE_3, GPIOTE20_TASKS_CLR_2); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_2); +#endif + phy_ppi_debug_enable(); +} +#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_PAYLOAD = DPPI_CH_PUB(RADIO_EVENTS_PAYLOAD_RADIO); + 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); + + PPIB_RADIO_MCU_0(RADIO_EVENTS_PAYLOAD_RADIO, DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + RADIO_PUBLISH_CSTONESEND = DPPI_CH_PUB(RADIO_EVENTS_CSTONES_END); + /* CC[0] for trigerring TXEN and RXEN */ + NRF_TIMER00->PUBLISH_COMPARE[0] = DPPI_CH_PUB(DPPIC00_TIMER00_EVENTS_COMPARE_0); + /* CC[2] for trigerring START */ + NRF_TIMER00->PUBLISH_COMPARE[2] = DPPI_CH_PUB(DPPIC00_TIMER00_EVENTS_COMPARE_2); + /* CC[3] for trigerring WFR */ + NRF_TIMER00->PUBLISH_COMPARE[3] = DPPI_CH_PUB(DPPIC00_TIMER00_EVENTS_COMPARE_3); + /* CC[4] for trigerring CSTONESSTART */ + NRF_TIMER00->PUBLISH_COMPARE[4] = DPPI_CH_PUB(DPPIC00_TIMER00_EVENTS_COMPARE_4); +// /* CC[1] for capturing ADDRESS event time */ +// NRF_TIMER00->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_ADDRESS); +// /* CC[5] for capturing CSTONESEND event time */ +// NRF_TIMER00->SUBSCRIBE_CAPTURE[5] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_CSTONES_END); + /* Proxy between domains */ + PPIB_MCU_RADIO_0(DPPIC00_TIMER00_EVENTS_COMPARE_0, TIMER00_EVENTS_COMPARE_0); + PPIB_MCU_RADIO_1(DPPIC00_TIMER00_EVENTS_COMPARE_2, TIMER00_EVENTS_COMPARE_2); + PPIB_MCU_RADIO_2(DPPIC00_TIMER00_EVENTS_COMPARE_3, TIMER00_EVENTS_COMPARE_3); + PPIB_MCU_RADIO_3(DPPIC00_TIMER00_EVENTS_COMPARE_4, TIMER00_EVENTS_COMPARE_4); + + /* Proxy for capturing ADDRESS or CSTONESEND event time */ + PPIB_RADIO_MCU_1(RADIO_EVENTS_ADDRESS, DPPIC00_RADIO_EVENTS_ADDRESS); + /* Proxy for starting TIMER00 */ + PPIB_RADIO_MCU_2(RTC0_EVENTS_COMPARE_0, DPPIC00_RTC0_EVENTS_COMPARE_0); + PPIB_RADIO_MCU_3(RADIO_EVENTS_CSTONES_END, DPPIC00_RADIO_EVENTS_CSTONES_END); +#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..5e81d88cf0 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l15/phy_ppi.h @@ -0,0 +1,332 @@ +/* + * 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)) + +/* DPPIC00 [0:7] */ +#define DPPI_CH_DPPIC00_RADIO_EVENTS_PAYLOAD_CCM 0 +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define DPPI_CH_DPPIC00_RADIO_EVENTS_ADDRESS 1 +#define DPPI_CH_DPPIC00_RTC0_EVENTS_COMPARE_0 2 +#define DPPI_CH_DPPIC00_TIMER00_EVENTS_COMPARE_0 3 +#define DPPI_CH_DPPIC00_TIMER00_EVENTS_COMPARE_2 4 +#define DPPI_CH_DPPIC00_TIMER00_EVENTS_COMPARE_3 5 +#define DPPI_CH_DPPIC00_TIMER00_EVENTS_COMPARE_4 6 +#define DPPI_CH_DPPIC00_RADIO_EVENTS_CSTONES_END 7 +#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 +#define DPPI_CH_RADIO_EVENTS_PAYLOAD_RADIO 10 +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#define DPPI_CH_RADIO_EVENTS_CSTONES_END 11 +#define DPPI_CH_TIMER00_EVENTS_COMPARE_0 12 +#define DPPI_CH_TIMER00_EVENTS_COMPARE_2 13 +#define DPPI_CH_TIMER00_EVENTS_COMPARE_3 14 +#define DPPI_CH_TIMER00_EVENTS_COMPARE_4 15 +#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_GPIOTE20_TASKS_SET_2 4 +#define DPPI_CH_GPIOTE20_TASKS_CLR_2 5 + +#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 | \ + DPPIC_CHEN_CH10_Msk) + +#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \ + DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) + +/* nrfx not updated yet */ +#define RADIO_TASKS_CSTONESSTART (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x0A0)) +#define RADIO_SUBSCRIBE_CSTONESSTART (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x1A0)) +#define RADIO_EVENTS_CSTONESEND (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x2C8)) +#define RADIO_PUBLISH_CSTONESEND (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x3C8)) +#define RADIO_INTENSET01 (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x48C)) +#define RADIO_INTENCLR01 (*(volatile uint32_t*)((uint8_t*)NRF_RADIO + 0x494)) +#define RADIO_INTENSET01_CSTONESSEND_Msk (0b1000) + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + NRF_CCM->SUBSCRIBE_START = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_cs_wfr_enable(void) +{ + NRF_TIMER00->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_cs_wfr_disable(void) +{ + NRF_TIMER00->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_3); +} + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +static inline void +phy_ppi_rtc0_compare0_to_timer00_start_enable(void) +{ + NRF_TIMER00->SUBSCRIBE_START = DPPI_CH_SUB(DPPIC00_RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer00_start_disable(void) +{ + NRF_TIMER00->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer00_compare0_to_radio_txen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer00_compare0_to_radio_txen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer00_compare0_to_radio_rxen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer00_compare0_to_radio_rxen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer00_compare2_to_radio_start_enable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_2); +} + +static inline void +phy_ppi_timer00_compare2_to_radio_start_disable(void) +{ + NRF_RADIO->SUBSCRIBE_START = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_2); +} + +static inline void +phy_ppi_timer00_compare3_to_radio_disable_enable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer00_compare3_to_radio_disable_disable(void) +{ + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer00_compare4_to_radio_cstonesstart_enable(void) +{ + RADIO_SUBSCRIBE_CSTONESSTART = DPPI_CH_SUB(TIMER00_EVENTS_COMPARE_4); +} + +static inline void +phy_ppi_timer00_compare4_to_radio_cstonesstart_disable(void) +{ + RADIO_SUBSCRIBE_CSTONESSTART = DPPI_CH_UNSUB(TIMER00_EVENTS_COMPARE_4); +} + +static inline void +phy_ppi_cs_mode_enable(void) +{ + /* We use the fastest timer in CS mode, so disable these */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_UNSUB(RADIO_EVENTS_END); + /* CC[1] for capturing ADDRESS event time */ + NRF_TIMER00->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_ADDRESS); + /* CC[5] for capturing CSTONESEND event time */ + NRF_TIMER00->SUBSCRIBE_CAPTURE[5] = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_CSTONES_END); +} + +static inline void +phy_ppi_cs_mode_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); + /* CC[1] for capturing ADDRESS event time */ + NRF_TIMER00->SUBSCRIBE_CAPTURE[1] = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_ADDRESS); + /* CC[5] for capturing CSTONESEND event time */ + NRF_TIMER00->SUBSCRIBE_CAPTURE[5] = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_CSTONES_END); +} + +#endif + +static inline void +phy_ppi_debug_enable(void) +{ + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_0); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_0); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_1); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_1); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_2); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_2); +} + +static inline void +phy_ppi_debug_disable(void) +{ + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_UNSUB(GPIOTE20_TASKS_SET_0); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_UNSUB(GPIOTE20_TASKS_CLR_0); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_UNSUB(GPIOTE20_TASKS_SET_1); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_UNSUB(GPIOTE20_TASKS_CLR_1); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_UNSUB(GPIOTE20_TASKS_SET_2); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_UNSUB(GPIOTE20_TASKS_CLR_2); +} + +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); + NRF_TIMER00->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_ADDRESS); +#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_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(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); + + 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..a85069751e 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,39 @@ 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 +#define RADIO_INTENSET_READY_Msk RADIO_INTENSET00_READY_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_ */