Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
spektrum_arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 Eric Parsonage <eric@eparsonage.com>
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 
22 #include <stdint.h>
23 #include <libopencm3/stm32/gpio.h>
24 #include <libopencm3/stm32/rcc.h>
25 #include <libopencm3/stm32/timer.h>
26 #include <libopencm3/stm32/usart.h>
27 #include <libopencm3/cm3/nvic.h>
28 
30 #include "subsystems/radio_control/spektrum_arch.h"
31 #include "mcu_periph/uart.h"
32 #include "mcu_periph/gpio.h"
33 #include "mcu_periph/sys_time.h"
34 
35 // for timer_get_frequency
36 #include "mcu_arch.h"
37 
38 INFO("Radio-Control now follows PPRZ sign convention: this means you might need to reverese some channels in your transmitter: RollRight / PitchUp / YawRight / FullThrottle / Auto2 are positive deflections")
39 
40 // for Min macro
41 #include "std.h"
42 
43 #include BOARD_CONFIG
44 
45 #define SPEKTRUM_CHANNELS_PER_FRAME 7
46 #define MAX_SPEKTRUM_FRAMES 2
47 #define MAX_SPEKTRUM_CHANNELS 16
48 
49 #define ONE_MHZ 1000000
50 
51 /* Number of low pulses sent to satellite receivers */
52 #if USE_DSMX
53 #define MASTER_RECEIVER_PULSES 9
54 #define SLAVE_RECEIVER_PULSES 10
55 #else
56 #define MASTER_RECEIVER_PULSES 5
57 #define SLAVE_RECEIVER_PULSES 6
58 #endif
59 
60 #define TIM_TICS_FOR_100us 100
61 #define MIN_FRAME_SPACE 70 // 7ms
62 #define MAX_BYTE_SPACE 3 // .3ms
63 
64 
65 //not all f1's have a timer 6, so, some redefines have to happen
66 #define PASTER3(x,y,z) x ## y ## z
67 #define EVALUATOR3(x,y,z) PASTER3(x,y,z)
68 #define NVIC_TIMx_IRQ EVALUATOR3(NVIC_TIM, SPEKTRUM_TIMER,_IRQ)
69 #define NVIC_TIMx_DAC_IRQ EVALUATOR3(NVIC_TIM, SPEKTRUM_TIMER,_DAC_IRQ) // not really necessary, only for f4 which probably always has a timer 4
70 #define TIMx_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_isr)
71 #define TIMx_DAC_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_dac_isr)
72 
73 #define PASTER2(x,y) x ## y
74 #define EVALUATOR2(x,y) PASTER2(x,y)
75 #define TIMx EVALUATOR2(TIM, SPEKTRUM_TIMER)
76 #define RCC_TIMx EVALUATOR2(RCC_TIM, SPEKTRUM_TIMER)
77 
78 #ifndef SPEKTRUM_TIMER
79 #define SPEKTRUM_TIMER 6
80 #endif
81 
82 #if (SPEKTRUM_TIMER == 6)
83 #ifndef NVIC_TIM6_IRQ_PRIO
84 #define NVIC_TIM6_IRQ_PRIO 2
85 #define NVIC_TIMx_IRQ_PRIO 2
86 #else
87 #define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO
88 #endif
89 #ifndef NVIC_TIM6_DAC_IRQ_PRIO
90 #define NVIC_TIM6_DAC_IRQ_PRIO 2
91 #define NVIC_TIMx_DAC_IRQ_PRIO 2
92 #else
93 #define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO
94 #endif
95 #endif
96 
97 #if (SPEKTRUM_TIMER == 3)
98 #ifndef NVIC_TIM3_IRQ_PRIO
99 #define NVIC_TIM3_IRQ_PRIO 2
100 #define NVIC_TIMx_IRQ_PRIO 2
101 #else
102 #define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO
103 #endif
104 #ifndef NVIC_TIM3_DAC_IRQ_PRIO
105 #define NVIC_TIM3_DAC_IRQ_PRIO 2
106 #define NVIC_TIMx_DAC_IRQ_PRIO 2
107 #else
108 #define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO
109 #endif
110 #endif
111 
112 PRINT_CONFIG_MSG_VALUE("SPEKTRUM_TIMER: " , SPEKTRUM_TIMER)
113 
114 #ifdef NVIC_UART_IRQ_PRIO
115 #define NVIC_PRIMARY_UART_PRIO NVIC_UART_IRQ_PRIO
116 #else
117 #define NVIC_PRIMARY_UART_PRIO 2
118 #endif
119 
120 /*
121  * in the makefile we set RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT to be UARTx
122  * but in uart_hw.c the initialisation functions are
123  * defined as uartx these macros give us the glue
124  * that allows static calls at compile time
125  */
126 
127 #define __PrimaryUart(dev, _x) dev##_x
128 #define _PrimaryUart(dev, _x) __PrimaryUart(dev, _x)
129 #define PrimaryUart(_x) _PrimaryUart(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT, _x)
130 
131 #define __SecondaryUart(dev, _x) dev##_x
132 #define _SecondaryUart(dev, _x) __SecondaryUart(dev, _x)
133 #define SecondaryUart(_x) _SecondaryUart(RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT, _x)
134 
146 };
147 
149 
150 SpektrumStateType PrimarySpektrumState = {1, 0, 0, 0, 0, 0, 0, 0, 0, {0}};
151 PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT)
152 
153 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
154 PRINT_CONFIG_MSG("Using secondary spektrum receiver.")
155 PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT)
156 SpektrumStateType SecondarySpektrumState = {1, 0, 0, 0, 0, 0, 0, 0, 0, {0}};
157 #else
158 PRINT_CONFIG_MSG("NOT using secondary spektrum receiver.")
159 #endif
160 
162 /* the order of the channels on a spektrum is always as follows :
163  *
164  * Throttle 0
165  * Aileron 1
166  * Elevator 2
167  * Rudder 3
168  * Gear 4
169  * Flap/Aux1 5
170  * Aux2 6
171  * Aux3 7
172  * Aux4 8
173  * Aux5 9
174  * Aux6 10
175  * Aux7 11
176  */
177 
178 /* reverse some channels to suit Paparazzi conventions */
179 /* the maximum number of channels a Spektrum can transmit is 12 */
181 
182 /* Parser state variables */
185 
186 /* initialise the timer used by the parser to ensure sync */
187 void SpektrumTimerInit(void);
188 
197 #ifndef RC_SET_POLARITY
198 #define RC_SET_POLARITY gpio_clear
199 #endif
200 
201 /*****************************************************************************
202 *
203 * Initialise the timer an uarts used by the Spektrum receiver subsystem
204 *
205 *****************************************************************************/
207 {
208 
209  PrimarySpektrumState.ReSync = 1;
210 
211 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
212  SecondarySpektrumState.ReSync = 1;
213 #endif
214 
215  // Set polarity to normal on boards that can change this
216 #ifdef RC_POLARITY_GPIO_PORT
219 #endif
220 
223 }
224 
225 /*****************************************************************************
226  * The bind function means that the satellite receivers believe they are
227  * connected to a 9 channel JR-R921 24 receiver thus during the bind process
228  * they try to get the transmitter to transmit at the highest resolution that
229  * it can manage. The data is contained in 16 byte packets transmitted at
230  * 115200 baud. Depending on the transmitter either 1 or 2 frames are required
231  * to contain the data for all channels. These frames are either 11ms or 22ms
232  * apart.
233  *
234  * The format of each frame for the main receiver is as follows
235  *
236  * byte1: frame loss data
237  * byte2: transmitter information
238  * byte3: and byte4: channel data
239  * byte5: and byte6: channel data
240  * byte7: and byte8: channel data
241  * byte9: and byte10: channel data
242  * byte11: and byte12: channel data
243  * byte13: and byte14: channel data
244  * byte15: and byte16: channel data
245  *
246  *
247  * The format of each frame for the secondary receiver is as follows
248  *
249  * byte1: frame loss data
250  * byte2: frame loss data
251  * byte3: and byte4: channel data
252  * byte5: and byte6: channel data
253  * byte7: and byte8: channel data
254  * byte9: and byte10: channel data
255  * byte11: and byte12: channel data
256  * byte13: and byte14: channel data
257  * byte15: and byte16: channel data
258  *
259  * The frame loss data bytes starts out containing 0 as long as the
260  * transmitter is switched on before the receivers. It then increments
261  * whenever frames are dropped.
262  *
263  * Three values for the transmitter information byte have been seen thus far
264  *
265  * 0x01 From a Spektrum DX7eu which transmits a single frame containing all
266  * channel data every 22ms with 10bit resolution.
267  *
268  * 0x02 From a Spektrum DM9 module which transmits two frames to carry the
269  * data for all channels 11ms apart with 10bit resolution.
270  *
271  * 0x12 From a Spektrum DX7se which transmits two frames to carry the
272  * data for all channels 11ms apart with 11bit resolution.
273  *
274  * 0x12 From a JR X9503 which transmits two frames to carry the
275  * data for all channels 11ms apart with 11bit resolution.
276  *
277  * 0x01 From a Spektrum DX7 which transmits a single frame containing all
278  * channel data every 22ms with 10bit resolution.
279  *
280  * 0x12 From a JR DSX12 which transmits two frames to carry the
281  * data for all channels 11ms apart with 11bit resolution.
282  *
283  * 0x1 From a Spektru DX5e which transmits a single frame containing all
284  * channel data every 22ms with 10bit resolution.
285  *
286  * 0x01 From a Spektrum DX6i which transmits a single frame containing all
287  * channel data every 22ms with 10bit resolution.
288  *
289  * Currently the assumption is that the data has the form :
290  *
291  * [0 0 0 R 0 0 N1 N0]
292  *
293  * where :
294  *
295  * 0 means a '0' bit
296  * R: 0 for 10 bit resolution 1 for 11 bit resolution channel data
297  * N1 to N0 is the number of frames required to receive all channel
298  * data.
299  *
300  * Channels can have either 10bit or 11bit resolution. Data from a tranmitter
301  * with 10 bit resolution has the form:
302  *
303  * [F 0 C3 C2 C1 C0 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0]
304  *
305  * Data from a tranmitter with 11 bit resolution has the form
306  *
307  * [F C3 C2 C1 C0 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0]
308  *
309  * where :
310  *
311  * 0 means a '0' bit
312  * F: Normally 0 but set to 1 for the first channel of the 2nd frame if a
313  * second frame is transmitted.
314  *
315  * C3 to C0 is the channel number, 4 bit, matching the numbers allocated in
316  * the transmitter.
317  *
318  * D9 to D0 is the channel data (10 bit) 0xaa..0x200..0x356 for
319  * 100% transmitter-travel
320  *
321  *
322  * D10 to D0 is the channel data (11 bit) 0x154..0x400..0x6AC for
323  * 100% transmitter-travel
324  *****************************************************************************/
325 
326 /*****************************************************************************
327 *
328 * Spektrum Parser captures frame data by using time between frames to sync on
329 *
330 *****************************************************************************/
331 
332 static inline void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, bool secondary_receiver)
333 {
334 
335 
336 
337  uint16_t ChannelData;
338  uint8_t TimedOut;
339  static uint8_t TmpEncType = 0; /* 0 = 10bit, 1 = 11 bit */
340  static uint8_t TmpExpFrames = 0; /* # of frames for channel data */
341 
342  TimedOut = (!spektrum_state->SpektrumTimer) ? 1 : 0;
343 
344  /* If we have just started the resync process or */
345  /* if we have recieved a character before our */
346  /* 7ms wait has finished */
347  if ((spektrum_state->ReSync == 1) ||
348  ((spektrum_state->Sync == 0) && (!TimedOut))) {
349 
350  spektrum_state->ReSync = 0;
351  spektrum_state->SpektrumTimer = MIN_FRAME_SPACE;
352  spektrum_state->Sync = 0;
353  spektrum_state->ChannelCnt = 0;
354  spektrum_state->FrameCnt = 0;
355  spektrum_state->SecondFrame = 0;
356  return;
357  }
358 //LED_OFF(1);
359 
360  /* the first byte of a new frame. It was received */
361  /* more than 7ms after the last received byte. */
362  /* It represents the number of lost frames so far.*/
363  if (spektrum_state->Sync == 0) {
364  spektrum_state->LostFrameCnt = _c;
365  if (secondary_receiver) { /* secondary receiver */
366  spektrum_state->LostFrameCnt = spektrum_state->LostFrameCnt << 8;
367  }
368  spektrum_state->Sync = 1;
369  spektrum_state->SpektrumTimer = MAX_BYTE_SPACE;
370  return;
371  }
372 
373  /* all other bytes should be recieved within */
374  /* MAX_BYTE_SPACE time of the last byte received */
375  /* otherwise something went wrong resynchronise */
376  if (TimedOut) {
377  spektrum_state->ReSync = 1;
378  /* next frame not expected sooner than 7ms */
379  spektrum_state->SpektrumTimer = MIN_FRAME_SPACE;
380  return;
381  }
382 
383  /* second character determines resolution and frame rate for main */
384  /* receiver or low byte of LostFrameCount for secondary receiver */
385  if (spektrum_state->Sync == 1) {
386  if (secondary_receiver) {
387  spektrum_state->LostFrameCnt += _c;
388  TmpExpFrames = ExpectedFrames;
389  } else {
391  /* protocol that is still 10 bit but without using the full range. */
392  TmpEncType = (_c & 0x10) >> 4; /* 0 = 10bit, 1 = 11 bit */
393  TmpExpFrames = _c & 0x03; /* 1 = 1 frame contains all channels */
394  /* 2 = 2 channel data in 2 frames */
395  }
396  spektrum_state->Sync = 2;
397  spektrum_state->SpektrumTimer = MAX_BYTE_SPACE;
398  return;
399  }
400 
401  /* high byte of channel data if this is the first byte */
402  /* of channel data and the most significant bit is set */
403  /* then this is the second frame of channel data. */
404  if (spektrum_state->Sync == 2) {
405  spektrum_state->HighByte = _c;
406  if (spektrum_state->ChannelCnt == 0) {
407  spektrum_state->SecondFrame = (spektrum_state->HighByte & 0x80) ? 1 : 0;
408  }
409  spektrum_state->Sync = 3;
410  spektrum_state->SpektrumTimer = MAX_BYTE_SPACE;
411  return;
412  }
413 
414  /* low byte of channel data */
415  if (spektrum_state->Sync == 3) {
416  spektrum_state->Sync = 2;
417  spektrum_state->SpektrumTimer = MAX_BYTE_SPACE;
418  /* we overwrite the buffer now so rc data is not available now */
419  spektrum_state->RcAvailable = 0;
420  ChannelData = ((uint16_t)spektrum_state->HighByte << 8) | _c;
421  spektrum_state->values[spektrum_state->ChannelCnt
422  + (spektrum_state->SecondFrame * 7)] = ChannelData;
423  spektrum_state->ChannelCnt ++;
424  }
425 
426  /* If we have a whole frame */
427  if (spektrum_state->ChannelCnt >= SPEKTRUM_CHANNELS_PER_FRAME) {
428  /* how many frames did we expect ? */
429  ++spektrum_state->FrameCnt;
430  if (spektrum_state->FrameCnt == TmpExpFrames) {
431  /* set the rc_available_flag */
432  spektrum_state->RcAvailable = 1;
433  spektrum_state->FrameCnt = 0;
434  }
435  if (!secondary_receiver) { /* main receiver */
436  EncodingType = TmpEncType; /* only update on a good */
437  ExpectedFrames = TmpExpFrames; /* main receiver frame */
438  }
439  spektrum_state->Sync = 0;
440  spektrum_state->ChannelCnt = 0;
441  spektrum_state->SecondFrame = 0;
442  spektrum_state->SpektrumTimer = MIN_FRAME_SPACE;
443  }
444 }
445 
446 /*****************************************************************************
447  *
448  * RadioControlEventImp decodes channel data stored by uart irq handlers
449  * and calls callback funtion
450  *
451  *****************************************************************************/
452 
453 void RadioControlEventImp(void (*frame_handler)(void))
454 {
456  uint8_t ChannelNum;
457  uint16_t ChannelData;
458  uint8_t MaxChannelNum = 0;
459 
460 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
461  /* If we have two receivers and at least one of them has new data */
462  uint8_t BestReceiver;
463  if ((PrimarySpektrumState.RcAvailable) ||
464  (SecondarySpektrumState.RcAvailable)) {
465  /* if both receivers have new data select the one */
466  /* that has had the least number of frames lost */
467  if ((PrimarySpektrumState.RcAvailable) &&
468  (SecondarySpektrumState.RcAvailable)) {
469  BestReceiver = (PrimarySpektrumState.LostFrameCnt
470  <= SecondarySpektrumState.LostFrameCnt) ? 0 : 1;
471  } else {
472  /* if only one of the receivers have new data use it */
473  BestReceiver = (PrimarySpektrumState.RcAvailable) ? 0 : 1;
474  }
475  /* clear the data ready flags */
476  PrimarySpektrumState.RcAvailable = 0;
477  SecondarySpektrumState.RcAvailable = 0;
478 
479 #else
480  /* if we have one receiver and it has new data */
481  if (PrimarySpektrumState.RcAvailable) {
482  PrimarySpektrumState.RcAvailable = 0;
483 #endif
484  ChannelCnt = 0;
485  /* for every piece of channel data we have received */
486  for (int i = 0; (i < SPEKTRUM_CHANNELS_PER_FRAME * ExpectedFrames); i++) {
487 #ifndef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
488  ChannelData = PrimarySpektrumState.values[i];
489 #else
490  ChannelData = (!BestReceiver) ? PrimarySpektrumState.values[i] :
491  SecondarySpektrumState.values[i];
492 #endif
493  /* find out the channel number and its value by */
494  /* using the EncodingType which is only received */
495  /* from the main receiver */
496  switch (EncodingType) {
497  case (0) : /* 10 bit */
498  ChannelNum = (ChannelData >> 10) & 0x0f;
499  /* don't bother decoding unused channels */
500  if (ChannelNum < SPEKTRUM_NB_CHANNEL) {
501  SpektrumBuf[ChannelNum] = ChannelData & 0x3ff;
502  SpektrumBuf[ChannelNum] -= 0x200;
503  SpektrumBuf[ChannelNum] *= MAX_PPRZ / 0x156;
504  ChannelCnt++;
505  }
506  break;
507 
508  case (1) : /* 11 bit */
509  ChannelNum = (ChannelData >> 11) & 0x0f;
510  /* don't bother decoding unused channels */
511  if (ChannelNum < SPEKTRUM_NB_CHANNEL) {
512  SpektrumBuf[ChannelNum] = ChannelData & 0x7ff;
513  SpektrumBuf[ChannelNum] -= 0x400;
514  SpektrumBuf[ChannelNum] *= MAX_PPRZ / 0x2AC;
515  ChannelCnt++;
516  }
517  break;
518 
519  default : ChannelNum = 0x0F; break; /* never going to get here */
520  }
521  /* store the value of the highest valid channel */
522  if ((ChannelNum != 0x0F) && (ChannelNum > MaxChannelNum)) {
523  MaxChannelNum = ChannelNum;
524  }
525 
526  }
527 
528  /* if we have a valid frame the pass it to the frame handler */
529  if (ChannelCnt >= (MaxChannelNum + 1)) {
533  /* since it is possible for the user use less than the actually available channels,
534  * we only transfer only Min(RADIO_CONTROL_NB_CHANNEL, available_channels)
535  */
536  for (int i = 0; i < Min(RADIO_CONTROL_NB_CHANNEL, (MaxChannelNum + 1)); i++) {
537  radio_control.values[i] = SpektrumBuf[i];
538  //Only values between +-MAX_PPRZ are allowed
539  Bound(radio_control.values[i], -MAX_PPRZ, MAX_PPRZ);
540  if (i == RADIO_THROTTLE) {
542  radio_control.values[i] /= 2;
543  }
544  radio_control.values[i] *= SpektrumSigns[i];
545  }
546  (*frame_handler)();
547  }
548  }
549 }
550 
551 
552 /*****************************************************************************
553  *
554  * Initialise TIMx to fire an interrupt every 100 microseconds to provide
555  * timebase for SpektrumParser
556  *
557  *****************************************************************************/
559 {
560 
561  /* enable TIMx clock */
562  rcc_periph_clock_enable(RCC_TIMx);
563 
564  timer_reset(TIMx);
565  /* TIMx configuration, always counts up */
566  timer_set_mode(TIMx, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // used to be 0 0
567  /* 100 microseconds ie 0.1 millisecond */
568  timer_set_period(TIMx, TIM_TICS_FOR_100us - 1);
569  uint32_t TIMx_clk = timer_get_frequency(TIMx);
570  /* timer ticks with 1us */
571  timer_set_prescaler(TIMx, ((TIMx_clk / ONE_MHZ) - 1));
572 
573  /* Enable TIMx interrupts */
574 #ifdef STM32F1
575  nvic_set_priority(NVIC_TIMx_IRQ, NVIC_TIMx_IRQ_PRIO);
576  nvic_enable_irq(NVIC_TIMx_IRQ);
577 #elif defined STM32F4
578  /* the define says DAC IRQ, but it is also the global TIMx IRQ*/
579  nvic_set_priority(NVIC_TIMx_DAC_IRQ, NVIC_TIMx_DAC_IRQ_PRIO);
580  nvic_enable_irq(NVIC_TIMx_DAC_IRQ);
581 #endif
582 
583  /* Enable TIMx Update interrupt */
584  timer_enable_irq(TIMx, TIM_DIER_UIE);
585  timer_clear_flag(TIMx, TIM_SR_UIF);
586 
587  /* TIMx enable counter */
588  timer_enable_counter(TIMx);
589 }
590 
591 /*****************************************************************************
592  *
593  * TIMx interrupt request handler updates times used by SpektrumParser
594  *
595  *****************************************************************************/
596 #ifdef STM32F1
597 void TIMx_ISR(void)
598 {
599 #elif defined STM32F4
600 void TIMx_DAC_ISR(void) {
601 #endif
602 
603  timer_clear_flag(TIMx, TIM_SR_UIF);
604 
605  if (PrimarySpektrumState.SpektrumTimer) {
606  --PrimarySpektrumState.SpektrumTimer;
607  }
608 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
609  if (SecondarySpektrumState.SpektrumTimer) {
610  --SecondarySpektrumState.SpektrumTimer;
611  }
612 #endif
613 }
614 
615 /*****************************************************************************
616  *
617  * Initialise the uarts for the spektrum satellite receivers
618  *
619  *****************************************************************************/
620 void SpektrumUartInit(void) {
621  /* init RCC */
623  rcc_periph_clock_enable(PrimaryUart(_RCC));
624 
625  /* Enable USART interrupts */
626  nvic_set_priority(PrimaryUart(_IRQ), NVIC_PRIMARY_UART_PRIO);
627  nvic_enable_irq(PrimaryUart(_IRQ));
628 
629  /* Init GPIOS */
630  /* Primary UART Rx pin as floating input */
632 
633  /* Configure Primary UART */
634  usart_set_baudrate(PrimaryUart(_DEV), B115200);
635  usart_set_databits(PrimaryUart(_DEV), 8);
636  usart_set_stopbits(PrimaryUart(_DEV), USART_STOPBITS_1);
637  usart_set_parity(PrimaryUart(_DEV), USART_PARITY_NONE);
638  usart_set_flow_control(PrimaryUart(_DEV), USART_FLOWCONTROL_NONE);
639  usart_set_mode(PrimaryUart(_DEV), USART_MODE_RX);
640 
641  /* Enable Primary UART Receive interrupts */
642  USART_CR1(PrimaryUart(_DEV)) |= USART_CR1_RXNEIE;
643 
644  /* Enable the Primary UART */
645  usart_enable(PrimaryUart(_DEV));
646 
647 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
648  /* init RCC */
650  rcc_periph_clock_enable(SecondaryUart(_RCC));
651 
652  /* Enable USART interrupts */
653  nvic_set_priority(SecondaryUart(_IRQ), NVIC_PRIMARY_UART_PRIO + 1);
654  nvic_enable_irq(SecondaryUart(_IRQ));
655 
656  /* Init GPIOS */;
657  /* Secondary UART Rx pin as floating input */
659 
660  /* Configure secondary UART */
661  usart_set_baudrate(SecondaryUart(_DEV), B115200);
662  usart_set_databits(SecondaryUart(_DEV), 8);
663  usart_set_stopbits(SecondaryUart(_DEV), USART_STOPBITS_1);
664  usart_set_parity(SecondaryUart(_DEV), USART_PARITY_NONE);
665  usart_set_flow_control(SecondaryUart(_DEV), USART_FLOWCONTROL_NONE);
666  usart_set_mode(SecondaryUart(_DEV), USART_MODE_RX);
667 
668  /* Enable Secondary UART Receive interrupts */
669  USART_CR1(SecondaryUart(_DEV)) |= USART_CR1_RXNEIE;
670 
671  /* Enable the Primary UART */
672  usart_enable(SecondaryUart(_DEV));
673 #endif
674 
675 }
676 
677 /*****************************************************************************
678  *
679  * The primary receiver UART interrupt request handler which passes the
680  * received character to Spektrum Parser.
681  *
682  *****************************************************************************/
683 void PrimaryUart(_ISR)(void) {
684 
685  if (((USART_CR1(PrimaryUart(_DEV)) & USART_CR1_TXEIE) != 0) &&
686  ((USART_SR(PrimaryUart(_DEV)) & USART_SR_TXE) != 0)) {
687  USART_CR1(PrimaryUart(_DEV)) &= ~USART_CR1_TXEIE;
688  }
689 
690  if (((USART_CR1(PrimaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) &&
691  ((USART_SR(PrimaryUart(_DEV)) & USART_SR_RXNE) != 0)) {
692  uint8_t b = usart_recv(PrimaryUart(_DEV));
693  SpektrumParser(b, &PrimarySpektrumState, FALSE);
694  }
695 
696 }
697 
698 /*****************************************************************************
699  *
700  * The secondary receiver UART interrupt request handler which passes the
701  * received character to Spektrum Parser.
702  *
703  *****************************************************************************/
704 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
705 void SecondaryUart(_ISR)(void) {
706 
707  if (((USART_CR1(SecondaryUart(_DEV)) & USART_CR1_TXEIE) != 0) &&
708  ((USART_SR(SecondaryUart(_DEV)) & USART_SR_TXE) != 0)) {
709  USART_CR1(SecondaryUart(_DEV)) &= ~USART_CR1_TXEIE;
710  }
711 
712  if (((USART_CR1(SecondaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) &&
713  ((USART_SR(SecondaryUart(_DEV)) & USART_SR_RXNE) != 0)) {
714  uint8_t b = usart_recv(SecondaryUart(_DEV));
715  SpektrumParser(b, &SecondarySpektrumState, TRUE);
716  }
717 
718 }
719 #endif
720 
721 
722 /*****************************************************************************
723  *
724  * The following functions provide functionality to allow binding of
725  * spektrum satellite receivers. The pulse train sent to them means
726  * that AP is emulating a 9 channel JR-R921 24.
727  * By default, the same pin is used for pulse train and uart rx, but
728  * they can be different if needed
729  *
730  *****************************************************************************/
731 #ifndef SPEKTRUM_PRIMARY_BIND_CONF_PORT
732 #define SPEKTRUM_PRIMARY_BIND_CONF_PORT PrimaryUart(_BANK)
733 #endif
734 #ifndef SPEKTRUM_PRIMARY_BIND_CONF_PIN
735 #define SPEKTRUM_PRIMARY_BIND_CONF_PIN PrimaryUart(_PIN)
736 #endif
737 #ifndef SPEKTRUM_SECONDARY_BIND_CONF_PORT
738 #define SPEKTRUM_SECONDARY_BIND_CONF_PORT SecondaryUart(_BANK)
739 #endif
740 #ifndef SPEKTRUM_SECONDARY_BIND_CONF_PIN
741 #define SPEKTRUM_SECONDARY_BIND_CONF_PIN SecondaryUart(_PIN)
742 #endif
743 
744 /*****************************************************************************
745  *
746  * radio_control_spektrum_try_bind(void) must called on powerup as spektrum
747  * satellites can only bind immediately after power up also it must be called
748  * before the call to SpektrumUartInit as we leave them with their Rx pins set
749  * as outputs.
750  *
751  *****************************************************************************/
753 #ifdef SPEKTRUM_BIND_PIN_PORT
754 #ifdef SPEKTRUM_BIND_PIN_HIGH
755  /* Init GPIO for the bind pin, we enable the pulldown resistor.
756  * (esden) As far as I can tell only navstick is using the PIN LOW version of
757  * the bind pin, but I assume this should not harm anything. If I am mistaken
758  * than I appologise for the inconvenience. :)
759  */
761 
762  /* exit if the BIND_PIN is low, it needs to
763  be pulled high at startup to initiate bind */
765  return;
766  }
767 #else
768  /* Init GPIO for the bind pin, we enable the pullup resistor in case we have
769  * a floating pin that does not have a hardware pullup resistor as it is the
770  * case with Lisa/M and Lisa/MX prior to version 2.1.
771  */
773 
774  /* exit if the BIND_PIN is high, it needs to
775  be pulled low at startup to initiate bind */
777  return;
778  }
779 #endif
780 #endif
781 
782  /* Master receiver Rx push-pull */
784 
785  /* Master receiver RX line, drive high */
787 
788 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
789  /* Slave receiver Rx push-pull */
791 
792  /* Slave receiver RX line, drive high */
794 #endif
795 
796  /* We have no idea how long the window for allowing binding after
797  power up is. This works for the moment but will need revisiting */
798  sys_time_usleep(61000);
799 
800  for (int i = 0; i < MASTER_RECEIVER_PULSES ; i++) {
802  sys_time_usleep(118);
804  sys_time_usleep(122);
805  }
806 
807 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
808  for (int i = 0; i < SLAVE_RECEIVER_PULSES; i++) {
810  sys_time_usleep(120);
812  sys_time_usleep(120);
813  }
814 #endif /* RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT */
815 
816  /* Set conf pin as input in case it is different from RX pin */
818 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
820 #endif
821 }
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:61
int16_t SpektrumBuf[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]
void radio_control_impl_init(void)
Definition: spektrum_arch.c:30
unsigned short uint16_t
Definition: types.h:16
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
#define SPEKTRUM_PRIMARY_BIND_CONF_PIN
#define SPEKTRUM_SECONDARY_BIND_CONF_PIN
#define RC_POLARITY_GPIO_PORT
Definition: board.h:720
#define SLAVE_RECEIVER_PULSES
Definition: spektrum_arch.c:57
#define MIN_FRAME_SPACE
Definition: spektrum_arch.c:61
#define NVIC_TIMx_IRQ_PRIO
Definition: spektrum_arch.c:85
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
Definition: gpio_arch.h:108
uint8_t status
Definition: radio_control.h:53
#define SPEKTRUM_SECONDARY_BIND_CONF_PORT
#define B115200
Definition: uart_arch.h:48
Some architecture independent helper functions for GPIOs.
void PrimaryUart() _ISR(void)
void SpektrumTimerInit(void)
#define SPEKTRUM_TIMER
Definition: spektrum_arch.c:79
#define MAX_SPEKTRUM_FRAMES
Definition: spektrum_arch.c:46
#define MASTER_RECEIVER_PULSES
Definition: spektrum_arch.c:56
#define SPEKTRUM_BIND_PIN
Definition: apogee_1.0.h:417
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:263
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
Definition: radio_control.h:58
void gpio_setup_output(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as outputs.
Definition: gpio_arch.c:33
#define PrimaryUart(_x)
static uint8_t ExpectedFrames
#define SecondaryUart(_x)
#define RC_POLARITY_GPIO_PIN
Definition: board.h:721
#define FALSE
Definition: std.h:5
void gpio_setup_input_pullup(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as inputs with pull up resistor enabled.
Definition: gpio_arch.c:47
timer_clear_flag(TIMx, TIM_SR_UIF)
void gpio_enable_clock(uint32_t port)
Enable the relevant clock.
Definition: gpio_arch.c:34
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
Definition: sys_time_arch.c:95
#define TRUE
Definition: std.h:4
Architecture independent timing functions.
SpektrumStateType PrimarySpektrumState
#define SPEKTRUM_CHANNELS_PER_FRAME
Definition: spektrum_arch.c:45
#define SPEKTRUM_NB_CHANNEL
Definition: spektrum_arch.h:32
unsigned long uint32_t
Definition: types.h:18
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
signed short int16_t
Definition: types.h:17
static uint8_t EncodingType
#define NVIC_PRIMARY_UART_PRIO
struct RadioControl radio_control
Definition: radio_control.c:30
#define RADIO_THROTTLE
Definition: spektrum_arch.h:42
#define Min(x, y)
Definition: main_fbw.c:52
#define NVIC_TIMx_DAC_IRQ
Definition: spektrum_arch.c:69
#define RC_SET_POLARITY
Set polarity using RC_POLARITY_GPIO.
#define RADIO_CONTROL_NB_CHANNEL
Definition: spektrum_arch.h:34
#define RC_OK
Definition: radio_control.h:48
#define SPEKTRUM_BIND_PIN_PORT
Definition: apogee_1.0.h:418
int8_t SpektrumSigns[]
#define TIMx_ISR
Definition: spektrum_arch.c:70
#define TIM_TICS_FOR_100us
Definition: spektrum_arch.c:60
#define SPEKTRUM_PRIMARY_BIND_CONF_PORT
static uint8_t gpio_get(ioportid_t port, uint16_t pin)
Get level of a gpio.
Definition: gpio_arch.h:88
#define RADIO_CONTROL_SPEKTRUM_SIGNS
Definition: spektrum_arch.h:75
unsigned char uint8_t
Definition: types.h:14
void RadioControlEventImp(void(*frame_handler)(void))
Definition: spektrum_arch.c:48
void SpektrumUartInit(void)
void radio_control_spektrum_try_bind(void)
Definition: spektrum_arch.c:42
#define NVIC_TIMx_IRQ
Definition: spektrum_arch.c:68
#define MAX_BYTE_SPACE
Definition: spektrum_arch.c:62
void gpio_setup_input_pulldown(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as inputs with pull down resistors enabled.
Definition: gpio_arch.c:54
uint8_t time_since_last_frame
Definition: radio_control.h:54
#define NVIC_TIMx_DAC_IRQ_PRIO
Definition: spektrum_arch.c:91
#define MAX_PPRZ
Definition: paparazzi.h:8
signed char int8_t
Definition: types.h:15
#define RCC_TIMx
Definition: spektrum_arch.c:76
void gpio_setup_input(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as inputs.
Definition: gpio_arch.c:40
#define TIMx_DAC_ISR
Definition: spektrum_arch.c:71
static void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, bool secondary_receiver)
static void gpio_set(ioportid_t port, uint16_t pin)
Set a gpio output to high level.
Definition: gpio_arch.h:98
#define ONE_MHZ
Definition: spektrum_arch.c:49
uint8_t frame_cpt
Definition: radio_control.h:57
int16_t values[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]
#define TIMx
Definition: spektrum_arch.c:75