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>
30 #include "subsystems/radio_control/spektrum_arch.h"
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")
45 #define SPEKTRUM_CHANNELS_PER_FRAME 7
46 #define MAX_SPEKTRUM_FRAMES 2
47 #define MAX_SPEKTRUM_CHANNELS 16
49 #define ONE_MHZ 1000000
52 #define MASTER_RECEIVER_PULSES 5
53 #define SLAVE_RECEIVER_PULSES 6
55 #define TIM_TICS_FOR_100us 100
56 #define MIN_FRAME_SPACE 70 // 7ms
57 #define MAX_BYTE_SPACE 3 // .3ms
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)
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)
73 #ifndef SPEKTRUM_TIMER
74 #define SPEKTRUM_TIMER 6
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
82 #define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO
84 #ifndef NVIC_TIM6_DAC_IRQ_PRIO
85 #define NVIC_TIM6_DAC_IRQ_PRIO 2
86 #define NVIC_TIMx_DAC_IRQ_PRIO 2
88 #define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO
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
97 #define NVIC_TIMx_IRQ_PRIO NVIC_TIM6_IRQ_PRIO
99 #ifndef NVIC_TIM3_DAC_IRQ_PRIO
100 #define NVIC_TIM3_DAC_IRQ_PRIO 2
101 #define NVIC_TIMx_DAC_IRQ_PRIO 2
103 #define NVIC_TIMx_DAC_IRQ_PRIO NVIC_TIM6_DAC_IRQ_PRIO
109 #ifdef NVIC_UART_IRQ_PRIO
110 #define NVIC_PRIMARY_UART_PRIO NVIC_UART_IRQ_PRIO
112 #define NVIC_PRIMARY_UART_PRIO 2
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)
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)
146 PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_PRIMARY_PORT)
148 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
150 PRINT_CONFIG_VAR(RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT)
192 #ifndef RC_SET_POLARITY
193 #define RC_SET_POLARITY gpio_clear
204 PrimarySpektrumState.
ReSync = 1;
206 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
207 SecondarySpektrumState.ReSync = 1;
211 #ifdef RC_POLARITY_GPIO_PORT
335 static uint8_t TmpExpFrames = 0;
342 if ((spektrum_state->
ReSync == 1) ||
343 ((spektrum_state->
Sync == 0) && (!TimedOut))) {
345 spektrum_state->
ReSync = 0;
347 spektrum_state->
Sync = 0;
358 if (spektrum_state->
Sync == 0) {
360 if (secondary_receiver) {
363 spektrum_state->
Sync = 1;
372 spektrum_state->
ReSync = 1;
380 if (spektrum_state->
Sync == 1) {
381 if (secondary_receiver) {
387 TmpEncType = (_c & 0x10) >> 4;
388 TmpExpFrames = _c & 0x03;
391 spektrum_state->
Sync = 2;
399 if (spektrum_state->
Sync == 2) {
404 spektrum_state->
Sync = 3;
410 if (spektrum_state->
Sync == 3) {
411 spektrum_state->
Sync = 2;
417 + (spektrum_state->
SecondFrame * 7)] = ChannelData;
425 if (spektrum_state->
FrameCnt == TmpExpFrames) {
430 if (!secondary_receiver) {
431 EncodingType = TmpEncType;
432 ExpectedFrames = TmpExpFrames;
434 spektrum_state->
Sync = 0;
455 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
459 (SecondarySpektrumState.RcAvailable)) {
463 (SecondarySpektrumState.RcAvailable)) {
465 <= SecondarySpektrumState.LostFrameCnt) ? 0 : 1;
468 BestReceiver = (PrimarySpektrumState.
RcAvailable) ? 0 : 1;
472 SecondarySpektrumState.RcAvailable = 0;
482 #ifndef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
483 ChannelData = PrimarySpektrumState.
values[i];
485 ChannelData = (!BestReceiver) ? PrimarySpektrumState.
values[i] :
486 SecondarySpektrumState.values[i];
491 switch (EncodingType) {
493 ChannelNum = (ChannelData >> 10) & 0x0f;
496 SpektrumBuf[ChannelNum] = ChannelData & 0x3ff;
497 SpektrumBuf[ChannelNum] -= 0x200;
498 SpektrumBuf[ChannelNum] *=
MAX_PPRZ / 0x156;
504 ChannelNum = (ChannelData >> 11) & 0x0f;
507 SpektrumBuf[ChannelNum] = ChannelData & 0x7ff;
508 SpektrumBuf[ChannelNum] -= 0x400;
509 SpektrumBuf[ChannelNum] *=
MAX_PPRZ / 0x2AC;
514 default : ChannelNum = 0x0F;
break;
517 if ((ChannelNum != 0x0F) && (ChannelNum > MaxChannelNum)) {
518 MaxChannelNum = ChannelNum;
524 if (ChannelCnt >= (MaxChannelNum + 1)) {
561 timer_set_mode(
TIMx, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
566 timer_set_prescaler(
TIMx, ((TIMx_clk /
ONE_MHZ) - 1));
572 #elif defined STM32F4
579 timer_enable_irq(
TIMx, TIM_DIER_UIE);
583 timer_enable_counter(
TIMx);
594 #elif defined STM32F4
603 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
604 if (SecondarySpektrumState.SpektrumTimer) {
605 --SecondarySpektrumState.SpektrumTimer;
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);
642 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
660 usart_set_flow_control(
SecondaryUart(_DEV), USART_FLOWCONTROL_NONE);
680 if (((USART_CR1(
PrimaryUart(_DEV)) & USART_CR1_TXEIE) != 0) &&
681 ((USART_SR(
PrimaryUart(_DEV)) & USART_SR_TXE) != 0)) {
685 if (((USART_CR1(
PrimaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) &&
686 ((USART_SR(
PrimaryUart(_DEV)) & USART_SR_RXNE) != 0)) {
699 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
702 if (((USART_CR1(
SecondaryUart(_DEV)) & USART_CR1_TXEIE) != 0) &&
707 if (((USART_CR1(
SecondaryUart(_DEV)) & USART_CR1_RXNEIE) != 0) &&
726 #ifndef SPEKTRUM_PRIMARY_BIND_CONF_PORT
727 #define SPEKTRUM_PRIMARY_BIND_CONF_PORT PrimaryUart(_BANK)
729 #ifndef SPEKTRUM_PRIMARY_BIND_CONF_PIN
730 #define SPEKTRUM_PRIMARY_BIND_CONF_PIN PrimaryUart(_PIN)
732 #ifndef SPEKTRUM_SECONDARY_BIND_CONF_PORT
733 #define SPEKTRUM_SECONDARY_BIND_CONF_PORT SecondaryUart(_BANK)
735 #ifndef SPEKTRUM_SECONDARY_BIND_CONF_PIN
736 #define SPEKTRUM_SECONDARY_BIND_CONF_PIN SecondaryUart(_PIN)
748 #ifdef SPEKTRUM_BIND_PIN_PORT
749 #ifdef SPEKTRUM_BIND_PIN_HIGH
783 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
802 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
813 #ifdef RADIO_CONTROL_SPEKTRUM_SECONDARY_PORT
int16_t SpektrumBuf[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]
void radio_control_impl_init(void)
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
#define SLAVE_RECEIVER_PULSES
#define NVIC_TIMx_IRQ_PRIO
static void gpio_clear(ioportid_t port, uint16_t pin)
Clear a gpio output to low level.
#define SPEKTRUM_SECONDARY_BIND_CONF_PORT
Some architecture independent helper functions for GPIOs.
void PrimaryUart() _ISR(void)
void SpektrumTimerInit(void)
#define MAX_SPEKTRUM_FRAMES
#define MASTER_RECEIVER_PULSES
#define SPEKTRUM_BIND_PIN
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...
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
void gpio_setup_output(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as outputs.
static uint8_t ExpectedFrames
#define SecondaryUart(_x)
#define RC_POLARITY_GPIO_PIN
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.
timer_clear_flag(TIMx, TIM_SR_UIF)
void gpio_enable_clock(uint32_t port)
Enable the relevant clock.
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
Architecture independent timing functions.
SpektrumStateType PrimarySpektrumState
#define SPEKTRUM_CHANNELS_PER_FRAME
#define SPEKTRUM_NB_CHANNEL
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
static uint8_t EncodingType
#define NVIC_PRIMARY_UART_PRIO
struct RadioControl radio_control
#define NVIC_TIMx_DAC_IRQ
#define RC_SET_POLARITY
Set polarity using RC_POLARITY_GPIO.
#define RADIO_CONTROL_NB_CHANNEL
#define SPEKTRUM_BIND_PIN_PORT
void gpio_setup_pin_af(ioportid_t port, uint16_t pin, uint8_t af)
Setup a gpio for input or output with alternate function.
#define TIM_TICS_FOR_100us
#define SPEKTRUM_PRIMARY_BIND_CONF_PORT
static uint8_t gpio_get(ioportid_t port, uint16_t pin)
Get level of a gpio.
#define RADIO_CONTROL_SPEKTRUM_SIGNS
void RadioControlEventImp(void(*frame_handler)(void))
void SpektrumUartInit(void)
void radio_control_spektrum_try_bind(void)
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.
uint8_t time_since_last_frame
#define NVIC_TIMx_DAC_IRQ_PRIO
void gpio_setup_input(ioportid_t port, uint16_t gpios)
Setup one or more pins of the given GPIO port as inputs.
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.
int16_t values[SPEKTRUM_CHANNELS_PER_FRAME *MAX_SPEKTRUM_FRAMES]