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/>.
28 #include "flight/failsafe.h" // FIXME dependency into the main code from a driver
30 #include "pwm_mapping.h"
32 #include "pwm_output.h"
34 typedef void (*pwmWriteFuncPtr
)(uint8_t index
, uint16_t value
); // function pointer used to write motors
37 volatile timCCR_t
*ccr
;
40 pwmWriteFuncPtr pwmWritePtr
;
43 static pwmOutputPort_t pwmOutputPorts
[MAX_PWM_OUTPUT_PORTS
];
45 static pwmOutputPort_t
*motors
[MAX_PWM_MOTORS
];
48 static pwmOutputPort_t
*servos
[MAX_PWM_SERVOS
];
51 static uint8_t allocatedOutputPortCount
= 0;
53 static bool pwmMotorsEnabled
= true;
54 static void pwmOCConfig(TIM_TypeDef
*tim
, uint8_t channel
, uint16_t value
)
56 TIM_OCInitTypeDef TIM_OCInitStructure
;
58 TIM_OCStructInit(&TIM_OCInitStructure
);
59 TIM_OCInitStructure
.TIM_OCMode
= TIM_OCMode_PWM2
;
60 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Enable
;
61 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Disable
;
62 TIM_OCInitStructure
.TIM_Pulse
= value
;
63 TIM_OCInitStructure
.TIM_OCPolarity
= TIM_OCPolarity_Low
;
64 TIM_OCInitStructure
.TIM_OCIdleState
= TIM_OCIdleState_Set
;
68 TIM_OC1Init(tim
, &TIM_OCInitStructure
);
69 TIM_OC1PreloadConfig(tim
, TIM_OCPreload_Enable
);
72 TIM_OC2Init(tim
, &TIM_OCInitStructure
);
73 TIM_OC2PreloadConfig(tim
, TIM_OCPreload_Enable
);
76 TIM_OC3Init(tim
, &TIM_OCInitStructure
);
77 TIM_OC3PreloadConfig(tim
, TIM_OCPreload_Enable
);
80 TIM_OC4Init(tim
, &TIM_OCInitStructure
);
81 TIM_OC4PreloadConfig(tim
, TIM_OCPreload_Enable
);
86 static void pwmGPIOConfig(GPIO_TypeDef
*gpio
, uint32_t pin
, GPIO_Mode mode
)
92 cfg
.speed
= Speed_2MHz
;
96 static pwmOutputPort_t
*pwmOutConfig(const timerHardware_t
*timerHardware
, uint8_t mhz
, uint16_t period
, uint16_t value
)
98 pwmOutputPort_t
*p
= &pwmOutputPorts
[allocatedOutputPortCount
++];
100 configTimeBase(timerHardware
->tim
, period
, mhz
);
101 pwmGPIOConfig(timerHardware
->gpio
, timerHardware
->pin
, Mode_AF_PP
);
104 pwmOCConfig(timerHardware
->tim
, timerHardware
->channel
, value
);
105 if (timerHardware
->outputEnable
)
106 TIM_CtrlPWMOutputs(timerHardware
->tim
, ENABLE
);
107 TIM_Cmd(timerHardware
->tim
, ENABLE
);
109 switch (timerHardware
->channel
) {
111 p
->ccr
= &timerHardware
->tim
->CCR1
;
114 p
->ccr
= &timerHardware
->tim
->CCR2
;
117 p
->ccr
= &timerHardware
->tim
->CCR3
;
120 p
->ccr
= &timerHardware
->tim
->CCR4
;
124 p
->tim
= timerHardware
->tim
;
129 static void pwmWriteBrushed(uint8_t index
, uint16_t value
)
131 *motors
[index
]->ccr
= (value
- 1000) * motors
[index
]->period
/ 1000;
134 static void pwmWriteStandard(uint8_t index
, uint16_t value
)
136 *motors
[index
]->ccr
= value
;
139 static void pwmWriteMultiShot(uint8_t index
, uint16_t value
)
141 *motors
[index
]->ccr
= 60001 * (value
- 1000) / 250000 + 60;
144 void pwmWriteMotor(uint8_t index
, uint16_t value
)
146 if (motors
[index
] && index
< MAX_MOTORS
&& pwmMotorsEnabled
)
147 motors
[index
]->pwmWritePtr(index
, value
);
150 void pwmShutdownPulsesForAllMotors(uint8_t motorCount
)
154 for(index
= 0; index
< motorCount
; index
++){
155 // Set the compare register to 0, which stops the output pulsing if the timer overflows
156 *motors
[index
]->ccr
= 0;
160 void pwmDisableMotors(void)
162 pwmMotorsEnabled
= false;
165 void pwmEnableMotors(void)
167 pwmMotorsEnabled
= true;
170 void pwmCompleteOneshotMotorUpdate(uint8_t motorCount
)
173 TIM_TypeDef
*lastTimerPtr
= NULL
;
175 for(index
= 0; index
< motorCount
; index
++){
177 // Force the timer to overflow if it's the first motor to output, or if we change timers
178 if(motors
[index
]->tim
!= lastTimerPtr
){
179 lastTimerPtr
= motors
[index
]->tim
;
181 timerForceOverflow(motors
[index
]->tim
);
184 // Set the compare register to 0, which stops the output pulsing if the timer overflows before the main loop completes again.
185 // This compare register will be set to the output value on the next main loop.
186 *motors
[index
]->ccr
= 0;
190 bool isMotorBrushed(uint16_t motorPwmRate
)
192 return (motorPwmRate
> 500);
195 void pwmBrushedMotorConfig(const timerHardware_t
*timerHardware
, uint8_t motorIndex
, uint16_t motorPwmRate
, uint16_t idlePulse
)
197 uint32_t hz
= PWM_BRUSHED_TIMER_MHZ
* 1000000;
198 motors
[motorIndex
] = pwmOutConfig(timerHardware
, PWM_BRUSHED_TIMER_MHZ
, hz
/ motorPwmRate
, idlePulse
);
199 motors
[motorIndex
]->pwmWritePtr
= pwmWriteBrushed
;
202 void pwmBrushlessMotorConfig(const timerHardware_t
*timerHardware
, uint8_t motorIndex
, uint16_t motorPwmRate
, uint16_t idlePulse
)
204 uint32_t hz
= PWM_TIMER_MHZ
* 1000000;
205 motors
[motorIndex
] = pwmOutConfig(timerHardware
, PWM_TIMER_MHZ
, hz
/ motorPwmRate
, idlePulse
);
206 motors
[motorIndex
]->pwmWritePtr
= pwmWriteStandard
;
209 void pwmFastPwmMotorConfig(const timerHardware_t
*timerHardware
, uint8_t motorIndex
, uint8_t fastPwmProtocolType
, uint16_t motorPwmRate
, uint8_t useUnsyncedPwm
, uint16_t idlePulse
)
211 uint32_t timerMhzCounter
;
213 switch (fastPwmProtocolType
) {
215 case (PWM_TYPE_ONESHOT125
):
216 timerMhzCounter
= ONESHOT125_TIMER_MHZ
;
218 case (PWM_TYPE_ONESHOT42
):
219 timerMhzCounter
= ONESHOT42_TIMER_MHZ
;
221 case (PWM_TYPE_MULTISHOT
):
222 timerMhzCounter
= MULTISHOT_TIMER_MHZ
;
225 if (useUnsyncedPwm
) {
226 uint32_t hz
= timerMhzCounter
* 1000000;
227 motors
[motorIndex
] = pwmOutConfig(timerHardware
, timerMhzCounter
, hz
/ motorPwmRate
, idlePulse
);
229 motors
[motorIndex
] = pwmOutConfig(timerHardware
, timerMhzCounter
, 0xFFFF, 0);
232 motors
[motorIndex
]->pwmWritePtr
= (fastPwmProtocolType
== PWM_TYPE_MULTISHOT
) ? pwmWriteMultiShot
: pwmWriteStandard
;
236 void pwmServoConfig(const timerHardware_t
*timerHardware
, uint8_t servoIndex
, uint16_t servoPwmRate
, uint16_t servoCenterPulse
)
238 servos
[servoIndex
] = pwmOutConfig(timerHardware
, PWM_TIMER_MHZ
, 1000000 / servoPwmRate
, servoCenterPulse
);
241 void pwmWriteServo(uint8_t index
, uint16_t value
)
243 if (servos
[index
] && index
< MAX_SERVOS
)
244 *servos
[index
]->ccr
= value
;