Cleanup CC3D/NAZE/OLIMEXINO ADC initialisation and PWM mapping. Fixes
[betaflight.git] / src / main / drivers / pwm_mapping.c
bloba09f6ec10f180cc9d6a551d8544b271d59f842de
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <string.h>
21 #include <stdlib.h>
23 #include "platform.h"
25 #include "gpio.h"
26 #include "timer.h"
28 #include "pwm_output.h"
29 #include "pwm_rx.h"
30 #include "pwm_mapping.h"
32 Configuration maps
34 Note: this documentation is only valid for STM32F10x, for STM32F30x please read the code itself.
36 1) multirotor PPM input
37 PWM1 used for PPM
38 PWM5..8 used for motors
39 PWM9..10 used for servo or else motors
40 PWM11..14 used for motors
42 2) multirotor PPM input with more servos
43 PWM1 used for PPM
44 PWM5..8 used for motors
45 PWM9..10 used for servo or else motors
46 PWM11..14 used for servos
48 2) multirotor PWM input
49 PWM1..8 used for input
50 PWM9..10 used for servo or else motors
51 PWM11..14 used for motors
53 3) airplane / flying wing w/PWM
54 PWM1..8 used for input
55 PWM9 used for motor throttle +PWM10 for 2nd motor
56 PWM11.14 used for servos
58 4) airplane / flying wing with PPM
59 PWM1 used for PPM
60 PWM5..8 used for servos
61 PWM9 used for motor throttle +PWM10 for 2nd motor
62 PWM11.14 used for servos
65 enum {
66 MAP_TO_PPM_INPUT = 1,
67 MAP_TO_PWM_INPUT,
68 MAP_TO_MOTOR_OUTPUT,
69 MAP_TO_SERVO_OUTPUT,
72 #if defined(NAZE) || defined(OLIMEXINO) || defined(NAZE32PRO) || defined(STM32F3DISCOVERY) || defined(EUSTM32F103RC) || defined(PORT103R)
73 static const uint16_t multiPPM[] = {
74 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
75 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
76 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
77 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
78 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
79 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
80 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
81 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
82 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
83 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
84 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
85 0xFFFF
88 static const uint16_t multiPWM[] = {
89 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
90 PWM2 | (MAP_TO_PWM_INPUT << 8),
91 PWM3 | (MAP_TO_PWM_INPUT << 8),
92 PWM4 | (MAP_TO_PWM_INPUT << 8),
93 PWM5 | (MAP_TO_PWM_INPUT << 8),
94 PWM6 | (MAP_TO_PWM_INPUT << 8),
95 PWM7 | (MAP_TO_PWM_INPUT << 8),
96 PWM8 | (MAP_TO_PWM_INPUT << 8), // input #8
97 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or servo #1 (swap to servo if needed)
98 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2 or servo #2 (swap to servo if needed)
99 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or #3
100 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
101 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
102 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4 or #6
103 0xFFFF
106 static const uint16_t airPPM[] = {
107 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
108 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
109 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
110 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
111 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
112 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
113 PWM14 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
114 PWM5 | (MAP_TO_SERVO_OUTPUT << 8), // servo #5
115 PWM6 | (MAP_TO_SERVO_OUTPUT << 8),
116 PWM7 | (MAP_TO_SERVO_OUTPUT << 8),
117 PWM8 | (MAP_TO_SERVO_OUTPUT << 8), // servo #8
118 0xFFFF
121 static const uint16_t airPWM[] = {
122 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
123 PWM2 | (MAP_TO_PWM_INPUT << 8),
124 PWM3 | (MAP_TO_PWM_INPUT << 8),
125 PWM4 | (MAP_TO_PWM_INPUT << 8),
126 PWM5 | (MAP_TO_PWM_INPUT << 8),
127 PWM6 | (MAP_TO_PWM_INPUT << 8),
128 PWM7 | (MAP_TO_PWM_INPUT << 8),
129 PWM8 | (MAP_TO_PWM_INPUT << 8), // input #8
130 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
131 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
132 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
133 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
134 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
135 PWM14 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
136 0xFFFF
138 #endif
140 #ifdef CC3D
141 static const uint16_t multiPPM[] = {
142 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
143 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
144 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
145 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
146 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
147 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
148 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
149 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
150 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
151 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
152 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
153 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
154 0xFFFF
156 static const uint16_t multiPWM[] = {
157 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
158 PWM2 | (MAP_TO_PWM_INPUT << 8),
159 PWM3 | (MAP_TO_PWM_INPUT << 8),
160 PWM4 | (MAP_TO_PWM_INPUT << 8),
161 PWM5 | (MAP_TO_PWM_INPUT << 8),
162 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
163 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or servo #1 (swap to servo if needed)
164 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2 or servo #2 (swap to servo if needed)
165 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or #3
166 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
167 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
168 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4 or #6
169 0xFFFF
172 static const uint16_t airPPM[] = {
173 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
174 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
175 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
176 PWM9 | (MAP_TO_SERVO_OUTPUT << 8),
177 PWM10 | (MAP_TO_SERVO_OUTPUT << 8),
178 PWM11 | (MAP_TO_SERVO_OUTPUT << 8),
179 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
180 PWM2 | (MAP_TO_SERVO_OUTPUT << 8),
181 PWM3 | (MAP_TO_SERVO_OUTPUT << 8),
182 PWM4 | (MAP_TO_SERVO_OUTPUT << 8),
183 PWM5 | (MAP_TO_SERVO_OUTPUT << 8),
184 PWM6 | (MAP_TO_SERVO_OUTPUT << 8),
185 0xFFFF
188 static const uint16_t airPWM[] = {
189 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
190 PWM2 | (MAP_TO_PWM_INPUT << 8),
191 PWM3 | (MAP_TO_PWM_INPUT << 8),
192 PWM4 | (MAP_TO_PWM_INPUT << 8),
193 PWM5 | (MAP_TO_PWM_INPUT << 8),
194 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
195 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
196 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
197 PWM9 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
198 PWM10 | (MAP_TO_SERVO_OUTPUT << 8), // servo #2
199 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #3
200 PWM12 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
201 0xFFFF
203 #endif
205 #ifdef CJMCU
206 static const uint16_t multiPPM[] = {
207 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
208 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
209 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
210 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
211 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
212 0xFFFF
215 static const uint16_t multiPWM[] = {
216 PWM1 | (MAP_TO_PWM_INPUT << 8),
217 PWM2 | (MAP_TO_PWM_INPUT << 8),
218 PWM3 | (MAP_TO_PWM_INPUT << 8),
219 PWM4 | (MAP_TO_PWM_INPUT << 8),
220 PWM9 | (MAP_TO_PWM_INPUT << 8),
221 PWM10 | (MAP_TO_PWM_INPUT << 8),
222 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
223 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
224 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
225 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
226 0xFFFF
229 static const uint16_t airPPM[] = {
230 0xFFFF
233 static const uint16_t airPWM[] = {
234 0xFFFF
236 #endif
238 #ifdef SPARKY
239 static const uint16_t multiPPM[] = {
240 PWM11 | (MAP_TO_PPM_INPUT << 8), // PPM input
242 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM15
243 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM15
244 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM1
245 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
246 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
247 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM2
248 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
249 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM17
250 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
251 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM2
252 0xFFFF
255 static const uint16_t multiPWM[] = {
256 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8),
257 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
258 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
259 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
260 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
261 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8),
262 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
263 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
264 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
265 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
266 0xFFFF
269 static const uint16_t airPPM[] = {
270 // TODO
271 0xFFFF
274 static const uint16_t airPWM[] = {
275 // TODO
276 0xFFFF
279 #endif
282 #ifdef SPRACINGF3
283 static const uint16_t multiPPM[] = {
284 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
286 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
287 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
288 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
289 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
290 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
291 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
292 PWM15 | (MAP_TO_MOTOR_OUTPUT << 8),
293 PWM16 | (MAP_TO_MOTOR_OUTPUT << 8),
294 0xFFFF
297 static const uint16_t multiPWM[] = {
298 PWM1 | (MAP_TO_PWM_INPUT << 8),
299 PWM2 | (MAP_TO_PWM_INPUT << 8),
300 PWM3 | (MAP_TO_PWM_INPUT << 8),
301 PWM4 | (MAP_TO_PWM_INPUT << 8),
302 PWM5 | (MAP_TO_PWM_INPUT << 8),
303 PWM6 | (MAP_TO_PWM_INPUT << 8),
304 PWM7 | (MAP_TO_PWM_INPUT << 8),
305 PWM8 | (MAP_TO_PWM_INPUT << 8),
306 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
307 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
308 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
309 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
310 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
311 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
312 PWM15 | (MAP_TO_MOTOR_OUTPUT << 8),
313 PWM16 | (MAP_TO_MOTOR_OUTPUT << 8),
314 0xFFFF
317 static const uint16_t airPPM[] = {
318 // TODO
319 0xFFFF
322 static const uint16_t airPWM[] = {
323 // TODO
324 0xFFFF
326 #endif
328 static const uint16_t * const hardwareMaps[] = {
329 multiPWM,
330 multiPPM,
331 airPWM,
332 airPPM,
335 pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
337 int i = 0;
338 const uint16_t *setup;
340 int channelIndex = 0;
342 static pwmOutputConfiguration_t pwmOutputConfiguration;
344 memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration));
346 // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ]
347 if (init->airplane)
348 i = 2; // switch to air hardware config
349 if (init->usePPM || init->useSerialRx)
350 i++; // next index is for PPM
352 setup = hardwareMaps[i];
354 for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT; i++) {
355 uint8_t timerIndex = setup[i] & 0x00FF;
356 uint8_t type = (setup[i] & 0xFF00) >> 8;
358 if (setup[i] == 0xFFFF) // terminator
359 break;
361 const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
363 #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER
364 // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E
365 if (timerIndex == PWM2)
366 continue;
367 #endif
369 #ifdef STM32F10X
370 // skip UART2 ports
371 if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4))
372 continue;
373 #endif
375 #ifdef SOFTSERIAL_1_TIMER
376 if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER)
377 continue;
378 #endif
379 #ifdef SOFTSERIAL_2_TIMER
380 if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER)
381 continue;
382 #endif
384 #ifdef LED_STRIP_TIMER
385 // skip LED Strip output
386 if (init->useLEDStrip) {
387 if (timerHardwarePtr->tim == LED_STRIP_TIMER)
388 continue;
389 #if defined(STM32F303xC) && defined(WS2811_GPIO) && defined(WS2811_PIN_SOURCE)
390 if (timerHardwarePtr->gpio == WS2811_GPIO && timerHardwarePtr->gpioPinSource == WS2811_PIN_SOURCE)
391 continue;
392 #endif
395 #endif
397 #ifdef VBAT_ADC_GPIO
398 if (init->useVbat && timerHardwarePtr->gpio == VBAT_ADC_GPIO && timerHardwarePtr->pin == VBAT_ADC_GPIO_PIN) {
399 continue;
401 #endif
403 #ifdef RSSI_ADC_GPIO
404 if (init->useRSSIADC && timerHardwarePtr->gpio == RSSI_ADC_GPIO && timerHardwarePtr->pin == RSSI_ADC_GPIO_PIN) {
405 continue;
407 #endif
409 #ifdef CURRENT_METER_ADC_GPIO
410 if (init->useCurrentMeterADC && timerHardwarePtr->gpio == CURRENT_METER_ADC_GPIO && timerHardwarePtr->pin == CURRENT_METER_ADC_GPIO_PIN) {
411 continue;
413 #endif
415 // hacks to allow current functionality
416 if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM)
417 continue;
419 if (type == MAP_TO_PPM_INPUT && !init->usePPM)
420 continue;
422 if (init->useServos && !init->airplane) {
423 #if defined(NAZE)
424 // remap PWM9+10 as servos
425 if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1)
426 type = MAP_TO_SERVO_OUTPUT;
427 #endif
429 #if defined(SPARKY)
430 // remap PWM1+2 as servos
431 if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15)
432 type = MAP_TO_SERVO_OUTPUT;
433 #endif
435 #if defined(SPRACINGF3)
436 // remap PWM15+16 as servos
437 if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15)
438 type = MAP_TO_SERVO_OUTPUT;
439 #endif
441 #if defined(NAZE32PRO) || (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3))
442 // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer
443 if (init->useSoftSerial) {
444 if (timerIndex == PWM5 || timerIndex == PWM6)
445 type = MAP_TO_SERVO_OUTPUT;
446 } else {
447 if (timerIndex == PWM9 || timerIndex == PWM10)
448 type = MAP_TO_SERVO_OUTPUT;
450 #endif
453 if (init->extraServos && !init->airplane) {
454 // remap PWM5..8 as servos when used in extended servo mode
455 if (timerIndex >= PWM5 && timerIndex <= PWM8)
456 type = MAP_TO_SERVO_OUTPUT;
459 #ifdef CC3D
460 if (init->useParallelPWM) {
461 // Skip PWM inputs that conflict with timers used outputs.
462 if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) {
463 continue;
465 if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) {
466 continue;
470 #endif
472 if (type == MAP_TO_PPM_INPUT) {
473 #ifdef CC3D
474 if (init->useOneshot) {
475 ppmAvoidPWMTimerClash(timerHardwarePtr, TIM4);
477 #endif
478 ppmInConfig(timerHardwarePtr);
479 } else if (type == MAP_TO_PWM_INPUT) {
480 pwmInConfig(timerHardwarePtr, channelIndex);
481 channelIndex++;
482 } else if (type == MAP_TO_MOTOR_OUTPUT) {
483 if (init->useOneshot) {
484 pwmOneshotMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->idlePulse);
485 } else if (init->motorPwmRate > 500) {
486 pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
487 } else {
488 pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
490 pwmOutputConfiguration.motorCount++;
491 } else if (type == MAP_TO_SERVO_OUTPUT) {
492 pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse);
493 pwmOutputConfiguration.servoCount++;
497 return &pwmOutputConfiguration;