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.
23 void setExternalModulePolarity()
26 pwmptr
->PWM_CH_NUM
[3].PWM_CDTYUPD
= GET_PPM_DELAY(EXTERNAL_MODULE
) * 2; // Duty in half uS
27 if (GET_PPM_POLARITY(EXTERNAL_MODULE
))
28 pwmptr
->PWM_CH_NUM
[3].PWM_CMR
&= ~0x00000200; // CPOL
30 pwmptr
->PWM_CH_NUM
[3].PWM_CMR
|= 0x00000200; // CPOL
33 void setExtraModulePolarity()
36 pwmptr
->PWM_CH_NUM
[1].PWM_CDTYUPD
= GET_PPM_DELAY(EXTRA_MODULE
) * 2; // Duty in half uS
37 if (GET_PPM_POLARITY(EXTRA_MODULE
))
38 pwmptr
->PWM_CH_NUM
[1].PWM_CMR
&= ~0x00000200; // CPOL
40 pwmptr
->PWM_CH_NUM
[1].PWM_CMR
|= 0x00000200; // CPOL
43 void module_output_active()
46 pioptr
->PIO_ABCDSR
[0] &= ~PIO_PA17
; // Peripheral C
47 pioptr
->PIO_ABCDSR
[1] |= PIO_PA17
; // Peripheral C
48 pioptr
->PIO_PDR
= PIO_PA17
; // Disable bit A17 Assign to peripheral
50 if (g_model
.moduleData
[EXTERNAL_MODULE
].ppm
.outputType
) {
51 pioptr
->PIO_MDDR
= PIO_PA17
; // Push Pull O/p in A17
54 pioptr
->PIO_MDER
= PIO_PA17
; // Open Drain O/p in A17
57 pioptr
->PIO_MDDR
= PIO_PA17
; // Push Pull O/p in A17
59 pioptr
->PIO_PUER
= PIO_PA17
; // With pull up
62 void init_main_ppm(uint32_t period
, uint32_t out_enable
)
66 setupPulsesPPMModule(EXTERNAL_MODULE
);
69 module_output_active();
73 // PWM3 for PPM output
74 pwmptr
->PWM_CH_NUM
[3].PWM_CMR
= 0x0004000B; // CLKA
75 pwmptr
->PWM_CH_NUM
[3].PWM_CPDR
= period
; // Period in half uS
76 pwmptr
->PWM_CH_NUM
[3].PWM_CPDRUPD
= period
; // Period in half uS
77 pwmptr
->PWM_CH_NUM
[3].PWM_CDTY
= GET_PPM_DELAY(EXTERNAL_MODULE
) * 2; // Duty in half uS
78 pwmptr
->PWM_ENA
= PWM_ENA_CHID3
; // Enable channel 3
79 pwmptr
->PWM_IER1
= PWM_IER1_CHID3
;
81 setExternalModulePolarity();
83 NVIC_SetPriority(PWM_IRQn
, 3);
84 NVIC_EnableIRQ(PWM_IRQn
);
87 void disable_main_ppm()
90 pioptr
->PIO_PER
= PIO_PA17
; // Assign A17 to PIO
91 PWM
->PWM_IDR1
= PWM_IDR1_CHID3
;
94 void init_second_ppm(uint32_t period
)
99 configure_pins(PIO_PC15
, PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_B
| PIN_PORTC
| PIN_NO_PULLUP
);
100 pwmptr
->PWM_CH_NUM
[1].PWM_CMR
= 0x0000000B; // CLKB
101 if (!GET_PPM_POLARITY(EXTRA_MODULE
)) {
102 pwmptr
->PWM_CH_NUM
[1].PWM_CMR
|= 0x00000200; // CPOL
104 pwmptr
->PWM_CH_NUM
[1].PWM_CPDR
= period
; // Period
105 pwmptr
->PWM_CH_NUM
[1].PWM_CPDRUPD
= period
; // Period
106 pwmptr
->PWM_CH_NUM
[1].PWM_CDTY
= GET_PPM_DELAY(EXTRA_MODULE
)*2; // Duty
107 pwmptr
->PWM_CH_NUM
[1].PWM_CDTYUPD
= GET_PPM_DELAY(EXTRA_MODULE
)*2; // Duty
108 pwmptr
->PWM_ENA
= PWM_ENA_CHID1
; // Enable channel 1
109 pwmptr
->PWM_IER1
= PWM_IER1_CHID1
;
113 void disable_second_ppm()
117 pioptr
->PIO_PER
= PIO_PC15
; // Assign C17 to PIO
118 PWM
->PWM_IDR1
= PWM_IDR1_CHID1
;
122 void init_no_pulses(uint32_t port
)
124 if (port
== EXTERNAL_MODULE
) {
125 init_main_ppm(3000, 0);
132 void disable_no_pulses(uint32_t port
)
134 if (port
== EXTERNAL_MODULE
) {
135 disable_ppm(EXTERNAL_MODULE
);
142 void init_ppm(uint32_t port
)
144 if (port
== EXTERNAL_MODULE
) {
145 init_main_ppm(3000, 1);
148 init_second_ppm(3000);
152 void disable_ppm(uint32_t port
)
154 if (port
== EXTERNAL_MODULE
) {
158 disable_second_ppm();
162 // Initialise the SSC to allow PXX output.
163 // TD is on PA17, peripheral A
164 void init_ssc(uint8_t baudrateDiv1000
)
168 PMC
->PMC_PCER0
|= 0x00400000L
; // Enable peripheral clock to SSC
170 configure_pins(PIO_PA17
, PIN_PERIPHERAL
| PIN_INPUT
| PIN_PER_A
| PIN_PORTA
);
173 sscptr
->SSC_THR
= 0xFF; // Make the output high.
174 sscptr
->SSC_TFMR
= 0x00000027; // 0000 0000 0000 0000 0000 0000 1010 0111 (8 bit data, lsb)
175 sscptr
->SSC_CMR
= Master_frequency
/ (1000 * baudrateDiv1000
* 2);
176 sscptr
->SSC_TCMR
= 0;
177 sscptr
->SSC_CR
= SSC_CR_TXEN
;
180 if (IS_MODULE_MULTIMODULE(EXTERNAL_MODULE
)) {
181 PIOA
->PIO_MDDR
= PIO_PA17
; // Push Pull O/p in A17
183 PIOA
->PIO_MDER
= PIO_PA17
; // Open Drain O/p in A17
186 PIOA
->PIO_MDDR
= PIO_PA17
; // Push Pull O/p in A17
195 // Revert back to pwm output
197 pioptr
->PIO_PER
= PIO_PA17
; // Assign A17 to PIO
200 sscptr
->SSC_CR
= SSC_CR_TXDIS
;
203 void init_pxx(uint32_t port
)
205 if (port
== EXTERNAL_MODULE
) {
206 init_main_ppm(2500 * 2, 0);
207 init_ssc(125); // 8us per bit
214 void disable_pxx(uint32_t port
)
216 if (port
== EXTERNAL_MODULE
) {
218 disable_ppm(EXTERNAL_MODULE
);
225 void init_serial(uint32_t port
, uint32_t baudrate
, uint32_t period_half_us
)
227 if (port
== EXTERNAL_MODULE
) {
228 if (baudrate
== 125000) {
229 // TODO init_main_ppm could take the period as parameter?
230 init_main_ppm(2500 * 2, 0);
234 init_main_ppm(3500 * 2, 0);
243 void disable_serial(uint32_t port
)
245 if (port
== EXTERNAL_MODULE
) {
247 disable_ppm(EXTERNAL_MODULE
);
255 extern "C" void PWM_IRQHandler(void)
258 uint32_t reason
= pwmptr
->PWM_ISR1
;
261 if (reason
& PWM_ISR1_CHID3
) {
262 // Use the current protocol, don't switch until set_up_pulses
263 switch (s_current_protocol
[EXTERNAL_MODULE
]) {
265 // Alternate periods of 6.5mS and 2.5 mS
266 period
= pwmptr
->PWM_CH_NUM
[3].PWM_CPDR
;
267 if (period
== 2500 * 2) {
273 pwmptr
->PWM_CH_NUM
[3].PWM_CPDRUPD
= period
; // Period in half uS
274 if (period
!= 2500 * 2) {
275 setupPulses(EXTERNAL_MODULE
);
276 setExternalModulePolarity();
279 // Kick off serial output here
281 sscptr
->SSC_TPR
= CONVERT_PTR_UINT(modulePulsesData
[EXTERNAL_MODULE
].pxx
.pulses
);
282 sscptr
->SSC_TCR
= (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].pxx
.ptr
- (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].pxx
.pulses
;
283 sscptr
->SSC_PTCR
= SSC_PTCR_TXTEN
; // Start transfers
287 case PROTO_DSM2_LP45
:
288 case PROTO_DSM2_DSM2
:
289 case PROTO_DSM2_DSMX
:
290 // Alternate periods of 19.5mS and 2.5 mS
291 period
= pwmptr
->PWM_CH_NUM
[3].PWM_CPDR
;
292 if (period
== 2500 * 2) {
298 pwmptr
->PWM_CH_NUM
[3].PWM_CPDRUPD
= period
; // Period in half uS
299 if (period
!= 2500 * 2) {
300 setupPulses(EXTERNAL_MODULE
);
303 // Kick off serial output here
305 sscptr
->SSC_TPR
= CONVERT_PTR_UINT(modulePulsesData
[EXTERNAL_MODULE
].dsm2
.pulses
);
306 sscptr
->SSC_TCR
= (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].dsm2
.ptr
- (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].dsm2
.pulses
;
307 sscptr
->SSC_PTCR
= SSC_PTCR_TXTEN
; // Start transfers
311 #if defined(MULTIMODULE)
312 case PROTO_MULTIMODULE
:
315 // Todo: how to do inverted polarity on this platform?
316 // Alternate periods of 5.5mS and 3.5 mS
317 period
= pwmptr
->PWM_CH_NUM
[3].PWM_CPDR
;
318 if (period
== 3500 * 2) {
324 pwmptr
->PWM_CH_NUM
[3].PWM_CPDRUPD
= period
; // Period in half uS
325 if (period
!= 3500 * 2) {
326 setupPulses(EXTERNAL_MODULE
);
329 // Kick off serial output here
331 sscptr
->SSC_TPR
= CONVERT_PTR_UINT(modulePulsesData
[EXTERNAL_MODULE
].dsm2
.pulses
);
332 sscptr
->SSC_TCR
= (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].dsm2
.ptr
- (uint8_t *)modulePulsesData
[EXTERNAL_MODULE
].dsm2
.pulses
;
333 sscptr
->SSC_PTCR
= SSC_PTCR_TXTEN
; // Start transfers
338 pwmptr
->PWM_CH_NUM
[3].PWM_CPDRUPD
= *modulePulsesData
[EXTERNAL_MODULE
].ppm
.ptr
++;
339 if (*modulePulsesData
[EXTERNAL_MODULE
].ppm
.ptr
== 0) {
340 setExternalModulePolarity();
341 setupPulses(EXTERNAL_MODULE
);
349 if (reason
& PWM_ISR1_CHID1
) {
350 pwmptr
->PWM_CH_NUM
[1].PWM_CPDRUPD
= *modulePulsesData
[EXTRA_MODULE
].ppm
.ptr
++;
351 if (*modulePulsesData
[EXTRA_MODULE
].ppm
.ptr
== 0) {
352 setupPulsesPPMModule(EXTRA_MODULE
);
353 setExtraModulePolarity();