Paparazzi UAS  v5.14.0_stable-0-g3f680d1
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
pwm_input_arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Gautier Hattenberger
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
28 #include "mcu_periph/pwm_input.h"
29 
30 #include BOARD_CONFIG
31 #include "generated/airframe.h"
32 
33 #include <libopencm3/stm32/rcc.h>
34 #include <libopencm3/stm32/gpio.h>
35 #include <libopencm3/stm32/timer.h>
36 #include <libopencm3/cm3/nvic.h>
37 
38 #include "mcu_periph/sys_time.h"
39 #include "mcu_periph/gpio.h"
40 
41 // for timer_get_frequency
42 #include "mcu_arch.h"
43 
44 #define ONE_MHZ_CLK 1000000
45 #ifdef NVIC_TIM_IRQ_PRIO
46 #define PWM_INPUT_IRQ_PRIO NVIC_TIM_IRQ_PRIO
47 #else
48 #define PWM_INPUT_IRQ_PRIO 2
49 #endif
50 
51 static inline void pwm_input_set_timer(uint32_t tim, uint32_t ticks_per_usec)
52 {
53  timer_reset(tim);
54  timer_set_mode(tim, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
55  timer_set_period(tim, 0xFFFF);
56  uint32_t timer_clk = timer_get_frequency(tim);
57  timer_set_prescaler(tim, (timer_clk / (ticks_per_usec * ONE_MHZ_CLK)) - 1);
58  timer_enable_counter(tim);
59 }
60 
61 void pwm_input_init(void)
62 {
63  int i;
64  // initialize the arrays to 0
65  for (i = 0; i < PWM_INPUT_NB; i++) {
66  pwm_input_duty_tics[i] = 0;
67  pwm_input_duty_valid[i] = 0;
68  pwm_input_period_tics[i] = 0;
70  }
71 
77 #if USE_PWM_INPUT_TIM1
78  rcc_periph_clock_enable(RCC_TIM1);
79  pwm_input_set_timer(TIM1, TIM1_TICKS_PER_USEC);
80 #endif
81 #if USE_PWM_INPUT_TIM2
82  rcc_periph_clock_enable(RCC_TIM2);
83  pwm_input_set_timer(TIM2, TIM2_TICKS_PER_USEC);
84 #endif
85 #if USE_PWM_INPUT_TIM3
86  rcc_periph_clock_enable(RCC_TIM3);
87  pwm_input_set_timer(TIM3, TIM3_TICKS_PER_USEC);
88 #endif
89 #if USE_PWM_INPUT_TIM4
90  rcc_periph_clock_enable(RCC_TIM4);
91  pwm_input_set_timer(TIM4, TIM4_TICKS_PER_USEC);
92 #endif
93 #if USE_PWM_INPUT_TIM5
94  rcc_periph_clock_enable(RCC_TIM5);
95  pwm_input_set_timer(TIM5, TIM5_TICKS_PER_USEC);
96 #endif
97 #if USE_PWM_INPUT_TIM8
98  rcc_periph_clock_enable(RCC_TIM8);
99  pwm_input_set_timer(TIM8, TIM8_TICKS_PER_USEC);
100 #endif
101 #if USE_PWM_INPUT_TIM9
102  rcc_periph_clock_enable(RCC_TIM9);
103  pwm_input_set_timer(TIM9, TIM9_TICKS_PER_USEC);
104 #endif
105 
106 #ifdef USE_PWM_INPUT1
107  /* GPIO configuration as input capture for timer */
109 
115 #if USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_LOW
116  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_RISING);
117  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_FALLING);
118 #elif USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_HIGH
119  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_FALLING);
120  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_RISING);
121 #endif
122 
123  /* Select the valid trigger input */
124  timer_slave_set_trigger(PWM_INPUT1_TIMER, PWM_INPUT1_SLAVE_TRIG);
125  /* Configure the slave mode controller in reset mode */
126  timer_slave_set_mode(PWM_INPUT1_TIMER, TIM_SMCR_SMS_RM);
127 
128  /* Enable timer Interrupt(s). */
129  nvic_set_priority(PWM_INPUT1_IRQ, PWM_INPUT_IRQ_PRIO);
130  nvic_enable_irq(PWM_INPUT1_IRQ);
131 #ifdef PWM_INPUT1_IRQ2
132  nvic_set_priority(PWM_INPUT1_IRQ2, PWM_INPUT_IRQ_PRIO);
133  nvic_enable_irq(PWM_INPUT1_IRQ2);
134 #endif
135 
136  /* Enable the Capture/Compare and Update interrupt requests. */
137  timer_enable_irq(PWM_INPUT1_TIMER, (PWM_INPUT1_CC_IE | TIM_DIER_UIE));
138 
139  /* Enable capture channel. */
141  timer_ic_enable(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY);
142 #endif
143 
144 #ifdef USE_PWM_INPUT2
145  /* GPIO configuration as input capture for timer */
147 
153 #if USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_LOW
154  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_RISING);
155  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_FALLING);
156 #elif USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_HIGH
157  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_FALLING);
158  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_RISING);
159 #endif
160 
161  /* Select the valid trigger input */
162  timer_slave_set_trigger(PWM_INPUT2_TIMER, PWM_INPUT2_SLAVE_TRIG);
163  /* Configure the slave mode controller in reset mode */
164  timer_slave_set_mode(PWM_INPUT2_TIMER, TIM_SMCR_SMS_RM);
165 
166  /* Enable timer Interrupt(s). */
167  nvic_set_priority(PWM_INPUT2_IRQ, PWM_INPUT_IRQ_PRIO);
168  nvic_enable_irq(PWM_INPUT2_IRQ);
169 #ifdef PWM_INPUT2_IRQ2
170  nvic_set_priority(PWM_INPUT2_IRQ2, PWM_INPUT_IRQ_PRIO);
171  nvic_enable_irq(PWM_INPUT2_IRQ2);
172 #endif
173 
174  /* Enable the Capture/Compare and Update interrupt requests. */
175  timer_enable_irq(PWM_INPUT2_TIMER, (PWM_INPUT2_CC_IE | TIM_DIER_UIE));
176 
177  /* Enable capture channel. */
179  timer_ic_enable(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY);
180 #endif
181 
182 }
183 
184 
185 #if USE_PWM_INPUT_TIM1
186 
187 #if defined(STM32F1)
188 void tim1_up_isr(void)
189 {
190 #elif defined(STM32F4)
191 void tim1_up_tim10_isr(void) {
192 #endif
193  if ((TIM1_SR & TIM_SR_UIF) != 0) {
194  timer_clear_flag(TIM1, TIM_SR_UIF);
195  // FIXME clear overflow interrupt but what else ?
196  }
197 }
198 
199 void tim1_cc_isr(void) {
200  if ((TIM1_SR & TIM1_CC_IF_PERIOD) != 0) {
201  timer_clear_flag(TIM1, TIM1_CC_IF_PERIOD);
204  }
205  if ((TIM1_SR & TIM1_CC_IF_DUTY) != 0) {
206  timer_clear_flag(TIM1, TIM1_CC_IF_DUTY);
209  }
210 }
211 
212 #endif
213 
214 #if USE_PWM_INPUT_TIM2
215 
216 void tim2_isr(void) {
217  if ((TIM2_SR & TIM2_CC_IF_PERIOD) != 0) {
218  timer_clear_flag(TIM2, TIM2_CC_IF_PERIOD);
219  pwm_input_period_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_PERIOD;
220  pwm_input_period_valid[TIM2_PWM_INPUT_IDX] = true;
221  }
222  if ((TIM2_SR & TIM2_CC_IF_DUTY) != 0) {
223  timer_clear_flag(TIM2, TIM2_CC_IF_DUTY);
224  pwm_input_duty_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_DUTY;
225  pwm_input_duty_valid[TIM2_PWM_INPUT_IDX] = true;
226  }
227  if ((TIM2_SR & TIM_SR_UIF) != 0) {
228  timer_clear_flag(TIM2, TIM_SR_UIF);
229  // FIXME clear overflow interrupt but what else ?
230  }
231 }
232 
233 #endif
234 
235 #if USE_PWM_INPUT_TIM3
236 
237 void tim3_isr(void) {
238  if ((TIM3_SR & TIM3_CC_IF_PERIOD) != 0) {
239  timer_clear_flag(TIM3, TIM3_CC_IF_PERIOD);
240  pwm_input_period_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_PERIOD;
241  pwm_input_period_valid[TIM3_PWM_INPUT_IDX] = true;
242  }
243  if ((TIM3_SR & TIM3_CC_IF_DUTY) != 0) {
244  timer_clear_flag(TIM3, TIM3_CC_IF_DUTY);
245  pwm_input_duty_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_DUTY;
246  pwm_input_duty_valid[TIM3_PWM_INPUT_IDX] = true;
247  }
248  if ((TIM3_SR & TIM_SR_UIF) != 0) {
249  timer_clear_flag(TIM3, TIM_SR_UIF);
250  // FIXME clear overflow interrupt but what else ?
251  }
252 }
253 
254 #endif
255 
256 #if USE_PWM_INPUT_TIM4
257 
258 void tim4_isr(void) {
259  if ((TIM4_SR & TIM4_CC_IF_PERIOD) != 0) {
260  timer_clear_flag(TIM4, TIM4_CC_IF_PERIOD);
261  pwm_input_period_tics[TIM4_PWM_INPUT_IDX] = TIM4_CCR_PERIOD;
262  pwm_input_period_valid[TIM4_PWM_INPUT_IDX] = true;
263  }
264  if ((TIM4_SR & TIM4_CC_IF_DUTY) != 0) {
265  timer_clear_flag(TIM4, TIM4_CC_IF_DUTY);
266  pwm_input_duty_tics[TIM4_PWM_INPUT_IDX] = TIM4_CCR_DUTY;
267  pwm_input_duty_valid[TIM4_PWM_INPUT_IDX] = true;
268  }
269  if ((TIM4_SR & TIM_SR_UIF) != 0) {
270  timer_clear_flag(TIM4, TIM_SR_UIF);
271  // FIXME clear overflow interrupt but what else ?
272  }
273 }
274 
275 #endif
276 
277 #if USE_PWM_INPUT_TIM5
278 
279 void tim5_isr(void) {
280  if ((TIM5_SR & TIM5_CC_IF_PERIOD) != 0) {
281  timer_clear_flag(TIM5, TIM5_CC_IF_PERIOD);
282  pwm_input_period_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_PERIOD;
283  pwm_input_period_valid[TIM5_PWM_INPUT_IDX] = true;
284  }
285  if ((TIM5_SR & TIM5_CC_IF_DUTY) != 0) {
286  timer_clear_flag(TIM5, TIM5_CC_IF_DUTY);
287  pwm_input_duty_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_DUTY;
288  pwm_input_duty_valid[TIM5_PWM_INPUT_IDX] = true;
289  }
290  if ((TIM5_SR & TIM_SR_UIF) != 0) {
291  timer_clear_flag(TIM5, TIM_SR_UIF);
292  // FIXME clear overflow interrupt but what else ?
293  }
294 }
295 
296 #endif
297 
298 #if USE_PWM_INPUT_TIM8
299 
300 #if defined(STM32F1)
301 void tim8_up_isr(void)
302 {
303 #elif defined(STM32F4)
304 void tim8_up_tim13_isr(void) {
305 #endif
306  if ((TIM8_SR & TIM_SR_UIF) != 0) {
307  timer_clear_flag(TIM8, TIM_SR_UIF);
308  // FIXME clear overflow interrupt but what else ?
309  }
310 }
311 
312 void tim8_cc_isr(void) {
313  if ((TIM8_SR & TIM8_CC_IF_PERIOD) != 0) {
314  timer_clear_flag(TIM8, TIM8_CC_IF_PERIOD);
315  pwm_input_period_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_PERIOD;
316  pwm_input_period_valid[TIM8_PWM_INPUT_IDX] = true;
317  }
318  if ((TIM8_SR & TIM8_CC_IF_DUTY) != 0) {
319  timer_clear_flag(TIM8, TIM8_CC_IF_DUTY);
320  pwm_input_duty_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_DUTY;
321  pwm_input_duty_valid[TIM8_PWM_INPUT_IDX] = true;
322  }
323 }
324 
325 #endif
326 
327 #if USE_PWM_INPUT_TIM9
328 
329 // TIM1 break interrupt (which we don't care here) and TIM9 global interrupt
330 void tim1_brk_tim9_isr(void) {
331  if ((TIM9_SR & TIM9_CC_IF_PERIOD) != 0) {
332  timer_clear_flag(TIM9, TIM9_CC_IF_PERIOD);
335  }
336  if ((TIM9_SR & TIM9_CC_IF_DUTY) != 0) {
337  timer_clear_flag(TIM9, TIM9_CC_IF_DUTY);
340  }
341  if ((TIM9_SR & TIM_SR_UIF) != 0) {
342  timer_clear_flag(TIM9, TIM_SR_UIF);
343  // FIXME clear overflow interrupt but what else ?
344  }
345 }
346 
347 #endif
348 
void gpio_setup_pin_af(ioportid_t port, uint16_t pin, uint8_t af, bool is_output)
Setup a gpio for input or output with alternate function.
Definition: gpio_arch.c:61
void pwm_input_init(void)
#define PWM_INPUT2_TIMER
Definition: apogee_1.0.h:382
volatile uint32_t pwm_input_duty_tics[PWM_INPUT_NB]
Definition: pwm_input.c:34
#define PWM_INPUT1_GPIO_PIN
Definition: board.h:384
#define TIM1_CC_IF_DUTY
Definition: apogee_1.0.h:373
Some architecture independent helper functions for GPIOs.
arch independent PWM input capture API
#define PWM_INPUT2_GPIO_AF
Definition: board.h:395
#define PWM_INPUT1_TIMER
Definition: apogee_1.0.h:359
#define TIM9_CCR_DUTY
Definition: apogee_1.0.h:401
uint32_t timer_get_frequency(uint32_t timer_peripheral)
Get Timer clock frequency (before prescaling) Only valid if using the internal clock for the timer...
Definition: mcu_arch.c:263
#define PWM_INPUT1_TIMER_INPUT
Definition: apogee_1.0.h:365
volatile uint8_t pwm_input_period_valid[PWM_INPUT_NB]
Definition: pwm_input.c:37
#define PWM_INPUT1_IRQ2
Definition: apogee_1.0.h:368
volatile uint8_t pwm_input_duty_valid[PWM_INPUT_NB]
Definition: pwm_input.c:35
#define FALSE
Definition: std.h:5
#define PWM_INPUT2_CHANNEL_DUTY
Definition: apogee_1.0.h:387
#define TIM1_PWM_INPUT_IDX
Definition: apogee_1.0.h:371
#define TIM1_CCR_PERIOD
Definition: apogee_1.0.h:374
#define TIM1_CCR_DUTY
Definition: apogee_1.0.h:375
#define PWM_INPUT1_GPIO_PORT
Definition: board.h:383
Architecture independent timing functions.
#define PWM_INPUT1_CC_IE
Definition: apogee_1.0.h:369
#define PWM_INPUT1_GPIO_AF
Definition: board.h:385
#define PWM_INPUT2_TIMER_INPUT
Definition: apogee_1.0.h:388
#define PWM_INPUT1_CHANNEL_DUTY
Definition: apogee_1.0.h:364
#define PWM_INPUT_IRQ_PRIO
#define TIM9_CC_IF_DUTY
Definition: apogee_1.0.h:399
#define PWM_INPUT2_CHANNEL_PERIOD
Definition: apogee_1.0.h:386
unsigned long uint32_t
Definition: types.h:18
#define PWM_INPUT2_IRQ
Definition: apogee_1.0.h:390
#define TIM9_CCR_PERIOD
Definition: apogee_1.0.h:400
volatile uint32_t pwm_input_period_tics[PWM_INPUT_NB]
Definition: pwm_input.c:36
#define PWM_INPUT2_CC_IE
Definition: apogee_1.0.h:391
#define PWM_INPUT2_SLAVE_TRIG
Definition: apogee_1.0.h:389
#define PWM_INPUT1_SLAVE_TRIG
Definition: apogee_1.0.h:366
#define ONE_MHZ_CLK
#define PWM_INPUT1_IRQ
Definition: apogee_1.0.h:367
#define PWM_INPUT2_GPIO_PORT
Definition: board.h:393
#define PWM_INPUT2_GPIO_PIN
Definition: board.h:394
#define TIM9_PWM_INPUT_IDX
Definition: apogee_1.0.h:397
#define TIM1_CC_IF_PERIOD
Definition: apogee_1.0.h:372
static void pwm_input_set_timer(uint32_t tim, uint32_t ticks_per_usec)
#define TIM9_CC_IF_PERIOD
Definition: apogee_1.0.h:398
#define PWM_INPUT1_CHANNEL_PERIOD
Definition: apogee_1.0.h:363