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