mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Committer:
AnnaBridge
Date:
Wed Feb 20 22:31:08 2019 +0000
Revision:
189:f392fc9709a3
Parent:
188:bcfe06ba3d64
mbed library release version 165

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 150:02e0a0aed4ec 1 /* mbed Microcontroller Library
<> 150:02e0a0aed4ec 2 * Copyright (c) 2016 u-blox
<> 150:02e0a0aed4ec 3 *
<> 150:02e0a0aed4ec 4 * Licensed under the Apache License, Version 2.0 (the "License");
<> 150:02e0a0aed4ec 5 * you may not use this file except in compliance with the License.
<> 150:02e0a0aed4ec 6 * You may obtain a copy of the License at
<> 150:02e0a0aed4ec 7 *
<> 150:02e0a0aed4ec 8 * http://www.apache.org/licenses/LICENSE-2.0
<> 150:02e0a0aed4ec 9 *
<> 150:02e0a0aed4ec 10 * Unless required by applicable law or agreed to in writing, software
<> 150:02e0a0aed4ec 11 * distributed under the License is distributed on an "AS IS" BASIS,
<> 150:02e0a0aed4ec 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 150:02e0a0aed4ec 13 * See the License for the specific language governing permissions and
<> 150:02e0a0aed4ec 14 * limitations under the License.
<> 150:02e0a0aed4ec 15 */
<> 150:02e0a0aed4ec 16
<> 150:02e0a0aed4ec 17 /* The usecond ticker is mapped to TIMER0. A few issues must be dealt
<> 150:02e0a0aed4ec 18 * with in this driver:
<> 150:02e0a0aed4ec 19 *
<> 150:02e0a0aed4ec 20 * 1. The us_ticker API must count upwards, not down.
<> 150:02e0a0aed4ec 21 * 2. The expected range/resolution is 32 bits each of 1 usecond,
<> 150:02e0a0aed4ec 22 * whereas TIMER0 runs at 48 MHz (not 1 MHz) and so actually
<> 150:02e0a0aed4ec 23 * has a range/resolution of 26 bits at 0.02 useconds. Software
<> 150:02e0a0aed4ec 24 * has to compensate for this.
<> 150:02e0a0aed4ec 25 */
<> 150:02e0a0aed4ec 26
<> 150:02e0a0aed4ec 27 #include "us_ticker_api.h"
<> 160:d5399cc887bb 28 #include "mbed_critical.h"
<> 150:02e0a0aed4ec 29
<> 150:02e0a0aed4ec 30 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 31 * MACROS
<> 150:02e0a0aed4ec 32 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 33
<> 150:02e0a0aed4ec 34 /* TIMER0 clock is 48 MHz */
<> 150:02e0a0aed4ec 35 #define CLOCK_TICKS_PER_US 48
<> 150:02e0a0aed4ec 36
<> 150:02e0a0aed4ec 37 /* The number of clock ticks in a full-run of
<> 150:02e0a0aed4ec 38 * TIMER0, scaled to represent useconds */
<> 150:02e0a0aed4ec 39 #define USECONDS_PER_FULL_TIMER0_RUN 89478485
<> 150:02e0a0aed4ec 40
<> 150:02e0a0aed4ec 41 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 42 * TYPES
<> 150:02e0a0aed4ec 43 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 44
<> 150:02e0a0aed4ec 45 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 46 * GLOBAL VARIABLES
<> 150:02e0a0aed4ec 47 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 48
<> 150:02e0a0aed4ec 49 /* Are we ready? */
<> 150:02e0a0aed4ec 50 static bool g_initialised = false;
<> 150:02e0a0aed4ec 51
<> 150:02e0a0aed4ec 52 /* Keep track of the number of useconds elapsed. */
<> 150:02e0a0aed4ec 53 static uint32_t g_us_overflow = 0;
<> 150:02e0a0aed4ec 54
<> 150:02e0a0aed4ec 55 /* The number of useconds to increment the by at each interrupt */
<> 150:02e0a0aed4ec 56 static uint32_t g_us_overflow_increment = USECONDS_PER_FULL_TIMER0_RUN;
<> 150:02e0a0aed4ec 57
<> 150:02e0a0aed4ec 58 /* Keep track of extra loops required to represent a particular time
<> 150:02e0a0aed4ec 59 * as the HW timer runs faster than 1 MHz */
<> 150:02e0a0aed4ec 60 static uint32_t g_timer_extra_loops_required = 0;
<> 150:02e0a0aed4ec 61 static uint32_t g_timer_extra_loops_done = 0;
<> 150:02e0a0aed4ec 62
<> 150:02e0a0aed4ec 63 /* Keep track of any adjustment due to user interrupts . */
<> 150:02e0a0aed4ec 64 static uint32_t g_user_interrupt_offset = 0;
<> 150:02e0a0aed4ec 65
<> 150:02e0a0aed4ec 66 /* Flag that a user timer is running */
<> 150:02e0a0aed4ec 67 static bool g_user_interrupt = false;
<> 150:02e0a0aed4ec 68
<> 150:02e0a0aed4ec 69 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 70 * FUNCTION PROTOTYPES
<> 150:02e0a0aed4ec 71 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 72
<> 150:02e0a0aed4ec 73 static inline uint32_t divide_by_48(uint32_t x);
<> 150:02e0a0aed4ec 74
<> 150:02e0a0aed4ec 75 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 76 * NON-API FUNCTIONS
<> 150:02e0a0aed4ec 77 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 78
<> 150:02e0a0aed4ec 79 /* Perform a divide-by-48 operation.
<> 150:02e0a0aed4ec 80 * This is done as a multiply-shift operation to take advantage of
<> 150:02e0a0aed4ec 81 * the ARM 32 bit single-cycle multiply and avoid using division;
<> 150:02e0a0aed4ec 82 * 1/48 is equivalent to 1365/2^16. It is also done in two halves
<> 150:02e0a0aed4ec 83 * to make sure that the multiplies fit into 32 bits.
<> 150:02e0a0aed4ec 84 *
<> 150:02e0a0aed4ec 85 * The principle is:
<> 150:02e0a0aed4ec 86 * - divide the top 16 bits by 48 using multiply-shift (=> x1),
<> 150:02e0a0aed4ec 87 * - work out the remainder of that operation and divide that by 48 (=> x1r),
<> 150:02e0a0aed4ec 88 * - divide the bottom 16 bits by 48 using multiply-shift (=> x2),
<> 150:02e0a0aed4ec 89 * - add the lot together to get the result.
<> 150:02e0a0aed4ec 90 *
<> 150:02e0a0aed4ec 91 * The cost is 29 instructions.
<> 150:02e0a0aed4ec 92 */
<> 150:02e0a0aed4ec 93 static inline uint32_t divide_by_48(uint32_t x)
<> 150:02e0a0aed4ec 94 {
<> 150:02e0a0aed4ec 95 uint32_t x1 = ((x >> 16) * 1365) >> 16;
<> 150:02e0a0aed4ec 96 uint32_t x1r = ((x & 0xFFFF0000) - ((x1 * 48) << 16));
<> 150:02e0a0aed4ec 97 x1r = (x1r * 1365) >> 16;
<> 150:02e0a0aed4ec 98 uint32_t x2 = ((x & 0xFFFF) * 1365) >> 16;
<> 150:02e0a0aed4ec 99
<> 150:02e0a0aed4ec 100 return (x1 << 16) + x1r + x2;
<> 150:02e0a0aed4ec 101 }
<> 150:02e0a0aed4ec 102
<> 150:02e0a0aed4ec 103 /* Timer0 handler */
<> 150:02e0a0aed4ec 104 void IRQ1_TMR0_Handler(void)
<> 150:02e0a0aed4ec 105 {
<> 150:02e0a0aed4ec 106 if (g_initialised) {
<> 150:02e0a0aed4ec 107 /* Increment the overflow count and set the increment
<> 150:02e0a0aed4ec 108 * value for next time */
<> 150:02e0a0aed4ec 109 g_us_overflow += g_us_overflow_increment;
<> 150:02e0a0aed4ec 110 g_us_overflow_increment = USECONDS_PER_FULL_TIMER0_RUN;
<> 150:02e0a0aed4ec 111
<> 150:02e0a0aed4ec 112 /* Now handle the user interrupt case */
<> 150:02e0a0aed4ec 113 if (g_user_interrupt) {
<> 150:02e0a0aed4ec 114 if (g_timer_extra_loops_done < g_timer_extra_loops_required) {
<> 150:02e0a0aed4ec 115 /* Let the timer go round again */
<> 150:02e0a0aed4ec 116 g_timer_extra_loops_done++;
<> 150:02e0a0aed4ec 117 } else {
<> 150:02e0a0aed4ec 118 /* We've done with looping around for a user interrupt */
<> 150:02e0a0aed4ec 119 g_user_interrupt = false;
<> 150:02e0a0aed4ec 120
<> 150:02e0a0aed4ec 121 /* Call the mbed API */
<> 150:02e0a0aed4ec 122 us_ticker_irq_handler();
<> 150:02e0a0aed4ec 123 }
<> 150:02e0a0aed4ec 124 }
<> 150:02e0a0aed4ec 125 }
<> 150:02e0a0aed4ec 126
<> 150:02e0a0aed4ec 127 NVIC_ClearPendingIRQ(Timer_IRQn);
<> 150:02e0a0aed4ec 128 }
<> 150:02e0a0aed4ec 129
<> 150:02e0a0aed4ec 130 /* ----------------------------------------------------------------
<> 150:02e0a0aed4ec 131 * MBED API CALLS
<> 150:02e0a0aed4ec 132 * ----------------------------------------------------------------*/
<> 150:02e0a0aed4ec 133
<> 150:02e0a0aed4ec 134 void us_ticker_init(void)
<> 150:02e0a0aed4ec 135 {
<> 150:02e0a0aed4ec 136 if (!g_initialised) {
<> 150:02e0a0aed4ec 137 /* Reset the globals */
<> 150:02e0a0aed4ec 138 g_timer_extra_loops_done = 0;
<> 150:02e0a0aed4ec 139 g_timer_extra_loops_required = 0;
<> 150:02e0a0aed4ec 140 g_us_overflow = 0;
<> 150:02e0a0aed4ec 141 g_us_overflow_increment = USECONDS_PER_FULL_TIMER0_RUN;
<> 150:02e0a0aed4ec 142 g_user_interrupt_offset = 0;
<> 150:02e0a0aed4ec 143 g_user_interrupt = false;
<> 150:02e0a0aed4ec 144
<> 150:02e0a0aed4ec 145 /* Get the timer running (starting at what is zero,
<> 150:02e0a0aed4ec 146 * once inverted), with repeat */
<> 150:02e0a0aed4ec 147 NVIC_ClearPendingIRQ(Timer_IRQn);
<> 150:02e0a0aed4ec 148 TIMER0_LOAD = 0xFFFFFFFF;
<> 150:02e0a0aed4ec 149 TIMER0_CTRL = 0x03;
<> 150:02e0a0aed4ec 150 NVIC_EnableIRQ(Timer_IRQn);
<> 150:02e0a0aed4ec 151
<> 150:02e0a0aed4ec 152 g_initialised = true;
<> 150:02e0a0aed4ec 153 }
<> 150:02e0a0aed4ec 154 }
<> 150:02e0a0aed4ec 155
<> 150:02e0a0aed4ec 156 uint32_t us_ticker_read()
<> 150:02e0a0aed4ec 157 {
<> 150:02e0a0aed4ec 158 uint32_t timeValue;
<> 150:02e0a0aed4ec 159
<> 150:02e0a0aed4ec 160 /* This can be called before initialisation has been performed */
<> 150:02e0a0aed4ec 161 if (!g_initialised) {
<> 150:02e0a0aed4ec 162 us_ticker_init();
<> 150:02e0a0aed4ec 163 }
<> 150:02e0a0aed4ec 164
<> 150:02e0a0aed4ec 165 /* Disable interrupts to avoid collisions */
<> 150:02e0a0aed4ec 166 core_util_critical_section_enter();
<> 150:02e0a0aed4ec 167
<> 150:02e0a0aed4ec 168 /* Get the timer value, adding the offset in case we've been moved
<> 150:02e0a0aed4ec 169 * around by user activity, inverting it (as a count-up timer is
<> 150:02e0a0aed4ec 170 * expected), then scaling it to useconds and finally adding the
<> 150:02e0a0aed4ec 171 * usecond overflow value to make up the 32-bit usecond total */
<> 150:02e0a0aed4ec 172 timeValue = divide_by_48(~(TIMER0_TIME + g_user_interrupt_offset)) + g_us_overflow;
<> 150:02e0a0aed4ec 173
<> 150:02e0a0aed4ec 174 /* Put interrupts back */
<> 150:02e0a0aed4ec 175 core_util_critical_section_exit();
<> 150:02e0a0aed4ec 176
<> 150:02e0a0aed4ec 177 return timeValue;
<> 150:02e0a0aed4ec 178 }
<> 150:02e0a0aed4ec 179
<> 150:02e0a0aed4ec 180 /* NOTE: it seems to be an accepted fact that users
<> 150:02e0a0aed4ec 181 * will never ask for a timeout of more than 2^31 useconds
<> 150:02e0a0aed4ec 182 * and hence it's possible to do signed arithmetic
<> 150:02e0a0aed4ec 183 */
<> 150:02e0a0aed4ec 184 void us_ticker_set_interrupt(timestamp_t timestamp)
<> 150:02e0a0aed4ec 185 {
<> 150:02e0a0aed4ec 186 g_timer_extra_loops_required = 0;
<> 150:02e0a0aed4ec 187 g_timer_extra_loops_done = 0;
<> 150:02e0a0aed4ec 188 int32_t timeDelta;
<> 150:02e0a0aed4ec 189
<> 150:02e0a0aed4ec 190 /* Disable interrupts to avoid collisions */
<> 150:02e0a0aed4ec 191 core_util_critical_section_enter();
<> 150:02e0a0aed4ec 192
<> 150:02e0a0aed4ec 193 /* Establish how far we're being asked to move */
<> 150:02e0a0aed4ec 194 timeDelta = (int32_t) ((uint32_t) timestamp - us_ticker_read());
<> 150:02e0a0aed4ec 195
<> 150:02e0a0aed4ec 196 if (timeDelta <= 0) {
<> 150:02e0a0aed4ec 197 /* Make delta positive if it's not, it will expire pretty quickly */
<> 150:02e0a0aed4ec 198 /* Note: can't just call us_ticker_irq_handler() directly as we
<> 150:02e0a0aed4ec 199 * may already be in it and will overflow the stack */
<> 150:02e0a0aed4ec 200 timeDelta = 1;
<> 150:02e0a0aed4ec 201 }
<> 150:02e0a0aed4ec 202
<> 150:02e0a0aed4ec 203 /* The TIMER0 clock source is greater than 1 MHz, so
<> 150:02e0a0aed4ec 204 * work out how many times we have to go around
<> 150:02e0a0aed4ec 205 * and what the remainder is */
<> 150:02e0a0aed4ec 206 g_timer_extra_loops_required = (uint32_t) timeDelta / USECONDS_PER_FULL_TIMER0_RUN;
<> 150:02e0a0aed4ec 207 timeDelta -= g_timer_extra_loops_required * USECONDS_PER_FULL_TIMER0_RUN;
<> 150:02e0a0aed4ec 208
<> 150:02e0a0aed4ec 209 /* Next time we hit the interrupt the increment will be smaller */
<> 150:02e0a0aed4ec 210 g_us_overflow_increment = (uint32_t) timeDelta;
<> 150:02e0a0aed4ec 211
<> 150:02e0a0aed4ec 212 /* We're about to modify the timer value; work out the
<> 150:02e0a0aed4ec 213 * difference so that we can compensate for it when
<> 150:02e0a0aed4ec 214 * the time is read */
<> 150:02e0a0aed4ec 215 timeDelta = timeDelta * CLOCK_TICKS_PER_US;
<> 150:02e0a0aed4ec 216 g_user_interrupt_offset += TIMER0_TIME - timeDelta;
<> 150:02e0a0aed4ec 217
<> 150:02e0a0aed4ec 218 /* Run for the remainder first, then we can loop for the full
<> 150:02e0a0aed4ec 219 * USECONDS_PER_FULL_TIMER0_RUN afterwards */
<> 150:02e0a0aed4ec 220 TIMER0_LOAD = timeDelta;
<> 150:02e0a0aed4ec 221
<> 150:02e0a0aed4ec 222 /* A user interrupt is now running */
<> 150:02e0a0aed4ec 223 g_user_interrupt = true;
<> 150:02e0a0aed4ec 224
<> 150:02e0a0aed4ec 225 /* Put interrupts back */
<> 150:02e0a0aed4ec 226 core_util_critical_section_exit();
<> 150:02e0a0aed4ec 227 }
<> 150:02e0a0aed4ec 228
AnnaBridge 174:b96e65c34a4d 229 void us_ticker_fire_interrupt(void)
AnnaBridge 174:b96e65c34a4d 230 {
AnnaBridge 174:b96e65c34a4d 231 g_user_interrupt = true;
AnnaBridge 174:b96e65c34a4d 232 NVIC_SetPendingIRQ(Timer_IRQn);
AnnaBridge 174:b96e65c34a4d 233 }
AnnaBridge 174:b96e65c34a4d 234
<> 150:02e0a0aed4ec 235 void us_ticker_disable_interrupt(void)
<> 150:02e0a0aed4ec 236 {
<> 150:02e0a0aed4ec 237 /* Can't actually disable the interrupt here
<> 150:02e0a0aed4ec 238 * as we need it to manage the timer overflow,
<> 150:02e0a0aed4ec 239 * instead switch off the user interrupt part */
<> 150:02e0a0aed4ec 240 g_user_interrupt = false;
<> 150:02e0a0aed4ec 241 g_timer_extra_loops_required = 0;
<> 150:02e0a0aed4ec 242 g_us_overflow_increment = 0;
<> 150:02e0a0aed4ec 243 }
<> 150:02e0a0aed4ec 244
<> 150:02e0a0aed4ec 245 void us_ticker_clear_interrupt(void)
<> 150:02e0a0aed4ec 246 {
<> 150:02e0a0aed4ec 247 /* As above, can't clear the interrupt as it
<> 150:02e0a0aed4ec 248 * may just be an overflow interrupt, instead
<> 150:02e0a0aed4ec 249 * clear the variables */
<> 150:02e0a0aed4ec 250 g_user_interrupt = false;
<> 150:02e0a0aed4ec 251 g_timer_extra_loops_required = 0;
<> 150:02e0a0aed4ec 252 g_us_overflow_increment = 0;
<> 150:02e0a0aed4ec 253 }
AnnaBridge 188:bcfe06ba3d64 254
AnnaBridge 188:bcfe06ba3d64 255 void us_ticker_free(void)
AnnaBridge 188:bcfe06ba3d64 256 {
AnnaBridge 188:bcfe06ba3d64 257
AnnaBridge 188:bcfe06ba3d64 258 }