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 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  */
31 
32 
33 #include "pios.h"
34 
35 #include "pios_tim.h"
36 #include "pios_tim_priv.h"
37 
39  PIOS_TIM_DEV_MAGIC = 0x87654098,
40 };
41 
42 struct pios_tim_dev {
44 
45  const struct pios_tim_channel * channels;
46  uint8_t num_channels;
47 
48  const struct pios_tim_callbacks * callbacks;
49  uintptr_t context;
50 };
51 
53 static uint8_t pios_tim_num_devs;
54 static struct pios_tim_dev * PIOS_TIM_alloc(void)
55 {
56  struct pios_tim_dev * tim_dev;
57 
59  return (NULL);
60  }
61 
62  tim_dev = &pios_tim_devs[pios_tim_num_devs++];
63  tim_dev->magic = PIOS_TIM_DEV_MAGIC;
64 
65  return (tim_dev);
66 }
67 
68 int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg * cfg)
69 {
70  PIOS_DEBUG_Assert(cfg);
71 
72  /* Configure the dividers for this timer */
73  TIM_TimeBaseInit(cfg->timer, (TIM_TimeBaseInitTypeDef*)cfg->time_base_init);
74 
75  /* Configure internal timer clocks */
76  TIM_InternalClockConfig(cfg->timer);
77 
78  /* Enable timers */
79  TIM_Cmd(cfg->timer, ENABLE);
80 
81  /* Enable Interrupts */
82  NVIC_Init((NVIC_InitTypeDef*)&cfg->irq.init);
83 
84  /* Check for optional second vector (dirty hack)
85  * This is needed for timers 1 when requiring more than one event
86  * to generate an interrupt.
87  */
88  if (cfg->irq2.init.NVIC_IRQChannel != 0)
89  NVIC_Init((NVIC_InitTypeDef*)&cfg->irq2.init);
90 
91  return 0;
92 }
93 
94 void PIOS_TIM_InitTimerPin(uintptr_t tim_id, int idx)
95 {
96  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
97 
98  PIOS_Assert(idx < tim_dev->num_channels);
99 
100  const struct pios_tim_channel * chan = &tim_dev->channels[idx];
101 
102  GPIO_Init(chan->pin.gpio, (GPIO_InitTypeDef*)&chan->pin.init);
103 
104  PIOS_DEBUG_Assert(chan->remap);
105 
106  GPIO_PinAFConfig(chan->pin.gpio, chan->pin.pin_source, chan->remap);
107 }
108 
109 void PIOS_TIM_InitAllTimerPins(uintptr_t tim_id)
110 {
111  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
112 
113  /* Configure the pins */
114  for (uint8_t i = 0; i < tim_dev->num_channels; i++) {
115  PIOS_TIM_InitTimerPin(tim_id, i);
116  }
117 }
118 
119 void PIOS_TIM_SetBankToGPOut(uintptr_t tim_id, TIM_TypeDef *timer)
120 {
121  struct pios_tim_dev * tim_dev = (struct pios_tim_dev *) tim_id;
122 
123  GPIO_InitTypeDef gpio_inf;
124  gpio_inf.GPIO_Speed = GPIO_Speed_10MHz;
125  gpio_inf.GPIO_Mode = GPIO_Mode_OUT;
126  gpio_inf.GPIO_OType = GPIO_OType_PP;
127  gpio_inf.GPIO_PuPd = GPIO_PuPd_DOWN;
128 
129  for (uint8_t i = 0; i < tim_dev->num_channels; i++) {
130  const struct pios_tim_channel * chan = &tim_dev->channels[i];
131 
132  if (chan->timer != timer) {
133  continue;
134  }
135 
136  // Only steal the pin info from the matching pin
137  gpio_inf.GPIO_Pin = chan->pin.init.GPIO_Pin;
138  GPIO_Init(chan->pin.gpio, &gpio_inf);
139  }
140 }
141 
142 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)
143 {
144  PIOS_Assert(channels);
145  PIOS_Assert(num_channels);
146 
147  struct pios_tim_dev * tim_dev;
148  tim_dev = (struct pios_tim_dev *) PIOS_TIM_alloc();
149  if (!tim_dev) goto out_fail;
150 
151  /* Bind the configuration to the device instance */
152  tim_dev->channels = channels;
153  tim_dev->num_channels = num_channels;
154  tim_dev->callbacks = callbacks;
155  tim_dev->context = context;
156 
157  *tim_id = (uintptr_t)tim_dev;
158 
159  PIOS_TIM_InitAllTimerPins(*tim_id);
160 
161  return(0);
162 
163 out_fail:
164  return(-1);
165 }
166 
167 static void PIOS_TIM_generic_irq_handler(TIM_TypeDef * timer)
168 {
169  /* Check for an overflow event on this timer */
170  bool overflow_event;
171  uint16_t overflow_count;
172  if (TIM_GetITStatus(timer, TIM_IT_Update) == SET) {
173  TIM_ClearITPendingBit(timer, TIM_IT_Update);
174  overflow_count = timer->ARR;
175  overflow_event = true;
176  } else {
177  overflow_count = 0;
178  overflow_event = false;
179  }
180 
181  /* Iterate over all registered clients of the TIM layer to find channels on this timer */
182 
183  for (uint8_t i = 0; i < pios_tim_num_devs; i++) {
184  const struct pios_tim_dev * tim_dev = &pios_tim_devs[i];
185 
186  if (!tim_dev->channels || tim_dev->num_channels == 0) {
187  /* No channels to process on this client */
188  continue;
189  }
190 
191  for (uint8_t j = 0; j < tim_dev->num_channels; j++) {
192  const struct pios_tim_channel * chan = &tim_dev->channels[j];
193 
194  if (chan->timer != timer) {
195  /* channel is not on this timer */
196  continue;
197  }
198 
199  /* Figure out which interrupt bit we should be looking at */
200  uint16_t timer_it;
201  switch (chan->timer_chan) {
202  case TIM_Channel_1:
203  timer_it = TIM_IT_CC1;
204  break;
205  case TIM_Channel_2:
206  timer_it = TIM_IT_CC2;
207  break;
208  case TIM_Channel_3:
209  timer_it = TIM_IT_CC3;
210  break;
211  case TIM_Channel_4:
212  timer_it = TIM_IT_CC4;
213  break;
214  default:
215  PIOS_Assert(0);
216  break;
217  }
218 
219  bool edge_event;
220  uint16_t edge_count;
221  if (TIM_GetITStatus(chan->timer, timer_it) == SET) {
222  TIM_ClearITPendingBit(chan->timer, timer_it);
223 
224  /* Read the current counter */
225  switch(chan->timer_chan) {
226  case TIM_Channel_1:
227  edge_count = TIM_GetCapture1(chan->timer);
228  break;
229  case TIM_Channel_2:
230  edge_count = TIM_GetCapture2(chan->timer);
231  break;
232  case TIM_Channel_3:
233  edge_count = TIM_GetCapture3(chan->timer);
234  break;
235  case TIM_Channel_4:
236  edge_count = TIM_GetCapture4(chan->timer);
237  break;
238  default:
239  PIOS_Assert(0);
240  break;
241  }
242  edge_event = true;
243  } else {
244  edge_event = false;
245  edge_count = 0;
246  }
247 
248  if (!tim_dev->callbacks) {
249  /* No callbacks registered, we're done with this channel */
250  continue;
251  }
252 
253  /* Generate the appropriate callbacks */
254  if (overflow_event && edge_event) {
255  /*
256  * When both edge and overflow happen in the same interrupt, we
257  * need a heuristic to determine the order of the edge and overflow
258  * events so that the callbacks happen in the right order. If we
259  * get the order wrong, our pulse width calculations could be off by up
260  * to ARR ticks. That could be bad.
261  *
262  * Heuristic: If the edge_count is < 16 ticks above zero then we assume the
263  * edge happened just after the overflow.
264  */
265 
266  if (edge_count < 16) {
267  /* Call the overflow callback first */
268  if (tim_dev->callbacks->overflow) {
269  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
270  tim_dev->context,
271  j,
272  overflow_count);
273  }
274  /* Call the edge callback second */
275  if (tim_dev->callbacks->edge) {
276  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
277  tim_dev->context,
278  j,
279  edge_count);
280  }
281  } else {
282  /* Call the edge callback first */
283  if (tim_dev->callbacks->edge) {
284  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
285  tim_dev->context,
286  j,
287  edge_count);
288  }
289  /* Call the overflow callback second */
290  if (tim_dev->callbacks->overflow) {
291  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
292  tim_dev->context,
293  j,
294  overflow_count);
295  }
296  }
297  } else if (overflow_event && tim_dev->callbacks->overflow) {
298  (*tim_dev->callbacks->overflow)((uintptr_t)tim_dev,
299  tim_dev->context,
300  j,
301  overflow_count);
302  } else if (edge_event && tim_dev->callbacks->edge) {
303  (*tim_dev->callbacks->edge)((uintptr_t)tim_dev,
304  tim_dev->context,
305  j,
306  edge_count);
307  }
308  }
309  }
310 }
311 
312 /* Bind Interrupt Handlers
313  *
314  * Map all valid TIM IRQs to the common interrupt handler
315  * and give it enough context to properly demux the various timers
316  */
317 void TIM1_CC_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_irq_handler")));
318 void TIM1_BRK_UP_TRG_COM_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_1_irq_handler")));
319 static void PIOS_TIM_1_irq_handler (void)
320 {
324 }
325 
326 
327 void TIM2_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_2_irq_handler")));
328 static void PIOS_TIM_2_irq_handler (void)
329 {
333 }
334 
335 void TIM3_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_3_irq_handler")));
336 static void PIOS_TIM_3_irq_handler (void)
337 {
341 }
342 
343 void TIM6_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_6_irq_handler")));
344 static void PIOS_TIM_6_irq_handler (void)
345 {
349 }
350 
351 void TIM14_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_14_irq_handler")));
352 static void PIOS_TIM_14_irq_handler (void)
353 {
357 }
358 
359 void TIM15_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_15_irq_handler")));
360 static void PIOS_TIM_15_irq_handler (void)
361 {
365 }
366 
367 void TIM16_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_16_irq_handler")));
368 static void PIOS_TIM_16_irq_handler (void)
369 {
373 }
374 
375 void TIM17_IRQHandler(void) __attribute__ ((alias ("PIOS_TIM_17_irq_handler")));
376 static void PIOS_TIM_17_irq_handler (void)
377 {
381 }
void TIM3_IRQHandler(void)
Definition: pios_tim.c:335
const TIM_TimeBaseInitTypeDef * time_base_init
Definition: pios_tim_priv.h:8
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
static uint8_t pios_tim_num_devs
Definition: pios_tim.c:53
#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
#define PIOS_IRQ_Epilogue()
Definition: pios_irq.h:46
pios_tim_dev_magic
Definition: pios_tim.c:38
volatile int j
Definition: loadabletest.c:12
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
struct stm32_irq irq2
Definition: pios_tim_priv.h:10
void PIOS_TIM_InitAllTimerPins(uintptr_t tim_id)
Definition: pios_tim.c:109
struct stm32_gpio pin
Definition: pios_tim_priv.h:17
void TIM15_IRQHandler(void)
Definition: pios_tim.c:359
uintptr_t context
Definition: pios_tim.c:49
static struct pios_tim_dev * PIOS_TIM_alloc(void)
Definition: pios_tim.c:54
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
static struct pios_tim_dev pios_tim_devs[PIOS_TIM_MAX_DEVS]
Definition: pios_tim.c:52
int32_t PIOS_TIM_InitClock(const struct pios_tim_clock_cfg *cfg)
Definition: pios_tim.c:68
void TIM16_IRQHandler(void)
Definition: pios_tim.c:367
uint8_t i
Definition: msp_messages.h:97
NVIC_InitTypeDef init
Definition: pios_stm32.h:36
uint8_t pin_source
Definition: pios_stm32.h:62
void TIM2_IRQHandler(void)
Definition: pios_tim.c:327
const struct pios_tim_callbacks * callbacks
Definition: pios_tim.c:48
void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
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 TIM17_IRQHandler(void)
Definition: pios_tim.c:375
void TIM6_IRQHandler(void)
Definition: pios_tim.c:343
#define PIOS_IRQ_Prologue()
Definition: pios_irq.h:45
void TIM14_IRQHandler(void)
Definition: pios_tim.c:351
static void PIOS_TIM_generic_irq_handler(TIM_TypeDef *timer)
Definition: pios_tim.c:167
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