5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
22 #include "pulses/pulses.h"
26 INTERNAL_MODULE_OFF();
28 NVIC_DisableIRQ(INTMODULE_DMA_STREAM_IRQn
);
29 NVIC_DisableIRQ(INTMODULE_TIMER_CC_IRQn
);
31 INTMODULE_DMA_STREAM
->CR
&= ~DMA_SxCR_EN
; // Disable DMA
32 INTMODULE_TIMER
->DIER
&= ~(TIM_DIER_CC2IE
| TIM_DIER_UDE
);
33 INTMODULE_TIMER
->CR1
&= ~TIM_CR1_CEN
;
36 // #define HEARBEAT_OFFSET unsigned(6000 + g_model.flightModeData[0].gvars[0] * 100)
37 constexpr unsigned HEARBEAT_OFFSET
= 6000;
39 void intmoduleSendNextFrame()
41 switch (moduleState
[INTERNAL_MODULE
].protocol
) {
43 case PROTOCOL_CHANNELS_PXX1_PULSES
:
45 uint32_t last
= intmodulePulsesData
.pxx
.getLast();
46 if (heartbeatCapture
.valid
) {
47 if (getTmr2MHz() - heartbeatCapture
.timestamp
> HEARBEAT_OFFSET
)
51 intmodulePulsesData
.pxx
.setLast(last
);
53 INTMODULE_TIMER
->CCR2
= last
- 4000; // 2mS in advance
54 INTMODULE_DMA_STREAM
->CR
&= ~DMA_SxCR_EN
; // Disable DMA
55 INTMODULE_DMA_STREAM
->CR
|= INTMODULE_DMA_CHANNEL
| DMA_SxCR_DIR_0
| DMA_SxCR_MINC
| DMA_SxCR_PSIZE_0
| DMA_SxCR_MSIZE_0
| DMA_SxCR_PL_0
| DMA_SxCR_PL_1
;
56 INTMODULE_DMA_STREAM
->PAR
= CONVERT_PTR_UINT(&INTMODULE_TIMER
->ARR
);
57 INTMODULE_DMA_STREAM
->M0AR
= CONVERT_PTR_UINT(intmodulePulsesData
.pxx
.getData());
58 INTMODULE_DMA_STREAM
->NDTR
= intmodulePulsesData
.pxx
.getSize();
59 INTMODULE_DMA_STREAM
->CR
|= DMA_SxCR_EN
| DMA_SxCR_TCIE
; // Enable DMA
64 #if defined(INTERNAL_MODULE_PPM)
65 case PROTOCOL_CHANNELS_PPM
:
66 INTMODULE_TIMER
->CCR3
= GET_MODULE_PPM_DELAY(INTERNAL_MODULE
) * 2;
67 INTMODULE_TIMER
->CCER
= TIM_CCER_CC3E
| (GET_MODULE_PPM_POLARITY(INTERNAL_MODULE
) ? 0 : TIM_CCER_CC3P
);
68 INTMODULE_TIMER
->CCR2
= *(intmodulePulsesData
.ppm
.ptr
- 1) - 4000; // 2mS in advance
69 INTMODULE_DMA_STREAM
->CR
&= ~DMA_SxCR_EN
; // Disable DMA
70 INTMODULE_DMA_STREAM
->CR
|= INTMODULE_DMA_CHANNEL
| DMA_SxCR_DIR_0
| DMA_SxCR_MINC
| DMA_SxCR_PSIZE_0
| DMA_SxCR_MSIZE_0
| DMA_SxCR_PL_0
| DMA_SxCR_PL_1
;
71 INTMODULE_DMA_STREAM
->PAR
= CONVERT_PTR_UINT(&INTMODULE_TIMER
->ARR
);
72 INTMODULE_DMA_STREAM
->M0AR
= CONVERT_PTR_UINT(intmodulePulsesData
.ppm
.pulses
);
73 INTMODULE_DMA_STREAM
->NDTR
= intmodulePulsesData
.ppm
.ptr
- intmodulePulsesData
.ppm
.pulses
;
74 INTMODULE_DMA_STREAM
->CR
|= DMA_SxCR_EN
| DMA_SxCR_TCIE
; // Enable DMA
79 INTMODULE_TIMER
->DIER
|= TIM_DIER_CC2IE
;
84 void intmodulePxx1PulsesStart()
88 GPIO_PinAFConfig(INTMODULE_TX_GPIO
, INTMODULE_TX_GPIO_PinSource
, INTMODULE_TX_GPIO_AF
);
90 GPIO_InitTypeDef GPIO_InitStructure
;
91 GPIO_InitStructure
.GPIO_Pin
= INTMODULE_TX_GPIO_PIN
;
92 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AF
;
93 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
94 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
95 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
96 GPIO_Init(INTMODULE_TX_GPIO
, &GPIO_InitStructure
);
98 INTMODULE_TIMER
->CR1
&= ~TIM_CR1_CEN
;
99 INTMODULE_TIMER
->PSC
= INTMODULE_TIMER_FREQ
/ 2000000 - 1; // 0.5uS (2Mhz)
100 INTMODULE_TIMER
->ARR
= 18000;
101 INTMODULE_TIMER
->CCER
= TIM_CCER_CC3E
| TIM_CCER_CC3NE
;
102 INTMODULE_TIMER
->BDTR
= TIM_BDTR_MOE
; // Enable outputs
103 INTMODULE_TIMER
->CCR3
= 16;
104 INTMODULE_TIMER
->CCMR2
= TIM_CCMR2_OC3M_2
| TIM_CCMR2_OC3M_0
; // Force O/P high
105 INTMODULE_TIMER
->EGR
= 1; // Restart
106 INTMODULE_TIMER
->DIER
|= TIM_DIER_UDE
; // Enable DMA on update
107 INTMODULE_TIMER
->CCMR2
= TIM_CCMR2_OC3M_1
| TIM_CCMR2_OC3M_2
;
108 INTMODULE_TIMER
->SR
&= ~TIM_SR_CC2IF
; // Clear flag
109 INTMODULE_TIMER
->CCR2
= 16000; // The first frame will be sent in 20ms
110 INTMODULE_TIMER
->DIER
|= TIM_DIER_CC2IE
; // Enable this interrupt
111 INTMODULE_TIMER
->CR1
|= TIM_CR1_CEN
;
113 NVIC_EnableIRQ(INTMODULE_DMA_STREAM_IRQn
);
114 NVIC_SetPriority(INTMODULE_DMA_STREAM_IRQn
, 7);
115 NVIC_EnableIRQ(INTMODULE_TIMER_CC_IRQn
);
116 NVIC_SetPriority(INTMODULE_TIMER_CC_IRQn
, 7);
119 #if defined(INTERNAL_MODULE_PPM)
120 void intmodulePpmStart()
122 INTERNAL_MODULE_ON();
124 GPIO_PinAFConfig(INTMODULE_TX_GPIO
, INTMODULE_TX_GPIO_PinSource
, INTMODULE_TX_GPIO_AF
);
126 GPIO_InitTypeDef GPIO_InitStructure
;
127 GPIO_InitStructure
.GPIO_Pin
= INTMODULE_TX_GPIO_PIN
;
128 GPIO_InitStructure
.GPIO_Mode
= GPIO_Mode_AF
;
129 GPIO_InitStructure
.GPIO_Speed
= GPIO_Speed_2MHz
;
130 GPIO_InitStructure
.GPIO_OType
= GPIO_OType_PP
;
131 GPIO_InitStructure
.GPIO_PuPd
= GPIO_PuPd_NOPULL
;
132 GPIO_Init(INTMODULE_TX_GPIO
, &GPIO_InitStructure
);
134 INTMODULE_TIMER
->CR1
&= ~TIM_CR1_CEN
;
135 INTMODULE_TIMER
->PSC
= INTMODULE_TIMER_FREQ
/ 2000000 - 1; // 0.5uS from 30MHz
136 INTMODULE_TIMER
->ARR
= 45000;
137 INTMODULE_TIMER
->CCMR2
= TIM_CCMR2_OC3M_1
| TIM_CCMR2_OC3M_2
; // PWM mode 1
138 INTMODULE_TIMER
->BDTR
= TIM_BDTR_MOE
;
139 INTMODULE_TIMER
->EGR
= 1;
140 INTMODULE_TIMER
->DIER
= TIM_DIER_UDE
;
141 INTMODULE_TIMER
->SR
&= ~TIM_SR_CC2IF
; // Clear flag
142 INTMODULE_TIMER
->CCR2
= 40000; // The first frame will be sent in 20ms
143 INTMODULE_TIMER
->DIER
|= TIM_DIER_CC2IE
; // Enable this interrupt
144 INTMODULE_TIMER
->CR1
= TIM_CR1_CEN
;
146 NVIC_EnableIRQ(INTMODULE_DMA_STREAM_IRQn
);
147 NVIC_SetPriority(INTMODULE_DMA_STREAM_IRQn
, 7);
148 NVIC_EnableIRQ(INTMODULE_TIMER_CC_IRQn
);
149 NVIC_SetPriority(INTMODULE_TIMER_CC_IRQn
, 7);
151 #endif // defined(INTERNAL_MODULE_PPM)
153 extern "C" void INTMODULE_DMA_STREAM_IRQHandler()
155 if (!DMA_GetITStatus(INTMODULE_DMA_STREAM
, INTMODULE_DMA_FLAG_TC
))
158 DMA_ClearITPendingBit(INTMODULE_DMA_STREAM
, INTMODULE_DMA_FLAG_TC
);
160 INTMODULE_TIMER
->SR
&= ~TIM_SR_CC2IF
; // Clear flag
161 INTMODULE_TIMER
->DIER
|= TIM_DIER_CC2IE
; // Enable this interrupt
164 extern "C" void INTMODULE_TIMER_CC_IRQHandler()
166 INTMODULE_TIMER
->DIER
&= ~TIM_DIER_CC2IE
; // Stop this interrupt
167 INTMODULE_TIMER
->SR
&= ~TIM_SR_CC2IF
;
168 if (setupPulsesInternalModule()) {
169 intmoduleSendNextFrame();