Fix oneshot kills RX_PPM
[betaflight.git] / src / main / drivers / pwm_mapping.c
blob1ff82ccb844cb5989f22eec60756d512767a0d0f
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 void pwmBrushedMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse);
33 void pwmBrushlessMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse);
34 void fastPWMMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, uint16_t motorPwmRate, uint16_t idlePulse);
35 void pwmOneshotMotorConfig(const timerHardware_t *timerHardware, uint8_t motorIndex);
36 void pwmServoConfig(const timerHardware_t *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
39 Configuration maps
41 Note: this documentation is only valid for STM32F10x, for STM32F30x please read the code itself.
43 1) multirotor PPM input
44 PWM1 used for PPM
45 PWM5..8 used for motors
46 PWM9..10 used for servo or else motors
47 PWM11..14 used for motors
49 2) multirotor PPM input with more servos
50 PWM1 used for PPM
51 PWM5..8 used for motors
52 PWM9..10 used for servo or else motors
53 PWM11..14 used for servos
55 2) multirotor PWM input
56 PWM1..8 used for input
57 PWM9..10 used for servo or else motors
58 PWM11..14 used for motors
60 3) airplane / flying wing w/PWM
61 PWM1..8 used for input
62 PWM9 used for motor throttle +PWM10 for 2nd motor
63 PWM11.14 used for servos
65 4) airplane / flying wing with PPM
66 PWM1 used for PPM
67 PWM5..8 used for servos
68 PWM9 used for motor throttle +PWM10 for 2nd motor
69 PWM11.14 used for servos
72 enum {
73 MAP_TO_PPM_INPUT = 1,
74 MAP_TO_PWM_INPUT,
75 MAP_TO_MOTOR_OUTPUT,
76 MAP_TO_SERVO_OUTPUT,
79 #if defined(NAZE) || defined(OLIMEXINO) || defined(NAZE32PRO) || defined(STM32F3DISCOVERY) || defined(EUSTM32F103RC) || defined(PORT103R)
80 static const uint16_t multiPPM[] = {
81 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
82 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
83 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
84 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
85 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
86 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
87 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
88 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
89 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
90 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
91 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
92 0xFFFF
95 static const uint16_t multiPWM[] = {
96 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
97 PWM2 | (MAP_TO_PWM_INPUT << 8),
98 PWM3 | (MAP_TO_PWM_INPUT << 8),
99 PWM4 | (MAP_TO_PWM_INPUT << 8),
100 PWM5 | (MAP_TO_PWM_INPUT << 8),
101 PWM6 | (MAP_TO_PWM_INPUT << 8),
102 PWM7 | (MAP_TO_PWM_INPUT << 8),
103 PWM8 | (MAP_TO_PWM_INPUT << 8), // input #8
104 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or servo #1 (swap to servo if needed)
105 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2 or servo #2 (swap to servo if needed)
106 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or #3
107 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
108 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
109 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4 or #6
110 0xFFFF
113 static const uint16_t airPPM[] = {
114 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
115 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
116 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
117 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
118 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
119 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
120 PWM14 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
121 PWM5 | (MAP_TO_SERVO_OUTPUT << 8), // servo #5
122 PWM6 | (MAP_TO_SERVO_OUTPUT << 8),
123 PWM7 | (MAP_TO_SERVO_OUTPUT << 8),
124 PWM8 | (MAP_TO_SERVO_OUTPUT << 8), // servo #8
125 0xFFFF
128 static const uint16_t airPWM[] = {
129 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
130 PWM2 | (MAP_TO_PWM_INPUT << 8),
131 PWM3 | (MAP_TO_PWM_INPUT << 8),
132 PWM4 | (MAP_TO_PWM_INPUT << 8),
133 PWM5 | (MAP_TO_PWM_INPUT << 8),
134 PWM6 | (MAP_TO_PWM_INPUT << 8),
135 PWM7 | (MAP_TO_PWM_INPUT << 8),
136 PWM8 | (MAP_TO_PWM_INPUT << 8), // input #8
137 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
138 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
139 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
140 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
141 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
142 PWM14 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
143 0xFFFF
145 #endif
147 #ifdef CC3D
148 static const uint16_t multiPPM[] = {
149 PWM6 | (MAP_TO_PPM_INPUT << 8), // PPM input
150 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
151 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
152 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #3
153 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4
154 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
155 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
156 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
157 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
158 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
159 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
160 0xFFFF
163 static const uint16_t multiPWM[] = {
164 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
165 PWM2 | (MAP_TO_PWM_INPUT << 8),
166 PWM3 | (MAP_TO_PWM_INPUT << 8),
167 PWM4 | (MAP_TO_PWM_INPUT << 8),
168 PWM5 | (MAP_TO_PWM_INPUT << 8),
169 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
170 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or servo #1 (swap to servo if needed)
171 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2 or servo #2 (swap to servo if needed)
172 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or #3
173 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
174 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
175 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4 or #6
176 0xFFFF
179 static const uint16_t airPPM[] = {
180 PWM6 | (MAP_TO_PPM_INPUT << 8), // PPM input
181 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
182 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
183 PWM9 | (MAP_TO_SERVO_OUTPUT << 8),
184 PWM10 | (MAP_TO_SERVO_OUTPUT << 8),
185 PWM11 | (MAP_TO_SERVO_OUTPUT << 8),
186 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
187 PWM2 | (MAP_TO_SERVO_OUTPUT << 8),
188 PWM3 | (MAP_TO_SERVO_OUTPUT << 8),
189 PWM4 | (MAP_TO_SERVO_OUTPUT << 8),
190 PWM5 | (MAP_TO_SERVO_OUTPUT << 8),
191 0xFFFF
194 static const uint16_t airPWM[] = {
195 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
196 PWM2 | (MAP_TO_PWM_INPUT << 8),
197 PWM3 | (MAP_TO_PWM_INPUT << 8),
198 PWM4 | (MAP_TO_PWM_INPUT << 8),
199 PWM5 | (MAP_TO_PWM_INPUT << 8),
200 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
201 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
202 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
203 PWM9 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
204 PWM10 | (MAP_TO_SERVO_OUTPUT << 8), // servo #2
205 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #3
206 PWM12 | (MAP_TO_SERVO_OUTPUT << 8), // servo #4
207 0xFFFF
209 static const uint16_t multiPPM_BP6[] = {
210 PWM6 | (MAP_TO_PPM_INPUT << 8), // PPM input
211 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
212 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
213 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #3
214 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #4
215 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
216 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
217 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
218 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
219 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
220 0xFFFF
223 static const uint16_t multiPWM_BP6[] = {
224 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
225 PWM2 | (MAP_TO_PWM_INPUT << 8),
226 PWM3 | (MAP_TO_PWM_INPUT << 8),
227 PWM4 | (MAP_TO_PWM_INPUT << 8),
228 PWM5 | (MAP_TO_PWM_INPUT << 8),
229 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
230 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or servo #1 (swap to servo if needed)
231 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2 or servo #2 (swap to servo if needed)
232 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1 or #3
233 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
234 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
235 0xFFFF
238 static const uint16_t airPPM_BP6[] = {
239 PWM6 | (MAP_TO_PPM_INPUT << 8), // PPM input
240 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
241 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
242 PWM9 | (MAP_TO_SERVO_OUTPUT << 8),
243 PWM10 | (MAP_TO_SERVO_OUTPUT << 8),
244 PWM11 | (MAP_TO_SERVO_OUTPUT << 8),
245 PWM2 | (MAP_TO_SERVO_OUTPUT << 8),
246 PWM3 | (MAP_TO_SERVO_OUTPUT << 8),
247 PWM4 | (MAP_TO_SERVO_OUTPUT << 8),
248 PWM5 | (MAP_TO_SERVO_OUTPUT << 8),
249 0xFFFF
252 static const uint16_t airPWM_BP6[] = {
253 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
254 PWM2 | (MAP_TO_PWM_INPUT << 8),
255 PWM3 | (MAP_TO_PWM_INPUT << 8),
256 PWM4 | (MAP_TO_PWM_INPUT << 8),
257 PWM5 | (MAP_TO_PWM_INPUT << 8),
258 PWM6 | (MAP_TO_PWM_INPUT << 8), // input #6
259 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
260 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
261 PWM9 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
262 PWM10 | (MAP_TO_SERVO_OUTPUT << 8), // servo #2
263 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #3
264 0xFFFF
266 #endif
268 #ifdef CJMCU
269 static const uint16_t multiPPM[] = {
270 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
271 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
272 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
273 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
274 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
275 0xFFFF
278 static const uint16_t multiPWM[] = {
279 PWM1 | (MAP_TO_PWM_INPUT << 8),
280 PWM2 | (MAP_TO_PWM_INPUT << 8),
281 PWM3 | (MAP_TO_PWM_INPUT << 8),
282 PWM4 | (MAP_TO_PWM_INPUT << 8),
283 PWM9 | (MAP_TO_PWM_INPUT << 8),
284 PWM10 | (MAP_TO_PWM_INPUT << 8),
285 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
286 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
287 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
288 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
289 0xFFFF
292 static const uint16_t airPPM[] = {
293 0xFFFF
296 static const uint16_t airPWM[] = {
297 0xFFFF
299 #endif
301 #if defined(COLIBRI_RACE) || defined(LUX_RACE)
302 static const uint16_t multiPPM[] = {
303 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
304 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
305 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
306 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
307 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
308 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
309 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
310 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
311 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
312 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
313 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
314 0xFFFF
317 static const uint16_t multiPWM[] = {
318 // prevent crashing, but do nothing
319 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
320 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
321 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
322 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
323 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
324 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
325 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
326 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
327 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
328 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
329 0xFFFF
332 static const uint16_t airPPM[] = {
333 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
334 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
335 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
336 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
337 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
338 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
339 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
340 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
341 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
342 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
343 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
344 0xFFFF
347 static const uint16_t airPWM[] = {
348 // prevent crashing, but do nothing
349 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
350 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
351 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
352 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
353 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
354 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
355 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
356 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
357 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
358 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
359 0xFFFF
361 #endif
363 #if defined(SPARKY) || defined(ALIENFLIGHTF3)
364 static const uint16_t multiPPM[] = {
365 PWM11 | (MAP_TO_PPM_INPUT << 8), // PPM input
367 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM15
368 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM15
369 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM1
370 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
371 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
372 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM2
373 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
374 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM17
375 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM3
376 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // TIM2
377 0xFFFF
380 static const uint16_t multiPWM[] = {
381 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8),
382 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
383 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
384 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
385 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
386 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8),
387 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
388 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
389 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
390 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
391 0xFFFF
394 static const uint16_t airPPM[] = {
395 // TODO
396 0xFFFF
399 static const uint16_t airPWM[] = {
400 // TODO
401 0xFFFF
403 #endif
405 #ifdef SPRACINGF3
406 static const uint16_t multiPPM[] = {
407 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
409 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
410 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
411 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
412 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
413 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
414 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
415 PWM15 | (MAP_TO_MOTOR_OUTPUT << 8),
416 PWM16 | (MAP_TO_MOTOR_OUTPUT << 8),
417 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
418 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
419 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
420 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8), // Swap to servo if needed
421 0xFFFF
424 static const uint16_t multiPWM[] = {
425 PWM1 | (MAP_TO_PWM_INPUT << 8),
426 PWM2 | (MAP_TO_PWM_INPUT << 8),
427 PWM3 | (MAP_TO_PWM_INPUT << 8),
428 PWM4 | (MAP_TO_PWM_INPUT << 8),
429 PWM5 | (MAP_TO_PWM_INPUT << 8),
430 PWM6 | (MAP_TO_PWM_INPUT << 8),
431 PWM7 | (MAP_TO_PWM_INPUT << 8),
432 PWM8 | (MAP_TO_PWM_INPUT << 8),
433 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
434 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
435 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
436 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
437 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
438 PWM14 | (MAP_TO_MOTOR_OUTPUT << 8),
439 PWM15 | (MAP_TO_MOTOR_OUTPUT << 8),
440 PWM16 | (MAP_TO_MOTOR_OUTPUT << 8),
441 0xFFFF
444 static const uint16_t airPPM[] = {
445 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
446 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
447 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
448 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
449 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
450 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
451 PWM14 | (MAP_TO_SERVO_OUTPUT << 8),
452 PWM15 | (MAP_TO_SERVO_OUTPUT << 8),
453 PWM16 | (MAP_TO_SERVO_OUTPUT << 8),
454 PWM5 | (MAP_TO_SERVO_OUTPUT << 8),
455 PWM6 | (MAP_TO_SERVO_OUTPUT << 8),
456 PWM7 | (MAP_TO_SERVO_OUTPUT << 8),
457 PWM8 | (MAP_TO_SERVO_OUTPUT << 8), // servo #10
458 0xFFFF
461 static const uint16_t airPWM[] = {
462 PWM1 | (MAP_TO_PWM_INPUT << 8), // input #1
463 PWM2 | (MAP_TO_PWM_INPUT << 8),
464 PWM3 | (MAP_TO_PWM_INPUT << 8),
465 PWM4 | (MAP_TO_PWM_INPUT << 8),
466 PWM5 | (MAP_TO_PWM_INPUT << 8),
467 PWM6 | (MAP_TO_PWM_INPUT << 8),
468 PWM7 | (MAP_TO_PWM_INPUT << 8),
469 PWM8 | (MAP_TO_PWM_INPUT << 8), // input #8
470 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
471 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
472 PWM11 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
473 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
474 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
475 PWM14 | (MAP_TO_SERVO_OUTPUT << 8),
476 PWM15 | (MAP_TO_SERVO_OUTPUT << 8),
477 PWM16 | (MAP_TO_SERVO_OUTPUT << 8), // server #6
478 0xFFFF
480 #endif
482 #if defined(MOTOLAB)
483 static const uint16_t multiPPM[] = {
484 PWM9 | (MAP_TO_PPM_INPUT << 8), // PPM input
486 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8),
487 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
488 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
489 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
490 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
491 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8),
492 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
493 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
494 0xFFFF
497 static const uint16_t multiPWM[] = {
498 PWM1 | (MAP_TO_MOTOR_OUTPUT << 8),
499 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
500 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
501 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
502 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
503 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8),
504 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
505 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
506 0xFFFF
509 static const uint16_t airPPM[] = {
510 // TODO
511 0xFFFF
514 static const uint16_t airPWM[] = {
515 // TODO
516 0xFFFF
518 #endif
520 #ifdef SPRACINGF3MINI
521 static const uint16_t multiPPM[] = {
522 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
524 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8),
525 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8),
526 PWM6 | (MAP_TO_MOTOR_OUTPUT << 8),
527 PWM7 | (MAP_TO_MOTOR_OUTPUT << 8),
528 PWM8 | (MAP_TO_MOTOR_OUTPUT << 8),
529 PWM9 | (MAP_TO_MOTOR_OUTPUT << 8),
530 PWM10 | (MAP_TO_MOTOR_OUTPUT << 8),
531 PWM11 | (MAP_TO_MOTOR_OUTPUT << 8),
532 PWM12 | (MAP_TO_MOTOR_OUTPUT << 8),
533 PWM13 | (MAP_TO_MOTOR_OUTPUT << 8),
534 PWM2 | (MAP_TO_MOTOR_OUTPUT << 8),
535 PWM3 | (MAP_TO_MOTOR_OUTPUT << 8),
536 0xFFFF
539 static const uint16_t multiPWM[] = {
540 0xFFFF
543 static const uint16_t airPPM[] = {
544 PWM1 | (MAP_TO_PPM_INPUT << 8), // PPM input
545 PWM4 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #1
546 PWM5 | (MAP_TO_MOTOR_OUTPUT << 8), // motor #2
547 PWM6 | (MAP_TO_SERVO_OUTPUT << 8), // servo #1
548 PWM7 | (MAP_TO_SERVO_OUTPUT << 8),
549 PWM8 | (MAP_TO_SERVO_OUTPUT << 8),
550 PWM9 | (MAP_TO_SERVO_OUTPUT << 8),
551 PWM10 | (MAP_TO_SERVO_OUTPUT << 8),
552 PWM11 | (MAP_TO_SERVO_OUTPUT << 8),
553 PWM12 | (MAP_TO_SERVO_OUTPUT << 8),
554 PWM13 | (MAP_TO_SERVO_OUTPUT << 8),
555 PWM2 | (MAP_TO_SERVO_OUTPUT << 8),
556 PWM3 | (MAP_TO_SERVO_OUTPUT << 8), // servo #10
557 0xFFFF
560 static const uint16_t airPWM[] = {
561 0xFFFF
563 #endif
565 static const uint16_t * const hardwareMaps[] = {
566 multiPWM,
567 multiPPM,
568 airPWM,
569 airPPM,
572 #ifdef CC3D
573 static const uint16_t * const hardwareMapsBP6[] = {
574 multiPWM_BP6,
575 multiPPM_BP6,
576 airPWM_BP6,
577 airPPM_BP6,
579 #endif
581 static pwmOutputConfiguration_t pwmOutputConfiguration;
583 pwmOutputConfiguration_t *pwmGetOutputConfiguration(void){
584 return &pwmOutputConfiguration;
586 pwmOutputConfiguration_t *pwmInit(drv_pwm_config_t *init)
588 int i = 0;
589 const uint16_t *setup;
591 int channelIndex = 0;
594 memset(&pwmOutputConfiguration, 0, sizeof(pwmOutputConfiguration));
596 // this is pretty hacky shit, but it will do for now. array of 4 config maps, [ multiPWM multiPPM airPWM airPPM ]
597 if (init->airplane)
598 i = 2; // switch to air hardware config
599 if (init->usePPM || init->useSerialRx)
600 i++; // next index is for PPM
602 #ifdef CC3D
603 if (init->useBuzzerP6) {
604 setup = hardwareMapsBP6[i];
605 } else {
606 setup = hardwareMaps[i];
608 #else
609 setup = hardwareMaps[i];
610 #endif
612 for (i = 0; i < USABLE_TIMER_CHANNEL_COUNT && setup[i] != 0xFFFF; i++) {
613 uint8_t timerIndex = setup[i] & 0x00FF;
614 uint8_t type = (setup[i] & 0xFF00) >> 8;
616 const timerHardware_t *timerHardwarePtr = &timerHardware[timerIndex];
618 #ifdef OLIMEXINO_UNCUT_LED2_E_JUMPER
619 // PWM2 is connected to LED2 on the board and cannot be connected unless you cut LED2_E
620 if (timerIndex == PWM2)
621 continue;
622 #endif
624 #ifdef STM32F10X
625 // skip UART2 ports
626 if (init->useUART2 && (timerIndex == PWM3 || timerIndex == PWM4))
627 continue;
628 #endif
630 #if defined(STM32F303xC) && defined(USE_USART3)
631 // skip UART3 ports (PB10/PB11)
632 if (init->useUART3 && timerHardwarePtr->gpio == UART3_GPIO && (timerHardwarePtr->pin == UART3_TX_PIN || timerHardwarePtr->pin == UART3_RX_PIN))
633 continue;
634 #endif
636 #ifdef SOFTSERIAL_1_TIMER
637 if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_1_TIMER)
638 continue;
639 #endif
640 #ifdef SOFTSERIAL_2_TIMER
641 if (init->useSoftSerial && timerHardwarePtr->tim == SOFTSERIAL_2_TIMER)
642 continue;
643 #endif
645 #ifdef LED_STRIP_TIMER
646 // skip LED Strip output
647 if (init->useLEDStrip) {
648 if (timerHardwarePtr->tim == LED_STRIP_TIMER)
649 continue;
650 #if defined(STM32F303xC) && defined(WS2811_GPIO) && defined(WS2811_PIN_SOURCE)
651 if (timerHardwarePtr->gpio == WS2811_GPIO && timerHardwarePtr->gpioPinSource == WS2811_PIN_SOURCE)
652 continue;
653 #endif
656 #endif
658 #ifdef VBAT_ADC_GPIO
659 if (init->useVbat && timerHardwarePtr->gpio == VBAT_ADC_GPIO && timerHardwarePtr->pin == VBAT_ADC_GPIO_PIN) {
660 continue;
662 #endif
664 #ifdef RSSI_ADC_GPIO
665 if (init->useRSSIADC && timerHardwarePtr->gpio == RSSI_ADC_GPIO && timerHardwarePtr->pin == RSSI_ADC_GPIO_PIN) {
666 continue;
668 #endif
670 #ifdef CURRENT_METER_ADC_GPIO
671 if (init->useCurrentMeterADC && timerHardwarePtr->gpio == CURRENT_METER_ADC_GPIO && timerHardwarePtr->pin == CURRENT_METER_ADC_GPIO_PIN) {
672 continue;
674 #endif
676 #ifdef SONAR
677 if (init->sonarGPIOConfig && timerHardwarePtr->gpio == init->sonarGPIOConfig->gpio &&
679 timerHardwarePtr->pin == init->sonarGPIOConfig->triggerPin ||
680 timerHardwarePtr->pin == init->sonarGPIOConfig->echoPin
683 continue;
685 #endif
687 // hacks to allow current functionality
688 if (type == MAP_TO_PWM_INPUT && !init->useParallelPWM)
689 continue;
691 if (type == MAP_TO_PPM_INPUT && !init->usePPM)
692 continue;
694 #ifdef USE_SERVOS
695 if (init->useServos && !init->airplane) {
696 #if defined(NAZE)
697 // remap PWM9+10 as servos
698 if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1)
699 type = MAP_TO_SERVO_OUTPUT;
700 #endif
702 #if defined(COLIBRI_RACE) || defined(LUX_RACE)
703 // remap PWM1+2 as servos
704 if ((timerIndex == PWM6 || timerIndex == PWM7 || timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM2)
705 type = MAP_TO_SERVO_OUTPUT;
706 #endif
708 #if defined(CC3D)
709 // remap PWM9+10 as servos
710 if ((timerIndex == PWM9 || timerIndex == PWM10) && timerHardwarePtr->tim == TIM1)
711 type = MAP_TO_SERVO_OUTPUT;
712 #endif
714 #if defined(SPARKY)
715 // remap PWM1+2 as servos
716 if ((timerIndex == PWM1 || timerIndex == PWM2) && timerHardwarePtr->tim == TIM15)
717 type = MAP_TO_SERVO_OUTPUT;
718 #endif
720 #if defined(SPRACINGF3)
721 // remap PWM15+16 as servos
722 if ((timerIndex == PWM15 || timerIndex == PWM16) && timerHardwarePtr->tim == TIM15)
723 type = MAP_TO_SERVO_OUTPUT;
724 #endif
726 #if defined(SPRACINGF3MINI)
727 // remap PWM8+9 as servos
728 if ((timerIndex == PWM8 || timerIndex == PWM9) && timerHardwarePtr->tim == TIM15)
729 type = MAP_TO_SERVO_OUTPUT;
730 #endif
732 #if defined(NAZE32PRO) || (defined(STM32F3DISCOVERY) && !defined(CHEBUZZF3))
733 // remap PWM 5+6 or 9+10 as servos - softserial pin pairs require timer ports that use the same timer
734 if (init->useSoftSerial) {
735 if (timerIndex == PWM5 || timerIndex == PWM6)
736 type = MAP_TO_SERVO_OUTPUT;
737 } else {
738 if (timerIndex == PWM9 || timerIndex == PWM10)
739 type = MAP_TO_SERVO_OUTPUT;
741 #endif
743 #if defined(MOTOLAB)
744 // remap PWM 7+8 as servos
745 if (timerIndex == PWM7 || timerIndex == PWM8)
746 type = MAP_TO_SERVO_OUTPUT;
747 #endif
750 if (init->useChannelForwarding && !init->airplane) {
751 #if defined(NAZE) && defined(LED_STRIP_TIMER)
752 // if LED strip is active, PWM5-8 are unavailable, so map AUX1+AUX2 to PWM13+PWM14
753 if (init->useLEDStrip) {
754 if (timerIndex >= PWM13 && timerIndex <= PWM14) {
755 type = MAP_TO_SERVO_OUTPUT;
757 } else
758 #endif
760 #if defined(SPRACINGF3) || defined(NAZE)
761 // remap PWM5..8 as servos when used in extended servo mode
762 if (timerIndex >= PWM5 && timerIndex <= PWM8)
763 type = MAP_TO_SERVO_OUTPUT;
764 #endif
767 #endif // USE_SERVOS
769 #ifdef CC3D
770 if (init->useParallelPWM) {
771 // Skip PWM inputs that conflict with timers used outputs.
772 if ((type == MAP_TO_SERVO_OUTPUT || type == MAP_TO_MOTOR_OUTPUT) && (timerHardwarePtr->tim == TIM2 || timerHardwarePtr->tim == TIM3)) {
773 continue;
775 if (type == MAP_TO_PWM_INPUT && timerHardwarePtr->tim == TIM4) {
776 continue;
780 #endif
782 if (type == MAP_TO_PPM_INPUT) {
783 #ifdef SPARKY
784 if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) {
785 ppmAvoidPWMTimerClash(timerHardwarePtr, TIM2);
787 #endif
788 #ifdef SPRACINGF3MINI
789 if (init->useOneshot || isMotorBrushed(init->motorPwmRate)) {
790 ppmAvoidPWMTimerClash(timerHardwarePtr, TIM3);
792 #endif
793 ppmInConfig(timerHardwarePtr);
794 } else if (type == MAP_TO_PWM_INPUT) {
795 pwmInConfig(timerHardwarePtr, channelIndex);
796 channelIndex++;
797 } else if (type == MAP_TO_MOTOR_OUTPUT) {
799 #ifdef CC3D
800 if (init->useOneshot || isMotorBrushed(init->motorPwmRate)){
801 // Skip it if it would cause PPM capture timer to be reconfigured or manually overflowed
802 if (timerHardwarePtr->tim == TIM2)
803 continue;
805 #endif
806 if (init->useOneshot) {
807 if (init->useFastPWM) {
808 fastPWMMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
809 } else {
810 pwmOneshotMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount);
812 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_ONESHOT|PWM_PF_OUTPUT_PROTOCOL_PWM ;
813 } else if (isMotorBrushed(init->motorPwmRate)) {
814 pwmBrushedMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
815 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_MOTOR_MODE_BRUSHED | PWM_PF_OUTPUT_PROTOCOL_PWM;
816 } else {
817 pwmBrushlessMotorConfig(timerHardwarePtr, pwmOutputConfiguration.motorCount, init->motorPwmRate, init->idlePulse);
818 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_MOTOR | PWM_PF_OUTPUT_PROTOCOL_PWM ;
820 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.motorCount;
821 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].timerHardware = timerHardwarePtr;
822 pwmOutputConfiguration.motorCount++;
823 pwmOutputConfiguration.outputCount++;
824 } else if (type == MAP_TO_SERVO_OUTPUT) {
825 #ifdef USE_SERVOS
826 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].index = pwmOutputConfiguration.servoCount;
827 pwmServoConfig(timerHardwarePtr, pwmOutputConfiguration.servoCount, init->servoPwmRate, init->servoCenterPulse);
828 pwmOutputConfiguration.portConfigurations[pwmOutputConfiguration.outputCount].flags = PWM_PF_SERVO | PWM_PF_OUTPUT_PROTOCOL_PWM;
829 pwmOutputConfiguration.servoCount++;
830 pwmOutputConfiguration.outputCount++;
831 #endif
835 return &pwmOutputConfiguration;