1*042d53a7SEvalZero /*
2*042d53a7SEvalZero * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero * or more contributor license agreements. See the NOTICE file
4*042d53a7SEvalZero * distributed with this work for additional information
5*042d53a7SEvalZero * regarding copyright ownership. The ASF licenses this file
6*042d53a7SEvalZero * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero * with the License. You may obtain a copy of the License at
9*042d53a7SEvalZero *
10*042d53a7SEvalZero * http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero *
12*042d53a7SEvalZero * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero * software distributed under the License is distributed on an
14*042d53a7SEvalZero * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero * KIND, either express or implied. See the License for the
16*042d53a7SEvalZero * specific language governing permissions and limitations
17*042d53a7SEvalZero * under the License.
18*042d53a7SEvalZero */
19*042d53a7SEvalZero
20*042d53a7SEvalZero #include <stdint.h>
21*042d53a7SEvalZero #include <string.h>
22*042d53a7SEvalZero #include <assert.h>
23*042d53a7SEvalZero #include "syscfg/syscfg.h"
24*042d53a7SEvalZero #include "os/os.h"
25*042d53a7SEvalZero #include "ble/xcvr.h"
26*042d53a7SEvalZero #include "nimble/ble.h"
27*042d53a7SEvalZero #include "nimble/nimble_opt.h"
28*042d53a7SEvalZero #include "nimble/nimble_npl.h"
29*042d53a7SEvalZero #include "controller/ble_phy.h"
30*042d53a7SEvalZero #include "controller/ble_phy_trace.h"
31*042d53a7SEvalZero #include "controller/ble_ll.h"
32*042d53a7SEvalZero #include "nrfx.h"
33*042d53a7SEvalZero #if MYNEWT
34*042d53a7SEvalZero #include "mcu/nrf52_clock.h"
35*042d53a7SEvalZero #include "mcu/cmsis_nvic.h"
36*042d53a7SEvalZero #include "hal/hal_gpio.h"
37*042d53a7SEvalZero #else
38*042d53a7SEvalZero #include "core_cm4.h"
39*042d53a7SEvalZero #endif
40*042d53a7SEvalZero
41*042d53a7SEvalZero /*
42*042d53a7SEvalZero * NOTE: This code uses a couple of PPI channels so care should be taken when
43*042d53a7SEvalZero * using PPI somewhere else.
44*042d53a7SEvalZero *
45*042d53a7SEvalZero * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31
46*042d53a7SEvalZero * Regular channels: CH4, CH5 and optionally CH17, CH18, CH19
47*042d53a7SEvalZero * - CH4 = cancel wfr timer on address match
48*042d53a7SEvalZero * - CH5 = disable radio on wfr timer expiry
49*042d53a7SEvalZero * - CH17 = (optional) gpio debug for radio ramp-up
50*042d53a7SEvalZero * - CH18 = (optional) gpio debug for wfr timer RX enabled
51*042d53a7SEvalZero * - CH19 = (optional) gpio debug for wfr timer radio disabled
52*042d53a7SEvalZero *
53*042d53a7SEvalZero */
54*042d53a7SEvalZero
55*042d53a7SEvalZero /* XXX: 4) Make sure RF is higher priority interrupt than schedule */
56*042d53a7SEvalZero
57*042d53a7SEvalZero /*
58*042d53a7SEvalZero * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
59*042d53a7SEvalZero * and 16ms for a 30ppm crystal! We need to limit PDU size based on
60*042d53a7SEvalZero * crystal accuracy. Look at this in the spec.
61*042d53a7SEvalZero */
62*042d53a7SEvalZero
63*042d53a7SEvalZero /* XXX: private header file? */
64*042d53a7SEvalZero extern uint8_t g_nrf_num_irks;
65*042d53a7SEvalZero extern uint32_t g_nrf_irk_list[];
66*042d53a7SEvalZero
67*042d53a7SEvalZero /* To disable all radio interrupts */
68*042d53a7SEvalZero #define NRF_RADIO_IRQ_MASK_ALL (0x34FF)
69*042d53a7SEvalZero
70*042d53a7SEvalZero /*
71*042d53a7SEvalZero * We configure the nrf with a 1 byte S0 field, 8 bit length field, and
72*042d53a7SEvalZero * zero bit S1 field. The preamble is 8 bits long.
73*042d53a7SEvalZero */
74*042d53a7SEvalZero #define NRF_LFLEN_BITS (8)
75*042d53a7SEvalZero #define NRF_S0LEN (1)
76*042d53a7SEvalZero #define NRF_S1LEN_BITS (0)
77*042d53a7SEvalZero #define NRF_CILEN_BITS (2)
78*042d53a7SEvalZero #define NRF_TERMLEN_BITS (3)
79*042d53a7SEvalZero
80*042d53a7SEvalZero /* Maximum length of frames */
81*042d53a7SEvalZero #define NRF_MAXLEN (255)
82*042d53a7SEvalZero #define NRF_BALEN (3) /* For base address of 3 bytes */
83*042d53a7SEvalZero
84*042d53a7SEvalZero /* Maximum tx power */
85*042d53a7SEvalZero #define NRF_TX_PWR_MAX_DBM (4)
86*042d53a7SEvalZero #define NRF_TX_PWR_MIN_DBM (-40)
87*042d53a7SEvalZero
88*042d53a7SEvalZero /* NRF_RADIO->PCNF0 configuration values */
89*042d53a7SEvalZero #define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \
90*042d53a7SEvalZero (RADIO_PCNF0_S1INCL_Msk) | \
91*042d53a7SEvalZero (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \
92*042d53a7SEvalZero (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos)
93*042d53a7SEvalZero #define NRF_PCNF0_1M (NRF_PCNF0) | \
94*042d53a7SEvalZero (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos)
95*042d53a7SEvalZero #define NRF_PCNF0_2M (NRF_PCNF0) | \
96*042d53a7SEvalZero (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos)
97*042d53a7SEvalZero #define NRF_PCNF0_CODED (NRF_PCNF0) | \
98*042d53a7SEvalZero (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \
99*042d53a7SEvalZero (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \
100*042d53a7SEvalZero (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos)
101*042d53a7SEvalZero
102*042d53a7SEvalZero /* BLE PHY data structure */
103*042d53a7SEvalZero struct ble_phy_obj
104*042d53a7SEvalZero {
105*042d53a7SEvalZero uint8_t phy_stats_initialized;
106*042d53a7SEvalZero int8_t phy_txpwr_dbm;
107*042d53a7SEvalZero uint8_t phy_chan;
108*042d53a7SEvalZero uint8_t phy_state;
109*042d53a7SEvalZero uint8_t phy_transition;
110*042d53a7SEvalZero uint8_t phy_transition_late;
111*042d53a7SEvalZero uint8_t phy_rx_started;
112*042d53a7SEvalZero uint8_t phy_encrypted;
113*042d53a7SEvalZero uint8_t phy_privacy;
114*042d53a7SEvalZero uint8_t phy_tx_pyld_len;
115*042d53a7SEvalZero uint8_t phy_txtorx_phy_mode;
116*042d53a7SEvalZero uint8_t phy_cur_phy_mode;
117*042d53a7SEvalZero uint8_t phy_bcc_offset;
118*042d53a7SEvalZero uint32_t phy_aar_scratch;
119*042d53a7SEvalZero uint32_t phy_access_address;
120*042d53a7SEvalZero struct ble_mbuf_hdr rxhdr;
121*042d53a7SEvalZero void *txend_arg;
122*042d53a7SEvalZero ble_phy_tx_end_func txend_cb;
123*042d53a7SEvalZero uint32_t phy_start_cputime;
124*042d53a7SEvalZero };
125*042d53a7SEvalZero struct ble_phy_obj g_ble_phy_data;
126*042d53a7SEvalZero
127*042d53a7SEvalZero /* XXX: if 27 byte packets desired we can make this smaller */
128*042d53a7SEvalZero /* Global transmit/receive buffer */
129*042d53a7SEvalZero static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
130*042d53a7SEvalZero static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
131*042d53a7SEvalZero
132*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
133*042d53a7SEvalZero /* Make sure word-aligned for faster copies */
134*042d53a7SEvalZero static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
135*042d53a7SEvalZero #endif
136*042d53a7SEvalZero
137*042d53a7SEvalZero /* RF center frequency for each channel index (offset from 2400 MHz) */
138*042d53a7SEvalZero static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = {
139*042d53a7SEvalZero 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */
140*042d53a7SEvalZero 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */
141*042d53a7SEvalZero 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */
142*042d53a7SEvalZero 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */
143*042d53a7SEvalZero };
144*042d53a7SEvalZero
145*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
146*042d53a7SEvalZero /* packet start offsets (in usecs) */
147*042d53a7SEvalZero static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { 376, 40, 24, 376 };
148*042d53a7SEvalZero #endif
149*042d53a7SEvalZero
150*042d53a7SEvalZero /* Various radio timings */
151*042d53a7SEvalZero /* Radio ramp-up times in usecs (fast mode) */
152*042d53a7SEvalZero #define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS)
153*042d53a7SEvalZero #define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS)
154*042d53a7SEvalZero /* delay between EVENTS_READY and start of tx */
155*042d53a7SEvalZero static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { 5, 4, 3, 5 };
156*042d53a7SEvalZero /* delay between EVENTS_END and end of txd packet */
157*042d53a7SEvalZero static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { 9, 4, 3, 3 };
158*042d53a7SEvalZero /* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */
159*042d53a7SEvalZero static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { 17, 6, 2, 17 };
160*042d53a7SEvalZero /* delay between end of rxd packet and EVENTS_END */
161*042d53a7SEvalZero static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { 27, 6, 2, 22 };
162*042d53a7SEvalZero
163*042d53a7SEvalZero /* Statistics */
164*042d53a7SEvalZero STATS_SECT_START(ble_phy_stats)
165*042d53a7SEvalZero STATS_SECT_ENTRY(phy_isrs)
166*042d53a7SEvalZero STATS_SECT_ENTRY(tx_good)
167*042d53a7SEvalZero STATS_SECT_ENTRY(tx_fail)
168*042d53a7SEvalZero STATS_SECT_ENTRY(tx_late)
169*042d53a7SEvalZero STATS_SECT_ENTRY(tx_bytes)
170*042d53a7SEvalZero STATS_SECT_ENTRY(rx_starts)
171*042d53a7SEvalZero STATS_SECT_ENTRY(rx_aborts)
172*042d53a7SEvalZero STATS_SECT_ENTRY(rx_valid)
173*042d53a7SEvalZero STATS_SECT_ENTRY(rx_crc_err)
174*042d53a7SEvalZero STATS_SECT_ENTRY(rx_late)
175*042d53a7SEvalZero STATS_SECT_ENTRY(radio_state_errs)
176*042d53a7SEvalZero STATS_SECT_ENTRY(rx_hw_err)
177*042d53a7SEvalZero STATS_SECT_ENTRY(tx_hw_err)
178*042d53a7SEvalZero STATS_SECT_END
179*042d53a7SEvalZero STATS_SECT_DECL(ble_phy_stats) ble_phy_stats;
180*042d53a7SEvalZero
181*042d53a7SEvalZero STATS_NAME_START(ble_phy_stats)
182*042d53a7SEvalZero STATS_NAME(ble_phy_stats, phy_isrs)
183*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_good)
184*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_fail)
185*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_late)
186*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_bytes)
187*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_starts)
188*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_aborts)
189*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_valid)
190*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_crc_err)
191*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_late)
192*042d53a7SEvalZero STATS_NAME(ble_phy_stats, radio_state_errs)
193*042d53a7SEvalZero STATS_NAME(ble_phy_stats, rx_hw_err)
194*042d53a7SEvalZero STATS_NAME(ble_phy_stats, tx_hw_err)
195*042d53a7SEvalZero STATS_NAME_END(ble_phy_stats)
196*042d53a7SEvalZero
197*042d53a7SEvalZero /*
198*042d53a7SEvalZero * NOTE:
199*042d53a7SEvalZero * Tested the following to see what would happen:
200*042d53a7SEvalZero * -> NVIC has radio irq enabled (interrupt # 1, mask 0x2).
201*042d53a7SEvalZero * -> Set up nrf to receive. Clear ADDRESS event register.
202*042d53a7SEvalZero * -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET.
203*042d53a7SEvalZero * -> Enable RX.
204*042d53a7SEvalZero * -> Disable interrupts globally using OS_ENTER_CRITICAL().
205*042d53a7SEvalZero * -> Wait until a packet is received and the ADDRESS event occurs.
206*042d53a7SEvalZero * -> Call ble_phy_disable().
207*042d53a7SEvalZero *
208*042d53a7SEvalZero * At this point I wanted to see the state of the cortex NVIC. The IRQ
209*042d53a7SEvalZero * pending bit was TRUE for the radio interrupt (as expected) as we never
210*042d53a7SEvalZero * serviced the radio interrupt (interrupts were disabled).
211*042d53a7SEvalZero *
212*042d53a7SEvalZero * What was unexpected was this: without clearing the pending IRQ in the NVIC,
213*042d53a7SEvalZero * when radio interrupts were re-enabled (address event bit in INTENSET set to
214*042d53a7SEvalZero * 1) and the radio ADDRESS event register read 1 (it was never cleared after
215*042d53a7SEvalZero * the first address event), the radio did not enter the ISR! I would have
216*042d53a7SEvalZero * expected that if the following were true, an interrupt would occur:
217*042d53a7SEvalZero * -> NVIC ISER bit set to TRUE
218*042d53a7SEvalZero * -> NVIC ISPR bit reads TRUE, meaning interrupt is pending.
219*042d53a7SEvalZero * -> Radio peripheral interrupts are enabled for some event (or events).
220*042d53a7SEvalZero * -> Corresponding event register(s) in radio peripheral read 1.
221*042d53a7SEvalZero *
222*042d53a7SEvalZero * Not sure what the end result of all this is. We will clear the pending
223*042d53a7SEvalZero * bit in the NVIC just to be sure when we disable the PHY.
224*042d53a7SEvalZero */
225*042d53a7SEvalZero
226*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
227*042d53a7SEvalZero
228*042d53a7SEvalZero /*
229*042d53a7SEvalZero * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE.
230*042d53a7SEvalZero * However, when I used a smaller size it still overwrote the scratchpad. Until
231*042d53a7SEvalZero * I figure this out I am just going to allocate 67 words so we have enough
232*042d53a7SEvalZero * space for 267 bytes of scratch. I used 268 bytes since not sure if this
233*042d53a7SEvalZero * needs to be aligned and burning a byte is no big deal.
234*042d53a7SEvalZero */
235*042d53a7SEvalZero //#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4)
236*042d53a7SEvalZero #define NRF_ENC_SCRATCH_WORDS (67)
237*042d53a7SEvalZero
238*042d53a7SEvalZero uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS];
239*042d53a7SEvalZero
240*042d53a7SEvalZero struct nrf_ccm_data
241*042d53a7SEvalZero {
242*042d53a7SEvalZero uint8_t key[16];
243*042d53a7SEvalZero uint64_t pkt_counter;
244*042d53a7SEvalZero uint8_t dir_bit;
245*042d53a7SEvalZero uint8_t iv[8];
246*042d53a7SEvalZero } __attribute__((packed));
247*042d53a7SEvalZero
248*042d53a7SEvalZero struct nrf_ccm_data g_nrf_ccm_data;
249*042d53a7SEvalZero #endif
250*042d53a7SEvalZero
251*042d53a7SEvalZero #ifdef NRF52
252*042d53a7SEvalZero static void
ble_phy_apply_errata_102_106_107(void)253*042d53a7SEvalZero ble_phy_apply_errata_102_106_107(void)
254*042d53a7SEvalZero {
255*042d53a7SEvalZero /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS
256*042d53a7SEvalZero * [106] RADIO: Higher CRC error rates for some access addresses
257*042d53a7SEvalZero * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00
258*042d53a7SEvalZero */
259*042d53a7SEvalZero *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) &
260*042d53a7SEvalZero 0xfffffffe) | 0x01000000;
261*042d53a7SEvalZero }
262*042d53a7SEvalZero #endif
263*042d53a7SEvalZero
264*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
265*042d53a7SEvalZero
266*042d53a7SEvalZero /* Packet start offset (in usecs). This is the preamble plus access address.
267*042d53a7SEvalZero * For LE Coded PHY this also includes CI and TERM1. */
268*042d53a7SEvalZero uint32_t
ble_phy_mode_pdu_start_off(int phy_mode)269*042d53a7SEvalZero ble_phy_mode_pdu_start_off(int phy_mode)
270*042d53a7SEvalZero {
271*042d53a7SEvalZero return g_ble_phy_mode_pkt_start_off[phy_mode];
272*042d53a7SEvalZero }
273*042d53a7SEvalZero
274*042d53a7SEvalZero #if NRF52840_XXAA
275*042d53a7SEvalZero static inline bool
ble_phy_mode_is_coded(uint8_t phy_mode)276*042d53a7SEvalZero ble_phy_mode_is_coded(uint8_t phy_mode)
277*042d53a7SEvalZero {
278*042d53a7SEvalZero return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) ||
279*042d53a7SEvalZero (phy_mode == BLE_PHY_MODE_CODED_500KBPS);
280*042d53a7SEvalZero }
281*042d53a7SEvalZero
282*042d53a7SEvalZero static void
ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode)283*042d53a7SEvalZero ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode)
284*042d53a7SEvalZero {
285*042d53a7SEvalZero bool new_coded = ble_phy_mode_is_coded(new_phy_mode);
286*042d53a7SEvalZero bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode);
287*042d53a7SEvalZero
288*042d53a7SEvalZero /*
289*042d53a7SEvalZero * Workarounds should be applied only when switching to/from LE Coded PHY
290*042d53a7SEvalZero * so no need to apply them every time.
291*042d53a7SEvalZero *
292*042d53a7SEvalZero * nRF52840 Engineering A Errata v1.2
293*042d53a7SEvalZero * [164] RADIO: Low sensitivity in long range mode
294*042d53a7SEvalZero *
295*042d53a7SEvalZero * nRF52840 Rev 1 Errata
296*042d53a7SEvalZero * [191] RADIO: High packet error rate in BLE Long Range mode
297*042d53a7SEvalZero */
298*042d53a7SEvalZero if (new_coded == cur_coded) {
299*042d53a7SEvalZero return;
300*042d53a7SEvalZero }
301*042d53a7SEvalZero
302*042d53a7SEvalZero if (new_coded) {
303*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
304*042d53a7SEvalZero /* [164] */
305*042d53a7SEvalZero *(volatile uint32_t *)0x4000173C |= 0x80000000;
306*042d53a7SEvalZero *(volatile uint32_t *)0x4000173C =
307*042d53a7SEvalZero ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
308*042d53a7SEvalZero #endif
309*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
310*042d53a7SEvalZero /* [191] */
311*042d53a7SEvalZero *(volatile uint32_t *) 0x40001740 =
312*042d53a7SEvalZero ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) |
313*042d53a7SEvalZero 0x80000000 | (((uint32_t)(196)) << 8);
314*042d53a7SEvalZero #endif
315*042d53a7SEvalZero } else {
316*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
317*042d53a7SEvalZero /* [164] */
318*042d53a7SEvalZero *(volatile uint32_t *)0x4000173C &= ~0x80000000;
319*042d53a7SEvalZero #endif
320*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
321*042d53a7SEvalZero /* [191] */
322*042d53a7SEvalZero *(volatile uint32_t *) 0x40001740 =
323*042d53a7SEvalZero ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
324*042d53a7SEvalZero #endif
325*042d53a7SEvalZero }
326*042d53a7SEvalZero }
327*042d53a7SEvalZero #endif
328*042d53a7SEvalZero
329*042d53a7SEvalZero void
ble_phy_mode_set(uint8_t new_phy_mode,uint8_t txtorx_phy_mode)330*042d53a7SEvalZero ble_phy_mode_set(uint8_t new_phy_mode, uint8_t txtorx_phy_mode)
331*042d53a7SEvalZero {
332*042d53a7SEvalZero if (new_phy_mode == g_ble_phy_data.phy_cur_phy_mode) {
333*042d53a7SEvalZero g_ble_phy_data.phy_txtorx_phy_mode = txtorx_phy_mode;
334*042d53a7SEvalZero return;
335*042d53a7SEvalZero }
336*042d53a7SEvalZero
337*042d53a7SEvalZero #if NRF52840_XXAA
338*042d53a7SEvalZero ble_phy_apply_nrf52840_errata(new_phy_mode);
339*042d53a7SEvalZero #endif
340*042d53a7SEvalZero
341*042d53a7SEvalZero switch (new_phy_mode) {
342*042d53a7SEvalZero case BLE_PHY_MODE_1M:
343*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
344*042d53a7SEvalZero NRF_RADIO->PCNF0 = NRF_PCNF0_1M;
345*042d53a7SEvalZero break;
346*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
347*042d53a7SEvalZero case BLE_PHY_MODE_2M:
348*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit;
349*042d53a7SEvalZero NRF_RADIO->PCNF0 = NRF_PCNF0_2M;
350*042d53a7SEvalZero break;
351*042d53a7SEvalZero #endif
352*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
353*042d53a7SEvalZero case BLE_PHY_MODE_CODED_125KBPS:
354*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit;
355*042d53a7SEvalZero NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
356*042d53a7SEvalZero break;
357*042d53a7SEvalZero case BLE_PHY_MODE_CODED_500KBPS:
358*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
359*042d53a7SEvalZero NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
360*042d53a7SEvalZero break;
361*042d53a7SEvalZero #endif
362*042d53a7SEvalZero default:
363*042d53a7SEvalZero assert(0);
364*042d53a7SEvalZero }
365*042d53a7SEvalZero
366*042d53a7SEvalZero g_ble_phy_data.phy_cur_phy_mode = new_phy_mode;
367*042d53a7SEvalZero g_ble_phy_data.phy_txtorx_phy_mode = txtorx_phy_mode;
368*042d53a7SEvalZero }
369*042d53a7SEvalZero #endif
370*042d53a7SEvalZero
371*042d53a7SEvalZero int
ble_phy_get_cur_phy(void)372*042d53a7SEvalZero ble_phy_get_cur_phy(void)
373*042d53a7SEvalZero {
374*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
375*042d53a7SEvalZero switch (g_ble_phy_data.phy_cur_phy_mode) {
376*042d53a7SEvalZero case BLE_PHY_MODE_1M:
377*042d53a7SEvalZero return BLE_PHY_1M;
378*042d53a7SEvalZero case BLE_PHY_MODE_2M:
379*042d53a7SEvalZero return BLE_PHY_2M;
380*042d53a7SEvalZero case BLE_PHY_MODE_CODED_125KBPS:
381*042d53a7SEvalZero case BLE_PHY_MODE_CODED_500KBPS:
382*042d53a7SEvalZero return BLE_PHY_CODED;
383*042d53a7SEvalZero default:
384*042d53a7SEvalZero assert(0);
385*042d53a7SEvalZero return -1;
386*042d53a7SEvalZero }
387*042d53a7SEvalZero #else
388*042d53a7SEvalZero return BLE_PHY_1M;
389*042d53a7SEvalZero #endif
390*042d53a7SEvalZero }
391*042d53a7SEvalZero
392*042d53a7SEvalZero /**
393*042d53a7SEvalZero * Copies the data from the phy receive buffer into a mbuf chain.
394*042d53a7SEvalZero *
395*042d53a7SEvalZero * @param dptr Pointer to receive buffer
396*042d53a7SEvalZero * @param rxpdu Pointer to already allocated mbuf chain
397*042d53a7SEvalZero *
398*042d53a7SEvalZero * NOTE: the packet header already has the total mbuf length in it. The
399*042d53a7SEvalZero * lengths of the individual mbufs are not set prior to calling.
400*042d53a7SEvalZero *
401*042d53a7SEvalZero */
402*042d53a7SEvalZero void
ble_phy_rxpdu_copy(uint8_t * dptr,struct os_mbuf * rxpdu)403*042d53a7SEvalZero ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
404*042d53a7SEvalZero {
405*042d53a7SEvalZero uint16_t rem_bytes;
406*042d53a7SEvalZero uint16_t mb_bytes;
407*042d53a7SEvalZero uint16_t copylen;
408*042d53a7SEvalZero uint32_t *dst;
409*042d53a7SEvalZero uint32_t *src;
410*042d53a7SEvalZero struct os_mbuf *m;
411*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
412*042d53a7SEvalZero struct os_mbuf_pkthdr *pkthdr;
413*042d53a7SEvalZero
414*042d53a7SEvalZero /* Better be aligned */
415*042d53a7SEvalZero assert(((uint32_t)dptr & 3) == 0);
416*042d53a7SEvalZero
417*042d53a7SEvalZero pkthdr = OS_MBUF_PKTHDR(rxpdu);
418*042d53a7SEvalZero rem_bytes = pkthdr->omp_len;
419*042d53a7SEvalZero
420*042d53a7SEvalZero /* Fill in the mbuf pkthdr first. */
421*042d53a7SEvalZero dst = (uint32_t *)(rxpdu->om_data);
422*042d53a7SEvalZero src = (uint32_t *)dptr;
423*042d53a7SEvalZero
424*042d53a7SEvalZero mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
425*042d53a7SEvalZero copylen = min(mb_bytes, rem_bytes);
426*042d53a7SEvalZero copylen &= 0xFFFC;
427*042d53a7SEvalZero rem_bytes -= copylen;
428*042d53a7SEvalZero mb_bytes -= copylen;
429*042d53a7SEvalZero rxpdu->om_len = copylen;
430*042d53a7SEvalZero while (copylen > 0) {
431*042d53a7SEvalZero *dst = *src;
432*042d53a7SEvalZero ++dst;
433*042d53a7SEvalZero ++src;
434*042d53a7SEvalZero copylen -= 4;
435*042d53a7SEvalZero }
436*042d53a7SEvalZero
437*042d53a7SEvalZero /* Copy remaining bytes */
438*042d53a7SEvalZero m = rxpdu;
439*042d53a7SEvalZero while (rem_bytes > 0) {
440*042d53a7SEvalZero /* If there are enough bytes in the mbuf, copy them and leave */
441*042d53a7SEvalZero if (rem_bytes <= mb_bytes) {
442*042d53a7SEvalZero memcpy(m->om_data + m->om_len, src, rem_bytes);
443*042d53a7SEvalZero m->om_len += rem_bytes;
444*042d53a7SEvalZero break;
445*042d53a7SEvalZero }
446*042d53a7SEvalZero
447*042d53a7SEvalZero m = SLIST_NEXT(m, om_next);
448*042d53a7SEvalZero assert(m != NULL);
449*042d53a7SEvalZero
450*042d53a7SEvalZero mb_bytes = m->om_omp->omp_databuf_len;
451*042d53a7SEvalZero copylen = min(mb_bytes, rem_bytes);
452*042d53a7SEvalZero copylen &= 0xFFFC;
453*042d53a7SEvalZero rem_bytes -= copylen;
454*042d53a7SEvalZero mb_bytes -= copylen;
455*042d53a7SEvalZero m->om_len = copylen;
456*042d53a7SEvalZero dst = (uint32_t *)m->om_data;
457*042d53a7SEvalZero while (copylen > 0) {
458*042d53a7SEvalZero *dst = *src;
459*042d53a7SEvalZero ++dst;
460*042d53a7SEvalZero ++src;
461*042d53a7SEvalZero copylen -= 4;
462*042d53a7SEvalZero }
463*042d53a7SEvalZero }
464*042d53a7SEvalZero
465*042d53a7SEvalZero /* Copy ble header */
466*042d53a7SEvalZero ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
467*042d53a7SEvalZero memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
468*042d53a7SEvalZero }
469*042d53a7SEvalZero
470*042d53a7SEvalZero /**
471*042d53a7SEvalZero * Called when we want to wait if the radio is in either the rx or tx
472*042d53a7SEvalZero * disable states. We want to wait until that state is over before doing
473*042d53a7SEvalZero * anything to the radio
474*042d53a7SEvalZero */
475*042d53a7SEvalZero static void
nrf_wait_disabled(void)476*042d53a7SEvalZero nrf_wait_disabled(void)
477*042d53a7SEvalZero {
478*042d53a7SEvalZero uint32_t state;
479*042d53a7SEvalZero
480*042d53a7SEvalZero state = NRF_RADIO->STATE;
481*042d53a7SEvalZero if (state != RADIO_STATE_STATE_Disabled) {
482*042d53a7SEvalZero if ((state == RADIO_STATE_STATE_RxDisable) ||
483*042d53a7SEvalZero (state == RADIO_STATE_STATE_TxDisable)) {
484*042d53a7SEvalZero /* This will end within a short time (6 usecs). Just poll */
485*042d53a7SEvalZero while (NRF_RADIO->STATE == state) {
486*042d53a7SEvalZero /* If this fails, something is really wrong. Should last
487*042d53a7SEvalZero * no more than 6 usecs */
488*042d53a7SEvalZero }
489*042d53a7SEvalZero }
490*042d53a7SEvalZero }
491*042d53a7SEvalZero }
492*042d53a7SEvalZero
493*042d53a7SEvalZero /**
494*042d53a7SEvalZero *
495*042d53a7SEvalZero *
496*042d53a7SEvalZero */
497*042d53a7SEvalZero static int
ble_phy_set_start_time(uint32_t cputime,uint8_t rem_usecs,bool tx)498*042d53a7SEvalZero ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
499*042d53a7SEvalZero {
500*042d53a7SEvalZero uint32_t next_cc;
501*042d53a7SEvalZero uint32_t cur_cc;
502*042d53a7SEvalZero uint32_t cntr;
503*042d53a7SEvalZero uint32_t delta;
504*042d53a7SEvalZero
505*042d53a7SEvalZero /*
506*042d53a7SEvalZero * We need to adjust start time to include radio ramp-up and TX pipeline
507*042d53a7SEvalZero * delay (the latter only if applicable, so only for TX).
508*042d53a7SEvalZero *
509*042d53a7SEvalZero * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on
510*042d53a7SEvalZero * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate
511*042d53a7SEvalZero * using TIMER0 with 1 usec precision.
512*042d53a7SEvalZero */
513*042d53a7SEvalZero
514*042d53a7SEvalZero cputime -= 2;
515*042d53a7SEvalZero rem_usecs += 61;
516*042d53a7SEvalZero if (tx) {
517*042d53a7SEvalZero rem_usecs -= BLE_PHY_T_TXENFAST;
518*042d53a7SEvalZero rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode];
519*042d53a7SEvalZero } else {
520*042d53a7SEvalZero rem_usecs -= BLE_PHY_T_RXENFAST;
521*042d53a7SEvalZero }
522*042d53a7SEvalZero
523*042d53a7SEvalZero /*
524*042d53a7SEvalZero * rem_usecs will be no more than 2 ticks, but if it is more than single
525*042d53a7SEvalZero * tick then we should better count one more low-power tick rather than
526*042d53a7SEvalZero * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the
527*042d53a7SEvalZero * compare won't occur.
528*042d53a7SEvalZero */
529*042d53a7SEvalZero
530*042d53a7SEvalZero if (rem_usecs > 30) {
531*042d53a7SEvalZero cputime++;
532*042d53a7SEvalZero rem_usecs -= 30;
533*042d53a7SEvalZero }
534*042d53a7SEvalZero
535*042d53a7SEvalZero /*
536*042d53a7SEvalZero * Can we set the RTC compare to start TIMER0? We can do it if:
537*042d53a7SEvalZero * a) Current compare value is not N+1 or N+2 ticks from current
538*042d53a7SEvalZero * counter.
539*042d53a7SEvalZero * b) The value we want to set is not at least N+2 from current
540*042d53a7SEvalZero * counter.
541*042d53a7SEvalZero *
542*042d53a7SEvalZero * NOTE: since the counter can tick 1 while we do these calculations we
543*042d53a7SEvalZero * need to account for it.
544*042d53a7SEvalZero */
545*042d53a7SEvalZero next_cc = cputime & 0xffffff;
546*042d53a7SEvalZero cur_cc = NRF_RTC0->CC[0];
547*042d53a7SEvalZero cntr = NRF_RTC0->COUNTER;
548*042d53a7SEvalZero
549*042d53a7SEvalZero delta = (cur_cc - cntr) & 0xffffff;
550*042d53a7SEvalZero if ((delta <= 3) && (delta != 0)) {
551*042d53a7SEvalZero return -1;
552*042d53a7SEvalZero }
553*042d53a7SEvalZero delta = (next_cc - cntr) & 0xffffff;
554*042d53a7SEvalZero if ((delta & 0x800000) || (delta < 3)) {
555*042d53a7SEvalZero return -1;
556*042d53a7SEvalZero }
557*042d53a7SEvalZero
558*042d53a7SEvalZero /* Clear and set TIMER0 to fire off at proper time */
559*042d53a7SEvalZero NRF_TIMER0->TASKS_CLEAR = 1;
560*042d53a7SEvalZero NRF_TIMER0->CC[0] = rem_usecs;
561*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[0] = 0;
562*042d53a7SEvalZero
563*042d53a7SEvalZero /* Set RTC compare to start TIMER0 */
564*042d53a7SEvalZero NRF_RTC0->EVENTS_COMPARE[0] = 0;
565*042d53a7SEvalZero NRF_RTC0->CC[0] = next_cc;
566*042d53a7SEvalZero NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
567*042d53a7SEvalZero
568*042d53a7SEvalZero /* Enable PPI */
569*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk;
570*042d53a7SEvalZero
571*042d53a7SEvalZero /* Store the cputime at which we set the RTC */
572*042d53a7SEvalZero g_ble_phy_data.phy_start_cputime = cputime;
573*042d53a7SEvalZero
574*042d53a7SEvalZero return 0;
575*042d53a7SEvalZero }
576*042d53a7SEvalZero
577*042d53a7SEvalZero static int
ble_phy_set_start_now(void)578*042d53a7SEvalZero ble_phy_set_start_now(void)
579*042d53a7SEvalZero {
580*042d53a7SEvalZero uint32_t cntr;
581*042d53a7SEvalZero
582*042d53a7SEvalZero /* Read current RTC0 state */
583*042d53a7SEvalZero cntr = NRF_RTC0->COUNTER;
584*042d53a7SEvalZero
585*042d53a7SEvalZero /*
586*042d53a7SEvalZero * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not
587*042d53a7SEvalZero * occur in such case.
588*042d53a7SEvalZero */
589*042d53a7SEvalZero NRF_TIMER0->TASKS_CLEAR = 1;
590*042d53a7SEvalZero NRF_TIMER0->CC[0] = 1;
591*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[0] = 0;
592*042d53a7SEvalZero
593*042d53a7SEvalZero /*
594*042d53a7SEvalZero * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks
595*042d53a7SEvalZero * from current value to guarantee triggering compare event, but let's set
596*042d53a7SEvalZero * it to N+3 to account for possible extra tick on RTC0 during these
597*042d53a7SEvalZero * operations.
598*042d53a7SEvalZero */
599*042d53a7SEvalZero NRF_RTC0->EVENTS_COMPARE[0] = 0;
600*042d53a7SEvalZero NRF_RTC0->CC[0] = cntr + 3;
601*042d53a7SEvalZero NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
602*042d53a7SEvalZero
603*042d53a7SEvalZero /* Enable PPI */
604*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk;
605*042d53a7SEvalZero
606*042d53a7SEvalZero /*
607*042d53a7SEvalZero * Store the cputime at which we set the RTC
608*042d53a7SEvalZero *
609*042d53a7SEvalZero * XXX Compare event may be triggered on previous CC value (if it was set to
610*042d53a7SEvalZero * less than N+2) so in rare cases actual start time may be 2 ticks earlier
611*042d53a7SEvalZero * than what we expect. Since this is only used on RX, it may cause AUX scan
612*042d53a7SEvalZero * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable
613*042d53a7SEvalZero * for now.
614*042d53a7SEvalZero */
615*042d53a7SEvalZero g_ble_phy_data.phy_start_cputime = cntr + 3;
616*042d53a7SEvalZero
617*042d53a7SEvalZero return 0;
618*042d53a7SEvalZero }
619*042d53a7SEvalZero
620*042d53a7SEvalZero /**
621*042d53a7SEvalZero * Function is used to set PPI so that we can time out waiting for a reception
622*042d53a7SEvalZero * to occur. This happens for two reasons: we have sent a packet and we are
623*042d53a7SEvalZero * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are
624*042d53a7SEvalZero * starting a connection event and we are a slave and we are waiting for the
625*042d53a7SEvalZero * master to send us a packet (txrx should be set to ENABLE_RX).
626*042d53a7SEvalZero *
627*042d53a7SEvalZero * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
628*042d53a7SEvalZero * is no additional time to wait; we know when we should receive the address of
629*042d53a7SEvalZero * the received frame.
630*042d53a7SEvalZero *
631*042d53a7SEvalZero * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
632*042d53a7SEvalZero * @param tx_phy_mode phy mode for last TX (only valid for TX->RX)
633*042d53a7SEvalZero * @param wfr_usecs Amount of usecs to wait.
634*042d53a7SEvalZero */
635*042d53a7SEvalZero void
ble_phy_wfr_enable(int txrx,uint8_t tx_phy_mode,uint32_t wfr_usecs)636*042d53a7SEvalZero ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
637*042d53a7SEvalZero {
638*042d53a7SEvalZero uint32_t end_time;
639*042d53a7SEvalZero uint8_t phy;
640*042d53a7SEvalZero
641*042d53a7SEvalZero phy = g_ble_phy_data.phy_cur_phy_mode;
642*042d53a7SEvalZero
643*042d53a7SEvalZero if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
644*042d53a7SEvalZero /* RX shall start exactly T_IFS after TX end captured in CC[2] */
645*042d53a7SEvalZero end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS;
646*042d53a7SEvalZero /* Adjust for delay between EVENT_END and actual TX end time */
647*042d53a7SEvalZero end_time += g_ble_phy_t_txenddelay[tx_phy_mode];
648*042d53a7SEvalZero /* Wait a bit longer due to allowed active clock accuracy */
649*042d53a7SEvalZero end_time += 2;
650*042d53a7SEvalZero /*
651*042d53a7SEvalZero * It's possible that we'll capture PDU start time at the end of timer
652*042d53a7SEvalZero * cycle and since wfr expires at the beginning of calculated timer
653*042d53a7SEvalZero * cycle it can be almost 1 usec too early. Let's compensate for this
654*042d53a7SEvalZero * by waiting 1 usec more.
655*042d53a7SEvalZero */
656*042d53a7SEvalZero end_time += 1;
657*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN) > 0
658*042d53a7SEvalZero if ((phy == BLE_PHY_MODE_CODED_125KBPS) ||
659*042d53a7SEvalZero (phy == BLE_PHY_MODE_CODED_500KBPS)) {
660*042d53a7SEvalZero /*
661*042d53a7SEvalZero * Some controllers exceed T_IFS when transmitting on coded phy
662*042d53a7SEvalZero * so let's wait a bit longer to be able to talk to them if this
663*042d53a7SEvalZero * workaround is enabled.
664*042d53a7SEvalZero */
665*042d53a7SEvalZero end_time += MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN);
666*042d53a7SEvalZero }
667*042d53a7SEvalZero #endif
668*042d53a7SEvalZero } else {
669*042d53a7SEvalZero /*
670*042d53a7SEvalZero * RX shall start no later than wfr_usecs after RX enabled.
671*042d53a7SEvalZero * CC[0] is the time of RXEN so adjust for radio ram-up.
672*042d53a7SEvalZero * Do not add jitter since this is already covered by LL.
673*042d53a7SEvalZero */
674*042d53a7SEvalZero end_time = NRF_TIMER0->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs;
675*042d53a7SEvalZero }
676*042d53a7SEvalZero
677*042d53a7SEvalZero /*
678*042d53a7SEvalZero * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so
679*042d53a7SEvalZero * we are actually calculating relative to start of packet payload
680*042d53a7SEvalZero * which is fine.
681*042d53a7SEvalZero */
682*042d53a7SEvalZero
683*042d53a7SEvalZero /* Adjust for receiving access address since this triggers EVENT_ADDRESS */
684*042d53a7SEvalZero end_time += ble_phy_mode_pdu_start_off(phy);
685*042d53a7SEvalZero /* Adjust for delay between actual access address RX and EVENT_ADDRESS */
686*042d53a7SEvalZero end_time += g_ble_phy_t_rxaddrdelay[phy];
687*042d53a7SEvalZero
688*042d53a7SEvalZero /* wfr_secs is the time from rxen until timeout */
689*042d53a7SEvalZero NRF_TIMER0->CC[3] = end_time;
690*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[3] = 0;
691*042d53a7SEvalZero
692*042d53a7SEvalZero /* Enable wait for response PPI */
693*042d53a7SEvalZero NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
694*042d53a7SEvalZero
695*042d53a7SEvalZero /* Enable the disabled interrupt so we time out on events compare */
696*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
697*042d53a7SEvalZero
698*042d53a7SEvalZero /*
699*042d53a7SEvalZero * It may happen that if CPU is halted for a brief moment (e.g. during flash
700*042d53a7SEvalZero * erase or write), TIMER0 already counted past CC[3] and thus wfr will not
701*042d53a7SEvalZero * fire as expected. In case this happened, let's just disable PPIs for wfr
702*042d53a7SEvalZero * and trigger wfr manually (i.e. disable radio).
703*042d53a7SEvalZero *
704*042d53a7SEvalZero * Note that the same applies to RX start time set in CC[0] but since it
705*042d53a7SEvalZero * should fire earlier than wfr, fixing wfr is enough.
706*042d53a7SEvalZero *
707*042d53a7SEvalZero * CC[1] is only used as a reference on RX start, we do not need it here so
708*042d53a7SEvalZero * it can be used to read TIMER0 counter.
709*042d53a7SEvalZero */
710*042d53a7SEvalZero NRF_TIMER0->TASKS_CAPTURE[1] = 1;
711*042d53a7SEvalZero if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) {
712*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk;
713*042d53a7SEvalZero NRF_RADIO->TASKS_DISABLE = 1;
714*042d53a7SEvalZero }
715*042d53a7SEvalZero }
716*042d53a7SEvalZero
717*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
718*042d53a7SEvalZero static uint32_t
ble_phy_get_ccm_datarate(void)719*042d53a7SEvalZero ble_phy_get_ccm_datarate(void)
720*042d53a7SEvalZero {
721*042d53a7SEvalZero #if BLE_LL_BT5_PHY_SUPPORTED
722*042d53a7SEvalZero switch (g_ble_phy_data.phy_cur_phy_mode) {
723*042d53a7SEvalZero case BLE_PHY_MODE_1M:
724*042d53a7SEvalZero return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos;
725*042d53a7SEvalZero case BLE_PHY_MODE_2M:
726*042d53a7SEvalZero return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos;
727*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
728*042d53a7SEvalZero case BLE_PHY_MODE_CODED_125KBPS:
729*042d53a7SEvalZero return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos;
730*042d53a7SEvalZero case BLE_PHY_MODE_CODED_500KBPS:
731*042d53a7SEvalZero return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos;
732*042d53a7SEvalZero #endif
733*042d53a7SEvalZero }
734*042d53a7SEvalZero
735*042d53a7SEvalZero assert(0);
736*042d53a7SEvalZero return 0;
737*042d53a7SEvalZero #else
738*042d53a7SEvalZero return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos;
739*042d53a7SEvalZero #endif
740*042d53a7SEvalZero }
741*042d53a7SEvalZero #endif
742*042d53a7SEvalZero
743*042d53a7SEvalZero /**
744*042d53a7SEvalZero * Setup transceiver for receive.
745*042d53a7SEvalZero */
746*042d53a7SEvalZero static void
ble_phy_rx_xcvr_setup(void)747*042d53a7SEvalZero ble_phy_rx_xcvr_setup(void)
748*042d53a7SEvalZero {
749*042d53a7SEvalZero uint8_t *dptr;
750*042d53a7SEvalZero
751*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
752*042d53a7SEvalZero dptr += 3;
753*042d53a7SEvalZero
754*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
755*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
756*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
757*042d53a7SEvalZero NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
758*042d53a7SEvalZero NRF_CCM->OUTPTR = (uint32_t)dptr;
759*042d53a7SEvalZero NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
760*042d53a7SEvalZero NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption |
761*042d53a7SEvalZero ble_phy_get_ccm_datarate();
762*042d53a7SEvalZero NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
763*042d53a7SEvalZero NRF_CCM->SHORTS = 0;
764*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
765*042d53a7SEvalZero NRF_CCM->EVENTS_ENDCRYPT = 0;
766*042d53a7SEvalZero NRF_CCM->TASKS_KSGEN = 1;
767*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH25_Msk;
768*042d53a7SEvalZero } else {
769*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)dptr;
770*042d53a7SEvalZero }
771*042d53a7SEvalZero #else
772*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)dptr;
773*042d53a7SEvalZero #endif
774*042d53a7SEvalZero
775*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
776*042d53a7SEvalZero if (g_ble_phy_data.phy_privacy) {
777*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
778*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
779*042d53a7SEvalZero NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
780*042d53a7SEvalZero NRF_AAR->EVENTS_END = 0;
781*042d53a7SEvalZero NRF_AAR->EVENTS_RESOLVED = 0;
782*042d53a7SEvalZero NRF_AAR->EVENTS_NOTRESOLVED = 0;
783*042d53a7SEvalZero } else {
784*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted == 0) {
785*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
786*042d53a7SEvalZero }
787*042d53a7SEvalZero }
788*042d53a7SEvalZero #endif
789*042d53a7SEvalZero
790*042d53a7SEvalZero /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
791*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk;
792*042d53a7SEvalZero
793*042d53a7SEvalZero /* Reset the rx started flag. Used for the wait for response */
794*042d53a7SEvalZero g_ble_phy_data.phy_rx_started = 0;
795*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
796*042d53a7SEvalZero
797*042d53a7SEvalZero #if BLE_LL_BT5_PHY_SUPPORTED
798*042d53a7SEvalZero /*
799*042d53a7SEvalZero * On Coded PHY there are CI and TERM1 fields before PDU starts so we need
800*042d53a7SEvalZero * to take this into account when setting up BCC.
801*042d53a7SEvalZero */
802*042d53a7SEvalZero if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS ||
803*042d53a7SEvalZero g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) {
804*042d53a7SEvalZero g_ble_phy_data.phy_bcc_offset = 5;
805*042d53a7SEvalZero } else {
806*042d53a7SEvalZero g_ble_phy_data.phy_bcc_offset = 0;
807*042d53a7SEvalZero }
808*042d53a7SEvalZero #else
809*042d53a7SEvalZero g_ble_phy_data.phy_bcc_offset = 0;
810*042d53a7SEvalZero #endif
811*042d53a7SEvalZero
812*042d53a7SEvalZero /* I want to know when 1st byte received (after address) */
813*042d53a7SEvalZero NRF_RADIO->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */
814*042d53a7SEvalZero NRF_RADIO->EVENTS_ADDRESS = 0;
815*042d53a7SEvalZero NRF_RADIO->EVENTS_DEVMATCH = 0;
816*042d53a7SEvalZero NRF_RADIO->EVENTS_BCMATCH = 0;
817*042d53a7SEvalZero NRF_RADIO->EVENTS_RSSIEND = 0;
818*042d53a7SEvalZero NRF_RADIO->EVENTS_CRCOK = 0;
819*042d53a7SEvalZero NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk |
820*042d53a7SEvalZero RADIO_SHORTS_READY_START_Msk |
821*042d53a7SEvalZero RADIO_SHORTS_ADDRESS_BCSTART_Msk |
822*042d53a7SEvalZero RADIO_SHORTS_ADDRESS_RSSISTART_Msk |
823*042d53a7SEvalZero RADIO_SHORTS_DISABLED_RSSISTOP_Msk;
824*042d53a7SEvalZero
825*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk;
826*042d53a7SEvalZero }
827*042d53a7SEvalZero
828*042d53a7SEvalZero /**
829*042d53a7SEvalZero * Called from interrupt context when the transmit ends
830*042d53a7SEvalZero *
831*042d53a7SEvalZero */
832*042d53a7SEvalZero static void
ble_phy_tx_end_isr(void)833*042d53a7SEvalZero ble_phy_tx_end_isr(void)
834*042d53a7SEvalZero {
835*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
836*042d53a7SEvalZero int phy;
837*042d53a7SEvalZero #endif
838*042d53a7SEvalZero uint8_t tx_phy_mode;
839*042d53a7SEvalZero uint8_t was_encrypted;
840*042d53a7SEvalZero uint8_t transition;
841*042d53a7SEvalZero uint32_t rx_time;
842*042d53a7SEvalZero uint32_t wfr_time;
843*042d53a7SEvalZero
844*042d53a7SEvalZero /* Store PHY on which we've just transmitted smth */
845*042d53a7SEvalZero tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode;
846*042d53a7SEvalZero
847*042d53a7SEvalZero /* If this transmission was encrypted we need to remember it */
848*042d53a7SEvalZero was_encrypted = g_ble_phy_data.phy_encrypted;
849*042d53a7SEvalZero (void)was_encrypted;
850*042d53a7SEvalZero
851*042d53a7SEvalZero /* Better be in TX state! */
852*042d53a7SEvalZero assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
853*042d53a7SEvalZero
854*042d53a7SEvalZero /* Clear events and clear interrupt on disabled event */
855*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
856*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
857*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
858*042d53a7SEvalZero wfr_time = NRF_RADIO->SHORTS;
859*042d53a7SEvalZero (void)wfr_time;
860*042d53a7SEvalZero
861*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
862*042d53a7SEvalZero /*
863*042d53a7SEvalZero * XXX: not sure what to do. We had a HW error during transmission.
864*042d53a7SEvalZero * For now I just count a stat but continue on like all is good.
865*042d53a7SEvalZero */
866*042d53a7SEvalZero if (was_encrypted) {
867*042d53a7SEvalZero if (NRF_CCM->EVENTS_ERROR) {
868*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_hw_err);
869*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
870*042d53a7SEvalZero }
871*042d53a7SEvalZero }
872*042d53a7SEvalZero #endif
873*042d53a7SEvalZero
874*042d53a7SEvalZero /* Call transmit end callback */
875*042d53a7SEvalZero if (g_ble_phy_data.txend_cb) {
876*042d53a7SEvalZero g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
877*042d53a7SEvalZero }
878*042d53a7SEvalZero
879*042d53a7SEvalZero transition = g_ble_phy_data.phy_transition;
880*042d53a7SEvalZero if (transition == BLE_PHY_TRANSITION_TX_RX) {
881*042d53a7SEvalZero
882*042d53a7SEvalZero #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
883*042d53a7SEvalZero /* See if a new phy has been specified for tx to rx transition */
884*042d53a7SEvalZero phy = g_ble_phy_data.phy_txtorx_phy_mode;
885*042d53a7SEvalZero if (phy != g_ble_phy_data.phy_cur_phy_mode) {
886*042d53a7SEvalZero ble_phy_mode_set(phy, phy);
887*042d53a7SEvalZero }
888*042d53a7SEvalZero #endif
889*042d53a7SEvalZero
890*042d53a7SEvalZero /* Packet pointer needs to be reset. */
891*042d53a7SEvalZero ble_phy_rx_xcvr_setup();
892*042d53a7SEvalZero
893*042d53a7SEvalZero ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0);
894*042d53a7SEvalZero
895*042d53a7SEvalZero /* Schedule RX exactly T_IFS after TX end captured in CC[2] */
896*042d53a7SEvalZero rx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS;
897*042d53a7SEvalZero /* Adjust for delay between EVENT_END and actual TX end time */
898*042d53a7SEvalZero rx_time += g_ble_phy_t_txenddelay[tx_phy_mode];
899*042d53a7SEvalZero /* Adjust for radio ramp-up */
900*042d53a7SEvalZero rx_time -= BLE_PHY_T_RXENFAST;
901*042d53a7SEvalZero /* Start listening a bit earlier due to allowed active clock accuracy */
902*042d53a7SEvalZero rx_time -= 2;
903*042d53a7SEvalZero
904*042d53a7SEvalZero NRF_TIMER0->CC[0] = rx_time;
905*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[0] = 0;
906*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
907*042d53a7SEvalZero } else {
908*042d53a7SEvalZero /*
909*042d53a7SEvalZero * XXX: not sure we need to stop the timer here all the time. Or that
910*042d53a7SEvalZero * it should be stopped here.
911*042d53a7SEvalZero */
912*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
913*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
914*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
915*042d53a7SEvalZero PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk;
916*042d53a7SEvalZero assert(transition == BLE_PHY_TRANSITION_NONE);
917*042d53a7SEvalZero }
918*042d53a7SEvalZero }
919*042d53a7SEvalZero
920*042d53a7SEvalZero static inline uint8_t
ble_phy_get_cur_rx_phy_mode(void)921*042d53a7SEvalZero ble_phy_get_cur_rx_phy_mode(void)
922*042d53a7SEvalZero {
923*042d53a7SEvalZero uint8_t phy;
924*042d53a7SEvalZero
925*042d53a7SEvalZero phy = g_ble_phy_data.phy_cur_phy_mode;
926*042d53a7SEvalZero
927*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
928*042d53a7SEvalZero /*
929*042d53a7SEvalZero * For Coded PHY mode can be set to either codings since actual coding is
930*042d53a7SEvalZero * set in packet header. However, here we need actual coding of received
931*042d53a7SEvalZero * packet as this determines pipeline delays so need to figure this out
932*042d53a7SEvalZero * using CI field.
933*042d53a7SEvalZero */
934*042d53a7SEvalZero if ((phy == BLE_PHY_MODE_CODED_125KBPS) ||
935*042d53a7SEvalZero (phy == BLE_PHY_MODE_CODED_500KBPS)) {
936*042d53a7SEvalZero phy = NRF_RADIO->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ?
937*042d53a7SEvalZero BLE_PHY_MODE_CODED_500KBPS :
938*042d53a7SEvalZero BLE_PHY_MODE_CODED_125KBPS;
939*042d53a7SEvalZero }
940*042d53a7SEvalZero #endif
941*042d53a7SEvalZero
942*042d53a7SEvalZero return phy;
943*042d53a7SEvalZero }
944*042d53a7SEvalZero
945*042d53a7SEvalZero static void
ble_phy_rx_end_isr(void)946*042d53a7SEvalZero ble_phy_rx_end_isr(void)
947*042d53a7SEvalZero {
948*042d53a7SEvalZero int rc;
949*042d53a7SEvalZero uint8_t *dptr;
950*042d53a7SEvalZero uint8_t crcok;
951*042d53a7SEvalZero uint32_t tx_time;
952*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
953*042d53a7SEvalZero
954*042d53a7SEvalZero /* Clear events and clear interrupt */
955*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
956*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk;
957*042d53a7SEvalZero
958*042d53a7SEvalZero /* Disable automatic RXEN */
959*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
960*042d53a7SEvalZero
961*042d53a7SEvalZero /* Set RSSI and CRC status flag in header */
962*042d53a7SEvalZero ble_hdr = &g_ble_phy_data.rxhdr;
963*042d53a7SEvalZero assert(NRF_RADIO->EVENTS_RSSIEND != 0);
964*042d53a7SEvalZero ble_hdr->rxinfo.rssi = -1 * NRF_RADIO->RSSISAMPLE;
965*042d53a7SEvalZero
966*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
967*042d53a7SEvalZero dptr += 3;
968*042d53a7SEvalZero
969*042d53a7SEvalZero /* Count PHY crc errors and valid packets */
970*042d53a7SEvalZero crcok = NRF_RADIO->EVENTS_CRCOK;
971*042d53a7SEvalZero if (!crcok) {
972*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_crc_err);
973*042d53a7SEvalZero } else {
974*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_valid);
975*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
976*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
977*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
978*042d53a7SEvalZero /* Only set MIC failure flag if frame is not zero length */
979*042d53a7SEvalZero if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) {
980*042d53a7SEvalZero ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE;
981*042d53a7SEvalZero }
982*042d53a7SEvalZero
983*042d53a7SEvalZero /*
984*042d53a7SEvalZero * XXX: not sure how to deal with this. This should not
985*042d53a7SEvalZero * be a MIC failure but we should not hand it up. I guess
986*042d53a7SEvalZero * this is just some form of rx error and that is how we
987*042d53a7SEvalZero * handle it? For now, just set CRC error flags
988*042d53a7SEvalZero */
989*042d53a7SEvalZero if (NRF_CCM->EVENTS_ERROR) {
990*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_hw_err);
991*042d53a7SEvalZero ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
992*042d53a7SEvalZero }
993*042d53a7SEvalZero
994*042d53a7SEvalZero /*
995*042d53a7SEvalZero * XXX: This is a total hack work-around for now but I dont
996*042d53a7SEvalZero * know what else to do. If ENDCRYPT is not set and we are
997*042d53a7SEvalZero * encrypted we need to not trust this frame and drop it.
998*042d53a7SEvalZero */
999*042d53a7SEvalZero if (NRF_CCM->EVENTS_ENDCRYPT == 0) {
1000*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_hw_err);
1001*042d53a7SEvalZero ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
1002*042d53a7SEvalZero }
1003*042d53a7SEvalZero }
1004*042d53a7SEvalZero #endif
1005*042d53a7SEvalZero }
1006*042d53a7SEvalZero
1007*042d53a7SEvalZero /*
1008*042d53a7SEvalZero * Let's schedule TX now and we will just cancel it after processing RXed
1009*042d53a7SEvalZero * packet if we don't need TX.
1010*042d53a7SEvalZero *
1011*042d53a7SEvalZero * We need this to initiate connection in case AUX_CONNECT_REQ was sent on
1012*042d53a7SEvalZero * LE Coded S8. In this case the time we process RXed packet is roughly the
1013*042d53a7SEvalZero * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI
1014*042d53a7SEvalZero * armed) so we may simply miss the slot and set the timer in the past.
1015*042d53a7SEvalZero *
1016*042d53a7SEvalZero * When TX is scheduled in advance, we may event process packet a bit longer
1017*042d53a7SEvalZero * during radio ramp-up - this gives us extra 40 usecs which is more than
1018*042d53a7SEvalZero * enough.
1019*042d53a7SEvalZero */
1020*042d53a7SEvalZero
1021*042d53a7SEvalZero /* Schedule TX exactly T_IFS after RX end captured in CC[2] */
1022*042d53a7SEvalZero tx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS;
1023*042d53a7SEvalZero /* Adjust for delay between actual RX end time and EVENT_END */
1024*042d53a7SEvalZero tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode];
1025*042d53a7SEvalZero /* Adjust for radio ramp-up */
1026*042d53a7SEvalZero tx_time -= BLE_PHY_T_TXENFAST;
1027*042d53a7SEvalZero /* Adjust for delay between EVENT_READY and actual TX start time */
1028*042d53a7SEvalZero /* XXX: we may have asymmetric phy so next phy may be different... */
1029*042d53a7SEvalZero tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode];
1030*042d53a7SEvalZero
1031*042d53a7SEvalZero NRF_TIMER0->CC[0] = tx_time;
1032*042d53a7SEvalZero NRF_TIMER0->EVENTS_COMPARE[0] = 0;
1033*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
1034*042d53a7SEvalZero
1035*042d53a7SEvalZero /*
1036*042d53a7SEvalZero * XXX: Hack warning!
1037*042d53a7SEvalZero *
1038*042d53a7SEvalZero * It may happen (during flash erase) that CPU is stopped for a moment and
1039*042d53a7SEvalZero * TIMER0 already counted past CC[0]. In such case we will be stuck waiting
1040*042d53a7SEvalZero * for TX to start since EVENTS_COMPARE[0] will not happen any time soon.
1041*042d53a7SEvalZero * For now let's set a flag denoting that we are late in RX-TX transition so
1042*042d53a7SEvalZero * ble_phy_tx() will fail - this allows everything to cleanup nicely without
1043*042d53a7SEvalZero * the need for extra handling in many places.
1044*042d53a7SEvalZero *
1045*042d53a7SEvalZero * Note: CC[3] is used only for wfr which we do not need here.
1046*042d53a7SEvalZero */
1047*042d53a7SEvalZero NRF_TIMER0->TASKS_CAPTURE[3] = 1;
1048*042d53a7SEvalZero if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
1049*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
1050*042d53a7SEvalZero g_ble_phy_data.phy_transition_late = 1;
1051*042d53a7SEvalZero }
1052*042d53a7SEvalZero
1053*042d53a7SEvalZero /*
1054*042d53a7SEvalZero * XXX: This is a horrible ugly hack to deal with the RAM S1 byte
1055*042d53a7SEvalZero * that is not sent over the air but is present here. Simply move the
1056*042d53a7SEvalZero * data pointer to deal with it. Fix this later.
1057*042d53a7SEvalZero */
1058*042d53a7SEvalZero dptr[2] = dptr[1];
1059*042d53a7SEvalZero dptr[1] = dptr[0];
1060*042d53a7SEvalZero rc = ble_ll_rx_end(dptr + 1, ble_hdr);
1061*042d53a7SEvalZero if (rc < 0) {
1062*042d53a7SEvalZero ble_phy_disable();
1063*042d53a7SEvalZero }
1064*042d53a7SEvalZero }
1065*042d53a7SEvalZero
1066*042d53a7SEvalZero static bool
ble_phy_rx_start_isr(void)1067*042d53a7SEvalZero ble_phy_rx_start_isr(void)
1068*042d53a7SEvalZero {
1069*042d53a7SEvalZero int rc;
1070*042d53a7SEvalZero uint32_t state;
1071*042d53a7SEvalZero uint32_t usecs;
1072*042d53a7SEvalZero uint32_t pdu_usecs;
1073*042d53a7SEvalZero uint32_t ticks;
1074*042d53a7SEvalZero struct ble_mbuf_hdr *ble_hdr;
1075*042d53a7SEvalZero uint8_t *dptr;
1076*042d53a7SEvalZero
1077*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
1078*042d53a7SEvalZero
1079*042d53a7SEvalZero /* Clear events and clear interrupt */
1080*042d53a7SEvalZero NRF_RADIO->EVENTS_ADDRESS = 0;
1081*042d53a7SEvalZero
1082*042d53a7SEvalZero /* Clear wfr timer channels and DISABLED interrupt */
1083*042d53a7SEvalZero NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk;
1084*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk;
1085*042d53a7SEvalZero
1086*042d53a7SEvalZero /* Initialize the ble mbuf header */
1087*042d53a7SEvalZero ble_hdr = &g_ble_phy_data.rxhdr;
1088*042d53a7SEvalZero ble_hdr->rxinfo.flags = ble_ll_state_get();
1089*042d53a7SEvalZero ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan;
1090*042d53a7SEvalZero ble_hdr->rxinfo.handle = 0;
1091*042d53a7SEvalZero ble_hdr->rxinfo.phy = ble_phy_get_cur_phy();
1092*042d53a7SEvalZero ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode();
1093*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
1094*042d53a7SEvalZero ble_hdr->rxinfo.user_data = NULL;
1095*042d53a7SEvalZero #endif
1096*042d53a7SEvalZero
1097*042d53a7SEvalZero /*
1098*042d53a7SEvalZero * Calculate accurate packets start time (with remainder)
1099*042d53a7SEvalZero *
1100*042d53a7SEvalZero * We may start receiving packet somewhere during preamble in which case
1101*042d53a7SEvalZero * it is possible that actual transmission started before TIMER0 was
1102*042d53a7SEvalZero * running - need to take this into account.
1103*042d53a7SEvalZero */
1104*042d53a7SEvalZero ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime;
1105*042d53a7SEvalZero
1106*042d53a7SEvalZero usecs = NRF_TIMER0->CC[1];
1107*042d53a7SEvalZero pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) +
1108*042d53a7SEvalZero g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode];
1109*042d53a7SEvalZero if (usecs < pdu_usecs) {
1110*042d53a7SEvalZero g_ble_phy_data.phy_start_cputime--;
1111*042d53a7SEvalZero usecs += 30;
1112*042d53a7SEvalZero }
1113*042d53a7SEvalZero usecs -= pdu_usecs;
1114*042d53a7SEvalZero
1115*042d53a7SEvalZero ticks = os_cputime_usecs_to_ticks(usecs);
1116*042d53a7SEvalZero usecs -= os_cputime_ticks_to_usecs(ticks);
1117*042d53a7SEvalZero if (usecs == 31) {
1118*042d53a7SEvalZero usecs = 0;
1119*042d53a7SEvalZero ++ticks;
1120*042d53a7SEvalZero }
1121*042d53a7SEvalZero
1122*042d53a7SEvalZero ble_hdr->beg_cputime += ticks;
1123*042d53a7SEvalZero ble_hdr->rem_usecs = usecs;
1124*042d53a7SEvalZero
1125*042d53a7SEvalZero /* XXX: I wonder if we always have the 1st byte. If we need to wait for
1126*042d53a7SEvalZero * rx chain delay, it could be 18 usecs from address interrupt. The
1127*042d53a7SEvalZero nrf52 may be able to get here early. */
1128*042d53a7SEvalZero /* Wait to get 1st byte of frame */
1129*042d53a7SEvalZero while (1) {
1130*042d53a7SEvalZero state = NRF_RADIO->STATE;
1131*042d53a7SEvalZero if (NRF_RADIO->EVENTS_BCMATCH != 0) {
1132*042d53a7SEvalZero break;
1133*042d53a7SEvalZero }
1134*042d53a7SEvalZero
1135*042d53a7SEvalZero /*
1136*042d53a7SEvalZero * If state is disabled, we should have the BCMATCH. If not,
1137*042d53a7SEvalZero * something is wrong!
1138*042d53a7SEvalZero */
1139*042d53a7SEvalZero if (state == RADIO_STATE_STATE_Disabled) {
1140*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
1141*042d53a7SEvalZero NRF_RADIO->SHORTS = 0;
1142*042d53a7SEvalZero return false;
1143*042d53a7SEvalZero }
1144*042d53a7SEvalZero }
1145*042d53a7SEvalZero
1146*042d53a7SEvalZero /* Call Link Layer receive start function */
1147*042d53a7SEvalZero rc = ble_ll_rx_start(dptr + 3,
1148*042d53a7SEvalZero g_ble_phy_data.phy_chan,
1149*042d53a7SEvalZero &g_ble_phy_data.rxhdr);
1150*042d53a7SEvalZero if (rc >= 0) {
1151*042d53a7SEvalZero /* Set rx started flag and enable rx end ISR */
1152*042d53a7SEvalZero g_ble_phy_data.phy_rx_started = 1;
1153*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
1154*042d53a7SEvalZero
1155*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1156*042d53a7SEvalZero /* Must start aar if we need to */
1157*042d53a7SEvalZero if (g_ble_phy_data.phy_privacy) {
1158*042d53a7SEvalZero NRF_RADIO->EVENTS_BCMATCH = 0;
1159*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk;
1160*042d53a7SEvalZero
1161*042d53a7SEvalZero /*
1162*042d53a7SEvalZero * Setup AAR to resolve AdvA and trigger it after complete address
1163*042d53a7SEvalZero * is received, i.e. after PDU header and AdvA is received.
1164*042d53a7SEvalZero *
1165*042d53a7SEvalZero * AdvA starts at 4th octet in receive buffer, after S0, len and S1
1166*042d53a7SEvalZero * fields.
1167*042d53a7SEvalZero *
1168*042d53a7SEvalZero * In case of extended advertising AdvA is located after extended
1169*042d53a7SEvalZero * header (+2 octets).
1170*042d53a7SEvalZero */
1171*042d53a7SEvalZero if (BLE_MBUF_HDR_EXT_ADV(&g_ble_phy_data.rxhdr)) {
1172*042d53a7SEvalZero NRF_AAR->ADDRPTR = (uint32_t)(dptr + 5);
1173*042d53a7SEvalZero NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN + 2) * 8 +
1174*042d53a7SEvalZero g_ble_phy_data.phy_bcc_offset;
1175*042d53a7SEvalZero } else {
1176*042d53a7SEvalZero NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3);
1177*042d53a7SEvalZero NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8 +
1178*042d53a7SEvalZero g_ble_phy_data.phy_bcc_offset;
1179*042d53a7SEvalZero }
1180*042d53a7SEvalZero }
1181*042d53a7SEvalZero #endif
1182*042d53a7SEvalZero } else {
1183*042d53a7SEvalZero /* Disable PHY */
1184*042d53a7SEvalZero ble_phy_disable();
1185*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_aborts);
1186*042d53a7SEvalZero }
1187*042d53a7SEvalZero
1188*042d53a7SEvalZero /* Count rx starts */
1189*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_starts);
1190*042d53a7SEvalZero
1191*042d53a7SEvalZero return true;
1192*042d53a7SEvalZero }
1193*042d53a7SEvalZero
1194*042d53a7SEvalZero static void
ble_phy_isr(void)1195*042d53a7SEvalZero ble_phy_isr(void)
1196*042d53a7SEvalZero {
1197*042d53a7SEvalZero uint32_t irq_en;
1198*042d53a7SEvalZero
1199*042d53a7SEvalZero os_trace_isr_enter();
1200*042d53a7SEvalZero
1201*042d53a7SEvalZero /* Read irq register to determine which interrupts are enabled */
1202*042d53a7SEvalZero irq_en = NRF_RADIO->INTENCLR;
1203*042d53a7SEvalZero
1204*042d53a7SEvalZero /*
1205*042d53a7SEvalZero * NOTE: order of checking is important! Possible, if things get delayed,
1206*042d53a7SEvalZero * we have both an ADDRESS and DISABLED interrupt in rx state. If we get
1207*042d53a7SEvalZero * an address, we disable the DISABLED interrupt.
1208*042d53a7SEvalZero */
1209*042d53a7SEvalZero
1210*042d53a7SEvalZero /* We get this if we have started to receive a frame */
1211*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO->EVENTS_ADDRESS) {
1212*042d53a7SEvalZero /*
1213*042d53a7SEvalZero * wfr timer is calculated to expire at the exact time we should start
1214*042d53a7SEvalZero * receiving a packet (with 1 usec precision) so it is possible it will
1215*042d53a7SEvalZero * fire at the same time as EVENT_ADDRESS. If this happens, radio will
1216*042d53a7SEvalZero * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte
1217*042d53a7SEvalZero * of payload is received and ble_phy_rx_start_isr() will fail. In this
1218*042d53a7SEvalZero * case we should not clear DISABLED irq mask so it will be handled as
1219*042d53a7SEvalZero * regular radio disabled event below. In other case radio was disabled
1220*042d53a7SEvalZero * on purpose and there's nothing more to handle so we can clear mask.
1221*042d53a7SEvalZero */
1222*042d53a7SEvalZero if (ble_phy_rx_start_isr()) {
1223*042d53a7SEvalZero irq_en &= ~RADIO_INTENCLR_DISABLED_Msk;
1224*042d53a7SEvalZero }
1225*042d53a7SEvalZero }
1226*042d53a7SEvalZero
1227*042d53a7SEvalZero /* Check for disabled event. This only happens for transmits now */
1228*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
1229*042d53a7SEvalZero if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) {
1230*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
1231*042d53a7SEvalZero ble_ll_wfr_timer_exp(NULL);
1232*042d53a7SEvalZero } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) {
1233*042d53a7SEvalZero assert(0);
1234*042d53a7SEvalZero } else {
1235*042d53a7SEvalZero ble_phy_tx_end_isr();
1236*042d53a7SEvalZero }
1237*042d53a7SEvalZero }
1238*042d53a7SEvalZero
1239*042d53a7SEvalZero /* Receive packet end (we dont enable this for transmit) */
1240*042d53a7SEvalZero if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) {
1241*042d53a7SEvalZero ble_phy_rx_end_isr();
1242*042d53a7SEvalZero }
1243*042d53a7SEvalZero
1244*042d53a7SEvalZero g_ble_phy_data.phy_transition_late = 0;
1245*042d53a7SEvalZero
1246*042d53a7SEvalZero /* Ensures IRQ is cleared */
1247*042d53a7SEvalZero irq_en = NRF_RADIO->SHORTS;
1248*042d53a7SEvalZero
1249*042d53a7SEvalZero /* Count # of interrupts */
1250*042d53a7SEvalZero STATS_INC(ble_phy_stats, phy_isrs);
1251*042d53a7SEvalZero
1252*042d53a7SEvalZero os_trace_isr_exit();
1253*042d53a7SEvalZero }
1254*042d53a7SEvalZero
1255*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
1256*042d53a7SEvalZero MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
1257*042d53a7SEvalZero MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
1258*042d53a7SEvalZero static inline void
ble_phy_dbg_time_setup_gpiote(int index,int pin)1259*042d53a7SEvalZero ble_phy_dbg_time_setup_gpiote(int index, int pin)
1260*042d53a7SEvalZero {
1261*042d53a7SEvalZero NRF_GPIO_Type *port;
1262*042d53a7SEvalZero
1263*042d53a7SEvalZero #if NRF52840_XXAA
1264*042d53a7SEvalZero port = pin > 31 ? NRF_P1 : NRF_P0;
1265*042d53a7SEvalZero pin &= 0x1f;
1266*042d53a7SEvalZero #else
1267*042d53a7SEvalZero port = NRF_P0;
1268*042d53a7SEvalZero #endif
1269*042d53a7SEvalZero
1270*042d53a7SEvalZero /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */
1271*042d53a7SEvalZero port->DIRSET = (1 << pin);
1272*042d53a7SEvalZero port->OUTCLR = (1 << pin);
1273*042d53a7SEvalZero
1274*042d53a7SEvalZero NRF_GPIOTE->CONFIG[index] =
1275*042d53a7SEvalZero (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
1276*042d53a7SEvalZero ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
1277*042d53a7SEvalZero #if NRF52840_XXAA
1278*042d53a7SEvalZero ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos);
1279*042d53a7SEvalZero #else
1280*042d53a7SEvalZero 0;
1281*042d53a7SEvalZero #endif
1282*042d53a7SEvalZero }
1283*042d53a7SEvalZero #endif
1284*042d53a7SEvalZero
1285*042d53a7SEvalZero static void
ble_phy_dbg_time_setup(void)1286*042d53a7SEvalZero ble_phy_dbg_time_setup(void)
1287*042d53a7SEvalZero {
1288*042d53a7SEvalZero int gpiote_idx __attribute__((unused)) = 8;
1289*042d53a7SEvalZero
1290*042d53a7SEvalZero /*
1291*042d53a7SEvalZero * We setup GPIOTE starting from last configuration index to minimize risk
1292*042d53a7SEvalZero * of conflict with GPIO setup via hal. It's not great solution, but since
1293*042d53a7SEvalZero * this is just debugging code we can live with this.
1294*042d53a7SEvalZero */
1295*042d53a7SEvalZero
1296*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
1297*042d53a7SEvalZero ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1298*042d53a7SEvalZero MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
1299*042d53a7SEvalZero
1300*042d53a7SEvalZero NRF_PPI->CH[17].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
1301*042d53a7SEvalZero NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1302*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH17_Msk;
1303*042d53a7SEvalZero
1304*042d53a7SEvalZero /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
1305*042d53a7SEvalZero NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1306*042d53a7SEvalZero NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1307*042d53a7SEvalZero #endif
1308*042d53a7SEvalZero
1309*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
1310*042d53a7SEvalZero ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1311*042d53a7SEvalZero MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
1312*042d53a7SEvalZero
1313*042d53a7SEvalZero /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
1314*042d53a7SEvalZero NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1315*042d53a7SEvalZero NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1316*042d53a7SEvalZero #endif
1317*042d53a7SEvalZero
1318*042d53a7SEvalZero #if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
1319*042d53a7SEvalZero ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1320*042d53a7SEvalZero MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
1321*042d53a7SEvalZero
1322*042d53a7SEvalZero #if NRF52840_XXAA
1323*042d53a7SEvalZero NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_RXREADY);
1324*042d53a7SEvalZero #else
1325*042d53a7SEvalZero NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
1326*042d53a7SEvalZero #endif
1327*042d53a7SEvalZero NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1328*042d53a7SEvalZero NRF_PPI->CH[19].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
1329*042d53a7SEvalZero NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1330*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk;
1331*042d53a7SEvalZero
1332*042d53a7SEvalZero /* CH[4] and CH[5] are always on for wfr */
1333*042d53a7SEvalZero NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1334*042d53a7SEvalZero NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1335*042d53a7SEvalZero #endif
1336*042d53a7SEvalZero }
1337*042d53a7SEvalZero
1338*042d53a7SEvalZero /**
1339*042d53a7SEvalZero * ble phy init
1340*042d53a7SEvalZero *
1341*042d53a7SEvalZero * Initialize the PHY.
1342*042d53a7SEvalZero *
1343*042d53a7SEvalZero * @return int 0: success; PHY error code otherwise
1344*042d53a7SEvalZero */
1345*042d53a7SEvalZero int
ble_phy_init(void)1346*042d53a7SEvalZero ble_phy_init(void)
1347*042d53a7SEvalZero {
1348*042d53a7SEvalZero int rc;
1349*042d53a7SEvalZero
1350*042d53a7SEvalZero /* Default phy to use is 1M */
1351*042d53a7SEvalZero g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M;
1352*042d53a7SEvalZero g_ble_phy_data.phy_txtorx_phy_mode = BLE_PHY_MODE_1M;
1353*042d53a7SEvalZero
1354*042d53a7SEvalZero #if !defined(BLE_XCVR_RFCLK)
1355*042d53a7SEvalZero /* BLE wants the HFXO on all the time in this case */
1356*042d53a7SEvalZero ble_phy_rfclk_enable();
1357*042d53a7SEvalZero
1358*042d53a7SEvalZero /*
1359*042d53a7SEvalZero * XXX: I do not think we need to wait for settling time here since
1360*042d53a7SEvalZero * we will probably not use the radio for longer than the settling time
1361*042d53a7SEvalZero * and it will only degrade performance. Might want to wait here though.
1362*042d53a7SEvalZero */
1363*042d53a7SEvalZero #endif
1364*042d53a7SEvalZero
1365*042d53a7SEvalZero /* Set phy channel to an invalid channel so first set channel works */
1366*042d53a7SEvalZero g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
1367*042d53a7SEvalZero
1368*042d53a7SEvalZero /* Toggle peripheral power to reset (just in case) */
1369*042d53a7SEvalZero NRF_RADIO->POWER = 0;
1370*042d53a7SEvalZero NRF_RADIO->POWER = 1;
1371*042d53a7SEvalZero
1372*042d53a7SEvalZero /* Disable all interrupts */
1373*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
1374*042d53a7SEvalZero
1375*042d53a7SEvalZero /* Set configuration registers */
1376*042d53a7SEvalZero NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
1377*042d53a7SEvalZero NRF_RADIO->PCNF0 = NRF_PCNF0;
1378*042d53a7SEvalZero
1379*042d53a7SEvalZero /* XXX: should maxlen be 251 for encryption? */
1380*042d53a7SEvalZero NRF_RADIO->PCNF1 = NRF_MAXLEN |
1381*042d53a7SEvalZero (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) |
1382*042d53a7SEvalZero (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) |
1383*042d53a7SEvalZero RADIO_PCNF1_WHITEEN_Msk;
1384*042d53a7SEvalZero
1385*042d53a7SEvalZero /* Enable radio fast ramp-up */
1386*042d53a7SEvalZero NRF_RADIO->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) &
1387*042d53a7SEvalZero RADIO_MODECNF0_RU_Msk;
1388*042d53a7SEvalZero
1389*042d53a7SEvalZero /* Set logical address 1 for TX and RX */
1390*042d53a7SEvalZero NRF_RADIO->TXADDRESS = 0;
1391*042d53a7SEvalZero NRF_RADIO->RXADDRESSES = (1 << 0);
1392*042d53a7SEvalZero
1393*042d53a7SEvalZero /* Configure the CRC registers */
1394*042d53a7SEvalZero NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three;
1395*042d53a7SEvalZero
1396*042d53a7SEvalZero /* Configure BLE poly */
1397*042d53a7SEvalZero NRF_RADIO->CRCPOLY = 0x0000065B;
1398*042d53a7SEvalZero
1399*042d53a7SEvalZero /* Configure IFS */
1400*042d53a7SEvalZero NRF_RADIO->TIFS = BLE_LL_IFS;
1401*042d53a7SEvalZero
1402*042d53a7SEvalZero /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
1403*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk;
1404*042d53a7SEvalZero
1405*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1406*042d53a7SEvalZero NRF_CCM->INTENCLR = 0xffffffff;
1407*042d53a7SEvalZero NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
1408*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
1409*042d53a7SEvalZero memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
1410*042d53a7SEvalZero #endif
1411*042d53a7SEvalZero
1412*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1413*042d53a7SEvalZero g_ble_phy_data.phy_aar_scratch = 0;
1414*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
1415*042d53a7SEvalZero NRF_AAR->INTENCLR = 0xffffffff;
1416*042d53a7SEvalZero NRF_AAR->EVENTS_END = 0;
1417*042d53a7SEvalZero NRF_AAR->EVENTS_RESOLVED = 0;
1418*042d53a7SEvalZero NRF_AAR->EVENTS_NOTRESOLVED = 0;
1419*042d53a7SEvalZero NRF_AAR->NIRK = 0;
1420*042d53a7SEvalZero #endif
1421*042d53a7SEvalZero
1422*042d53a7SEvalZero /* TIMER0 setup for PHY when using RTC */
1423*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
1424*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
1425*042d53a7SEvalZero NRF_TIMER0->BITMODE = 3; /* 32-bit timer */
1426*042d53a7SEvalZero NRF_TIMER0->MODE = 0; /* Timer mode */
1427*042d53a7SEvalZero NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */
1428*042d53a7SEvalZero
1429*042d53a7SEvalZero /*
1430*042d53a7SEvalZero * PPI setup.
1431*042d53a7SEvalZero * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
1432*042d53a7SEvalZero * to cancel the wait for response timer.
1433*042d53a7SEvalZero * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
1434*042d53a7SEvalZero * for response timer.
1435*042d53a7SEvalZero */
1436*042d53a7SEvalZero NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS);
1437*042d53a7SEvalZero NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]);
1438*042d53a7SEvalZero NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]);
1439*042d53a7SEvalZero NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
1440*042d53a7SEvalZero
1441*042d53a7SEvalZero /* Set isr in vector table and enable interrupt */
1442*042d53a7SEvalZero NVIC_SetPriority(RADIO_IRQn, 0);
1443*042d53a7SEvalZero #if MYNEWT
1444*042d53a7SEvalZero NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
1445*042d53a7SEvalZero #else
1446*042d53a7SEvalZero ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr);
1447*042d53a7SEvalZero #endif
1448*042d53a7SEvalZero NVIC_EnableIRQ(RADIO_IRQn);
1449*042d53a7SEvalZero
1450*042d53a7SEvalZero /* Register phy statistics */
1451*042d53a7SEvalZero if (!g_ble_phy_data.phy_stats_initialized) {
1452*042d53a7SEvalZero rc = stats_init_and_reg(STATS_HDR(ble_phy_stats),
1453*042d53a7SEvalZero STATS_SIZE_INIT_PARMS(ble_phy_stats,
1454*042d53a7SEvalZero STATS_SIZE_32),
1455*042d53a7SEvalZero STATS_NAME_INIT_PARMS(ble_phy_stats),
1456*042d53a7SEvalZero "ble_phy");
1457*042d53a7SEvalZero assert(rc == 0);
1458*042d53a7SEvalZero
1459*042d53a7SEvalZero g_ble_phy_data.phy_stats_initialized = 1;
1460*042d53a7SEvalZero }
1461*042d53a7SEvalZero
1462*042d53a7SEvalZero ble_phy_dbg_time_setup();
1463*042d53a7SEvalZero
1464*042d53a7SEvalZero return 0;
1465*042d53a7SEvalZero }
1466*042d53a7SEvalZero
1467*042d53a7SEvalZero /**
1468*042d53a7SEvalZero * Puts the phy into receive mode.
1469*042d53a7SEvalZero *
1470*042d53a7SEvalZero * @return int 0: success; BLE Phy error code otherwise
1471*042d53a7SEvalZero */
1472*042d53a7SEvalZero int
ble_phy_rx(void)1473*042d53a7SEvalZero ble_phy_rx(void)
1474*042d53a7SEvalZero {
1475*042d53a7SEvalZero /*
1476*042d53a7SEvalZero * Check radio state.
1477*042d53a7SEvalZero *
1478*042d53a7SEvalZero * In case radio is now disabling we'll wait for it to finish, but if for
1479*042d53a7SEvalZero * any reason it's just in idle state we proceed with RX as usual since
1480*042d53a7SEvalZero * nRF52 radio can ramp-up from idle state as well.
1481*042d53a7SEvalZero *
1482*042d53a7SEvalZero * Note that TX and RX states values are the same except for 3rd bit so we
1483*042d53a7SEvalZero * can make a shortcut here when checking for idle state.
1484*042d53a7SEvalZero */
1485*042d53a7SEvalZero nrf_wait_disabled();
1486*042d53a7SEvalZero if ((NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) &&
1487*042d53a7SEvalZero ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) {
1488*042d53a7SEvalZero ble_phy_disable();
1489*042d53a7SEvalZero STATS_INC(ble_phy_stats, radio_state_errs);
1490*042d53a7SEvalZero return BLE_PHY_ERR_RADIO_STATE;
1491*042d53a7SEvalZero }
1492*042d53a7SEvalZero
1493*042d53a7SEvalZero /* Make sure all interrupts are disabled */
1494*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
1495*042d53a7SEvalZero
1496*042d53a7SEvalZero /* Clear events prior to enabling receive */
1497*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
1498*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
1499*042d53a7SEvalZero
1500*042d53a7SEvalZero /* Setup for rx */
1501*042d53a7SEvalZero ble_phy_rx_xcvr_setup();
1502*042d53a7SEvalZero
1503*042d53a7SEvalZero /* PPI to start radio automatically shall be set here */
1504*042d53a7SEvalZero assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk);
1505*042d53a7SEvalZero
1506*042d53a7SEvalZero return 0;
1507*042d53a7SEvalZero }
1508*042d53a7SEvalZero
1509*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1510*042d53a7SEvalZero /**
1511*042d53a7SEvalZero * Called to enable encryption at the PHY. Note that this state will persist
1512*042d53a7SEvalZero * in the PHY; in other words, if you call this function you have to call
1513*042d53a7SEvalZero * disable so that future PHY transmits/receives will not be encrypted.
1514*042d53a7SEvalZero *
1515*042d53a7SEvalZero * @param pkt_counter
1516*042d53a7SEvalZero * @param iv
1517*042d53a7SEvalZero * @param key
1518*042d53a7SEvalZero * @param is_master
1519*042d53a7SEvalZero */
1520*042d53a7SEvalZero void
ble_phy_encrypt_enable(uint64_t pkt_counter,uint8_t * iv,uint8_t * key,uint8_t is_master)1521*042d53a7SEvalZero ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
1522*042d53a7SEvalZero uint8_t is_master)
1523*042d53a7SEvalZero {
1524*042d53a7SEvalZero memcpy(g_nrf_ccm_data.key, key, 16);
1525*042d53a7SEvalZero g_nrf_ccm_data.pkt_counter = pkt_counter;
1526*042d53a7SEvalZero memcpy(g_nrf_ccm_data.iv, iv, 8);
1527*042d53a7SEvalZero g_nrf_ccm_data.dir_bit = is_master;
1528*042d53a7SEvalZero g_ble_phy_data.phy_encrypted = 1;
1529*042d53a7SEvalZero /* Enable the module (AAR cannot be on while CCM on) */
1530*042d53a7SEvalZero NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
1531*042d53a7SEvalZero NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
1532*042d53a7SEvalZero }
1533*042d53a7SEvalZero
1534*042d53a7SEvalZero void
ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter,int dir)1535*042d53a7SEvalZero ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
1536*042d53a7SEvalZero {
1537*042d53a7SEvalZero g_nrf_ccm_data.pkt_counter = pkt_counter;
1538*042d53a7SEvalZero g_nrf_ccm_data.dir_bit = dir;
1539*042d53a7SEvalZero }
1540*042d53a7SEvalZero
1541*042d53a7SEvalZero void
ble_phy_encrypt_disable(void)1542*042d53a7SEvalZero ble_phy_encrypt_disable(void)
1543*042d53a7SEvalZero {
1544*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk;
1545*042d53a7SEvalZero NRF_CCM->TASKS_STOP = 1;
1546*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
1547*042d53a7SEvalZero NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
1548*042d53a7SEvalZero
1549*042d53a7SEvalZero g_ble_phy_data.phy_encrypted = 0;
1550*042d53a7SEvalZero }
1551*042d53a7SEvalZero #endif
1552*042d53a7SEvalZero
1553*042d53a7SEvalZero void
ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb,void * arg)1554*042d53a7SEvalZero ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
1555*042d53a7SEvalZero {
1556*042d53a7SEvalZero /* Set transmit end callback and arg */
1557*042d53a7SEvalZero g_ble_phy_data.txend_cb = txend_cb;
1558*042d53a7SEvalZero g_ble_phy_data.txend_arg = arg;
1559*042d53a7SEvalZero }
1560*042d53a7SEvalZero
1561*042d53a7SEvalZero /**
1562*042d53a7SEvalZero * Called to set the start time of a transmission.
1563*042d53a7SEvalZero *
1564*042d53a7SEvalZero * This function is called to set the start time when we are not going from
1565*042d53a7SEvalZero * rx to tx automatically.
1566*042d53a7SEvalZero *
1567*042d53a7SEvalZero * NOTE: care must be taken when calling this function. The channel should
1568*042d53a7SEvalZero * already be set.
1569*042d53a7SEvalZero *
1570*042d53a7SEvalZero * @param cputime This is the tick at which the 1st bit of the preamble
1571*042d53a7SEvalZero * should be transmitted
1572*042d53a7SEvalZero * @param rem_usecs This is used only when the underlying timing uses a 32.768
1573*042d53a7SEvalZero * kHz crystal. It is the # of usecs from the cputime tick
1574*042d53a7SEvalZero * at which the first bit of the preamble should be
1575*042d53a7SEvalZero * transmitted.
1576*042d53a7SEvalZero * @return int
1577*042d53a7SEvalZero */
1578*042d53a7SEvalZero int
ble_phy_tx_set_start_time(uint32_t cputime,uint8_t rem_usecs)1579*042d53a7SEvalZero ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
1580*042d53a7SEvalZero {
1581*042d53a7SEvalZero int rc;
1582*042d53a7SEvalZero
1583*042d53a7SEvalZero ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs);
1584*042d53a7SEvalZero
1585*042d53a7SEvalZero /* XXX: This should not be necessary, but paranoia is good! */
1586*042d53a7SEvalZero /* Clear timer0 compare to RXEN since we are transmitting */
1587*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk;
1588*042d53a7SEvalZero
1589*042d53a7SEvalZero if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) {
1590*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_late);
1591*042d53a7SEvalZero ble_phy_disable();
1592*042d53a7SEvalZero rc = BLE_PHY_ERR_TX_LATE;
1593*042d53a7SEvalZero } else {
1594*042d53a7SEvalZero /* Enable PPI to automatically start TXEN */
1595*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
1596*042d53a7SEvalZero rc = 0;
1597*042d53a7SEvalZero }
1598*042d53a7SEvalZero return rc;
1599*042d53a7SEvalZero }
1600*042d53a7SEvalZero
1601*042d53a7SEvalZero /**
1602*042d53a7SEvalZero * Called to set the start time of a reception
1603*042d53a7SEvalZero *
1604*042d53a7SEvalZero * This function acts a bit differently than transmit. If we are late getting
1605*042d53a7SEvalZero * here we will still attempt to receive.
1606*042d53a7SEvalZero *
1607*042d53a7SEvalZero * NOTE: care must be taken when calling this function. The channel should
1608*042d53a7SEvalZero * already be set.
1609*042d53a7SEvalZero *
1610*042d53a7SEvalZero * @param cputime
1611*042d53a7SEvalZero *
1612*042d53a7SEvalZero * @return int
1613*042d53a7SEvalZero */
1614*042d53a7SEvalZero int
ble_phy_rx_set_start_time(uint32_t cputime,uint8_t rem_usecs)1615*042d53a7SEvalZero ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
1616*042d53a7SEvalZero {
1617*042d53a7SEvalZero bool late = false;
1618*042d53a7SEvalZero int rc = 0;
1619*042d53a7SEvalZero
1620*042d53a7SEvalZero ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs);
1621*042d53a7SEvalZero
1622*042d53a7SEvalZero /* XXX: This should not be necessary, but paranoia is good! */
1623*042d53a7SEvalZero /* Clear timer0 compare to TXEN since we are transmitting */
1624*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
1625*042d53a7SEvalZero
1626*042d53a7SEvalZero if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) {
1627*042d53a7SEvalZero STATS_INC(ble_phy_stats, rx_late);
1628*042d53a7SEvalZero
1629*042d53a7SEvalZero /* We're late so let's just try to start RX as soon as possible */
1630*042d53a7SEvalZero ble_phy_set_start_now();
1631*042d53a7SEvalZero
1632*042d53a7SEvalZero late = true;
1633*042d53a7SEvalZero }
1634*042d53a7SEvalZero
1635*042d53a7SEvalZero /* Enable PPI to automatically start RXEN */
1636*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
1637*042d53a7SEvalZero
1638*042d53a7SEvalZero /* Start rx */
1639*042d53a7SEvalZero rc = ble_phy_rx();
1640*042d53a7SEvalZero
1641*042d53a7SEvalZero /*
1642*042d53a7SEvalZero * If we enabled receiver but were late, let's return proper error code so
1643*042d53a7SEvalZero * caller can handle this.
1644*042d53a7SEvalZero */
1645*042d53a7SEvalZero if (!rc && late) {
1646*042d53a7SEvalZero rc = BLE_PHY_ERR_RX_LATE;
1647*042d53a7SEvalZero }
1648*042d53a7SEvalZero
1649*042d53a7SEvalZero return rc;
1650*042d53a7SEvalZero }
1651*042d53a7SEvalZero
1652*042d53a7SEvalZero int
ble_phy_tx(ble_phy_tx_pducb_t pducb,void * pducb_arg,uint8_t end_trans)1653*042d53a7SEvalZero ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
1654*042d53a7SEvalZero {
1655*042d53a7SEvalZero int rc;
1656*042d53a7SEvalZero uint8_t *dptr;
1657*042d53a7SEvalZero uint8_t *pktptr;
1658*042d53a7SEvalZero uint8_t payload_len;
1659*042d53a7SEvalZero uint8_t hdr_byte;
1660*042d53a7SEvalZero uint32_t state;
1661*042d53a7SEvalZero uint32_t shortcuts;
1662*042d53a7SEvalZero
1663*042d53a7SEvalZero if (g_ble_phy_data.phy_transition_late) {
1664*042d53a7SEvalZero ble_phy_disable();
1665*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_late);
1666*042d53a7SEvalZero return BLE_PHY_ERR_TX_LATE;
1667*042d53a7SEvalZero }
1668*042d53a7SEvalZero
1669*042d53a7SEvalZero /*
1670*042d53a7SEvalZero * This check is to make sure that the radio is not in a state where
1671*042d53a7SEvalZero * it is moving to disabled state. If so, let it get there.
1672*042d53a7SEvalZero */
1673*042d53a7SEvalZero nrf_wait_disabled();
1674*042d53a7SEvalZero
1675*042d53a7SEvalZero /*
1676*042d53a7SEvalZero * XXX: Although we may not have to do this here, I clear all the PPI
1677*042d53a7SEvalZero * that should not be used when transmitting. Some of them are only enabled
1678*042d53a7SEvalZero * if encryption and/or privacy is on, but I dont care. Better to be
1679*042d53a7SEvalZero * paranoid, and if you are going to clear one, might as well clear them
1680*042d53a7SEvalZero * all.
1681*042d53a7SEvalZero */
1682*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk |
1683*042d53a7SEvalZero PPI_CHEN_CH25_Msk;
1684*042d53a7SEvalZero
1685*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1686*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
1687*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
1688*042d53a7SEvalZero pktptr = (uint8_t *)&g_ble_phy_tx_buf[0];
1689*042d53a7SEvalZero NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
1690*042d53a7SEvalZero NRF_CCM->INPTR = (uint32_t)dptr;
1691*042d53a7SEvalZero NRF_CCM->OUTPTR = (uint32_t)pktptr;
1692*042d53a7SEvalZero NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
1693*042d53a7SEvalZero NRF_CCM->EVENTS_ERROR = 0;
1694*042d53a7SEvalZero NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate();
1695*042d53a7SEvalZero NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
1696*042d53a7SEvalZero } else {
1697*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
1698*042d53a7SEvalZero NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
1699*042d53a7SEvalZero #endif
1700*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
1701*042d53a7SEvalZero pktptr = dptr;
1702*042d53a7SEvalZero }
1703*042d53a7SEvalZero #else
1704*042d53a7SEvalZero dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
1705*042d53a7SEvalZero pktptr = dptr;
1706*042d53a7SEvalZero #endif
1707*042d53a7SEvalZero
1708*042d53a7SEvalZero /* Set PDU payload */
1709*042d53a7SEvalZero payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte);
1710*042d53a7SEvalZero
1711*042d53a7SEvalZero /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
1712*042d53a7SEvalZero dptr[0] = hdr_byte;
1713*042d53a7SEvalZero dptr[1] = payload_len;
1714*042d53a7SEvalZero dptr[2] = 0;
1715*042d53a7SEvalZero
1716*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) == 1)
1717*042d53a7SEvalZero /* Start key-stream generation and encryption (via short) */
1718*042d53a7SEvalZero if (g_ble_phy_data.phy_encrypted) {
1719*042d53a7SEvalZero NRF_CCM->TASKS_KSGEN = 1;
1720*042d53a7SEvalZero }
1721*042d53a7SEvalZero #endif
1722*042d53a7SEvalZero
1723*042d53a7SEvalZero NRF_RADIO->PACKETPTR = (uint32_t)pktptr;
1724*042d53a7SEvalZero
1725*042d53a7SEvalZero /* Clear the ready, end and disabled events */
1726*042d53a7SEvalZero NRF_RADIO->EVENTS_READY = 0;
1727*042d53a7SEvalZero NRF_RADIO->EVENTS_END = 0;
1728*042d53a7SEvalZero NRF_RADIO->EVENTS_DISABLED = 0;
1729*042d53a7SEvalZero
1730*042d53a7SEvalZero /* Enable shortcuts for transmit start/end. */
1731*042d53a7SEvalZero shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
1732*042d53a7SEvalZero NRF_RADIO->SHORTS = shortcuts;
1733*042d53a7SEvalZero NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk;
1734*042d53a7SEvalZero
1735*042d53a7SEvalZero /* Set the PHY transition */
1736*042d53a7SEvalZero g_ble_phy_data.phy_transition = end_trans;
1737*042d53a7SEvalZero
1738*042d53a7SEvalZero /* Set transmitted payload length */
1739*042d53a7SEvalZero g_ble_phy_data.phy_tx_pyld_len = payload_len;
1740*042d53a7SEvalZero
1741*042d53a7SEvalZero /* If we already started transmitting, abort it! */
1742*042d53a7SEvalZero state = NRF_RADIO->STATE;
1743*042d53a7SEvalZero if (state != RADIO_STATE_STATE_Tx) {
1744*042d53a7SEvalZero /* Set phy state to transmitting and count packet statistics */
1745*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
1746*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_good);
1747*042d53a7SEvalZero STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN);
1748*042d53a7SEvalZero rc = BLE_ERR_SUCCESS;
1749*042d53a7SEvalZero } else {
1750*042d53a7SEvalZero ble_phy_disable();
1751*042d53a7SEvalZero STATS_INC(ble_phy_stats, tx_late);
1752*042d53a7SEvalZero rc = BLE_PHY_ERR_RADIO_STATE;
1753*042d53a7SEvalZero }
1754*042d53a7SEvalZero
1755*042d53a7SEvalZero return rc;
1756*042d53a7SEvalZero }
1757*042d53a7SEvalZero
1758*042d53a7SEvalZero /**
1759*042d53a7SEvalZero * ble phy txpwr set
1760*042d53a7SEvalZero *
1761*042d53a7SEvalZero * Set the transmit output power (in dBm).
1762*042d53a7SEvalZero *
1763*042d53a7SEvalZero * NOTE: If the output power specified is within the BLE limits but outside
1764*042d53a7SEvalZero * the chip limits, we "rail" the power level so we dont exceed the min/max
1765*042d53a7SEvalZero * chip values.
1766*042d53a7SEvalZero *
1767*042d53a7SEvalZero * @param dbm Power output in dBm.
1768*042d53a7SEvalZero *
1769*042d53a7SEvalZero * @return int 0: success; anything else is an error
1770*042d53a7SEvalZero */
1771*042d53a7SEvalZero int
ble_phy_txpwr_set(int dbm)1772*042d53a7SEvalZero ble_phy_txpwr_set(int dbm)
1773*042d53a7SEvalZero {
1774*042d53a7SEvalZero /* Check valid range */
1775*042d53a7SEvalZero assert(dbm <= BLE_PHY_MAX_PWR_DBM);
1776*042d53a7SEvalZero
1777*042d53a7SEvalZero /* "Rail" power level if outside supported range */
1778*042d53a7SEvalZero if (dbm > NRF_TX_PWR_MAX_DBM) {
1779*042d53a7SEvalZero dbm = NRF_TX_PWR_MAX_DBM;
1780*042d53a7SEvalZero } else {
1781*042d53a7SEvalZero if (dbm < NRF_TX_PWR_MIN_DBM) {
1782*042d53a7SEvalZero dbm = NRF_TX_PWR_MIN_DBM;
1783*042d53a7SEvalZero }
1784*042d53a7SEvalZero }
1785*042d53a7SEvalZero
1786*042d53a7SEvalZero NRF_RADIO->TXPOWER = dbm;
1787*042d53a7SEvalZero g_ble_phy_data.phy_txpwr_dbm = dbm;
1788*042d53a7SEvalZero
1789*042d53a7SEvalZero return 0;
1790*042d53a7SEvalZero }
1791*042d53a7SEvalZero
1792*042d53a7SEvalZero /**
1793*042d53a7SEvalZero * ble phy txpwr round
1794*042d53a7SEvalZero *
1795*042d53a7SEvalZero * Get the rounded transmit output power (in dBm).
1796*042d53a7SEvalZero *
1797*042d53a7SEvalZero * @param dbm Power output in dBm.
1798*042d53a7SEvalZero *
1799*042d53a7SEvalZero * @return int Rounded power in dBm
1800*042d53a7SEvalZero */
ble_phy_txpower_round(int dbm)1801*042d53a7SEvalZero int ble_phy_txpower_round(int dbm)
1802*042d53a7SEvalZero {
1803*042d53a7SEvalZero /* "Rail" power level if outside supported range */
1804*042d53a7SEvalZero if (dbm > NRF_TX_PWR_MAX_DBM) {
1805*042d53a7SEvalZero dbm = NRF_TX_PWR_MAX_DBM;
1806*042d53a7SEvalZero } else {
1807*042d53a7SEvalZero if (dbm < NRF_TX_PWR_MIN_DBM) {
1808*042d53a7SEvalZero dbm = NRF_TX_PWR_MIN_DBM;
1809*042d53a7SEvalZero }
1810*042d53a7SEvalZero }
1811*042d53a7SEvalZero
1812*042d53a7SEvalZero return dbm;
1813*042d53a7SEvalZero }
1814*042d53a7SEvalZero
1815*042d53a7SEvalZero /**
1816*042d53a7SEvalZero * ble phy set access addr
1817*042d53a7SEvalZero *
1818*042d53a7SEvalZero * Set access address.
1819*042d53a7SEvalZero *
1820*042d53a7SEvalZero * @param access_addr Access address
1821*042d53a7SEvalZero *
1822*042d53a7SEvalZero * @return int 0: success; PHY error code otherwise
1823*042d53a7SEvalZero */
1824*042d53a7SEvalZero int
ble_phy_set_access_addr(uint32_t access_addr)1825*042d53a7SEvalZero ble_phy_set_access_addr(uint32_t access_addr)
1826*042d53a7SEvalZero {
1827*042d53a7SEvalZero NRF_RADIO->BASE0 = (access_addr << 8);
1828*042d53a7SEvalZero NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24);
1829*042d53a7SEvalZero
1830*042d53a7SEvalZero g_ble_phy_data.phy_access_address = access_addr;
1831*042d53a7SEvalZero
1832*042d53a7SEvalZero #ifdef NRF52
1833*042d53a7SEvalZero ble_phy_apply_errata_102_106_107();
1834*042d53a7SEvalZero #endif
1835*042d53a7SEvalZero
1836*042d53a7SEvalZero return 0;
1837*042d53a7SEvalZero }
1838*042d53a7SEvalZero
1839*042d53a7SEvalZero /**
1840*042d53a7SEvalZero * ble phy txpwr get
1841*042d53a7SEvalZero *
1842*042d53a7SEvalZero * Get the transmit power.
1843*042d53a7SEvalZero *
1844*042d53a7SEvalZero * @return int The current PHY transmit power, in dBm
1845*042d53a7SEvalZero */
1846*042d53a7SEvalZero int
ble_phy_txpwr_get(void)1847*042d53a7SEvalZero ble_phy_txpwr_get(void)
1848*042d53a7SEvalZero {
1849*042d53a7SEvalZero return g_ble_phy_data.phy_txpwr_dbm;
1850*042d53a7SEvalZero }
1851*042d53a7SEvalZero
1852*042d53a7SEvalZero /**
1853*042d53a7SEvalZero * ble phy setchan
1854*042d53a7SEvalZero *
1855*042d53a7SEvalZero * Sets the logical frequency of the transceiver. The input parameter is the
1856*042d53a7SEvalZero * BLE channel index (0 to 39, inclusive). The NRF frequency register works like
1857*042d53a7SEvalZero * this: logical frequency = 2400 + FREQ (MHz).
1858*042d53a7SEvalZero *
1859*042d53a7SEvalZero * Thus, to get a logical frequency of 2402 MHz, you would program the
1860*042d53a7SEvalZero * FREQUENCY register to 2.
1861*042d53a7SEvalZero *
1862*042d53a7SEvalZero * @param chan This is the Data Channel Index or Advertising Channel index
1863*042d53a7SEvalZero *
1864*042d53a7SEvalZero * @return int 0: success; PHY error code otherwise
1865*042d53a7SEvalZero */
1866*042d53a7SEvalZero int
ble_phy_setchan(uint8_t chan,uint32_t access_addr,uint32_t crcinit)1867*042d53a7SEvalZero ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
1868*042d53a7SEvalZero {
1869*042d53a7SEvalZero assert(chan < BLE_PHY_NUM_CHANS);
1870*042d53a7SEvalZero
1871*042d53a7SEvalZero /* Check for valid channel range */
1872*042d53a7SEvalZero if (chan >= BLE_PHY_NUM_CHANS) {
1873*042d53a7SEvalZero return BLE_PHY_ERR_INV_PARAM;
1874*042d53a7SEvalZero }
1875*042d53a7SEvalZero
1876*042d53a7SEvalZero /* Set current access address */
1877*042d53a7SEvalZero ble_phy_set_access_addr(access_addr);
1878*042d53a7SEvalZero
1879*042d53a7SEvalZero /* Configure crcinit */
1880*042d53a7SEvalZero NRF_RADIO->CRCINIT = crcinit;
1881*042d53a7SEvalZero
1882*042d53a7SEvalZero /* Set the frequency and the data whitening initial value */
1883*042d53a7SEvalZero g_ble_phy_data.phy_chan = chan;
1884*042d53a7SEvalZero NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan];
1885*042d53a7SEvalZero NRF_RADIO->DATAWHITEIV = chan;
1886*042d53a7SEvalZero
1887*042d53a7SEvalZero return 0;
1888*042d53a7SEvalZero }
1889*042d53a7SEvalZero
1890*042d53a7SEvalZero /**
1891*042d53a7SEvalZero * Stop the timer used to count microseconds when using RTC for cputime
1892*042d53a7SEvalZero */
1893*042d53a7SEvalZero void
ble_phy_stop_usec_timer(void)1894*042d53a7SEvalZero ble_phy_stop_usec_timer(void)
1895*042d53a7SEvalZero {
1896*042d53a7SEvalZero NRF_TIMER0->TASKS_STOP = 1;
1897*042d53a7SEvalZero NRF_TIMER0->TASKS_SHUTDOWN = 1;
1898*042d53a7SEvalZero NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
1899*042d53a7SEvalZero }
1900*042d53a7SEvalZero
1901*042d53a7SEvalZero /**
1902*042d53a7SEvalZero * ble phy disable irq and ppi
1903*042d53a7SEvalZero *
1904*042d53a7SEvalZero * This routine is to be called when reception was stopped due to either a
1905*042d53a7SEvalZero * wait for response timeout or a packet being received and the phy is to be
1906*042d53a7SEvalZero * restarted in receive mode. Generally, the disable routine is called to stop
1907*042d53a7SEvalZero * the phy.
1908*042d53a7SEvalZero */
1909*042d53a7SEvalZero void
ble_phy_disable_irq_and_ppi(void)1910*042d53a7SEvalZero ble_phy_disable_irq_and_ppi(void)
1911*042d53a7SEvalZero {
1912*042d53a7SEvalZero NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
1913*042d53a7SEvalZero NRF_RADIO->SHORTS = 0;
1914*042d53a7SEvalZero NRF_RADIO->TASKS_DISABLE = 1;
1915*042d53a7SEvalZero NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk |
1916*042d53a7SEvalZero PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk |
1917*042d53a7SEvalZero PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk;
1918*042d53a7SEvalZero NVIC_ClearPendingIRQ(RADIO_IRQn);
1919*042d53a7SEvalZero g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
1920*042d53a7SEvalZero }
1921*042d53a7SEvalZero
1922*042d53a7SEvalZero void
ble_phy_restart_rx(void)1923*042d53a7SEvalZero ble_phy_restart_rx(void)
1924*042d53a7SEvalZero {
1925*042d53a7SEvalZero ble_phy_disable_irq_and_ppi();
1926*042d53a7SEvalZero
1927*042d53a7SEvalZero ble_phy_set_start_now();
1928*042d53a7SEvalZero /* Enable PPI to automatically start RXEN */
1929*042d53a7SEvalZero NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
1930*042d53a7SEvalZero
1931*042d53a7SEvalZero ble_phy_rx();
1932*042d53a7SEvalZero }
1933*042d53a7SEvalZero
1934*042d53a7SEvalZero /**
1935*042d53a7SEvalZero * ble phy disable
1936*042d53a7SEvalZero *
1937*042d53a7SEvalZero * Disables the PHY. This should be called when an event is over. It stops
1938*042d53a7SEvalZero * the usec timer (if used), disables interrupts, disables the RADIO, disables
1939*042d53a7SEvalZero * PPI and sets state to idle.
1940*042d53a7SEvalZero */
1941*042d53a7SEvalZero void
ble_phy_disable(void)1942*042d53a7SEvalZero ble_phy_disable(void)
1943*042d53a7SEvalZero {
1944*042d53a7SEvalZero ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE);
1945*042d53a7SEvalZero
1946*042d53a7SEvalZero ble_phy_stop_usec_timer();
1947*042d53a7SEvalZero ble_phy_disable_irq_and_ppi();
1948*042d53a7SEvalZero }
1949*042d53a7SEvalZero
1950*042d53a7SEvalZero /* Gets the current access address */
ble_phy_access_addr_get(void)1951*042d53a7SEvalZero uint32_t ble_phy_access_addr_get(void)
1952*042d53a7SEvalZero {
1953*042d53a7SEvalZero return g_ble_phy_data.phy_access_address;
1954*042d53a7SEvalZero }
1955*042d53a7SEvalZero
1956*042d53a7SEvalZero /**
1957*042d53a7SEvalZero * Return the phy state
1958*042d53a7SEvalZero *
1959*042d53a7SEvalZero * @return int The current PHY state.
1960*042d53a7SEvalZero */
1961*042d53a7SEvalZero int
ble_phy_state_get(void)1962*042d53a7SEvalZero ble_phy_state_get(void)
1963*042d53a7SEvalZero {
1964*042d53a7SEvalZero return g_ble_phy_data.phy_state;
1965*042d53a7SEvalZero }
1966*042d53a7SEvalZero
1967*042d53a7SEvalZero /**
1968*042d53a7SEvalZero * Called to see if a reception has started
1969*042d53a7SEvalZero *
1970*042d53a7SEvalZero * @return int
1971*042d53a7SEvalZero */
1972*042d53a7SEvalZero int
ble_phy_rx_started(void)1973*042d53a7SEvalZero ble_phy_rx_started(void)
1974*042d53a7SEvalZero {
1975*042d53a7SEvalZero return g_ble_phy_data.phy_rx_started;
1976*042d53a7SEvalZero }
1977*042d53a7SEvalZero
1978*042d53a7SEvalZero /**
1979*042d53a7SEvalZero * Return the transceiver state
1980*042d53a7SEvalZero *
1981*042d53a7SEvalZero * @return int transceiver state.
1982*042d53a7SEvalZero */
1983*042d53a7SEvalZero uint8_t
ble_phy_xcvr_state_get(void)1984*042d53a7SEvalZero ble_phy_xcvr_state_get(void)
1985*042d53a7SEvalZero {
1986*042d53a7SEvalZero uint32_t state;
1987*042d53a7SEvalZero state = NRF_RADIO->STATE;
1988*042d53a7SEvalZero return (uint8_t)state;
1989*042d53a7SEvalZero }
1990*042d53a7SEvalZero
1991*042d53a7SEvalZero /**
1992*042d53a7SEvalZero * Called to return the maximum data pdu payload length supported by the
1993*042d53a7SEvalZero * phy. For this chip, if encryption is enabled, the maximum payload is 27
1994*042d53a7SEvalZero * bytes.
1995*042d53a7SEvalZero *
1996*042d53a7SEvalZero * @return uint8_t Maximum data channel PDU payload size supported
1997*042d53a7SEvalZero */
1998*042d53a7SEvalZero uint8_t
ble_phy_max_data_pdu_pyld(void)1999*042d53a7SEvalZero ble_phy_max_data_pdu_pyld(void)
2000*042d53a7SEvalZero {
2001*042d53a7SEvalZero return BLE_LL_DATA_PDU_MAX_PYLD;
2002*042d53a7SEvalZero }
2003*042d53a7SEvalZero
2004*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
2005*042d53a7SEvalZero void
ble_phy_resolv_list_enable(void)2006*042d53a7SEvalZero ble_phy_resolv_list_enable(void)
2007*042d53a7SEvalZero {
2008*042d53a7SEvalZero NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks;
2009*042d53a7SEvalZero g_ble_phy_data.phy_privacy = 1;
2010*042d53a7SEvalZero }
2011*042d53a7SEvalZero
2012*042d53a7SEvalZero void
ble_phy_resolv_list_disable(void)2013*042d53a7SEvalZero ble_phy_resolv_list_disable(void)
2014*042d53a7SEvalZero {
2015*042d53a7SEvalZero g_ble_phy_data.phy_privacy = 0;
2016*042d53a7SEvalZero }
2017*042d53a7SEvalZero #endif
2018*042d53a7SEvalZero
2019*042d53a7SEvalZero #if MYNEWT_VAL(BLE_LL_DIRECT_TEST_MODE) == 1
ble_phy_enable_dtm(void)2020*042d53a7SEvalZero void ble_phy_enable_dtm(void)
2021*042d53a7SEvalZero {
2022*042d53a7SEvalZero /* When DTM is enabled we need to disable whitening as per
2023*042d53a7SEvalZero * Bluetooth v5.0 Vol 6. Part F. 4.1.1
2024*042d53a7SEvalZero */
2025*042d53a7SEvalZero NRF_RADIO->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk;
2026*042d53a7SEvalZero }
2027*042d53a7SEvalZero
ble_phy_disable_dtm(void)2028*042d53a7SEvalZero void ble_phy_disable_dtm(void)
2029*042d53a7SEvalZero {
2030*042d53a7SEvalZero /* Enable whitening */
2031*042d53a7SEvalZero NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk;
2032*042d53a7SEvalZero }
2033*042d53a7SEvalZero #endif
2034*042d53a7SEvalZero
2035*042d53a7SEvalZero void
ble_phy_rfclk_enable(void)2036*042d53a7SEvalZero ble_phy_rfclk_enable(void)
2037*042d53a7SEvalZero {
2038*042d53a7SEvalZero #if MYNEWT
2039*042d53a7SEvalZero nrf52_clock_hfxo_request();
2040*042d53a7SEvalZero #else
2041*042d53a7SEvalZero NRF_CLOCK->TASKS_HFCLKSTART = 1;
2042*042d53a7SEvalZero #endif
2043*042d53a7SEvalZero }
2044*042d53a7SEvalZero
2045*042d53a7SEvalZero void
ble_phy_rfclk_disable(void)2046*042d53a7SEvalZero ble_phy_rfclk_disable(void)
2047*042d53a7SEvalZero {
2048*042d53a7SEvalZero #if MYNEWT
2049*042d53a7SEvalZero nrf52_clock_hfxo_release();
2050*042d53a7SEvalZero #else
2051*042d53a7SEvalZero NRF_CLOCK->TASKS_HFCLKSTOP = 1;
2052*042d53a7SEvalZero #endif
2053*042d53a7SEvalZero }
2054