dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_pwm.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 /* Project Includes */
32 #include "pios.h"
33 #include "pios_pwm_priv.h"
34 
35 #if defined(PIOS_INCLUDE_PWM)
36 
37 /* Provide a RCVR driver */
38 static int32_t PIOS_PWM_Get(uintptr_t rcvr_id, uint8_t channel);
39 
41  .read = PIOS_PWM_Get,
42 };
43 
44 /* Local Variables */
45 /* 100 ms timeout without updates on channels */
46 const static uint32_t PWM_SUPERVISOR_TIMEOUT = 100000;
47 const static uint32_t PWM_CAPTURE_MAX = 3000;
48 
49 enum pios_pwm_dev_magic {
50  PIOS_PWM_DEV_MAGIC = 0xab30293c,
51 };
52 
53 enum pios_pwm_capture_state {
54  PIOS_PWM_CAPTURE_RISING,
55  PIOS_PWM_CAPTURE_FALLING,
56 };
57 
58 struct pios_pwm_dev {
59  enum pios_pwm_dev_magic magic;
60  const struct pios_pwm_cfg * cfg;
61 
62  volatile enum pios_pwm_capture_state CaptureState[PIOS_PWM_NUM_INPUTS];
63  volatile uint16_t RiseValue[PIOS_PWM_NUM_INPUTS];
64  volatile uint32_t CaptureValue[PIOS_PWM_NUM_INPUTS];
65  volatile uint32_t overflow_count[PIOS_PWM_NUM_INPUTS];
66 };
67 
68 static bool PIOS_PWM_validate(struct pios_pwm_dev * pwm_dev)
69 {
70  return (pwm_dev->magic == PIOS_PWM_DEV_MAGIC);
71 }
72 
73 static struct pios_pwm_dev * PIOS_PWM_alloc(void)
74 {
75  struct pios_pwm_dev * pwm_dev;
76 
77  pwm_dev = (struct pios_pwm_dev *)PIOS_malloc(sizeof(*pwm_dev));
78  if (!pwm_dev) return(NULL);
79 
80  memset(pwm_dev, 0, sizeof(*pwm_dev));
81 
82  pwm_dev->magic = PIOS_PWM_DEV_MAGIC;
83  return(pwm_dev);
84 }
85 
86 static void PIOS_PWM_tim_overflow_cb (uintptr_t id, uintptr_t context, uint8_t channel, uint16_t count);
87 static void PIOS_PWM_tim_edge_cb (uintptr_t id, uintptr_t context, uint8_t channel, uint16_t count);
88 const static struct pios_tim_callbacks tim_callbacks = {
89  .overflow = PIOS_PWM_tim_overflow_cb,
90  .edge = PIOS_PWM_tim_edge_cb,
91 };
92 
96 int32_t PIOS_PWM_Init(uintptr_t * pwm_id, const struct pios_pwm_cfg * cfg)
97 {
98  PIOS_DEBUG_Assert(pwm_id);
99  PIOS_DEBUG_Assert(cfg);
100 
101  struct pios_pwm_dev * pwm_dev;
102 
103  pwm_dev = (struct pios_pwm_dev *) PIOS_PWM_alloc();
104  if (!pwm_dev) goto out_fail;
105 
106  /* Bind the configuration to the device instance */
107  pwm_dev->cfg = cfg;
108 
109  for (uint8_t i = 0; i < PIOS_PWM_NUM_INPUTS; i++) {
110  pwm_dev->CaptureValue[i] = PIOS_RCVR_TIMEOUT;
111  }
112 
113  uintptr_t tim_id;
114  if (PIOS_TIM_InitChannels(&tim_id, cfg->channels, cfg->num_channels, &tim_callbacks, (uintptr_t)pwm_dev)) {
115  return -1;
116  }
117 
118  /* Configure the channels to be in capture/compare mode */
119  for (uint8_t i = 0; i < cfg->num_channels; i++) {
120  const struct pios_tim_channel * chan = &cfg->channels[i];
121 
122  /* Configure timer for input capture */
123  TIM_ICInitTypeDef TIM_ICInitStructure = cfg->tim_ic_init;
124  TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
125  TIM_ICInit(chan->timer, &TIM_ICInitStructure);
126 
127  /* Enable the Capture Compare Interrupt Request */
128  switch (chan->timer_chan) {
129  case TIM_Channel_1:
130  TIM_ITConfig(chan->timer, TIM_IT_CC1, ENABLE);
131  break;
132  case TIM_Channel_2:
133  TIM_ITConfig(chan->timer, TIM_IT_CC2, ENABLE);
134  break;
135  case TIM_Channel_3:
136  TIM_ITConfig(chan->timer, TIM_IT_CC3, ENABLE);
137  break;
138  case TIM_Channel_4:
139  TIM_ITConfig(chan->timer, TIM_IT_CC4, ENABLE);
140  break;
141  }
142 
143  // Need the update event for that timer to detect timeouts
144  TIM_ITConfig(chan->timer, TIM_IT_Update, ENABLE);
145 
146  }
147 
148  *pwm_id = (uintptr_t) pwm_dev;
149 
150  return (0);
151 
152 out_fail:
153  return (-1);
154 }
155 
163 static int32_t PIOS_PWM_Get(uintptr_t rcvr_id, uint8_t channel)
164 {
165  struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)rcvr_id;
166 
167  if (!PIOS_PWM_validate(pwm_dev)) {
168  /* Invalid device specified */
169  return PIOS_RCVR_INVALID;
170  }
171 
172  if (channel >= PIOS_PWM_NUM_INPUTS) {
173  /* Channel out of range */
174  return PIOS_RCVR_INVALID;
175  }
176  return pwm_dev->CaptureValue[channel];
177 }
178 
179 static void PIOS_PWM_tim_overflow_cb (uintptr_t tim_id, uintptr_t context, uint8_t channel, uint16_t count)
180 {
181  struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)context;
182 
183  if (!PIOS_PWM_validate(pwm_dev)) {
184  /* Invalid device specified */
185  return;
186  }
187 
188  if (channel >= pwm_dev->cfg->num_channels) {
189  /* Channel out of range */
190  return;
191  }
192 
193  pwm_dev->overflow_count[channel]++;
194 
195  if (pwm_dev->overflow_count[channel] * count >= PWM_SUPERVISOR_TIMEOUT) {
196  pwm_dev->CaptureState[channel] = PIOS_PWM_CAPTURE_RISING;
197  pwm_dev->RiseValue[channel] = 0;
198  pwm_dev->CaptureValue[channel] = PIOS_RCVR_TIMEOUT;
199  pwm_dev->overflow_count[channel] = 0;
200  }
201 }
202 
203 static void PIOS_PWM_tim_edge_cb (uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
204 {
205  /* Recover our device context */
206  struct pios_pwm_dev * pwm_dev = (struct pios_pwm_dev *)context;
207 
208  if (!PIOS_PWM_validate(pwm_dev)) {
209  /* Invalid device specified */
210  return;
211  }
212 
213  if (chan_idx >= pwm_dev->cfg->num_channels) {
214  /* Channel out of range */
215  return;
216  }
217 
218  const struct pios_tim_channel * chan = &pwm_dev->cfg->channels[chan_idx];
219 
220  // flip state machine and capture value here
221  /* Simple rise or fall state machine */
222  TIM_ICInitTypeDef TIM_ICInitStructure = pwm_dev->cfg->tim_ic_init;
223  if (pwm_dev->CaptureState[chan_idx] == PIOS_PWM_CAPTURE_RISING) {
224  pwm_dev->RiseValue[chan_idx] = count;
225  pwm_dev->overflow_count[chan_idx] = 0;
226 
227  /* Switch states */
228  pwm_dev->CaptureState[chan_idx] = PIOS_PWM_CAPTURE_FALLING;
229 
230  /* Switch polarity of input capture */
231  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
232  TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
233  TIM_ICInit(chan->timer, &TIM_ICInitStructure);
234  } else {
235  uint16_t fall_value = count;
236 
237  uint32_t value = fall_value - pwm_dev->RiseValue[chan_idx];
238  /* Capture computation */
239  if (pwm_dev->overflow_count[chan_idx] > 1 || fall_value > pwm_dev->RiseValue[chan_idx])
240  value += pwm_dev->overflow_count[chan_idx] * chan->timer->ARR;
241 
242  if (value <= PWM_CAPTURE_MAX) {
243  pwm_dev->CaptureValue[chan_idx] = value;
244  pwm_dev->overflow_count[chan_idx] = 0;
245  }
246 
247  /* Switch states */
248  pwm_dev->CaptureState[chan_idx] = PIOS_PWM_CAPTURE_RISING;
249 
250  /* Switch polarity of input capture */
251  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
252  TIM_ICInitStructure.TIM_Channel = chan->timer_chan;
253  TIM_ICInit(chan->timer, &TIM_ICInitStructure);
254  }
255 }
256 
257 #endif
258 
int32_t PIOS_PWM_Init(uintptr_t *pwm_id, const struct pios_pwm_cfg *cfg)
const struct pios_rcvr_driver pios_pwm_rcvr_driver
int32_t(* read)(uintptr_t id, uint8_t channel)
Definition: pios_rcvr.h:35
Main PiOS header to include all the compiled in PiOS options.
const uint8_t count
Definition: panel.c:515
TIM_ICInitTypeDef tim_ic_init
Definition: pios_pwm_priv.h:39
#define PIOS_DEBUG_Assert(test)
Definition: pios_debug.h:51
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
void(* overflow)(uintptr_t tim_id, uintptr_t context, uint8_t chan_idx, uint16_t count)
Definition: pios_tim_priv.h:22
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
const struct pios_tim_channel * channels
Definition: pios_pwm_priv.h:40
uint8_t i
Definition: msp_messages.h:97
uint16_t value
Definition: storm32bgc.c:155
uint32_t magic
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:172
#define PIOS_PWM_NUM_INPUTS
Definition: pios_board.h:188
uint8_t num_channels
Definition: pios_pwm_priv.h:41
TIM_TypeDef * timer
Definition: pios_tim_priv.h:14