mbed library sources

Dependents:   Encrypted my_mbed lklk CyaSSL_DTLS_Cellular ... more

Superseded

This library was superseded by mbed-dev - https://os.mbed.com/users/mbed_official/code/mbed-dev/.

Development branch of the mbed library sources. This library is kept in synch with the latest changes from the mbed SDK and it is not guaranteed to work.

If you are looking for a stable and tested release, please import one of the official mbed library releases:

Import librarymbed

The official Mbed 2 C/C++ SDK provides the software platform and libraries to build your applications.

Committer:
mbed_official
Date:
Fri Mar 20 09:30:08 2015 +0000
Revision:
495:01cb89f68337
Parent:
453:a290c6acf95e
Child:
603:3c75ef011213
Synchronized with git revision d1d900d30c656b1f35f4f5db49e47ea199b0b8d6

Full URL: https://github.com/mbedmicro/mbed/commit/d1d900d30c656b1f35f4f5db49e47ea199b0b8d6/

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 85:e1a8e879a6a9 1 /* mbed Microcontroller Library
mbed_official 104:a6a92e2e5a92 2 * Copyright (c) 2013 Nordic Semiconductor
mbed_official 85:e1a8e879a6a9 3 *
mbed_official 85:e1a8e879a6a9 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 85:e1a8e879a6a9 5 * you may not use this file except in compliance with the License.
mbed_official 85:e1a8e879a6a9 6 * You may obtain a copy of the License at
mbed_official 85:e1a8e879a6a9 7 *
mbed_official 85:e1a8e879a6a9 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 85:e1a8e879a6a9 9 *
mbed_official 85:e1a8e879a6a9 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 85:e1a8e879a6a9 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 85:e1a8e879a6a9 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 85:e1a8e879a6a9 13 * See the License for the specific language governing permissions and
mbed_official 85:e1a8e879a6a9 14 * limitations under the License.
mbed_official 85:e1a8e879a6a9 15 */
mbed_official 85:e1a8e879a6a9 16 #include <stddef.h>
mbed_official 495:01cb89f68337 17 #include <stdbool.h>
mbed_official 85:e1a8e879a6a9 18 #include "us_ticker_api.h"
mbed_official 85:e1a8e879a6a9 19 #include "cmsis.h"
mbed_official 85:e1a8e879a6a9 20 #include "PeripheralNames.h"
mbed_official 495:01cb89f68337 21 #include "nrf_delay.h"
mbed_official 495:01cb89f68337 22
mbed_official 495:01cb89f68337 23 /*
mbed_official 495:01cb89f68337 24 * Note: The micro-second timer API on the nRF51 platform is implemented using
mbed_official 495:01cb89f68337 25 * the RTC counter run at 32kHz (sourced from an external oscillator). This is
mbed_official 495:01cb89f68337 26 * a trade-off between precision and power. Running a normal 32-bit MCU counter
mbed_official 495:01cb89f68337 27 * at high frequency causes the average power consumption to rise to a few
mbed_official 495:01cb89f68337 28 * hundred micro-amps, which is prohibitive for typical low-power BLE
mbed_official 495:01cb89f68337 29 * applications.
mbed_official 495:01cb89f68337 30 * A 32kHz clock doesn't offer the precision needed for keeping u-second time,
mbed_official 495:01cb89f68337 31 * but we're assuming that this will not be a problem for the average user.
mbed_official 495:01cb89f68337 32 */
mbed_official 495:01cb89f68337 33
mbed_official 495:01cb89f68337 34 #define MAX_RTC_COUNTER_VAL 0x00FFFFFF /**< Maximum value of the RTC counter. */
mbed_official 495:01cb89f68337 35 #define RTC_CLOCK_FREQ (uint32_t)(32768)
mbed_official 495:01cb89f68337 36 #define RTC1_IRQ_PRI 3 /**< Priority of the RTC1 interrupt (used
mbed_official 495:01cb89f68337 37 * for checking for timeouts and executing
mbed_official 495:01cb89f68337 38 * timeout handlers). This must be the same
mbed_official 495:01cb89f68337 39 * as APP_IRQ_PRIORITY_LOW; taken from the
mbed_official 495:01cb89f68337 40 * Nordic SDK. */
mbed_official 495:01cb89f68337 41 #define MAX_RTC_TASKS_DELAY 47 /**< Maximum delay until an RTC task is executed. */
mbed_official 495:01cb89f68337 42
mbed_official 495:01cb89f68337 43 #define FUZZY_RTC_TICKS 2 /* RTC COMPARE occurs when a CC register is N and the RTC
mbed_official 495:01cb89f68337 44 * COUNTER value transitions from N-1 to N. If we're trying to
mbed_official 495:01cb89f68337 45 * setup a callback for a time which will arrive very shortly,
mbed_official 495:01cb89f68337 46 * there are limits to how short the callback interval may be for us
mbed_official 495:01cb89f68337 47 * to rely upon the RTC Compare trigger. If the COUNTER is N,
mbed_official 495:01cb89f68337 48 * writing N+2 to a CC register is guaranteed to trigger a COMPARE
mbed_official 495:01cb89f68337 49 * event at N+2. */
mbed_official 495:01cb89f68337 50
mbed_official 495:01cb89f68337 51 #define RTC_UNITS_TO_MICROSECONDS(RTC_UNITS) (((RTC_UNITS) * (uint64_t)1000000) / RTC_CLOCK_FREQ)
mbed_official 495:01cb89f68337 52 #define MICROSECONDS_TO_RTC_UNITS(MICROS) ((((uint64_t)(MICROS) * RTC_CLOCK_FREQ) + 999999) / 1000000)
mbed_official 495:01cb89f68337 53
mbed_official 495:01cb89f68337 54 static bool us_ticker_inited = false;
mbed_official 495:01cb89f68337 55 static volatile uint32_t overflowCount; /**< The number of times the 24-bit RTC counter has overflowed. */
mbed_official 495:01cb89f68337 56 static volatile bool us_ticker_callbackPending = false;
mbed_official 495:01cb89f68337 57 static uint32_t us_ticker_callbackTimestamp;
mbed_official 495:01cb89f68337 58
mbed_official 495:01cb89f68337 59 static inline void rtc1_enableCompareInterrupt(void)
mbed_official 495:01cb89f68337 60 {
mbed_official 495:01cb89f68337 61 NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
mbed_official 495:01cb89f68337 62 NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk;
mbed_official 495:01cb89f68337 63 }
mbed_official 495:01cb89f68337 64
mbed_official 495:01cb89f68337 65 static inline void rtc1_disableCompareInterrupt(void)
mbed_official 495:01cb89f68337 66 {
mbed_official 495:01cb89f68337 67 NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
mbed_official 495:01cb89f68337 68 NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
mbed_official 495:01cb89f68337 69 }
mbed_official 495:01cb89f68337 70
mbed_official 495:01cb89f68337 71 static inline void rtc1_enableOverflowInterrupt(void)
mbed_official 495:01cb89f68337 72 {
mbed_official 495:01cb89f68337 73 NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
mbed_official 495:01cb89f68337 74 NRF_RTC1->INTENSET = RTC_INTENSET_OVRFLW_Msk;
mbed_official 495:01cb89f68337 75 }
mbed_official 495:01cb89f68337 76
mbed_official 495:01cb89f68337 77 static inline void rtc1_disableOverflowInterrupt(void)
mbed_official 495:01cb89f68337 78 {
mbed_official 495:01cb89f68337 79 NRF_RTC1->INTENCLR = RTC_INTENSET_OVRFLW_Msk;
mbed_official 495:01cb89f68337 80 NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
mbed_official 495:01cb89f68337 81 }
mbed_official 495:01cb89f68337 82
mbed_official 495:01cb89f68337 83 static inline void invokeCallback(void)
mbed_official 495:01cb89f68337 84 {
mbed_official 495:01cb89f68337 85 us_ticker_callbackPending = false;
mbed_official 495:01cb89f68337 86 rtc1_disableCompareInterrupt();
mbed_official 495:01cb89f68337 87 us_ticker_irq_handler();
mbed_official 495:01cb89f68337 88 }
mbed_official 127:ce7cebc0511f 89
mbed_official 495:01cb89f68337 90 /**
mbed_official 495:01cb89f68337 91 * @brief Function for starting the RTC1 timer. The RTC timer is expected to
mbed_official 495:01cb89f68337 92 * keep running--some interrupts may be disabled temporarily.
mbed_official 495:01cb89f68337 93 */
mbed_official 495:01cb89f68337 94 static void rtc1_start()
mbed_official 495:01cb89f68337 95 {
mbed_official 495:01cb89f68337 96 NRF_RTC1->PRESCALER = 0; /* for no pre-scaling. */
mbed_official 495:01cb89f68337 97
mbed_official 495:01cb89f68337 98 rtc1_enableOverflowInterrupt();
mbed_official 495:01cb89f68337 99
mbed_official 495:01cb89f68337 100 NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI);
mbed_official 495:01cb89f68337 101 NVIC_ClearPendingIRQ(RTC1_IRQn);
mbed_official 495:01cb89f68337 102 NVIC_EnableIRQ(RTC1_IRQn);
mbed_official 495:01cb89f68337 103
mbed_official 495:01cb89f68337 104 NRF_RTC1->TASKS_START = 1;
mbed_official 495:01cb89f68337 105 nrf_delay_us(MAX_RTC_TASKS_DELAY);
mbed_official 495:01cb89f68337 106 }
mbed_official 495:01cb89f68337 107
mbed_official 495:01cb89f68337 108 /**
mbed_official 495:01cb89f68337 109 * @brief Function for stopping the RTC1 timer. We don't expect to call this.
mbed_official 495:01cb89f68337 110 */
mbed_official 495:01cb89f68337 111 void rtc1_stop(void)
mbed_official 495:01cb89f68337 112 {
mbed_official 495:01cb89f68337 113 NVIC_DisableIRQ(RTC1_IRQn);
mbed_official 495:01cb89f68337 114 rtc1_disableCompareInterrupt();
mbed_official 495:01cb89f68337 115 rtc1_disableOverflowInterrupt();
mbed_official 495:01cb89f68337 116
mbed_official 495:01cb89f68337 117 NRF_RTC1->TASKS_STOP = 1;
mbed_official 495:01cb89f68337 118 nrf_delay_us(MAX_RTC_TASKS_DELAY);
mbed_official 495:01cb89f68337 119
mbed_official 495:01cb89f68337 120 NRF_RTC1->TASKS_CLEAR = 1;
mbed_official 495:01cb89f68337 121 nrf_delay_us(MAX_RTC_TASKS_DELAY);
mbed_official 495:01cb89f68337 122 }
mbed_official 495:01cb89f68337 123
mbed_official 495:01cb89f68337 124 /**
mbed_official 495:01cb89f68337 125 * @brief Function for returning the current value of the RTC1 counter.
mbed_official 495:01cb89f68337 126 *
mbed_official 495:01cb89f68337 127 * @return Current RTC1 counter as a 64-bit value with 56-bit precision (even
mbed_official 495:01cb89f68337 128 * though the underlying counter is 24-bit)
mbed_official 495:01cb89f68337 129 */
mbed_official 495:01cb89f68337 130 static inline uint64_t rtc1_getCounter64(void)
mbed_official 495:01cb89f68337 131 {
mbed_official 495:01cb89f68337 132 if (NRF_RTC1->EVENTS_OVRFLW) {
mbed_official 495:01cb89f68337 133 overflowCount++;
mbed_official 495:01cb89f68337 134 NRF_RTC1->EVENTS_OVRFLW = 0;
mbed_official 495:01cb89f68337 135 NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
mbed_official 495:01cb89f68337 136 }
mbed_official 495:01cb89f68337 137 return ((uint64_t)overflowCount << 24) | NRF_RTC1->COUNTER;
mbed_official 495:01cb89f68337 138 }
mbed_official 495:01cb89f68337 139
mbed_official 495:01cb89f68337 140 /**
mbed_official 495:01cb89f68337 141 * @brief Function for returning the current value of the RTC1 counter.
mbed_official 495:01cb89f68337 142 *
mbed_official 495:01cb89f68337 143 * @return Current RTC1 counter as a 32-bit value (even though the underlying counter is 24-bit)
mbed_official 495:01cb89f68337 144 */
mbed_official 495:01cb89f68337 145 static inline uint32_t rtc1_getCounter(void)
mbed_official 495:01cb89f68337 146 {
mbed_official 495:01cb89f68337 147 return rtc1_getCounter64();
mbed_official 495:01cb89f68337 148 }
mbed_official 495:01cb89f68337 149
mbed_official 495:01cb89f68337 150 /**
mbed_official 495:01cb89f68337 151 * @brief Function for handling the RTC1 interrupt.
mbed_official 495:01cb89f68337 152 *
mbed_official 495:01cb89f68337 153 * @details Checks for timeouts, and executes timeout handlers for expired timers.
mbed_official 495:01cb89f68337 154 */
mbed_official 495:01cb89f68337 155 void RTC1_IRQHandler(void)
mbed_official 495:01cb89f68337 156 {
mbed_official 495:01cb89f68337 157 if (NRF_RTC1->EVENTS_OVRFLW) {
mbed_official 495:01cb89f68337 158 overflowCount++;
mbed_official 495:01cb89f68337 159 NRF_RTC1->EVENTS_OVRFLW = 0;
mbed_official 495:01cb89f68337 160 NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
mbed_official 495:01cb89f68337 161 }
mbed_official 495:01cb89f68337 162 if (NRF_RTC1->EVENTS_COMPARE[0] && us_ticker_callbackPending && ((int)(us_ticker_callbackTimestamp - rtc1_getCounter()) <= 0)) {
mbed_official 495:01cb89f68337 163 NRF_RTC1->EVENTS_COMPARE[0] = 0;
mbed_official 495:01cb89f68337 164 NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
mbed_official 495:01cb89f68337 165 invokeCallback();
mbed_official 495:01cb89f68337 166 }
mbed_official 495:01cb89f68337 167 }
mbed_official 300:55638feb26a4 168
mbed_official 300:55638feb26a4 169 void us_ticker_init(void)
mbed_official 300:55638feb26a4 170 {
mbed_official 304:89b9c3a9a045 171 if (us_ticker_inited) {
mbed_official 85:e1a8e879a6a9 172 return;
mbed_official 85:e1a8e879a6a9 173 }
mbed_official 300:55638feb26a4 174
mbed_official 495:01cb89f68337 175 rtc1_start();
mbed_official 304:89b9c3a9a045 176 us_ticker_inited = true;
mbed_official 85:e1a8e879a6a9 177 }
mbed_official 85:e1a8e879a6a9 178
mbed_official 300:55638feb26a4 179 uint32_t us_ticker_read()
mbed_official 300:55638feb26a4 180 {
mbed_official 304:89b9c3a9a045 181 if (!us_ticker_inited) {
mbed_official 304:89b9c3a9a045 182 us_ticker_init();
mbed_official 304:89b9c3a9a045 183 }
mbed_official 304:89b9c3a9a045 184
mbed_official 495:01cb89f68337 185 /* Return a pseudo microsecond counter value. This is only as precise as the
mbed_official 495:01cb89f68337 186 * 32khz low-freq clock source, but could be adequate.*/
mbed_official 495:01cb89f68337 187 return RTC_UNITS_TO_MICROSECONDS(rtc1_getCounter64());
mbed_official 304:89b9c3a9a045 188 }
mbed_official 304:89b9c3a9a045 189
mbed_official 495:01cb89f68337 190 /**
mbed_official 495:01cb89f68337 191 * Setup the us_ticker callback interrupt to go at the given timestamp.
mbed_official 495:01cb89f68337 192 *
mbed_official 495:01cb89f68337 193 * @Note: Only one callback is pending at any time.
mbed_official 495:01cb89f68337 194 *
mbed_official 495:01cb89f68337 195 * @Note: If a callback is pending, and this function is called again, the new
mbed_official 495:01cb89f68337 196 * callback-time overrides the existing callback setting. It is the caller's
mbed_official 495:01cb89f68337 197 * responsibility to ensure that this function is called to setup a callback for
mbed_official 495:01cb89f68337 198 * the earliest timeout.
mbed_official 495:01cb89f68337 199 *
mbed_official 495:01cb89f68337 200 * @Note: If this function is used to setup an interrupt which is immediately
mbed_official 495:01cb89f68337 201 * pending--such as for 'now' or a time in the past,--then the callback is
mbed_official 495:01cb89f68337 202 * invoked a few ticks later.
mbed_official 495:01cb89f68337 203 */
mbed_official 304:89b9c3a9a045 204 void us_ticker_set_interrupt(timestamp_t timestamp)
mbed_official 304:89b9c3a9a045 205 {
mbed_official 304:89b9c3a9a045 206 if (!us_ticker_inited) {
mbed_official 85:e1a8e879a6a9 207 us_ticker_init();
mbed_official 85:e1a8e879a6a9 208 }
mbed_official 300:55638feb26a4 209
mbed_official 495:01cb89f68337 210 /*
mbed_official 495:01cb89f68337 211 * The argument to this function is a 32-bit microsecond timestamp for when
mbed_official 495:01cb89f68337 212 * a callback should be invoked. On the nRF51, we use an RTC timer running
mbed_official 495:01cb89f68337 213 * at 32kHz to implement a low-power us-ticker. This results in a problem
mbed_official 495:01cb89f68337 214 * based on the fact that 1000000 is not a multiple of 32768.
mbed_official 495:01cb89f68337 215 *
mbed_official 495:01cb89f68337 216 * Going from a micro-second based timestamp to a 32kHz based RTC-time is a
mbed_official 495:01cb89f68337 217 * linear mapping; but this mapping doesn't preserve wraparounds--i.e. when
mbed_official 495:01cb89f68337 218 * the 32-bit micro-second timestamp wraps around unfortunately the
mbed_official 495:01cb89f68337 219 * underlying RTC counter doesn't. The result is that timestamp expiry
mbed_official 495:01cb89f68337 220 * checks on micro-second timestamps don't yield the same result when
mbed_official 495:01cb89f68337 221 * applied on the corresponding RTC timestamp values.
mbed_official 495:01cb89f68337 222 *
mbed_official 495:01cb89f68337 223 * One solution is to translate the incoming 32-bit timestamp into a virtual
mbed_official 495:01cb89f68337 224 * 64-bit timestamp based on the knowledge of system-uptime, and then use
mbed_official 495:01cb89f68337 225 * this wraparound-free 64-bit value to do a linear mapping to RTC time.
mbed_official 495:01cb89f68337 226 * System uptime on an nRF is maintained using the 24-bit RTC counter. We
mbed_official 495:01cb89f68337 227 * track the overflow count to extend the 24-bit hardware counter by an
mbed_official 495:01cb89f68337 228 * additional 32 bits. RTC_UNITS_TO_MICROSECONDS() converts this into
mbed_official 495:01cb89f68337 229 * microsecond units (in 64-bits).
mbed_official 495:01cb89f68337 230 */
mbed_official 495:01cb89f68337 231 const uint64_t currentTime64 = RTC_UNITS_TO_MICROSECONDS(rtc1_getCounter64());
mbed_official 495:01cb89f68337 232 uint64_t timestamp64 = (currentTime64 & ~(uint64_t)0xFFFFFFFFULL) + timestamp;
mbed_official 495:01cb89f68337 233 if (((uint32_t)currentTime64 > 0x80000000) && (timestamp < 0x80000000)) {
mbed_official 495:01cb89f68337 234 timestamp64 += (uint64_t)0x100000000ULL;
mbed_official 300:55638feb26a4 235 }
mbed_official 495:01cb89f68337 236 uint32_t newCallbackTime = MICROSECONDS_TO_RTC_UNITS(timestamp64);
mbed_official 85:e1a8e879a6a9 237
mbed_official 495:01cb89f68337 238 /* Check for repeat setup of an existing callback. This is actually not
mbed_official 495:01cb89f68337 239 * important; the following code should work even without this check. */
mbed_official 495:01cb89f68337 240 if (us_ticker_callbackPending && (newCallbackTime == us_ticker_callbackTimestamp)) {
mbed_official 304:89b9c3a9a045 241 return;
mbed_official 300:55638feb26a4 242 }
mbed_official 300:55638feb26a4 243
mbed_official 495:01cb89f68337 244 /* Check for callbacks which are immediately (or will *very* shortly become) pending.
mbed_official 495:01cb89f68337 245 * Even if they are immediately pending, they are scheduled to trigger a few
mbed_official 495:01cb89f68337 246 * ticks later. This keeps things simple by invoking the callback from an
mbed_official 495:01cb89f68337 247 * independent interrupt context. */
mbed_official 495:01cb89f68337 248 if ((int)(newCallbackTime - rtc1_getCounter()) <= (int)FUZZY_RTC_TICKS) {
mbed_official 495:01cb89f68337 249 newCallbackTime = rtc1_getCounter() + FUZZY_RTC_TICKS;
mbed_official 300:55638feb26a4 250 }
mbed_official 361:56c2a6244bba 251
mbed_official 495:01cb89f68337 252 NRF_RTC1->CC[0] = newCallbackTime & MAX_RTC_COUNTER_VAL;
mbed_official 495:01cb89f68337 253 us_ticker_callbackTimestamp = newCallbackTime;
mbed_official 495:01cb89f68337 254 if (!us_ticker_callbackPending) {
mbed_official 495:01cb89f68337 255 us_ticker_callbackPending = true;
mbed_official 495:01cb89f68337 256 rtc1_enableCompareInterrupt();
mbed_official 361:56c2a6244bba 257 }
mbed_official 85:e1a8e879a6a9 258 }
mbed_official 85:e1a8e879a6a9 259
mbed_official 300:55638feb26a4 260 void us_ticker_disable_interrupt(void)
mbed_official 300:55638feb26a4 261 {
mbed_official 495:01cb89f68337 262 if (us_ticker_callbackPending) {
mbed_official 495:01cb89f68337 263 rtc1_disableCompareInterrupt();
mbed_official 495:01cb89f68337 264 us_ticker_callbackPending = false;
mbed_official 304:89b9c3a9a045 265 }
mbed_official 85:e1a8e879a6a9 266 }
mbed_official 300:55638feb26a4 267
mbed_official 300:55638feb26a4 268 void us_ticker_clear_interrupt(void)
mbed_official 300:55638feb26a4 269 {
mbed_official 495:01cb89f68337 270 NRF_RTC1->EVENTS_OVRFLW = 0;
mbed_official 495:01cb89f68337 271 NRF_RTC1->EVENTS_COMPARE[0] = 0;
mbed_official 85:e1a8e879a6a9 272 }