forked

Committer:
Kojto
Date:
Thu Aug 03 13:13:39 2017 +0100
Revision:
170:19eb464bc2be
Parent:
167:e84263d55307
This updates the lib to the mbed lib v 148

Who changed what in which revision?

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