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/>.
24 #if !defined(SITL_BUILD)
26 #include "build/debug.h"
27 #include "common/log.h"
28 #include "common/memory.h"
30 #include "config/feature.h"
32 #include "fc/config.h"
34 #include "drivers/io.h"
35 #include "drivers/io_impl.h"
36 #include "drivers/timer.h"
37 #include "drivers/pwm_output.h"
38 #include "drivers/pwm_mapping.h"
39 #include "drivers/serial.h"
40 #include "drivers/serial_uart.h"
42 #include "sensors/rangefinder.h"
44 #include "io/serial.h"
56 const timerHardware_t
* timMotors
[MAX_PWM_OUTPUTS
];
57 const timerHardware_t
* timServos
[MAX_PWM_OUTPUTS
];
58 } timMotorServoHardware_t
;
60 static pwmInitError_e pwmInitError
= PWM_INIT_ERROR_NONE
;
62 static const char * pwmInitErrorMsg
[] = {
63 /* PWM_INIT_ERROR_NONE */ "No error",
64 /* PWM_INIT_ERROR_TOO_MANY_MOTORS */ "Mixer defines too many motors",
65 /* PWM_INIT_ERROR_TOO_MANY_SERVOS */ "Mixer defines too many servos",
66 /* PWM_INIT_ERROR_NOT_ENOUGH_MOTOR_OUTPUTS */ "Not enough motor outputs/timers",
67 /* PWM_INIT_ERROR_NOT_ENOUGH_SERVO_OUTPUTS */ "Not enough servo outputs/timers",
68 /* PWM_INIT_ERROR_TIMER_INIT_FAILED */ "Output timer init failed"
71 static const motorProtocolProperties_t motorProtocolProperties
[] = {
72 [PWM_TYPE_STANDARD
] = { .usesHwTimer
= true, .isDSHOT
= false },
73 [PWM_TYPE_ONESHOT125
] = { .usesHwTimer
= true, .isDSHOT
= false },
74 [PWM_TYPE_MULTISHOT
] = { .usesHwTimer
= true, .isDSHOT
= false },
75 [PWM_TYPE_BRUSHED
] = { .usesHwTimer
= true, .isDSHOT
= false },
76 [PWM_TYPE_DSHOT150
] = { .usesHwTimer
= true, .isDSHOT
= true },
77 [PWM_TYPE_DSHOT300
] = { .usesHwTimer
= true, .isDSHOT
= true },
78 [PWM_TYPE_DSHOT600
] = { .usesHwTimer
= true, .isDSHOT
= true },
81 pwmInitError_e
getPwmInitError(void)
86 const char * getPwmInitErrorMessage(void)
88 return pwmInitErrorMsg
[pwmInitError
];
91 const motorProtocolProperties_t
* getMotorProtocolProperties(motorPwmProtocolTypes_e proto
)
93 return &motorProtocolProperties
[proto
];
96 static bool checkPwmTimerConflicts(const timerHardware_t
*timHw
)
98 serialPortPins_t uartPins
;
100 #if defined(USE_UART2)
101 uartGetPortPins(UARTDEV_2
, &uartPins
);
102 if (doesConfigurationUsePort(SERIAL_PORT_USART2
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
107 #if defined(USE_UART3)
108 uartGetPortPins(UARTDEV_3
, &uartPins
);
109 if (doesConfigurationUsePort(SERIAL_PORT_USART3
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
114 #if defined(USE_UART4)
115 uartGetPortPins(UARTDEV_4
, &uartPins
);
116 if (doesConfigurationUsePort(SERIAL_PORT_USART4
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
121 #if defined(USE_UART5)
122 uartGetPortPins(UARTDEV_5
, &uartPins
);
123 if (doesConfigurationUsePort(SERIAL_PORT_USART5
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
128 #if defined(USE_UART6)
129 uartGetPortPins(UARTDEV_6
, &uartPins
);
130 if (doesConfigurationUsePort(SERIAL_PORT_USART6
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
135 #if defined(USE_UART7)
136 uartGetPortPins(UARTDEV_7
, &uartPins
);
137 if (doesConfigurationUsePort(SERIAL_PORT_USART7
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
142 #if defined(USE_UART8)
143 uartGetPortPins(UARTDEV_8
, &uartPins
);
144 if (doesConfigurationUsePort(SERIAL_PORT_USART8
) && (timHw
->tag
== uartPins
.txPin
|| timHw
->tag
== uartPins
.rxPin
)) {
149 #if defined(USE_SOFTSERIAL1)
150 if (feature(FEATURE_SOFTSERIAL
)) {
151 const timerHardware_t
*ssrx
= timerGetByTag(IO_TAG(SOFTSERIAL_1_RX_PIN
), TIM_USE_ANY
);
152 const timerHardware_t
*sstx
= timerGetByTag(IO_TAG(SOFTSERIAL_1_TX_PIN
), TIM_USE_ANY
);
153 if ((ssrx
!= NULL
&& ssrx
->tim
== timHw
->tim
) || (sstx
!= NULL
&& sstx
->tim
== timHw
->tim
)) {
159 #if defined(USE_SOFTSERIAL2)
160 if (feature(FEATURE_SOFTSERIAL
)) {
161 const timerHardware_t
*ssrx
= timerGetByTag(IO_TAG(SOFTSERIAL_2_RX_PIN
), TIM_USE_ANY
);
162 const timerHardware_t
*sstx
= timerGetByTag(IO_TAG(SOFTSERIAL_2_TX_PIN
), TIM_USE_ANY
);
163 if ((ssrx
!= NULL
&& ssrx
->tim
== timHw
->tim
) || (sstx
!= NULL
&& sstx
->tim
== timHw
->tim
)) {
169 #if defined(USE_LED_STRIP)
170 if (feature(FEATURE_LED_STRIP
)) {
171 for (int i
= 0; i
< timerHardwareCount
; i
++) {
172 if (timHw
->tim
== timerHardware
[i
].tim
&& timerHardware
[i
].usageFlags
& TIM_USE_LED
) {
177 //const timerHardware_t * ledTimHw = timerGetByTag(IO_TAG(WS2811_PIN), TIM_USE_ANY);
178 //if (ledTimHw != NULL && timHw->tim == ledTimHw->tim) {
185 #if defined(ADC_CHANNEL_1_PIN)
186 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_1_PIN
)) {
190 #if defined(ADC_CHANNEL_2_PIN)
191 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_2_PIN
)) {
195 #if defined(ADC_CHANNEL_3_PIN)
196 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_3_PIN
)) {
200 #if defined(ADC_CHANNEL_4_PIN)
201 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_4_PIN
)) {
205 #if defined(ADC_CHANNEL_5_PIN)
206 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_5_PIN
)) {
210 #if defined(ADC_CHANNEL_6_PIN)
211 if (timHw
->tag
== IO_TAG(ADC_CHANNEL_6_PIN
)) {
220 static void timerHardwareOverride(timerHardware_t
* timer
) {
221 switch (timerOverrides(timer2id(timer
->tim
))->outputMode
) {
222 case OUTPUT_MODE_MOTORS
:
223 timer
->usageFlags
&= ~(TIM_USE_SERVO
|TIM_USE_LED
);
224 timer
->usageFlags
|= TIM_USE_MOTOR
;
226 case OUTPUT_MODE_SERVOS
:
227 timer
->usageFlags
&= ~(TIM_USE_MOTOR
|TIM_USE_LED
);
228 timer
->usageFlags
|= TIM_USE_SERVO
;
230 case OUTPUT_MODE_LED
:
231 timer
->usageFlags
&= ~(TIM_USE_MOTOR
|TIM_USE_SERVO
);
232 timer
->usageFlags
|= TIM_USE_LED
;
237 bool pwmHasMotorOnTimer(timMotorServoHardware_t
* timOutputs
, HAL_Timer_t
*tim
)
239 for (int i
= 0; i
< timOutputs
->maxTimMotorCount
; ++i
) {
240 if (timOutputs
->timMotors
[i
]->tim
== tim
) {
248 bool pwmHasServoOnTimer(timMotorServoHardware_t
* timOutputs
, HAL_Timer_t
*tim
)
250 for (int i
= 0; i
< timOutputs
->maxTimServoCount
; ++i
) {
251 if (timOutputs
->timServos
[i
]->tim
== tim
) {
259 uint8_t pwmClaimTimer(HAL_Timer_t
*tim
, uint32_t usageFlags
) {
261 for (int idx
= 0; idx
< timerHardwareCount
; idx
++) {
262 timerHardware_t
*timHw
= &timerHardware
[idx
];
263 if (timHw
->tim
== tim
&& timHw
->usageFlags
!= usageFlags
) {
264 timHw
->usageFlags
= usageFlags
;
272 void pwmEnsureEnoughtMotors(uint8_t motorCount
)
274 uint8_t motorOnlyOutputs
= 0;
276 for (int idx
= 0; idx
< timerHardwareCount
; idx
++) {
277 timerHardware_t
*timHw
= &timerHardware
[idx
];
279 timerHardwareOverride(timHw
);
281 if (checkPwmTimerConflicts(timHw
)) {
285 if (TIM_IS_MOTOR_ONLY(timHw
->usageFlags
)) {
287 motorOnlyOutputs
+= pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
291 for (int idx
= 0; idx
< timerHardwareCount
; idx
++) {
292 timerHardware_t
*timHw
= &timerHardware
[idx
];
294 if (checkPwmTimerConflicts(timHw
)) {
298 if (TIM_IS_MOTOR(timHw
->usageFlags
) && !TIM_IS_MOTOR_ONLY(timHw
->usageFlags
)) {
299 if (motorOnlyOutputs
< motorCount
) {
300 timHw
->usageFlags
&= ~TIM_USE_SERVO
;
301 timHw
->usageFlags
|= TIM_USE_MOTOR
;
303 motorOnlyOutputs
+= pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
305 timHw
->usageFlags
&= ~TIM_USE_MOTOR
;
306 pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
312 void pwmBuildTimerOutputList(timMotorServoHardware_t
* timOutputs
, bool isMixerUsingServos
)
314 UNUSED(isMixerUsingServos
);
315 timOutputs
->maxTimMotorCount
= 0;
316 timOutputs
->maxTimServoCount
= 0;
318 uint8_t motorCount
= getMotorCount();
319 uint8_t motorIdx
= 0;
321 pwmEnsureEnoughtMotors(motorCount
);
323 for (int idx
= 0; idx
< timerHardwareCount
; idx
++) {
324 timerHardware_t
*timHw
= &timerHardware
[idx
];
326 int type
= MAP_TO_NONE
;
328 // Check for known conflicts (i.e. UART, LEDSTRIP, Rangefinder and ADC)
329 if (checkPwmTimerConflicts(timHw
)) {
330 LOG_WARNING(PWM
, "Timer output %d skipped", idx
);
334 // Make sure first motorCount motor outputs get assigned to motor
335 if (TIM_IS_MOTOR(timHw
->usageFlags
) && (motorIdx
< motorCount
)) {
336 timHw
->usageFlags
&= ~TIM_USE_SERVO
;
337 pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
341 if (TIM_IS_SERVO(timHw
->usageFlags
) && !pwmHasMotorOnTimer(timOutputs
, timHw
->tim
)) {
342 type
= MAP_TO_SERVO_OUTPUT
;
343 } else if (TIM_IS_MOTOR(timHw
->usageFlags
) && !pwmHasServoOnTimer(timOutputs
, timHw
->tim
)) {
344 type
= MAP_TO_MOTOR_OUTPUT
;
345 } else if (TIM_IS_LED(timHw
->usageFlags
) && !pwmHasMotorOnTimer(timOutputs
, timHw
->tim
) && !pwmHasServoOnTimer(timOutputs
, timHw
->tim
)) {
346 type
= MAP_TO_LED_OUTPUT
;
350 case MAP_TO_MOTOR_OUTPUT
:
351 timHw
->usageFlags
&= TIM_USE_MOTOR
;
352 timOutputs
->timMotors
[timOutputs
->maxTimMotorCount
++] = timHw
;
353 pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
355 case MAP_TO_SERVO_OUTPUT
:
356 timHw
->usageFlags
&= TIM_USE_SERVO
;
357 timOutputs
->timServos
[timOutputs
->maxTimServoCount
++] = timHw
;
358 pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
360 case MAP_TO_LED_OUTPUT
:
361 timHw
->usageFlags
&= TIM_USE_LED
;
362 pwmClaimTimer(timHw
->tim
, timHw
->usageFlags
);
370 static bool motorsUseHardwareTimers(void)
372 return getMotorProtocolProperties(motorConfig()->motorPwmProtocol
)->usesHwTimer
;
375 static bool servosUseHardwareTimers(void)
377 return servoConfig()->servo_protocol
== SERVO_TYPE_PWM
||
378 servoConfig()->servo_protocol
== SERVO_TYPE_SBUS_PWM
;
381 static void pwmInitMotors(timMotorServoHardware_t
* timOutputs
)
383 const int motorCount
= getMotorCount();
385 // Check if too many motors
386 if (motorCount
> MAX_MOTORS
) {
387 pwmInitError
= PWM_INIT_ERROR_TOO_MANY_MOTORS
;
388 LOG_ERROR(PWM
, "Too many motors. Mixer requested %d, max %d", motorCount
, MAX_MOTORS
);
392 // Do the pre-configuration. For motors w/o hardware timers this should be sufficient
393 pwmMotorPreconfigure();
395 // Now if we need to configure individual motor outputs - do that
396 if (!motorsUseHardwareTimers()) {
397 LOG_INFO(PWM
, "Skipped timer init for motors");
401 // If mixer requests more motors than we have timer outputs - throw an error
402 if (motorCount
> timOutputs
->maxTimMotorCount
) {
403 pwmInitError
= PWM_INIT_ERROR_NOT_ENOUGH_MOTOR_OUTPUTS
;
404 LOG_ERROR(PWM
, "Not enough motor outputs. Mixer requested %d, outputs %d", motorCount
, timOutputs
->maxTimMotorCount
);
408 // Finally initialize individual motor outputs
409 for (int idx
= 0; idx
< motorCount
; idx
++) {
410 const timerHardware_t
*timHw
= timOutputs
->timMotors
[idx
];
411 if (!pwmMotorConfig(timHw
, idx
, feature(FEATURE_PWM_OUTPUT_ENABLE
))) {
412 pwmInitError
= PWM_INIT_ERROR_TIMER_INIT_FAILED
;
413 LOG_ERROR(PWM
, "Timer allocation failed for motor %d", idx
);
419 static void pwmInitServos(timMotorServoHardware_t
* timOutputs
)
421 const int servoCount
= getServoCount();
423 if (!isMixerUsingServos()) {
424 LOG_INFO(PWM
, "Mixer does not use servos");
428 // Check if too many servos
429 if (servoCount
> MAX_SERVOS
) {
430 pwmInitError
= PWM_INIT_ERROR_TOO_MANY_SERVOS
;
431 LOG_ERROR(PWM
, "Too many servos. Mixer requested %d, max %d", servoCount
, MAX_SERVOS
);
435 // Do the pre-configuration. This should configure non-timer PWM drivers
436 pwmServoPreconfigure();
438 // Check if we need to init timer output for servos
439 if (!servosUseHardwareTimers()) {
440 // External PWM servo driver
441 LOG_INFO(PWM
, "Skipped timer init for servos - using external servo driver");
445 // If mixer requests more servos than we have timer outputs - throw an error
446 if (servoCount
> timOutputs
->maxTimServoCount
) {
447 pwmInitError
= PWM_INIT_ERROR_NOT_ENOUGH_SERVO_OUTPUTS
;
448 LOG_ERROR(PWM
, "Too many servos. Mixer requested %d, timer outputs %d", servoCount
, timOutputs
->maxTimServoCount
);
452 // Configure individual servo outputs
453 for (int idx
= 0; idx
< servoCount
; idx
++) {
454 const timerHardware_t
*timHw
= timOutputs
->timServos
[idx
];
456 if (!pwmServoConfig(timHw
, idx
, servoConfig()->servoPwmRate
, servoConfig()->servoCenterPulse
, feature(FEATURE_PWM_OUTPUT_ENABLE
))) {
457 pwmInitError
= PWM_INIT_ERROR_TIMER_INIT_FAILED
;
458 LOG_ERROR(PWM
, "Timer allocation failed for servo %d", idx
);
465 bool pwmMotorAndServoInit(void)
467 timMotorServoHardware_t timOutputs
;
469 // Build temporary timer mappings for motor and servo
470 pwmBuildTimerOutputList(&timOutputs
, isMixerUsingServos());
472 // At this point we have built tables of timers suitable for motor and servo mappings
473 // Now we can actually initialize them according to motor/servo count from mixer
474 pwmInitMotors(&timOutputs
);
475 pwmInitServos(&timOutputs
);
477 return (pwmInitError
== PWM_INIT_ERROR_NONE
);