MacroRat / MouseCode

Dependencies:   ITG3200 QEI

Committer:
sahilmgandhi
Date:
Sat Jun 03 00:22:44 2017 +0000
Revision:
46:b156ef445742
Parent:
18:6a4db94011d3
Final code for internal battlebot competition.

Who changed what in which revision?

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