dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_tim.c
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  */
26 
27 #include "pios.h"
28 
29 #include "pios_tim.h"
30 #include "pios_tim_priv.h"
31 
33  PIOS_TIM_DEV_MAGIC = 0x87654098,
34 };
35 
36 struct pios_tim_dev {
38 
39  const struct pios_tim_channel * channels;
40  uint8_t num_channels;
41 
42  const struct pios_tim_callbacks * callbacks;
43  uintptr_t context;
44 };
45 
47 static uint8_t pios_tim_num_devs;
48 static struct pios_tim_dev * PIOS_TIM_alloc(void)
49 {
50  struct pios_tim_dev * tim_dev;
51 
53  return (NULL);
54  }
55 
56  tim_dev = &pios_tim_devs[pios_tim_num_devs++];
57  tim_dev->magic = PIOS_TIM_DEV_MAGIC;
58 
59  return (tim_dev);
60 }
61 
62 int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg * cfg)
63 {
64  PIOS_DEBUG_Assert(cfg);
65 
66  /* Enable appropriate clock to timer module */
67  switch((uint32_t) cfg->timer) {
68  case (uint32_t)TIM1:
69  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
70  break;
71  case (uint32_t)TIM2:
72  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
73  break;
74  case (uint32_t)TIM3:
75  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
76  break;
77  case (uint32_t)TIM4:
78  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
79  break;
80 #ifdef STM32F10X_HD
81  case (uint32_t)TIM5:
82  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
83  break;
84  case (uint32_t)TIM6:
85  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
86  break;
87  case (uint32_t)TIM7:
88  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
89  break;
90  case (uint32_t)TIM8:
91  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
92  break;
93 #endif
94  }
95 
96  /* Configure the dividers for this timer */
97  TIM_TimeBaseInit(cfg->timer, (TIM_TimeBaseInitTypeDef*)cfg->time_base_init);
98 
99  /* Configure internal timer clocks */
100  TIM_InternalClockConfig(cfg->timer);
101 
102  /* Enable timers */
103  TIM_Cmd(cfg->timer, ENABLE);
104 
105  /* Enable Interrupts */
106  NVIC_Init((NVIC_InitTypeDef*)&cfg->irq.init);
107 
108  return 0;
109 }
110 
111 void PIOS_TIM_InitTimerPin(uintptr_t tim_id, int idx)
112 {
113  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
114 
115  PIOS_Assert(idx < tim_dev->num_channels);
116 
117  const struct pios_tim_channel * chan = &tim_dev->channels[idx];
118 
119  /* Enable the peripheral clock for the GPIO */
120  switch ((uint32_t)chan->pin.gpio) {
121  case (uint32_t) GPIOA:
122  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
123  break;
124  case (uint32_t) GPIOB:
125  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
126  break;
127  case (uint32_t) GPIOC:
128  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
129  break;
130  default:
131  PIOS_Assert(0);
132  break;
133  }
134  GPIO_Init(chan->pin.gpio, (GPIO_InitTypeDef*)&chan->pin.init);
135 
136  if (chan->remap) {
137  GPIO_PinRemapConfig(chan->remap, ENABLE);
138  }
139 }
140 
141 void PIOS_TIM_InitAllTimerPins(uintptr_t tim_id)
142 {
143  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
144 
145  /* Configure the pins */
146  for (uint8_t i = 0; i < tim_dev->num_channels; i++) {
147  PIOS_TIM_InitTimerPin(tim_id, i);
148  }
149 }
150 
151 void PIOS_TIM_SetBankToGPOut(uintptr_t tim_id, TIM_TypeDef *timer)
152 {
153  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
154 
155  GPIO_InitTypeDef gpio_inf;
156  gpio_inf.GPIO_Speed = GPIO_Speed_50MHz;
157  gpio_inf.GPIO_Mode = GPIO_Mode_Out_PP;
158 
159  for (uint8_t i = 0; i < tim_dev->num_channels; i++) {
160  const struct pios_tim_channel * chan = &tim_dev->channels[i];
161 
162  if (chan->timer != timer) {
163  continue;
164  }
165 
166  // Only steal the pin info from the matching pin
167  gpio_inf.GPIO_Pin = chan->pin.init.GPIO_Pin;
168  GPIO_Init(chan->pin.gpio, &gpio_inf);
169  }
170 }
171 
172 int32_t PIOS_TIM_InitChannels(uintptr_t * tim_id, const struct pios_tim_channel * channels, uint8_t num_channels, const struct pios_tim_callbacks * callbacks, uintptr_t context)
173 {
174  PIOS_Assert(channels);
175  PIOS_Assert(num_channels);
176 
177  struct pios_tim_dev * tim_dev;
178  tim_dev = (struct pios_tim_dev *) PIOS_TIM_alloc();
179  if (!tim_dev) goto out_fail;
180 
181  /* Bind the configuration to the device instance */
182  tim_dev->channels = channels;
183  tim_dev->num_channels = num_channels;
184  tim_dev->callbacks = callbacks;
185  tim_dev->context = context;
186 
187  *tim_id = (uintptr_t)tim_dev;
188 
189  PIOS_TIM_InitAllTimerPins(*tim_id);
190 
191  return(0);
192 
193 out_fail:
194  return(-1);
195 }
196 
197 static void PIOS_TIM_generic_irq_handler(TIM_TypeDef * timer)
198 {
199  uint16_t flags = timer->SR;
200 
201  /* Reference manual indicates these are rc_w0-- can only be
202  * written to 0.
203  *
204  * Therefore, clear only the events we're going to process.
205  * Otherwise we could lose an overflow just after a rising edge,
206  * which would offset our count.
207  */
208  timer->SR = ~flags;
209 
210  /* Check for an overflow event on this timer */
211  bool overflow_event;
212  uint16_t overflow_count;
213  if (flags & TIM_IT_Update) {
214  overflow_count = timer->ARR;
215  overflow_event = true;
216  } else {
217  overflow_count = 0;
218  overflow_event = false;
219  }
220 
221  /* Iterate over all registered clients of the TIM layer to find channels on this timer */
222  for (uint8_t i = 0; i < pios_tim_num_devs; i++) {
223  const struct pios_tim_dev * tim_dev = &pios_tim_devs[i];
224 
225  if (!tim_dev->channels || tim_dev->num_channels == 0) {
226  /* No channels to process on this client */
227  continue;
228  }
229 
230  for (uint8_t chan_num = 0; chan_num < tim_dev->num_channels; chan_num++) {
231  const struct pios_tim_channel *chan = &tim_dev->channels[chan_num];
232 
233  if (chan->timer != timer) {
234  /* channel is not on this timer */
235  continue;
236  }
237 
238  /* Figure out which interrupt bit we should be looking at */
239  uint16_t timer_it;
240  switch (chan->timer_chan) {
241  case TIM_Channel_1:
242  timer_it = TIM_IT_CC1;
243  break;
244  case TIM_Channel_2:
245  timer_it = TIM_IT_CC2;
246  break;
247  case TIM_Channel_3:
248  timer_it = TIM_IT_CC3;
249  break;
250  case TIM_Channel_4:
251  timer_it = TIM_IT_CC4;
252  break;
253  default:
254  PIOS_Assert(0);
255  break;
256  }
257 
258  bool edge_event;
259  uint16_t edge_count;
260  if (flags & timer_it) {
261  /* Read the current counter */
262  switch(chan->timer_chan) {
263  case TIM_Channel_1:
264  edge_count = TIM_GetCapture1(chan->timer);
265  break;
266  case TIM_Channel_2:
267  edge_count = TIM_GetCapture2(chan->timer);
268  break;
269  case TIM_Channel_3:
270  edge_count = TIM_GetCapture3(chan->timer);
271  break;
272  case TIM_Channel_4:
273  edge_count = TIM_GetCapture4(chan->timer);
274  break;
275  default:
276  PIOS_Assert(0);
277  break;
278  }
279  edge_event = true;
280  } else {
281  edge_event = false;
282  edge_count = 0;
283  }
284 
285  if (!tim_dev->callbacks) {
286  /* No callbacks registered, we're done with this channel */
287  continue;
288  }
289 
290  /* Generate the appropriate callbacks */
291  if (overflow_event && edge_event) {
292  /*
293  * When both edge and overflow happen in the same interrupt, we
294  * need a heuristic to determine the order of the edge and overflow
295  * events so that the callbacks happen in the right order. If we
296  * get the order wrong, our pulse width calculations could be off by up
297  * to ARR ticks. That could be bad.
298  *
299  * Heuristic: If the edge_count is in the last half of the timer period,
300  * assume it happened before the overflow.
301  */
302 
303  if (edge_count < (chan->timer->ARR / 2)) {
304  /* Call the overflow callback first */
305  if (tim_dev->callbacks->overflow) {
306  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
307  tim_dev->context,
308  chan_num,
309  overflow_count);
310  }
311  /* Call the edge callback second */
312  if (tim_dev->callbacks->edge) {
313  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
314  tim_dev->context,
315  chan_num,
316  edge_count);
317  }
318  } else {
319  /* Call the edge callback first */
320  if (tim_dev->callbacks->edge) {
321  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
322  tim_dev->context,
323  chan_num,
324  edge_count);
325  }
326  /* Call the overflow callback second */
327  if (tim_dev->callbacks->overflow) {
328  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
329  tim_dev->context,
330  chan_num,
331  overflow_count);
332  }
333  }
334  } else if (overflow_event && tim_dev->callbacks->overflow) {
335  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
336  tim_dev->context,
337  chan_num,
338  overflow_count);
339  } else if (edge_event && tim_dev->callbacks->edge) {
340  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
341  tim_dev->context,
342  chan_num,
343  edge_count);
344  }
345  }
346  }
347 }
348 
349 /* Bind Interrupt Handlers
350  *
351  * Map all valid TIM IRQs to the common interrupt handler
352  * and give it enough context to properly demux the various timers
353  */
354 void TIM1_UP_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_UP_irq_handler")));
355 static void PIOS_TIM_1_UP_irq_handler (void)
356 {
358 }
359 
360 void TIM1_CC_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_CC_irq_handler")));
361 static void PIOS_TIM_1_CC_irq_handler (void)
362 {
364 }
365 
366 void TIM2_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_2_irq_handler")));
367 static void PIOS_TIM_2_irq_handler (void)
368 {
370 }
371 
372 void TIM3_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_3_irq_handler")));
373 static void PIOS_TIM_3_irq_handler (void)
374 {
376 }
377 
378 void TIM4_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_4_irq_handler")));
379 static void PIOS_TIM_4_irq_handler (void)
380 {
382 }
383 
384 void TIM5_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_5_irq_handler")));
385 static void PIOS_TIM_5_irq_handler (void)
386 {
388 }
389 
390 void TIM6_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_6_irq_handler")));
391 static void PIOS_TIM_6_irq_handler (void)
392 {
394 }
395 
396 void TIM7_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_7_irq_handler")));
397 static void PIOS_TIM_7_irq_handler (void)
398 {
400 }
401 
402 void TIM8_UP_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_8_UP_irq_handler")));
403 static void PIOS_TIM_8_UP_irq_handler (void)
404 {
406 }
407 
408 void TIM8_CC_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_8_CC_irq_handler")));
409 static void PIOS_TIM_8_CC_irq_handler (void)
410 {
412 }
413 
void TIM3_IRQHandler(void)
Definition: pios_tim.c:335
const TIM_TimeBaseInitTypeDef * time_base_init
Definition: pios_tim_priv.h:8
void TIM1_UP_IRQHandler(void)
Definition: pios_tim.c:354
Main PiOS header to include all the compiled in PiOS options.
uint8_t num_channels
Definition: pios_tim.c:46
GPIO_InitTypeDef init
Definition: pios_stm32.h:61
void TIM5_IRQHandler(void)
Definition: pios_tim.c:384
static uint8_t pios_tim_num_devs
Definition: pios_tim.c:47
#define PIOS_TIM_MAX_DEVS
Definition: pios_board.h:215
GPIO_TypeDef * gpio
Definition: pios_stm32.h:60
void PIOS_TIM_InitTimerPin(uintptr_t tim_id, int idx)
Definition: pios_tim.c:94
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
pios_tim_dev_magic
Definition: pios_tim.c:38
void TIM8_UP_IRQHandler(void)
Definition: pios_tim.c:402
void(* overflow)(uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
Definition: pios_tim_priv.h:22
const struct pios_tim_channel * channels
Definition: pios_tim.c:45
void PIOS_TIM_InitAllTimerPins(uintptr_t tim_id)
Definition: pios_tim.c:109
uint16_t flags
Definition: uavtalk_priv.h:52
struct stm32_gpio pin
Definition: pios_tim_priv.h:17
static void PIOS_TIM_generic_irq_handler(TIM_TypeDef *timer)
Definition: pios_tim.c:197
uintptr_t context
Definition: pios_tim.c:49
void TIM7_IRQHandler(void)
Definition: pios_tim.c:396
enum pios_tim_dev_magic magic
Definition: pios_tim.c:43
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
TIM_TypeDef * timer
Definition: pios_tim_priv.h:7
void TIM4_IRQHandler(void)
Definition: pios_tim.c:378
static struct pios_tim_dev pios_tim_devs[PIOS_TIM_MAX_DEVS]
Definition: pios_tim.c:46
int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg *cfg)
Definition: pios_tim.c:68
uint8_t i
Definition: msp_messages.h:97
NVIC_InitTypeDef init
Definition: pios_stm32.h:36
void TIM2_IRQHandler(void)
Definition: pios_tim.c:327
const struct pios_tim_callbacks * callbacks
Definition: pios_tim.c:48
void TIM8_CC_IRQHandler(void)
Definition: pios_tim.c:408
int32_t PIOS_TIM_InitChannels(uintptr_t *tim_id, const struct pios_tim_channel *channels, uint8_t num_channels, const struct pios_tim_callbacks *callbacks, uintptr_t context)
Definition: pios_tim.c:142
void PIOS_TIM_SetBankToGPOut(uintptr_t tim_id, TIM_TypeDef *timer)
Definition: pios_tim.c:119
void TIM6_IRQHandler(void)
Definition: pios_tim.c:343
static struct pios_tim_dev * PIOS_TIM_alloc(void)
Definition: pios_tim.c:48
void TIM1_CC_IRQHandler(void)
Definition: pios_tim.c:317
TIM_TypeDef * timer
Definition: pios_tim_priv.h:14
void(* edge)(uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
Definition: pios_tim_priv.h:23
#define PIOS_Assert(test)
Definition: pios_debug.h:52
struct stm32_irq irq
Definition: pios_tim_priv.h:9