Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
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_set_mode(tim, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
54  timer_set_period(tim, 0xFFFF);
55  uint32_t timer_clk = timer_get_frequency(tim);
56  timer_set_prescaler(tim, (timer_clk / (ticks_per_usec * ONE_MHZ_CLK)) - 1);
57  timer_enable_counter(tim);
58 }
59 
60 void pwm_input_init(void)
61 {
62  int i;
63  // initialize the arrays to 0
64  for (i = 0; i < PWM_INPUT_NB; i++) {
65  pwm_input_duty_tics[i] = 0;
66  pwm_input_duty_valid[i] = 0;
67  pwm_input_period_tics[i] = 0;
69  }
70 
76 #if USE_PWM_INPUT_TIM1
77  rcc_periph_clock_enable(RCC_TIM1);
78  rcc_periph_reset_pulse(RST_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  rcc_periph_reset_pulse(RST_TIM2);
84  pwm_input_set_timer(TIM2, TIM2_TICKS_PER_USEC);
85 #endif
86 #if USE_PWM_INPUT_TIM3
87  rcc_periph_clock_enable(RCC_TIM3);
88  rcc_periph_reset_pulse(RST_TIM3);
89  pwm_input_set_timer(TIM3, TIM3_TICKS_PER_USEC);
90 #endif
91 #if USE_PWM_INPUT_TIM4
92  rcc_periph_clock_enable(RCC_TIM4);
93  rcc_periph_reset_pulse(RST_TIM4);
94  pwm_input_set_timer(TIM4, TIM4_TICKS_PER_USEC);
95 #endif
96 #if USE_PWM_INPUT_TIM5
97  rcc_periph_clock_enable(RCC_TIM5);
98  rcc_periph_reset_pulse(RST_TIM5);
99  pwm_input_set_timer(TIM5, TIM5_TICKS_PER_USEC);
100 #endif
101 #if USE_PWM_INPUT_TIM8
102  rcc_periph_clock_enable(RCC_TIM8);
103  rcc_periph_reset_pulse(RST_TIM8);
104  pwm_input_set_timer(TIM8, TIM8_TICKS_PER_USEC);
105 #endif
106 #if USE_PWM_INPUT_TIM9
107  rcc_periph_clock_enable(RCC_TIM9);
108  rcc_periph_reset_pulse(RST_TIM9);
109  pwm_input_set_timer(TIM9, TIM9_TICKS_PER_USEC);
110 #endif
111 
112 #ifdef USE_PWM_INPUT1
113  /* GPIO configuration as input capture for timer */
115 
121 #if USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_LOW
122  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_RISING);
123  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_FALLING);
124 #elif USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_HIGH
125  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_FALLING);
126  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_RISING);
127 #endif
128 
129  /* Select the valid trigger input */
130  timer_slave_set_trigger(PWM_INPUT1_TIMER, PWM_INPUT1_SLAVE_TRIG);
131  /* Configure the slave mode controller in reset mode */
132  timer_slave_set_mode(PWM_INPUT1_TIMER, TIM_SMCR_SMS_RM);
133 
134  /* Enable timer Interrupt(s). */
135  nvic_set_priority(PWM_INPUT1_IRQ, PWM_INPUT_IRQ_PRIO);
136  nvic_enable_irq(PWM_INPUT1_IRQ);
137 #ifdef PWM_INPUT1_IRQ2
138  nvic_set_priority(PWM_INPUT1_IRQ2, PWM_INPUT_IRQ_PRIO);
139  nvic_enable_irq(PWM_INPUT1_IRQ2);
140 #endif
141 
142  /* Enable the Capture/Compare and Update interrupt requests. */
143  timer_enable_irq(PWM_INPUT1_TIMER, (PWM_INPUT1_CC_IE | TIM_DIER_UIE));
144 
145  /* Enable capture channel. */
147  timer_ic_enable(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY);
148 #endif
149 
150 #ifdef USE_PWM_INPUT2
151  /* GPIO configuration as input capture for timer */
153 
159 #if USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_LOW
160  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_RISING);
161  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_FALLING);
162 #elif USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_HIGH
163  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_FALLING);
164  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_RISING);
165 #endif
166 
167  /* Select the valid trigger input */
168  timer_slave_set_trigger(PWM_INPUT2_TIMER, PWM_INPUT2_SLAVE_TRIG);
169  /* Configure the slave mode controller in reset mode */
170  timer_slave_set_mode(PWM_INPUT2_TIMER, TIM_SMCR_SMS_RM);
171 
172  /* Enable timer Interrupt(s). */
173  nvic_set_priority(PWM_INPUT2_IRQ, PWM_INPUT_IRQ_PRIO);
174  nvic_enable_irq(PWM_INPUT2_IRQ);
175 #ifdef PWM_INPUT2_IRQ2
176  nvic_set_priority(PWM_INPUT2_IRQ2, PWM_INPUT_IRQ_PRIO);
177  nvic_enable_irq(PWM_INPUT2_IRQ2);
178 #endif
179 
180  /* Enable the Capture/Compare and Update interrupt requests. */
181  timer_enable_irq(PWM_INPUT2_TIMER, (PWM_INPUT2_CC_IE | TIM_DIER_UIE));
182 
183  /* Enable capture channel. */
185  timer_ic_enable(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY);
186 #endif
187 
188 }
189 
190 
191 #if USE_PWM_INPUT_TIM1
192 
193 #if defined(STM32F1)
194 void tim1_up_isr(void)
195 {
196 #elif defined(STM32F4)
197 void tim1_up_tim10_isr(void) {
198 #endif
199  if ((TIM1_SR & TIM_SR_UIF) != 0) {
200  timer_clear_flag(TIM1, TIM_SR_UIF);
201  // FIXME clear overflow interrupt but what else ?
202  }
203 }
204 
205 void tim1_cc_isr(void) {
206  if ((TIM1_SR & TIM1_CC_IF_PERIOD) != 0) {
207  timer_clear_flag(TIM1, TIM1_CC_IF_PERIOD);
210  }
211  if ((TIM1_SR & TIM1_CC_IF_DUTY) != 0) {
212  timer_clear_flag(TIM1, TIM1_CC_IF_DUTY);
215  }
216 }
217 
218 #endif
219 
220 #if USE_PWM_INPUT_TIM2
221 
222 void tim2_isr(void) {
223  if ((TIM2_SR & TIM2_CC_IF_PERIOD) != 0) {
224  timer_clear_flag(TIM2, TIM2_CC_IF_PERIOD);
225  pwm_input_period_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_PERIOD;
226  pwm_input_period_valid[TIM2_PWM_INPUT_IDX] = true;
227  }
228  if ((TIM2_SR & TIM2_CC_IF_DUTY) != 0) {
229  timer_clear_flag(TIM2, TIM2_CC_IF_DUTY);
230  pwm_input_duty_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_DUTY;
231  pwm_input_duty_valid[TIM2_PWM_INPUT_IDX] = true;
232  }
233  if ((TIM2_SR & TIM_SR_UIF) != 0) {
234  timer_clear_flag(TIM2, TIM_SR_UIF);
235  // FIXME clear overflow interrupt but what else ?
236  }
237 }
238 
239 #endif
240 
241 #if USE_PWM_INPUT_TIM3
242 
243 void tim3_isr(void) {
244  if ((TIM3_SR & TIM3_CC_IF_PERIOD) != 0) {
245  timer_clear_flag(TIM3, TIM3_CC_IF_PERIOD);
246  pwm_input_period_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_PERIOD;
247  pwm_input_period_valid[TIM3_PWM_INPUT_IDX] = true;
248  }
249  if ((TIM3_SR & TIM3_CC_IF_DUTY) != 0) {
250  timer_clear_flag(TIM3, TIM3_CC_IF_DUTY);
251  pwm_input_duty_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_DUTY;
252  pwm_input_duty_valid[TIM3_PWM_INPUT_IDX] = true;
253  }
254  if ((TIM3_SR & TIM_SR_UIF) != 0) {
255  timer_clear_flag(TIM3, TIM_SR_UIF);
256  // FIXME clear overflow interrupt but what else ?
257  }
258 }
259 
260 #endif
261 
262 #if USE_PWM_INPUT_TIM4
263 
264 void tim4_isr(void) {
265  if ((TIM4_SR & TIM4_CC_IF_PERIOD) != 0) {
266  timer_clear_flag(TIM4, TIM4_CC_IF_PERIOD);
267  pwm_input_period_tics[TIM4_PWM_INPUT_IDX] = TIM4_CCR_PERIOD;
268  pwm_input_period_valid[TIM4_PWM_INPUT_IDX] = true;
269  }
270  if ((TIM4_SR & TIM4_CC_IF_DUTY) != 0) {
271  timer_clear_flag(TIM4, TIM4_CC_IF_DUTY);
272  pwm_input_duty_tics[TIM4_PWM_INPUT_IDX] = TIM4_CCR_DUTY;
273  pwm_input_duty_valid[TIM4_PWM_INPUT_IDX] = true;
274  }
275  if ((TIM4_SR & TIM_SR_UIF) != 0) {
276  timer_clear_flag(TIM4, TIM_SR_UIF);
277  // FIXME clear overflow interrupt but what else ?
278  }
279 }
280 
281 #endif
282 
283 #if USE_PWM_INPUT_TIM5
284 
285 void tim5_isr(void) {
286  if ((TIM5_SR & TIM5_CC_IF_PERIOD) != 0) {
287  timer_clear_flag(TIM5, TIM5_CC_IF_PERIOD);
288  pwm_input_period_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_PERIOD;
289  pwm_input_period_valid[TIM5_PWM_INPUT_IDX] = true;
290  }
291  if ((TIM5_SR & TIM5_CC_IF_DUTY) != 0) {
292  timer_clear_flag(TIM5, TIM5_CC_IF_DUTY);
293  pwm_input_duty_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_DUTY;
294  pwm_input_duty_valid[TIM5_PWM_INPUT_IDX] = true;
295  }
296  if ((TIM5_SR & TIM_SR_UIF) != 0) {
297  timer_clear_flag(TIM5, TIM_SR_UIF);
298  // FIXME clear overflow interrupt but what else ?
299  }
300 }
301 
302 #endif
303 
304 #if USE_PWM_INPUT_TIM8
305 
306 #if defined(STM32F1)
307 void tim8_up_isr(void)
308 {
309 #elif defined(STM32F4)
310 void tim8_up_tim13_isr(void) {
311 #endif
312  if ((TIM8_SR & TIM_SR_UIF) != 0) {
313  timer_clear_flag(TIM8, TIM_SR_UIF);
314  // FIXME clear overflow interrupt but what else ?
315  }
316 }
317 
318 void tim8_cc_isr(void) {
319  if ((TIM8_SR & TIM8_CC_IF_PERIOD) != 0) {
320  timer_clear_flag(TIM8, TIM8_CC_IF_PERIOD);
321  pwm_input_period_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_PERIOD;
322  pwm_input_period_valid[TIM8_PWM_INPUT_IDX] = true;
323  }
324  if ((TIM8_SR & TIM8_CC_IF_DUTY) != 0) {
325  timer_clear_flag(TIM8, TIM8_CC_IF_DUTY);
326  pwm_input_duty_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_DUTY;
327  pwm_input_duty_valid[TIM8_PWM_INPUT_IDX] = true;
328  }
329 }
330 
331 #endif
332 
333 #if USE_PWM_INPUT_TIM9
334 
335 // TIM1 break interrupt (which we don't care here) and TIM9 global interrupt
336 void tim1_brk_tim9_isr(void) {
337  if ((TIM9_SR & TIM9_CC_IF_PERIOD) != 0) {
338  timer_clear_flag(TIM9, TIM9_CC_IF_PERIOD);
341  }
342  if ((TIM9_SR & TIM9_CC_IF_DUTY) != 0) {
343  timer_clear_flag(TIM9, TIM9_CC_IF_DUTY);
346  }
347  if ((TIM9_SR & TIM_SR_UIF) != 0) {
348  timer_clear_flag(TIM9, TIM_SR_UIF);
349  // FIXME clear overflow interrupt but what else ?
350  }
351 }
352 
353 #endif
354 
#define PWM_INPUT2_GPIO_PORT
Definition: board.h:430
#define PWM_INPUT2_GPIO_AF
Definition: board.h:432
#define PWM_INPUT2_GPIO_PIN
Definition: board.h:431
#define PWM_INPUT2_IRQ
Definition: apogee_1.0.h:390
#define PWM_INPUT1_TIMER_INPUT
Definition: apogee_1.0.h:365
#define TIM9_PWM_INPUT_IDX
Definition: apogee_1.0.h:397
#define PWM_INPUT2_CC_IE
Definition: apogee_1.0.h:391
#define TIM9_CC_IF_DUTY
Definition: apogee_1.0.h:399
#define TIM1_CCR_PERIOD
Definition: apogee_1.0.h:374
#define PWM_INPUT2_SLAVE_TRIG
Definition: apogee_1.0.h:389
#define TIM1_CC_IF_PERIOD
Definition: apogee_1.0.h:372
#define TIM9_CC_IF_PERIOD
Definition: apogee_1.0.h:398
#define PWM_INPUT1_SLAVE_TRIG
Definition: apogee_1.0.h:366
#define TIM9_CCR_PERIOD
Definition: apogee_1.0.h:400
#define TIM1_CC_IF_DUTY
Definition: apogee_1.0.h:373
#define PWM_INPUT1_CHANNEL_PERIOD
Definition: apogee_1.0.h:363
#define TIM1_PWM_INPUT_IDX
Definition: apogee_1.0.h:371
#define PWM_INPUT1_TIMER
Definition: apogee_1.0.h:359
#define PWM_INPUT1_CHANNEL_DUTY
Definition: apogee_1.0.h:364
#define PWM_INPUT1_IRQ
Definition: apogee_1.0.h:367
#define PWM_INPUT2_CHANNEL_DUTY
Definition: apogee_1.0.h:387
#define PWM_INPUT1_CC_IE
Definition: apogee_1.0.h:369
#define TIM1_CCR_DUTY
Definition: apogee_1.0.h:375
#define PWM_INPUT1_IRQ2
Definition: apogee_1.0.h:368
#define PWM_INPUT2_CHANNEL_PERIOD
Definition: apogee_1.0.h:386
#define PWM_INPUT2_TIMER_INPUT
Definition: apogee_1.0.h:388
#define PWM_INPUT2_TIMER
Definition: apogee_1.0.h:382
#define TIM9_CCR_DUTY
Definition: apogee_1.0.h:401
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:65
void pwm_input_init(void)
@ PWM_INPUT_NB
#define PWM_INPUT1_GPIO_PORT
Definition: common_board.h:316
#define PWM_INPUT1_GPIO_AF
Definition: common_board.h:318
#define PWM_INPUT1_GPIO_PIN
Definition: common_board.h:317
Some architecture independent helper functions for GPIOs.
volatile uint32_t pwm_input_duty_tics[PWM_INPUT_NB]
Definition: pwm_input.c:34
volatile uint8_t pwm_input_period_valid[PWM_INPUT_NB]
Definition: pwm_input.c:37
volatile uint8_t pwm_input_duty_valid[PWM_INPUT_NB]
Definition: pwm_input.c:35
volatile uint32_t pwm_input_period_tics[PWM_INPUT_NB]
Definition: pwm_input.c:36
arch independent PWM input capture API
#define FALSE
Definition: std.h:5
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:311
static void pwm_input_set_timer(uint32_t tim, uint32_t ticks_per_usec)
#define PWM_INPUT_IRQ_PRIO
#define ONE_MHZ_CLK
Architecture independent timing functions.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78