Paparazzi UAS  v5.8.2_stable-0-g6260b7c
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 
54 };
55 
56 static inline void pwm_input_set_timer(uint32_t tim, uint32_t ticks_per_usec)
57 {
58  timer_reset(tim);
59  timer_set_mode(tim, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
60  timer_set_period(tim, 0xFFFF);
61  uint32_t timer_clk = timer_get_frequency(tim);
62  timer_set_prescaler(tim, (timer_clk / (ticks_per_usec * ONE_MHZ_CLK)) - 1);
63  timer_enable_counter(tim);
64 }
65 
66 void pwm_input_init(void)
67 {
68  int i;
69  // initialize the arrays to 0
70  for (i = 0; i < PWM_INPUT_NB; i++) {
71  pwm_input_duty_tics[i] = 0;
72  pwm_input_duty_valid[i] = 0;
73  pwm_input_period_tics[i] = 0;
75  }
76 
82 #if USE_PWM_INPUT_TIM1
83  rcc_periph_clock_enable(RCC_TIM1);
84  pwm_input_set_timer(TIM1, PWM_INPUT_TIM1_TICKS_PER_USEC);
85 #endif
86 #if USE_PWM_INPUT_TIM2
87  rcc_periph_clock_enable(RCC_TIM2);
88  pwm_input_set_timer(TIM2, PWM_INPUT_TIM2_TICKS_PER_USEC);
89 #endif
90 #if USE_PWM_INPUT_TIM3
91  rcc_periph_clock_enable(RCC_TIM3);
92  pwm_input_set_timer(TIM3, PWM_INPUT_TIM3_TICKS_PER_USEC);
93 #endif
94 #if USE_PWM_INPUT_TIM5
95  rcc_periph_clock_enable(RCC_TIM5);
96  pwm_input_set_timer(TIM5, PWM_INPUT_TIM5_TICKS_PER_USEC);
97 #endif
98 #if USE_PWM_INPUT_TIM8
99  rcc_periph_clock_enable(RCC_TIM8);
100  pwm_input_set_timer(TIM8, PWM_INPUT_TIM8_TICKS_PER_USEC);
101 #endif
102 #if USE_PWM_INPUT_TIM9
103  rcc_periph_clock_enable(RCC_TIM9);
104  pwm_input_set_timer(TIM9, PWM_INPUT_TIM9_TICKS_PER_USEC);
105 #endif
106 
107 #ifdef USE_PWM_INPUT1
108  /* GPIO configuration as input capture for timer */
110 
116 #if USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_LOW
117  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_RISING);
118  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_FALLING);
119 #elif USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_HIGH
120  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_FALLING);
121  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_RISING);
122 #endif
123 
124  /* Select the valid trigger input */
125  timer_slave_set_trigger(PWM_INPUT1_TIMER, PWM_INPUT1_SLAVE_TRIG);
126  /* Configure the slave mode controller in reset mode */
127  timer_slave_set_mode(PWM_INPUT1_TIMER, TIM_SMCR_SMS_RM);
128 
129  /* Enable timer Interrupt(s). */
130  nvic_set_priority(PWM_INPUT1_IRQ, PWM_INPUT_IRQ_PRIO);
131  nvic_enable_irq(PWM_INPUT1_IRQ);
132 #ifdef PWM_INPUT1_IRQ2
133  nvic_set_priority(PWM_INPUT1_IRQ2, PWM_INPUT_IRQ_PRIO);
134  nvic_enable_irq(PWM_INPUT1_IRQ2);
135 #endif
136 
137  /* Enable the Capture/Compare and Update interrupt requests. */
138  timer_enable_irq(PWM_INPUT1_TIMER, (PWM_INPUT1_CC_IE | TIM_DIER_UIE));
139 
140  /* Enable capture channel. */
142  timer_ic_enable(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY);
143 #endif
144 
145 #ifdef USE_PWM_INPUT2
146  /* GPIO configuration as input capture for timer */
148 
154 #if USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_LOW
155  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_RISING);
156  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_FALLING);
157 #elif USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_HIGH
158  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_FALLING);
159  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_RISING);
160 #endif
161 
162  /* Select the valid trigger input */
163  timer_slave_set_trigger(PWM_INPUT2_TIMER, PWM_INPUT2_SLAVE_TRIG);
164  /* Configure the slave mode controller in reset mode */
165  timer_slave_set_mode(PWM_INPUT2_TIMER, TIM_SMCR_SMS_RM);
166 
167  /* Enable timer Interrupt(s). */
168  nvic_set_priority(PWM_INPUT2_IRQ, PWM_INPUT_IRQ_PRIO);
169  nvic_enable_irq(PWM_INPUT2_IRQ);
170 #ifdef PWM_INPUT2_IRQ2
171  nvic_set_priority(PWM_INPUT2_IRQ2, PWM_INPUT_IRQ_PRIO);
172  nvic_enable_irq(PWM_INPUT2_IRQ2);
173 #endif
174 
175  /* Enable the Capture/Compare and Update interrupt requests. */
176  timer_enable_irq(PWM_INPUT2_TIMER, (PWM_INPUT2_CC_IE | TIM_DIER_UIE));
177 
178  /* Enable capture channel. */
180  timer_ic_enable(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY);
181 #endif
182 
183 }
184 
187 }
188 
191 }
192 
193 #if USE_PWM_INPUT_TIM1
194 
195 #if defined(STM32F1)
196 void tim1_up_isr(void)
197 {
198 #elif defined(STM32F4)
199 void tim1_up_tim10_isr(void) {
200 #endif
201  if ((TIM1_SR & TIM_SR_UIF) != 0) {
202  timer_clear_flag(TIM1, TIM_SR_UIF);
203  // FIXME clear overflow interrupt but what else ?
204  }
205 }
206 
207 void tim1_cc_isr(void) {
208  if ((TIM1_SR & TIM1_CC_IF_PERIOD) != 0) {
209  timer_clear_flag(TIM1, TIM1_CC_IF_PERIOD);
212  }
213  if ((TIM1_SR & TIM1_CC_IF_DUTY) != 0) {
214  timer_clear_flag(TIM1, TIM1_CC_IF_DUTY);
217  }
218 }
219 
220 #endif
221 
222 #if USE_PWM_INPUT_TIM2
223 
224 void tim2_isr(void) {
225  if ((TIM2_SR & TIM2_CC_IF_PERIOD) != 0) {
226  timer_clear_flag(TIM2, TIM2_CC_IF_PERIOD);
227  pwm_input_period_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_PERIOD;
228  pwm_input_period_valid[TIM2_PWM_INPUT_IDX] = TRUE;
229  }
230  if ((TIM2_SR & TIM2_CC_IF_DUTY) != 0) {
231  timer_clear_flag(TIM2, TIM2_CC_IF_DUTY);
232  pwm_input_duty_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_DUTY;
233  pwm_input_duty_valid[TIM2_PWM_INPUT_IDX] = TRUE;
234  }
235  if ((TIM2_SR & TIM_SR_UIF) != 0) {
236  timer_clear_flag(TIM2, TIM_SR_UIF);
237  // FIXME clear overflow interrupt but what else ?
238  }
239 }
240 
241 #endif
242 
243 #if USE_PWM_INPUT_TIM3
244 
245 void tim3_isr(void) {
246  if ((TIM3_SR & TIM3_CC_IF_PERIOD) != 0) {
247  timer_clear_flag(TIM3, TIM3_CC_IF_PERIOD);
248  pwm_input_period_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_PERIOD;
249  pwm_input_period_valid[TIM3_PWM_INPUT_IDX] = TRUE;
250  }
251  if ((TIM3_SR & TIM3_CC_IF_DUTY) != 0) {
252  timer_clear_flag(TIM3, TIM3_CC_IF_DUTY);
253  pwm_input_duty_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_DUTY;
254  pwm_input_duty_valid[TIM3_PWM_INPUT_IDX] = TRUE;
255  }
256  if ((TIM3_SR & TIM_SR_UIF) != 0) {
257  timer_clear_flag(TIM3, TIM_SR_UIF);
258  // FIXME clear overflow interrupt but what else ?
259  }
260 }
261 
262 #endif
263 
264 #if USE_PWM_INPUT_TIM5
265 
266 void tim5_isr(void) {
267  if ((TIM5_SR & TIM5_CC_IF_PERIOD) != 0) {
268  timer_clear_flag(TIM5, TIM5_CC_IF_PERIOD);
269  pwm_input_period_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_PERIOD;
270  pwm_input_period_valid[TIM5_PWM_INPUT_IDX] = TRUE;
271  }
272  if ((TIM5_SR & TIM5_CC_IF_DUTY) != 0) {
273  timer_clear_flag(TIM5, TIM5_CC_IF_DUTY);
274  pwm_input_duty_tics[TIM5_PWM_INPUT_IDX] = TIM5_CCR_DUTY;
275  pwm_input_duty_valid[TIM5_PWM_INPUT_IDX] = TRUE;
276  }
277  if ((TIM5_SR & TIM_SR_UIF) != 0) {
278  timer_clear_flag(TIM5, TIM_SR_UIF);
279  // FIXME clear overflow interrupt but what else ?
280  }
281 }
282 
283 #endif
284 
285 #if USE_PWM_INPUT_TIM8
286 
287 #if defined(STM32F1)
288 void tim8_up_isr(void)
289 {
290 #elif defined(STM32F4)
291 void tim8_up_tim13_isr(void) {
292 #endif
293  if ((TIM8_SR & TIM_SR_UIF) != 0) {
294  timer_clear_flag(TIM8, TIM_SR_UIF);
295  // FIXME clear overflow interrupt but what else ?
296  }
297 }
298 
299 void tim8_cc_isr(void) {
300  if ((TIM8_SR & TIM8_CC_IF_PERIOD) != 0) {
301  timer_clear_flag(TIM8, TIM8_CC_IF_PERIOD);
302  pwm_input_period_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_PERIOD;
303  pwm_input_period_valid[TIM8_PWM_INPUT_IDX] = TRUE;
304  }
305  if ((TIM8_SR & TIM8_CC_IF_DUTY) != 0) {
306  timer_clear_flag(TIM8, TIM8_CC_IF_DUTY);
307  pwm_input_duty_tics[TIM8_PWM_INPUT_IDX] = TIM8_CCR_DUTY;
308  pwm_input_duty_valid[TIM8_PWM_INPUT_IDX] = TRUE;
309  }
310 }
311 
312 #endif
313 
314 #if USE_PWM_INPUT_TIM9
315 
316 // TIM1 break interrupt (which we don't care here) and TIM9 global interrupt
317 void tim1_brk_tim9_isr(void) {
318  if ((TIM9_SR & TIM9_CC_IF_PERIOD) != 0) {
319  timer_clear_flag(TIM9, TIM9_CC_IF_PERIOD);
322  }
323  if ((TIM9_SR & TIM9_CC_IF_DUTY) != 0) {
324  timer_clear_flag(TIM9, TIM9_CC_IF_DUTY);
327  }
328  if ((TIM9_SR & TIM_SR_UIF) != 0) {
329  timer_clear_flag(TIM9, TIM_SR_UIF);
330  // FIXME clear overflow interrupt but what else ?
331  }
332 }
333 
334 #endif
335 
void pwm_input_init(void)
#define PWM_INPUT2_GPIO_AF
Definition: apogee_1.0.h:408
CM3_WEAK tim8_cc_isr(void)
#define PWM_INPUT2_TIMER
Definition: apogee_1.0.h:382
#define PWM_INPUT1_GPIO_PIN
Definition: apogee_1.0.h:378
volatile uint32_t pwm_input_duty_tics[PWM_INPUT_NB]
Definition: pwm_input.c:29
timer_clear_flag(TIM6, TIM_SR_UIF)
#define TIM1_CC_IF_DUTY
Definition: apogee_1.0.h:373
CM3_WEAK tim2_isr(void)
uint32_t get_pwm_input_duty_in_usec(uint32_t channel)
CM3_WEAK tim3_isr(void)
Some architecture independent helper functions for GPIOs.
CM3_WEAK tim1_cc_isr(void)
arch independent PWM input capture API
#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:179
#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:32
#define PWM_INPUT1_IRQ2
Definition: apogee_1.0.h:368
volatile uint8_t pwm_input_duty_valid[PWM_INPUT_NB]
Definition: pwm_input.c:30
#define FALSE
Definition: std.h:5
#define PWM_INPUT2_CHANNEL_DUTY
Definition: apogee_1.0.h:387
CM3_WEAK tim1_up_tim10_isr(void)
#define TIM1_PWM_INPUT_IDX
Definition: apogee_1.0.h:371
#define TRUE
Definition: std.h:4
#define TIM1_CCR_PERIOD
Definition: apogee_1.0.h:374
#define TIM1_CCR_DUTY
Definition: apogee_1.0.h:375
Architecture independent timing functions.
#define PWM_INPUT1_CC_IE
Definition: apogee_1.0.h:369
#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_INPUT1_GPIO_AF
Definition: apogee_1.0.h:379
static const uint32_t pwm_input_ticks_per_usec[]
#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:31
#define PWM_INPUT1_TICKS_PER_USEC
The default pwm counter is set-up to have 1/6 us resolution.
#define PWM_INPUT2_CC_IE
Definition: apogee_1.0.h:391
void gpio_setup_pin_af(uint32_t port, uint16_t pin, uint8_t af, bool_t is_output)
Setup a gpio for input or output with alternate function.
#define PWM_INPUT2_SLAVE_TRIG
Definition: apogee_1.0.h:389
uint32_t get_pwm_input_period_in_usec(uint32_t channel)
#define PWM_INPUT1_SLAVE_TRIG
Definition: apogee_1.0.h:366
#define PWM_INPUT2_GPIO_PIN
Definition: apogee_1.0.h:407
#define ONE_MHZ_CLK
#define PWM_INPUT1_IRQ
Definition: apogee_1.0.h:367
#define PWM_INPUT1_GPIO_PORT
Definition: apogee_1.0.h:377
#define PWM_INPUT2_TICKS_PER_USEC
CM3_WEAK tim8_up_tim13_isr(void)
CM3_WEAK tim1_brk_tim9_isr(void)
#define TIM9_PWM_INPUT_IDX
Definition: apogee_1.0.h:397
#define PWM_INPUT2_GPIO_PORT
Definition: apogee_1.0.h:406
#define TIM1_CC_IF_PERIOD
Definition: apogee_1.0.h:372
CM3_WEAK tim5_isr(void)
static uint8_t channel
Definition: ADS8344.c:80
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