MYNEWT-701: Low power timer support This commit adds low power timer support to the controller for the nordic chips. Please see the Jira ticket for more information.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/3c785953 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/3c785953 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/3c785953 Branch: refs/heads/develop Commit: 3c7859538a63df76d170fb5cc30cac902f13a7b0 Parents: 507f493 Author: William San Filippo <[email protected]> Authored: Thu Mar 30 13:30:57 2017 -0700 Committer: William San Filippo <[email protected]> Committed: Thu Mar 30 14:10:22 2017 -0700 ---------------------------------------------------------------------- hw/drivers/nimble/nrf51/include/ble/xcvr.h | 11 +- hw/drivers/nimble/nrf51/src/ble_phy.c | 440 +++++++++++++++++-- hw/drivers/nimble/nrf52/src/ble_phy.c | 5 + kernel/os/src/os_cputime.c | 13 +- .../controller/include/controller/ble_ll.h | 2 +- net/nimble/controller/src/ble_ll_conn.c | 6 +- 6 files changed, 434 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/hw/drivers/nimble/nrf51/include/ble/xcvr.h ---------------------------------------------------------------------- diff --git a/hw/drivers/nimble/nrf51/include/ble/xcvr.h b/hw/drivers/nimble/nrf51/include/ble/xcvr.h index 0736506..9f15271 100644 --- a/hw/drivers/nimble/nrf51/include/ble/xcvr.h +++ b/hw/drivers/nimble/nrf51/include/ble/xcvr.h @@ -25,9 +25,18 @@ extern "C" { #endif /* Transceiver specific defintions */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 +/* + * NOTE: we have to account for the RTC output compare issue, which is why + * this number is much larger when using the 32.768 crystal. + */ +#define XCVR_PROC_DELAY_USECS (230) +#else +#define XCVR_PROC_DELAY_USECS (100) +#endif + #define XCVR_RX_START_DELAY_USECS (140) #define XCVR_TX_START_DELAY_USECS (140) -#define XCVR_PROC_DELAY_USECS (100) #define XCVR_TX_SCHED_DELAY_USECS \ (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) #define XCVR_RX_SCHED_DELAY_USECS \ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/hw/drivers/nimble/nrf51/src/ble_phy.c ---------------------------------------------------------------------- diff --git a/hw/drivers/nimble/nrf51/src/ble_phy.c b/hw/drivers/nimble/nrf51/src/ble_phy.c index d6ca388..c9e2b74 100644 --- a/hw/drivers/nimble/nrf51/src/ble_phy.c +++ b/hw/drivers/nimble/nrf51/src/ble_phy.c @@ -22,6 +22,7 @@ #include <assert.h> #include "syscfg/syscfg.h" #include "os/os.h" +#include "ble/xcvr.h" #include "bsp/cmsis_nvic.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" @@ -84,6 +85,9 @@ struct ble_phy_obj struct ble_mbuf_hdr rxhdr; void *txend_arg; ble_phy_tx_end_func txend_cb; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + uint32_t phy_start_cputime; +#endif }; struct ble_phy_obj g_ble_phy_data; @@ -278,6 +282,133 @@ nrf_wait_disabled(void) } } +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 +/** + * + * + */ +int +ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs) +{ + uint32_t next_cc; + uint32_t cur_cc; + uint32_t cntr; + uint32_t delta; + + /* + * XXX: The TXEN time is 140 usecs but there may be additional delays + * Need to look at this. + */ + + /* + * With the 32.768 kHz crystal, we may need to adjust the RTC compare + * value by 1 tick due to the time it takes for TXEN. The code uses a 5 RTC + * tick offset, which is 152.5 usecs. The TXEN time is 140 usecs. This + * means that with a remainder of 0, TIMER0 should be set to 12 or 13 (as + * TIMER0 counts at 1MHz). A remainder of 19 or more we will need to add + * 1 tick. We dont need to add 1 tick per se, but it does give us slightly + * more time and thus less of a chance to miss a tick. Another note: we + * cant set TIMER0 CC to 0 as the compare wont occur; it must be 1 or more. + * This is why we subtract 18 (as opposed to 19) as rem_uses will be >= 1. + */ + if (rem_usecs <= 18) { + cputime -= 5; + rem_usecs += 12; + } else { + cputime -= 4; + rem_usecs -= 18; + } + + /* + * 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_TIMER0->TASKS_CLEAR = 1; + NRF_TIMER0->CC[0] = rem_usecs; + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + + /* Set RTC compare to start TIMER0 */ + NRF_RTC0->EVENTS_COMPARE[0] = 0; + NRF_RTC0->CC[0] = next_cc; + NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; + + /* Enable PPI */ + NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; + + /* Store the cputime at which we set the RTC */ + g_ble_phy_data.phy_start_cputime = cputime; + + return 0; +} + +/** + * 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 + * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are + * starting a connection event and we are a slave and we are waiting for the + * master to send us a packet (txrx should be set to ENABLE_RX). + * + * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there + * is no additional time to wait; we know when we should receive the address of + * the received frame. + * + * @param txrx Flag denoting if this wfr is a txrx turn-around or not. + * @param wfr_usecs Amount of usecs to wait. + */ +void +ble_phy_wfr_enable(int txrx, uint32_t wfr_usecs) +{ + uint32_t end_time; + + if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { + /* + * Timeout occurs an IFS time plus time it takes to receive address + * from the transmit end. We add additional time to make sure the + * address event comes before the compare. Note that transmit end + * is captured in CC[2] + * + * XXX: this assumes 1Mbps as 40 usecs is header rx time for 1Mbps + */ + end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS + 40 + 16; + } else { + /* CC[0] is set to when RXEN occurs. NOTE: the extra 16 usecs is + jitter */ + end_time = NRF_TIMER0->CC[0] + XCVR_RX_START_DELAY_USECS + wfr_usecs + + 40 + 16; + } + + /* wfr_secs is the time from rxen until timeout */ + NRF_TIMER0->CC[3] = end_time; + NRF_TIMER0->EVENTS_COMPARE[3] = 0; + + /* Enable wait for response PPI */ + NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); + + /* Enable the disabled interrupt so we time out on events compare */ + NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; +} +#endif + /** * Setup transceiver for receive. */ @@ -368,14 +499,18 @@ ble_phy_tx_end_isr(void) uint8_t transition; uint8_t txlen; uint32_t wfr_time; +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768) uint32_t txstart; +#endif +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768) /* * Read captured tx start time. This is not the actual transmit start * time but it is the time at which the address event occurred * (after transmission of access address) */ txstart = NRF_TIMER0->CC[1]; +#endif /* If this transmission was encrypted we need to remember it */ was_encrypted = g_ble_phy_data.phy_encrypted; @@ -384,14 +519,20 @@ ble_phy_tx_end_isr(void) assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); /* Log the event */ - ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, (g_ble_phy_tx_buf[0] >> 8) & 0xFF, +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) + ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len, + was_encrypted, NRF_TIMER0->CC[2]); +#else + ble_ll_log(BLE_LL_LOG_ID_PHY_TXEND, g_ble_phy_data.phy_tx_pyld_len, was_encrypted, txstart); +#endif /* Clear events and clear interrupt on disabled event */ NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; NRF_RADIO->EVENTS_END = 0; wfr_time = NRF_RADIO->SHORTS; + (void)wfr_time; #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) /* @@ -424,13 +565,28 @@ ble_phy_tx_end_isr(void) if (txlen && was_encrypted) { txlen += BLE_LL_DATA_MIC_LEN; } +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, 0); +#else wfr_time = BLE_LL_WFR_USECS - BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET); wfr_time += BLE_TX_DUR_USECS_M(txlen); wfr_time = os_cputime_usecs_to_ticks(wfr_time); ble_ll_wfr_enable(txstart + wfr_time); +#endif } else { +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) + /* + * XXX: not sure we need to stop the timer here all the time. Or that + * it should be stopped here. + */ + NRF_TIMER0->TASKS_STOP = 1; + NRF_TIMER0->TASKS_SHUTDOWN = 1; + NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | + PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk; +#else /* Disable automatic TXEN */ NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; +#endif assert(transition == BLE_PHY_TRANSITION_NONE); } } @@ -518,11 +674,48 @@ ble_phy_rx_start_isr(void) { int rc; uint32_t state; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + uint32_t usecs; + uint32_t ticks; +#endif struct ble_mbuf_hdr *ble_hdr; /* Clear events and clear interrupt */ NRF_RADIO->EVENTS_ADDRESS = 0; + + /* Clear wfr timer channels and DISABLED interrupt */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; + NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; +#else NRF_RADIO->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk; +#endif + + /* Initialize flags, channel and state in ble header at rx start */ + ble_hdr = &g_ble_phy_data.rxhdr; + ble_hdr->rxinfo.flags = ble_ll_state_get(); + ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; + ble_hdr->rxinfo.handle = 0; + +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) + /* + * Calculate receive start time. We assume that the header time is + * 40 usecs (only 1 mbps supported right now). + * + * XXX: possibly use other routine with remainder! + */ + usecs = NRF_TIMER0->CC[1] - 40; + ticks = os_cputime_usecs_to_ticks(usecs); + ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks); + if (ble_hdr->rem_usecs == 31) { + ble_hdr->rem_usecs = 0; + ++ticks; + } + ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks; +#else + ble_hdr->beg_cputime = NRF_TIMER0->CC[1] - + os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET)); +#endif /* Wait to get 1st byte of frame */ while (1) { @@ -542,14 +735,6 @@ ble_phy_rx_start_isr(void) } } - /* Initialize flags, channel and state in ble header at rx start */ - ble_hdr = &g_ble_phy_data.rxhdr; - ble_hdr->rxinfo.flags = ble_ll_state_get(); - ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; - ble_hdr->rxinfo.handle = 0; - ble_hdr->beg_cputime = NRF_TIMER0->CC[1] - - os_cputime_usecs_to_ticks(BLE_TX_LEN_USECS_M(NRF_RX_START_OFFSET)); - /* Call Link Layer receive start function */ rc = ble_ll_rx_start(g_ble_phy_data.rxdptr, g_ble_phy_data.phy_chan, &g_ble_phy_data.rxhdr); @@ -584,16 +769,34 @@ ble_phy_isr(void) /* Read irq register to determine which interrupts are enabled */ irq_en = NRF_RADIO->INTENCLR; - /* Check for disabled event. This only happens for transmits now */ - if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { - ble_phy_tx_end_isr(); - } + /* + * NOTE: order of checking is important! Possible, if things get delayed, + * we have both an ADDRESS and DISABLED interrupt in rx state. If we get + * an address, we disable the DISABLED interrupt. + */ /* We get this if we have started to receive a frame */ if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; +#endif ble_phy_rx_start_isr(); } + /* Check for disabled event. This only happens for transmits now */ + if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { + NRF_RADIO->EVENTS_DISABLED = 0; + ble_ll_wfr_timer_exp(NULL); + } else { + ble_phy_tx_end_isr(); + } +#else + ble_phy_tx_end_isr(); +#endif + } + /* Receive packet end (we dont enable this for transmit) */ if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) { ble_phy_rx_end_isr(); @@ -617,6 +820,8 @@ int ble_phy_init(void) { int rc; + +#if !defined(BLE_XCVR_RFCLK) uint32_t os_tmo; /* Make sure HFXO is started */ @@ -631,6 +836,7 @@ ble_phy_init(void) return BLE_PHY_ERR_INIT; } } +#endif /* Set phy channel to an invalid channel so first set channel works */ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; @@ -665,8 +871,13 @@ ble_phy_init(void) /* Configure IFS */ NRF_RADIO->TIFS = BLE_LL_IFS; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ + NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk; +#else /* Captures tx/rx start in timer0 capture 1 */ NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk; +#endif #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) NRF_CCM->INTENCLR = 0xffffffff; @@ -685,6 +896,27 @@ ble_phy_init(void) NRF_AAR->NIRK = 0; #endif + /* TIMER0 setup for PHY when using RTC */ +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) + NRF_TIMER0->TASKS_STOP = 1; + NRF_TIMER0->TASKS_SHUTDOWN = 1; + NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ + NRF_TIMER0->MODE = 0; /* Timer mode */ + NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ + + /* + * PPI setup. + * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used + * to cancel the wait for response timer. + * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait + * for response timer. + */ + NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS); + NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]); + NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]); + NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE); +#endif + /* Set isr in vector table and enable interrupt */ NVIC_SetPriority(RADIO_IRQn, 0); NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); @@ -803,6 +1035,7 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) g_ble_phy_data.txend_arg = arg; } +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) /** * Called to set the start time of a transmission. * @@ -812,28 +1045,38 @@ ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) * NOTE: care must be taken when calling this function. The channel should * already be set. * - * @param cputime - * + * @param cputime This is the tick at which the 1st bit of the preamble + * should be transmitted + * @param rem_usecs This is used only when the underlying timing uses a 32.768 + * kHz crystal. It is the # of usecs from the cputime tick + * at which the first bit of the preamble should be + * transmitted. * @return int */ int -ble_phy_tx_set_start_time(uint32_t cputime) +ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) { int rc; - NRF_TIMER0->CC[0] = cputime; - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; + /* XXX: This should not be necessary, but paranoia is good! */ + /* Clear timer0 compare to RXEN since we are transmitting */ NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; - if ((int32_t)(os_cputime_get32() - cputime) >= 0) { + + /* + * XXX: The TXEN time is 140 usecs but there may be additional delays + * Need to look at this. + */ + if (ble_phy_set_start_time(cputime, rem_usecs) != 0) { STATS_INC(ble_phy_stats, tx_late); ble_phy_disable(); - rc = BLE_PHY_ERR_TX_LATE; + rc = BLE_PHY_ERR_TX_LATE; } else { + /* Enable PPI to automatically start TXEN */ + NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; rc = 0; } return rc; } - /** * Called to set the start time of a reception * @@ -848,23 +1091,91 @@ ble_phy_tx_set_start_time(uint32_t cputime) * @return int */ int -ble_phy_rx_set_start_time(uint32_t cputime) +ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) { int rc; + /* XXX: This should not be necessary, but paranoia is good! */ + /* Clear timer0 compare to TXEN since we are transmitting */ + NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; + + /* + * XXX: The RXEN time is 138 usecs but there may be additional delays + * Need to look at this. + */ + if (ble_phy_set_start_time(cputime, rem_usecs) != 0) { + STATS_INC(ble_phy_stats, rx_late); + NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; + NRF_RADIO->TASKS_RXEN = 1; + rc = BLE_PHY_ERR_RX_LATE; + } else { + /* Enable PPI to automatically start RXEN */ + NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + + /* Start rx */ + rc = ble_phy_rx(); + } + return rc; +} +#else +/** + * Called to set the start time of a transmission. + * + * This function is called to set the start time when we are not going from + * rx to tx automatically. + * + * NOTE: care must be taken when calling this function. The channel should + * already be set. + * + * @param cputime This is the tick at which the 1st bit of the preamble + * should be transmitted + * @return int + */ +int +ble_phy_tx_set_start_time(uint32_t cputime) +{ + int rc; + + cputime -= os_cputime_usecs_to_ticks(XCVR_TX_START_DELAY_USECS); + NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; NRF_TIMER0->CC[0] = cputime; + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; + if ((int32_t)(os_cputime_get32() - cputime) >= 0) { + STATS_INC(ble_phy_stats, tx_late); + ble_phy_disable(); + rc = BLE_PHY_ERR_TX_LATE; + } else { + rc = 0; + } + + return rc; +} + +#if 0 +int +ble_phy_rx_set_start_time(void) +{ + /* + * XXX: For now, we dont use this function if we are not using the + * RTC. Keeping the code around just in case we want to use it later. + */ NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; + NRF_TIMER0->CC[0] = cputime; + NRF_TIMER0->EVENTS_COMPARE[0] = 0; NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; if ((int32_t)(os_cputime_get32() - cputime) >= 0) { STATS_INC(ble_phy_stats, rx_late); NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; NRF_RADIO->TASKS_RXEN = 1; - rc = BLE_PHY_ERR_TX_LATE; + rc = BLE_PHY_ERR_RX_LATE; } else { rc = 0; } return rc; } +#endif +#endif int ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) @@ -888,6 +1199,16 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) ble_hdr = BLE_MBUF_HDR_PTR(txpdu); payload_len = ble_hdr->txinfo.pyld_len; + /* + * XXX: Although we may not have to do this here, I clear all the PPI + * that should not be used when transmitting. Some of them are only enabled + * if encryption and/or privacy is on, but I dont care. Better to be + * paranoid, and if you are going to clear one, might as well clear them + * all. + */ + NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk | + PPI_CHEN_CH25_Msk; + #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1) if (g_ble_phy_data.phy_encrypted) { /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ @@ -904,15 +1225,12 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->MODE = CCM_MODE_MODE_Encryption; NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data; - NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk | PPI_CHEN_CH23_Msk; NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk; } else { - #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) /* Reconfigure PCNF0 */ NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; #endif /* RAM representation has S0 and LENGTH fields (2 bytes) */ @@ -927,7 +1245,6 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) /* Reconfigure PCNF0 */ NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos); - NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; #endif /* RAM representation has S0 and LENGTH fields (2 bytes) */ @@ -1106,29 +1423,62 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) /** - * Disable the PHY. This will do the following: - * -> Turn off all phy interrupts. - * -> Disable internal shortcuts. - * -> Disable the radio. - * -> Make sure we wont automatically go to rx/tx on output compare - * -> Sets phy state to idle. - * -> Clears any pending irqs in the NVIC. Might not be necessary but we do - * it as a precaution. + * Stop the timer used to count microseconds when using RTC for cputime */ void -ble_phy_disable(void) +ble_phy_stop_usec_timer(void) { - ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0); + NRF_TIMER0->TASKS_STOP = 1; + NRF_TIMER0->TASKS_SHUTDOWN = 1; + NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; +} +#endif +/** + * ble phy disable irq and ppi + * + * This routine is to be called when reception was stopped due to either a + * wait for response timeout or a packet being received and the phy is to be + * restarted in receive mode. Generally, the disable routine is called to stop + * the phy. + */ +void +ble_phy_disable_irq_and_ppi(void) +{ NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; NRF_RADIO->SHORTS = 0; NRF_RADIO->TASKS_DISABLE = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk; + NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk | + PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | PPI_CHEN_CH24_Msk | + PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk; NVIC_ClearPendingIRQ(RADIO_IRQn); g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; } +void +ble_phy_restart_rx(void) +{ + ble_phy_disable_irq_and_ppi(); + ble_phy_rx(); +} + +/** + * ble phy disable + * + * Disables the PHY. This should be called when an event is over. It stops + * the usec timer (if used), disables interrupts, disables the RADIO, disables + * PPI and sets state to idle. + */ +void +ble_phy_disable(void) +{ + ble_ll_log(BLE_LL_LOG_ID_PHY_DISABLE, g_ble_phy_data.phy_state, 0, 0); + ble_phy_stop_usec_timer(); + ble_phy_disable_irq_and_ppi(); +} + /* Gets the current access address */ uint32_t ble_phy_access_addr_get(void) { @@ -1201,3 +1551,17 @@ ble_phy_resolv_list_disable(void) g_ble_phy_data.phy_privacy = 0; } #endif + +#ifdef BLE_XCVR_RFCLK +void +ble_phy_rfclk_enable(void) +{ + NRF_CLOCK->TASKS_HFCLKSTART = 1; +} + +void +ble_phy_rfclk_disable(void) +{ + NRF_CLOCK->TASKS_HFCLKSTOP = 1; +} +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/hw/drivers/nimble/nrf52/src/ble_phy.c ---------------------------------------------------------------------- diff --git a/hw/drivers/nimble/nrf52/src/ble_phy.c b/hw/drivers/nimble/nrf52/src/ble_phy.c index 8d8b0e1..e6b470e 100644 --- a/hw/drivers/nimble/nrf52/src/ble_phy.c +++ b/hw/drivers/nimble/nrf52/src/ble_phy.c @@ -694,6 +694,10 @@ ble_phy_rx_start_isr(void) usecs = NRF_TIMER0->CC[1] - 40; ticks = os_cputime_usecs_to_ticks(usecs); ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks); + if (ble_hdr->rem_usecs == 31) { + ble_hdr->rem_usecs = 0; + ++ticks; + } ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime + ticks; #else ble_hdr->beg_cputime = NRF_TIMER0->CC[1] - @@ -1152,6 +1156,7 @@ ble_phy_rx_set_start_time(void) } else { rc = 0; } + return rc; } #endif #endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/kernel/os/src/os_cputime.c ---------------------------------------------------------------------- diff --git a/kernel/os/src/os_cputime.c b/kernel/os/src/os_cputime.c index 01b15fe..56b626c 100644 --- a/kernel/os/src/os_cputime.c +++ b/kernel/os/src/os_cputime.c @@ -122,8 +122,17 @@ os_cputime_usecs_to_ticks(uint32_t usecs) { uint64_t ticks; - ticks = ((uint64_t)usecs << 9) / 15625; - return (uint32_t)ticks; + /* + * Faster calculation but could be off 1 full tick since we do not + * add residual back. Adding back the residual is commented out below, but + * shown. + */ + ticks = (uint64_t)usecs * (uint32_t)((((uint64_t)1 << 32) * 32768) / 1000000); + + /* Residual */ + //ticks += ((uint64_t)us * (1526122139+1)) >> 32; + + return (uint32_t)(ticks >> 32); } /** http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/net/nimble/controller/include/controller/ble_ll.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h index acc201d..2094290 100644 --- a/net/nimble/controller/include/controller/ble_ll.h +++ b/net/nimble/controller/include/controller/ble_ll.h @@ -425,7 +425,7 @@ int ble_ll_rand_start(void); * XXX: temporary LL debug log. Will get removed once we transition to real * log */ -#define BLE_LL_LOG +#undef BLE_LL_LOG #include "console/console.h" #define BLE_LL_LOG_ID_PHY_SETCHAN (1) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/3c785953/net/nimble/controller/src/ble_ll_conn.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c index d7f926e..9a6dc1a 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -242,9 +242,13 @@ ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) */ usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; ticks = os_cputime_usecs_to_ticks(usecs); - connsm->conn_itvl_ticks = ticks; connsm->conn_itvl_usecs = (uint8_t)(usecs - os_cputime_ticks_to_usecs(ticks)); + if (connsm->conn_itvl_usecs == 31) { + connsm->conn_itvl_usecs = 0; + ++ticks; + } + connsm->conn_itvl_ticks = ticks; } #endif
