test

Committer:
elijahsj
Date:
Mon Nov 09 00:02:47 2020 -0500
Revision:
1:8a094db1347f
test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elijahsj 1:8a094db1347f 1 /* mbed Microcontroller Library
elijahsj 1:8a094db1347f 2 * Copyright (c) 2006-2016 ARM Limited
elijahsj 1:8a094db1347f 3 *
elijahsj 1:8a094db1347f 4 * Licensed under the Apache License, Version 2.0 (the "License");
elijahsj 1:8a094db1347f 5 * you may not use this file except in compliance with the License.
elijahsj 1:8a094db1347f 6 * You may obtain a copy of the License at
elijahsj 1:8a094db1347f 7 *
elijahsj 1:8a094db1347f 8 * http://www.apache.org/licenses/LICENSE-2.0
elijahsj 1:8a094db1347f 9 *
elijahsj 1:8a094db1347f 10 * Unless required by applicable law or agreed to in writing, software
elijahsj 1:8a094db1347f 11 * distributed under the License is distributed on an "AS IS" BASIS,
elijahsj 1:8a094db1347f 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
elijahsj 1:8a094db1347f 13 * See the License for the specific language governing permissions and
elijahsj 1:8a094db1347f 14 * limitations under the License.
elijahsj 1:8a094db1347f 15 */
elijahsj 1:8a094db1347f 16 #include <stddef.h>
elijahsj 1:8a094db1347f 17 #include "us_ticker_api.h"
elijahsj 1:8a094db1347f 18 #include "PeripheralNames.h"
elijahsj 1:8a094db1347f 19 #include "hal_tick.h"
elijahsj 1:8a094db1347f 20
elijahsj 1:8a094db1347f 21 // A 16-bit timer is used
elijahsj 1:8a094db1347f 22 #if TIM_MST_16BIT
elijahsj 1:8a094db1347f 23
elijahsj 1:8a094db1347f 24 TIM_HandleTypeDef TimMasterHandle;
elijahsj 1:8a094db1347f 25
elijahsj 1:8a094db1347f 26 volatile uint32_t SlaveCounter = 0;
elijahsj 1:8a094db1347f 27 volatile uint32_t oc_int_part = 0;
elijahsj 1:8a094db1347f 28
elijahsj 1:8a094db1347f 29 void us_ticker_init(void)
elijahsj 1:8a094db1347f 30 {
elijahsj 1:8a094db1347f 31 /* NOTE: assuming that HAL tick has already been initialized! */
elijahsj 1:8a094db1347f 32 }
elijahsj 1:8a094db1347f 33
elijahsj 1:8a094db1347f 34 uint32_t us_ticker_read()
elijahsj 1:8a094db1347f 35 {
elijahsj 1:8a094db1347f 36 uint16_t cntH_old, cntH, cntL;
elijahsj 1:8a094db1347f 37 do {
elijahsj 1:8a094db1347f 38 cntH_old = SlaveCounter;
elijahsj 1:8a094db1347f 39 /* SlaveCounter needs to be checked before AND after we read the
elijahsj 1:8a094db1347f 40 * current counter TIM_MST->CNT, in case it wraps around.
elijahsj 1:8a094db1347f 41 * there are 2 possible cases of wrap around
elijahsj 1:8a094db1347f 42 * 1) in case this function is interrupted by timer_irq_handler and
elijahsj 1:8a094db1347f 43 * the SlaveCounter is updated. In that case we will loop again.
elijahsj 1:8a094db1347f 44 * 2) in case this function is called from interrupt context during
elijahsj 1:8a094db1347f 45 * wrap-around condtion. That would prevent/delay the timer_irq_handler
elijahsj 1:8a094db1347f 46 * from being called so we need to locally check the FLAG_UPDATE and
elijahsj 1:8a094db1347f 47 * update the cntH accordingly. The SlaveCounter variable itself will
elijahsj 1:8a094db1347f 48 * be updated in the interrupt handler just after ...
elijahsj 1:8a094db1347f 49 */
elijahsj 1:8a094db1347f 50 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
elijahsj 1:8a094db1347f 51 cntH_old += 1;
elijahsj 1:8a094db1347f 52 }
elijahsj 1:8a094db1347f 53 cntL = TIM_MST->CNT;
elijahsj 1:8a094db1347f 54 cntH = SlaveCounter;
elijahsj 1:8a094db1347f 55 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
elijahsj 1:8a094db1347f 56 cntH += 1;
elijahsj 1:8a094db1347f 57 }
elijahsj 1:8a094db1347f 58 } while(cntH_old != cntH);
elijahsj 1:8a094db1347f 59 // Glue the upper and lower part together to get a 32 bit timer
elijahsj 1:8a094db1347f 60 return (uint32_t)(cntH << 16 | cntL);
elijahsj 1:8a094db1347f 61 }
elijahsj 1:8a094db1347f 62
elijahsj 1:8a094db1347f 63 void us_ticker_set_interrupt(timestamp_t timestamp)
elijahsj 1:8a094db1347f 64 {
elijahsj 1:8a094db1347f 65 // NOTE: This function must be called with interrupts disabled to keep our
elijahsj 1:8a094db1347f 66 // timer interrupt setup atomic
elijahsj 1:8a094db1347f 67
elijahsj 1:8a094db1347f 68 // Set new output compare value
elijahsj 1:8a094db1347f 69 __HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_1, timestamp & 0xFFFF);
elijahsj 1:8a094db1347f 70 // Ensure the compare event starts clear
elijahsj 1:8a094db1347f 71 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
elijahsj 1:8a094db1347f 72 // Enable IT
elijahsj 1:8a094db1347f 73 __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
elijahsj 1:8a094db1347f 74
elijahsj 1:8a094db1347f 75 /* Set the number of timer wrap-around loops before the actual timestamp
elijahsj 1:8a094db1347f 76 * is reached. If the calculated delta time is more than halfway to the
elijahsj 1:8a094db1347f 77 * next compare event, check to see if a compare event has already been
elijahsj 1:8a094db1347f 78 * set, and if so, add one to the wrap-around count. This is done to
elijahsj 1:8a094db1347f 79 * ensure the correct wrap count is used in the corner cases where the
elijahsj 1:8a094db1347f 80 * 16 bit counter passes the compare value during the process of
elijahsj 1:8a094db1347f 81 * configuring this interrupt.
elijahsj 1:8a094db1347f 82 *
elijahsj 1:8a094db1347f 83 * Assumption: The time to execute this function is less than 32ms
elijahsj 1:8a094db1347f 84 * (otherwise incorrect behaviour could result)
elijahsj 1:8a094db1347f 85 *
elijahsj 1:8a094db1347f 86 * Consider the following corner cases:
elijahsj 1:8a094db1347f 87 * 1) timestamp is 1 us in the future:
elijahsj 1:8a094db1347f 88 * oc_int_part = 0 initially
elijahsj 1:8a094db1347f 89 * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000
elijahsj 1:8a094db1347f 90 * Compare event should happen in 1 us and us_ticker_irq_handler()
elijahsj 1:8a094db1347f 91 * called
elijahsj 1:8a094db1347f 92 * 2) timestamp is 0x8000 us in the future:
elijahsj 1:8a094db1347f 93 * oc_int_part = 0 initially
elijahsj 1:8a094db1347f 94 * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000
elijahsj 1:8a094db1347f 95 * There should be no possibility of the CC1 flag being set yet
elijahsj 1:8a094db1347f 96 * (see assumption above). When the compare event does occur in
elijahsj 1:8a094db1347f 97 * 32768 us, us_ticker_irq_handler() will be called
elijahsj 1:8a094db1347f 98 * 3) timestamp is 0x8001 us in the future:
elijahsj 1:8a094db1347f 99 * oc_int_part = 0 initially
elijahsj 1:8a094db1347f 100 * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no
elijahsj 1:8a094db1347f 101 * possibility of the CC1 flag being set yet (see assumption above),
elijahsj 1:8a094db1347f 102 * so oc_int_part will be left at 0, and when the compare event
elijahsj 1:8a094db1347f 103 * does occur in 32769 us, us_ticker_irq_handler() will be called
elijahsj 1:8a094db1347f 104 * 4) timestamp is 0x10000 us in the future:
elijahsj 1:8a094db1347f 105 * oc_int_part = 0 initially
elijahsj 1:8a094db1347f 106 * ((delta - 1) & 0xFFFF) >= 0x8000
elijahsj 1:8a094db1347f 107 * There are two subcases:
elijahsj 1:8a094db1347f 108 * a) The timer counter has not incremented past the compare
elijahsj 1:8a094db1347f 109 * value while setting up the interrupt. In this case, the
elijahsj 1:8a094db1347f 110 * CC1 flag will not be set, so oc_int_part will be
elijahsj 1:8a094db1347f 111 * left at 0, and when the compare event occurs in 65536 us,
elijahsj 1:8a094db1347f 112 * us_ticker_irq_handler() will be called
elijahsj 1:8a094db1347f 113 * b) The timer counter has JUST incremented past the compare
elijahsj 1:8a094db1347f 114 * value. In this case, the CC1 flag will be set, so
elijahsj 1:8a094db1347f 115 * oc_int_part will be incremented to 1, and the interrupt will
elijahsj 1:8a094db1347f 116 * occur immediately after this function returns, where
elijahsj 1:8a094db1347f 117 * oc_int_part will decrement to 0 without calling
elijahsj 1:8a094db1347f 118 * us_ticker_irq_handler(). Then about 65536 us later, the
elijahsj 1:8a094db1347f 119 * compare event will occur again, and us_ticker_irq_handler()
elijahsj 1:8a094db1347f 120 * will be called
elijahsj 1:8a094db1347f 121 * 5) timestamp is 0x10001 us in the future:
elijahsj 1:8a094db1347f 122 * oc_int_part = 1 initially
elijahsj 1:8a094db1347f 123 * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000
elijahsj 1:8a094db1347f 124 * CC1 flag will not be set (see assumption above). In 1 us the
elijahsj 1:8a094db1347f 125 * compare event will cause an interrupt, where oc_int_part will be
elijahsj 1:8a094db1347f 126 * decremented to 0 without calling us_ticker_irq_handler(). Then
elijahsj 1:8a094db1347f 127 * about 65536 us later, the compare event will occur again, and
elijahsj 1:8a094db1347f 128 * us_ticker_irq_handler() will be called
elijahsj 1:8a094db1347f 129 * 6) timestamp is 0x18000 us in the future:
elijahsj 1:8a094db1347f 130 * oc_int_part = 1 initially
elijahsj 1:8a094db1347f 131 * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000
elijahsj 1:8a094db1347f 132 * There should be no possibility of the CC1 flag being set yet
elijahsj 1:8a094db1347f 133 * (see assumption above). When the compare event does occur in
elijahsj 1:8a094db1347f 134 * 32768 us, oc_int_part will be decremented to 0 without calling
elijahsj 1:8a094db1347f 135 * us_ticker_irq_handler(). Then about 65536 us later, the
elijahsj 1:8a094db1347f 136 * compare event will occur again, and us_ticker_irq_handler() will
elijahsj 1:8a094db1347f 137 * be called
elijahsj 1:8a094db1347f 138 * 7) timestamp is 0x18001 us in the future:
elijahsj 1:8a094db1347f 139 * oc_int_part = 1 initially
elijahsj 1:8a094db1347f 140 * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no
elijahsj 1:8a094db1347f 141 * possibility of the CC1 flag being set yet (see assumption above),
elijahsj 1:8a094db1347f 142 * so oc_int_part will be left at 1, and when the compare event
elijahsj 1:8a094db1347f 143 * does occur in 32769 us, oc_int_part will be decremented to 0
elijahsj 1:8a094db1347f 144 * without calling us_ticker_irq_handler(). Then about 65536 us
elijahsj 1:8a094db1347f 145 * later, the compare event will occur again, and
elijahsj 1:8a094db1347f 146 * us_ticker_irq_handler() will be called
elijahsj 1:8a094db1347f 147 *
elijahsj 1:8a094db1347f 148 * delta - 1 is used because the timer compare event happens on the
elijahsj 1:8a094db1347f 149 * counter incrementing to match the compare value, and it won't occur
elijahsj 1:8a094db1347f 150 * immediately when the compare value is set to the current counter
elijahsj 1:8a094db1347f 151 * value.
elijahsj 1:8a094db1347f 152 */
elijahsj 1:8a094db1347f 153 uint32_t current_time = us_ticker_read();
elijahsj 1:8a094db1347f 154 uint32_t delta = timestamp - current_time;
elijahsj 1:8a094db1347f 155 /* Note: The case of delta <= 0 is handled in MBED upper layer */
elijahsj 1:8a094db1347f 156 oc_int_part = (delta - 1) >> 16;
elijahsj 1:8a094db1347f 157 if ( ((delta - 1) & 0xFFFF) >= 0x8000 &&
elijahsj 1:8a094db1347f 158 __HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET ) {
elijahsj 1:8a094db1347f 159 ++oc_int_part;
elijahsj 1:8a094db1347f 160 /* NOTE: Instead of incrementing oc_int_part here, we could clear
elijahsj 1:8a094db1347f 161 * the CC1 flag, but then you'd have to wait to ensure the
elijahsj 1:8a094db1347f 162 * interrupt is knocked down before returning and reenabling
elijahsj 1:8a094db1347f 163 * interrupts. Since this is a rare case, it's not worth it
elijahsj 1:8a094db1347f 164 * to try and optimize it, and it keeps the code simpler and
elijahsj 1:8a094db1347f 165 * safer to just do this increment instead.
elijahsj 1:8a094db1347f 166 */
elijahsj 1:8a094db1347f 167 }
elijahsj 1:8a094db1347f 168
elijahsj 1:8a094db1347f 169 }
elijahsj 1:8a094db1347f 170
elijahsj 1:8a094db1347f 171 void us_ticker_fire_interrupt(void)
elijahsj 1:8a094db1347f 172 {
elijahsj 1:8a094db1347f 173 /* When firing the event, the number of 16 bits counter wrap-ups (oc_int)
elijahsj 1:8a094db1347f 174 * must be re-initialized */
elijahsj 1:8a094db1347f 175 oc_int_part = 0;
elijahsj 1:8a094db1347f 176 HAL_TIM_GenerateEvent(&TimMasterHandle, TIM_EVENTSOURCE_CC1);
elijahsj 1:8a094db1347f 177 }
elijahsj 1:8a094db1347f 178
elijahsj 1:8a094db1347f 179 /* NOTE: must be called with interrupts disabled! */
elijahsj 1:8a094db1347f 180 void us_ticker_disable_interrupt(void)
elijahsj 1:8a094db1347f 181 {
elijahsj 1:8a094db1347f 182 __HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1);
elijahsj 1:8a094db1347f 183 }
elijahsj 1:8a094db1347f 184
elijahsj 1:8a094db1347f 185 /* NOTE: must be called with interrupts disabled! */
elijahsj 1:8a094db1347f 186 void us_ticker_clear_interrupt(void)
elijahsj 1:8a094db1347f 187 {
elijahsj 1:8a094db1347f 188 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
elijahsj 1:8a094db1347f 189 }
elijahsj 1:8a094db1347f 190
elijahsj 1:8a094db1347f 191 #endif // TIM_MST_16BIT