Timer code simplification in preparation of led strip being assignable.
[betaflight.git] / src / main / drivers / pwm_output_stm32f3xx.c
blobf45b0483e7dd23a01a24c96e5a771b7a7afd5693
1 /*
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/>.
17 #include <stdbool.h>
18 #include <stdint.h>
19 #include <math.h>
21 #include "platform.h"
23 #include "io.h"
24 #include "timer.h"
25 #include "pwm_output.h"
26 #include "nvic.h"
27 #include "dma.h"
28 #include "system.h"
29 #include "rcc.h"
31 #ifdef USE_DSHOT
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) {
50 return i;
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)
62 // compute checksum
63 int csum = 0;
64 int csum_data = packet;
65 for (int i = 0; i < 3; i++) {
66 csum ^= csum_data; // xor data by nibbles
67 csum_data >>= 4;
69 csum &= 0xf;
70 // append checksum
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
75 packet <<= 1;
78 DMA_SetCurrDataCounter(motor->timerHardware->dmaChannel, MOTOR_DMA_BUFFER_SIZE);
79 DMA_Cmd(motor->timerHardware->dmaChannel, ENABLE);
82 void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
84 UNUSED(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;
142 } else {
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);
170 DMA_DeInit(channel);
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);
189 #endif