]> git.gir.st - tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F0/us_ticker.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_STM / TARGET_STM32F0 / us_ticker.c
1 /* mbed Microcontroller Library
2 * Copyright (c) 2014, STMicroelectronics
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of STMicroelectronics nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <stddef.h>
29 #include "us_ticker_api.h"
30 #include "PeripheralNames.h"
31
32 #if defined(TARGET_STM32F070RB)
33
34 // Timer selection
35 #define TIM_MST TIM1
36
37 static TIM_HandleTypeDef TimMasterHandle;
38 static int us_ticker_inited = 0;
39
40 volatile uint32_t SlaveCounter = 0;
41 volatile uint32_t oc_int_part = 0;
42 volatile uint16_t oc_rem_part = 0;
43
44 void set_compare(uint16_t count)
45 {
46 TimMasterHandle.Instance = TIM_MST;
47 // Set new output compare value
48 __HAL_TIM_SetCompare(&TimMasterHandle, TIM_CHANNEL_1, count);
49 // Enable IT
50 __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
51 }
52
53 void us_ticker_init(void)
54 {
55 if (us_ticker_inited) return;
56 us_ticker_inited = 1;
57
58 HAL_InitTick(0); // The passed value is not used
59 }
60
61 uint32_t us_ticker_read()
62 {
63 uint32_t counter, counter2;
64 if (!us_ticker_inited) us_ticker_init();
65 // A situation might appear when Master overflows right after Slave is read and before the
66 // new (overflowed) value of Master is read. Which would make the code below consider the
67 // previous (incorrect) value of Slave and the new value of Master, which would return a
68 // value in the past. Avoid this by computing consecutive values of the timer until they
69 // are properly ordered.
70 counter = (uint32_t)(SlaveCounter << 16);
71 counter += TIM_MST->CNT;
72 while (1) {
73 counter2 = (uint32_t)(SlaveCounter << 16);
74 counter2 += TIM_MST->CNT;
75 if (counter2 > counter) {
76 break;
77 }
78 counter = counter2;
79 }
80 return counter2;
81 }
82
83 void us_ticker_set_interrupt(timestamp_t timestamp)
84 {
85 int delta = (int)((uint32_t)timestamp - us_ticker_read());
86 uint16_t cval = TIM_MST->CNT;
87
88 if (delta <= 0) { // This event was in the past
89 us_ticker_irq_handler();
90 } else {
91 oc_int_part = (uint32_t)(delta >> 16);
92 oc_rem_part = (uint16_t)(delta & 0xFFFF);
93 if (oc_rem_part <= (0xFFFF - cval)) {
94 set_compare(cval + oc_rem_part);
95 oc_rem_part = 0;
96 } else {
97 set_compare(0xFFFF);
98 oc_rem_part = oc_rem_part - (0xFFFF - cval);
99 }
100 }
101 }
102
103 void us_ticker_disable_interrupt(void)
104 {
105 TimMasterHandle.Instance = TIM_MST;
106 __HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1);
107 }
108
109 void us_ticker_clear_interrupt(void)
110 {
111 TimMasterHandle.Instance = TIM_MST;
112 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET) {
113 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
114 }
115 }
116
117 #elif defined(TARGET_STM32F030R8) || defined (TARGET_STM32F051R8)
118
119 // Timer selection:
120 #define TIM_MST TIM1
121 #define TIM_MST_UP_IRQ TIM1_BRK_UP_TRG_COM_IRQn
122 #define TIM_MST_OC_IRQ TIM1_CC_IRQn
123 #define TIM_MST_RCC __TIM1_CLK_ENABLE()
124
125 static TIM_HandleTypeDef TimMasterHandle;
126
127
128 static int us_ticker_inited = 0;
129 static volatile uint32_t SlaveCounter = 0;
130 static volatile uint32_t oc_int_part = 0;
131 static volatile uint16_t oc_rem_part = 0;
132
133 void set_compare(uint16_t count)
134 {
135 TimMasterHandle.Instance = TIM_MST;
136
137 // Set new output compare value
138 __HAL_TIM_SetCompare(&TimMasterHandle, TIM_CHANNEL_1, count);
139 // Enable IT
140 __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
141 }
142
143 // Used to increment the slave counter
144 static void tim_update_irq_handler(void)
145 {
146 TimMasterHandle.Instance = TIM_MST;
147
148 // Clear Update interrupt flag
149 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) {
150 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE);
151 SlaveCounter++;
152 }
153 }
154
155 // Used by interrupt system
156 static void tim_oc_irq_handler(void)
157 {
158 uint16_t cval = TIM_MST->CNT;
159 TimMasterHandle.Instance = TIM_MST;
160
161 // Clear CC1 interrupt flag
162 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET) {
163 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
164 }
165 if (oc_rem_part > 0) {
166 set_compare(oc_rem_part); // Finish the remaining time left
167 oc_rem_part = 0;
168 } else {
169 if (oc_int_part > 0) {
170 set_compare(0xFFFF);
171 oc_rem_part = cval; // To finish the counter loop the next time
172 oc_int_part--;
173 } else {
174 us_ticker_irq_handler();
175 }
176 }
177
178 }
179
180 void us_ticker_init(void)
181 {
182
183 if (us_ticker_inited) return;
184 us_ticker_inited = 1;
185
186 // Enable timer clock
187 TIM_MST_RCC;
188
189 // Configure time base
190 TimMasterHandle.Instance = TIM_MST;
191 TimMasterHandle.Init.Period = 0xFFFF;
192 TimMasterHandle.Init.Prescaler = (uint32_t)(SystemCoreClock / 1000000) - 1; // 1 �s tick
193 TimMasterHandle.Init.ClockDivision = 0;
194 TimMasterHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
195 HAL_TIM_Base_Init(&TimMasterHandle);
196
197 // Configure interrupts
198 __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_UPDATE);
199
200 // Update interrupt used for 32-bit counter
201 NVIC_SetVector(TIM_MST_UP_IRQ, (uint32_t)tim_update_irq_handler);
202 NVIC_EnableIRQ(TIM_MST_UP_IRQ);
203
204 // Output compare interrupt used for timeout feature
205 NVIC_SetVector(TIM_MST_OC_IRQ, (uint32_t)tim_oc_irq_handler);
206 NVIC_EnableIRQ(TIM_MST_OC_IRQ);
207
208 // Enable timer
209 HAL_TIM_Base_Start(&TimMasterHandle);
210 }
211
212 uint32_t us_ticker_read()
213 {
214 uint32_t counter, counter2;
215 if (!us_ticker_inited) us_ticker_init();
216 // A situation might appear when Master overflows right after Slave is read and before the
217 // new (overflowed) value of Master is read. Which would make the code below consider the
218 // previous (incorrect) value of Slave and the new value of Master, which would return a
219 // value in the past. Avoid this by computing consecutive values of the timer until they
220 // are properly ordered.
221 counter = (uint32_t)(SlaveCounter << 16);
222 counter += TIM_MST->CNT;
223 while (1) {
224 counter2 = (uint32_t)(SlaveCounter << 16);
225 counter2 += TIM_MST->CNT;
226 if (counter2 > counter) {
227 break;
228 }
229 counter = counter2;
230 }
231 return counter2;
232 }
233
234 void us_ticker_set_interrupt(timestamp_t timestamp)
235 {
236 int delta = (int)((uint32_t)timestamp - us_ticker_read());
237 uint16_t cval = TIM_MST->CNT;
238
239 if (delta <= 0) { // This event was in the past
240 us_ticker_irq_handler();
241 } else {
242 oc_int_part = (uint32_t)(delta >> 16);
243 oc_rem_part = (uint16_t)(delta & 0xFFFF);
244 if (oc_rem_part <= (0xFFFF - cval)) {
245 set_compare(cval + oc_rem_part);
246 oc_rem_part = 0;
247 } else {
248 set_compare(0xFFFF);
249 oc_rem_part = oc_rem_part - (0xFFFF - cval);
250 }
251 }
252 }
253
254 void us_ticker_disable_interrupt(void)
255 {
256 TimMasterHandle.Instance = TIM_MST;
257 __HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1);
258 }
259
260 void us_ticker_clear_interrupt(void)
261 {
262 TimMasterHandle.Instance = TIM_MST;
263 if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET) {
264 __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
265 }
266 }
267
268 #else
269
270 // 32-bit timer selection
271 #define TIM_MST TIM2
272
273 static TIM_HandleTypeDef TimMasterHandle;
274 static int us_ticker_inited = 0;
275
276 void us_ticker_init(void)
277 {
278 if (us_ticker_inited) return;
279 us_ticker_inited = 1;
280
281 TimMasterHandle.Instance = TIM_MST;
282
283 HAL_InitTick(0); // The passed value is not used
284 }
285
286 uint32_t us_ticker_read()
287 {
288 if (!us_ticker_inited) us_ticker_init();
289 return TIM_MST->CNT;
290 }
291
292 void us_ticker_set_interrupt(timestamp_t timestamp)
293 {
294 // Set new output compare value
295 __HAL_TIM_SetCompare(&TimMasterHandle, TIM_CHANNEL_1, (uint32_t)timestamp);
296 // Enable IT
297 __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
298 }
299
300 void us_ticker_disable_interrupt(void)
301 {
302 __HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1);
303 }
304
305 void us_ticker_clear_interrupt(void)
306 {
307 __HAL_TIM_CLEAR_IT(&TimMasterHandle, TIM_IT_CC1);
308 }
309 #endif
Imprint / Impressum