2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_TIM Timer Functions
6 * @brief PIOS Timer control code
10 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
11 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
12 * @brief Sets up timers and ways to register callbacks on them
13 * @see The GNU Public License (GPL) Version 3
15 *****************************************************************************/
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #ifdef PIOS_INCLUDE_TIM
35 #include "pios_tim_priv.h"
37 enum pios_tim_dev_magic
{
38 PIOS_TIM_DEV_MAGIC
= 0x87654098,
42 enum pios_tim_dev_magic magic
;
44 const struct pios_tim_channel
*channels
;
47 const struct pios_tim_callbacks
*callbacks
;
52 static bool PIOS_TIM_validate(struct pios_tim_dev
*tim_dev
)
54 return tim_dev
->magic
== PIOS_TIM_DEV_MAGIC
;
58 #if defined(PIOS_INCLUDE_FREERTOS) && 0
59 static struct pios_tim_dev
*PIOS_TIM_alloc(void)
61 struct pios_tim_dev
*tim_dev
;
63 tim_dev
= (struct pios_tim_dev
*)pios_malloc(sizeof(*tim_dev
));
68 tim_dev
->magic
= PIOS_TIM_DEV_MAGIC
;
72 static struct pios_tim_dev pios_tim_devs
[PIOS_TIM_MAX_DEVS
];
73 static uint8_t pios_tim_num_devs
;
74 static struct pios_tim_dev
*PIOS_TIM_alloc(void)
76 struct pios_tim_dev
*tim_dev
;
78 if (pios_tim_num_devs
>= PIOS_TIM_MAX_DEVS
) {
82 tim_dev
= &pios_tim_devs
[pios_tim_num_devs
++];
83 tim_dev
->magic
= PIOS_TIM_DEV_MAGIC
;
87 #endif /* if defined(PIOS_INCLUDE_FREERTOS) && 0 */
90 int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg
*cfg
)
92 PIOS_DEBUG_Assert(cfg
);
94 /* Configure the dividers for this timer */
95 TIM_TimeBaseInit(cfg
->timer
, (TIM_TimeBaseInitTypeDef
*)cfg
->time_base_init
);
97 /* Configure internal timer clocks */
98 TIM_InternalClockConfig(cfg
->timer
);
101 TIM_Cmd(cfg
->timer
, ENABLE
);
103 /* Enable Interrupts */
104 NVIC_Init((NVIC_InitTypeDef
*)&cfg
->irq
.init
);
106 // Advanced timers TIM1 & TIM8 need special handling:
107 // There are up to 4 separate interrupts handlers for each advanced timer, but
108 // pios_tim_clock_cfg has provision for only one irq init, so we take care here
109 // to enable additional irq channels that we intend to use.
111 if (cfg
->timer
== TIM1
) {
112 NVIC_InitTypeDef init
= cfg
->irq
.init
;
113 init
.NVIC_IRQChannel
= TIM1_UP_TIM16_IRQn
;
115 } else if (cfg
->timer
== TIM8
) {
116 NVIC_InitTypeDef init
= cfg
->irq
.init
;
117 init
.NVIC_IRQChannel
= TIM8_UP_IRQn
;
124 int32_t PIOS_TIM_InitChannels(uint32_t *tim_id
, const struct pios_tim_channel
*channels
, uint8_t num_channels
, const struct pios_tim_callbacks
*callbacks
, uint32_t context
)
126 PIOS_Assert(channels
);
127 PIOS_Assert(num_channels
);
129 struct pios_tim_dev
*tim_dev
;
130 tim_dev
= (struct pios_tim_dev
*)PIOS_TIM_alloc();
135 /* Bind the configuration to the device instance */
136 tim_dev
->channels
= channels
;
137 tim_dev
->num_channels
= num_channels
;
138 tim_dev
->callbacks
= callbacks
;
139 tim_dev
->context
= context
;
141 /* Configure the pins */
142 for (uint8_t i
= 0; i
< num_channels
; i
++) {
143 const struct pios_tim_channel
*chan
= &(channels
[i
]);
145 GPIO_Init(chan
->pin
.gpio
, (GPIO_InitTypeDef
*)&chan
->pin
.init
);
148 GPIO_PinAFConfig(chan
->pin
.gpio
, chan
->pin
.pin_source
, chan
->remap
);
152 *tim_id
= (uint32_t)tim_dev
;
160 static void PIOS_TIM_generic_irq_handler(TIM_TypeDef
*timer
)
162 /* Check for an overflow event on this timer */
163 bool overflow_event
= 0;
164 uint16_t overflow_count
= false;
166 if (TIM_GetITStatus(timer
, TIM_IT_Update
) == SET
) {
167 TIM_ClearITPendingBit(timer
, TIM_IT_Update
);
168 overflow_count
= timer
->ARR
;
169 overflow_event
= true;
172 /* Iterate over all registered clients of the TIM layer to find channels on this timer */
173 for (uint8_t i
= 0; i
< pios_tim_num_devs
; i
++) {
174 const struct pios_tim_dev
*tim_dev
= &pios_tim_devs
[i
];
176 if (!tim_dev
->channels
|| tim_dev
->num_channels
== 0) {
177 /* No channels to process on this client */
181 for (uint8_t j
= 0; j
< tim_dev
->num_channels
; j
++) {
182 const struct pios_tim_channel
*chan
= &tim_dev
->channels
[j
];
184 if (chan
->timer
!= timer
) {
185 /* channel is not on this timer */
189 /* Figure out which interrupt bit we should be looking at */
191 switch (chan
->timer_chan
) {
193 timer_it
= TIM_IT_CC1
;
196 timer_it
= TIM_IT_CC2
;
199 timer_it
= TIM_IT_CC3
;
202 timer_it
= TIM_IT_CC4
;
211 if (TIM_GetITStatus(chan
->timer
, timer_it
) == SET
) {
212 TIM_ClearITPendingBit(chan
->timer
, timer_it
);
214 /* Read the current counter */
215 switch (chan
->timer_chan
) {
217 edge_count
= TIM_GetCapture1(chan
->timer
);
220 edge_count
= TIM_GetCapture2(chan
->timer
);
223 edge_count
= TIM_GetCapture3(chan
->timer
);
226 edge_count
= TIM_GetCapture4(chan
->timer
);
238 if (!tim_dev
->callbacks
) {
239 /* No callbacks registered, we're done with this channel */
243 /* Generate the appropriate callbacks */
244 if (overflow_event
& edge_event
) {
246 * When both edge and overflow happen in the same interrupt, we
247 * need a heuristic to determine the order of the edge and overflow
248 * events so that the callbacks happen in the right order. If we
249 * get the order wrong, our pulse width calculations could be off by up
250 * to ARR ticks. That could be bad.
252 * Heuristic: If the edge_count is < 32 ticks above zero then we assume the
253 * edge happened just after the overflow.
256 if (edge_count
< 32) {
257 /* Call the overflow callback first */
258 if (tim_dev
->callbacks
->overflow
) {
259 (*tim_dev
->callbacks
->overflow
)((uint32_t)tim_dev
,
264 /* Call the edge callback second */
265 if (tim_dev
->callbacks
->edge
) {
266 (*tim_dev
->callbacks
->edge
)((uint32_t)tim_dev
,
272 /* Call the edge callback first */
273 if (tim_dev
->callbacks
->edge
) {
274 (*tim_dev
->callbacks
->edge
)((uint32_t)tim_dev
,
279 /* Call the overflow callback second */
280 if (tim_dev
->callbacks
->overflow
) {
281 (*tim_dev
->callbacks
->overflow
)((uint32_t)tim_dev
,
287 } else if (overflow_event
&& tim_dev
->callbacks
->overflow
) {
288 (*tim_dev
->callbacks
->overflow
)((uint32_t)tim_dev
,
292 } else if (edge_event
&& tim_dev
->callbacks
->edge
) {
293 (*tim_dev
->callbacks
->edge
)((uint32_t)tim_dev
,
302 /* Bind Interrupt Handlers
304 * Map all valid TIM IRQs to the common interrupt handler
305 * and give it enough context to properly demux the various timers
307 void TIM1_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_CC_irq_handler")));
308 static void PIOS_TIM_1_CC_irq_handler(void)
310 PIOS_TIM_generic_irq_handler(TIM1
);
313 // The rest of TIM1 interrupts are overlapped
314 void TIM1_BRK_TIM15_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_BRK_TIM_15_irq_handler")));
315 static void PIOS_TIM_1_BRK_TIM_15_irq_handler(void)
317 if (TIM_GetITStatus(TIM1
, TIM_IT_Break
)) {
318 PIOS_TIM_generic_irq_handler(TIM1
);
319 } else if (TIM_GetITStatus(TIM15
, TIM_IT_Update
| TIM_IT_CC1
| TIM_IT_CC2
| TIM_IT_CC3
| TIM_IT_CC4
| TIM_IT_COM
| TIM_IT_Trigger
| TIM_IT_Break
)) {
320 PIOS_TIM_generic_irq_handler(TIM15
);
324 void TIM1_UP_TIM16_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_UP_TIM_16_irq_handler")));
325 static void PIOS_TIM_1_UP_TIM_16_irq_handler(void)
327 if (TIM_GetITStatus(TIM1
, TIM_IT_Update
)) {
328 PIOS_TIM_generic_irq_handler(TIM1
);
329 } else if (TIM_GetITStatus(TIM16
, TIM_IT_Update
| TIM_IT_CC1
| TIM_IT_CC2
| TIM_IT_CC3
| TIM_IT_CC4
| TIM_IT_COM
| TIM_IT_Trigger
| TIM_IT_Break
)) {
330 PIOS_TIM_generic_irq_handler(TIM16
);
333 void TIM1_TRG_COM_TIM17_IRQHandler(void) __attribute__((alias("PIOS_TIM_1_TRG_COM_TIM_17_irq_handler")));
334 static void PIOS_TIM_1_TRG_COM_TIM_17_irq_handler(void)
336 if (TIM_GetITStatus(TIM1
, TIM_IT_Trigger
| TIM_IT_COM
)) {
337 PIOS_TIM_generic_irq_handler(TIM1
);
338 } else if (TIM_GetITStatus(TIM17
, TIM_IT_Update
| TIM_IT_CC1
| TIM_IT_CC2
| TIM_IT_CC3
| TIM_IT_CC4
| TIM_IT_COM
| TIM_IT_Trigger
| TIM_IT_Break
)) {
339 PIOS_TIM_generic_irq_handler(TIM17
);
343 void TIM2_IRQHandler(void) __attribute__((alias("PIOS_TIM_2_irq_handler")));
344 static void PIOS_TIM_2_irq_handler(void)
346 PIOS_TIM_generic_irq_handler(TIM2
);
349 void TIM3_IRQHandler(void) __attribute__((alias("PIOS_TIM_3_irq_handler")));
350 static void PIOS_TIM_3_irq_handler(void)
352 PIOS_TIM_generic_irq_handler(TIM3
);
355 void TIM4_IRQHandler(void) __attribute__((alias("PIOS_TIM_4_irq_handler")));
356 static void PIOS_TIM_4_irq_handler(void)
358 PIOS_TIM_generic_irq_handler(TIM4
);
361 void TIM6_DAC_IRQHandler(void) __attribute__((alias("PIOS_TIM_6_DAC_irq_handler")));
362 static void PIOS_TIM_6_DAC_irq_handler(void)
364 // What about DAC irq?
365 if (TIM_GetITStatus(TIM6
, TIM_IT_Update
| TIM_IT_CC1
| TIM_IT_CC2
| TIM_IT_CC3
| TIM_IT_CC4
| TIM_IT_COM
| TIM_IT_Trigger
| TIM_IT_Break
)) {
366 PIOS_TIM_generic_irq_handler(TIM6
);
370 void TIM7_IRQHandler(void) __attribute__((alias("PIOS_TIM_7_irq_handler")));
371 static void PIOS_TIM_7_irq_handler(void)
373 PIOS_TIM_generic_irq_handler(TIM7
);
376 void TIM8_CC_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_CC_irq_handler")));
377 static void PIOS_TIM_8_CC_irq_handler(void)
379 PIOS_TIM_generic_irq_handler(TIM8
);
382 void TIM8_BRK_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_BRK_irq_handler")));
383 static void PIOS_TIM_8_BRK_irq_handler(void)
385 PIOS_TIM_generic_irq_handler(TIM8
);
388 void TIM8_UP_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_UP_irq_handler")));
389 static void PIOS_TIM_8_UP_irq_handler(void)
391 PIOS_TIM_generic_irq_handler(TIM8
);
394 void TIM8_TRG_COM_IRQHandler(void) __attribute__((alias("PIOS_TIM_8_TRG_COM_irq_handler")));
395 static void PIOS_TIM_8_TRG_COM_irq_handler(void)
397 PIOS_TIM_generic_irq_handler(TIM8
);
401 #endif /* PIOS_INCLUDE_TIM */