mbed library sources. Supersedes mbed-src.

Dependents:   Hobbyking_Cheetah_Compact Hobbyking_Cheetah_Compact_DRV8323_14bit Hobbyking_Cheetah_Compact_DRV8323_V51_201907 HKC_MiniCheetah ... more

Fork of mbed-dev by mbed official

Committer:
benkatz
Date:
Mon Jul 30 20:31:44 2018 +0000
Revision:
181:36facd806e4a
Parent:
175:af195413fb11
going on the robot.  fixed a dumb bug in float_to_uint

Who changed what in which revision?

UserRevisionLine numberNew contents of line
<> 144:ef7eb2e8f9f7 1 /***************************************************************************//**
<> 144:ef7eb2e8f9f7 2 * @file us_ticker.c
<> 144:ef7eb2e8f9f7 3 *******************************************************************************
<> 144:ef7eb2e8f9f7 4 * @section License
<> 148:21d94c44109e 5 * <b>(C) Copyright 2016 Silicon Labs, http://www.silabs.com</b>
<> 144:ef7eb2e8f9f7 6 *******************************************************************************
<> 144:ef7eb2e8f9f7 7 *
<> 144:ef7eb2e8f9f7 8 * SPDX-License-Identifier: Apache-2.0
<> 144:ef7eb2e8f9f7 9 *
<> 144:ef7eb2e8f9f7 10 * Licensed under the Apache License, Version 2.0 (the "License"); you may
<> 144:ef7eb2e8f9f7 11 * not use this file except in compliance with the License.
<> 144:ef7eb2e8f9f7 12 * You may obtain a copy of the License at
<> 144:ef7eb2e8f9f7 13 *
<> 144:ef7eb2e8f9f7 14 * http://www.apache.org/licenses/LICENSE-2.0
<> 144:ef7eb2e8f9f7 15 *
<> 144:ef7eb2e8f9f7 16 * Unless required by applicable law or agreed to in writing, software
<> 144:ef7eb2e8f9f7 17 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
<> 144:ef7eb2e8f9f7 18 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<> 144:ef7eb2e8f9f7 19 * See the License for the specific language governing permissions and
<> 144:ef7eb2e8f9f7 20 * limitations under the License.
<> 144:ef7eb2e8f9f7 21 *
<> 144:ef7eb2e8f9f7 22 ******************************************************************************/
<> 144:ef7eb2e8f9f7 23
<> 144:ef7eb2e8f9f7 24 #include <stddef.h>
<> 144:ef7eb2e8f9f7 25 #include "us_ticker_api.h"
<> 150:02e0a0aed4ec 26 #include "device.h"
<> 144:ef7eb2e8f9f7 27 #include "mbed_assert.h"
<> 144:ef7eb2e8f9f7 28 #include "em_cmu.h"
<> 144:ef7eb2e8f9f7 29 #include "em_timer.h"
<> 144:ef7eb2e8f9f7 30 #include "clocking.h"
<> 144:ef7eb2e8f9f7 31 #include "sleep_api.h"
<> 144:ef7eb2e8f9f7 32 #include "sleepmodes.h"
<> 144:ef7eb2e8f9f7 33
<> 144:ef7eb2e8f9f7 34 #define TIMER_LEAST_ACTIVE_SLEEPMODE EM1
<> 144:ef7eb2e8f9f7 35 /**
<> 144:ef7eb2e8f9f7 36 * Timer functions for microsecond ticker.
<> 144:ef7eb2e8f9f7 37 * mbed expects a 32-bit timer. Since the EFM32 only has 16-bit timers,
<> 144:ef7eb2e8f9f7 38 * the upper 16 bits are implemented in software.
<> 144:ef7eb2e8f9f7 39 */
<> 144:ef7eb2e8f9f7 40
<> 144:ef7eb2e8f9f7 41 static uint8_t us_ticker_inited = 0; // Is ticker initialized yet
<> 144:ef7eb2e8f9f7 42
<> 148:21d94c44109e 43 static volatile uint32_t ticker_cnt = 0; //Internal overflow count, used to extend internal 16-bit counter to (MHz * 32-bit)
<> 144:ef7eb2e8f9f7 44 static volatile uint32_t ticker_int_cnt = 0; //Amount of overflows until user interrupt
<> 144:ef7eb2e8f9f7 45 static volatile uint8_t ticker_freq_mhz = 0; //Frequency of timer in MHz
<> 148:21d94c44109e 46 static volatile uint32_t ticker_top_us = 0; //Amount of us corresponding to the top value of the timer
<> 144:ef7eb2e8f9f7 47
<> 144:ef7eb2e8f9f7 48 void us_ticker_irq_handler_internal(void)
<> 144:ef7eb2e8f9f7 49 {
<> 148:21d94c44109e 50 /* Handle timer overflow */
<> 148:21d94c44109e 51 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
<> 148:21d94c44109e 52 ticker_cnt++;
<> 148:21d94c44109e 53 if(ticker_cnt >= ((uint32_t)ticker_freq_mhz << 16)) ticker_cnt = 0;
<> 148:21d94c44109e 54 TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_OF);
<> 148:21d94c44109e 55 }
<> 148:21d94c44109e 56
<> 144:ef7eb2e8f9f7 57 /* Check for user interrupt expiration */
<> 144:ef7eb2e8f9f7 58 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_CC0) {
<> 148:21d94c44109e 59 if (ticker_int_cnt > 0) {
<> 144:ef7eb2e8f9f7 60 ticker_int_cnt--;
<> 144:ef7eb2e8f9f7 61 TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_CC0);
<> 144:ef7eb2e8f9f7 62 } else {
<> 144:ef7eb2e8f9f7 63 us_ticker_irq_handler();
<> 144:ef7eb2e8f9f7 64 }
<> 144:ef7eb2e8f9f7 65 }
<> 144:ef7eb2e8f9f7 66 }
<> 144:ef7eb2e8f9f7 67
<> 144:ef7eb2e8f9f7 68 void us_ticker_init(void)
<> 144:ef7eb2e8f9f7 69 {
<> 144:ef7eb2e8f9f7 70 if (us_ticker_inited) {
<> 144:ef7eb2e8f9f7 71 return;
<> 144:ef7eb2e8f9f7 72 }
<> 144:ef7eb2e8f9f7 73 us_ticker_inited = 1;
<> 144:ef7eb2e8f9f7 74
<> 144:ef7eb2e8f9f7 75 /* Enable clock for TIMERs */
<> 144:ef7eb2e8f9f7 76 CMU_ClockEnable(US_TICKER_TIMER_CLOCK, true);
<> 144:ef7eb2e8f9f7 77
<> 144:ef7eb2e8f9f7 78 /* Clear TIMER counter value */
<> 144:ef7eb2e8f9f7 79 TIMER_CounterSet(US_TICKER_TIMER, 0);
<> 144:ef7eb2e8f9f7 80
<> 144:ef7eb2e8f9f7 81 /* Get frequency of clock in MHz for scaling ticks to microseconds */
<> 144:ef7eb2e8f9f7 82 ticker_freq_mhz = (REFERENCE_FREQUENCY / 1000000);
<> 144:ef7eb2e8f9f7 83 MBED_ASSERT(ticker_freq_mhz > 0);
<> 144:ef7eb2e8f9f7 84
<> 144:ef7eb2e8f9f7 85 /*
<> 144:ef7eb2e8f9f7 86 * Calculate maximum prescaler that gives at least 1 MHz frequency, while keeping clock as an integer multiple of 1 MHz.
<> 144:ef7eb2e8f9f7 87 * Example: 14 MHz => prescaler = 1 (i.e. DIV2), ticker_freq_mhz = 7;
<> 144:ef7eb2e8f9f7 88 * 24 MHz => prescaler = 3 (i.e. DIV8), ticker_freq_mhz = 3;
<> 144:ef7eb2e8f9f7 89 * 48 MHz => prescaler = 4 (i.e. DIV16), ticker_freq_mhz = 3;
<> 144:ef7eb2e8f9f7 90 * Limit prescaling to maximum prescaler value, which is 10 (DIV1024).
<> 144:ef7eb2e8f9f7 91 */
<> 144:ef7eb2e8f9f7 92 uint32_t prescaler = 0;
<> 144:ef7eb2e8f9f7 93 while((ticker_freq_mhz & 1) == 0 && prescaler <= 10) {
<> 144:ef7eb2e8f9f7 94 ticker_freq_mhz = ticker_freq_mhz >> 1;
<> 144:ef7eb2e8f9f7 95 prescaler++;
<> 144:ef7eb2e8f9f7 96 }
<> 144:ef7eb2e8f9f7 97
<> 144:ef7eb2e8f9f7 98 /* Set prescaler */
<> 144:ef7eb2e8f9f7 99 US_TICKER_TIMER->CTRL = (US_TICKER_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (prescaler << _TIMER_CTRL_PRESC_SHIFT);
<> 144:ef7eb2e8f9f7 100
<> 148:21d94c44109e 101 /* calculate top value */
<> 148:21d94c44109e 102 ticker_top_us = (uint32_t) 0x10000 / ticker_freq_mhz;
<> 148:21d94c44109e 103
<> 144:ef7eb2e8f9f7 104 /* Select Compare Channel parameters */
<> 144:ef7eb2e8f9f7 105 TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
<> 144:ef7eb2e8f9f7 106 timerCCInit.mode = timerCCModeCompare;
<> 144:ef7eb2e8f9f7 107
<> 144:ef7eb2e8f9f7 108 /* Configure Compare Channel 0 */
<> 144:ef7eb2e8f9f7 109 TIMER_InitCC(US_TICKER_TIMER, 0, &timerCCInit);
<> 144:ef7eb2e8f9f7 110
<> 144:ef7eb2e8f9f7 111 /* Enable interrupt vector in NVIC */
<> 144:ef7eb2e8f9f7 112 TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_OF);
<> 144:ef7eb2e8f9f7 113 NVIC_SetVector(US_TICKER_TIMER_IRQ, (uint32_t) us_ticker_irq_handler_internal);
<> 144:ef7eb2e8f9f7 114 NVIC_EnableIRQ(US_TICKER_TIMER_IRQ);
<> 144:ef7eb2e8f9f7 115
<> 144:ef7eb2e8f9f7 116 /* Set top value */
<> 148:21d94c44109e 117 TIMER_TopSet(US_TICKER_TIMER, (ticker_top_us * ticker_freq_mhz) - 1);
<> 144:ef7eb2e8f9f7 118
<> 144:ef7eb2e8f9f7 119 /* Start TIMER */
<> 144:ef7eb2e8f9f7 120 TIMER_Enable(US_TICKER_TIMER, true);
<> 144:ef7eb2e8f9f7 121 }
<> 144:ef7eb2e8f9f7 122
<> 144:ef7eb2e8f9f7 123 uint32_t us_ticker_read()
<> 144:ef7eb2e8f9f7 124 {
<> 148:21d94c44109e 125 uint32_t countH_old, countH;
<> 148:21d94c44109e 126 uint16_t countL;
<> 144:ef7eb2e8f9f7 127
<> 144:ef7eb2e8f9f7 128 if (!us_ticker_inited) {
<> 144:ef7eb2e8f9f7 129 us_ticker_init();
<> 144:ef7eb2e8f9f7 130 }
<> 144:ef7eb2e8f9f7 131
<> 144:ef7eb2e8f9f7 132 /* Avoid jumping in time by reading high bits twice */
<> 144:ef7eb2e8f9f7 133 do {
<> 144:ef7eb2e8f9f7 134 countH_old = ticker_cnt;
<> 144:ef7eb2e8f9f7 135 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
<> 148:21d94c44109e 136 countH_old++;
<> 144:ef7eb2e8f9f7 137 }
<> 144:ef7eb2e8f9f7 138 countL = US_TICKER_TIMER->CNT;
<> 144:ef7eb2e8f9f7 139 countH = ticker_cnt;
<> 144:ef7eb2e8f9f7 140 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
<> 148:21d94c44109e 141 countH++;
<> 144:ef7eb2e8f9f7 142 }
<> 144:ef7eb2e8f9f7 143 } while (countH_old != countH);
<> 144:ef7eb2e8f9f7 144
<> 148:21d94c44109e 145 /* Timer count value needs to be div'ed by the frequency to get to 1MHz ticks.
<> 148:21d94c44109e 146 * For the software-extended part, the amount of us in one overflow is constant.
<> 148:21d94c44109e 147 */
<> 148:21d94c44109e 148 return (countL / ticker_freq_mhz) + (countH * ticker_top_us);
<> 144:ef7eb2e8f9f7 149 }
<> 144:ef7eb2e8f9f7 150
<> 144:ef7eb2e8f9f7 151 void us_ticker_set_interrupt(timestamp_t timestamp)
<> 144:ef7eb2e8f9f7 152 {
<> 148:21d94c44109e 153 uint64_t goal = timestamp;
<> 148:21d94c44109e 154 uint32_t trigger;
<> 144:ef7eb2e8f9f7 155
<> 144:ef7eb2e8f9f7 156 if((US_TICKER_TIMER->IEN & TIMER_IEN_CC0) == 0) {
<> 144:ef7eb2e8f9f7 157 //Timer was disabled, but is going to be enabled. Set sleep mode.
<> 144:ef7eb2e8f9f7 158 blockSleepMode(TIMER_LEAST_ACTIVE_SLEEPMODE);
<> 144:ef7eb2e8f9f7 159 }
<> 144:ef7eb2e8f9f7 160 TIMER_IntDisable(US_TICKER_TIMER, TIMER_IEN_CC0);
<> 144:ef7eb2e8f9f7 161
<> 148:21d94c44109e 162 /* convert us delta value back to timer ticks */
<> 148:21d94c44109e 163 goal -= us_ticker_read();
<> 148:21d94c44109e 164 trigger = US_TICKER_TIMER->CNT;
<> 148:21d94c44109e 165
<> 148:21d94c44109e 166 /* Catch "Going back in time" */
<> 148:21d94c44109e 167 if(goal < (50 / (REFERENCE_FREQUENCY / 1000000)) ||
<> 148:21d94c44109e 168 goal >= 0xFFFFFF00UL) {
<> 148:21d94c44109e 169 TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
<> 148:21d94c44109e 170 TIMER_CompareSet(US_TICKER_TIMER, 0, (US_TICKER_TIMER->CNT + 3 > US_TICKER_TIMER->TOP ? 3 : US_TICKER_TIMER->CNT + 3));
<> 148:21d94c44109e 171 TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_CC0);
<> 148:21d94c44109e 172 return;
<> 144:ef7eb2e8f9f7 173 }
<> 144:ef7eb2e8f9f7 174
<> 148:21d94c44109e 175 /* Cap at 32 bit */
<> 148:21d94c44109e 176 goal &= 0xFFFFFFFFUL;
<> 148:21d94c44109e 177 /* Convert to ticker timebase */
<> 148:21d94c44109e 178 goal *= ticker_freq_mhz;
<> 144:ef7eb2e8f9f7 179
<> 148:21d94c44109e 180 /* Note: we should actually populate the following fields by the division and remainder
<> 148:21d94c44109e 181 * of goal / ticks_per_overflow, but since we're keeping the frequency as low
<> 148:21d94c44109e 182 * as possible, and ticks_per_overflow as close to FFFF as possible, we can
<> 148:21d94c44109e 183 * get away with ditching the division here and saving cycles.
<> 148:21d94c44109e 184 *
<> 148:21d94c44109e 185 * "exact" implementation:
<> 148:21d94c44109e 186 * ticker_int_cnt = goal / TIMER_TopGet(US_TICKER_TIMER);
<> 148:21d94c44109e 187 * ticker_int_rem = goal % TIMER_TopGet(US_TICKER_TIMER);
<> 148:21d94c44109e 188 */
<> 148:21d94c44109e 189 ticker_int_cnt = (goal >> 16) & 0xFFFFFFFF;
<> 144:ef7eb2e8f9f7 190
<> 148:21d94c44109e 191 /* Set compare channel 0 to (current position + lower 16 bits of target).
<> 148:21d94c44109e 192 * When lower 16 bits match, run complete cycles with ticker_int_rem as trigger value
<> 148:21d94c44109e 193 * for ticker_int_cnt times. */
<> 148:21d94c44109e 194 TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
<> 148:21d94c44109e 195
<> 148:21d94c44109e 196 /* Take top of timer into account so that we don't end up missing a cycle */
<> 148:21d94c44109e 197 /* Set trigger point by adding delta to current time */
<> 148:21d94c44109e 198 if((goal & 0xFFFF) >= TIMER_TopGet(US_TICKER_TIMER)) {
<> 148:21d94c44109e 199 trigger += (goal & 0xFFFF) - TIMER_TopGet(US_TICKER_TIMER);
<> 148:21d94c44109e 200 ticker_int_cnt++;
<> 144:ef7eb2e8f9f7 201 } else {
<> 148:21d94c44109e 202 trigger += (goal & 0xFFFF);
<> 144:ef7eb2e8f9f7 203 }
<> 148:21d94c44109e 204
<> 148:21d94c44109e 205 if(trigger >= TIMER_TopGet(US_TICKER_TIMER)) {
<> 148:21d94c44109e 206 trigger -= TIMER_TopGet(US_TICKER_TIMER);
<> 148:21d94c44109e 207 }
<> 148:21d94c44109e 208
<> 148:21d94c44109e 209 TIMER_CompareSet(US_TICKER_TIMER, 0, trigger);
<> 148:21d94c44109e 210
<> 144:ef7eb2e8f9f7 211 TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_CC0);
<> 144:ef7eb2e8f9f7 212 }
<> 144:ef7eb2e8f9f7 213
AnnaBridge 174:b96e65c34a4d 214 void us_ticker_fire_interrupt(void)
AnnaBridge 174:b96e65c34a4d 215 {
AnnaBridge 175:af195413fb11 216 ticker_int_cnt = 0;
AnnaBridge 175:af195413fb11 217 TIMER_IntSet(US_TICKER_TIMER, TIMER_IF_CC0);
AnnaBridge 174:b96e65c34a4d 218 NVIC_SetPendingIRQ(US_TICKER_TIMER_IRQ);
AnnaBridge 174:b96e65c34a4d 219 }
AnnaBridge 174:b96e65c34a4d 220
<> 144:ef7eb2e8f9f7 221 void us_ticker_disable_interrupt(void)
<> 144:ef7eb2e8f9f7 222 {
<> 144:ef7eb2e8f9f7 223 if((US_TICKER_TIMER->IEN & TIMER_IEN_CC0) != 0) {
<> 144:ef7eb2e8f9f7 224 //Timer was enabled, but is going to get disabled. Clear sleepmode.
<> 144:ef7eb2e8f9f7 225 unblockSleepMode(TIMER_LEAST_ACTIVE_SLEEPMODE);
<> 144:ef7eb2e8f9f7 226 }
<> 144:ef7eb2e8f9f7 227 /* Disable compare channel interrupts */
<> 144:ef7eb2e8f9f7 228 TIMER_IntDisable(US_TICKER_TIMER, TIMER_IEN_CC0);
<> 144:ef7eb2e8f9f7 229 }
<> 144:ef7eb2e8f9f7 230
<> 144:ef7eb2e8f9f7 231 void us_ticker_clear_interrupt(void)
<> 144:ef7eb2e8f9f7 232 {
<> 144:ef7eb2e8f9f7 233 /* Clear compare channel interrupts */
<> 144:ef7eb2e8f9f7 234 TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
<> 144:ef7eb2e8f9f7 235 }