Merge pull request #1282 from blckmn/digital_motors
DSHOT600 & 150 -> digital one shot motor (ESC) protocol
This commit is contained in:
commit
f698f99198
2
Makefile
2
Makefile
|
@ -534,6 +534,7 @@ STM32F30x_COMMON_SRC = \
|
||||||
drivers/dma.c \
|
drivers/dma.c \
|
||||||
drivers/gpio_stm32f30x.c \
|
drivers/gpio_stm32f30x.c \
|
||||||
drivers/light_ws2811strip_stm32f30x.c \
|
drivers/light_ws2811strip_stm32f30x.c \
|
||||||
|
drivers/pwm_output_stm32f3xx.c \
|
||||||
drivers/serial_uart_stm32f30x.c \
|
drivers/serial_uart_stm32f30x.c \
|
||||||
drivers/system_stm32f30x.c \
|
drivers/system_stm32f30x.c \
|
||||||
drivers/timer_stm32f30x.c
|
drivers/timer_stm32f30x.c
|
||||||
|
@ -548,6 +549,7 @@ STM32F4xx_COMMON_SRC = \
|
||||||
drivers/gpio_stm32f4xx.c \
|
drivers/gpio_stm32f4xx.c \
|
||||||
drivers/inverter.c \
|
drivers/inverter.c \
|
||||||
drivers/light_ws2811strip_stm32f4xx.c \
|
drivers/light_ws2811strip_stm32f4xx.c \
|
||||||
|
drivers/pwm_output_stm32f4xx.c \
|
||||||
drivers/serial_uart_stm32f4xx.c \
|
drivers/serial_uart_stm32f4xx.c \
|
||||||
drivers/system_stm32f4xx.c \
|
drivers/system_stm32f4xx.c \
|
||||||
drivers/timer_stm32f4xx.c
|
drivers/timer_stm32f4xx.c
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define MULTISHOT_20US_MULT (MULTISHOT_TIMER_MHZ * 20 / 1000.0f)
|
#define MULTISHOT_20US_MULT (MULTISHOT_TIMER_MHZ * 20 / 1000.0f)
|
||||||
|
|
||||||
static pwmOutputPort_t motors[MAX_SUPPORTED_MOTORS];
|
static pwmOutputPort_t motors[MAX_SUPPORTED_MOTORS];
|
||||||
|
static pwmCompleteWriteFuncPtr pwmCompleteWritePtr = NULL;
|
||||||
|
|
||||||
#ifdef USE_SERVOS
|
#ifdef USE_SERVOS
|
||||||
static pwmOutputPort_t servos[MAX_SUPPORTED_SERVOS];
|
static pwmOutputPort_t servos[MAX_SUPPORTED_SERVOS];
|
||||||
|
@ -153,7 +154,7 @@ void pwmEnableMotors(void)
|
||||||
pwmMotorsEnabled = true;
|
pwmMotorsEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
|
static void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
|
||||||
{
|
{
|
||||||
for (int index = 0; index < motorCount; index++) {
|
for (int index = 0; index < motorCount; index++) {
|
||||||
bool overflowed = false;
|
bool overflowed = false;
|
||||||
|
@ -173,40 +174,59 @@ void pwmCompleteOneshotMotorUpdate(uint8_t motorCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pwmCompleteMotorUpdate(uint8_t motorCount)
|
||||||
|
{
|
||||||
|
if (pwmCompleteWritePtr) {
|
||||||
|
pwmCompleteWritePtr(motorCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount)
|
void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t motorCount)
|
||||||
{
|
{
|
||||||
uint32_t timerMhzCounter;
|
uint32_t timerMhzCounter;
|
||||||
pwmWriteFuncPtr pwmWritePtr;
|
pwmWriteFuncPtr pwmWritePtr;
|
||||||
bool useUnsyncedPwm = motorConfig->useUnsyncedPwm;
|
bool useUnsyncedPwm = motorConfig->useUnsyncedPwm;
|
||||||
|
bool isDigital = false;
|
||||||
|
|
||||||
switch (motorConfig->motorPwmProtocol) {
|
switch (motorConfig->motorPwmProtocol) {
|
||||||
default:
|
default:
|
||||||
case (PWM_TYPE_ONESHOT125):
|
case PWM_TYPE_ONESHOT125:
|
||||||
timerMhzCounter = ONESHOT125_TIMER_MHZ;
|
timerMhzCounter = ONESHOT125_TIMER_MHZ;
|
||||||
pwmWritePtr = pwmWriteOneShot125;
|
pwmWritePtr = pwmWriteOneShot125;
|
||||||
break;
|
break;
|
||||||
case (PWM_TYPE_ONESHOT42):
|
case PWM_TYPE_ONESHOT42:
|
||||||
timerMhzCounter = ONESHOT42_TIMER_MHZ;
|
timerMhzCounter = ONESHOT42_TIMER_MHZ;
|
||||||
pwmWritePtr = pwmWriteOneShot42;
|
pwmWritePtr = pwmWriteOneShot42;
|
||||||
break;
|
break;
|
||||||
case (PWM_TYPE_MULTISHOT):
|
case PWM_TYPE_MULTISHOT:
|
||||||
timerMhzCounter = MULTISHOT_TIMER_MHZ;
|
timerMhzCounter = MULTISHOT_TIMER_MHZ;
|
||||||
pwmWritePtr = pwmWriteMultiShot;
|
pwmWritePtr = pwmWriteMultiShot;
|
||||||
break;
|
break;
|
||||||
case (PWM_TYPE_BRUSHED):
|
case PWM_TYPE_BRUSHED:
|
||||||
timerMhzCounter = PWM_BRUSHED_TIMER_MHZ;
|
timerMhzCounter = PWM_BRUSHED_TIMER_MHZ;
|
||||||
pwmWritePtr = pwmWriteBrushed;
|
pwmWritePtr = pwmWriteBrushed;
|
||||||
useUnsyncedPwm = true;
|
useUnsyncedPwm = true;
|
||||||
idlePulse = 0;
|
idlePulse = 0;
|
||||||
break;
|
break;
|
||||||
case (PWM_TYPE_STANDARD):
|
case PWM_TYPE_STANDARD:
|
||||||
timerMhzCounter = PWM_TIMER_MHZ;
|
timerMhzCounter = PWM_TIMER_MHZ;
|
||||||
pwmWritePtr = pwmWriteStandard;
|
pwmWritePtr = pwmWriteStandard;
|
||||||
useUnsyncedPwm = true;
|
useUnsyncedPwm = true;
|
||||||
idlePulse = 0;
|
idlePulse = 0;
|
||||||
break;
|
break;
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
case PWM_TYPE_DSHOT600:
|
||||||
|
case PWM_TYPE_DSHOT150:
|
||||||
|
pwmCompleteWritePtr = pwmCompleteDigitalMotorUpdate;
|
||||||
|
isDigital = true;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!useUnsyncedPwm && !isDigital) {
|
||||||
|
pwmCompleteWritePtr = pwmCompleteOneshotMotorUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
for (int motorIndex = 0; motorIndex < MAX_SUPPORTED_MOTORS && motorIndex < motorCount; motorIndex++) {
|
for (int motorIndex = 0; motorIndex < MAX_SUPPORTED_MOTORS && motorIndex < motorCount; motorIndex++) {
|
||||||
const ioTag_t tag = motorConfig->ioTags[motorIndex];
|
const ioTag_t tag = motorConfig->ioTags[motorIndex];
|
||||||
|
|
||||||
|
@ -214,30 +234,43 @@ void motorInit(const motorConfig_t *motorConfig, uint16_t idlePulse, uint8_t mot
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timerHardware_t *timerHardware = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
|
||||||
|
|
||||||
|
if (timerHardware == NULL) {
|
||||||
|
/* flag failure and disable ability to arm */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
if (isDigital) {
|
||||||
|
pwmDigitalMotorHardwareConfig(timerHardware, motorIndex, motorConfig->motorPwmProtocol);
|
||||||
|
motors[motorIndex].pwmWritePtr = pwmWriteDigital;
|
||||||
|
motors[motorIndex].enabled = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
motors[motorIndex].io = IOGetByTag(tag);
|
motors[motorIndex].io = IOGetByTag(tag);
|
||||||
|
|
||||||
IOInit(motors[motorIndex].io, OWNER_MOTOR, RESOURCE_OUTPUT, RESOURCE_INDEX(motorIndex));
|
IOInit(motors[motorIndex].io, OWNER_MOTOR, RESOURCE_OUTPUT, RESOURCE_INDEX(motorIndex));
|
||||||
IOConfigGPIO(motors[motorIndex].io, IOCFG_AF_PP);
|
IOConfigGPIO(motors[motorIndex].io, IOCFG_AF_PP);
|
||||||
|
|
||||||
const timerHardware_t *timer = timerGetByTag(tag, TIMER_OUTPUT_ENABLED);
|
|
||||||
|
|
||||||
if (timer == NULL) {
|
|
||||||
/* flag failure and disable ability to arm */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
motors[motorIndex].pwmWritePtr = pwmWritePtr;
|
motors[motorIndex].pwmWritePtr = pwmWritePtr;
|
||||||
if (useUnsyncedPwm) {
|
if (useUnsyncedPwm) {
|
||||||
const uint32_t hz = timerMhzCounter * 1000000;
|
const uint32_t hz = timerMhzCounter * 1000000;
|
||||||
pwmOutConfig(&motors[motorIndex], timer, timerMhzCounter, hz / motorConfig->motorPwmProtocol, idlePulse);
|
pwmOutConfig(&motors[motorIndex], timerHardware, timerMhzCounter, hz / motorConfig->motorPwmProtocol, idlePulse);
|
||||||
} else {
|
} else {
|
||||||
pwmOutConfig(&motors[motorIndex], timer, timerMhzCounter, 0xFFFF, 0);
|
pwmOutConfig(&motors[motorIndex], timerHardware, timerMhzCounter, 0xFFFF, 0);
|
||||||
}
|
}
|
||||||
motors[motorIndex].enabled = true;
|
motors[motorIndex].enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pwmOutputPort_t *pwmGetMotors()
|
bool pwmIsSynced(void)
|
||||||
|
{
|
||||||
|
return pwmCompleteWritePtr != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwmOutputPort_t *pwmGetMotors(void)
|
||||||
{
|
{
|
||||||
return motors;
|
return motors;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,12 @@ typedef enum {
|
||||||
PWM_TYPE_ONESHOT125,
|
PWM_TYPE_ONESHOT125,
|
||||||
PWM_TYPE_ONESHOT42,
|
PWM_TYPE_ONESHOT42,
|
||||||
PWM_TYPE_MULTISHOT,
|
PWM_TYPE_MULTISHOT,
|
||||||
PWM_TYPE_BRUSHED
|
PWM_TYPE_BRUSHED,
|
||||||
|
PWM_TYPE_DSHOT600,
|
||||||
|
PWM_TYPE_DSHOT150
|
||||||
} motorPwmProtocolTypes_e;
|
} motorPwmProtocolTypes_e;
|
||||||
|
|
||||||
#define PWM_TIMER_MHZ 1
|
#define PWM_TIMER_MHZ 1
|
||||||
|
|
||||||
#if defined(STM32F40_41xxx) // must be multiples of timer clock
|
#if defined(STM32F40_41xxx) // must be multiples of timer clock
|
||||||
#define ONESHOT125_TIMER_MHZ 12
|
#define ONESHOT125_TIMER_MHZ 12
|
||||||
|
@ -43,8 +45,28 @@ typedef enum {
|
||||||
#define PWM_BRUSHED_TIMER_MHZ 24
|
#define PWM_BRUSHED_TIMER_MHZ 24
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MOTOR_DMA_BUFFER_SIZE 18 /* resolution + frame reset (2us) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TIM_TypeDef *timer;
|
||||||
|
uint16_t timerDmaSources;
|
||||||
|
} motorDmaTimer_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ioTag_t ioTag;
|
||||||
|
const timerHardware_t *timerHardware;
|
||||||
|
uint16_t value;
|
||||||
|
uint16_t timerDmaSource;
|
||||||
|
#if defined(STM32F3) || defined(STM32F4)
|
||||||
|
uint32_t dmaBuffer[MOTOR_DMA_BUFFER_SIZE];
|
||||||
|
#else
|
||||||
|
uint8_t dmaBuffer[MOTOR_DMA_BUFFER_SIZE];
|
||||||
|
#endif
|
||||||
|
} motorDmaOutput_t;
|
||||||
|
|
||||||
struct timerHardware_s;
|
struct timerHardware_s;
|
||||||
typedef void(*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors
|
typedef void(*pwmWriteFuncPtr)(uint8_t index, uint16_t value); // function pointer used to write motors
|
||||||
|
typedef void(*pwmCompleteWriteFuncPtr)(uint8_t motorCount); // function pointer used after motors are written
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
volatile timCCR_t *ccr;
|
volatile timCCR_t *ccr;
|
||||||
|
@ -60,13 +82,20 @@ void servoInit(const servoConfig_t *servoConfig);
|
||||||
|
|
||||||
void pwmServoConfig(const struct timerHardware_s *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
|
void pwmServoConfig(const struct timerHardware_s *timerHardware, uint8_t servoIndex, uint16_t servoPwmRate, uint16_t servoCenterPulse);
|
||||||
|
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
void pwmWriteDigital(uint8_t index, uint16_t value);
|
||||||
|
void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType);
|
||||||
|
void pwmCompleteDigitalMotorUpdate(uint8_t motorCount);
|
||||||
|
#endif
|
||||||
|
|
||||||
void pwmWriteMotor(uint8_t index, uint16_t value);
|
void pwmWriteMotor(uint8_t index, uint16_t value);
|
||||||
void pwmShutdownPulsesForAllMotors(uint8_t motorCount);
|
void pwmShutdownPulsesForAllMotors(uint8_t motorCount);
|
||||||
void pwmCompleteOneshotMotorUpdate(uint8_t motorCount);
|
void pwmCompleteMotorUpdate(uint8_t motorCount);
|
||||||
|
|
||||||
void pwmWriteServo(uint8_t index, uint16_t value);
|
void pwmWriteServo(uint8_t index, uint16_t value);
|
||||||
|
|
||||||
pwmOutputPort_t *pwmGetMotors();
|
pwmOutputPort_t *pwmGetMotors(void);
|
||||||
|
bool pwmIsSynced(void);
|
||||||
void pwmDisableMotors(void);
|
void pwmDisableMotors(void);
|
||||||
void pwmEnableMotors(void);
|
void pwmEnableMotors(void);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Betaflight.
|
||||||
|
*
|
||||||
|
* Betaflight is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Betaflight is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Betaflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "pwm_output.h"
|
||||||
|
#include "nvic.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "rcc.h"
|
||||||
|
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
|
||||||
|
#define MAX_DMA_TIMERS 8
|
||||||
|
|
||||||
|
#define MOTOR_DSHOT600_MHZ 24
|
||||||
|
#define MOTOR_DSHOT150_MHZ 6
|
||||||
|
|
||||||
|
#define MOTOR_BIT_0 14
|
||||||
|
#define MOTOR_BIT_1 29
|
||||||
|
#define MOTOR_BITLENGTH 39
|
||||||
|
|
||||||
|
static uint8_t dmaMotorTimerCount = 0;
|
||||||
|
static motorDmaTimer_t dmaMotorTimers[MAX_DMA_TIMERS];
|
||||||
|
static motorDmaOutput_t dmaMotors[MAX_SUPPORTED_MOTORS];
|
||||||
|
|
||||||
|
uint8_t getTimerIndex(TIM_TypeDef *timer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
|
if (dmaMotorTimers[i].timer == timer) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dmaMotorTimers[dmaMotorTimerCount++].timer = timer;
|
||||||
|
return dmaMotorTimerCount-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmWriteDigital(uint8_t index, uint16_t value)
|
||||||
|
{
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[index];
|
||||||
|
|
||||||
|
value = (value <= 1000) ? 0 : ((value - 1000) * 2);
|
||||||
|
motor->value = value;
|
||||||
|
|
||||||
|
motor->dmaBuffer[0] = (value & 0x400) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[1] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[2] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[3] = (value & 0x80) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[4] = (value & 0x40) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[5] = (value & 0x20) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[6] = (value & 0x10) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[7] = (value & 0x8) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[8] = (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[9] = (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[10] = (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[11] = MOTOR_BIT_0; /* telemetry is always false for the moment */
|
||||||
|
|
||||||
|
/* check sum */
|
||||||
|
motor->dmaBuffer[12] = (value & 0x400) ^ (value & 0x40) ^ (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[13] = (value & 0x200) ^ (value & 0x20) ^ (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[14] = (value & 0x100) ^ (value & 0x10) ^ (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[15] = (value & 0x80) ^ (value & 0x8) ^ (0x0) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
|
||||||
|
DMA_SetCurrDataCounter(motor->timerHardware->dmaChannel, MOTOR_DMA_BUFFER_SIZE);
|
||||||
|
DMA_Cmd(motor->timerHardware->dmaChannel, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
|
||||||
|
{
|
||||||
|
UNUSED(motorCount);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
|
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
||||||
|
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void motor_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
|
||||||
|
{
|
||||||
|
if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[descriptor->userParam];
|
||||||
|
DMA_Cmd(descriptor->channel, DISABLE);
|
||||||
|
TIM_DMACmd(motor->timerHardware->tim, motor->timerDmaSource, DISABLE);
|
||||||
|
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType)
|
||||||
|
{
|
||||||
|
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||||
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[motorIndex];
|
||||||
|
motor->timerHardware = timerHardware;
|
||||||
|
|
||||||
|
TIM_TypeDef *timer = timerHardware->tim;
|
||||||
|
const IO_t motorIO = IOGetByTag(timerHardware->tag);
|
||||||
|
|
||||||
|
const uint8_t timerIndex = getTimerIndex(timer);
|
||||||
|
const bool configureTimer = (timerIndex == dmaMotorTimerCount-1);
|
||||||
|
|
||||||
|
IOInit(motorIO, OWNER_MOTOR, RESOURCE_OUTPUT, 0);
|
||||||
|
IOConfigGPIOAF(motorIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
|
||||||
|
|
||||||
|
if (configureTimer) {
|
||||||
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
|
|
||||||
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
|
TIM_Cmd(timer, DISABLE);
|
||||||
|
|
||||||
|
uint32_t hz = (pwmProtocolType == PWM_TYPE_DSHOT600 ? MOTOR_DSHOT600_MHZ : MOTOR_DSHOT150_MHZ) * 1000000;
|
||||||
|
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)((SystemCoreClock / timerClockDivisor(timer) / hz) - 1);
|
||||||
|
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
||||||
|
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIM_OCStructInit(&TIM_OCInitStructure);
|
||||||
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
|
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
|
||||||
|
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
|
||||||
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
|
||||||
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;
|
||||||
|
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
|
||||||
|
} else {
|
||||||
|
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
|
||||||
|
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
||||||
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
|
||||||
|
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
|
||||||
|
}
|
||||||
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
|
|
||||||
|
uint32_t timerChannelAddress = 0;
|
||||||
|
switch (timerHardware->channel) {
|
||||||
|
case TIM_Channel_1:
|
||||||
|
TIM_OC1Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC1;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR1);
|
||||||
|
TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
break;
|
||||||
|
case TIM_Channel_2:
|
||||||
|
TIM_OC2Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC2;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR2);
|
||||||
|
TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
break;
|
||||||
|
case TIM_Channel_3:
|
||||||
|
TIM_OC3Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC3;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR3);
|
||||||
|
TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
break;
|
||||||
|
case TIM_Channel_4:
|
||||||
|
TIM_OC4Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC4;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR4);
|
||||||
|
TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
|
||||||
|
|
||||||
|
TIM_CCxCmd(timer, motor->timerHardware->channel, TIM_CCx_Enable);
|
||||||
|
|
||||||
|
if (configureTimer) {
|
||||||
|
TIM_CtrlPWMOutputs(timer, ENABLE);
|
||||||
|
TIM_ARRPreloadConfig(timer, ENABLE);
|
||||||
|
TIM_Cmd(timer, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DMA_Channel_TypeDef *channel = timerHardware->dmaChannel;
|
||||||
|
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
||||||
|
|
||||||
|
DMA_Cmd(channel, DISABLE);
|
||||||
|
DMA_DeInit(channel);
|
||||||
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
|
DMA_InitStructure.DMA_PeripheralBaseAddr = timerChannelAddress;
|
||||||
|
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)motor->dmaBuffer;
|
||||||
|
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
|
||||||
|
DMA_InitStructure.DMA_BufferSize = MOTOR_DMA_BUFFER_SIZE;
|
||||||
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||||
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||||
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
|
||||||
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
|
||||||
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||||
|
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
|
||||||
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||||
|
|
||||||
|
DMA_Init(channel, &DMA_InitStructure);
|
||||||
|
|
||||||
|
DMA_ITConfig(channel, DMA_IT_TC, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Betaflight.
|
||||||
|
*
|
||||||
|
* Betaflight is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Betaflight is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Betaflight. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "io.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "pwm_output.h"
|
||||||
|
#include "nvic.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "rcc.h"
|
||||||
|
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
|
||||||
|
#define MAX_DMA_TIMERS 8
|
||||||
|
|
||||||
|
#define MOTOR_DSHOT600_MHZ 12
|
||||||
|
#define MOTOR_DSHOT150_MHZ 3
|
||||||
|
|
||||||
|
#define MOTOR_BIT_0 7
|
||||||
|
#define MOTOR_BIT_1 14
|
||||||
|
#define MOTOR_BITLENGTH 19
|
||||||
|
|
||||||
|
static uint8_t dmaMotorTimerCount = 0;
|
||||||
|
static motorDmaTimer_t dmaMotorTimers[MAX_DMA_TIMERS];
|
||||||
|
static motorDmaOutput_t dmaMotors[MAX_SUPPORTED_MOTORS];
|
||||||
|
|
||||||
|
uint8_t getTimerIndex(TIM_TypeDef *timer)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
|
if (dmaMotorTimers[i].timer == timer) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dmaMotorTimers[dmaMotorTimerCount++].timer = timer;
|
||||||
|
return dmaMotorTimerCount-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmWriteDigital(uint8_t index, uint16_t value)
|
||||||
|
{
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[index];
|
||||||
|
|
||||||
|
value = (value <= 1000) ? 0 : ((value - 1000) * 2);
|
||||||
|
motor->value = value;
|
||||||
|
|
||||||
|
motor->dmaBuffer[0] = (value & 0x400) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[1] = (value & 0x200) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[2] = (value & 0x100) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[3] = (value & 0x80) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[4] = (value & 0x40) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[5] = (value & 0x20) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[6] = (value & 0x10) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[7] = (value & 0x8) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[8] = (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[9] = (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[10] = (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[11] = MOTOR_BIT_0; /* telemetry is always false for the moment */
|
||||||
|
|
||||||
|
/* check sum */
|
||||||
|
motor->dmaBuffer[12] = (value & 0x400) ^ (value & 0x40) ^ (value & 0x4) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[13] = (value & 0x200) ^ (value & 0x20) ^ (value & 0x2) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[14] = (value & 0x100) ^ (value & 0x10) ^ (value & 0x1) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
motor->dmaBuffer[15] = (value & 0x80) ^ (value & 0x8) ^ (0x0) ? MOTOR_BIT_1 : MOTOR_BIT_0;
|
||||||
|
|
||||||
|
DMA_SetCurrDataCounter(motor->timerHardware->dmaStream, MOTOR_DMA_BUFFER_SIZE);
|
||||||
|
DMA_Cmd(motor->timerHardware->dmaStream, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmCompleteDigitalMotorUpdate(uint8_t motorCount)
|
||||||
|
{
|
||||||
|
UNUSED(motorCount);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < dmaMotorTimerCount; i++) {
|
||||||
|
TIM_SetCounter(dmaMotorTimers[i].timer, 0);
|
||||||
|
TIM_DMACmd(dmaMotorTimers[i].timer, dmaMotorTimers[i].timerDmaSources, ENABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void motor_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
|
||||||
|
{
|
||||||
|
if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[descriptor->userParam];
|
||||||
|
DMA_Cmd(descriptor->stream, DISABLE);
|
||||||
|
TIM_DMACmd(motor->timerHardware->tim, motor->timerDmaSource, DISABLE);
|
||||||
|
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwmDigitalMotorHardwareConfig(const timerHardware_t *timerHardware, uint8_t motorIndex, motorPwmProtocolTypes_e pwmProtocolType)
|
||||||
|
{
|
||||||
|
TIM_OCInitTypeDef TIM_OCInitStructure;
|
||||||
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
|
|
||||||
|
motorDmaOutput_t * const motor = &dmaMotors[motorIndex];
|
||||||
|
motor->timerHardware = timerHardware;
|
||||||
|
|
||||||
|
TIM_TypeDef *timer = timerHardware->tim;
|
||||||
|
const IO_t motorIO = IOGetByTag(timerHardware->tag);
|
||||||
|
|
||||||
|
const uint8_t timerIndex = getTimerIndex(timer);
|
||||||
|
const bool configureTimer = (timerIndex == dmaMotorTimerCount-1);
|
||||||
|
|
||||||
|
IOInit(motorIO, OWNER_MOTOR, RESOURCE_OUTPUT, 0);
|
||||||
|
IOConfigGPIOAF(motorIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_UP), timerHardware->alternateFunction);
|
||||||
|
|
||||||
|
if (configureTimer) {
|
||||||
|
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
|
||||||
|
|
||||||
|
RCC_ClockCmd(timerRCC(timer), ENABLE);
|
||||||
|
TIM_Cmd(timer, DISABLE);
|
||||||
|
|
||||||
|
uint32_t hz = (pwmProtocolType == PWM_TYPE_DSHOT600 ? MOTOR_DSHOT600_MHZ : MOTOR_DSHOT150_MHZ) * 1000000;
|
||||||
|
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(timer) / hz) - 1;
|
||||||
|
TIM_TimeBaseStructure.TIM_Period = MOTOR_BITLENGTH;
|
||||||
|
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
|
||||||
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
|
TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
|
||||||
|
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
|
||||||
|
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
|
||||||
|
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_High;
|
||||||
|
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
|
||||||
|
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
|
||||||
|
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
|
||||||
|
TIM_OCInitStructure.TIM_Pulse = 0;
|
||||||
|
|
||||||
|
uint32_t timerChannelAddress = 0;
|
||||||
|
uint32_t dmaItFlag = 0;
|
||||||
|
switch (timerHardware->channel) {
|
||||||
|
case TIM_Channel_1:
|
||||||
|
TIM_OC1Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC1;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR1);
|
||||||
|
TIM_OC1PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
dmaItFlag = DMA_IT_TCIF1;
|
||||||
|
break;
|
||||||
|
case TIM_Channel_2:
|
||||||
|
TIM_OC2Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC2;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR2);
|
||||||
|
TIM_OC2PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
dmaItFlag = DMA_IT_TCIF2;
|
||||||
|
break;
|
||||||
|
case TIM_Channel_3:
|
||||||
|
TIM_OC3Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC3;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR3);
|
||||||
|
TIM_OC3PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
dmaItFlag = DMA_IT_TCIF3;
|
||||||
|
break;
|
||||||
|
case TIM_Channel_4:
|
||||||
|
TIM_OC4Init(timer, &TIM_OCInitStructure);
|
||||||
|
motor->timerDmaSource = TIM_DMA_CC4;
|
||||||
|
timerChannelAddress = (uint32_t)(&timer->CCR4);
|
||||||
|
TIM_OC4PreloadConfig(timer, TIM_OCPreload_Enable);
|
||||||
|
dmaItFlag = DMA_IT_TCIF4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dmaMotorTimers[timerIndex].timerDmaSources |= motor->timerDmaSource;
|
||||||
|
|
||||||
|
TIM_CCxCmd(timer, motor->timerHardware->channel, TIM_CCx_Enable);
|
||||||
|
|
||||||
|
if (configureTimer) {
|
||||||
|
TIM_CtrlPWMOutputs(timer, ENABLE);
|
||||||
|
TIM_ARRPreloadConfig(timer, ENABLE);
|
||||||
|
TIM_Cmd(timer, ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DMA_Stream_TypeDef *stream = timerHardware->dmaStream;
|
||||||
|
|
||||||
|
DMA_Cmd(stream, DISABLE);
|
||||||
|
DMA_DeInit(stream);
|
||||||
|
DMA_StructInit(&DMA_InitStructure);
|
||||||
|
DMA_InitStructure.DMA_Channel = timerHardware->dmaChannel;
|
||||||
|
DMA_InitStructure.DMA_PeripheralBaseAddr = timerChannelAddress;
|
||||||
|
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)motor->dmaBuffer;
|
||||||
|
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
|
||||||
|
DMA_InitStructure.DMA_BufferSize = MOTOR_DMA_BUFFER_SIZE;
|
||||||
|
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||||
|
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
||||||
|
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
|
||||||
|
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
|
||||||
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||||
|
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
|
||||||
|
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
|
||||||
|
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
|
||||||
|
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
|
||||||
|
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
|
||||||
|
|
||||||
|
DMA_Init(stream, &DMA_InitStructure);
|
||||||
|
|
||||||
|
DMA_ITConfig(stream, DMA_IT_TC, ENABLE);
|
||||||
|
DMA_ClearITPendingBit(stream, dmaItFlag);
|
||||||
|
|
||||||
|
dmaSetHandler(timerHardware->dmaIrqHandler, motor_DMA_IRQHandler, NVIC_BUILD_PRIORITY(1, 2), motorIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -227,23 +227,7 @@ void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz)
|
||||||
|
|
||||||
// "The counter clock frequency (CK_CNT) is equal to f CK_PSC / (PSC[15:0] + 1)." - STM32F10x Reference Manual 14.4.11
|
// "The counter clock frequency (CK_CNT) is equal to f CK_PSC / (PSC[15:0] + 1)." - STM32F10x Reference Manual 14.4.11
|
||||||
// Thus for 1Mhz: 72000000 / 1000000 = 72, 72 - 1 = 71 = TIM_Prescaler
|
// Thus for 1Mhz: 72000000 / 1000000 = 72, 72 - 1 = 71 = TIM_Prescaler
|
||||||
#if defined (STM32F40_41xxx)
|
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / timerClockDivisor(tim) / ((uint32_t)mhz * 1000000)) - 1;
|
||||||
if (tim == TIM1 || tim == TIM8 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
|
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2 / ((uint32_t)mhz * 1000000)) - 1;
|
|
||||||
}
|
|
||||||
#elif defined (STM32F411xE)
|
|
||||||
if (tim == TIM1 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
|
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2 / ((uint32_t)mhz * 1000000)) - 1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / ((uint32_t)mhz * 1000000)) - 1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
|
||||||
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
|
||||||
|
|
|
@ -80,6 +80,15 @@ typedef struct timerHardware_s {
|
||||||
#if defined(STM32F3) || defined(STM32F4)
|
#if defined(STM32F3) || defined(STM32F4)
|
||||||
uint8_t alternateFunction;
|
uint8_t alternateFunction;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(USE_DSHOT)
|
||||||
|
#if defined(STM32F4)
|
||||||
|
DMA_Stream_TypeDef *dmaStream;
|
||||||
|
uint32_t dmaChannel;
|
||||||
|
#elif defined(STM32F3)
|
||||||
|
DMA_Channel_TypeDef *dmaChannel;
|
||||||
|
#endif
|
||||||
|
uint8_t dmaIrqHandler;
|
||||||
|
#endif
|
||||||
} timerHardware_t;
|
} timerHardware_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -149,6 +158,8 @@ void timerInit(void);
|
||||||
void timerStart(void);
|
void timerStart(void);
|
||||||
void timerForceOverflow(TIM_TypeDef *tim);
|
void timerForceOverflow(TIM_TypeDef *tim);
|
||||||
|
|
||||||
|
uint8_t timerClockDivisor(TIM_TypeDef *tim);
|
||||||
|
|
||||||
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz); // TODO - just for migration
|
void configTimeBase(TIM_TypeDef *tim, uint16_t period, uint8_t mhz); // TODO - just for migration
|
||||||
|
|
||||||
rccPeriphTag_t timerRCC(TIM_TypeDef *tim);
|
rccPeriphTag_t timerRCC(TIM_TypeDef *tim);
|
||||||
|
|
|
@ -37,6 +37,12 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
||||||
|
{
|
||||||
|
UNUSED(tim);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Selects the TIM Output Compare Mode.
|
* @brief Selects the TIM Output Compare Mode.
|
||||||
* @note This function does NOT disable the selected channel before changing the Output
|
* @note This function does NOT disable the selected channel before changing the Output
|
||||||
|
|
|
@ -29,6 +29,11 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
{ .TIMx = TIM17, .rcc = RCC_APB2(TIM17) },
|
{ .TIMx = TIM17, .rcc = RCC_APB2(TIM17) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
||||||
|
{
|
||||||
|
UNUSED(tim);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Selects the TIM Output Compare Mode.
|
* @brief Selects the TIM Output Compare Mode.
|
||||||
|
|
|
@ -58,6 +58,54 @@ const timerDef_t timerDefinitions[HARDWARE_TIMER_DEFINITION_COUNT] = {
|
||||||
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14) },
|
{ .TIMx = TIM14, .rcc = RCC_APB1(TIM14) },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
need a mapping from dma and timers to pins, and the values should all be set here to the dmaMotors array.
|
||||||
|
this mapping could be used for both these motors and for led strip.
|
||||||
|
|
||||||
|
only certain pins have OC output (already used in normal PWM et al) but then
|
||||||
|
there are only certain DMA streams/channels available for certain timers and channels.
|
||||||
|
*** (this may highlight some hardware limitations on some targets) ***
|
||||||
|
|
||||||
|
DMA1
|
||||||
|
|
||||||
|
Channel Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2 TIM4_CH1 TIM4_CH2 TIM4_CH3
|
||||||
|
3 TIM2_CH3 TIM2_CH1 TIM2_CH1 TIM2_CH4
|
||||||
|
TIM2_CH4
|
||||||
|
4
|
||||||
|
5 TIM3_CH4 TIM3_CH1 TIM3_CH2 TIM3_CH3
|
||||||
|
6 TIM5_CH3 TIM5_CH4 TIM5_CH1 TIM5_CH4 TIM5_CH2
|
||||||
|
7
|
||||||
|
|
||||||
|
DMA2
|
||||||
|
|
||||||
|
Channel Stream0 Stream1 Stream2 Stream3 Stream4 Stream5 Stream6 Stream7
|
||||||
|
0 TIM8_CH1 TIM1_CH1
|
||||||
|
TIM8_CH2 TIM1_CH2
|
||||||
|
TIM8_CH3 TIM1_CH3
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6 TIM1_CH1 TIM1_CH2 TIM1_CH1 TIM1_CH4 TIM1_CH3
|
||||||
|
7 TIM8_CH1 TIM8_CH2 TIM8_CH3 TIM8_CH4
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t timerClockDivisor(TIM_TypeDef *tim)
|
||||||
|
{
|
||||||
|
#if defined (STM32F40_41xxx)
|
||||||
|
if (tim == TIM8) return 1;
|
||||||
|
#endif
|
||||||
|
if (tim == TIM1 || tim == TIM9 || tim == TIM10 || tim == TIM11) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TIM_SelectOCxM_NoDisable(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
|
void TIM_SelectOCxM_NoDisable(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
|
||||||
{
|
{
|
||||||
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
||||||
|
|
|
@ -331,7 +331,6 @@ const mixerRules_t servoMixers[] = {
|
||||||
static servoMixer_t *customServoMixers;
|
static servoMixer_t *customServoMixers;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static motorMixer_t *customMixers;
|
static motorMixer_t *customMixers;
|
||||||
|
|
||||||
void mixerUseConfigs(
|
void mixerUseConfigs(
|
||||||
|
@ -404,14 +403,12 @@ void mixerInit(mixerMode_e mixerMode, motorMixer_t *initialCustomMixers)
|
||||||
|
|
||||||
void loadCustomServoMixer(void)
|
void loadCustomServoMixer(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
// reset settings
|
// reset settings
|
||||||
servoRuleCount = 0;
|
servoRuleCount = 0;
|
||||||
memset(currentServoMixer, 0, sizeof(currentServoMixer));
|
memset(currentServoMixer, 0, sizeof(currentServoMixer));
|
||||||
|
|
||||||
// load custom mixer into currentServoMixer
|
// load custom mixer into currentServoMixer
|
||||||
for (i = 0; i < MAX_SERVO_RULES; i++) {
|
for (uint8_t i = 0; i < MAX_SERVO_RULES; i++) {
|
||||||
// check if done
|
// check if done
|
||||||
if (customServoMixers[i].rate == 0)
|
if (customServoMixers[i].rate == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -421,13 +418,13 @@ void loadCustomServoMixer(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm)
|
void mixerConfigureOutput(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
motorCount = 0;
|
motorCount = 0;
|
||||||
|
|
||||||
syncMotorOutputWithPidLoop = !use_unsyncedPwm;
|
syncMotorOutputWithPidLoop = pwmIsSynced();
|
||||||
|
|
||||||
if (currentMixerMode == MIXER_CUSTOM || currentMixerMode == MIXER_CUSTOM_TRI || currentMixerMode == MIXER_CUSTOM_AIRPLANE) {
|
if (currentMixerMode == MIXER_CUSTOM || currentMixerMode == MIXER_CUSTOM_TRI || currentMixerMode == MIXER_CUSTOM_AIRPLANE) {
|
||||||
// load custom mixer into currentMixer
|
// load custom mixer into currentMixer
|
||||||
|
@ -518,18 +515,14 @@ void mixerLoadMix(int index, motorMixer_t *customMixers)
|
||||||
customMixers[i] = mixers[index].motor[i];
|
customMixers[i] = mixers[index].motor[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
void mixerConfigureOutput(void)
|
||||||
void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm)
|
|
||||||
{
|
{
|
||||||
|
syncMotorOutputWithPidLoop = pwmIsSynced();
|
||||||
|
|
||||||
syncMotorOutputWithPidLoop = !use_unsyncedPwm;
|
motorCount = QUAD_MOTOR_COUNT;
|
||||||
|
|
||||||
motorCount = 4;
|
|
||||||
|
|
||||||
uint8_t i;
|
for (uint8_t i = 0; i < motorCount; i++) {
|
||||||
for (i = 0; i < motorCount; i++) {
|
|
||||||
currentMixer[i] = mixerQuadX[i];
|
currentMixer[i] = mixerQuadX[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,23 +624,22 @@ void writeServos(void)
|
||||||
|
|
||||||
void writeMotors(void)
|
void writeMotors(void)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
for (uint8_t i = 0; i < motorCount; i++) {
|
||||||
|
|
||||||
for (i = 0; i < motorCount; i++)
|
|
||||||
pwmWriteMotor(i, motor[i]);
|
pwmWriteMotor(i, motor[i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (syncMotorOutputWithPidLoop) {
|
if (syncMotorOutputWithPidLoop) {
|
||||||
pwmCompleteOneshotMotorUpdate(motorCount);
|
pwmCompleteMotorUpdate(motorCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeAllMotors(int16_t mc)
|
void writeAllMotors(int16_t mc)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
// Sends commands to all motors
|
// Sends commands to all motors
|
||||||
for (i = 0; i < motorCount; i++)
|
for (uint8_t i = 0; i < motorCount; i++) {
|
||||||
motor[i] = mc;
|
motor[i] = mc;
|
||||||
|
}
|
||||||
|
|
||||||
writeMotors();
|
writeMotors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,7 +650,7 @@ void stopMotors(void)
|
||||||
delay(50); // give the timers and ESCs a chance to react.
|
delay(50); // give the timers and ESCs a chance to react.
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopPwmAllMotors()
|
void stopPwmAllMotors(void)
|
||||||
{
|
{
|
||||||
pwmShutdownPulsesForAllMotors(motorCount);
|
pwmShutdownPulsesForAllMotors(motorCount);
|
||||||
delayMicroseconds(1500);
|
delayMicroseconds(1500);
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#define MAX_SUPPORTED_MOTORS 12
|
#define MAX_SUPPORTED_MOTORS 12
|
||||||
#define MAX_SUPPORTED_SERVOS 8
|
#define MAX_SUPPORTED_SERVOS 8
|
||||||
|
|
||||||
|
#define QUAD_MOTOR_COUNT 4
|
||||||
|
|
||||||
// Note: this is called MultiType/MULTITYPE_* in baseflight.
|
// Note: this is called MultiType/MULTITYPE_* in baseflight.
|
||||||
typedef enum mixerMode
|
typedef enum mixerMode
|
||||||
{
|
{
|
||||||
|
@ -213,7 +215,7 @@ int servoDirection(int servoIndex, int fromChannel);
|
||||||
#endif
|
#endif
|
||||||
void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
|
void mixerInit(mixerMode_e mixerMode, motorMixer_t *customMotorMixers);
|
||||||
|
|
||||||
void mixerUsePWMOutputConfiguration(bool use_unsyncedPwm);
|
void mixerConfigureOutput(void);
|
||||||
|
|
||||||
void mixerResetDisarmedMotors(void);
|
void mixerResetDisarmedMotors(void);
|
||||||
void mixTable(void *pidProfilePtr);
|
void mixTable(void *pidProfilePtr);
|
||||||
|
|
|
@ -516,7 +516,10 @@ static const char * const lookupTableSuperExpoYaw[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const lookupTablePwmProtocol[] = {
|
static const char * const lookupTablePwmProtocol[] = {
|
||||||
"OFF", "ONESHOT125", "ONESHOT42", "MULTISHOT", "BRUSHED"
|
"OFF", "ONESHOT125", "ONESHOT42", "MULTISHOT", "BRUSHED",
|
||||||
|
#ifdef USE_DSHOT
|
||||||
|
"DSHOT600", "DSHOT150"
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const lookupTableRcInterpolation[] = {
|
static const char * const lookupTableRcInterpolation[] = {
|
||||||
|
|
|
@ -259,8 +259,9 @@ void init(void)
|
||||||
featureClear(FEATURE_3D);
|
featureClear(FEATURE_3D);
|
||||||
idlePulse = 0; // brushed motors
|
idlePulse = 0; // brushed motors
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_QUAD_MIXER_ONLY
|
#ifdef USE_QUAD_MIXER_ONLY
|
||||||
motorInit(&masterConfig.motorConfig, idlePulse, 4);
|
motorInit(&masterConfig.motorConfig, idlePulse, QUAD_MOTOR_COUNT);
|
||||||
#else
|
#else
|
||||||
motorInit(&masterConfig.motorConfig, idlePulse, mixers[masterConfig.mixerMode].motorCount);
|
motorInit(&masterConfig.motorConfig, idlePulse, mixers[masterConfig.mixerMode].motorCount);
|
||||||
#endif
|
#endif
|
||||||
|
@ -281,10 +282,7 @@ void init(void)
|
||||||
pwmRxSetInputFilteringMode(masterConfig.inputFilteringMode);
|
pwmRxSetInputFilteringMode(masterConfig.inputFilteringMode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool usingUnsyncedOutput = (masterConfig.motorConfig.useUnsyncedPwm
|
mixerConfigureOutput();
|
||||||
|| masterConfig.motorConfig.motorPwmProtocol == PWM_TYPE_BRUSHED
|
|
||||||
|| masterConfig.motorConfig.motorPwmProtocol == PWM_TYPE_STANDARD);
|
|
||||||
mixerUsePWMOutputConfiguration(usingUnsyncedOutput);
|
|
||||||
|
|
||||||
systemState |= SYSTEM_STATE_MOTORS_READY;
|
systemState |= SYSTEM_STATE_MOTORS_READY;
|
||||||
|
|
||||||
|
|
|
@ -20,14 +20,15 @@
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // PPM IN
|
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // PPM IN
|
||||||
{ TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S1_OUT
|
{ TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream2, DMA_Channel_6, DMA1_ST2_HANDLER }, // S1_OUT
|
||||||
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S2_OUT
|
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream4, DMA_Channel_6, DMA1_ST4_HANDLER }, // S2_OUT
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S3_OUT
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S3_OUT
|
||||||
{ TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S4_OUT
|
{ TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S4_OUT
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S5_OUT
|
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S5_OUT
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S6_OUT
|
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S6_OUT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
#define USE_ADC
|
#define USE_ADC
|
||||||
#define VBAT_ADC_PIN PC3
|
#define VBAT_ADC_PIN PC3
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
// LED Strip can run off Pin 6 (PB1) of the ESC outputs.
|
// LED Strip can run off Pin 6 (PB1) of the ESC outputs.
|
||||||
#define WS2811_PIN PB1
|
#define WS2811_PIN PB1
|
||||||
|
|
|
@ -4,5 +4,5 @@ FEATURES += SDCARD VCP ONBOARDFLASH
|
||||||
TARGET_SRC = \
|
TARGET_SRC = \
|
||||||
drivers/accgyro_spi_mpu6500.c \
|
drivers/accgyro_spi_mpu6500.c \
|
||||||
drivers/accgyro_mpu6500.c \
|
drivers/accgyro_mpu6500.c \
|
||||||
drivers/barometer_ms5611.c
|
drivers/barometer_ms5611.c
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,20 @@
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 }, // PPM IN
|
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // SS1 - PB0 - *TIM3_CH3, TIM1_CH2N, TIM8_CH2N
|
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // SS1 - PB1 - *TIM3_CH4, TIM1_CH3N, TIM8_CH3N
|
|
||||||
|
|
||||||
{ TIM4, IO_TAG(PB7), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM4 - S1
|
{ TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PPM IN
|
||||||
{ TIM4, IO_TAG(PB6), TIM_Channel_1, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM5 - S2
|
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // SS1 - PB0 - *TIM3_CH3, TIM1_CH2N, TIM8_CH2N
|
||||||
{ TIM17, IO_TAG(PB5), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10}, // PWM6 - S3
|
{ TIM1, IO_TAG(PB1), TIM_Channel_3, TIM1_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_6, NULL, 0 }, // SS1 - PB1 - *TIM3_CH4, TIM1_CH3N, TIM8_CH3N
|
||||||
{ TIM16, IO_TAG(PB4), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM7 - S4
|
|
||||||
|
{ TIM3, IO_TAG(PB7), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA1_Channel3, DMA1_CH3_HANDLER }, // PWM4 - S1
|
||||||
|
{ TIM8, IO_TAG(PB6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_5, DMA2_Channel3, DMA2_CH3_HANDLER }, // PWM5 - S2
|
||||||
|
{ TIM8, IO_TAG(PB5), TIM_Channel_3, TIM8_CC_IRQn, (1 | TIMER_OUTPUT_N_CHANNEL), IOCFG_AF_PP, GPIO_AF_3, DMA2_Channel1, DMA2_CH1_HANDLER }, // PWM6 - S3
|
||||||
|
{ TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, DMA1_Channel6, DMA1_CH6_HANDLER }, // PWM7 - S4
|
||||||
|
|
||||||
|
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6, NULL, 0 }, // GPIO TIMER - LED_STRIP
|
||||||
|
|
||||||
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6 }, // GPIO TIMER - LED_STRIP
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,8 @@
|
||||||
|
|
||||||
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
|
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define TARGET_IO_PORTA 0xffff
|
#define TARGET_IO_PORTA 0xffff
|
||||||
#define TARGET_IO_PORTB 0xffff
|
#define TARGET_IO_PORTB 0xffff
|
||||||
#define TARGET_IO_PORTC 0xffff
|
#define TARGET_IO_PORTC 0xffff
|
||||||
|
@ -174,5 +176,5 @@
|
||||||
#define TARGET_IO_PORTF (BIT(4))
|
#define TARGET_IO_PORTF (BIT(4))
|
||||||
|
|
||||||
#define USABLE_TIMER_CHANNEL_COUNT 8
|
#define USABLE_TIMER_CHANNEL_COUNT 8
|
||||||
#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(16) |TIM_N(17))
|
#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(8) | TIM_N(16) | TIM_N(17))
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,6 @@ TARGET_SRC = \
|
||||||
drivers/accgyro_spi_mpu6000.c \
|
drivers/accgyro_spi_mpu6000.c \
|
||||||
drivers/accgyro_mpu6500.c \
|
drivers/accgyro_mpu6500.c \
|
||||||
drivers/accgyro_spi_mpu6500.c \
|
drivers/accgyro_spi_mpu6500.c \
|
||||||
drivers/accgyro_spi_icm20689.c
|
drivers/accgyro_spi_icm20689.c \
|
||||||
|
drivers/pwm_output_stm32f3xx.c
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,17 @@
|
||||||
|
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // PPM_IN
|
|
||||||
|
|
||||||
{ TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S1_OUT
|
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // PPM_IN
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
|
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S3_OUT
|
{ TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S1_OUT
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
|
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S2_OUT
|
||||||
|
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S3_OUT
|
||||||
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
|
||||||
|
|
||||||
// { TIM5, GPIOA, Pin_0, TIM_Channel_1, TIM5_IRQn, 1, GPIO_Mode_AF, GPIO_PinSource0, GPIO_AF_TIM5 }, // LED Strip
|
// { TIM5, GPIOA, Pin_0, TIM_Channel_1, TIM5_IRQn, 1, GPIO_Mode_AF, GPIO_PinSource0, GPIO_AF_TIM5 }, // LED Strip
|
||||||
};
|
};
|
||||||
|
|
|
@ -183,11 +183,13 @@
|
||||||
|
|
||||||
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
|
#define USE_SERIAL_4WAY_BLHELI_INTERFACE
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define TARGET_IO_PORTA 0xffff
|
#define TARGET_IO_PORTA 0xffff
|
||||||
#define TARGET_IO_PORTB 0xffff
|
#define TARGET_IO_PORTB 0xffff
|
||||||
#define TARGET_IO_PORTC 0xffff
|
#define TARGET_IO_PORTC 0xffff
|
||||||
#define TARGET_IO_PORTD (BIT(2))
|
#define TARGET_IO_PORTD (BIT(2))
|
||||||
|
|
||||||
#define USABLE_TIMER_CHANNEL_COUNT 5
|
#define USABLE_TIMER_CHANNEL_COUNT 5
|
||||||
#define USED_TIMERS ( TIM_N(2) | TIM_N(3) | TIM_N(8) | TIM_N(9))
|
#define USED_TIMERS ( TIM_N(2) | TIM_N(3) | TIM_N(8) )
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,6 @@ TARGET_SRC = \
|
||||||
drivers/accgyro_spi_mpu6500.c \
|
drivers/accgyro_spi_mpu6500.c \
|
||||||
drivers/accgyro_mpu6500.c \
|
drivers/accgyro_mpu6500.c \
|
||||||
drivers/accgyro_spi_icm20689.c \
|
drivers/accgyro_spi_icm20689.c \
|
||||||
drivers/barometer_ms5611.c
|
drivers/barometer_ms5611.c \
|
||||||
|
drivers/pwm_output_stm32f4xx.c
|
||||||
|
|
||||||
|
|
|
@ -19,22 +19,23 @@
|
||||||
|
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_6},
|
{ TIM15, IO_TAG(PB15), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_6, DMA1_Channel5, DMA1_CH5_HANDLER },
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_2},
|
{ TIM8, IO_TAG(PB0), TIM_Channel_2, TIM8_CC_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_2, DMA2_Channel5, DMA2_CH5_HANDLER },
|
||||||
{ TIM15, IO_TAG(PB14), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel2, DMA1_CH2_HANDLER },
|
||||||
{ TIM15, IO_TAG(PB15), TIM_Channel_2, TIM1_BRK_TIM15_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM1, IO_TAG(PB14), TIM_Channel_2, TIM1_CC_IRQn, TIMER_OUTPUT_ENABLED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel3, DMA1_CH3_HANDLER },
|
||||||
{ TIM16, IO_TAG(PA6), TIM_Channel_1, TIM1_UP_TIM16_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM3, IO_TAG(PA6), TIM_Channel_1, TIM3_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel6, DMA1_CH6_HANDLER },
|
||||||
{ TIM17, IO_TAG(PA7), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM17, IO_TAG(PA7), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, TIMER_OUTPUT_ENABLED|TIMER_OUTPUT_INVERTED, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel7, DMA1_CH7_HANDLER },
|
||||||
|
|
||||||
{ TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1}, // TODO - Cleanup. KISS FC uses the same pin for serial and PPM
|
{ TIM2, IO_TAG(PB3), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0}, // TODO - Cleanup. KISS FC uses the same pin for serial and PPM
|
||||||
{ TIM2, IO_TAG(PA15), TIM_Channel_1, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM2, IO_TAG(PA15), TIM_Channel_1, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
|
||||||
{ TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1},
|
{ TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0},
|
||||||
{ TIM4, IO_TAG(PA13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_10},
|
{ TIM4, IO_TAG(PA13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_10, NULL, 0},
|
||||||
{ TIM8, IO_TAG(PA14), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_5},
|
{ TIM8, IO_TAG(PA14), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_5, NULL, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#define SBUS_PORT_OPTIONS (SERIAL_STOPBITS_2 | SERIAL_PARITY_EVEN | SERIAL_INVERTED | SERIAL_BIDIR)
|
#define SBUS_PORT_OPTIONS (SERIAL_STOPBITS_2 | SERIAL_PARITY_EVEN | SERIAL_INVERTED | SERIAL_BIDIR)
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define LED0 PB1
|
#define LED0 PB1
|
||||||
|
|
||||||
#define BEEPER PB13
|
#define BEEPER PB13
|
||||||
|
|
|
@ -4,5 +4,5 @@ FEATURES = VCP
|
||||||
TARGET_SRC = \
|
TARGET_SRC = \
|
||||||
drivers/accgyro_mpu.c \
|
drivers/accgyro_mpu.c \
|
||||||
drivers/display_ug2864hsweg01.c \
|
drivers/display_ug2864hsweg01.c \
|
||||||
drivers/accgyro_mpu6050.c
|
drivers/accgyro_mpu6050.c
|
||||||
|
|
||||||
|
|
|
@ -21,18 +21,22 @@
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
// PPM Pad
|
// PPM Pad
|
||||||
{ TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PPM - PB4
|
{ TIM3, IO_TAG(PB4), TIM_Channel_1, TIM3_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PPM - PB4
|
||||||
// PB5 / TIM3 CH2 is connected to USBPresent
|
// PB5 / TIM3 CH2 is connected to USBPresent
|
||||||
|
|
||||||
{ TIM4, IO_TAG(PB8), TIM_Channel_3, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM1 - PB8
|
{ TIM8, IO_TAG(PB8), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA2_Channel5, DMA2_CH5_HANDLER }, // PWM1 - PB8
|
||||||
{ TIM4, IO_TAG(PB9), TIM_Channel_4, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2 }, // PWM2 - PB9
|
{ TIM8, IO_TAG(PB9), TIM_Channel_3, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_10, DMA2_Channel1, DMA2_CH1_HANDLER }, // PWM2 - PB9
|
||||||
{ TIM15, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM15_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9 }, // PWM3 - PA3
|
{ TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, DMA1_Channel7, DMA1_CH7_HANDLER }, // PWM3 - PA3
|
||||||
{ TIM15, IO_TAG(PA2), TIM_Channel_1, TIM1_BRK_TIM15_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9 }, // PWM4 - PA2
|
{ TIM15, IO_TAG(PA2), TIM_Channel_1, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_9, DMA1_Channel5, DMA1_CH5_HANDLER }, // PWM4 - PA2
|
||||||
|
|
||||||
// UART3 RX/TX
|
// UART3 RX/TX
|
||||||
{ TIM2, IO_TAG(PB10), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM5 - PB10 - TIM2_CH3 / UART3_TX (AF7)
|
//{ TIM2, IO_TAG(PB10), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PWM5 - PB10 - TIM2_CH3 / UART3_TX (AF7)
|
||||||
{ TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1 }, // PWM6 - PB11 - TIM2_CH4 / UART3_RX (AF7)
|
//{ TIM2, IO_TAG(PB11), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }, // PWM6 - PB11 - TIM2_CH4 / UART3_RX (AF7)
|
||||||
|
{ TIM4, IO_TAG(PB7), TIM_Channel_2, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PWM7 - PB7
|
||||||
|
{ TIM4, IO_TAG(PB6), TIM_Channel_1, TIM4_IRQn, 1, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 }, // PWM8 - PB6
|
||||||
|
//{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_6, DMA1_Channel2, DMA1_CH2_HANDLER }, // GPIO_TIMER / LED_STRIP
|
||||||
};
|
};
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
//#define RSSI_ADC_PIN PB1
|
//#define RSSI_ADC_PIN PB1
|
||||||
//#define ADC_INSTANCE ADC3
|
//#define ADC_INSTANCE ADC3
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#define WS2811_PIN PA8
|
#define WS2811_PIN PA8
|
||||||
|
@ -193,4 +194,4 @@
|
||||||
#define TARGET_IO_PORTF (BIT(0)|BIT(1)|BIT(4))
|
#define TARGET_IO_PORTF (BIT(0)|BIT(1)|BIT(4))
|
||||||
|
|
||||||
#define USABLE_TIMER_CHANNEL_COUNT 7 // PPM + 6 Outputs (2 shared with UART3)
|
#define USABLE_TIMER_CHANNEL_COUNT 7 // PPM + 6 Outputs (2 shared with UART3)
|
||||||
#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(15))
|
#define USED_TIMERS (TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(8) | TIM_N(15))
|
||||||
|
|
|
@ -21,19 +21,20 @@
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 },// PPM (5th pin on FlexiIO port)
|
{ TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // PPM (5th pin on FlexiIO port)
|
||||||
{ TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 },// S2_IN - GPIO_PartialRemap_TIM3
|
{ TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // S2_IN - GPIO_PartialRemap_TIM3
|
||||||
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S3_IN
|
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S3_IN
|
||||||
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S4_IN
|
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S4_IN
|
||||||
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S5_IN
|
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S5_IN
|
||||||
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S6_IN
|
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S6_IN
|
||||||
|
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S1_OUT
|
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S1_OUT
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
|
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S2_OUT
|
||||||
{ TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S4_OUT
|
{ TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S4_OUT
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
|
||||||
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S5_OUT - GPIO_PartialRemap_TIM3
|
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, NULL, 0, 0 }, // S5_OUT - GPIO_PartialRemap_TIM3
|
||||||
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM1 }, // S6_OUT
|
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM1, NULL, 0, 0 }, // S6_OUT
|
||||||
};
|
};
|
||||||
|
|
|
@ -116,6 +116,8 @@
|
||||||
#define VBAT_ADC_PIN PC2
|
#define VBAT_ADC_PIN PC2
|
||||||
//#define RSSI_ADC_PIN PA0
|
//#define RSSI_ADC_PIN PA0
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
// LED Strip can run off Pin 5 (PA1) of the MOTOR outputs.
|
// LED Strip can run off Pin 5 (PA1) of the MOTOR outputs.
|
||||||
#define WS2811_PIN PA1
|
#define WS2811_PIN PA1
|
||||||
|
|
|
@ -19,20 +19,21 @@
|
||||||
|
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 }, // PPM (5th pin on FlexiIO port)
|
{ TIM12, IO_TAG(PB14), TIM_Channel_1, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // PPM (5th pin on FlexiIO port)
|
||||||
{ TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12 }, // S2_IN - GPIO_PartialRemap_TIM3
|
{ TIM12, IO_TAG(PB15), TIM_Channel_2, TIM8_BRK_TIM12_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM12, NULL, 0, 0 }, // S2_IN
|
||||||
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S3_IN
|
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S3_IN
|
||||||
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S4_IN
|
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S4_IN
|
||||||
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S5_IN
|
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S5_IN
|
||||||
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8 }, // S6_IN
|
{ TIM8, IO_TAG(PC9), TIM_Channel_4, TIM8_CC_IRQn, 0, IOCFG_AF_PP, GPIO_AF_TIM8, NULL, 0, 0 }, // S6_IN
|
||||||
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S1_OUT
|
{ TIM3, IO_TAG(PB0), TIM_Channel_3, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream7, DMA_Channel_5, DMA1_ST7_HANDLER }, // S1_OUT
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3 }, // S2_OUT
|
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM3, DMA1_Stream2, DMA_Channel_5, DMA1_ST2_HANDLER }, // S2_OUT
|
||||||
{ TIM9, IO_TAG(PA3), TIM_Channel_2, TIM1_BRK_TIM9_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM9 }, // S3_OUT
|
{ TIM2, IO_TAG(PA3), TIM_Channel_4, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream6, DMA_Channel_3, DMA1_ST6_HANDLER }, // S3_OUT
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2 }, // S4_OUT
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM2, DMA1_Stream1, DMA_Channel_3, DMA1_ST1_HANDLER }, // S4_OUT
|
||||||
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S5_OUT - GPIO_PartialRemap_TIM3
|
{ TIM5, IO_TAG(PA1), TIM_Channel_2, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream4, DMA_Channel_6, DMA1_ST4_HANDLER }, // S5_OUT
|
||||||
{ TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5 }, // S6_OUT
|
{ TIM5, IO_TAG(PA0), TIM_Channel_1, TIM5_IRQn, 1, IOCFG_AF_PP, GPIO_AF_TIM5, DMA1_Stream2, DMA_Channel_6, DMA1_ST2_HANDLER }, // S6_OUT
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#define USBD_SERIALNUMBER_STRING "0x8020000"
|
#define USBD_SERIALNUMBER_STRING "0x8020000"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define LED0 PB5
|
#define LED0 PB5
|
||||||
// Disable LED1, conflicts with AirbotF4/Flip32F4 beeper
|
// Disable LED1, conflicts with AirbotF4/Flip32F4 beeper
|
||||||
//#define LED1 PB4
|
//#define LED1 PB4
|
||||||
|
|
|
@ -21,21 +21,22 @@
|
||||||
#include "drivers/io.h"
|
#include "drivers/io.h"
|
||||||
|
|
||||||
#include "drivers/timer.h"
|
#include "drivers/timer.h"
|
||||||
|
#include "drivers/dma.h"
|
||||||
|
|
||||||
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
|
||||||
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_6 }, // PWM1 - PA8
|
{ TIM16, IO_TAG(PB8), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1, NULL, 0 },
|
||||||
{ TIM16, IO_TAG(PB8), TIM_Channel_1, TIM1_UP_TIM16_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1 }, // PWM2 - PB8
|
{ TIM17, IO_TAG(PB9), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1, NULL, 0 },
|
||||||
{ TIM17, IO_TAG(PB9), TIM_Channel_1, TIM1_TRG_COM_TIM17_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_1 }, // PWM3 - PB9
|
{ TIM1, IO_TAG(PA8), TIM_Channel_1, TIM1_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_6, DMA1_Channel2, DMA1_CH2_HANDLER },
|
||||||
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM4 - PC6
|
{ TIM8, IO_TAG(PC6), TIM_Channel_1, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel3, DMA2_CH3_HANDLER },
|
||||||
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM5 - PC7
|
{ TIM8, IO_TAG(PC7), TIM_Channel_2, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel5, DMA2_CH5_HANDLER },
|
||||||
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4 }, // PWM6 - PC8
|
{ TIM8, IO_TAG(PC8), TIM_Channel_3, TIM8_CC_IRQn, 1, IOCFG_AF_PP_PD, GPIO_AF_4, DMA2_Channel1, DMA2_CH1_HANDLER },
|
||||||
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2 }, // PWM7 - PB1
|
{ TIM3, IO_TAG(PB1), TIM_Channel_4, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM3, IO_TAG(PA4), TIM_Channel_2, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2 }, // PWM8 - PA2
|
{ TIM3, IO_TAG(PA4), TIM_Channel_2, TIM3_IRQn, 0, IOCFG_AF_PP_PD, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM4, IO_TAG(PD12), TIM_Channel_1, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM9 - PD12
|
{ TIM4, IO_TAG(PD12), TIM_Channel_1, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM4, IO_TAG(PD13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM10 - PD13
|
{ TIM4, IO_TAG(PD13), TIM_Channel_2, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM4, IO_TAG(PD14), TIM_Channel_3, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM11 - PD14
|
{ TIM4, IO_TAG(PD14), TIM_Channel_3, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM4, IO_TAG(PD15), TIM_Channel_4, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2 }, // PWM12 - PD15
|
{ TIM4, IO_TAG(PD15), TIM_Channel_4, TIM4_IRQn, 0, IOCFG_AF_PP, GPIO_AF_2, NULL, 0 },
|
||||||
{ TIM2, IO_TAG(PA1), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 }, // PWM13 - PA1
|
{ TIM2, IO_TAG(PA1), TIM_Channel_2, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 },
|
||||||
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1 } // PWM14 - PA2
|
{ TIM2, IO_TAG(PA2), TIM_Channel_3, TIM2_IRQn, 0, IOCFG_AF_PP, GPIO_AF_1, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,8 @@
|
||||||
#define RSSI_ADC_PIN PC2
|
#define RSSI_ADC_PIN PC2
|
||||||
#define EXTERNAL1_ADC_PIN PC3
|
#define EXTERNAL1_ADC_PIN PC3
|
||||||
|
|
||||||
|
#define USE_DSHOT
|
||||||
|
|
||||||
#define LED_STRIP
|
#define LED_STRIP
|
||||||
#define WS2811_PIN PB8 // TIM16_CH1
|
#define WS2811_PIN PB8 // TIM16_CH1
|
||||||
#define WS2811_TIMER TIM16
|
#define WS2811_TIMER TIM16
|
||||||
|
|
Loading…
Reference in New Issue