1 /* mbed Microcontroller Library
2 * Copyright (c) 2014, STMicroelectronics
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
29 #include "us_ticker_api.h"
30 #include "PeripheralNames.h"
32 #if defined(TARGET_STM32F070RB)
37 static TIM_HandleTypeDef TimMasterHandle
;
38 static int us_ticker_inited
= 0;
40 volatile uint32_t SlaveCounter
= 0;
41 volatile uint32_t oc_int_part
= 0;
42 volatile uint16_t oc_rem_part
= 0;
44 void set_compare(uint16_t count
)
46 TimMasterHandle
.Instance
= TIM_MST
;
47 // Set new output compare value
48 __HAL_TIM_SetCompare(&TimMasterHandle
, TIM_CHANNEL_1
, count
);
50 __HAL_TIM_ENABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
53 void us_ticker_init(void)
55 if (us_ticker_inited
) return;
58 HAL_InitTick(0); // The passed value is not used
61 uint32_t us_ticker_read()
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
;
73 counter2
= (uint32_t)(SlaveCounter
<< 16);
74 counter2
+= TIM_MST
->CNT
;
75 if (counter2
> counter
) {
83 void us_ticker_set_interrupt(timestamp_t timestamp
)
85 int delta
= (int)((uint32_t)timestamp
- us_ticker_read());
86 uint16_t cval
= TIM_MST
->CNT
;
88 if (delta
<= 0) { // This event was in the past
89 us_ticker_irq_handler();
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
);
98 oc_rem_part
= oc_rem_part
- (0xFFFF - cval
);
103 void us_ticker_disable_interrupt(void)
105 TimMasterHandle
.Instance
= TIM_MST
;
106 __HAL_TIM_DISABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
109 void us_ticker_clear_interrupt(void)
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
);
117 #elif defined(TARGET_STM32F030R8) || defined (TARGET_STM32F051R8)
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()
125 static TIM_HandleTypeDef TimMasterHandle
;
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;
133 void set_compare(uint16_t count
)
135 TimMasterHandle
.Instance
= TIM_MST
;
137 // Set new output compare value
138 __HAL_TIM_SetCompare(&TimMasterHandle
, TIM_CHANNEL_1
, count
);
140 __HAL_TIM_ENABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
143 // Used to increment the slave counter
144 static void tim_update_irq_handler(void)
146 TimMasterHandle
.Instance
= TIM_MST
;
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
);
155 // Used by interrupt system
156 static void tim_oc_irq_handler(void)
158 uint16_t cval
= TIM_MST
->CNT
;
159 TimMasterHandle
.Instance
= TIM_MST
;
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
);
165 if (oc_rem_part
> 0) {
166 set_compare(oc_rem_part
); // Finish the remaining time left
169 if (oc_int_part
> 0) {
171 oc_rem_part
= cval
; // To finish the counter loop the next time
174 us_ticker_irq_handler();
180 void us_ticker_init(void)
183 if (us_ticker_inited
) return;
184 us_ticker_inited
= 1;
186 // Enable timer clock
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
);
197 // Configure interrupts
198 __HAL_TIM_ENABLE_IT(&TimMasterHandle
, TIM_IT_UPDATE
);
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
);
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
);
209 HAL_TIM_Base_Start(&TimMasterHandle
);
212 uint32_t us_ticker_read()
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
;
224 counter2
= (uint32_t)(SlaveCounter
<< 16);
225 counter2
+= TIM_MST
->CNT
;
226 if (counter2
> counter
) {
234 void us_ticker_set_interrupt(timestamp_t timestamp
)
236 int delta
= (int)((uint32_t)timestamp
- us_ticker_read());
237 uint16_t cval
= TIM_MST
->CNT
;
239 if (delta
<= 0) { // This event was in the past
240 us_ticker_irq_handler();
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
);
249 oc_rem_part
= oc_rem_part
- (0xFFFF - cval
);
254 void us_ticker_disable_interrupt(void)
256 TimMasterHandle
.Instance
= TIM_MST
;
257 __HAL_TIM_DISABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
260 void us_ticker_clear_interrupt(void)
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
);
270 // 32-bit timer selection
273 static TIM_HandleTypeDef TimMasterHandle
;
274 static int us_ticker_inited
= 0;
276 void us_ticker_init(void)
278 if (us_ticker_inited
) return;
279 us_ticker_inited
= 1;
281 TimMasterHandle
.Instance
= TIM_MST
;
283 HAL_InitTick(0); // The passed value is not used
286 uint32_t us_ticker_read()
288 if (!us_ticker_inited
) us_ticker_init();
292 void us_ticker_set_interrupt(timestamp_t timestamp
)
294 // Set new output compare value
295 __HAL_TIM_SetCompare(&TimMasterHandle
, TIM_CHANNEL_1
, (uint32_t)timestamp
);
297 __HAL_TIM_ENABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
300 void us_ticker_disable_interrupt(void)
302 __HAL_TIM_DISABLE_IT(&TimMasterHandle
, TIM_IT_CC1
);
305 void us_ticker_clear_interrupt(void)
307 __HAL_TIM_CLEAR_IT(&TimMasterHandle
, TIM_IT_CC1
);