]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F0/us_ticker.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.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