From 424cd788f574518bd69ac9cdaf4d0969a28b38f5 Mon Sep 17 00:00:00 2001 From: Gautier Hattenberger Date: Sun, 29 Apr 2018 00:15:10 +0200 Subject: [PATCH] [radio] rewrite the Spektrum driver to be generic (#2250) This is based on #1799 and replace it. Now, the normal UART driver is used instead of the specific code. It makes it possible to use on only arch, including ChibiOS. Binding is also possible, but for boards using ChibiOS and SD logger, it is recommended to disable it for the binding process as the LSE clock required by the RTC is longer to start (bind pulses should be issued before 200ms after power up). The configuration is backward compatible and some defines in the boards' header could be even removed. Only Apogee, Chimera and Elle0 have been updated as it is the only board tested for now. There is no harm to keep the old defines. --- conf/airframes/ENAC/fixed-wing/chimera.xml | 2 +- conf/modules/radio_control_spektrum.xml | 76 +- .../arch/chibios/mcu_periph/sys_time_arch.c | 11 +- .../subsystems/radio_control/spektrum_arch.c | 34 - .../subsystems/radio_control/spektrum_arch.h | 100 --- .../subsystems/radio_control/spektrum_arch.c | 8 +- .../subsystems/radio_control/spektrum_arch.h | 40 +- .../subsystems/radio_control/spektrum_arch.c | 825 ------------------ .../boards/apogee/chibios/v1.0/board.h | 22 + sw/airborne/boards/apogee_1.0.h | 18 - .../boards/chimera/chibios/v1.0/chimera.h | 58 +- .../boards/chimera/chibios/v1.0/mcuconf.h | 8 + sw/airborne/boards/elle0_common.h | 24 - sw/airborne/mcu.c | 4 +- .../subsystems/radio_control/joby_9ch.h | 49 -- .../subsystems/radio_control/spektrum.c | 368 +++++++- .../subsystems/radio_control/spektrum.h | 44 +- .../subsystems/radio_control/spektrum_dx7se.h | 53 -- .../radio_control/spektrum_dx7se_joby.h | 52 -- .../radio_control/spektrum_radio.h} | 61 +- 20 files changed, 556 insertions(+), 1301 deletions(-) delete mode 100644 sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.c delete mode 100644 sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.h delete mode 100644 sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c delete mode 100644 sw/airborne/subsystems/radio_control/joby_9ch.h delete mode 100644 sw/airborne/subsystems/radio_control/spektrum_dx7se.h delete mode 100644 sw/airborne/subsystems/radio_control/spektrum_dx7se_joby.h rename sw/airborne/{arch/stm32/subsystems/radio_control/spektrum_arch.h => subsystems/radio_control/spektrum_radio.h} (55%) diff --git a/conf/airframes/ENAC/fixed-wing/chimera.xml b/conf/airframes/ENAC/fixed-wing/chimera.xml index 233e1c30446..cfb9bd01249 100644 --- a/conf/airframes/ENAC/fixed-wing/chimera.xml +++ b/conf/airframes/ENAC/fixed-wing/chimera.xml @@ -18,7 +18,7 @@ UBX GPS / HMC58XX mag (drotek) - + diff --git a/conf/modules/radio_control_spektrum.xml b/conf/modules/radio_control_spektrum.xml index 28b2367064e..2256f3b7ce0 100644 --- a/conf/modules/radio_control_spektrum.xml +++ b/conf/modules/radio_control_spektrum.xml @@ -8,50 +8,70 @@ Define USE_DSMX on STM32 microcontrollers to bind in DSMX instead of DSM2 - - + + -
- + - - - ifeq ($(ARCH), lpc21) - ifndef RADIO_CONTROL_SPEKTRUM_MODEL - RADIO_CONTROL_SPEKTRUM_MODEL=\"subsystems/radio_control/spektrum_dx7se.h\" - endif - RC_CFLAGS += -DRADIO_CONTROL_SPEKTRUM_MODEL_H=$(RADIO_CONTROL_SPEKTRUM_MODEL) - endif - - - + - - - - - + + + + + + + + + + + + + + + + + + - + + + - - - - - - + + + + + + + + + + + + + + + + + - + + + + + + diff --git a/sw/airborne/arch/chibios/mcu_periph/sys_time_arch.c b/sw/airborne/arch/chibios/mcu_periph/sys_time_arch.c index f99391d5824..5b17afa9320 100644 --- a/sw/airborne/arch/chibios/mcu_periph/sys_time_arch.c +++ b/sw/airborne/arch/chibios/mcu_periph/sys_time_arch.c @@ -94,8 +94,15 @@ uint32_t get_sys_time_msec(void) */ void sys_time_usleep(uint32_t us) { - uint64_t wait_st = ((uint64_t)us * CH_CFG_ST_FREQUENCY) / 1000000UL; - chThdSleep((systime_t)wait_st); + if (us < 1000) { + // for small time, use the polled version instead of thread sleep + chSysDisable(); + chSysPolledDelayX(US2RTC(STM32_HCLK, us)); + chSysEnable(); + } else { + uint64_t wait_st = ((uint64_t)us * CH_CFG_ST_FREQUENCY) / 1000000UL; + chThdSleep((systime_t)wait_st); + } } void sys_time_msleep(uint16_t ms) diff --git a/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.c b/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.c deleted file mode 100644 index 5a49f7303cb..00000000000 --- a/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2008-2009 Antoine Drouin - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "subsystems/radio_control.h" -#include "subsystems/radio_control/spektrum_arch.h" - -bool rc_spk_parser_status; -uint8_t rc_spk_parser_idx; -uint8_t rc_spk_parser_buf[RADIO_CONTROL_NB_CHANNEL * 2]; -const int16_t rc_spk_throw[RADIO_CONTROL_NB_CHANNEL] = RC_SPK_THROWS; - -void radio_control_impl_init(void) -{ - rc_spk_parser_status = RC_SPK_STA_UNINIT; - rc_spk_parser_idx = 0; -} diff --git a/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.h b/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.h deleted file mode 100644 index f3f9c7cf85a..00000000000 --- a/sw/airborne/arch/lpc21/subsystems/radio_control/spektrum_arch.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2009-2010 The Paparazzi Team - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef RADIO_CONTROL_SPEKTRUM_ARCH_H -#define RADIO_CONTROL_SPEKTRUM_ARCH_H - -#include "std.h" -#include "mcu_periph/uart.h" - -#include RADIO_CONTROL_SPEKTRUM_MODEL_H - -#define RC_SPK_SYNC_1 0x03 - -#define RC_SPK_STA_UNINIT 0 -#define RC_SPK_STA_GOT_SYNC_1 1 -#define RC_SPK_STA_GOT_SYNC_2 2 - -extern bool rc_spk_parser_status; -extern uint8_t rc_spk_parser_idx; -extern uint8_t rc_spk_parser_buf[RADIO_CONTROL_NB_CHANNEL * 2]; - -#define MAX_SPK 344 - - -extern const int16_t rc_spk_throw[RADIO_CONTROL_NB_CHANNEL]; - -#define __RcLink(dev, _x) dev##_x -#define _RcLink(dev, _x) __RcLink(dev, _x) -#define RcLink(_x) _RcLink(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT, _x) - -#define RcLinkChAvailable() RcLink(ChAvailable()) -#define RcLinkGetCh() RcLink(Getch()) - -#define RadioControlEventImpl(_received_frame_handler) { \ - while (RcLinkChAvailable()) { \ - int8_t c = RcLinkGetCh(); \ - switch (rc_spk_parser_status) { \ - case RC_SPK_STA_UNINIT: \ - if (c==RC_SPK_SYNC_1) \ - rc_spk_parser_status = RC_SPK_STA_GOT_SYNC_1; \ - break; \ - case RC_SPK_STA_GOT_SYNC_1: \ - if (c==RC_SPK_SYNC_2) { \ - rc_spk_parser_status = RC_SPK_STA_GOT_SYNC_2; \ - rc_spk_parser_idx = 0; \ - } \ - else \ - rc_spk_parser_status = RC_SPK_STA_UNINIT; \ - break; \ - case RC_SPK_STA_GOT_SYNC_2: \ - rc_spk_parser_buf[rc_spk_parser_idx] = c; \ - rc_spk_parser_idx++; \ - if (rc_spk_parser_idx >= 2*RADIO_CONTROL_NB_CHANNEL) { \ - rc_spk_parser_status = RC_SPK_STA_UNINIT; \ - radio_control.frame_cpt++; \ - radio_control.time_since_last_frame = 0; \ - radio_control.status = RC_OK; \ - uint8_t i; \ - for (i=0;i> 10;*/ \ - const int16_t val = (tmp&0x03FF) - 512; \ - radio_control.values[i] = val; \ - radio_control.values[i] *= rc_spk_throw[i]; \ - if (i==RADIO_CONTROL_THROTTLE) { \ - radio_control.values[i] += MAX_PPRZ; \ - radio_control.values[i] /= 2; \ - } \ - } \ - _received_frame_handler(); \ - } \ - break; \ - default: \ - rc_spk_parser_status = RC_SPK_STA_UNINIT; \ - } \ - } \ - } - - -#endif /* RADIO_CONTROL_SPEKTRUM_ARCH_H */ diff --git a/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.c b/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.c index 3480ecd2b3e..182a7d0df86 100644 --- a/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.c +++ b/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.c @@ -27,7 +27,7 @@ */ #include "subsystems/radio_control.h" -#include "subsystems/radio_control/spektrum.h" +#include "subsystems/radio_control/spektrum_arch.h" #include "std.h" #include @@ -39,13 +39,11 @@ static bool spektrum_available; -void radio_control_spektrum_try_bind(void) {} - void radio_control_impl_init(void) { spektrum_available = false; } -void RadioControlEventImp(void (*frame_handler)(void)) +void spektrum_event(void (*frame_handler)(void)) { if (spektrum_available) { radio_control.frame_cpt++; @@ -56,6 +54,8 @@ void RadioControlEventImp(void (*frame_handler)(void)) spektrum_available = false; } +void spektrum_try_bind(void) {} + #if USE_NPS #ifdef RADIO_CONTROL void radio_control_feed(void) diff --git a/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.h b/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.h index 94239f7db97..ffdc9f964a1 100644 --- a/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.h +++ b/sw/airborne/arch/sim/subsystems/radio_control/spektrum_arch.h @@ -23,43 +23,11 @@ #ifndef RADIO_CONTROL_SPEKTRUM_ARCH_H #define RADIO_CONTROL_SPEKTRUM_ARCH_H +#include "subsystems/radio_control/spektrum_radio.h" -/* - * All Spektrum and JR 2.4 GHz transmitters - * have the same channel assignments. - */ - - -#ifndef RADIO_CONTROL_NB_CHANNEL -#define RADIO_CONTROL_NB_CHANNEL 12 -#endif - -#if RADIO_CONTROL_NB_CHANNEL > 12 -#error "RADIO_CONTROL_NB_CHANNEL mustn't be higher than 12." -#endif - -/* channel assignments */ -#define RADIO_THROTTLE 0 -#define RADIO_ROLL 1 -#define RADIO_PITCH 2 -#define RADIO_YAW 3 -#define RADIO_GEAR 4 -#define RADIO_FLAP 5 -#define RADIO_AUX1 5 -#define RADIO_AUX2 6 -#define RADIO_AUX3 7 -#define RADIO_AUX4 8 -#define RADIO_AUX5 9 -#define RADIO_AUX6 10 -#define RADIO_AUX7 11 - -/* really for a 9 channel transmitter - we would swap the order of these */ -#ifndef RADIO_MODE -#define RADIO_MODE RADIO_GEAR -#endif - -extern void RadioControlEventImp(void (*_received_frame_handler)(void)); +extern void spektrum_event(void (*_received_frame_handler)(void)); +#define RadioControlEventImp spektrum_event +extern void spektrum_try_bind(void); #if USE_NPS extern void radio_control_feed(void); diff --git a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c b/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c deleted file mode 100644 index f6d765d3464..00000000000 --- a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * Copyright (C) 2010 Eric Parsonage - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "subsystems/radio_control.h" -#include "subsystems/radio_control/spektrum_arch.h" -#include "mcu_periph/uart.h" -#include "mcu_periph/gpio.h" -#include "mcu_periph/sys_time.h" - -// for timer_get_frequency -#include "mcu_arch.h" - -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") - -// for Min macro -#include "std.h" - -#include BOARD_CONFIG - -#define SPEKTRUM_CHANNELS_PER_FRAME 7 -#define MAX_SPEKTRUM_FRAMES 2 -#define MAX_SPEKTRUM_CHANNELS 16 - -#define ONE_MHZ 1000000 - -/* Number of low pulses sent to satellite receivers */ -#if USE_DSMX -#define MASTER_RECEIVER_PULSES 9 -#define SLAVE_RECEIVER_PULSES 10 -#else -#define MASTER_RECEIVER_PULSES 5 -#define SLAVE_RECEIVER_PULSES 6 -#endif - -#define TIM_TICS_FOR_100us 100 -#define MIN_FRAME_SPACE 70 // 7ms -#define MAX_BYTE_SPACE 3 // .3ms - - -//not all f1's have a timer 6, so, some redefines have to happen -#define PASTER3(x,y,z) x ## y ## z -#define EVALUATOR3(x,y,z) PASTER3(x,y,z) -#define NVIC_TIMx_IRQ EVALUATOR3(NVIC_TIM, SPEKTRUM_TIMER,_IRQ) -#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 -#define TIMx_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_isr) -#define TIMx_DAC_ISR EVALUATOR3(tim, SPEKTRUM_TIMER,_dac_isr) - -#define PASTER2(x,y) x ## y -#define EVALUATOR2(x,y) PASTER2(x,y) -#define TIMx EVALUATOR2(TIM, SPEKTRUM_TIMER) -#define RCC_TIMx EVALUATOR2(RCC_TIM, SPEKTRUM_TIMER) - -#ifndef SPEKTRUM_TIMER -#define SPEKTRUM_TIMER 6 -#endif - -#if (SPEKTRUM_TIMER == 6) -#ifndef NVIC_TIM6_IRQ_PRIO -#define NVIC_TIM6_IRQ_PRIO 2 -#define NVIC_TIMx_IRQ_PRIO 2 -#else -#define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO -#endif -#ifndef NVIC_TIM6_DAC_IRQ_PRIO -#define NVIC_TIM6_DAC_IRQ_PRIO 2 -#define NVIC_TIMx_DAC_IRQ_PRIO 2 -#else -#define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO -#endif -#endif - -#if (SPEKTRUM_TIMER == 3) -#ifndef NVIC_TIM3_IRQ_PRIO -#define NVIC_TIM3_IRQ_PRIO 2 -#define NVIC_TIMx_IRQ_PRIO 2 -#else -#define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO -#endif -#ifndef NVIC_TIM3_DAC_IRQ_PRIO -#define NVIC_TIM3_DAC_IRQ_PRIO 2 -#define NVIC_TIMx_DAC_IRQ_PRIO 2 -#else -#define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO -#endif -#endif - -PRINT_CONFIG_MSG_VALUE("SPEKTRUM_TIMER: " , SPEKTRUM_TIMER) - -#ifdef NVIC_UART_IRQ_PRIO -#define NVIC_PRIMARY_UART_PRIO NVIC_UART_IRQ_PRIO -#else -#define NVIC_PRIMARY_UART_PRIO 2 -#endif - -/* - * in the makefile we set RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT to be UARTx - * but in uart_hw.c the initialisation functions are - * defined as uartx these macros give us the glue - * that allows static calls at compile time - */ - -#define __PrimaryUart(dev, _x) dev##_x -#define _PrimaryUart(dev, _x) __PrimaryUart(dev, _x) -#define PrimaryUart(_x) _PrimaryUart(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT, _x) - -#define __SecondaryUart(dev, _x) dev##_x -#define _SecondaryUart(dev, _x) __SecondaryUart(dev, _x) -#define SecondaryUart(_x) _SecondaryUart(RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT, _x) - -struct SpektrumStateStruct { - uint8_t ReSync; - uint8_t SpektrumTimer; - uint8_t Sync; - uint8_t ChannelCnt; - uint8_t FrameCnt; - uint8_t HighByte; - uint8_t SecondFrame; - uint16_t LostFrameCnt; - uint8_t RcAvailable; - int16_t values[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]; -}; - -typedef struct SpektrumStateStruct SpektrumStateType; - -SpektrumStateType PrimarySpektrumState = {1, 0, 0, 0, 0, 0, 0, 0, 0, {0}}; -PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT) - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT -PRINT_CONFIG_MSG("Using secondary spektrum receiver.") -PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT) -SpektrumStateType SecondarySpektrumState = {1, 0, 0, 0, 0, 0, 0, 0, 0, {0}}; -#else -PRINT_CONFIG_MSG("NOT using secondary spektrum receiver.") -#endif - -int16_t SpektrumBuf[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]; -/* the order of the channels on a spektrum is always as follows : - * - * Throttle 0 - * Aileron 1 - * Elevator 2 - * Rudder 3 - * Gear 4 - * Flap/Aux1 5 - * Aux2 6 - * Aux3 7 - * Aux4 8 - * Aux5 9 - * Aux6 10 - * Aux7 11 - */ - -/* reverse some channels to suit Paparazzi conventions */ -/* the maximum number of channels a Spektrum can transmit is 12 */ -int8_t SpektrumSigns[] = RADIO_CONTROL_SPEKTRUM_SIGNS; - -/* Parser state variables */ -static uint8_t EncodingType = 0; -static uint8_t ExpectedFrames = 0; - -/* initialise the timer used by the parser to ensure sync */ -void SpektrumTimerInit(void); - -/** Set polarity using RC_POLARITY_GPIO. - * SBUS signal has a reversed polarity compared to normal UART - * this allows to using hardware UART peripheral by changing - * the input signal polarity. - * Setting this gpio ouput high inverts the signal, - * output low sets it to normal polarity. - * So for spektrum this is set to normal polarity. - */ -#ifndef RC_SET_POLARITY -#define RC_SET_POLARITY gpio_clear -#endif - -/***************************************************************************** -* -* Initialise the timer an uarts used by the Spektrum receiver subsystem -* -*****************************************************************************/ -void radio_control_impl_init(void) -{ - - PrimarySpektrumState.ReSync = 1; - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - SecondarySpektrumState.ReSync = 1; -#endif - - // Set polarity to normal on boards that can change this -#ifdef RC_POLARITY_GPIO_PORT - gpio_setup_output(RC_POLARITY_GPIO_PORT, RC_POLARITY_GPIO_PIN); - RC_SET_POLARITY(RC_POLARITY_GPIO_PORT, RC_POLARITY_GPIO_PIN); -#endif - - SpektrumTimerInit(); - SpektrumUartInit(); -} - -/***************************************************************************** - * The bind function means that the satellite receivers believe they are - * connected to a 9 channel JR-R921 24 receiver thus during the bind process - * they try to get the transmitter to transmit at the highest resolution that - * it can manage. The data is contained in 16 byte packets transmitted at - * 115200 baud. Depending on the transmitter either 1 or 2 frames are required - * to contain the data for all channels. These frames are either 11ms or 22ms - * apart. - * - * The format of each frame for the main receiver is as follows - * - * byte1: frame loss data - * byte2: transmitter information - * byte3: and byte4: channel data - * byte5: and byte6: channel data - * byte7: and byte8: channel data - * byte9: and byte10: channel data - * byte11: and byte12: channel data - * byte13: and byte14: channel data - * byte15: and byte16: channel data - * - * - * The format of each frame for the secondary receiver is as follows - * - * byte1: frame loss data - * byte2: frame loss data - * byte3: and byte4: channel data - * byte5: and byte6: channel data - * byte7: and byte8: channel data - * byte9: and byte10: channel data - * byte11: and byte12: channel data - * byte13: and byte14: channel data - * byte15: and byte16: channel data - * - * The frame loss data bytes starts out containing 0 as long as the - * transmitter is switched on before the receivers. It then increments - * whenever frames are dropped. - * - * Three values for the transmitter information byte have been seen thus far - * - * 0x01 From a Spektrum DX7eu which transmits a single frame containing all - * channel data every 22ms with 10bit resolution. - * - * 0x02 From a Spektrum DM9 module which transmits two frames to carry the - * data for all channels 11ms apart with 10bit resolution. - * - * 0x12 From a Spektrum DX7se which transmits two frames to carry the - * data for all channels 11ms apart with 11bit resolution. - * - * 0x12 From a JR X9503 which transmits two frames to carry the - * data for all channels 11ms apart with 11bit resolution. - * - * 0x01 From a Spektrum DX7 which transmits a single frame containing all - * channel data every 22ms with 10bit resolution. - * - * 0x12 From a JR DSX12 which transmits two frames to carry the - * data for all channels 11ms apart with 11bit resolution. - * - * 0x1 From a Spektru DX5e which transmits a single frame containing all - * channel data every 22ms with 10bit resolution. - * - * 0x01 From a Spektrum DX6i which transmits a single frame containing all - * channel data every 22ms with 10bit resolution. - * - * Currently the assumption is that the data has the form : - * - * [0 0 0 R 0 0 N1 N0] - * - * where : - * - * 0 means a '0' bit - * R: 0 for 10 bit resolution 1 for 11 bit resolution channel data - * N1 to N0 is the number of frames required to receive all channel - * data. - * - * Channels can have either 10bit or 11bit resolution. Data from a tranmitter - * with 10 bit resolution has the form: - * - * [F 0 C3 C2 C1 C0 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0] - * - * Data from a tranmitter with 11 bit resolution has the form - * - * [F C3 C2 C1 C0 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0] - * - * where : - * - * 0 means a '0' bit - * F: Normally 0 but set to 1 for the first channel of the 2nd frame if a - * second frame is transmitted. - * - * C3 to C0 is the channel number, 4 bit, matching the numbers allocated in - * the transmitter. - * - * D9 to D0 is the channel data (10 bit) 0xaa..0x200..0x356 for - * 100% transmitter-travel - * - * - * D10 to D0 is the channel data (11 bit) 0x154..0x400..0x6AC for - * 100% transmitter-travel - *****************************************************************************/ - -/***************************************************************************** -* -* Spektrum Parser captures frame data by using time between frames to sync on -* -*****************************************************************************/ - -static inline void SpektrumParser(uint8_t _c, SpektrumStateType *spektrum_state, bool secondary_receiver) -{ - - - - uint16_t ChannelData; - uint8_t TimedOut; - static uint8_t TmpEncType = 0; /* 0 = 10bit, 1 = 11 bit */ - static uint8_t TmpExpFrames = 0; /* # of frames for channel data */ - - TimedOut = (!spektrum_state->SpektrumTimer) ? 1 : 0; - - /* If we have just started the resync process or */ - /* if we have recieved a character before our */ - /* 7ms wait has finished */ - if ((spektrum_state->ReSync == 1) || - ((spektrum_state->Sync == 0) && (!TimedOut))) { - - spektrum_state->ReSync = 0; - spektrum_state->SpektrumTimer = MIN_FRAME_SPACE; - spektrum_state->Sync = 0; - spektrum_state->ChannelCnt = 0; - spektrum_state->FrameCnt = 0; - spektrum_state->SecondFrame = 0; - return; - } -//LED_OFF(1); - - /* the first byte of a new frame. It was received */ - /* more than 7ms after the last received byte. */ - /* It represents the number of lost frames so far.*/ - if (spektrum_state->Sync == 0) { - spektrum_state->LostFrameCnt = _c; - if (secondary_receiver) { /* secondary receiver */ - spektrum_state->LostFrameCnt = spektrum_state->LostFrameCnt << 8; - } - spektrum_state->Sync = 1; - spektrum_state->SpektrumTimer = MAX_BYTE_SPACE; - return; - } - - /* all other bytes should be recieved within */ - /* MAX_BYTE_SPACE time of the last byte received */ - /* otherwise something went wrong resynchronise */ - if (TimedOut) { - spektrum_state->ReSync = 1; - /* next frame not expected sooner than 7ms */ - spektrum_state->SpektrumTimer = MIN_FRAME_SPACE; - return; - } - - /* second character determines resolution and frame rate for main */ - /* receiver or low byte of LostFrameCount for secondary receiver */ - if (spektrum_state->Sync == 1) { - if (secondary_receiver) { - spektrum_state->LostFrameCnt += _c; - TmpExpFrames = ExpectedFrames; - } else { - /** @todo collect more data. I suspect that there is a low res */ - /* protocol that is still 10 bit but without using the full range. */ - TmpEncType = (_c & 0x10) >> 4; /* 0 = 10bit, 1 = 11 bit */ - TmpExpFrames = _c & 0x03; /* 1 = 1 frame contains all channels */ - /* 2 = 2 channel data in 2 frames */ - } - spektrum_state->Sync = 2; - spektrum_state->SpektrumTimer = MAX_BYTE_SPACE; - return; - } - - /* high byte of channel data if this is the first byte */ - /* of channel data and the most significant bit is set */ - /* then this is the second frame of channel data. */ - if (spektrum_state->Sync == 2) { - spektrum_state->HighByte = _c; - if (spektrum_state->ChannelCnt == 0) { - spektrum_state->SecondFrame = (spektrum_state->HighByte & 0x80) ? 1 : 0; - } - spektrum_state->Sync = 3; - spektrum_state->SpektrumTimer = MAX_BYTE_SPACE; - return; - } - - /* low byte of channel data */ - if (spektrum_state->Sync == 3) { - spektrum_state->Sync = 2; - spektrum_state->SpektrumTimer = MAX_BYTE_SPACE; - /* we overwrite the buffer now so rc data is not available now */ - spektrum_state->RcAvailable = 0; - ChannelData = ((uint16_t)spektrum_state->HighByte << 8) | _c; - spektrum_state->values[spektrum_state->ChannelCnt - + (spektrum_state->SecondFrame * 7)] = ChannelData; - spektrum_state->ChannelCnt ++; - } - - /* If we have a whole frame */ - if (spektrum_state->ChannelCnt >= SPEKTRUM_CHANNELS_PER_FRAME) { - /* how many frames did we expect ? */ - ++spektrum_state->FrameCnt; - if (spektrum_state->FrameCnt == TmpExpFrames) { - /* set the rc_available_flag */ - spektrum_state->RcAvailable = 1; - spektrum_state->FrameCnt = 0; - } - if (!secondary_receiver) { /* main receiver */ - EncodingType = TmpEncType; /* only update on a good */ - ExpectedFrames = TmpExpFrames; /* main receiver frame */ - } - spektrum_state->Sync = 0; - spektrum_state->ChannelCnt = 0; - spektrum_state->SecondFrame = 0; - spektrum_state->SpektrumTimer = MIN_FRAME_SPACE; - } -} - -/***************************************************************************** - * - * RadioControlEventImp decodes channel data stored by uart irq handlers - * and calls callback funtion - * - *****************************************************************************/ - -void RadioControlEventImp(void (*frame_handler)(void)) -{ - uint8_t ChannelCnt; - uint8_t ChannelNum; - uint16_t ChannelData; - uint8_t MaxChannelNum = 0; - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - /* If we have two receivers and at least one of them has new data */ - uint8_t BestReceiver; - if ((PrimarySpektrumState.RcAvailable) || - (SecondarySpektrumState.RcAvailable)) { - /* if both receivers have new data select the one */ - /* that has had the least number of frames lost */ - if ((PrimarySpektrumState.RcAvailable) && - (SecondarySpektrumState.RcAvailable)) { - BestReceiver = (PrimarySpektrumState.LostFrameCnt - <= SecondarySpektrumState.LostFrameCnt) ? 0 : 1; - } else { - /* if only one of the receivers have new data use it */ - BestReceiver = (PrimarySpektrumState.RcAvailable) ? 0 : 1; - } - /* clear the data ready flags */ - PrimarySpektrumState.RcAvailable = 0; - SecondarySpektrumState.RcAvailable = 0; - -#else - /* if we have one receiver and it has new data */ - if (PrimarySpektrumState.RcAvailable) { - PrimarySpektrumState.RcAvailable = 0; -#endif - ChannelCnt = 0; - /* for every piece of channel data we have received */ - for (int i = 0; (i < SPEKTRUM_CHANNELS_PER_FRAME * ExpectedFrames); i++) { -#ifndef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - ChannelData = PrimarySpektrumState.values[i]; -#else - ChannelData = (!BestReceiver) ? PrimarySpektrumState.values[i] : - SecondarySpektrumState.values[i]; -#endif - /* find out the channel number and its value by */ - /* using the EncodingType which is only received */ - /* from the main receiver */ - switch (EncodingType) { - case (0) : /* 10 bit */ - ChannelNum = (ChannelData >> 10) & 0x0f; - /* don't bother decoding unused channels */ - if (ChannelNum < SPEKTRUM_NB_CHANNEL) { - SpektrumBuf[ChannelNum] = ChannelData & 0x3ff; - SpektrumBuf[ChannelNum] -= 0x200; - SpektrumBuf[ChannelNum] *= MAX_PPRZ / 0x156; - ChannelCnt++; - } - break; - - case (1) : /* 11 bit */ - ChannelNum = (ChannelData >> 11) & 0x0f; - /* don't bother decoding unused channels */ - if (ChannelNum < SPEKTRUM_NB_CHANNEL) { - SpektrumBuf[ChannelNum] = ChannelData & 0x7ff; - SpektrumBuf[ChannelNum] -= 0x400; - SpektrumBuf[ChannelNum] *= MAX_PPRZ / 0x2AC; - ChannelCnt++; - } - break; - - default : ChannelNum = 0x0F; break; /* never going to get here */ - } - /* store the value of the highest valid channel */ - if ((ChannelNum != 0x0F) && (ChannelNum > MaxChannelNum)) { - MaxChannelNum = ChannelNum; - } - - } - - /* if we have a valid frame the pass it to the frame handler */ - if (ChannelCnt >= (MaxChannelNum + 1)) { - radio_control.frame_cpt++; - radio_control.time_since_last_frame = 0; - radio_control.status = RC_OK; - /* since it is possible for the user use less than the actually available channels, - * we only transfer only Min(RADIO_CONTROL_NB_CHANNEL, available_channels) - */ - for (int i = 0; i < Min(RADIO_CONTROL_NB_CHANNEL, (MaxChannelNum + 1)); i++) { - radio_control.values[i] = SpektrumBuf[i]; - //Only values between +-MAX_PPRZ are allowed - Bound(radio_control.values[i], -MAX_PPRZ, MAX_PPRZ); - if (i == RADIO_THROTTLE) { - radio_control.values[i] += MAX_PPRZ; - radio_control.values[i] /= 2; - } - radio_control.values[i] *= SpektrumSigns[i]; - } - (*frame_handler)(); - } - } -} - - -/***************************************************************************** - * - * Initialise TIMx to fire an interrupt every 100 microseconds to provide - * timebase for SpektrumParser - * - *****************************************************************************/ -void SpektrumTimerInit(void) -{ - - /* enable TIMx clock */ - rcc_periph_clock_enable(RCC_TIMx); - - timer_reset(TIMx); - /* TIMx configuration, always counts up */ - timer_set_mode(TIMx, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // used to be 0 0 - /* 100 microseconds ie 0.1 millisecond */ - timer_set_period(TIMx, TIM_TICS_FOR_100us - 1); - uint32_t TIMx_clk = timer_get_frequency(TIMx); - /* timer ticks with 1us */ - timer_set_prescaler(TIMx, ((TIMx_clk / ONE_MHZ) - 1)); - - /* Enable TIMx interrupts */ -#ifdef STM32F1 - nvic_set_priority(NVIC_TIMx_IRQ, NVIC_TIMx_IRQ_PRIO); - nvic_enable_irq(NVIC_TIMx_IRQ); -#elif defined STM32F4 - /* the define says DAC IRQ, but it is also the global TIMx IRQ*/ - nvic_set_priority(NVIC_TIMx_DAC_IRQ, NVIC_TIMx_DAC_IRQ_PRIO); - nvic_enable_irq(NVIC_TIMx_DAC_IRQ); -#endif - - /* Enable TIMx Update interrupt */ - timer_enable_irq(TIMx, TIM_DIER_UIE); - timer_clear_flag(TIMx, TIM_SR_UIF); - - /* TIMx enable counter */ - timer_enable_counter(TIMx); -} - -/***************************************************************************** - * - * TIMx interrupt request handler updates times used by SpektrumParser - * - *****************************************************************************/ -#ifdef STM32F1 -void TIMx_ISR(void) -{ -#elif defined STM32F4 -void TIMx_DAC_ISR(void) { -#endif - - timer_clear_flag(TIMx, TIM_SR_UIF); - - if (PrimarySpektrumState.SpektrumTimer) { - --PrimarySpektrumState.SpektrumTimer; - } -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - if (SecondarySpektrumState.SpektrumTimer) { - --SecondarySpektrumState.SpektrumTimer; - } -#endif -} - -/***************************************************************************** - * - * Initialise the uarts for the spektrum satellite receivers - * - *****************************************************************************/ -void SpektrumUartInit(void) { - /* init RCC */ - gpio_enable_clock(PrimaryUart(_BANK)); - rcc_periph_clock_enable(PrimaryUart(_RCC)); - - /* Enable USART interrupts */ - nvic_set_priority(PrimaryUart(_IRQ), NVIC_PRIMARY_UART_PRIO); - nvic_enable_irq(PrimaryUart(_IRQ)); - - /* Init GPIOS */ - /* Primary UART Rx pin as floating input */ - gpio_setup_pin_af(PrimaryUart(_BANK), PrimaryUart(_PIN), PrimaryUart(_AF), FALSE); - - /* Configure Primary UART */ - usart_set_baudrate(PrimaryUart(_DEV), B115200); - usart_set_databits(PrimaryUart(_DEV), 8); - usart_set_stopbits(PrimaryUart(_DEV), USART_STOPBITS_1); - usart_set_parity(PrimaryUart(_DEV), USART_PARITY_NONE); - usart_set_flow_control(PrimaryUart(_DEV), USART_FLOWCONTROL_NONE); - usart_set_mode(PrimaryUart(_DEV), USART_MODE_RX); - - /* Enable Primary UART Receive interrupts */ - USART_CR1(PrimaryUart(_DEV)) |= USART_CR1_RXNEIE; - - /* Enable the Primary UART */ - usart_enable(PrimaryUart(_DEV)); - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - /* init RCC */ - gpio_enable_clock(SecondaryUart(_BANK)); - rcc_periph_clock_enable(SecondaryUart(_RCC)); - - /* Enable USART interrupts */ - nvic_set_priority(SecondaryUart(_IRQ), NVIC_PRIMARY_UART_PRIO + 1); - nvic_enable_irq(SecondaryUart(_IRQ)); - - /* Init GPIOS */; - /* Secondary UART Rx pin as floating input */ - gpio_setup_pin_af(SecondaryUart(_BANK), SecondaryUart(_PIN), SecondaryUart(_AF), FALSE); - - /* Configure secondary UART */ - usart_set_baudrate(SecondaryUart(_DEV), B115200); - usart_set_databits(SecondaryUart(_DEV), 8); - usart_set_stopbits(SecondaryUart(_DEV), USART_STOPBITS_1); - usart_set_parity(SecondaryUart(_DEV), USART_PARITY_NONE); - usart_set_flow_control(SecondaryUart(_DEV), USART_FLOWCONTROL_NONE); - usart_set_mode(SecondaryUart(_DEV), USART_MODE_RX); - - /* Enable Secondary UART Receive interrupts */ - USART_CR1(SecondaryUart(_DEV)) |= USART_CR1_RXNEIE; - - /* Enable the Primary UART */ - usart_enable(SecondaryUart(_DEV)); -#endif - -} - -/***************************************************************************** - * - * The primary receiver UART interrupt request handler which passes the - * received character to Spektrum Parser. - * - *****************************************************************************/ -void PrimaryUart(_ISR)(void) { - - if (((USART_CR1(PrimaryUart(_DEV)) & USART_CR1_TXEIE) != 0) && - ((USART_SR(PrimaryUart(_DEV)) & USART_SR_TXE) != 0)) { - USART_CR1(PrimaryUart(_DEV)) &= ~USART_CR1_TXEIE; - } - - if (((USART_CR1(PrimaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) && - ((USART_SR(PrimaryUart(_DEV)) & USART_SR_RXNE) != 0)) { - uint8_t b = usart_recv(PrimaryUart(_DEV)); - SpektrumParser(b, &PrimarySpektrumState, FALSE); - } - -} - -/***************************************************************************** - * - * The secondary receiver UART interrupt request handler which passes the - * received character to Spektrum Parser. - * - *****************************************************************************/ -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT -void SecondaryUart(_ISR)(void) { - - if (((USART_CR1(SecondaryUart(_DEV)) & USART_CR1_TXEIE) != 0) && - ((USART_SR(SecondaryUart(_DEV)) & USART_SR_TXE) != 0)) { - USART_CR1(SecondaryUart(_DEV)) &= ~USART_CR1_TXEIE; - } - - if (((USART_CR1(SecondaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) && - ((USART_SR(SecondaryUart(_DEV)) & USART_SR_RXNE) != 0)) { - uint8_t b = usart_recv(SecondaryUart(_DEV)); - SpektrumParser(b, &SecondarySpektrumState, TRUE); - } - -} -#endif - - -/***************************************************************************** - * - * The following functions provide functionality to allow binding of - * spektrum satellite receivers. The pulse train sent to them means - * that AP is emulating a 9 channel JR-R921 24. - * By default, the same pin is used for pulse train and uart rx, but - * they can be different if needed - * - *****************************************************************************/ -#ifndef SPEKTRUM_PRIMARY_BIND_CONF_PORT -#define SPEKTRUM_PRIMARY_BIND_CONF_PORT PrimaryUart(_BANK) -#endif -#ifndef SPEKTRUM_PRIMARY_BIND_CONF_PIN -#define SPEKTRUM_PRIMARY_BIND_CONF_PIN PrimaryUart(_PIN) -#endif -#ifndef SPEKTRUM_SECONDARY_BIND_CONF_PORT -#define SPEKTRUM_SECONDARY_BIND_CONF_PORT SecondaryUart(_BANK) -#endif -#ifndef SPEKTRUM_SECONDARY_BIND_CONF_PIN -#define SPEKTRUM_SECONDARY_BIND_CONF_PIN SecondaryUart(_PIN) -#endif - -/***************************************************************************** - * - * radio_control_spektrum_try_bind(void) must called on powerup as spektrum - * satellites can only bind immediately after power up also it must be called - * before the call to SpektrumUartInit as we leave them with their Rx pins set - * as outputs. - * - *****************************************************************************/ -void radio_control_spektrum_try_bind(void) { -#ifdef SPEKTRUM_BIND_PIN_PORT -#ifdef SPEKTRUM_BIND_PIN_HIGH - /* Init GPIO for the bind pin, we enable the pulldown resistor. - * (esden) As far as I can tell only navstick is using the PIN LOW version of - * the bind pin, but I assume this should not harm anything. If I am mistaken - * than I appologise for the inconvenience. :) - */ - gpio_setup_input_pulldown(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN); - - sys_time_usleep(10); // wait for electrical level to stabilize - - /* exit if the BIND_PIN is low, it needs to - be pulled high at startup to initiate bind */ - if (gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) == 0) { - return; - } -#else - /* Init GPIO for the bind pin, we enable the pullup resistor in case we have - * a floating pin that does not have a hardware pullup resistor as it is the - * case with Lisa/M and Lisa/MX prior to version 2.1. - */ - gpio_setup_input_pullup(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN); - - sys_time_usleep(10); // wait for electrical level to stabilize - - /* exit if the BIND_PIN is high, it needs to - be pulled low at startup to initiate bind */ - if (gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) != 0) { - return; - } -#endif -#endif - - /* Master receiver Rx push-pull */ - gpio_setup_output(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); - - /* Master receiver RX line, drive high */ - gpio_set(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - /* Slave receiver Rx push-pull */ - gpio_setup_output(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); - - /* Slave receiver RX line, drive high */ - gpio_set(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); -#endif - - /* We have no idea how long the window for allowing binding after - power up is. This works for the moment but will need revisiting */ - sys_time_usleep(61000); - - for (int i = 0; i < MASTER_RECEIVER_PULSES ; i++) { - gpio_clear(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); - sys_time_usleep(118); - gpio_set(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); - sys_time_usleep(122); - } - -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - for (int i = 0; i < SLAVE_RECEIVER_PULSES; i++) { - gpio_clear(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); - sys_time_usleep(120); - gpio_set(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); - sys_time_usleep(120); - } -#endif /* RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT */ - - /* Set conf pin as input in case it is different from RX pin */ - gpio_setup_input(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); -#ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT - gpio_setup_input(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); -#endif -} diff --git a/sw/airborne/boards/apogee/chibios/v1.0/board.h b/sw/airborne/boards/apogee/chibios/v1.0/board.h index 5814edd991b..dd0704e5b9d 100644 --- a/sw/airborne/boards/apogee/chibios/v1.0/board.h +++ b/sw/airborne/boards/apogee/chibios/v1.0/board.h @@ -917,6 +917,28 @@ #define PPM_CHANNEL ICU_CHANNEL_1 #define PPM_TIMER ICUD1 +/* + * Spektrum + */ + +// shorter wait with chibios as the RTC oscillator takes longer to stabilize +#define SPEKTRUM_BIND_WAIT 30000 + +/* The line that is pulled low at power up to initiate the bind process + * PB15: AUX4 + */ +#define SPEKTRUM_BIND_PIN GPIO15 +#define SPEKTRUM_BIND_PIN_PORT GPIOB + +/* The line used to send the pulse train for the bind process + * When using UART2 on Apogee, this as to be a different pin than the uart2 rx + * Default pin for this is PA8: PPM_IN + */ +#ifndef SPEKTRUM_PRIMARY_BIND_CONF_PORT +#define SPEKTRUM_PRIMARY_BIND_CONF_PORT GPIOA +#define SPEKTRUM_PRIMARY_BIND_CONF_PIN GPIO8 +#endif + /* * PWM input */ diff --git a/sw/airborne/boards/apogee_1.0.h b/sw/airborne/boards/apogee_1.0.h index c7cb9430396..6accca0f56f 100644 --- a/sw/airborne/boards/apogee_1.0.h +++ b/sw/airborne/boards/apogee_1.0.h @@ -426,24 +426,6 @@ #define SPEKTRUM_PRIMARY_BIND_CONF_PIN GPIO8 #endif -/* Configuration of UART2 for Spektrum */ -#define SPEKTRUM_UART2_RCC RCC_USART2 -#define SPEKTRUM_UART2_BANK GPIOA -#define SPEKTRUM_UART2_PIN GPIO3 -#define SPEKTRUM_UART2_AF GPIO_AF7 -#define SPEKTRUM_UART2_IRQ NVIC_USART2_IRQ -#define SPEKTRUM_UART2_ISR usart2_isr -#define SPEKTRUM_UART2_DEV USART2 - -/* Configuration of UART6 for Spektrum */ -#define SPEKTRUM_UART6_RCC RCC_USART6 -#define SPEKTRUM_UART6_BANK GPIOC -#define SPEKTRUM_UART6_PIN GPIO7 -#define SPEKTRUM_UART6_AF GPIO_AF8 -#define SPEKTRUM_UART6_IRQ NVIC_USART6_IRQ -#define SPEKTRUM_UART6_ISR usart6_isr -#define SPEKTRUM_UART6_DEV USART6 - /* * IRQ Priorities */ diff --git a/sw/airborne/boards/chimera/chibios/v1.0/chimera.h b/sw/airborne/boards/chimera/chibios/v1.0/chimera.h index 1955657a0bf..d9126fec7c3 100644 --- a/sw/airborne/boards/chimera/chibios/v1.0/chimera.h +++ b/sw/airborne/boards/chimera/chibios/v1.0/chimera.h @@ -384,14 +384,37 @@ /** * UART3 (XBee slot), UART8 (GPS) and UART1 (Companion) - * are configured as UART from ChibiOS board file + * are configured as UART from ChibiOS board file by default */ +#define UART1_GPIO_PORT_TX GPIOB +#define UART1_GPIO_TX GPIO6 +#define UART1_GPIO_PORT_RX GPIOB +#define UART1_GPIO_RX GPIO7 +#define UART1_GPIO_AF 7 + +#define UART3_GPIO_PORT_TX GPIOD +#define UART3_GPIO_TX GPIO8 +#define UART3_GPIO_PORT_RX GPIOD +#define UART3_GPIO_RX GPIO9 +#define UART3_GPIO_AF 7 + +#define UART8_GPIO_PORT_TX GPIOE +#define UART8_GPIO_TX GPIO0 +#define UART8_GPIO_PORT_RX GPIOE +#define UART8_GPIO_RX GPIO1 +#define UART8_GPIO_AF 8 + /** - * SBUS + * SBUS / Spektrum port + * + * Recommended config: * * primary SBUS port is UART7, a.k.a. RC2 on Chimera board * secondary port (in dual driver) is UART4, a.k.a. RC1 on Chimera board + * + * primary Spektrum port is UART4, a.k.a. RC1 on Chimera board + * secondary port is UART7, a.k.a. RC2 on Chimera board */ // In case, do dynamic config of UARTs @@ -405,31 +428,18 @@ #define USE_UART4_RX TRUE #define USE_UART4_TX FALSE -#define UART4_GPIO_PORT_RX GPIOE -#define UART4_GPIO_RX GPIO7 +#define UART4_GPIO_PORT_RX GPIOA +#define UART4_GPIO_RX GPIO1 #define UART4_GPIO_AF 8 -/* - * Spektrum - * - * Not supported yet in chibios arch - * Only here for future reference - * - * primary Spektrum port is UART4, a.k.a. RC1 on Chimera board - * secondary port is UART7, a.k.a. RC2 on Chimera board +/* The line that is pulled low at power up to initiate the bind process + * PC7: AUX7 */ -/* The line that is pulled low at power up to initiate the bind process */ -/* These are not common between versions of lisa/mx and thus defined in the - * version specific header files. */ -#define SPEKTRUM_UART4_BANK UART4_GPIO_PORT_RX -#define SPEKTRUM_UART4_PIN UART4_GPIO_RX -#define SPEKTRUM_UART4_AF UART4_GPIO_AF -#define SPEKTRUM_UART4_DEV SD4 - -#define SPEKTRUM_UART7_BANK UART7_GPIO_PORT_RX -#define SPEKTRUM_UART7_PIN UART7_GPIO_RX -#define SPEKTRUM_UART7_AF UART7_GPIO_AF -#define SPEKTRUM_UART7_DEV SD7 +#define SPEKTRUM_BIND_PIN GPIO7 +#define SPEKTRUM_BIND_PIN_PORT GPIOC + +// no wait with chibios as the RTC oscillator takes longer to stabilize +#define SPEKTRUM_BIND_WAIT 30000 /** * PPM radio defines diff --git a/sw/airborne/boards/chimera/chibios/v1.0/mcuconf.h b/sw/airborne/boards/chimera/chibios/v1.0/mcuconf.h index ff559672163..26f0c1275a2 100644 --- a/sw/airborne/boards/chimera/chibios/v1.0/mcuconf.h +++ b/sw/airborne/boards/chimera/chibios/v1.0/mcuconf.h @@ -43,7 +43,11 @@ #define STM32_HSI_ENABLED TRUE #define STM32_LSI_ENABLED FALSE #define STM32_HSE_ENABLED TRUE +#if HAL_USE_RTC // disable LSE init if not needed to start faster #define STM32_LSE_ENABLED TRUE +#else +#define STM32_LSE_ENABLED FALSE +#endif #define STM32_CLOCK48_REQUIRED TRUE #define STM32_SW STM32_SW_PLL #define STM32_PLLSRC STM32_PLLSRC_HSE @@ -54,7 +58,11 @@ #define STM32_HPRE STM32_HPRE_DIV1 #define STM32_PPRE1 STM32_PPRE1_DIV4 #define STM32_PPRE2 STM32_PPRE2_DIV2 +#if HAL_USE_RTC #define STM32_RTCSEL STM32_RTCSEL_LSE +#else +#define STM32_RTCSEL STM32_RTCSEL_NOCLOCK +#endif #define STM32_RTCPRE_VALUE 25 #define STM32_MCO1SEL STM32_MCO1SEL_HSE #define STM32_MCO1PRE STM32_MCO1PRE_DIV1 diff --git a/sw/airborne/boards/elle0_common.h b/sw/airborne/boards/elle0_common.h index bce675fe0c9..4fe13f50b24 100644 --- a/sw/airborne/boards/elle0_common.h +++ b/sw/airborne/boards/elle0_common.h @@ -121,30 +121,6 @@ #define SPEKTRUM_BIND_PIN GPIO0 #define SPEKTRUM_BIND_PIN_PORT GPIOB -#define SPEKTRUM_UART1_RCC RCC_USART1 -#define SPEKTRUM_UART1_BANK GPIOA -#define SPEKTRUM_UART1_PIN GPIO10 -#define SPEKTRUM_UART1_AF GPIO_AF7 -#define SPEKTRUM_UART1_IRQ NVIC_USART1_IRQ -#define SPEKTRUM_UART1_ISR usart1_isr -#define SPEKTRUM_UART1_DEV USART1 - -#define SPEKTRUM_UART2_RCC RCC_USART2 -#define SPEKTRUM_UART2_BANK GPIOA -#define SPEKTRUM_UART2_PIN GPIO3 -#define SPEKTRUM_UART2_AF GPIO_AF7 -#define SPEKTRUM_UART2_IRQ NVIC_USART2_IRQ -#define SPEKTRUM_UART2_ISR usart2_isr -#define SPEKTRUM_UART2_DEV USART2 - -#define SPEKTRUM_UART5_RCC RCC_UART5 -#define SPEKTRUM_UART5_BANK GPIOD -#define SPEKTRUM_UART5_PIN GPIO2 -#define SPEKTRUM_UART5_AF GPIO_AF8 -#define SPEKTRUM_UART5_IRQ NVIC_UART5_IRQ -#define SPEKTRUM_UART5_ISR uart5_isr -#define SPEKTRUM_UART5_DEV UART5 - /* PPM * * Default is PPM config 2, input on GPIOA1 (Servo pin 6) diff --git a/sw/airborne/mcu.c b/sw/airborne/mcu.c index 664f0077241..603586cb1ae 100644 --- a/sw/airborne/mcu.c +++ b/sw/airborne/mcu.c @@ -34,7 +34,7 @@ #include "led.h" #endif #if defined RADIO_CONTROL -#if defined RADIO_CONTROL_LINK || defined RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT +#if defined RADIO_CONTROL_BIND_IMPL_FUNC & defined SPEKTRUM_BIND_PIN_PORT #include "subsystems/radio_control.h" #endif #endif @@ -124,7 +124,7 @@ void mcu_init(void) PERIPHERAL3V3_ENABLE_ON(PERIPHERAL3V3_ENABLE_PORT, PERIPHERAL3V3_ENABLE_PIN); #endif /* for now this means using spektrum */ -#if defined RADIO_CONTROL & defined RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT & defined RADIO_CONTROL_BIND_IMPL_FUNC & defined SPEKTRUM_BIND_PIN_PORT +#if defined RADIO_CONTROL & defined RADIO_CONTROL_BIND_IMPL_FUNC & defined SPEKTRUM_BIND_PIN_PORT RADIO_CONTROL_BIND_IMPL_FUNC(); #endif #if USE_UART0 diff --git a/sw/airborne/subsystems/radio_control/joby_9ch.h b/sw/airborne/subsystems/radio_control/joby_9ch.h deleted file mode 100644 index c9bdef26a9b..00000000000 --- a/sw/airborne/subsystems/radio_control/joby_9ch.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2008-2009 Antoine Drouin - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef RADIO_CONTROL_JOBY_9CH_H -#define RADIO_CONTROL_JOBY_9CH_H - -#define RADIO_CONTROL_NB_CHANNEL 9 - -#define RADIO_THROTTLE 0 -#define RADIO_YAW 1 -#define RADIO_PITCH 2 -#define RADIO_ROLL 3 -#define RADIO_GEAR 4 -#define RADIO_MODE 5 -#define RADIO_AUX2 6 -#define RADIO_AUX3 7 -#define RADIO_KILL 8 - -#define RC_JOBY_SYNC_2 0x12 - -#define RC_JOBY_SIGNS { 1, \ - 1, \ - 1, \ - 1, \ - 1, \ - 1, \ - 1, \ - 1, \ - 1 } - -#endif /* RADIO_CONTROL_JOBY_9CH_H */ diff --git a/sw/airborne/subsystems/radio_control/spektrum.c b/sw/airborne/subsystems/radio_control/spektrum.c index f606c2f9361..4db6df00fd5 100644 --- a/sw/airborne/subsystems/radio_control/spektrum.c +++ b/sw/airborne/subsystems/radio_control/spektrum.c @@ -1,5 +1,8 @@ /* * Copyright (C) 2008-2009 Antoine Drouin + * 2010 Eric Parsonage + * 2015 Freek van Tienen + * 2018 Gautier Hattenberger * * This file is part of paparazzi. * @@ -14,16 +17,363 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with paparazzi; see the file COPYING. If not, see + * . */ -#include "spektrum.h" +#include "subsystems/radio_control/spektrum.h" -/* Currently the functionality has been pushed into the arch directories - * both arch directories contain essentially the original parser. - * The next step is to implement a new parser for lisa. Once this is complete - * hardware dependent functions will be written for booz then the lisa parser - * will end up in here +/** + * @file subsystems/radio_control/spektrum.c + * + * Spektrum sattelite receiver implementation. For the protocol specification see: + * http://www.spektrumrc.com/ProdInfo/Files/Remote%20Receiver%20Interfacing%20Rev%20A.pdf + */ + +#include "std.h" +#include "subsystems/radio_control.h" +#include "mcu_periph/uart.h" +#include "mcu_periph/gpio.h" +#include "mcu_periph/sys_time.h" + +/* Check if primary receiver is defined */ +#ifndef SPEKTRUM_PRIMARY_UART +#error "You must at least define the primary Spektrum satellite receiver." +#endif + +/* Changed radio control order Notice */ +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") + +/* Number of low pulses sent during binding to the satellite receivers + * As recommended, master and slave receivers are in DSMX 11ms mode, + * other modes (DSM2, 22ms) will be automatically supported + */ +#define SPEKTRUM_MASTER_RECEIVER_PULSES 9 // only one receiver should be in master mode +#define SPEKTRUM_SLAVE_RECEIVER_PULSES 10 + +/* Set polarity using RC_POLARITY_GPIO. */ +#ifndef RC_SET_POLARITY +#define RC_SET_POLARITY gpio_clear +#endif + +/* Busy wait to let the receiver starts properly + * This should be reduced when the MCU takes longer to start + */ +#ifndef SPEKTRUM_BIND_WAIT +#define SPEKTRUM_BIND_WAIT 60000 +#endif + +// in case the number of channel is less than maximum +const int8_t spektrum_signs[] = RADIO_CONTROL_SPEKTRUM_SIGNS; + +/* Default spektrum values */ +static struct spektrum_t spektrum = { + .valid = false, + .tx_type = 0, // unknown type +}; + +/** Allowed system field valaues. + * from datasheet, possible values for the frame format + * encoded in the system field of the internal remote + * frame (second byte). + * Only the first one is encoding values on 10bits, + * other ones on 11bits. + */ +#define SPEKTRUM_SYS_22_1024_2 0x01 // 22ms 1024 DSM2 +#define SPEKTRUM_SYS_11_2048_2 0x12 // 11ms 2048 DSM2 +#define SPEKTRUM_SYS_22_2048_X 0xa2 // 22ms 2048 DSMX +#define SPEKTRUM_SYS_11_2048_X 0xb2 // 11ms 2048 DSMX + +static void spektrum_bind(void); + +/** Initialize a spektrum sattelite */ +static inline void spektrum_init_sat(struct spektrum_sat_t *sat) +{ + sat->valid = false; + sat->timer = get_sys_time_msec(); + sat->idx = 0; + + // Initialize values + for (uint8_t i = 0; i < SPEKTRUM_MAX_CHANNELS; i++) { + sat->values[i] = 0; + } +} + +/***************************************************************************** + * + * spektrum_try_bind(void) must called on powerup as spektrum + * satellites can only bind immediately after power up also it must be called + * before the call to SpektrumUartInit as we leave them with their Rx pins set + * as outputs. + * + *****************************************************************************/ +void spektrum_try_bind(void) +{ +#ifdef SPEKTRUM_BIND_PIN_PORT +#ifdef SPEKTRUM_BIND_PIN_HIGH + /* Init GPIO for the bind pin, we enable the pulldown resistor. + * (esden) As far as I can tell only navstick is using the PIN LOW version of + * the bind pin, but I assume this should not harm anything. If I am mistaken + * than I appologise for the inconvenience. :) + */ + gpio_setup_input_pulldown(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN); + + sys_time_usleep(10); // wait for electrical level to stabilize + + /* Exit if the BIND_PIN is low, it needs to + be pulled high at startup to initiate bind */ + if (gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) != 0) { + spektrum_bind(); + } +#else + /* Init GPIO for the bind pin, we enable the pullup resistor in case we have + * a floating pin that does not have a hardware pullup resistor as it is the + * case with Lisa/M and Lisa/MX prior to version 2.1. + */ + gpio_setup_input_pullup(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN); + + sys_time_usleep(10); // wait for electrical level to stabilize + + /* Exit if the BIND_PIN is high, it needs to + be pulled low at startup to initiate bind */ + if (gpio_get(SPEKTRUM_BIND_PIN_PORT, SPEKTRUM_BIND_PIN) == 0) { + spektrum_bind(); + } +#endif +#endif +} + + +/** Main Radio initialization */ +void radio_control_impl_init(void) +{ + + for (uint8_t i = 0; i < RADIO_CONTROL_NB_CHANNEL; i++) { + spektrum.signs[i] = spektrum_signs[i]; + } + + // Set polarity to normal on boards that can change this +#ifdef RC_POLARITY_GPIO_PORT + gpio_setup_output(RC_POLARITY_GPIO_PORT, RC_POLARITY_GPIO_PIN); + RC_SET_POLARITY(RC_POLARITY_GPIO_PORT, RC_POLARITY_GPIO_PIN); +#endif + + // Initialize all the UART's in the satellites + spektrum_init_sat(&spektrum.satellites[0]); +#ifdef SPEKTRUM_SECONDARY_UART + spektrum_init_sat(&spektrum.satellites[1]); +#endif +} + +/* Parse a sattelite channel */ +static inline void spektrum_parse_channel(struct spektrum_sat_t *sat, uint16_t chan) +{ + // This channel is not used + if (chan == 0xFFFF) { + return; + } + + if (spektrum.tx_type == SPEKTRUM_SYS_22_1024_2) { + // We got a 10bit precision packet + uint8_t chan_num = (chan & 0xFC00) >> 10; + sat->values[chan_num] = chan & 0x03FF; + if (chan_num == RADIO_THROTTLE) { + // scale full range to pprz_t + // but since 1024 correspond to 150%, scale with 1024/1.5 ~ 684 + // remove an offset of 2400 = 171 * MAX_PPRZ / 684 + sat->values[chan_num] = ((MAX_PPRZ * sat->values[chan_num]) / 684) - 2400; + } else { + sat->values[chan_num] -= (1 << 9); // substract 2^9 to get a value between [-512;512] + // scale full range to pprz_t + // but since 512 correspond to 150%, scale with 512/1.5 ~ 342 + sat->values[chan_num] = (MAX_PPRZ * sat->values[chan_num]) / 342; + } + } + else { + // We got a 11bit precision packet + uint8_t chan_num = (chan & 0x7800) >> 11; + sat->values[chan_num] = chan & 0x07FF; + if (chan_num == RADIO_THROTTLE) { + // scale full range to pprz_t + // but since 2048 correspond to 150%, scale with 2048/1.5 ~ 1368 + // remove an offset of 2400 = 234 * MAX_PPRZ / 1368 + sat->values[chan_num] = ((MAX_PPRZ * sat->values[chan_num]) / 1368) - 2400; + } else { + sat->values[chan_num] -= (1 << 10); // substract 2^10 to get a value between [-1024;1024] + // scale full range to pprz_t + // but since 1024 correspond to 150%, scale with 1024/1.5 ~ 684 + sat->values[chan_num] = (MAX_PPRZ * sat->values[chan_num]) / 684; + } + } + + // mark a valid frame + sat->valid = true; + spektrum.valid = true; +} + +/* Spektrum parser for a satellite */ +static inline void spektrum_parser(struct spektrum_sat_t *sat) +{ + // Parse packet + sat->lost_frame_cnt = sat->buf[0]; + // For now ignore the second byte (which could be the TX type) + // if frame type is still unknown, try to find it in the 'system' byte + // only the primary receiver should have a valid type + if (spektrum.tx_type == 0) { + uint8_t type = sat->buf[1]; + if (type == SPEKTRUM_SYS_22_1024_2 || type == SPEKTRUM_SYS_11_2048_2 || + type == SPEKTRUM_SYS_22_2048_X || type == SPEKTRUM_SYS_11_2048_X) { + // we have a valid type, we assume it comes from primary receiver + spektrum.tx_type = type; + } else { + // return and drop frame as we don't know what to do with it + return; + } + } + // parse servo channels + for (uint8_t i = 2; i < 2*SPEKTRUM_CHANNELS_PER_FRAME+2; i = i+2) { + uint16_t chan = (((uint16_t)sat->buf[i]) << 8) | ((uint16_t)sat->buf[i+1]); + spektrum_parse_channel(sat, chan); + } +} + +/** Check bytes on the UART */ +static void spektrum_uart_check(struct uart_periph *dev, struct spektrum_sat_t *sat) +{ + // detect sync space based on frame spacing + uint32_t t = get_sys_time_msec(); + if (t - sat->timer > SPEKTRUM_MIN_FRAME_SPACE) { + sat->timer = t; // reset counter + uint16_t bytes_cnt = uart_char_available(dev); // The amount of bytes in the buffer + // sync space detected but buffer not empty, flush data + if (bytes_cnt > 0) { + for (uint8_t i = 0; i < bytes_cnt; i++) { + uart_getch(dev); + } + } + } + // check and parse bytes in uart buffer + while (uart_char_available(dev)) { + sat->buf[sat->idx++] = uart_getch(dev); + sat->timer = t; // reset counter + if (sat->idx == SPEKTRUM_FRAME_LEN) { + // buffer is full, parse frame + spektrum_parser(sat); + sat->idx = 0; // reset index + break; // stop here to handle RC frame + } + } +} + +/** Checks if there is one valid satellite and sets the radio_control structure */ +void spektrum_event(void (*frame_handler)(void)) +{ + spektrum_uart_check(&SPEKTRUM_PRIMARY_UART, &spektrum.satellites[0]); + +#ifdef SPEKTRUM_SECONDARY_UART + spektrum_uart_check(&SPEKTRUM_SECONDARY_UART, &spektrum.satellites[1]); +#endif + + // Whenever we received a valid RC packet + if (spektrum.valid) { + uint8_t sat_id = SPEKTRUM_SATELLITES_NB; + spektrum.valid = false; + + // Find the first satellite that has a valid packet + for (uint8_t i = 0; i < SPEKTRUM_SATELLITES_NB; i++) { + if (i < sat_id) { + sat_id = i; + } + if (spektrum.satellites[i].valid) { + spektrum.satellites[i].valid = false; + } + } + + // Failsafe case if found satellite is out of bound (Should not happen) + if (sat_id >= SPEKTRUM_SATELLITES_NB) { + return; + } + + // Set the radio control status + radio_control.frame_cpt++; + radio_control.time_since_last_frame = 0; + radio_control.status = RC_OK; + + // Copy the radio control channels + for (uint8_t i = 0; i < RADIO_CONTROL_NB_CHANNEL; i++) { + radio_control.values[i] = spektrum.satellites[sat_id].values[i] * spektrum.signs[i]; + Bound(radio_control.values[i], -MAX_PPRZ, MAX_PPRZ); + } + + // We got a valid frame so execute the frame handler + (*frame_handler)(); + } +} + +/* Defines needed for easy access of port information */ +#define _UART_RX_PORT(i) i ## _PORT_RX +#define UART_RX_PORT(i) _UART_RX_PORT(i) +#define _UART_RX(i) i ## _RX +#define UART_RX(i) _UART_RX(i) + +/** + * By default, the same pin is used for pulse train and uart rx, but + * they can be different if needed + */ +#ifndef SPEKTRUM_PRIMARY_BIND_CONF_PORT +#define SPEKTRUM_PRIMARY_BIND_CONF_PORT UART_RX_PORT(SPEKTRUM_PRIMARY_UART_UPPER) +#endif +#ifndef SPEKTRUM_PRIMARY_BIND_CONF_PIN +#define SPEKTRUM_PRIMARY_BIND_CONF_PIN UART_RX(SPEKTRUM_PRIMARY_UART_UPPER) +#endif +#ifndef SPEKTRUM_SECONDARY_BIND_CONF_PORT +#define SPEKTRUM_SECONDARY_BIND_CONF_PORT UART_RX_PORT(SPEKTRUM_SECONDARY_UART_UPPER) +#endif +#ifndef SPEKTRUM_SECONDARY_BIND_CONF_PIN +#define SPEKTRUM_SECONDARY_BIND_CONF_PIN UART_RX(SPEKTRUM_SECONDARY_UART_UPPER) +#endif + +/** This function puts the satellite in binding mode. + * The requirement of this are that this needs to be done while powering up. */ +static void spektrum_bind(void) +{ + + /* Master receiver Rx push-pull */ + gpio_setup_output(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); + /* Master receiver RX line, drive high */ + gpio_set(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); + +#ifdef SPEKTRUM_SECONDARY_UART + /* Slave receiver Rx push-pull */ + gpio_setup_output(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); + /* Slave receiver RX line, drive high */ + gpio_set(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); +#endif + + /* bind pulses should be issued within 200ms after power up + * wait a bit to let the receiver start properly, + * set to 0 to disable */ +#if SPEKTRUM_BIND_WAIT + sys_time_usleep(SPEKTRUM_BIND_WAIT); +#endif + + /* Transmit the bind pulses */ + for (int i = 0; i < 2 * SPEKTRUM_MASTER_RECEIVER_PULSES ; i++) { + gpio_toggle(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); + sys_time_usleep(120); + } +#ifdef SPEKTRUM_SECONDARY_UART + for (int i = 0; i < 2 * SPEKTRUM_SLAVE_RECEIVER_PULSES; i++) { + gpio_toggle(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); + sys_time_usleep(120); + } +#endif + + /* Set conf pin as input in case it is different from RX pin */ + gpio_setup_input(SPEKTRUM_PRIMARY_BIND_CONF_PORT, SPEKTRUM_PRIMARY_BIND_CONF_PIN); +#ifdef SPEKTRUM_SECONDARY_UART + gpio_setup_input(SPEKTRUM_SECONDARY_BIND_CONF_PORT, SPEKTRUM_SECONDARY_BIND_CONF_PIN); +#endif +} + diff --git a/sw/airborne/subsystems/radio_control/spektrum.h b/sw/airborne/subsystems/radio_control/spektrum.h index a544cbf8afd..70a592690ac 100644 --- a/sw/airborne/subsystems/radio_control/spektrum.h +++ b/sw/airborne/subsystems/radio_control/spektrum.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2009-2014 The Paparazzi Team + * 2015 Freek van Tienen + * 2018 Gautier Hattenberger * * This file is part of paparazzi. * @@ -27,12 +29,44 @@ #ifndef RADIO_CONTROL_SPEKTRUM_H #define RADIO_CONTROL_SPEKTRUM_H -/* implemented in arch/xxx/subsystems/radio_control/spektrum_arch.c */ -extern void radio_control_spektrum_try_bind(void); +#include "std.h" -#include "subsystems/radio_control/spektrum_arch.h" -/* implemented in arch/xxx/subsystems/radio_control/spektrum_arch.c */ +/* Include channels information */ +#include "spektrum_radio.h" -#define RadioControlEvent(_received_frame_handler) RadioControlEventImp(_received_frame_handler) +/* For now only two satellites are supported */ +#define SPEKTRUM_SATELLITES_NB 2 + +/* Timings and maximums of Spektrum DSM protocol */ +#define SPEKTRUM_FRAME_LEN 16 ///< 16 bytes in a standard frame +#define SPEKTRUM_CHANNELS_PER_FRAME 7 ///< Maximum amount of RC channels per frame +#define SPEKTRUM_MAX_FRAMES 2 ///< Maximum amount of RC frames containing different channels +#define SPEKTRUM_MAX_CHANNELS (SPEKTRUM_CHANNELS_PER_FRAME * SPEKTRUM_MAX_FRAMES) +#define SPEKTRUM_MIN_FRAME_SPACE 7 ///< Minum amount of time between frames (7ms), in fact either 11 or 22 ms + +/* Set the event function to the correct */ +#define RadioControlEvent(_received_frame_handler) spektrum_event(_received_frame_handler) + +/* Per satellite we keep track of data */ +struct spektrum_sat_t { + bool valid; ///< True when we received a packet else false + uint32_t timer; ///< Timer to keep track of the UART synchronisation + uint8_t lost_frame_cnt; ///< Amount of RC frames lost + uint8_t buf[SPEKTRUM_FRAME_LEN]; ///< input buffer + uint8_t idx; ///< input buffer index + int16_t values[SPEKTRUM_MAX_CHANNELS]; ///< RC channel values +}; + +/* Main spektrum structure */ +struct spektrum_t { + bool valid; ///< True when we received a packet else false + uint8_t tx_type; ///< Transmitter type encoded (see wiki) + int8_t signs[RADIO_CONTROL_NB_CHANNEL]; ///< Signs for the RC channels + struct spektrum_sat_t satellites[SPEKTRUM_SATELLITES_NB]; ///< All the satellites connected +}; + +/* External functions */ +extern void spektrum_event(void (*_received_frame_handler)(void)); +extern void spektrum_try_bind(void); #endif /* RADIO_CONTROL_SPEKTRUM_H */ diff --git a/sw/airborne/subsystems/radio_control/spektrum_dx7se.h b/sw/airborne/subsystems/radio_control/spektrum_dx7se.h deleted file mode 100644 index 42463e5c3d2..00000000000 --- a/sw/airborne/subsystems/radio_control/spektrum_dx7se.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008-2009 Antoine Drouin - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef RADIO_CONTROL_SPEKTRUM_DX7SE_H -#define RADIO_CONTROL_SPEKTRUM_DX7SE_H - -#define RADIO_CONTROL_NB_CHANNEL 7 - -#define RADIO_ROLL 0 -#define RADIO_THROTTLE 1 -#define RADIO_PITCH 2 -#define RADIO_YAW 3 -#define RADIO_AUX3 4 -#define RADIO_MODE 5 -#define RADIO_AUX4 6 - -#define RC_SPK_SYNC_2 0x12 - -#define RC_SPK_THROWS { MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK, \ - -MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK, \ - -MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK } - -/* - aileron 1 - elevator 2 - rudder 3 - gear 4 - throttle 5 -*/ - -#endif /* RADIO_CONTROL_SPEKTRUM_DX7SE_H */ diff --git a/sw/airborne/subsystems/radio_control/spektrum_dx7se_joby.h b/sw/airborne/subsystems/radio_control/spektrum_dx7se_joby.h deleted file mode 100644 index 7a468a471b6..00000000000 --- a/sw/airborne/subsystems/radio_control/spektrum_dx7se_joby.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2008-2009 Antoine Drouin - * - * This file is part of paparazzi. - * - * paparazzi is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * paparazzi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef RADIO_CONTROL_SPEKTRUM_DX7SE_H -#define RADIO_CONTROL_SPEKTRUM_DX7SE_H - -#define RADIO_CONTROL_NB_CHANNEL 7 - -#define RADIO_ROLL 0 -#define RADIO_THROTTLE 5 -#define RADIO_PITCH 3 -#define RADIO_YAW 6 -#define RADIO_MODE 1 -#define RADIO_KILL_SWITCH 4 - -#define RC_SPK_SYNC_2 0x01 - -#define RC_SPK_THROWS { MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK, \ - -MAX_PPRZ/MAX_SPK, \ - -MAX_PPRZ/MAX_SPK, \ - -MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK, \ - MAX_PPRZ/MAX_SPK } - -/* - aileron 1 - elevator 2 - rudder 3 - gear 4 - throttle 5 -*/ - -#endif /* RADIO_CONTROL_SPEKTRUM_DX7SE_H */ diff --git a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h b/sw/airborne/subsystems/radio_control/spektrum_radio.h similarity index 55% rename from sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h rename to sw/airborne/subsystems/radio_control/spektrum_radio.h index 753deeaabec..0a3af0b4895 100644 --- a/sw/airborne/arch/stm32/subsystems/radio_control/spektrum_arch.h +++ b/sw/airborne/subsystems/radio_control/spektrum_radio.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010 Eric Parsonage + * Copyright (C) 2009-2014 The Paparazzi Team + * 2016 Freek van Tienen * * This file is part of paparazzi. * @@ -14,29 +15,26 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with paparazzi; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * along with paparazzi; see the file COPYING. If not, see + * . */ -#ifndef RADIO_CONTROL_SPEKTRUM_ARCH_H -#define RADIO_CONTROL_SPEKTRUM_ARCH_H - - -/* - * All Spektrum and JR 2.4 GHz transmitters - * have the same channel assignments. +/** + * @file subsystems/radio_control/spektrum_radio.h + * + * Radio control channels defaults, because they are digital */ -#define SPEKTRUM_NB_CHANNEL 12 +#ifndef RADIO_CONTROL_SPEKTRUM_RADIO_H +#define RADIO_CONTROL_SPEKTRUM_RADIO_H +/* Amount of spektrum channels */ #ifndef RADIO_CONTROL_NB_CHANNEL -#define RADIO_CONTROL_NB_CHANNEL 12 +#define RADIO_CONTROL_NB_CHANNEL 14 #endif -#if RADIO_CONTROL_NB_CHANNEL > 12 -#error "RADIO_CONTROL_NB_CHANNEL mustn't be higher than 12." +#if RADIO_CONTROL_NB_CHANNEL > 14 +#error "RADIO_CONTROL_NB_CHANNEL mustn't be higher than 14." #endif /* default channel assignments */ @@ -52,12 +50,8 @@ #ifndef RADIO_YAW #define RADIO_YAW 3 #endif -#ifndef RADIO_GEAR #define RADIO_GEAR 4 -#endif -#ifndef RADIO_FLAP #define RADIO_FLAP 5 -#endif #define RADIO_AUX1 5 #define RADIO_AUX2 6 #define RADIO_AUX3 7 @@ -65,25 +59,22 @@ #define RADIO_AUX5 9 #define RADIO_AUX6 10 #define RADIO_AUX7 11 +#define RADIO_AUX8 12 +#define RADIO_AUX9 13 + +/* Default Mode channel is GEAR (number 5) */ +#ifndef RADIO_MODE +#define RADIO_MODE RADIO_GEAR +#endif -/* reverse some channels to suit Paparazzi conventions */ -/* the maximum number of channels a Spektrum can transmit is 12 */ +/* Possibility to reverse channels */ #ifndef RADIO_CONTROL_SPEKTRUM_SIGNS +// #ifdef RADIO_CONTROL_SPEKTRUM_OLD_SIGNS -#define RADIO_CONTROL_SPEKTRUM_SIGNS {1,-1,-1,-1,1,-1,1,1,1,1,1,1} // As most transmitters are sold +#define RADIO_CONTROL_SPEKTRUM_SIGNS {1,-1,-1,-1,1,-1,1,1,1,1,1,1,1,1} // As most transmitters are sold #else -#define RADIO_CONTROL_SPEKTRUM_SIGNS {1,1,1,1,1,1,1,1,1,1,1,1} // PPRZ sign convention -#endif +#define RADIO_CONTROL_SPEKTRUM_SIGNS {1,1,1,1,1,1,1,1,1,1,1,1,1,1} // PPRZ sign convention #endif - -/* really for a 9 channel transmitter - we would swap the order of these */ -#ifndef RADIO_MODE -#define RADIO_MODE RADIO_GEAR #endif -extern void RadioControlEventImp(void (*_received_frame_handler)(void)); -/* initialise the uarts used by the parser */ -void SpektrumUartInit(void); - -#endif /* RADIO_CONTROL_SPEKTRUM_ARCH_H */ +#endif /* RADIO_CONTROL_SPEKTRUM_RADIO_H */