dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_dmashot.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  *
25  * Additional note on redistribution: The copyright and license notices above
26  * must be maintained in each individual source file that is a derivative work
27  * of this source file; otherwise redistribution is prohibited.
28  */
29 
30 #include <pios.h>
31 #include "pios_dmashot.h"
32 
33 #define MAX_TIMERS 8
34 
35 // This is to do half-word writes where appropriate. TIM2 and TIM5 are 32-bit, the rest
36 // are 16-bit. Can do full word writes to 16bit regardless, but it doubles DMA buffer size
37 // unnecessarily.
38 union dma_buffer {
39  uint32_t ptr;
40  uint32_t *fw;
41  uint16_t *hw;
42 };
43 
44 // Internal structure for timer and DShot configuration.
45 struct servo_timer {
46  uint32_t sysclock; // Flava Flav! Timer's clock frequency.
47 
48  const struct pios_dmashot_timer_cfg *dma; // DMA config
49  const struct pios_tim_channel *servo_channels[4]; // DMAShot configured channels
50 
51  // Tracking used TIM channels to allocate least memory.
52  uint8_t low_channel; // Lowest registered TIM channel
53  uint8_t high_channel; // Duh
54 
55  uint32_t dshot_freq; // Stores the desired frequency for
56  // timer initialization
57  uint16_t duty_cycle_0; // Calculated duty cycle for 0-bit
58  uint16_t duty_cycle_1; // And for 1-bit
59 
60  union dma_buffer buffer; // DMA buffer
61  uint8_t dma_started; // Whether DMA transfers have been initiated
62 
63 };
64 
65 // DShot signal is 16-bit. Use a pause before and after to delimit signal and quell the timer CC
66 // when the message ends.
67 #define DMASHOT_MESSAGE_WIDTH 16
68 #define DMASHOT_MESSAGE_PAUSE 1
69 #define DMASHOT_STM32_BUFFER (DMASHOT_MESSAGE_PAUSE + DMASHOT_MESSAGE_WIDTH + DMASHOT_MESSAGE_PAUSE)
70 
71 // Those values are in percent. These represent the Betaflight/BLHeli_s timing,
72 // instead of the spec one. Works with KISS RE 24A though.
73 #define DSHOT_DUTY_CYCLE_0 36
74 #define DSHOT_DUTY_CYCLE_1 74
75 
76 #define TIMC_TO_INDEX(c) ((c)>>2)
77 
80 
81 // Whether a timer is 16- or 32-bit wide.
82 static inline bool PIOS_DMAShot_HalfWord(struct servo_timer *s_timer)
83 {
84  // In STM32F4 and STM32L4, these two are 32-bit, the rest is 16-bit.
85  return (s_timer->dma->timer == TIM2 || s_timer->dma->timer == TIM5 ? false : true);
86 }
87 
88 static int PIOS_DMAShot_GetNumChannels(struct servo_timer *timer)
89 {
90  int channels = timer->high_channel - timer->low_channel;
91  if (channels < 0)
92  return 0;
93  return (channels >> 2) + 1;
94 }
95 
97 {
98  dmashot_cfg = config;
99 }
100 
105 {
106  if (dmashot_cfg) {
107  if (!servo_timers) {
108  // Allocate memory
109  servo_timers = PIOS_malloc_no_dma(sizeof(servo_timers) * MAX_TIMERS);
110  PIOS_Assert(servo_timers);
111 
112  memset(servo_timers, 0, sizeof(servo_timers) * MAX_TIMERS);
113  }
114  for (int i = 0; i < MAX_TIMERS; i++) {
115  if (servo_timers[i]) {
116  // Force sysclock to zero to consider this timer disabled,
117  // so that DMAShot doesn't hijack it when an user configures from DMAShot
118  // to something else.
119  servo_timers[i]->sysclock = 0;
120  }
121  }
122  }
123 }
124 
125 // Returns the internal timer config. struct for a servo, if there is one.
126 static struct servo_timer *PIOS_DMAShot_GetServoTimer(const struct pios_tim_channel *servo_channel)
127 {
128  if (!servo_timers)
129  return NULL;
130 
131  for (int i = 0; i < MAX_TIMERS; i++) {
132  struct servo_timer *s_timer = servo_timers[i];
133  if (!s_timer || !s_timer->sysclock)
134  continue;
135 
136  if (s_timer->dma->timer == servo_channel->timer)
137  return s_timer;
138  }
139 
140  return NULL;
141 }
142 
143 void PIOS_DMAShot_WriteValue(const struct pios_tim_channel *servo_channel, uint16_t throttle)
144 {
145  // Fail hard if trying to write values without configured DMAShot. We shouldn't be getting to
146  // this point in that case.
147  PIOS_Assert(dmashot_cfg);
148 
149  // If we can't find a timer for this, something's wrong. We shouldn't be getting to this point.
150  // Fail hard.
151  struct servo_timer *s_timer = PIOS_DMAShot_GetServoTimer(servo_channel);
152  PIOS_Assert(s_timer);
153 
154  int shift = (servo_channel->timer_chan - s_timer->low_channel) >> 2;
155  int channels = PIOS_DMAShot_GetNumChannels(s_timer);
156 
157  bool telem_bit = false;
158 
159  /* Set telem bit on commands */
160  if ((throttle > 0) && (throttle < 48)) {
161  telem_bit = true;
162  }
163 
164  if (throttle > 2047)
165  throttle = 2047;
166 
167  throttle <<= 5;
168 
169  if (telem_bit) {
170  throttle |= 16;
171  }
172 
173  throttle |=
174  ((throttle >> 4 ) & 0xf) ^
175  ((throttle >> 8 ) & 0xf) ^
176  ((throttle >> 12) & 0xf);
177 
178  // Leading zero, trailing zero.
180  int addr = i * channels + shift;
181  if (PIOS_DMAShot_HalfWord(s_timer)) {
182  s_timer->buffer.hw[addr] = throttle & 0x8000 ? s_timer->duty_cycle_1 : s_timer->duty_cycle_0;
183  } else {
184  s_timer->buffer.fw[addr] = throttle & 0x8000 ? s_timer->duty_cycle_1 : s_timer->duty_cycle_0;
185  }
186  throttle <<= 1;
187  }
188 }
189 
190 bool PIOS_DMAShot_RegisterTimer(TIM_TypeDef *timer, uint32_t clockrate, uint32_t dshot_freq)
191 {
192  // No configuration, push for GPIO in upstream.
193  if (!dmashot_cfg || !servo_timers)
194  return false;
195 
196  // Check whether the timer is configured for DMA first. If not, bail and
197  // tell upstairs that DMA DShot is a no-go.
198  const struct pios_dmashot_timer_cfg *dma_config = NULL;
199 
200  for (int i = 0; i < dmashot_cfg->num_timers; i++) {
201  if (dmashot_cfg->timer_cfg[i].timer == timer) {
202  dma_config = &dmashot_cfg->timer_cfg[i];
203  }
204  }
205 
206  if (!dma_config)
207  return false;
208 
209  // Check whether there's an existing config from a previous registration,
210  // since we can't clean up due to a lack of free(). Timer/pin stuff is
211  // static anyway.
212  struct servo_timer *s_timer = NULL;
213 
214  bool found = false;
215  for (int i = 0; i < MAX_TIMERS; i++) {
216  if (servo_timers[i] && servo_timers[i]->dma->timer == timer) {
217  s_timer = servo_timers[i];
218  found = true;
219  break;
220  }
221  }
222 
223  // Nothing found? Allocate a new slot for the timer.
224  if (!found) {
225  for (int i = 0; i < MAX_TIMERS; i++) {
226  if (!servo_timers[i]) {
227  s_timer = PIOS_malloc_no_dma(sizeof(*s_timer));
228  // No point in returning false and falling back to GPIO, because that
229  // also needs to allocate stuff later on, so we might just fail here.
230  PIOS_Assert(s_timer);
231  memset(s_timer, 0, sizeof(*s_timer));
232  s_timer->low_channel = TIM_Channel_4;
233  s_timer->high_channel = TIM_Channel_1;
234  servo_timers[i] = s_timer;
235  break;
236  }
237  }
238  }
239 
240  // Why are we trying to register more than MAX_TIMERS, anyway?
241  PIOS_Assert(s_timer);
242 
243  s_timer->sysclock = clockrate;
244  s_timer->dshot_freq = dshot_freq;
245  s_timer->dma = dma_config;
246 
247  return true;
248 }
249 
250 bool PIOS_DMAShot_RegisterServo(const struct pios_tim_channel *servo_channel)
251 {
252  // No configuration? kthxbye!
253  if (!dmashot_cfg || !servo_timers)
254  return false;
255 
256  struct servo_timer *s_timer = PIOS_DMAShot_GetServoTimer(servo_channel);
257 
258  // No timer found, tell upstream to GPIO!
259  if (!s_timer)
260  return false;
261 
262  if (s_timer->dma->master_timer && (PIOS_DMAShot_GetNumChannels(s_timer) > 0) &&
263  (s_timer->low_channel != servo_channel->timer_chan)) {
264  // I'm sorry, Dave, I'm afraid I cannot do that!
265 
266  // If DMA'ing directly to CCR, can only do one channel per timer.
267  // Tell upstream to GPIO instead.
268  return false;
269  }
270 
271  if (servo_channel->timer_chan < s_timer->low_channel) s_timer->low_channel = servo_channel->timer_chan;
272  if (servo_channel->timer_chan > s_timer->high_channel) s_timer->high_channel = servo_channel->timer_chan;
273 
274  s_timer->servo_channels[TIMC_TO_INDEX(servo_channel->timer_chan)] = servo_channel;
275 
276  return true;
277 }
278 
280 {
281  if (!dmashot_cfg || !servo_timers)
282  return;
283 
284  for (int i = 0; i < MAX_TIMERS; i++) {
285  struct servo_timer *s_timer = servo_timers[i];
286  if (!s_timer || !s_timer->sysclock)
287  continue;
288 
289  // If after servo "registration", there's a low channel higher than the high
290  // one, something went wrong, lets ignore the timer.
291  if (s_timer->low_channel > s_timer->high_channel) {
292  s_timer->sysclock = 0;
293  }
294  }
295 }
296 
298 {
299  // If there's nothing setup, fail hard. We shouldn't be getting here.
300  PIOS_Assert(dmashot_cfg && servo_timers);
301 
302  for (int i = 0; i < MAX_TIMERS; i++) {
303  for (int j = 0; j < 4; j++) {
304 
305  struct servo_timer *s_timer = servo_timers[i];
306  if (!s_timer || !s_timer->sysclock)
307  continue;
308 
309  const struct pios_tim_channel *servo_channel = s_timer->servo_channels[j];
310  if (servo_channel) {
311 
312  GPIO_InitTypeDef gpio_cfg = servo_channel->pin.init;
313  gpio_cfg.GPIO_Speed = GPIO_High_Speed;
314  GPIO_Init(servo_channel->pin.gpio, &gpio_cfg);
315 
316  GPIO_PinAFConfig(servo_channel->pin.gpio, servo_channel->pin.pin_source, servo_channel->remap);
317  }
318  }
319  }
320 }
321 
322 static void PIOS_DMAShot_TimerSetup(struct servo_timer *s_timer, uint32_t sysclock, uint32_t dshot_freq, TIM_OCInitTypeDef *ocinit, bool master)
323 {
324  TIM_TypeDef *timer = master ? s_timer->dma->master_timer : s_timer->dma->timer;
325  TIM_TimeBaseInitTypeDef timerdef;
326 
327  TIM_Cmd(timer, DISABLE);
328 
329  TIM_TimeBaseStructInit(&timerdef);
330 
331  timerdef.TIM_Prescaler = 0;
332  timerdef.TIM_Period = sysclock / dshot_freq;
333  timerdef.TIM_ClockDivision = TIM_CKD_DIV1;
334  timerdef.TIM_RepetitionCounter = 0;
335  timerdef.TIM_CounterMode = TIM_CounterMode_Up;
336 
337  TIM_TimeBaseInit(timer, &timerdef);
338 
339  // TIM_Channels are spread apart by 4 in stm32f4xx_tim.h
340  for(int i = s_timer->low_channel; i <= s_timer->high_channel; i+=4)
341  {
342  switch(i)
343  {
344  case TIM_Channel_1:
345  TIM_OC1Init(timer, ocinit);
346  TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
347  break;
348  case TIM_Channel_2:
349  TIM_OC2Init(timer, ocinit);
350  TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable);
351  break;
352  case TIM_Channel_3:
353  TIM_OC3Init(timer, ocinit);
354  TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable);
355  break;
356  case TIM_Channel_4:
357  TIM_OC4Init(timer, ocinit);
358  TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable);
359  break;
360  }
361  }
362 
363  // Do this, in case SyncPWM was configured before.
364  TIM_SelectOnePulseMode(timer, TIM_OPMode_Repetitive);
365 }
366 
367 void PIOS_DMAShot_InitializeTimers(TIM_OCInitTypeDef *ocinit)
368 {
369  // If there's nothing setup, fail hard. We shouldn't be getting here.
370  PIOS_Assert(dmashot_cfg && servo_timers);
371 
372  for (int i = 0; i < MAX_TIMERS; i++) {
373 
374  struct servo_timer *s_timer = servo_timers[i];
375  if (!s_timer || !s_timer->sysclock)
376  continue;
377 
378  if(PIOS_DMAShot_GetNumChannels(s_timer) == 0) {
379  // Servo's should have been registered before InitializeTimers. If there's none,
380  // disable the timer.
381  s_timer->sysclock = 0;
382  continue;
383  }
384 
385  PIOS_DMAShot_TimerSetup(s_timer, s_timer->sysclock, s_timer->dshot_freq, ocinit, false);
386 
387  int f = s_timer->sysclock / s_timer->dshot_freq;
388 
389  s_timer->duty_cycle_0 = (f * DSHOT_DUTY_CYCLE_0 + 50) / 100;
390  s_timer->duty_cycle_1 = (f * DSHOT_DUTY_CYCLE_1 + 50) / 100;
391 
392  if (s_timer->dma->master_timer)
393  PIOS_DMAShot_TimerSetup(s_timer, s_timer->sysclock, s_timer->dshot_freq, ocinit, true);
394 
395  s_timer->dma_started = 0;
396  }
397 }
398 
399 static void PIOS_DMAShot_DMASetup(struct servo_timer *s_timer)
400 {
401  DMA_Cmd(s_timer->dma->stream, DISABLE);
402  while (DMA_GetCmdStatus(s_timer->dma->stream) == ENABLE) ;
403 
404  DMA_DeInit(s_timer->dma->stream);
405 
406  DMA_InitTypeDef dma;
407  DMA_StructInit(&dma);
408 
409  dma.DMA_Channel = s_timer->dma->channel;
410  dma.DMA_Memory0BaseAddr = s_timer->buffer.ptr;
411  if (s_timer->dma->master_timer) {
412  // The DMABase shift is in count of 32-bit registers. 16-bit registers are padded with 16-bit reserved ones,
413  // and thus defacto 32-bit.
414  dma.DMA_PeripheralBaseAddr = ((uint32_t)&s_timer->dma->timer->CR1) + ((s_timer->dma->master_config & 0x00FF) << 2);
415  } else {
416  dma.DMA_PeripheralBaseAddr = (uint32_t)(&s_timer->dma->timer->DMAR);
417  }
418 
419  if (PIOS_DMAShot_HalfWord(s_timer)) {
420  dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
421  dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
422  } else {
423  dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
424  dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
425  }
426 
427  dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
428  dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
429 
430  dma.DMA_DIR = DMA_DIR_MemoryToPeripheral;
431  dma.DMA_Mode = DMA_Mode_Normal;
432 
433  dma.DMA_BufferSize = PIOS_DMAShot_GetNumChannels(s_timer) * DMASHOT_STM32_BUFFER;
434 
435  dma.DMA_Priority = DMA_Priority_VeryHigh;
436  dma.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
437  dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
438 
439  dma.DMA_FIFOMode = DMA_FIFOMode_Enable;
440  dma.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
441 
442  DMA_Init(s_timer->dma->stream, &dma);
443 
444  // Don't do interrupts.
445  DMA_ITConfig(s_timer->dma->stream, DMA_IT_TC, DISABLE);
446 }
447 
448 // Allocates an aligned buffer for DMA burst transfers. Returns uint32_t, since
449 // that's the pointer type for Mem0 base address in DMA_InitTypeDef.
450 static uint32_t PIOS_DMAShot_AllocateBuffer(uint16_t size)
451 {
452  size += 12;
453  uint32_t ptr = (uint32_t)PIOS_malloc(size);
454 
455  // Blow up if we didn't get a buffer.
456  PIOS_Assert(ptr);
457 
458  memset((void*)ptr, 0, size);
459 
460  // Align to 16-byte boundary.
461  uint32_t shift = 16 - (ptr % 16);
462  if(shift != 16) ptr += shift;
463 
464  return ptr;
465 }
466 
468 {
469  // If there's nothing setup, fail hard. We shouldn't be getting here.
470  PIOS_Assert(dmashot_cfg && servo_timers);
471 
472  for (int i = 0; i < MAX_TIMERS; i++) {
473  struct servo_timer *s_timer = servo_timers[i];
474  if (!s_timer || !s_timer->sysclock)
475  continue;
476 
477  if (!s_timer->buffer.ptr) {
478  // Allocate buffer at timer resolution.
481  (PIOS_DMAShot_HalfWord(s_timer) ? sizeof(uint16_t) : sizeof(uint32_t))
482  );
483  }
484 
485  PIOS_DMAShot_DMASetup(s_timer);
486  }
487 }
488 
490 {
491  // If there's nothing setup, fail hard. We shouldn't be getting here.
492  PIOS_Assert(dmashot_cfg && servo_timers);
493 
494  for (int i = 0; i < MAX_TIMERS; i++) {
495  struct servo_timer *s_timer = servo_timers[i];
496  if (!s_timer || !s_timer->sysclock)
497  continue;
498 
499  // Wait for DMA to finish.
500  if(s_timer->dma_started) {
501  while(DMA_GetFlagStatus(s_timer->dma->stream, s_timer->dma->tcif) != SET) ;
502  }
503 
504  DMA_Cmd(s_timer->dma->stream, DISABLE);
505  while (DMA_GetCmdStatus(s_timer->dma->stream) == ENABLE) ;
506 
507  if (s_timer->dma->master_timer) {
508  TIM_DMACmd(s_timer->dma->master_timer,
509  // This results in a typical event source value
510  s_timer->dma->master_config & 0xFF00,
511  DISABLE);
512  TIM_Cmd(s_timer->dma->master_timer, DISABLE);
513  TIM_SetCounter(s_timer->dma->master_timer, 0);
514  } else {
515  TIM_DMACmd(s_timer->dma->timer, TIM_DMA_Update, DISABLE);
516  }
517 
518  TIM_Cmd(s_timer->dma->timer, DISABLE);
519  TIM_SetCounter(s_timer->dma->timer, 0);
520 
521  DMA_ClearFlag(s_timer->dma->stream, s_timer->dma->tcif);
522  DMA_SetCurrDataCounter(s_timer->dma->stream, PIOS_DMAShot_GetNumChannels(s_timer) * DMASHOT_STM32_BUFFER);
523  }
524 
525  // Re-enable the timers and DMA in a separate loop, to make the signals line up better.
526  for (int i = 0; i < MAX_TIMERS; i++) {
527  struct servo_timer *s_timer = servo_timers[i];
528  if (!s_timer || !s_timer->sysclock)
529  continue;
530 
531  if (s_timer->dma->master_timer) {
532  TIM_DMACmd(s_timer->dma->master_timer,
533  // This results in a typical event source value
534  s_timer->dma->master_config & 0xFF00,
535  ENABLE);
536  TIM_Cmd(s_timer->dma->timer, ENABLE);
537  TIM_Cmd(s_timer->dma->master_timer, ENABLE);
538  } else {
539  int offset = s_timer->low_channel >> 2;
540  int transfers = (s_timer->high_channel - s_timer->low_channel) >> 2;
541  TIM_DMAConfig(s_timer->dma->timer, TIM_DMABase_CCR1 + offset, transfers << 8);
542 
543  TIM_DMACmd(s_timer->dma->timer, TIM_DMA_Update, ENABLE);
544  TIM_Cmd(s_timer->dma->timer, ENABLE);
545  }
546 
547  DMA_Cmd(s_timer->dma->stream, ENABLE);
548  s_timer->dma_started = 1;
549  }
550 }
551 
553 {
554  if (!dmashot_cfg || !servo_timers)
555  return false;
556 
557  for (int i = 0; i < MAX_TIMERS; i++) {
558  struct servo_timer *s_timer = servo_timers[i];
559  if (s_timer && s_timer->sysclock) return true;
560  }
561 
562  return false;
563 }
564 
566 {
567  return dmashot_cfg != NULL;
568 }
#define DMASHOT_STM32_BUFFER
Definition: pios_dmashot.c:69
static void PIOS_DMAShot_DMASetup(struct servo_timer *s_timer)
Definition: pios_dmashot.c:399
#define TIMC_TO_INDEX(c)
Definition: pios_dmashot.c:76
const struct pios_dmashot_timer_cfg * timer_cfg
Definition: pios_dmashot.h:68
Main PiOS header to include all the compiled in PiOS options.
void PIOS_DMAShot_Prepare()
Makes sure the DMAShot driver has allocated all internal structs.
Definition: pios_dmashot.c:104
struct usb_configuration_desc config
GPIO_InitTypeDef init
Definition: pios_stm32.h:61
TIM_TypeDef * timer
Definition: pios_dmashot.h:53
uint16_t duty_cycle_0
Definition: pios_dmashot.c:57
void PIOS_DMAShot_InitializeTimers(TIM_OCInitTypeDef *ocinit)
Initializes and configures the registered timers for DMAShot operation.
Definition: pios_dmashot.c:367
#define MAX_TIMERS
Definition: pios_dmashot.c:33
GPIO_TypeDef * gpio
Definition: pios_stm32.h:60
static uint32_t PIOS_DMAShot_AllocateBuffer(uint16_t size)
Definition: pios_dmashot.c:450
uint32_t ptr
Definition: pios_dmashot.c:39
volatile int j
Definition: loadabletest.c:12
void PIOS_DMAShot_Validate()
Validates any timer and servo registrations.
Definition: pios_dmashot.c:279
TIM_TypeDef * master_timer
Definition: pios_dmashot.h:58
uint16_t duty_cycle_1
Definition: pios_dmashot.c:58
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_DMAShot_RegisterTimer(TIM_TypeDef *timer, uint32_t clockrate, uint32_t dshot_freq)
Tells the DMAShot driver about a timer that needs to be set up.
Definition: pios_dmashot.c:190
bool PIOS_DMAShot_RegisterServo(const struct pios_tim_channel *servo_channel)
Tells the DMAShot driver about a servo that needs to be set up.
Definition: pios_dmashot.c:250
struct stm32_gpio pin
Definition: pios_tim_priv.h:17
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
static struct servo_timer * PIOS_DMAShot_GetServoTimer(const struct pios_tim_channel *servo_channel)
Definition: pios_dmashot.c:126
uint32_t * fw
Definition: pios_dmashot.c:40
DMA_Stream_TypeDef * stream
Definition: pios_dmashot.h:54
bool PIOS_DMAShot_IsConfigured()
Checks whether DMAShot has been configured.
Definition: pios_dmashot.c:565
Configuration struct holding all timer configurations.
Definition: pios_dmashot.h:66
Configuration struct to assign a DMA channel and stream to a timer, and optionally specify a master t...
Definition: pios_dmashot.h:51
void PIOS_DMAShot_InitializeGPIOs()
Initializes the GPIO on the registered servos for DMAShot operation.
Definition: pios_dmashot.c:297
const struct pios_dmashot_timer_cfg * dma
Definition: pios_dmashot.c:48
static int PIOS_DMAShot_GetNumChannels(struct servo_timer *timer)
Definition: pios_dmashot.c:88
static void PIOS_DMAShot_TimerSetup(struct servo_timer *s_timer, uint32_t sysclock, uint32_t dshot_freq, TIM_OCInitTypeDef *ocinit, bool master)
Definition: pios_dmashot.c:322
uint32_t dshot_freq
Definition: pios_dmashot.c:55
void PIOS_DMAShot_InitializeDMAs()
Initializes and configures the known DMA channels for DMAShot operation.
Definition: pios_dmashot.c:467
#define DMASHOT_MESSAGE_PAUSE
Definition: pios_dmashot.c:68
uint8_t i
Definition: msp_messages.h:97
uint8_t pin_source
Definition: pios_stm32.h:62
uint32_t sysclock
Definition: pios_dmashot.c:46
uint8_t num_timers
Definition: pios_dmashot.h:69
union dma_buffer buffer
Definition: pios_dmashot.c:60
uint32_t offset
Definition: uavtalk_priv.h:51
tuple f
Definition: px_mkfw.py:81
#define DSHOT_DUTY_CYCLE_0
Definition: pios_dmashot.c:73
#define DSHOT_DUTY_CYCLE_1
Definition: pios_dmashot.c:74
#define DMASHOT_MESSAGE_WIDTH
Definition: pios_dmashot.c:67
void PIOS_DMAShot_WriteValue(const struct pios_tim_channel *servo_channel, uint16_t throttle)
Sets the throttle value of a specific servo.
Definition: pios_dmashot.c:143
struct servo_timer ** servo_timers
Definition: pios_dmashot.c:79
uint8_t low_channel
Definition: pios_dmashot.c:52
uint8_t dma_started
Definition: pios_dmashot.c:61
bool PIOS_DMAShot_IsReady()
Checks whether DMAShot is ready for use (i.e. at least one DMA configured timer). ...
Definition: pios_dmashot.c:552
const struct pios_dmashot_cfg * dmashot_cfg
Definition: pios_dmashot.c:78
static bool PIOS_DMAShot_HalfWord(struct servo_timer *s_timer)
Definition: pios_dmashot.c:82
TIM_TypeDef * timer
Definition: pios_tim_priv.h:14
const struct pios_tim_channel * servo_channels[4]
Definition: pios_dmashot.c:49
uint16_t * hw
Definition: pios_dmashot.c:41
void PIOS_DMAShot_Init(const struct pios_dmashot_cfg *config)
Initializes the DMAShot driver by loading the configuration.
Definition: pios_dmashot.c:96
#define PIOS_Assert(test)
Definition: pios_debug.h:52
void PIOS_DMAShot_TriggerUpdate()
Triggers the configured DMA channels to fire and send throttle values to the timer DMAR and optional ...
Definition: pios_dmashot.c:489
uint8_t high_channel
Definition: pios_dmashot.c:53