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 "pwm_output.h"
33 #define MAX_DMA_TIMERS 8
35 #define MOTOR_DSHOT600_MHZ 24
36 #define MOTOR_DSHOT150_MHZ 6
38 #define MOTOR_BIT_0 14
39 #define MOTOR_BIT_1 29
40 #define MOTOR_BITLENGTH 39
42 static uint8_t dmaMotorTimerCount
= 0;
43 static motorDmaTimer_t dmaMotorTimers
[MAX_DMA_TIMERS
];
44 static motorDmaOutput_t dmaMotors
[MAX_SUPPORTED_MOTORS
];
46 uint8_t getTimerIndex(TIM_TypeDef
*timer
)
48 for (int i
= 0; i
< dmaMotorTimerCount
; i
++) {
49 if (dmaMotorTimers
[i
].timer
== timer
) {
53 dmaMotorTimers
[dmaMotorTimerCount
++].timer
= timer
;
54 return dmaMotorTimerCount
-1;
57 void pwmWriteDigital(uint8_t index
, uint16_t value
)
59 motorDmaOutput_t
* const motor
= &dmaMotors
[index
];
61 uint16_t packet
= (value
<< 1) | 0; // Here goes telemetry bit (false for now)
64 int csum_data
= packet
;
65 for (int i
= 0; i
< 3; i
++) {
66 csum
^= csum_data
; // xor data by nibbles
71 packet
= (packet
<< 4) | csum
;
72 // generate pulses for whole packet
73 for (int i
= 0; i
< 16; i
++) {
74 motor
->dmaBuffer
[i
] = (packet
& 0x8000) ? MOTOR_BIT_1
: MOTOR_BIT_0
; // MSB first
78 DMA_SetCurrDataCounter(motor
->timerHardware
->dmaChannel
, MOTOR_DMA_BUFFER_SIZE
);
79 DMA_Cmd(motor
->timerHardware
->dmaChannel
, ENABLE
);
82 void pwmCompleteDigitalMotorUpdate(uint8_t motorCount
)
86 for (uint8_t i
= 0; i
< dmaMotorTimerCount
; i
++) {
87 TIM_SetCounter(dmaMotorTimers
[i
].timer
, 0);
88 TIM_DMACmd(dmaMotorTimers
[i
].timer
, dmaMotorTimers
[i
].timerDmaSources
, ENABLE
);
92 static void motor_DMA_IRQHandler(dmaChannelDescriptor_t
*descriptor
)
94 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TCIF
)) {
95 motorDmaOutput_t
* const motor
= &dmaMotors
[descriptor
->userParam
];
96 DMA_Cmd(descriptor
->channel
, DISABLE
);
97 TIM_DMACmd(motor
->timerHardware
->tim
, motor
->timerDmaSource
, DISABLE
);
98 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TCIF
);
102 void pwmDigitalMotorHardwareConfig(const timerHardware_t
*timerHardware
, uint8_t motorIndex
, motorPwmProtocolTypes_e pwmProtocolType
)
104 TIM_OCInitTypeDef TIM_OCInitStructure
;
105 DMA_InitTypeDef DMA_InitStructure
;
107 motorDmaOutput_t
* const motor
= &dmaMotors
[motorIndex
];
108 motor
->timerHardware
= timerHardware
;
110 TIM_TypeDef
*timer
= timerHardware
->tim
;
111 const IO_t motorIO
= IOGetByTag(timerHardware
->tag
);
113 const uint8_t timerIndex
= getTimerIndex(timer
);
114 const bool configureTimer
= (timerIndex
== dmaMotorTimerCount
-1);
116 IOInit(motorIO
, OWNER_MOTOR
, RESOURCE_OUTPUT
, 0);
117 IOConfigGPIOAF(motorIO
, IO_CONFIG(GPIO_Mode_AF
, GPIO_Speed_50MHz
, GPIO_OType_PP
, GPIO_PuPd_UP
), timerHardware
->alternateFunction
);
119 if (configureTimer
) {
120 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure
;
122 RCC_ClockCmd(timerRCC(timer
), ENABLE
);
123 TIM_Cmd(timer
, DISABLE
);
125 uint32_t hz
= (pwmProtocolType
== PWM_TYPE_DSHOT600
? MOTOR_DSHOT600_MHZ
: MOTOR_DSHOT150_MHZ
) * 1000000;
126 TIM_TimeBaseStructure
.TIM_Prescaler
= (uint16_t)((SystemCoreClock
/ timerClockDivisor(timer
) / hz
) - 1);
127 TIM_TimeBaseStructure
.TIM_Period
= MOTOR_BITLENGTH
;
128 TIM_TimeBaseStructure
.TIM_ClockDivision
= TIM_CKD_DIV1
;
129 TIM_TimeBaseStructure
.TIM_CounterMode
= TIM_CounterMode_Up
;
130 TIM_TimeBaseInit(timer
, &TIM_TimeBaseStructure
);
133 TIM_OCStructInit(&TIM_OCInitStructure
);
134 TIM_OCInitStructure
.TIM_OCMode
= TIM_OCMode_PWM1
;
135 if (timerHardware
->output
& TIMER_OUTPUT_N_CHANNEL
) {
136 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Disable
;
137 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Enable
;
138 TIM_OCInitStructure
.TIM_OCIdleState
= TIM_OCIdleState_Set
;
139 TIM_OCInitStructure
.TIM_OCNIdleState
= TIM_OCNIdleState_Reset
;
140 TIM_OCInitStructure
.TIM_OCPolarity
= TIM_OCNPolarity_Low
;
141 TIM_OCInitStructure
.TIM_OCNPolarity
= TIM_OCNPolarity_Low
;
143 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Enable
;
144 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Disable
;
145 TIM_OCInitStructure
.TIM_OCIdleState
= TIM_OCIdleState_Reset
;
146 TIM_OCInitStructure
.TIM_OCNIdleState
= TIM_OCNIdleState_Set
;
147 TIM_OCInitStructure
.TIM_OCPolarity
= TIM_OCNPolarity_High
;
148 TIM_OCInitStructure
.TIM_OCNPolarity
= TIM_OCNPolarity_High
;
150 TIM_OCInitStructure
.TIM_Pulse
= 0;
152 timerOCInit(timer
, timerHardware
->channel
, &TIM_OCInitStructure
);
153 timerOCPreloadConfig(timer
, timerHardware
->channel
, TIM_OCPreload_Enable
);
154 motor
->timerDmaSource
= timerDmaSource(timerHardware
->channel
);
155 dmaMotorTimers
[timerIndex
].timerDmaSources
|= motor
->timerDmaSource
;
157 TIM_CCxCmd(timer
, timerHardware
->channel
, TIM_CCx_Enable
);
159 if (configureTimer
) {
160 TIM_CtrlPWMOutputs(timer
, ENABLE
);
161 TIM_ARRPreloadConfig(timer
, ENABLE
);
162 TIM_Cmd(timer
, ENABLE
);
165 DMA_Channel_TypeDef
*channel
= timerHardware
->dmaChannel
;
167 dmaSetHandler(timerHardware
->dmaIrqHandler
, motor_DMA_IRQHandler
, NVIC_BUILD_PRIORITY(1, 2), motorIndex
);
169 DMA_Cmd(channel
, DISABLE
);
171 DMA_StructInit(&DMA_InitStructure
);
172 DMA_InitStructure
.DMA_PeripheralBaseAddr
= (uint32_t)timerChCCR(timerHardware
);
173 DMA_InitStructure
.DMA_MemoryBaseAddr
= (uint32_t)motor
->dmaBuffer
;
174 DMA_InitStructure
.DMA_DIR
= DMA_DIR_PeripheralDST
;
175 DMA_InitStructure
.DMA_BufferSize
= MOTOR_DMA_BUFFER_SIZE
;
176 DMA_InitStructure
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
;
177 DMA_InitStructure
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
178 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Word
;
179 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Word
;
180 DMA_InitStructure
.DMA_Mode
= DMA_Mode_Normal
;
181 DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
;
182 DMA_InitStructure
.DMA_M2M
= DMA_M2M_Disable
;
184 DMA_Init(channel
, &DMA_InitStructure
);
186 DMA_ITConfig(channel
, DMA_IT_TC
, ENABLE
);