2 * This file is part of Betaflight.
4 * Betaflight 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 * Betaflight 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 Betaflight. If not, see <http://www.gnu.org/licenses/>.
25 #include "timer_stm32f4xx.h"
26 #include "pwm_output.h"
34 #define MAX_DMA_TIMERS 8
36 #define MOTOR_DSHOT600_MHZ 12
37 #define MOTOR_DSHOT300_MHZ 6
38 #define MOTOR_DSHOT150_MHZ 3
41 #define MOTOR_BIT_1 14
42 #define MOTOR_BITLENGTH 19
44 static uint8_t dmaMotorTimerCount
= 0;
45 static motorDmaTimer_t dmaMotorTimers
[MAX_DMA_TIMERS
];
46 static motorDmaOutput_t dmaMotors
[MAX_SUPPORTED_MOTORS
];
48 uint8_t getTimerIndex(TIM_TypeDef
*timer
)
50 for (int i
= 0; i
< dmaMotorTimerCount
; i
++) {
51 if (dmaMotorTimers
[i
].timer
== timer
) {
55 dmaMotorTimers
[dmaMotorTimerCount
++].timer
= timer
;
56 return dmaMotorTimerCount
-1;
59 void pwmWriteDigital(uint8_t index
, uint16_t value
)
61 if (!pwmMotorsEnabled
) {
65 motorDmaOutput_t
* const motor
= &dmaMotors
[index
];
67 uint16_t packet
= (value
<< 1) | 0; // Here goes telemetry bit (false for now)
70 int csum_data
= packet
;
71 for (int i
= 0; i
< 3; i
++) {
72 csum
^= csum_data
; // xor data by nibbles
77 packet
= (packet
<< 4) | csum
;
78 // generate pulses for whole packet
79 for (int i
= 0; i
< 16; i
++) {
80 motor
->dmaBuffer
[i
] = (packet
& 0x8000) ? MOTOR_BIT_1
: MOTOR_BIT_0
; // MSB first
84 DMA_SetCurrDataCounter(motor
->timerHardware
->dmaStream
, MOTOR_DMA_BUFFER_SIZE
);
85 DMA_Cmd(motor
->timerHardware
->dmaStream
, ENABLE
);
88 void pwmCompleteDigitalMotorUpdate(uint8_t motorCount
)
92 if (!pwmMotorsEnabled
) {
96 for (int i
= 0; i
< dmaMotorTimerCount
; i
++) {
97 TIM_SetCounter(dmaMotorTimers
[i
].timer
, 0);
98 TIM_DMACmd(dmaMotorTimers
[i
].timer
, dmaMotorTimers
[i
].timerDmaSources
, ENABLE
);
102 static void motor_DMA_IRQHandler(dmaChannelDescriptor_t
*descriptor
)
104 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TCIF
)) {
105 motorDmaOutput_t
* const motor
= &dmaMotors
[descriptor
->userParam
];
106 DMA_Cmd(descriptor
->stream
, DISABLE
);
107 TIM_DMACmd(motor
->timerHardware
->tim
, motor
->timerDmaSource
, DISABLE
);
108 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TCIF
);
112 void pwmDigitalMotorHardwareConfig(const timerHardware_t
*timerHardware
, uint8_t motorIndex
, motorPwmProtocolTypes_e pwmProtocolType
)
114 TIM_OCInitTypeDef TIM_OCInitStructure
;
115 DMA_InitTypeDef DMA_InitStructure
;
117 motorDmaOutput_t
* const motor
= &dmaMotors
[motorIndex
];
118 motor
->timerHardware
= timerHardware
;
120 TIM_TypeDef
*timer
= timerHardware
->tim
;
121 const IO_t motorIO
= IOGetByTag(timerHardware
->tag
);
123 const uint8_t timerIndex
= getTimerIndex(timer
);
124 const bool configureTimer
= (timerIndex
== dmaMotorTimerCount
-1);
126 IOInit(motorIO
, OWNER_MOTOR
, 0);
127 IOConfigGPIOAF(motorIO
, IO_CONFIG(GPIO_Mode_AF
, GPIO_Speed_50MHz
, GPIO_OType_PP
, GPIO_PuPd_UP
), timerHardware
->alternateFunction
);
129 if (configureTimer
) {
130 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure
;
131 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure
);
133 RCC_ClockCmd(timerRCC(timer
), ENABLE
);
134 TIM_Cmd(timer
, DISABLE
);
137 switch (pwmProtocolType
) {
138 case(PWM_TYPE_DSHOT600
):
139 hz
= MOTOR_DSHOT600_MHZ
* 1000000;
141 case(PWM_TYPE_DSHOT300
):
142 hz
= MOTOR_DSHOT300_MHZ
* 1000000;
145 case(PWM_TYPE_DSHOT150
):
146 hz
= MOTOR_DSHOT150_MHZ
* 1000000;
149 TIM_TimeBaseStructure
.TIM_Prescaler
= (SystemCoreClock
/ timerClockDivisor(timer
) / hz
) - 1;
150 TIM_TimeBaseStructure
.TIM_Period
= MOTOR_BITLENGTH
;
151 TIM_TimeBaseStructure
.TIM_ClockDivision
= TIM_CKD_DIV1
;
152 TIM_TimeBaseStructure
.TIM_RepetitionCounter
= 0;
153 TIM_TimeBaseStructure
.TIM_CounterMode
= TIM_CounterMode_Up
;
154 TIM_TimeBaseInit(timer
, &TIM_TimeBaseStructure
);
157 TIM_OCStructInit(&TIM_OCInitStructure
);
158 TIM_OCInitStructure
.TIM_OCMode
= TIM_OCMode_PWM1
;
159 if (timerHardware
->output
& TIMER_OUTPUT_N_CHANNEL
) {
160 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Enable
;
161 TIM_OCInitStructure
.TIM_OCNIdleState
= TIM_OCNIdleState_Reset
;
162 TIM_OCInitStructure
.TIM_OCNPolarity
= (timerHardware
->output
& TIMER_OUTPUT_INVERTED
) ? TIM_OCNPolarity_High
: TIM_OCNPolarity_Low
;
164 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Enable
;
165 TIM_OCInitStructure
.TIM_OCIdleState
= TIM_OCIdleState_Set
;
166 TIM_OCInitStructure
.TIM_OCPolarity
= (timerHardware
->output
& TIMER_OUTPUT_INVERTED
) ? TIM_OCPolarity_Low
: TIM_OCPolarity_High
;
168 TIM_OCInitStructure
.TIM_Pulse
= 0;
170 timerOCInit(timer
, timerHardware
->channel
, &TIM_OCInitStructure
);
171 timerOCPreloadConfig(timer
, timerHardware
->channel
, TIM_OCPreload_Enable
);
172 motor
->timerDmaSource
= timerDmaSource(timerHardware
->channel
);
173 dmaMotorTimers
[timerIndex
].timerDmaSources
|= motor
->timerDmaSource
;
175 TIM_CCxCmd(timer
, motor
->timerHardware
->channel
, TIM_CCx_Enable
);
177 if (configureTimer
) {
178 TIM_CtrlPWMOutputs(timer
, ENABLE
);
179 TIM_ARRPreloadConfig(timer
, ENABLE
);
180 TIM_Cmd(timer
, ENABLE
);
183 DMA_Stream_TypeDef
*stream
= timerHardware
->dmaStream
;
185 dmaInit(timerHardware
->dmaIrqHandler
, OWNER_MOTOR
, RESOURCE_INDEX(motorIndex
));
186 dmaSetHandler(timerHardware
->dmaIrqHandler
, motor_DMA_IRQHandler
, NVIC_BUILD_PRIORITY(1, 2), motorIndex
);
188 DMA_Cmd(stream
, DISABLE
);
191 DMA_StructInit(&DMA_InitStructure
);
192 DMA_InitStructure
.DMA_Channel
= timerHardware
->dmaChannel
;
193 DMA_InitStructure
.DMA_PeripheralBaseAddr
= (uint32_t)timerChCCR(timerHardware
);
194 DMA_InitStructure
.DMA_Memory0BaseAddr
= (uint32_t)motor
->dmaBuffer
;
195 DMA_InitStructure
.DMA_DIR
= DMA_DIR_MemoryToPeripheral
;
196 DMA_InitStructure
.DMA_BufferSize
= MOTOR_DMA_BUFFER_SIZE
;
197 DMA_InitStructure
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
;
198 DMA_InitStructure
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
199 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Word
;
200 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Word
;
201 DMA_InitStructure
.DMA_Mode
= DMA_Mode_Normal
;
202 DMA_InitStructure
.DMA_Priority
= DMA_Priority_VeryHigh
;
203 DMA_InitStructure
.DMA_FIFOMode
= DMA_FIFOMode_Enable
;
204 DMA_InitStructure
.DMA_FIFOThreshold
= DMA_FIFOThreshold_1QuarterFull
;
205 DMA_InitStructure
.DMA_MemoryBurst
= DMA_MemoryBurst_Single
;
206 DMA_InitStructure
.DMA_PeripheralBurst
= DMA_PeripheralBurst_Single
;
208 DMA_Init(stream
, &DMA_InitStructure
);
210 DMA_ITConfig(stream
, DMA_IT_TC
, ENABLE
);
211 DMA_ClearITPendingBit(stream
, dmaFlag_IT_TCIF(timerHardware
->dmaStream
));