Paparazzi UAS  v5.2.2_stable-0-gd6b9f29
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures 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_arch.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) {
52  timer_reset(tim);
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 / (PWM_INPUT_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  pwm_input_set_timer(TIM1);
79 #endif
80 #if USE_PWM_INPUT_TIM2
81  rcc_periph_clock_enable(RCC_TIM2);
82  pwm_input_set_timer(TIM2);
83 #endif
84 #if USE_PWM_INPUT_TIM3
85  rcc_periph_clock_enable(RCC_TIM3);
86  pwm_input_set_timer(TIM3);
87 #endif
88 
89 #ifdef USE_PWM_INPUT1
90  /* GPIO configuration as input capture for timer */
92 
98 #if USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_LOW
99  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_RISING);
100  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_FALLING);
101 #elif USE_PWM_INPUT1 == PWM_PULSE_TYPE_ACTIVE_HIGH
102  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_PERIOD, TIM_IC_FALLING);
103  timer_ic_set_polarity(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY, TIM_IC_RISING);
104 #endif
105 
106  /* Select the valid trigger input */
107  timer_slave_set_trigger(PWM_INPUT1_TIMER, PWM_INPUT1_SLAVE_TRIG);
108  /* Configure the slave mode controller in reset mode */
109  timer_slave_set_mode(PWM_INPUT1_TIMER, TIM_SMCR_SMS_RM);
110 
111  /* Enable timer Interrupt(s). */
112  nvic_set_priority(PWM_INPUT1_IRQ, PWM_INPUT_IRQ_PRIO);
113  nvic_enable_irq(PWM_INPUT1_IRQ);
114 #ifdef PWM_INPUT1_IRQ2
115  nvic_set_priority(PWM_INPUT1_IRQ2, PWM_INPUT_IRQ_PRIO);
116  nvic_enable_irq(PWM_INPUT1_IRQ2);
117 #endif
118 
119  /* Enable the Capture/Compare and Update interrupt requests. */
120  timer_enable_irq(PWM_INPUT1_TIMER, (PWM_INPUT1_CC_IE | TIM_DIER_UIE));
121 
122  /* Enable capture channel. */
124  timer_ic_enable(PWM_INPUT1_TIMER, PWM_INPUT1_CHANNEL_DUTY);
125 #endif
126 
127 #ifdef USE_PWM_INPUT2
128  /* GPIO configuration as input capture for timer */
129  gpio_setup_pin_af(PWM_INPUT2_GPIO_PORT, PWM_INPUT2_GPIO_PIN, PWM_INPUT2_GPIO_AF, FALSE);
130 
134  timer_ic_set_input(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, PWM_INPUT2_TIMER_INPUT);
135  timer_ic_set_input(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, PWM_INPUT2_TIMER_INPUT);
136 #if USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_LOW
137  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_RISING);
138  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_FALLING);
139 #elif USE_PWM_INPUT2 == PWM_PULSE_TYPE_ACTIVE_HIGH
140  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD, TIM_IC_FALLING);
141  timer_ic_set_polarity(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY, TIM_IC_RISING);
142 #endif
143 
144  /* Select the valid trigger input */
145  timer_slave_set_trigger(PWM_INPUT2_TIMER, PWM_INPUT2_SLAVE_TRIG);
146  /* Configure the slave mode controller in reset mode */
147  timer_slave_set_mode(PWM_INPUT2_TIMER, TIM_SMCR_SMS_RM);
148 
149  /* Enable timer Interrupt(s). */
150  nvic_set_priority(PWM_INPUT2_IRQ, PWM_INPUT_IRQ_PRIO);
151  nvic_enable_irq(PWM_INPUT2_IRQ);
152 #ifdef PWM_INPUT2_IRQ2
153  nvic_set_priority(PWM_INPUT2_IRQ2, PWM_INPUT_IRQ_PRIO);
154  nvic_enable_irq(PWM_INPUT2_IRQ2);
155 #endif
156 
157  /* Enable the Capture/Compare and Update interrupt requests. */
158  timer_enable_irq(PWM_INPUT2_TIMER, (PWM_INPUT2_CC_IE | TIM_DIER_UIE));
159 
160  /* Enable capture channel. */
161  timer_ic_enable(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_PERIOD);
162  timer_ic_enable(PWM_INPUT2_TIMER, PWM_INPUT2_CHANNEL_DUTY);
163 #endif
164 
165 }
166 
167 #if USE_PWM_INPUT_TIM1
168 
169 #if defined(STM32F1)
170 void tim1_up_isr(void) {
171 #elif defined(STM32F4)
172 void tim1_up_tim10_isr(void) {
173 #endif
174  if((TIM1_SR & TIM_SR_UIF) != 0) {
175  timer_clear_flag(TIM1, TIM_SR_UIF);
176  // FIXME clear overflow interrupt but what else ?
177  }
178 }
179 
180 void tim1_cc_isr(void) {
181  if((TIM1_SR & TIM1_CC_IF_PERIOD) != 0) {
182  timer_clear_flag(TIM1, TIM1_CC_IF_PERIOD);
185  }
186  if((TIM1_SR & TIM1_CC_IF_DUTY) != 0) {
187  timer_clear_flag(TIM1, TIM1_CC_IF_DUTY);
190  }
191 }
192 
193 #endif
194 
195 #if USE_PWM_INPUT_TIM2
196 
197 void tim2_isr(void) {
198  if((TIM2_SR & TIM2_CC_IF_PERIOD) != 0) {
199  timer_clear_flag(TIM2, TIM2_CC_IF_PERIOD);
200  pwm_input_period_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_PERIOD;
201  pwm_input_period_valid[TIM2_PWM_INPUT_IDX] = TRUE;
202  }
203  if((TIM2_SR & TIM2_CC_IF_DUTY) != 0) {
204  timer_clear_flag(TIM2, TIM2_CC_IF_DUTY);
205  pwm_input_duty_tics[TIM2_PWM_INPUT_IDX] = TIM2_CCR_DUTY;
206  pwm_input_duty_valid[TIM2_PWM_INPUT_IDX] = TRUE;
207  }
208  if((TIM2_SR & TIM_SR_UIF) != 0) {
209  timer_clear_flag(TIM2, TIM_SR_UIF);
210  // FIXME clear overflow interrupt but what else ?
211  }
212 }
213 
214 #endif
215 
216 #if USE_PWM_INPUT_TIM3
217 
218 void tim3_isr(void) {
219  if((TIM3_SR & TIM3_CC_IF_PERIOD) != 0) {
220  timer_clear_flag(TIM3, TIM3_CC_IF_PERIOD);
221  pwm_input_period_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_PERIOD;
222  pwm_input_period_valid[TIM3_PWM_INPUT_IDX] = TRUE;
223  }
224  if((TIM3_SR & TIM3_CC_IF_DUTY) != 0) {
225  timer_clear_flag(TIM3, TIM3_CC_IF_DUTY);
226  pwm_input_duty_tics[TIM3_PWM_INPUT_IDX] = TIM3_CCR_DUTY;
227  pwm_input_duty_valid[TIM3_PWM_INPUT_IDX] = TRUE;
228  }
229  if((TIM3_SR & TIM_SR_UIF) != 0) {
230  timer_clear_flag(TIM3, TIM_SR_UIF);
231  // FIXME clear overflow interrupt but what else ?
232  }
233 }
234 
235 #endif
void pwm_input_init(void)
#define PWM_INPUT1_GPIO_PIN
Definition: apogee_1.0.h:361
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:356
CM3_WEAK tim2_isr(void)
CM3_WEAK tim3_isr(void)
Some architecture independent helper functions for GPIOs.
CM3_WEAK tim1_cc_isr(void)
#define PWM_INPUT1_TIMER
Definition: apogee_1.0.h:345
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:139
#define PWM_INPUT1_TIMER_INPUT
Definition: apogee_1.0.h:348
volatile uint8_t pwm_input_period_valid[PWM_INPUT_NB]
Definition: pwm_input.c:32
#define PWM_INPUT1_IRQ2
Definition: apogee_1.0.h:351
volatile uint8_t pwm_input_duty_valid[PWM_INPUT_NB]
Definition: pwm_input.c:30
#define FALSE
Definition: imu_chimu.h:141
CM3_WEAK tim1_up_tim10_isr(void)
#define TIM1_PWM_INPUT_IDX
Definition: apogee_1.0.h:354
#define TIM1_CCR_PERIOD
Definition: apogee_1.0.h:357
#define TIM1_CCR_DUTY
Definition: apogee_1.0.h:358
static void pwm_input_set_timer(uint32_t tim)
Architecture independent timing functions.
#define PWM_INPUT1_CC_IE
Definition: apogee_1.0.h:352
#define PWM_INPUT1_CHANNEL_DUTY
Definition: apogee_1.0.h:347
#define PWM_INPUT_IRQ_PRIO
unsigned long uint32_t
Definition: types.h:18
#define PWM_INPUT1_GPIO_AF
Definition: apogee_1.0.h:362
volatile uint32_t pwm_input_period_tics[PWM_INPUT_NB]
Definition: pwm_input.c:31
#define TRUE
Definition: imu_chimu.h:144
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_INPUT1_SLAVE_TRIG
Definition: apogee_1.0.h:349
#define ONE_MHZ_CLK
#define PWM_INPUT1_IRQ
Definition: apogee_1.0.h:350
#define PWM_INPUT1_GPIO_PORT
Definition: apogee_1.0.h:360
#define TIM1_CC_IF_PERIOD
Definition: apogee_1.0.h:355
#define PWM_INPUT_TICKS_PER_USEC
The pwm counter is set-up to have 1/6 us resolution.
#define PWM_INPUT1_CHANNEL_PERIOD
Definition: apogee_1.0.h:346