Merge pull request #11297 from SteveCEvans/baro_state
[betaflight.git] / src / main / drivers / dshot_dpwm.c
blobde26d589da44d165325848548f232abd33405469
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
20 * Author: jflyper
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <math.h>
26 #include <string.h>
28 #include "platform.h"
30 #ifdef USE_DSHOT
32 #include "drivers/pwm_output.h"
33 #include "drivers/dshot.h"
34 #include "drivers/dshot_dpwm.h"
35 #include "drivers/motor.h"
37 #include "pg/motor.h"
39 // XXX TODO: Share a single region among dshotDmaBuffer and dshotBurstDmaBuffer
41 DSHOT_DMA_BUFFER_ATTRIBUTE DSHOT_DMA_BUFFER_UNIT dshotDmaBuffer[MAX_SUPPORTED_MOTORS][DSHOT_DMA_BUFFER_ALLOC_SIZE];
43 #ifdef USE_DSHOT_DMAR
44 DSHOT_DMA_BUFFER_ATTRIBUTE DSHOT_DMA_BUFFER_UNIT dshotBurstDmaBuffer[MAX_DMA_TIMERS][DSHOT_DMA_BUFFER_SIZE * 4];
45 #endif
47 #ifdef USE_DSHOT_DMAR
48 FAST_DATA_ZERO_INIT bool useBurstDshot = false;
49 #endif
50 #ifdef USE_DSHOT_TELEMETRY
51 FAST_DATA_ZERO_INIT bool useDshotTelemetry = false;
52 #endif
54 FAST_DATA_ZERO_INIT loadDmaBufferFn *loadDmaBuffer;
56 FAST_CODE_NOINLINE uint8_t loadDmaBufferDshot(uint32_t *dmaBuffer, int stride, uint16_t packet)
58 int i;
59 for (i = 0; i < 16; i++) {
60 dmaBuffer[i * stride] = (packet & 0x8000) ? MOTOR_BIT_1 : MOTOR_BIT_0; // MSB first
61 packet <<= 1;
63 dmaBuffer[i++ * stride] = 0;
64 dmaBuffer[i++ * stride] = 0;
66 return DSHOT_DMA_BUFFER_SIZE;
69 FAST_CODE_NOINLINE uint8_t loadDmaBufferProshot(uint32_t *dmaBuffer, int stride, uint16_t packet)
71 int i;
72 for (i = 0; i < 4; i++) {
73 dmaBuffer[i * stride] = PROSHOT_BASE_SYMBOL + ((packet & 0xF000) >> 12) * PROSHOT_BIT_WIDTH; // Most significant nibble first
74 packet <<= 4; // Shift 4 bits
76 dmaBuffer[i++ * stride] = 0;
77 dmaBuffer[i++ * stride] = 0;
79 return PROSHOT_DMA_BUFFER_SIZE;
82 uint32_t getDshotHz(motorPwmProtocolTypes_e pwmProtocolType)
84 switch (pwmProtocolType) {
85 case(PWM_TYPE_PROSHOT1000):
86 return MOTOR_PROSHOT1000_HZ;
87 case(PWM_TYPE_DSHOT600):
88 return MOTOR_DSHOT600_HZ;
89 case(PWM_TYPE_DSHOT300):
90 return MOTOR_DSHOT300_HZ;
91 default:
92 case(PWM_TYPE_DSHOT150):
93 return MOTOR_DSHOT150_HZ;
97 static void dshotPwmShutdown(void)
99 // DShot signal is only generated if write to motors happen,
100 // and that is prevented by enabled checking at write.
101 // Hence there's no special processing required here.
102 return;
105 static void dshotPwmDisableMotors(void)
107 // No special processing required
108 return;
111 static bool dshotPwmEnableMotors(void)
113 for (int i = 0; i < dshotPwmDevice.count; i++) {
114 motorDmaOutput_t *motor = getMotorDmaOutput(i);
115 const IO_t motorIO = IOGetByTag(motor->timerHardware->tag);
116 IOConfigGPIOAF(motorIO, motor->iocfg, motor->timerHardware->alternateFunction);
119 // No special processing required
120 return true;
123 static bool dshotPwmIsMotorEnabled(uint8_t index)
125 return motors[index].enabled;
128 static FAST_CODE void dshotWriteInt(uint8_t index, uint16_t value)
130 pwmWriteDshotInt(index, value);
133 static FAST_CODE void dshotWrite(uint8_t index, float value)
135 pwmWriteDshotInt(index, lrintf(value));
138 static motorVTable_t dshotPwmVTable = {
139 .postInit = motorPostInitNull,
140 .enable = dshotPwmEnableMotors,
141 .disable = dshotPwmDisableMotors,
142 .isMotorEnabled = dshotPwmIsMotorEnabled,
143 .updateStart = motorUpdateStartNull, // May be updated after copying
144 .write = dshotWrite,
145 .writeInt = dshotWriteInt,
146 .updateComplete = pwmCompleteDshotMotorUpdate,
147 .convertExternalToMotor = dshotConvertFromExternal,
148 .convertMotorToExternal = dshotConvertToExternal,
149 .shutdown = dshotPwmShutdown,
152 FAST_DATA_ZERO_INIT motorDevice_t dshotPwmDevice;
154 motorDevice_t *dshotPwmDevInit(const motorDevConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount, bool useUnsyncedPwm)
156 UNUSED(idlePulse);
157 UNUSED(useUnsyncedPwm);
159 dshotPwmDevice.vTable = dshotPwmVTable;
161 #ifdef USE_DSHOT_TELEMETRY
162 useDshotTelemetry = motorConfig->useDshotTelemetry;
163 dshotPwmDevice.vTable.updateStart = pwmStartDshotMotorUpdate;
164 #endif
166 switch (motorConfig->motorPwmProtocol) {
167 case PWM_TYPE_PROSHOT1000:
168 loadDmaBuffer = loadDmaBufferProshot;
169 break;
170 case PWM_TYPE_DSHOT600:
171 case PWM_TYPE_DSHOT300:
172 case PWM_TYPE_DSHOT150:
173 loadDmaBuffer = loadDmaBufferDshot;
174 #ifdef USE_DSHOT_DMAR
175 useBurstDshot = motorConfig->useBurstDshot == DSHOT_DMAR_ON ||
176 (motorConfig->useBurstDshot == DSHOT_DMAR_AUTO && !motorConfig->useDshotTelemetry);
177 #endif
178 break;
181 for (int motorIndex = 0; motorIndex < MAX_SUPPORTED_MOTORS && motorIndex < motorCount; motorIndex++) {
182 const unsigned reorderedMotorIndex = motorConfig->motorOutputReordering[motorIndex];
183 const ioTag_t tag = motorConfig->ioTags[reorderedMotorIndex];
184 const timerHardware_t *timerHardware = timerAllocate(tag, OWNER_MOTOR, RESOURCE_INDEX(reorderedMotorIndex));
186 if (timerHardware != NULL) {
187 motors[motorIndex].io = IOGetByTag(tag);
188 IOInit(motors[motorIndex].io, OWNER_MOTOR, RESOURCE_INDEX(reorderedMotorIndex));
190 if (pwmDshotMotorHardwareConfig(timerHardware,
191 motorIndex,
192 reorderedMotorIndex,
193 motorConfig->motorPwmProtocol,
194 motorConfig->motorPwmInversion ? timerHardware->output ^ TIMER_OUTPUT_INVERTED : timerHardware->output)) {
195 motors[motorIndex].enabled = true;
197 continue;
201 /* not enough motors initialised for the mixer or a break in the motors */
202 dshotPwmDevice.vTable.write = motorWriteNull;
203 dshotPwmDevice.vTable.updateComplete = motorUpdateCompleteNull;
205 /* TODO: block arming and add reason system cannot arm */
206 return NULL;
209 return &dshotPwmDevice;
212 #endif // USE_DSHOT