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
<> 144:ef7eb2e8f9f7 1 /*******************************************************************************
<> 144:ef7eb2e8f9f7 2 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved.
<> 144:ef7eb2e8f9f7 3 *
<> 144:ef7eb2e8f9f7 4 * Permission is hereby granted, free of charge, to any person obtaining a
<> 144:ef7eb2e8f9f7 5 * copy of this software and associated documentation files (the "Software"),
<> 144:ef7eb2e8f9f7 6 * to deal in the Software without restriction, including without limitation
<> 144:ef7eb2e8f9f7 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
<> 144:ef7eb2e8f9f7 8 * and/or sell copies of the Software, and to permit persons to whom the
<> 144:ef7eb2e8f9f7 9 * Software is furnished to do so, subject to the following conditions:
<> 144:ef7eb2e8f9f7 10 *
<> 144:ef7eb2e8f9f7 11 * The above copyright notice and this permission notice shall be included
<> 144:ef7eb2e8f9f7 12 * in all copies or substantial portions of the Software.
<> 144:ef7eb2e8f9f7 13 *
<> 144:ef7eb2e8f9f7 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
<> 144:ef7eb2e8f9f7 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
<> 144:ef7eb2e8f9f7 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
<> 144:ef7eb2e8f9f7 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
<> 144:ef7eb2e8f9f7 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
<> 144:ef7eb2e8f9f7 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
<> 144:ef7eb2e8f9f7 20 * OTHER DEALINGS IN THE SOFTWARE.
<> 144:ef7eb2e8f9f7 21 *
<> 144:ef7eb2e8f9f7 22 * Except as contained in this notice, the name of Maxim Integrated
<> 144:ef7eb2e8f9f7 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
<> 144:ef7eb2e8f9f7 24 * Products, Inc. Branding Policy.
<> 144:ef7eb2e8f9f7 25 *
<> 144:ef7eb2e8f9f7 26 * The mere transfer of this software does not imply any licenses
<> 144:ef7eb2e8f9f7 27 * of trade secrets, proprietary technology, copyrights, patents,
<> 144:ef7eb2e8f9f7 28 * trademarks, maskwork rights, or any other form of intellectual
<> 144:ef7eb2e8f9f7 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
<> 144:ef7eb2e8f9f7 30 * ownership rights.
<> 144:ef7eb2e8f9f7 31 *******************************************************************************
<> 144:ef7eb2e8f9f7 32 */
<> 144:ef7eb2e8f9f7 33
<> 144:ef7eb2e8f9f7 34 #include "mbed_error.h"
<> 144:ef7eb2e8f9f7 35 #include "us_ticker_api.h"
<> 144:ef7eb2e8f9f7 36 #include "PeripheralNames.h"
<> 144:ef7eb2e8f9f7 37 #include "tmr_regs.h"
<> 144:ef7eb2e8f9f7 38
<> 144:ef7eb2e8f9f7 39 #define US_TIMER MXC_TMR0
<> 144:ef7eb2e8f9f7 40 #define US_TIMER_IRQn TMR0_IRQn
<> 144:ef7eb2e8f9f7 41
<> 144:ef7eb2e8f9f7 42 static int us_ticker_inited = 0;
<> 144:ef7eb2e8f9f7 43 static uint32_t ticks_per_us;
<> 144:ef7eb2e8f9f7 44 static uint32_t tick_win;
<> 144:ef7eb2e8f9f7 45 static volatile uint64_t current_cnt; // Hold the current ticks
<> 144:ef7eb2e8f9f7 46 static volatile uint64_t event_cnt; // Holds the value of the next event
<> 144:ef7eb2e8f9f7 47
<> 144:ef7eb2e8f9f7 48 #define ticks_to_us(ticks) ((ticks) / ticks_per_us);
<> 144:ef7eb2e8f9f7 49 #define MAX_TICK_VAL ((uint64_t)0xFFFFFFFF * ticks_per_us)
<> 144:ef7eb2e8f9f7 50
<> 144:ef7eb2e8f9f7 51 //******************************************************************************
<> 144:ef7eb2e8f9f7 52 static inline void inc_current_cnt(uint32_t inc) {
<> 144:ef7eb2e8f9f7 53
<> 144:ef7eb2e8f9f7 54 // Overflow the ticker when the us ticker overflows
<> 144:ef7eb2e8f9f7 55 current_cnt += inc;
<> 144:ef7eb2e8f9f7 56 if (current_cnt > MAX_TICK_VAL) {
<> 144:ef7eb2e8f9f7 57 current_cnt -= (MAX_TICK_VAL + 1);
<> 144:ef7eb2e8f9f7 58 }
<> 144:ef7eb2e8f9f7 59 }
<> 144:ef7eb2e8f9f7 60
<> 144:ef7eb2e8f9f7 61 //******************************************************************************
<> 144:ef7eb2e8f9f7 62 static inline int event_passed(uint64_t current, uint64_t event) {
<> 144:ef7eb2e8f9f7 63
<> 144:ef7eb2e8f9f7 64 // Determine if the event has already happened.
<> 144:ef7eb2e8f9f7 65 // If the event is behind the current ticker, within a window,
<> 144:ef7eb2e8f9f7 66 // then the event has already happened.
<> 144:ef7eb2e8f9f7 67 if (((current < tick_win) && ((event < current) ||
<> 144:ef7eb2e8f9f7 68 (event > (MAX_TICK_VAL - (tick_win - current))))) ||
<> 144:ef7eb2e8f9f7 69 ((event < current) && (event > (current - tick_win)))) {
<> 144:ef7eb2e8f9f7 70 return 1;
<> 144:ef7eb2e8f9f7 71 }
<> 144:ef7eb2e8f9f7 72
<> 144:ef7eb2e8f9f7 73 return 0;
<> 144:ef7eb2e8f9f7 74 }
<> 144:ef7eb2e8f9f7 75
<> 144:ef7eb2e8f9f7 76 //******************************************************************************
<> 144:ef7eb2e8f9f7 77 static inline uint64_t event_diff(uint64_t current, uint64_t event) {
<> 144:ef7eb2e8f9f7 78
<> 144:ef7eb2e8f9f7 79 // Check to see if the ticker will overflow before the event
<> 144:ef7eb2e8f9f7 80 if(current <= event) {
<> 144:ef7eb2e8f9f7 81 return (event - current);
<> 144:ef7eb2e8f9f7 82 }
<> 144:ef7eb2e8f9f7 83
<> 144:ef7eb2e8f9f7 84 return ((MAX_TICK_VAL - current) + event);
<> 144:ef7eb2e8f9f7 85 }
<> 144:ef7eb2e8f9f7 86
<> 144:ef7eb2e8f9f7 87 //******************************************************************************
<> 144:ef7eb2e8f9f7 88 static void tmr_handler(void)
<> 144:ef7eb2e8f9f7 89 {
<> 144:ef7eb2e8f9f7 90 uint32_t term_cnt32 = US_TIMER->term_cnt32;
<> 144:ef7eb2e8f9f7 91 US_TIMER->term_cnt32 = 0xFFFFFFFF; // reset to max value to prevent further interrupts
<> 144:ef7eb2e8f9f7 92 US_TIMER->intfl = (MXC_F_TMR_INTFL_TIMER0 | MXC_F_TMR_INTFL_TIMER1); // clear interrupt
<> 144:ef7eb2e8f9f7 93 NVIC_ClearPendingIRQ(US_TIMER_IRQn);
<> 144:ef7eb2e8f9f7 94
<> 144:ef7eb2e8f9f7 95 inc_current_cnt(term_cnt32);
<> 144:ef7eb2e8f9f7 96
<> 144:ef7eb2e8f9f7 97 if (event_passed(current_cnt + US_TIMER->count32, event_cnt )) {
<> 144:ef7eb2e8f9f7 98 // the timestamp has expired
<> 144:ef7eb2e8f9f7 99 event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
<> 144:ef7eb2e8f9f7 100 us_ticker_irq_handler();
<> 144:ef7eb2e8f9f7 101 } else {
<> 144:ef7eb2e8f9f7 102
<> 144:ef7eb2e8f9f7 103 uint64_t diff = event_diff(current_cnt, event_cnt);
<> 144:ef7eb2e8f9f7 104 if (diff < (uint64_t)0xFFFFFFFF) {
<> 144:ef7eb2e8f9f7 105 // the event occurs before the next overflow
<> 144:ef7eb2e8f9f7 106 US_TIMER->term_cnt32 = diff;
<> 144:ef7eb2e8f9f7 107
<> 144:ef7eb2e8f9f7 108 // Since the timer keeps counting after the terminal value is reached, it is possible that the new
<> 144:ef7eb2e8f9f7 109 // terminal value is in the past.
<> 144:ef7eb2e8f9f7 110 if (US_TIMER->term_cnt32 < US_TIMER->count32) {
<> 144:ef7eb2e8f9f7 111 // the timestamp has expired
<> 144:ef7eb2e8f9f7 112 US_TIMER->term_cnt32 = 0xFFFFFFFF; // reset to max value to prevent further interrupts
<> 144:ef7eb2e8f9f7 113 US_TIMER->intfl = (MXC_F_TMR_INTFL_TIMER0 | MXC_F_TMR_INTFL_TIMER1); // clear interrupt
<> 144:ef7eb2e8f9f7 114 NVIC_ClearPendingIRQ(US_TIMER_IRQn);
<> 144:ef7eb2e8f9f7 115 event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
<> 144:ef7eb2e8f9f7 116 us_ticker_irq_handler();
<> 144:ef7eb2e8f9f7 117 }
<> 144:ef7eb2e8f9f7 118 }
<> 144:ef7eb2e8f9f7 119 }
<> 144:ef7eb2e8f9f7 120 }
<> 144:ef7eb2e8f9f7 121
<> 144:ef7eb2e8f9f7 122 //******************************************************************************
<> 144:ef7eb2e8f9f7 123 void us_ticker_init(void)
<> 144:ef7eb2e8f9f7 124 {
<> 144:ef7eb2e8f9f7 125 if (us_ticker_inited)
<> 144:ef7eb2e8f9f7 126 return;
<> 144:ef7eb2e8f9f7 127 us_ticker_inited = 1;
<> 144:ef7eb2e8f9f7 128
<> 144:ef7eb2e8f9f7 129 current_cnt = 0;
<> 144:ef7eb2e8f9f7 130 event_cnt = 0xFFFFFFFFFFFFFFFFULL; // reset to max value
<> 144:ef7eb2e8f9f7 131
<> 144:ef7eb2e8f9f7 132 if (SystemCoreClock <= 1000000) {
<> 144:ef7eb2e8f9f7 133 error("us_ticker cannot operate at this SystemCoreClock");
<> 144:ef7eb2e8f9f7 134 return;
<> 144:ef7eb2e8f9f7 135 }
<> 144:ef7eb2e8f9f7 136
<> 144:ef7eb2e8f9f7 137 // Configure timer for 32-bit continuous mode with /1 prescaler
<> 144:ef7eb2e8f9f7 138 US_TIMER->ctrl = MXC_E_TMR_MODE_CONTINUOUS << MXC_F_TMR_CTRL_MODE_POS | (0 << MXC_F_TMR_CTRL_PRESCALE_POS);
<> 144:ef7eb2e8f9f7 139 ticks_per_us = SystemCoreClock / 1000000;
<> 144:ef7eb2e8f9f7 140
<> 144:ef7eb2e8f9f7 141 // Set the tick window to 10ms
<> 144:ef7eb2e8f9f7 142 tick_win = SystemCoreClock/100;
<> 144:ef7eb2e8f9f7 143
<> 144:ef7eb2e8f9f7 144 // Set timer overflow to the max
<> 144:ef7eb2e8f9f7 145 US_TIMER->term_cnt32 = 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 146 US_TIMER->pwm_cap32 = 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 147 US_TIMER->count32 = 0;
<> 144:ef7eb2e8f9f7 148
<> 144:ef7eb2e8f9f7 149 US_TIMER->intfl = (MXC_F_TMR_INTFL_TIMER0 | MXC_F_TMR_INTFL_TIMER1); // clear pending interrupts
<> 144:ef7eb2e8f9f7 150
<> 144:ef7eb2e8f9f7 151 NVIC_SetVector(US_TIMER_IRQn, (uint32_t)tmr_handler);
<> 144:ef7eb2e8f9f7 152 NVIC_EnableIRQ(US_TIMER_IRQn);
<> 144:ef7eb2e8f9f7 153
<> 144:ef7eb2e8f9f7 154 US_TIMER->inten |= MXC_F_TMR_INTEN_TIMER0; // enable interrupts
<> 144:ef7eb2e8f9f7 155 US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
<> 144:ef7eb2e8f9f7 156 }
<> 144:ef7eb2e8f9f7 157
<> 144:ef7eb2e8f9f7 158 //******************************************************************************
<> 144:ef7eb2e8f9f7 159 void us_ticker_deinit(void)
<> 144:ef7eb2e8f9f7 160 {
<> 144:ef7eb2e8f9f7 161 US_TIMER->ctrl = 0; // disable timer
<> 144:ef7eb2e8f9f7 162 US_TIMER->inten = 0; // disable interrupts
<> 144:ef7eb2e8f9f7 163 US_TIMER->intfl = (MXC_F_TMR_INTFL_TIMER0 | MXC_F_TMR_INTFL_TIMER1); // clear interrupts
<> 144:ef7eb2e8f9f7 164 us_ticker_inited = 0;
<> 144:ef7eb2e8f9f7 165 }
<> 144:ef7eb2e8f9f7 166
<> 144:ef7eb2e8f9f7 167 //******************************************************************************
<> 144:ef7eb2e8f9f7 168 uint32_t us_ticker_read(void)
<> 144:ef7eb2e8f9f7 169 {
<> 144:ef7eb2e8f9f7 170 uint64_t current_cnt1, current_cnt2;
<> 144:ef7eb2e8f9f7 171 uint32_t term_cnt, tmr_cnt;
<> 144:ef7eb2e8f9f7 172 uint32_t intfl1, intfl2;
<> 144:ef7eb2e8f9f7 173
<> 144:ef7eb2e8f9f7 174 if (!us_ticker_inited)
<> 144:ef7eb2e8f9f7 175 us_ticker_init();
<> 144:ef7eb2e8f9f7 176
<> 144:ef7eb2e8f9f7 177 // Ensure coherency between current_cnt and US_TIMER->count32
<> 144:ef7eb2e8f9f7 178 do {
<> 144:ef7eb2e8f9f7 179 current_cnt1 = current_cnt;
<> 144:ef7eb2e8f9f7 180 intfl1 = US_TIMER->intfl;
<> 144:ef7eb2e8f9f7 181 term_cnt = US_TIMER->term_cnt32;
<> 144:ef7eb2e8f9f7 182 tmr_cnt = US_TIMER->count32;
<> 144:ef7eb2e8f9f7 183 intfl2 = US_TIMER->intfl;
<> 144:ef7eb2e8f9f7 184 current_cnt2 = current_cnt;
<> 144:ef7eb2e8f9f7 185 } while ((current_cnt1 != current_cnt2) || (intfl1 != intfl2));
<> 144:ef7eb2e8f9f7 186
<> 144:ef7eb2e8f9f7 187 // Account for an unserviced interrupt
<> 144:ef7eb2e8f9f7 188 if (intfl1) {
<> 144:ef7eb2e8f9f7 189 current_cnt1 += term_cnt;
<> 144:ef7eb2e8f9f7 190 }
<> 144:ef7eb2e8f9f7 191
<> 144:ef7eb2e8f9f7 192 current_cnt1 += tmr_cnt;
<> 144:ef7eb2e8f9f7 193
<> 144:ef7eb2e8f9f7 194 return (current_cnt1 / ticks_per_us);
<> 144:ef7eb2e8f9f7 195 }
<> 144:ef7eb2e8f9f7 196
<> 144:ef7eb2e8f9f7 197 //******************************************************************************
<> 144:ef7eb2e8f9f7 198 void us_ticker_set_interrupt(timestamp_t timestamp)
<> 144:ef7eb2e8f9f7 199 {
<> 144:ef7eb2e8f9f7 200 // Note: interrupts are disabled before this function is called.
<> 144:ef7eb2e8f9f7 201
<> 144:ef7eb2e8f9f7 202 US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
<> 144:ef7eb2e8f9f7 203
<> 144:ef7eb2e8f9f7 204 if (US_TIMER->intfl) {
<> 144:ef7eb2e8f9f7 205 US_TIMER->intfl = (MXC_F_TMR_INTFL_TIMER0 | MXC_F_TMR_INTFL_TIMER1); // clear interrupt
<> 144:ef7eb2e8f9f7 206 NVIC_ClearPendingIRQ(US_TIMER_IRQn);
<> 144:ef7eb2e8f9f7 207 inc_current_cnt(US_TIMER->term_cnt32);
<> 144:ef7eb2e8f9f7 208 }
<> 144:ef7eb2e8f9f7 209
<> 144:ef7eb2e8f9f7 210 // add and reset the current count value
<> 144:ef7eb2e8f9f7 211 inc_current_cnt(US_TIMER->count32);
<> 144:ef7eb2e8f9f7 212 US_TIMER->count32 = 0;
<> 144:ef7eb2e8f9f7 213
<> 144:ef7eb2e8f9f7 214 // add the number of cycles that the timer is disabled here for
<> 144:ef7eb2e8f9f7 215 inc_current_cnt(200);
<> 144:ef7eb2e8f9f7 216
<> 144:ef7eb2e8f9f7 217 event_cnt = (uint64_t)timestamp * ticks_per_us;
<> 144:ef7eb2e8f9f7 218
<> 144:ef7eb2e8f9f7 219 // Check to see if the event has already passed
<> 144:ef7eb2e8f9f7 220 if (!event_passed(current_cnt, event_cnt)) {
<> 144:ef7eb2e8f9f7 221 uint64_t diff = event_diff(current_cnt, event_cnt);
<> 144:ef7eb2e8f9f7 222 if (diff < (uint64_t)0xFFFFFFFF) {
<> 144:ef7eb2e8f9f7 223 // the event occurs before the next overflow
<> 144:ef7eb2e8f9f7 224 US_TIMER->term_cnt32 = diff;
<> 144:ef7eb2e8f9f7 225 } else {
<> 144:ef7eb2e8f9f7 226 // the event occurs after the next overflow
<> 144:ef7eb2e8f9f7 227 US_TIMER->term_cnt32 = 0xFFFFFFFF; // set to max
<> 144:ef7eb2e8f9f7 228 }
<> 144:ef7eb2e8f9f7 229 } else {
<> 144:ef7eb2e8f9f7 230 // the requested timestamp occurs in the past
<> 144:ef7eb2e8f9f7 231 // set the timer up to immediately expire
<> 144:ef7eb2e8f9f7 232 US_TIMER->term_cnt32 = 1;
<> 144:ef7eb2e8f9f7 233 }
<> 144:ef7eb2e8f9f7 234 US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
<> 144:ef7eb2e8f9f7 235 }
<> 144:ef7eb2e8f9f7 236
AnnaBridge 174:b96e65c34a4d 237 void us_ticker_fire_interrupt(void)
AnnaBridge 174:b96e65c34a4d 238 {
AnnaBridge 182:a56a73fd2a6f 239 US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
AnnaBridge 182:a56a73fd2a6f 240 US_TIMER->term_cnt32 = 1;
AnnaBridge 182:a56a73fd2a6f 241 US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
AnnaBridge 174:b96e65c34a4d 242 }
AnnaBridge 174:b96e65c34a4d 243
<> 144:ef7eb2e8f9f7 244 //******************************************************************************
<> 144:ef7eb2e8f9f7 245 void us_ticker_disable_interrupt(void)
<> 144:ef7eb2e8f9f7 246 {
<> 144:ef7eb2e8f9f7 247 // There are no more events, set timer overflow to the max
<> 144:ef7eb2e8f9f7 248 US_TIMER->term_cnt32 = 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 249 }
<> 144:ef7eb2e8f9f7 250
<> 144:ef7eb2e8f9f7 251 //******************************************************************************
<> 144:ef7eb2e8f9f7 252 void us_ticker_clear_interrupt(void)
<> 144:ef7eb2e8f9f7 253 {
<> 144:ef7eb2e8f9f7 254 // cleared in the local handler
<> 144:ef7eb2e8f9f7 255 }
<> 144:ef7eb2e8f9f7 256
<> 144:ef7eb2e8f9f7 257 //******************************************************************************
<> 144:ef7eb2e8f9f7 258 void us_ticker_set(timestamp_t timestamp)
<> 144:ef7eb2e8f9f7 259 {
<> 144:ef7eb2e8f9f7 260 US_TIMER->ctrl &= ~MXC_F_TMR_CTRL_ENABLE0; // disable timer
<> 144:ef7eb2e8f9f7 261 current_cnt = (uint64_t)timestamp * ticks_per_us;
<> 144:ef7eb2e8f9f7 262 US_TIMER->count32 = 0;
<> 144:ef7eb2e8f9f7 263 US_TIMER->term_cnt32 = 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 264 US_TIMER->ctrl |= MXC_F_TMR_CTRL_ENABLE0; // enable timer
<> 144:ef7eb2e8f9f7 265
<> 144:ef7eb2e8f9f7 266 if (((uint64_t)timestamp * ticks_per_us) >= event_cnt) {
<> 144:ef7eb2e8f9f7 267 // The next timestamp has elapsed. Trigger the interrupt to handle it.
<> 144:ef7eb2e8f9f7 268 NVIC_SetPendingIRQ(US_TIMER_IRQn);
<> 144:ef7eb2e8f9f7 269 }
<> 144:ef7eb2e8f9f7 270 }
AnnaBridge 188:bcfe06ba3d64 271
AnnaBridge 188:bcfe06ba3d64 272 void us_ticker_free(void)
AnnaBridge 188:bcfe06ba3d64 273 {
AnnaBridge 188:bcfe06ba3d64 274
AnnaBridge 188:bcfe06ba3d64 275 }