mbed library sources. Supersedes mbed-src.

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

Committer:
AnnaBridge
Date:
Tue Mar 20 16:56:18 2018 +0000
Revision:
182:a56a73fd2a6f
Parent:
174:b96e65c34a4d
Child:
186:707f6e361f3e
mbed-dev library. Release version 160

Who changed what in which revision?

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