Low power timer. Only nrf52 right now.
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/507f493a Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/507f493a Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/507f493a Branch: refs/heads/develop Commit: 507f493ab86266528c7f921784978e63a07ddd33 Parents: 8158805 Author: William San Filippo <wi...@runtime.io> Authored: Thu Feb 16 16:12:39 2017 -0800 Committer: William San Filippo <wi...@runtime.io> Committed: Thu Mar 30 14:09:52 2017 -0700 ---------------------------------------------------------------------- apps/bletest/src/main.c | 2 +- hw/drivers/nimble/nrf52/include/ble/xcvr.h | 12 +- hw/drivers/nimble/nrf52/src/ble_phy.c | 438 +++++++++++++++++-- kernel/os/include/os/os_cputime.h | 8 + kernel/os/src/os_cputime.c | 50 +++ .../controller/include/controller/ble_ll.h | 51 ++- .../controller/include/controller/ble_ll_conn.h | 5 + .../include/controller/ble_ll_sched.h | 32 +- .../controller/include/controller/ble_ll_xcvr.h | 48 ++ .../controller/include/controller/ble_phy.h | 31 +- net/nimble/controller/src/ble_ll.c | 37 ++ net/nimble/controller/src/ble_ll_adv.c | 86 +++- net/nimble/controller/src/ble_ll_conn.c | 265 +++++++++-- net/nimble/controller/src/ble_ll_conn_priv.h | 3 +- net/nimble/controller/src/ble_ll_scan.c | 145 +++++- net/nimble/controller/src/ble_ll_sched.c | 354 +++++++++++---- net/nimble/controller/src/ble_ll_xcvr.c | 153 +++++++ net/nimble/controller/syscfg.yml | 8 + net/nimble/host/src/ble_hs_hci_evt.c | 6 +- net/nimble/include/nimble/ble.h | 3 + 20 files changed, 1531 insertions(+), 206 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/apps/bletest/src/main.c ---------------------------------------------------------------------- diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c index e2519eb..efb3fd4 100755 --- a/apps/bletest/src/main.c +++ b/apps/bletest/src/main.c @@ -172,7 +172,7 @@ bletest_multi_adv_instances[BLETEST_CFG_ADV_TEST_INSTANCES] = { #define BLETEST_CFG_MAX_CE_LEN (BLETEST_CFG_CONN_ITVL) #define BLETEST_CFG_CONN_PEER_ADDR_TYPE (BLE_HCI_CONN_PEER_ADDR_PUBLIC) #define BLETEST_CFG_CONN_OWN_ADDR_TYPE (BLE_HCI_ADV_OWN_ADDR_PUBLIC) -#define BLETEST_CFG_CONCURRENT_CONNS (1) +#define BLETEST_CFG_CONCURRENT_CONNS (8) /* Test packet config */ #define BLETEST_CFG_RAND_PKT_SIZE (1) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/hw/drivers/nimble/nrf52/include/ble/xcvr.h ---------------------------------------------------------------------- diff --git a/hw/drivers/nimble/nrf52/include/ble/xcvr.h b/hw/drivers/nimble/nrf52/include/ble/xcvr.h index 6a35124..2b6d7ea 100644 --- a/hw/drivers/nimble/nrf52/include/ble/xcvr.h +++ b/hw/drivers/nimble/nrf52/include/ble/xcvr.h @@ -24,10 +24,18 @@ extern "C" { #endif -/* Transceiver specific definitions */ +#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 for cputime. We + * want it to be 5 ticks. + */ +#define XCVR_PROC_DELAY_USECS (153) +#else +#define XCVR_PROC_DELAY_USECS (50) +#endif #define XCVR_RX_START_DELAY_USECS (140) #define XCVR_TX_START_DELAY_USECS (140) -#define XCVR_PROC_DELAY_USECS (50) #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/507f493a/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 8771f49..8d8b0e1 100644 --- a/hw/drivers/nimble/nrf52/src/ble_phy.c +++ b/hw/drivers/nimble/nrf52/src/ble_phy.c @@ -78,6 +78,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; @@ -280,6 +283,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. */ @@ -360,14 +490,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; @@ -376,14 +510,20 @@ ble_phy_tx_end_isr(void) assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); /* Log the event */ +#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) /* @@ -416,13 +556,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); } } @@ -506,12 +661,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 the ble mbuf header */ + ble_hdr = &g_ble_phy_data.rxhdr; + ble_hdr->rxinfo.flags = ble_ll_state_get(); + ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; + ble_hdr->rxinfo.handle = 0; + +#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); + 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 + + /* XXX: I wonder if we always have the 1st byte. If we need to wait for + * rx chain delay, it could be 18 usecs from address interrupt. The + nrf52 may be able to get here early. */ /* Wait to get 1st byte of frame */ while (1) { state = NRF_RADIO->STATE; @@ -530,14 +721,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((uint8_t *)&g_ble_phy_rx_buf[0] + 3, g_ble_phy_data.phy_chan, @@ -573,16 +756,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(); @@ -606,6 +807,8 @@ int ble_phy_init(void) { int rc; + +#if !defined(BLE_XCVR_RFCLK) uint32_t os_tmo; /* Make sure HFXO is started */ @@ -620,6 +823,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; @@ -657,8 +861,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; @@ -677,6 +886,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); @@ -785,6 +1015,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. * @@ -794,28 +1025,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 * @@ -830,23 +1071,90 @@ 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) @@ -871,6 +1179,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) { dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; @@ -883,11 +1201,9 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->MODE = CCM_MODE_LENGTH_Msk; 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) - NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; #endif dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; @@ -895,9 +1211,6 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans) pktptr = dptr; } #else -#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1) - NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk; -#endif dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; ++dptr; pktptr = dptr; @@ -1077,29 +1390,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) { @@ -1168,3 +1514,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/507f493a/kernel/os/include/os/os_cputime.h ---------------------------------------------------------------------- diff --git a/kernel/os/include/os/os_cputime.h b/kernel/os/include/os/os_cputime.h index f44c941..022efdc 100644 --- a/kernel/os/include/os/os_cputime.h +++ b/kernel/os/include/os/os_cputime.h @@ -45,6 +45,10 @@ extern "C" { #define OS_CPUTIME_FREQ_1MHZ #endif +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) +#define OS_CPUTIME_FREQ_32768 +#endif + /* CPUTIME data. */ struct os_cputime_data { @@ -80,6 +84,7 @@ int os_cputime_init(uint32_t clock_freq); */ uint32_t os_cputime_get32(void); +#if !defined(OS_CPUTIME_FREQ_32768) /** * os cputime nsecs to ticks * @@ -101,6 +106,7 @@ uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs); * @return uint32_t The number of nanoseconds corresponding to 'ticks' */ uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks); +#endif #if defined(OS_CPUTIME_FREQ_1MHZ) #define os_cputime_usecs_to_ticks(x) (x) @@ -138,6 +144,7 @@ uint32_t os_cputime_ticks_to_usecs(uint32_t ticks); */ void os_cputime_delay_ticks(uint32_t ticks); +#if !defined(OS_CPUTIME_FREQ_32768) /** * os cputime delay nsecs * @@ -146,6 +153,7 @@ void os_cputime_delay_ticks(uint32_t ticks); * @param nsecs The number of nanoseconds to wait. */ void os_cputime_delay_nsecs(uint32_t nsecs); +#endif /** * os cputime delay usecs http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/kernel/os/src/os_cputime.c ---------------------------------------------------------------------- diff --git a/kernel/os/src/os_cputime.c b/kernel/os/src/os_cputime.c index 067f1a1..01b15fe 100644 --- a/kernel/os/src/os_cputime.c +++ b/kernel/os/src/os_cputime.c @@ -30,7 +30,9 @@ * @{ */ +#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ) struct os_cputime_data g_os_cputime; +#endif /** * os cputime init @@ -49,11 +51,14 @@ os_cputime_init(uint32_t clock_freq) int rc; /* Set the ticks per microsecond. */ +#if !defined(OS_CPUTIME_FREQ_32768) && !defined(OS_CPUTIME_FREQ_1MHZ) g_os_cputime.ticks_per_usec = clock_freq / 1000000U; +#endif rc = hal_timer_config(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), clock_freq); return rc; } +#if !defined(OS_CPUTIME_FREQ_32768) /** * os cputime nsecs to ticks * @@ -99,8 +104,50 @@ os_cputime_ticks_to_nsecs(uint32_t ticks) return nsecs; } +#endif #if !defined(OS_CPUTIME_FREQ_1MHZ) +#if defined(OS_CPUTIME_FREQ_32768) +/** + * os cputime usecs to ticks + * + * Converts the given number of microseconds into cputime ticks. + * + * @param usecs The number of microseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'usecs' + */ +uint32_t +os_cputime_usecs_to_ticks(uint32_t usecs) +{ + uint64_t ticks; + + ticks = ((uint64_t)usecs << 9) / 15625; + return (uint32_t)ticks; +} + +/** + * cputime ticks to usecs + * + * Convert the given number of ticks into microseconds. + * + * @param ticks The number of ticks to convert to microseconds. + * + * @return uint32_t The number of microseconds corresponding to 'ticks' + * + * NOTE: This calculation will overflow if the value for ticks is greater + * than 140737488. I am not going to check that here because that many ticks + * is about 4222 seconds, way more than what this routine should be used for. + */ +uint32_t +os_cputime_ticks_to_usecs(uint32_t ticks) +{ + uint32_t usecs; + + usecs = ((ticks >> 9) * 15625) + (((ticks & 0x1ff) * 15625) >> 9); + return usecs; +} +#else /** * os cputime usecs to ticks * @@ -138,6 +185,7 @@ os_cputime_ticks_to_usecs(uint32_t ticks) return us; } #endif +#endif /** * os cputime delay ticks @@ -157,6 +205,7 @@ os_cputime_delay_ticks(uint32_t ticks) } } +#if !defined(OS_CPUTIME_FREQ_32768) /** * os cputime delay nsecs * @@ -172,6 +221,7 @@ os_cputime_delay_nsecs(uint32_t nsecs) ticks = os_cputime_nsecs_to_ticks(nsecs); os_cputime_delay_ticks(ticks); } +#endif /** * os cputime delay usecs http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 e349d71..acc201d 100644 --- a/net/nimble/controller/include/controller/ble_ll.h +++ b/net/nimble/controller/include/controller/ble_ll.h @@ -22,13 +22,41 @@ #include "stats/stats.h" #include "os/os_eventq.h" +#include "os/os_callout.h" #include "os/os_cputime.h" #include "nimble/nimble_opt.h" +#include "controller/ble_phy.h" #ifdef __cplusplus extern "C" { #endif +/* + * XXX: + * I guess this should not depend on the 32768 crystal to be honest. This + * should be done for TIMER0 as well since the rf clock chews up more current. + * Deal with this later. + * + * Another note: BLE_XTAL_SETTLE_TIME should be bsp related (I guess). There + * should be a note in there that the converted usecs to ticks value of this + * should not be 0. Thus: if you are using a 32.768 os cputime freq, the min + * value of settle time should be 31 usecs. I would suspect all settling times + * would exceed 31 usecs. + */ + +/* Determines if we need to turn on/off rf clock */ +#undef BLE_XCVR_RFCLK + +/* Transceiver specific definitions */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + +/* We will turn on/off rf clock */ +#if MYNEWT_VAL(BLE_XTAL_SETTLE_TIME) != 0 +#define BLE_XCVR_RFCLK +#endif + +#endif + /* Controller revision. */ #define BLE_LL_SUB_VERS_NR (0x0000) @@ -61,11 +89,22 @@ struct ble_ll_obj /* Number of ACL data packets supported */ uint8_t ll_num_acl_pkts; + +#ifdef BLE_XCVR_RFCLK + uint8_t ll_rfclk_state; + uint16_t ll_xtal_ticks; +#else uint8_t _pad; + uint16_t _pad16; +#endif /* ACL data packet size */ uint16_t ll_acl_pkt_size; - uint16_t _pad16; + +#ifdef BLE_XCVR_RFCLK + uint32_t ll_rfclk_start_time; + struct hal_timer ll_rfclk_timer; +#endif /* Task event queue */ struct os_eventq ll_evq; @@ -362,6 +401,9 @@ void ble_ll_wfr_enable(uint32_t cputime); /* Disable wait for response timer */ void ble_ll_wfr_disable(void); +/* Wait for response timer expiration callback */ +void ble_ll_wfr_timer_exp(void *arg); + /* Read set of features supported by the Link Layer */ uint8_t ble_ll_read_supp_features(void); @@ -383,7 +425,7 @@ int ble_ll_rand_start(void); * XXX: temporary LL debug log. Will get removed once we transition to real * log */ -#undef BLE_LL_LOG +#define BLE_LL_LOG #include "console/console.h" #define BLE_LL_LOG_ID_PHY_SETCHAN (1) @@ -405,6 +447,11 @@ int ble_ll_rand_start(void); #define BLE_LL_LOG_ID_ADV_TXBEG (50) #define BLE_LL_LOG_ID_ADV_TXDONE (60) #define BLE_LL_LOG_ID_SCHED (80) +#define BLE_LL_LOG_ID_RFCLK_START (90) +#define BLE_LL_LOG_ID_RFCLK_ENABLE (91) +#define BLE_LL_LOG_ID_RFCLK_STOP (95) +#define BLE_LL_LOG_ID_RFCLK_SCHED_DIS (96) +#define BLE_LL_LOG_ID_RFCLK_SCAN_DIS (97) #ifdef BLE_LL_LOG void ble_ll_log(uint8_t id, uint8_t arg8, uint16_t arg16, uint32_t arg32); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_conn.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h index b2e6410..041504d 100644 --- a/net/nimble/controller/include/controller/ble_ll_conn.h +++ b/net/nimble/controller/include/controller/ble_ll_conn.h @@ -202,6 +202,11 @@ struct ble_ll_conn_sm uint16_t max_ce_len; uint16_t tx_win_off; uint32_t anchor_point; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/ + uint8_t conn_itvl_usecs; + uint32_t conn_itvl_ticks; +#endif uint32_t last_anchor_point; /* Slave only */ uint32_t slave_cur_tx_win_usecs; uint32_t slave_cur_window_widening; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_sched.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll_sched.h b/net/nimble/controller/include/controller/ble_ll_sched.h index 3a05cfe..d2321b7 100644 --- a/net/nimble/controller/include/controller/ble_ll_sched.h +++ b/net/nimble/controller/include/controller/ble_ll_sched.h @@ -25,7 +25,8 @@ extern "C" { #endif /* Time per BLE scheduler slot */ -#define BLE_LL_SCHED_USECS_PER_SLOT (1250) +#define BLE_LL_SCHED_USECS_PER_SLOT (1250) +#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */ /* * Worst case time needed for scheduled advertising item. This is the longest @@ -46,6 +47,17 @@ extern "C" { #define BLE_LL_SCHED_DIRECT_ADV_MAX_USECS (502) #define BLE_LL_SCHED_MAX_ADV_PDU_USECS (376) +/* BLE Jitter (+/- 16 useecs) */ +#define BLE_LL_JITTER_USECS (16) + +/* + * This is the offset from the start of the scheduled item until the actual + * tx/rx should occur, in ticks. + */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 +extern uint8_t g_ble_ll_sched_offset_ticks; +#endif + /* * This is the number of slots needed to transmit and receive a maximum * size PDU, including an IFS time before each. The actual time is @@ -69,10 +81,19 @@ extern "C" { struct ble_ll_sched_item; typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch); +/* + * Schedule item + * sched_type: This is the type of the schedule item. + * enqueued: Flag denoting if item is on the scheduler list. 0: no, 1:yes + * remainder: # of usecs from offset till tx/rx should occur + * txrx_offset: Number of ticks from start time until tx/rx should occur. + * + */ struct ble_ll_sched_item { uint8_t sched_type; uint8_t enqueued; + uint8_t remainder; uint32_t start_time; uint32_t end_time; void *cb_arg; @@ -94,8 +115,8 @@ void ble_ll_sched_free_item(struct ble_ll_sched_item *sch); /* Schedule a new master connection */ struct ble_ll_conn_sm; -int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, uint32_t adv_rxend, - uint8_t req_slots); +int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, + struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len); /* Schedule a new slave connection */ int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm); @@ -128,6 +149,11 @@ int ble_ll_sched_next_time(uint32_t *next_event_time); /* Stop the scheduler */ void ble_ll_sched_stop(void); +#ifdef BLE_XCVR_RFCLK +/* Check if RF clock needs to be restarted */ +void ble_ll_sched_rfclk_chk_restart(void); +#endif + #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_ll_xcvr.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_ll_xcvr.h b/net/nimble/controller/include/controller/ble_ll_xcvr.h new file mode 100644 index 0000000..c59b009 --- /dev/null +++ b/net/nimble/controller/include/controller/ble_ll_xcvr.h @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_XCVR_ +#define H_BLE_LL_XCVR_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef BLE_XCVR_RFCLK + +/* RF clock states */ +#define BLE_RFCLK_STATE_OFF (0) +#define BLE_RFCLK_STATE_ON (1) +#define BLE_RFCLK_STATE_SETTLED (2) + +int ble_ll_xcvr_rfclk_state(void); +void ble_ll_xcvr_rfclk_start_now(uint32_t now); +void ble_ll_xcvr_rfclk_stop(void); +void ble_ll_xcvr_rfclk_enable(void); +void ble_ll_xcvr_rfclk_disable(void); +uint32_t ble_ll_xcvr_rfclk_time_till_settled(void); +void ble_ll_xcvr_rfclk_timer_exp(void *arg); +void ble_ll_xcvr_rfclk_timer_start(uint32_t cputime); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_LL_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/include/controller/ble_phy.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/include/controller/ble_phy.h b/net/nimble/controller/include/controller/ble_phy.h index 674cbc5..e62b216 100644 --- a/net/nimble/controller/include/controller/ble_phy.h +++ b/net/nimble/controller/include/controller/ble_phy.h @@ -70,6 +70,7 @@ struct os_mbuf; #define BLE_PHY_ERR_INV_PARAM (3) #define BLE_PHY_ERR_NO_BUFS (4) #define BLE_PHY_ERR_TX_LATE (5) +#define BLE_PHY_ERR_RX_LATE (6) /* Maximun PDU length. Includes LL header of 2 bytes and 255 bytes payload. */ #define BLE_PHY_MAX_PDU_LEN (257) @@ -86,11 +87,16 @@ int ble_phy_reset(void); /* Set the PHY channel */ int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 /* Set transmit start time */ -int ble_phy_tx_set_start_time(uint32_t cputime); +int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs); /* Set receive start time */ -int ble_phy_rx_set_start_time(uint32_t cputime); +int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs); +#else +/* Set transmit start time */ +int ble_phy_tx_set_start_time(uint32_t cputime); +#endif /* Set the transmit end callback and argument */ void ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg); @@ -116,6 +122,27 @@ int ble_phy_txpwr_get(void); /* Disable the PHY */ void ble_phy_disable(void); +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768) +void ble_phy_stop_usec_timer(void); +void ble_phy_wfr_enable(int txrx, uint32_t wfr_usecs); +#define BLE_PHY_WFR_ENABLE_RX (0) +#define BLE_PHY_WFR_ENABLE_TXRX (1) +#else +#define ble_phy_stop_usec_timer() +#endif + +/* Starts rf clock */ +void ble_phy_rfclk_enable(void); + +/* Stops rf clock */ +void ble_phy_rfclk_disable(void); + +/* + * Used to restart reception on same channel after wfr timer expiration or + * frame received. + */ +void ble_phy_restart_rx(void); + /* Gets the current state of the PHY */ int ble_phy_state_get(void); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/src/ble_ll.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c index 6071d3c..3204ff2 100644 --- a/net/nimble/controller/src/ble_ll.c +++ b/net/nimble/controller/src/ble_ll.c @@ -39,6 +39,7 @@ #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" +#include "controller/ble_ll_xcvr.h" #include "ble_ll_conn_priv.h" /* XXX: @@ -51,6 +52,11 @@ * 4) Should look into always disabled the wfr interrupt if we receive the * start of a frame. Need to look at the various states to see if this is the * right thing to do. + * 5) I am not sure that if we are passed the output compare that we actually + * get the interrupt. Test this. + * 6) I am not sure that if we receive a packet while scanning that we actually + * go back to scanning. I need to make sure we re-enable the receive. + * Put an event in the log! */ /* Supported states */ @@ -536,7 +542,9 @@ ble_ll_wfr_timer_exp(void *arg) void ble_ll_wfr_enable(uint32_t cputime) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 os_cputime_timer_start(&g_ble_ll_data.ll_wfr_timer, cputime); +#endif } /** @@ -545,7 +553,9 @@ ble_ll_wfr_enable(uint32_t cputime) void ble_ll_wfr_disable(void) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 os_cputime_timer_stop(&g_ble_ll_data.ll_wfr_timer); +#endif } /** @@ -786,7 +796,12 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) int rc; uint8_t pdu_type; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, rxhdr->rem_usecs, + rxhdr->beg_cputime); +#else ble_ll_log(BLE_LL_LOG_ID_RX_START, chan, 0, rxhdr->beg_cputime); +#endif /* Check channel type */ if (chan < BLE_PHY_NUM_DATA_CHANS) { @@ -1167,6 +1182,11 @@ ble_ll_reset(void) /* Set state to standby */ ble_ll_state_set(BLE_LL_STATE_STANDBY); +#ifdef BLE_XCVR_RFCLK + /* Stops rf clock and rfclock timer */ + ble_ll_xcvr_rfclk_stop(); +#endif + /* Reset our random address */ memset(g_random_addr, 0, BLE_DEV_ADDR_LEN); @@ -1211,11 +1231,26 @@ ble_ll_init(void) { int rc; uint8_t features; +#ifdef BLE_XCVR_RFCLK + uint32_t xtal_ticks; +#endif struct ble_ll_obj *lldata; /* Ensure this function only gets called by sysinit. */ SYSINIT_ASSERT_ACTIVE(); +#ifdef BLE_XCVR_RFCLK + /* Settling time of crystal, in ticks */ + xtal_ticks = MYNEWT_VAL(BLE_XTAL_SETTLE_TIME); + assert(xtal_ticks != 0); + g_ble_ll_data.ll_xtal_ticks = os_cputime_usecs_to_ticks(xtal_ticks); + + /* Initialize rf clock timer */ + os_cputime_timer_init(&g_ble_ll_data.ll_rfclk_timer, + ble_ll_xcvr_rfclk_timer_exp, NULL); + +#endif + /* Get pointer to global data object */ lldata = &g_ble_ll_data; @@ -1241,9 +1276,11 @@ ble_ll_init(void) ble_ll_hw_err_timer_cb, NULL); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 /* Initialize wait for response timer */ os_cputime_timer_init(&g_ble_ll_data.ll_wfr_timer, ble_ll_wfr_timer_exp, NULL); +#endif /* Initialize LL HCI */ ble_ll_hci_init(); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/src/ble_ll_adv.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_adv.c b/net/nimble/controller/src/ble_ll_adv.c index 203f13a..8240d7a 100644 --- a/net/nimble/controller/src/ble_ll_adv.c +++ b/net/nimble/controller/src/ble_ll_adv.c @@ -430,8 +430,14 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) assert(rc == 0); /* Set transmit start time. */ - txstart = sch->start_time + os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + txstart = sch->start_time + g_ble_ll_sched_offset_ticks; + rc = ble_phy_tx_set_start_time(txstart, sch->remainder); +#else + txstart = sch->start_time + + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); rc = ble_phy_tx_set_start_time(txstart); +#endif if (rc) { STATS_INC(ble_ll_stats, adv_late_starts); goto adv_tx_done; @@ -498,7 +504,7 @@ adv_tx_done: } static void -ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new) +ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) { uint32_t max_usecs; struct ble_ll_sched_item *sch; @@ -529,20 +535,15 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm, int sched_new) */ max_usecs += XCVR_PROC_DELAY_USECS; - if (sched_new) { - /* - * We have to add the scheduling delay and tx start delay to the max - * time of the event since the pdu does not start at the scheduled start. - */ - max_usecs += XCVR_TX_SCHED_DELAY_USECS; - sch->start_time = os_cputime_get32(); - sch->end_time = sch->start_time + os_cputime_usecs_to_ticks(max_usecs); - } else { - sch->start_time = advsm->adv_pdu_start_time - - os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); - sch->end_time = advsm->adv_pdu_start_time + - os_cputime_usecs_to_ticks(max_usecs); - } +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; + sch->remainder = 0; +#else + sch->start_time = advsm->adv_pdu_start_time - + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); +#endif + sch->end_time = advsm->adv_pdu_start_time + + os_cputime_usecs_to_ticks(max_usecs); } /** @@ -745,6 +746,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) ble_ll_wfr_disable(); ble_ll_state_set(BLE_LL_STATE_STANDBY); g_ble_ll_cur_adv_sm = NULL; + ble_ll_scan_chk_resume(); +#ifdef BLE_XCVR_RFCLK + ble_ll_sched_rfclk_chk_restart(); +#endif } #else if (ble_ll_state_get() == BLE_LL_STATE_ADV) { @@ -752,6 +757,10 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) ble_ll_wfr_disable(); ble_ll_state_set(BLE_LL_STATE_STANDBY); g_ble_ll_cur_adv_sm = NULL; + ble_ll_scan_chk_resume(); +#ifdef BLE_XCVR_RFCLK + ble_ll_sched_rfclk_chk_restart(); +#endif } #endif OS_EXIT_CRITICAL(sr); @@ -872,10 +881,23 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) advsm->adv_chan = adv_chan; /* + * XXX: while this may not be the most efficient, schedule the first + * advertising event some time in the future (5 msecs). This will give + * time to start up any clocks or anything and also avoid a bunch of code + * to check if we are currently doing anything. Just makes this simple. + * + * Might also want to align this on a slot in the future. + * + * NOTE: adv_event_start_time gets set by the sched_adv_new + */ + advsm->adv_pdu_start_time = os_cputime_get32() + + os_cputime_usecs_to_ticks(BLE_LL_SCHED_MAX_TXRX_SLOT); + + /* * Schedule advertising. We set the initial schedule start and end * times to the earliest possible start/end. */ - ble_ll_adv_set_sched(advsm, 1); + ble_ll_adv_set_sched(advsm); ble_ll_sched_adv_new(&advsm->adv_sch); return BLE_ERR_SUCCESS; @@ -884,9 +906,14 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) void ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* The event start time is when we start transmission of the adv PDU */ + advsm->adv_event_start_time = sch_start + g_ble_ll_sched_offset_ticks; +#else /* The event start time is when we start transmission of the adv PDU */ advsm->adv_event_start_time = sch_start + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); +#endif advsm->adv_pdu_start_time = advsm->adv_event_start_time; @@ -1489,6 +1516,11 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* Check if we need to resume scanning */ ble_ll_scan_chk_resume(); + /* Turn off the clock if not doing anything else */ +#ifdef BLE_XCVR_RFCLK + ble_ll_sched_rfclk_chk_restart(); +#endif + /* This event is over. Set adv channel to first one */ advsm->adv_chan = ble_ll_adv_first_chan(advsm); @@ -1511,8 +1543,12 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) * The scheduled time better be in the future! If it is not, we will * just keep advancing until we the time is in the future */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; +#else start_time = advsm->adv_pdu_start_time - os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); +#endif delta_t = (int32_t)(start_time - os_cputime_get32()); if (delta_t < 0) { @@ -1543,9 +1579,13 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) * We will transmit right away. Set next pdu start time to now * plus a xcvr start delay just so we dont count late adv starts */ - advsm->adv_pdu_start_time = os_cputime_get32() + + advsm->adv_pdu_start_time = os_cputime_get32(); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + advsm->adv_pdu_start_time += g_ble_ll_sched_offset_ticks; +#else + advsm->adv_pdu_start_time += os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); - +#endif resched_pdu = 1; } @@ -1571,7 +1611,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) #endif /* Schedule advertising transmit */ - ble_ll_adv_set_sched(advsm, 0); + ble_ll_adv_set_sched(advsm); /* * In the unlikely event we cant reschedule this, just post a done @@ -1580,9 +1620,15 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) if (resched_pdu) { rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch); } else { + /* Reschedule advertising event */ rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time, max_delay_ticks); if (!rc) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + start_time += g_ble_ll_sched_offset_ticks; +#else + start_time += os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); +#endif advsm->adv_event_start_time = start_time; advsm->adv_pdu_start_time = start_time; } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/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 1d2714a..d7f926e 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -95,15 +95,26 @@ extern void bletest_completed_pkt(uint16_t handle); * response. Well, it should. If this packet will overrun the next scheduled * event, what should we do? Transmit anyway? Not transmit? For now, we just * transmit. + * + * 32kHz crystal + * 1) When scheduling, I need to make sure I have time between + * this one and the next. Should I deal with this in the sched. Or + * is this basically accounted for given a slot? I really just need to + * make sure everything is over N ticks before the next sched start! + * Just add to end time? + * + * 2) I think one way to handle the problem of losing up to a microsecond + * every time we call ble_ll_conn_next_event in a loop is to do everything by + * keeping track of last anchor point. Would need last anchor usecs too. I guess + * we could also keep last anchor usecs as a uint32 or something and when we + * do the next event keep track of the residual using a different ticks to + * usecs calculation. Not sure. */ /* * XXX: How should we deal with a late connection event? We need to determine * what we want to do under the following cases: * 1) The current connection event has not ended but a schedule item starts - * 2) The connection event start cb is called but we are later than we - * expected. What to do? If we cant transmit at correct point in slot we - * are hosed. Well, anchor point can get really messed up! */ /* @@ -218,6 +229,25 @@ STATS_NAME_END(ble_ll_conn_stats) static void ble_ll_conn_event_end(struct os_event *ev); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 +static void +ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) +{ + uint32_t ticks; + uint32_t usecs; + + /* + * Precalculate the number of ticks and remaining microseconds for + * the connection interval + */ + 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)); +} +#endif + /** * Get the event buffer allocated to send the connection complete event * when we are initiating. @@ -402,7 +432,6 @@ ble_ll_conn_calc_window_widening(struct ble_ll_conn_sm *connsm) window_widening = (total_sca_ppm * delta_msec) / 1000; } - /* XXX: spec gives 16 usecs error btw. Probably should add that in */ return window_widening; } @@ -689,7 +718,10 @@ ble_ll_conn_continue_rx_encrypt(void *arg) * the current connection event. The current connection event must end before * the next scheduled item. However, the current connection itself is not * in the scheduler list! Thus, we need to calculate the time at which the - * next connection will start and not overrun it. + * next connection will start (the schedule start time; not the anchor point) + * and not overrun it. + * + * Context: Interrupt * * @param connsm * @@ -698,13 +730,25 @@ ble_ll_conn_continue_rx_encrypt(void *arg) static uint32_t ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 uint32_t itvl; +#endif uint32_t ce_end; uint32_t next_sched_time; /* Calculate time at which next connection event will start */ - itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* NOTE: We dont care if this time is tick short. */ + ce_end = connsm->anchor_point + connsm->conn_itvl_ticks - + g_ble_ll_sched_offset_ticks; + if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) { + ++ce_end; + } +#else + itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS) - + XCVR_TX_SCHED_DELAY_USECS; ce_end = connsm->anchor_point + os_cputime_usecs_to_ticks(itvl); +#endif if (ble_ll_sched_next_time(&next_sched_time)) { if (CPUTIME_LT(next_sched_time, ce_end)) { @@ -1121,8 +1165,10 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) { int rc; uint32_t usecs; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 uint32_t wfr_time; - uint32_t txstart; +#endif + uint32_t start; struct ble_ll_conn_sm *connsm; /* XXX: note that we can extend end time here if we want. Look at this */ @@ -1151,9 +1197,15 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) #endif if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* Set start time of transmission */ + start = sch->start_time + g_ble_ll_sched_offset_ticks; + rc = ble_phy_tx_set_start_time(start, sch->remainder); +#else /* Set start time of transmission */ - txstart = sch->start_time + os_cputime_usecs_to_ticks(XCVR_PROC_DELAY_USECS); - rc = ble_phy_tx_set_start_time(txstart); + start = sch->start_time + os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS); + rc = ble_phy_tx_set_start_time(start); +#endif if (!rc) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (CONN_F_ENCRYPTED(connsm)) { @@ -1187,11 +1239,13 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) ble_phy_encrypt_disable(); } #endif - /* - * XXX: make sure I dont care that I get here early to start receiving. - * I could use events compare and all that shit to start rx. - */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* XXX: what is this really for the slave? */ + start = sch->start_time + g_ble_ll_sched_offset_ticks; + rc = ble_phy_rx_set_start_time(start, sch->remainder); +#else rc = ble_phy_rx(); +#endif if (rc) { /* End the connection event as we have no more buffers */ STATS_INC(ble_ll_conn_stats, slave_ce_failures); @@ -1207,15 +1261,35 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) * Set the wait for response time. The anchor point is when we * expect the master to start transmitting. Worst-case, we expect * to hear a reply within the anchor point plus: - * -> the current tx window size - * -> The current window widening amount + * -> current tx window size + * -> current window widening amount (includes +/- 16 usec jitter) * -> Amount of time it takes to detect packet start. + * -> Some extra time (16 usec) to insure timing is OK + */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* + * For the 32 kHz crystal, the amount of usecs we have to wait + * is not from the anchor point; we have to account for the time + * from when the receiver is enabled until the anchor point. The + * time we start before the anchor point is this: + * -> current window widening. + * -> up to one 32 kHz tick since we discard remainder. + * -> Up to one tick since the usecs to ticks calc can be off + * by up to one tick. + * NOTES: + * 1) the 61 we add is for the two ticks mentioned above. + * 2) The address rx time and jitter is accounted for in the + * phy function */ + usecs = connsm->slave_cur_tx_win_usecs + 61 + + (2 * connsm->slave_cur_window_widening); + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, usecs); +#else usecs = connsm->slave_cur_tx_win_usecs + BLE_LL_WFR_USECS + connsm->slave_cur_window_widening; wfr_time = connsm->anchor_point + os_cputime_usecs_to_ticks(usecs); ble_ll_wfr_enable(wfr_time); - +#endif /* Set next wakeup time to connection event end time */ rc = BLE_LL_SCHED_STATE_RUNNING; } @@ -1246,15 +1320,20 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) * @return int 0: not allowed to send 1: allowed to send */ static int -ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime) +ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, + uint32_t add_usecs) { int rc; uint8_t rem_bytes; uint32_t ticks; + uint32_t usecs; uint32_t next_sched_time; struct os_mbuf *txpdu; struct os_mbuf_pkthdr *pkthdr; struct ble_mbuf_hdr *txhdr; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + uint32_t allowed_usecs; +#endif rc = 1; if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { @@ -1277,16 +1356,25 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime) if (rem_bytes > connsm->eff_max_tx_octets) { rem_bytes = connsm->eff_max_tx_octets; } - ticks = BLE_TX_DUR_USECS_M(rem_bytes); + usecs = BLE_TX_DUR_USECS_M(rem_bytes); } else { /* We will send empty pdu (just a LL header) */ - ticks = BLE_TX_DUR_USECS_M(0); + usecs = BLE_TX_DUR_USECS_M(0); } - ticks += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time; - ticks = os_cputime_usecs_to_ticks(ticks); + usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time; + +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + ticks = (uint32_t)(next_sched_time - begtime); + allowed_usecs = os_cputime_ticks_to_usecs(ticks); + if ((usecs + add_usecs) >= allowed_usecs) { + rc = 0; + } +#else + ticks = os_cputime_usecs_to_ticks(usecs); if ((begtime + ticks) >= next_sched_time) { rc = 0; } +#endif } return rc; @@ -1347,7 +1435,15 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, connsm->conn_role = BLE_LL_CONN_ROLE_MASTER; /* Set default ce parameters */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* + * XXX: for now, we need twice the transmit window as our calculations + * for the transmit window offset could be off. + */ + connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1; +#else connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN; +#endif connsm->tx_win_off = 0; connsm->master_sca = MYNEWT_VAL(BLE_LL_MASTER_SCA); @@ -1482,6 +1578,10 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm); #endif +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + ble_ll_conn_calc_itvl_ticks(connsm); +#endif + /* Add to list of active connections */ SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); } @@ -1629,6 +1729,11 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) uint32_t cur_ww; uint32_t max_ww; struct ble_ll_conn_upd_req *upd; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + uint32_t ticks; + uint32_t usecs; +#endif + /* XXX: deal with connection request procedure here as well */ ble_ll_conn_chk_csm_flags(connsm); @@ -1647,7 +1752,24 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->event_cntr += latency; /* Set next connection event start time */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* We can use pre-calculated values for one interval if latency is 1. */ + if (latency == 1) { + connsm->anchor_point += connsm->conn_itvl_ticks; + connsm->anchor_point_usecs += connsm->conn_itvl_usecs; + } else { + uint32_t ticks; + ticks = os_cputime_usecs_to_ticks(itvl); + connsm->anchor_point += ticks; + connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); + } + if (connsm->anchor_point_usecs >= 31) { + ++connsm->anchor_point; + connsm->anchor_point_usecs -= 31; + } +#else connsm->anchor_point += os_cputime_usecs_to_ticks(itvl); +#endif /* * If a connection update has been scheduled and the event counter @@ -1669,15 +1791,30 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->csmflags.cfbit.host_expects_upd_event = 1; } - connsm->conn_itvl = upd->interval; connsm->supervision_tmo = upd->timeout; connsm->slave_latency = upd->latency; connsm->tx_win_size = upd->winsize; connsm->slave_cur_tx_win_usecs = connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; connsm->tx_win_off = upd->winoffset; + connsm->conn_itvl = upd->interval; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + ble_ll_conn_calc_itvl_ticks(connsm); + if (upd->winoffset != 0) { + usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS; + ticks = os_cputime_usecs_to_ticks(usecs); + connsm->anchor_point += ticks; + usecs = usecs - os_cputime_ticks_to_usecs(ticks); + connsm->anchor_point_usecs += usecs; + if (connsm->anchor_point_usecs >= 31) { + ++connsm->anchor_point; + connsm->anchor_point_usecs -= 31; + } + } +#else connsm->anchor_point += os_cputime_usecs_to_ticks(upd->winoffset * BLE_LL_CONN_ITVL_USECS); +#endif /* Reset the starting point of the connection supervision timeout */ connsm->last_rxd_pdu_cputime = connsm->anchor_point; @@ -1736,20 +1873,35 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * Calculate ce end time. For a slave, we need to add window widening and * the transmit window if we still have one. */ - itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { cur_ww = ble_ll_conn_calc_window_widening(connsm); max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS; if (cur_ww >= max_ww) { return -1; } + cur_ww += BLE_LL_JITTER_USECS; connsm->slave_cur_window_widening = cur_ww; + itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs); + } + itvl -= g_ble_ll_sched_offset_ticks; + connsm->ce_end_time = connsm->anchor_point + itvl; +#else + itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT; + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + cur_ww = ble_ll_conn_calc_window_widening(connsm); + max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS; + if (cur_ww >= max_ww) { + return -1; + } + connsm->slave_cur_window_widening = cur_ww + BLE_LL_JITTER_USECS; itvl += cur_ww + connsm->slave_cur_tx_win_usecs; } else { - /* We adjust end time for connection to end of time slot */ itvl -= XCVR_TX_SCHED_DELAY_USECS; } connsm->ce_end_time = connsm->anchor_point + os_cputime_usecs_to_ticks(itvl); +#endif return 0; } @@ -1799,9 +1951,38 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) */ rc = 1; if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* + * With a 32.768 kHz crystal we dont care about the remaining usecs + * when setting last anchor point. The only thing last anchor is used + * for is to calculate window widening. The effect of this is + * negligible. + */ + connsm->last_anchor_point = rxhdr->beg_cputime; + + usecs = rxhdr->rem_usecs + 1250 + + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + + BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN); + + /* Anchor point is cputime. */ + endtime = os_cputime_usecs_to_ticks(usecs); + connsm->anchor_point = rxhdr->beg_cputime + endtime; + connsm->anchor_point_usecs = usecs - os_cputime_ticks_to_usecs(endtime); + if (connsm->anchor_point_usecs == 31) { + ++connsm->anchor_point; + connsm->anchor_point_usecs = 0; + } + + connsm->slave_cur_tx_win_usecs = + connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; + + connsm->ce_end_time = connsm->anchor_point + + (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT) + + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; +#else + connsm->last_anchor_point = rxhdr->beg_cputime; endtime = rxhdr->beg_cputime + os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(BLE_CONNECT_REQ_LEN)); - connsm->last_anchor_point = endtime; connsm->slave_cur_tx_win_usecs = connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; usecs = 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS); @@ -1810,7 +1991,8 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_USECS_PER_SLOT); connsm->ce_end_time = connsm->anchor_point + os_cputime_usecs_to_ticks(usecs); - connsm->slave_cur_window_widening = 0; +#endif + connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS; /* Start the scheduler for the first connection event */ while (ble_ll_sched_slave_new(connsm)) { @@ -1870,6 +2052,10 @@ ble_ll_conn_event_end(struct os_event *ev) /* Check if we need to resume scanning */ ble_ll_scan_chk_resume(); +#ifdef BLE_XCVR_RFCLK + ble_ll_sched_rfclk_chk_restart(); +#endif + /* If we have transmitted the terminate IND successfully, we are done */ if ((connsm->csmflags.cfbit.terminate_ind_txd) || (connsm->csmflags.cfbit.terminate_ind_rxd)) { @@ -1958,6 +2144,7 @@ ble_ll_conn_event_end(struct os_event *ev) } else { tmo = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000UL; } + /* XXX: Convert to ticks to usecs calculation instead??? */ tmo = os_cputime_usecs_to_ticks(tmo); if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) { ble_ll_conn_end(connsm, BLE_ERR_CONN_SPVN_TMO); @@ -2251,7 +2438,6 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, uint8_t *init_addr = NULL; uint8_t pyld_len; uint8_t inita_is_rpa; - uint32_t endtime; struct os_mbuf *rxpdu; struct ble_ll_conn_sm *connsm; @@ -2366,10 +2552,7 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, } /* Attempt to schedule new connection. Possible that this might fail */ - endtime = ble_hdr->beg_cputime + - os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(pyld_len)); - if (!ble_ll_sched_master_new(connsm, endtime, - MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS))) { + if (!ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) { /* Setup to transmit the connect request */ rc = ble_ll_conn_request_send(addr_type, adv_addr, connsm->tx_win_off, index); @@ -2392,8 +2575,6 @@ init_rx_isr_exit: */ rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN); if (rxpdu == NULL) { - ble_phy_disable(); - /* * XXX: possible allocate the PDU when we start initiating? * I cannot say I like this solution, but if we cannot allocate a PDU @@ -2405,8 +2586,7 @@ init_rx_isr_exit: CONN_F_CONN_REQ_TXD(connsm) = 0; ble_ll_sched_rmv_elem(&connsm->conn_sch); } - - ble_phy_rx(); + ble_phy_restart_rx(); rc = 0; } else { ble_phy_rxpdu_copy(rxbuf, rxpdu); @@ -2498,6 +2678,9 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) connsm->csmflags.cfbit.slave_set_last_anchor = 0; connsm->last_anchor_point = rxhdr->beg_cputime; connsm->anchor_point = connsm->last_anchor_point; +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + connsm->anchor_point_usecs = rxhdr->rem_usecs; +#endif } } return 1; @@ -2659,6 +2842,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) uint8_t opcode = 0; uint8_t rx_pyld_len; uint32_t endtime; + uint32_t add_usecs; struct os_mbuf *txpdu; struct ble_ll_conn_sm *connsm; struct os_mbuf *rxpdu; @@ -2689,8 +2873,14 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } /* Calculate the end time of the received PDU */ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + endtime = rxhdr->beg_cputime; + add_usecs = rxhdr->rem_usecs + BLE_TX_DUR_USECS_M(rx_pyld_len); +#else endtime = rxhdr->beg_cputime + os_cputime_usecs_to_ticks(BLE_TX_DUR_USECS_M(rx_pyld_len)); + add_usecs = 0; +#endif /* * Check the packet CRC. A connection event can continue even if the @@ -2861,7 +3051,7 @@ chk_rx_terminate_ind: if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) { rx_pyld_len += BLE_LL_DATA_MIC_LEN; } - if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime)) { + if (reply && ble_ll_conn_can_send_next_pdu(connsm, endtime, add_usecs)) { rc = ble_ll_conn_tx_data_pdu(connsm); } @@ -3045,7 +3235,6 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, uint8_t *chanmap) * Context: Link Layer * * @param rxbuf Pointer to received Connect Request PDU - * @param conn_req_end receive end time of connect request * * @return 0: connection not started; 1 connecton started */ @@ -3269,3 +3458,5 @@ ble_ll_conn_module_init(void) /* Call reset to finish reset of initialization */ ble_ll_conn_module_reset(); } + + http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/src/ble_ll_conn_priv.h ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h b/net/nimble/controller/src/ble_ll_conn_priv.h index 0913892..02cac60 100644 --- a/net/nimble/controller/src/ble_ll_conn_priv.h +++ b/net/nimble/controller/src/ble_ll_conn_priv.h @@ -42,12 +42,13 @@ extern "C" { #define BLE_LL_CONN_INITIAL_OFFSET (1250) #define BLE_LL_CONN_ITVL_USECS (1250) #define BLE_LL_CONN_TX_WIN_USECS (1250) +#define BLE_LL_CONN_TX_OFF_USECS (1250) #define BLE_LL_CONN_CE_USECS (625) #define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */ #define BLE_LL_CONN_SLAVE_LATENCY_MAX (499) /* Connection request duration (in usecs) */ -#define BLE_LL_CONN_REQ_DURATION (352) +#define BLE_LL_CONN_REQ_DURATION (352) /* 1 Mbps only */ /* Connection handle range */ #define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/507f493a/net/nimble/controller/src/ble_ll_scan.c ---------------------------------------------------------------------- diff --git a/net/nimble/controller/src/ble_ll_scan.c b/net/nimble/controller/src/ble_ll_scan.c index f732753..f5eca7f 100644 --- a/net/nimble/controller/src/ble_ll_scan.c +++ b/net/nimble/controller/src/ble_ll_scan.c @@ -37,6 +37,7 @@ #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" +#include "controller/ble_ll_xcvr.h" #include "hal/hal_gpio.h" /* @@ -588,8 +589,14 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan) } #endif - /* Start receiving */ - rc = ble_phy_rx(); +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 + /* XXX: probably need to make sure hfxo is running too */ + /* XXX: can make this better; want to just start asap. */ + rc = ble_phy_rx_set_start_time(os_cputime_get32() + + g_ble_ll_sched_offset_ticks, 0); +#else + rc = ble_phy_rx(); +#endif if (!rc) { /* Enable/disable whitelisting */ if (scansm->scan_filt_policy & 1) { @@ -612,6 +619,37 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, uint8_t chan) } } +#ifdef BLE_XCVR_RFCLK +static void +ble_ll_scan_rfclk_chk_stop(void) +{ + int stop; + int32_t time_till_next; + os_sr_t sr; + uint32_t next_time; + + stop = 0; + OS_ENTER_CRITICAL(sr); + if (ble_ll_sched_next_time(&next_time)) { + /* + * If the time until the next event is too close, dont bother to turn + * off the clock + */ + time_till_next = (int32_t)(next_time - os_cputime_get32()); + if (time_till_next > g_ble_ll_data.ll_xtal_ticks) { + stop = 1; + } + } else { + stop = 1; + } + if (stop) { + ble_ll_log(BLE_LL_LOG_ID_RFCLK_SCAN_DIS, g_ble_ll_data.ll_rfclk_state,0,0); + ble_ll_xcvr_rfclk_disable(); + } + OS_EXIT_CRITICAL(sr); +} +#endif + /** * Called to determine if we are inside or outside the scan window. If we * are inside the scan window it means that the device should be receiving @@ -629,6 +667,7 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime) int rc; uint8_t chan; uint32_t itvl; + uint32_t dt; uint32_t win_start; itvl = os_cputime_usecs_to_ticks(scansm->scan_itvl * BLE_HCI_SCAN_ITVL); @@ -645,7 +684,13 @@ ble_ll_scan_window_chk(struct ble_ll_scan_sm *scansm, uint32_t cputime) rc = 0; if (scansm->scan_window != scansm->scan_itvl) { itvl = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL); - if ((cputime - win_start) >= itvl) { + dt = cputime - win_start; + if (dt >= itvl) { +#ifdef BLE_XCVR_RFCLK + if (dt < (scansm->scan_itvl - g_ble_ll_data.ll_xtal_ticks)) { + ble_ll_scan_rfclk_chk_stop(); + } +#endif rc = 1; } } @@ -688,6 +733,11 @@ ble_ll_scan_sm_stop(int chk_disable) /* Set LL state to standby */ ble_ll_state_set(BLE_LL_STATE_STANDBY); + + /* May need to stop the rfclk */ +#ifdef BLE_XCVR_RFCLK + ble_ll_scan_rfclk_chk_stop(); +#endif } OS_EXIT_CRITICAL(sr); } @@ -757,6 +807,9 @@ ble_ll_scan_event_proc(struct os_event *ev) uint32_t win_start; uint32_t scan_itvl; uint32_t next_event_time; +#ifdef BLE_XCVR_RFCLK + uint32_t xtal_ticks; +#endif struct ble_ll_scan_sm *scansm; /* @@ -786,12 +839,19 @@ ble_ll_scan_event_proc(struct os_event *ev) dt = now - win_start; scansm->scan_chan = chan; scansm->scan_win_start_time = win_start; + if (scansm->scan_window != scansm->scan_itvl) { + win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL); + } else { + win = 0; + } /* Determine on/off state based on scan window */ rxstate = 1; next_event_time = win_start + scan_itvl; - if (scansm->scan_window != scansm->scan_itvl) { - win = os_cputime_usecs_to_ticks(scansm->scan_window * BLE_HCI_SCAN_ITVL); + + OS_ENTER_CRITICAL(sr); + + if (win != 0) { if (dt >= win) { rxstate = 0; } else { @@ -799,7 +859,6 @@ ble_ll_scan_event_proc(struct os_event *ev) } } - OS_ENTER_CRITICAL(sr); /* * If we are not in the standby state it means that the scheduled * scanning event was overlapped in the schedule. In this case all we do @@ -815,6 +874,9 @@ ble_ll_scan_event_proc(struct os_event *ev) case BLE_LL_STATE_SCANNING: /* Must disable PHY since we will move to a new channel */ ble_phy_disable(); + if (!rxstate) { + ble_ll_state_set(BLE_LL_STATE_STANDBY); + } break; case BLE_LL_STATE_STANDBY: break; @@ -822,11 +884,70 @@ ble_ll_scan_event_proc(struct os_event *ev) assert(0); break; } + +#ifdef BLE_XCVR_RFCLK + if (rxstate == 0) { + /* + * We need to wake up before we need to start scanning in order + * to make sure the rfclock is on. If we are close to being on, + * enable the rfclock. If not, set wakeup time. + */ + if (dt >= (scan_itvl - g_ble_ll_data.ll_xtal_ticks)) { + /* Start the clock if necessary */ + if (start_scan) { + if (ble_ll_xcvr_rfclk_state() == BLE_RFCLK_STATE_OFF) { + ble_ll_xcvr_rfclk_start_now(now); + next_event_time = now + g_ble_ll_data.ll_xtal_ticks; + } + } + } else { + next_event_time -= g_ble_ll_data.ll_xtal_ticks; + if (start_scan) { + ble_ll_scan_rfclk_chk_stop(); + } + } + } +#endif + if (start_scan && rxstate) { +#ifdef BLE_XCVR_RFCLK + /* NOTE: reuse rxstate */ + rxstate = ble_ll_xcvr_rfclk_state(); + if (rxstate != BLE_RFCLK_STATE_SETTLED) { + if (rxstate == BLE_RFCLK_STATE_OFF) { + xtal_ticks = g_ble_ll_data.ll_xtal_ticks; + } else { + xtal_ticks = ble_ll_xcvr_rfclk_time_till_settled(); + } + + /* + * Only bother if we have enough time to receive anything + * here. The next event time will turn off the clock. + */ + if (win != 0) { + if ((win - dt) <= xtal_ticks) { + goto rfclk_not_settled; + } + } + + /* + * If clock off, start clock. Set next event time to now plus + * the clock setting time. + */ + if (rxstate == BLE_RFCLK_STATE_OFF) { + ble_ll_xcvr_rfclk_start_now(now); + } + next_event_time = now + xtal_ticks; + goto rfclk_not_settled; + } +#endif ble_ll_scan_start(scansm, scansm->scan_chan); } - OS_EXIT_CRITICAL(sr); +#ifdef BLE_XCVR_RFCLK +rfclk_not_settled: +#endif + OS_EXIT_CRITICAL(sr); os_cputime_timer_start(&scansm->scan_timer, next_event_time); } @@ -929,8 +1050,7 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if (scansm->scan_rsp_pending) { ble_ll_scan_req_backoff(scansm, 0); } - ble_phy_disable(); - ble_phy_rx(); + ble_phy_restart_rx(); return 0; } @@ -1081,8 +1201,6 @@ ble_ll_scan_wfr_timer_exp(void) { struct ble_ll_scan_sm *scansm; - ble_phy_disable(); - /* * If we timed out waiting for a response, the scan response pending * flag should be set. Deal with scan backoff. Put device back into rx. @@ -1091,7 +1209,8 @@ ble_ll_scan_wfr_timer_exp(void) if (scansm->scan_rsp_pending) { ble_ll_scan_req_backoff(scansm, 0); } - ble_phy_rx(); + + ble_phy_restart_rx(); } /** @@ -1480,7 +1599,7 @@ ble_ll_scan_init(void) scansm->scan_itvl = BLE_HCI_SCAN_ITVL_DEF; scansm->scan_window = BLE_HCI_SCAN_WINDOW_DEF; - /* Initialize connection supervision timer */ + /* Initialize scanning timer */ os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm); /* Get a scan request mbuf (packet header) and attach to state machine */