Skip to content

Commit

Permalink
Firmware revision 5
Browse files Browse the repository at this point in the history
+ DSHOT 1200
+ Servo PWM up to 500Hz
+ Oneshot125 up to 4kHz

New targets: FLYCOLOR2, NEUTRONRC2
16kHz main loop (was 10kHz)
Set DSHOT telemetry delay at 30us (was 25us)
Force arming after reset
Minor desync detection tuning
ANALOG never return rather than reset
Fix broken pause modifier
Add MUSIC (startup music) build option
Cosmetics
  • Loading branch information
neoxic committed Jul 29, 2023
1 parent cfacbc5 commit b7a902c
Show file tree
Hide file tree
Showing 16 changed files with 121 additions and 93 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ add_target(AIRBOT2 STM32F051 DEAD_TIME=26 COMP_MAP=321 SENS_MAP=0xA3 VOLT_MUL=74
add_target(EMAX1 STM32F051 DEAD_TIME=26 COMP_MAP=123 IO_PA2)
add_target(ESCAPE1 STM32G071 DEAD_TIME=35 COMP_MAP=123 SENS_MAP=0xA5A4 VOLT_MUL=110 CURR_MUL=40 LED_WS2812 IO_PA2)
add_target(FLYCOLOR1 STM32F051 DEAD_TIME=26 COMP_MAP=123 SENS_MAP=0xA6 VOLT_MUL=110 LED_MAP=0xB5B4B3 IO_PA2)
add_target(FLYCOLOR2 STM32G071 DEAD_TIME=35 COMP_MAP=123 SENS_MAP=0xA6 VOLT_MUL=110 LED_MAP=0xB8)
add_target(HAKRC1 STM32F051 DEAD_TIME=26 COMP_MAP=213 SENS_MAP=0xA3 VOLT_MUL=110 LED_MAP=0xA15B5B3 LED_INV)
add_target(HAKRC2 AT32F421 DEAD_TIME=66 COMP_MAP=213 SENS_MAP=0xA3 VOLT_MUL=110 LED_MAP=0xA15B5B3 LED_INV)
add_target(HGLRC1 STM32F051 DEAD_TIME=26 COMP_MAP=123 SENS_MAP=0xA6 VOLT_MUL=210 IO_PA2)
add_target(IFLIGHT1 STM32F051 DEAD_TIME=26 COMP_MAP=321 SENS_MAP=0xA3A6 VOLT_MUL=110 CURR_MUL=20 LED_MAP=0xB8B5B3 LED_INV)
add_target(IFLIGHT2 STM32G071 DEAD_TIME=35 COMP_MAP=213 SENS_MAP=0xA5A4 VOLT_MUL=110 CURR_MUL=20 LED_WS2812 IO_PA6)
add_target(IFLIGHT3 STM32G071 DEAD_TIME=35 COMP_MAP=132 SENS_MAP=0xA0 VOLT_MUL=110 LED_WS2812)
add_target(NEUTRONRC1 STM32G071 DEAD_TIME=35 COMP_MAP=123 SENS_MAP=0xA6A4 VOLT_MUL=210 CURR_MUL=50 LED_WS2812)
add_target(NEUTRONRC2 AT32F421 DEAD_TIME=66 COMP_MAP=321)
add_target(SKYSTARS1 GD32E230 DEAD_TIME=40 COMP_MAP=321 SENS_MAP=0xA3 VOLT_MUL=110 LED_MAP=0xB5B3A15)
add_target(TMOTOR1 STM32F051 DEAD_TIME=26 COMP_MAP=132 IO_PA2)
add_target(TMOTOR2 STM32F051 DEAD_TIME=26 COMP_MAP=321)
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ Firmware for 32-bit BLDC motor electronic speed controllers that aims at simplic
Features
--------

+ Servo PWM up to 400Hz, automatic throttle calibration
+ DSHOT 300/600, bidirectional DSHOT, extended telemetry
+ Servo PWM, Oneshot125, automatic throttle calibration
+ DSHOT 300/600/1200, bidirectional DSHOT, extended telemetry
+ Analog/serial/iBUS/SBUS input mode
+ KISS/iBUS/S.Port telemetry
+ DSHOT 3D mode, turtle mode, beacon, LED, programming
+ Sine startup mode
+ Sine startup mode (crawler mode)
+ Proportional brake, drag brake
+ Temperature/voltage/current protection
+ Variable PWM frequency, active freewheeling
+ Customizable sounds
+ Customizable startup music
+ Configuration via CLI using a USB-TTL adapter or Betaflight passthrough


Expand Down
2 changes: 1 addition & 1 deletion mcu/AT32F421/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
#define ADC1_BASE ADC_BASE
#define COMP_CSR MMIO32(SYSCFG_COMP_BASE + 0x1c)

static uint16_t buf[10];
static char len, ain;
static uint16_t buf[10];

void init(void) {
RCC_CFGR &= ~RCC_CFGR_SW_PLL;
Expand Down
8 changes: 4 additions & 4 deletions mcu/AT32F421/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

#pragma once

#if SENS_MAP == 0xA3A6 // A3 (volt), A6 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x66
#elif SENS_MAP == 0xA3 // A3 (volt)
#if SENS_MAP == 0xA3 // A3 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x3
#elif SENS_MAP == 0xA3A6 // A3 (volt), A6 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x66
#endif

#ifndef THROT_CHAN
Expand Down
2 changes: 1 addition & 1 deletion mcu/GD32E230/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
#define ADC1_BASE ADC_BASE
#define COMP_CSR MMIO32(SYSCFG_COMP_BASE + 0x1c)

static uint16_t buf[5];
static char len, ain;
static uint16_t buf[5];

void init(void) {
RCC_CFGR &= ~RCC_CFGR_SW_PLL;
Expand Down
2 changes: 1 addition & 1 deletion mcu/STM32F051/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

#define COMP_CSR MMIO32(SYSCFG_COMP_BASE + 0x1c)

static uint16_t buf[5];
static char len, ain;
static uint16_t buf[5];

void init(void) {
RCC_APB2RSTR = -1;
Expand Down
10 changes: 5 additions & 5 deletions mcu/STM32F051/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@

#pragma once

#if SENS_MAP == 0xA3A6 // A3 (volt), A6 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x48
#define SENS_SWAP
#elif SENS_MAP == 0xA3 // A3 (volt)
#if SENS_MAP == 0xA3 // A3 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x8
#elif SENS_MAP == 0xA6 // A6 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x40
#elif SENS_MAP == 0xA3A6 // A3 (volt), A6 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x48
#define SENS_SWAP
#endif

#ifndef THROT_CHAN
Expand Down
2 changes: 1 addition & 1 deletion mcu/STM32G071/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
#define ADC1_DR ADC_DR(ADC1)
#define ADC1_CCR ADC_CCR(ADC1)

static uint16_t buf[10];
static char len, ain;
static uint16_t buf[10];

void init(void) {
RCC_APBRSTR2 = -1;
Expand Down
11 changes: 7 additions & 4 deletions mcu/STM32G071/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@

#pragma once

#if SENS_MAP == 0xA5A4 // A5 (volt), A4 (curr)
#if SENS_MAP == 0xA0 // A0 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x0
#elif SENS_MAP == 0xA6 // A6 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x6
#elif SENS_MAP == 0xA5A4 // A5 (volt), A4 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x54
#elif SENS_MAP == 0xA6A4 // A6 (volt), A4 (curr)
#define SENS_CNT 2
#define SENS_CHAN 0x64
#elif SENS_MAP == 0xA0 // A0 (volt)
#define SENS_CNT 1
#define SENS_CHAN 0x0
#endif

#ifndef THROT_CHAN
Expand Down
2 changes: 1 addition & 1 deletion mcu/STSPIN32F0/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#include <libopencm3/stm32/adc.h>
#include "common.h"

static uint16_t buf[3];
static char len, ain;
static uint16_t buf[3];

void init(void) {
RCC_APB2RSTR = -1;
Expand Down
2 changes: 1 addition & 1 deletion src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ extern const Cfg cfgdata;
extern Cfg cfg;
extern int throt, ertm, erpm, temp, volt, curr, csum, dshotval, beepval;
extern char analog, telreq, flipdir, beacon, dshotext;
extern volatile uint32_t tick;
extern volatile uint32_t tickms;

void init(void);
void initio(void);
Expand Down
7 changes: 7 additions & 0 deletions src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
#define LED_CNT 3
#elif !defined LED_MAP
#define LED_CNT 0
#elif LED_MAP == 0xB8
#define LED_CNT 1
#define LED1_PORT B
#define LED1_PIN 8
#elif LED_MAP == 0xA15B3B4
#define LED_CNT 3
#define LED1_PORT A
Expand Down Expand Up @@ -212,6 +216,9 @@
#ifndef PROT_CURR
#define PROT_CURR 0
#endif
#ifndef MUSIC
#define MUSIC "dfa#"
#endif
#ifndef VOLUME
#define VOLUME 25
#endif
Expand Down
59 changes: 35 additions & 24 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ static char rxlen;
static void (*ioirq)(void);
static void (*iodma)(void);

static char iobuf[1024], dshotinv;
static char dshotinv, iobuf[1024];
static uint16_t dshotarr1, dshotarr2, dshotbuf[23];

void initio(void) {
ioirq = entryirq;
Expand All @@ -61,7 +62,7 @@ void initio(void) {
}

static void entryirq(void) {
static int c, n, u = 5;
static int n, c, d;
if (TIM_SR(IOTIM) & TIM_SR_UIF) { // Timeout ~66ms
TIM_SR(IOTIM) = ~TIM_SR_UIF;
if (!IOTIM_IDR) { // Low level
Expand Down Expand Up @@ -129,34 +130,43 @@ static void entryirq(void) {
#endif
int t = TIM_CCR1(IOTIM); // Time between two rising edges
if (!n++) return; // First capture is always invalid
if (t >= 2400) { // Servo PWM
ioirq = calibirq;
calibirq();
if (TIM_PSC(IOTIM)) {
if (t > 2000) { // Servo/Oneshot125
ioirq = calibirq;
calibirq();
return;
}
TIM_PSC(IOTIM) = TIM_PSC(IOTIM) == CLK_MHZ - 1 ? CLK_MHZ / 8 - 1 : 0;
TIM_EGR(IOTIM) = TIM_EGR_UG;
n = 0;
return;
}
if (t >= 5 || n <= 4) return;
if (u != t) {
u = t;
int m = 3;
while (t >= CLK_CNT(800000)) t >>= 1, --m;
if (d != m) {
d = m;
n = 1;
return;
}
if (m < 1 || n < 4) return;
ioirq = dshotirq;
iodma = dshotdma;
dshotarr1 = CLK_CNT(m * 150000) - 1;
dshotarr2 = CLK_CNT(m * 375000) - 1;
TIM_SMCR(IOTIM) = TIM_SMCR_SMS_RM | TIM_SMCR_TS_TI1F_ED; // Reset on any edge on TI1
TIM_CCER(IOTIM) = 0;
TIM_DIER(IOTIM) = TIM_DIER_UIE;
TIM_PSC(IOTIM) = u >= 2; // 0 - DSHOT 600, 1 - DSHOT 300
TIM_ARR(IOTIM) = CLK_CNT(300000) - 1; // Minimum idle time
TIM_ARR(IOTIM) = dshotarr1; // Frame reset time (two bits)
TIM_EGR(IOTIM) = TIM_EGR_UG;
DMA1_CPAR(IOTIM_DMA) = (uint32_t)&TIM_CCR1(IOTIM);
DMA1_CMAR(IOTIM_DMA) = (uint32_t)iobuf;
DMA1_CMAR(IOTIM_DMA) = (uint32_t)dshotbuf;
}

static void calibirq(void) { // Align pulse period to the nearest millisecond via HSI trimming within 6.25% margin
static int n, q, x, y;
if (!cfg.throt_cal) goto done;
int p = TIM_CCR1(IOTIM); // Pulse period
if (p < 2400) return; // Invalid signal
if (p < 2000) return; // Invalid signal
IWDG_KR = IWDG_KR_RESET;
q += p - ((p + 500) / 1000) * 1000; // Cumulative error
if (++n & 3) return;
Expand Down Expand Up @@ -189,7 +199,7 @@ static void servoval(int x) {
static void servoirq(void) {
int p = TIM_CCR1(IOTIM); // Pulse period
int w = TIM_CCR2(IOTIM); // Pulse width
if (p < 2400) return; // Invalid signal
if (p < 2000) return; // Invalid signal
if (w >= 28 && w <= 32) { // Telemetry request
telreq = 1;
IWDG_KR = IWDG_KR_RESET;
Expand All @@ -213,7 +223,7 @@ static void dshotirq(void) {
}
}
DMA1_CNDTR(IOTIM_DMA) = 16;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_8BIT;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_16BIT;
TIM_ARR(IOTIM) = -1;
TIM_EGR(IOTIM) = TIM_EGR_UG;
TIM_CR1(IOTIM) = TIM_CR1_CEN | TIM_CR1_ARPE;
Expand Down Expand Up @@ -245,7 +255,7 @@ static void dshotdma(void) {
#endif
DMA1_CCR(IOTIM_DMA) = 0;
DMA1_CNDTR(IOTIM_DMA) = 16;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_8BIT;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_16BIT;
TIM_ARR(IOTIM) = -1;
TIM_EGR(IOTIM) = TIM_EGR_UG;
TIM_SMCR(IOTIM) = TIM_SMCR_SMS_RM | TIM_SMCR_TS_TI1F_ED; // Reset on any edge on TI1
Expand All @@ -255,14 +265,15 @@ static void dshotdma(void) {
return;
}
int x = 0;
int y = (dshotarr1 + 1) >> 2; // Half-bit time
for (int i = 0; i < 16; ++i) {
x <<= 1;
if (iobuf[i] >= CLK_CNT(1200000)) x |= 1;
if (dshotbuf[i] >= y) x |= 1;
}
if (dshotcrc(x, dshotinv)) { // Invalid checksum
DMA1_CCR(IOTIM_DMA) = 0;
TIM_CR1(IOTIM) = TIM_CR1_CEN | TIM_CR1_ARPE | TIM_CR1_URS;
TIM_ARR(IOTIM) = CLK_CNT(300000) - 1; // Minimum idle time
TIM_ARR(IOTIM) = dshotarr1; // Frame reset time (two bits)
TIM_EGR(IOTIM) = TIM_EGR_UG;
TIM_SR(IOTIM) = ~TIM_SR_UIF;
TIM_DIER(IOTIM) = TIM_DIER_UIE;
Expand All @@ -277,7 +288,7 @@ static void dshotdma(void) {
TIM_CR2(IOTIM) = TIM_CR2_CCDS; // CC1 DMA request on UEV using the same DMA channel
DMA1_CCR(IOTIM_DMA) = 0;
DMA1_CNDTR(IOTIM_DMA) = 23;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_8BIT;
DMA1_CCR(IOTIM_DMA) = DMA_CCR_EN | DMA_CCR_TCIE | DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PSIZE_16BIT | DMA_CCR_MSIZE_16BIT;
if (!dshotval) {
int a = ertm ? ertm : 65408;
int b = 0;
Expand All @@ -290,18 +301,18 @@ static void dshotdma(void) {
for (int i = 0, j = 0; i < 16; i += 4, j += 5) b |= gcr[a >> i & 0xf] << j;
for (int p = -1, i = 19; i >= 0; --i) {
if (b >> i & 1) p = ~p;
iobuf[20 - i] = p;
dshotbuf[20 - i] = p;
}
iobuf[0] = -1;
iobuf[21] = 0;
iobuf[22] = 0;
dshotbuf[0] = -1;
dshotbuf[21] = 0;
dshotbuf[22] = 0;
__disable_irq();
int arr = (CLK_CNT(40000) >> TIM_PSC(IOTIM)) - TIM_CNT(IOTIM) - 1; // Calculate 25us output delay
int arr = CLK_CNT(33333) - TIM_CNT(IOTIM) - 1; // Calculate 30us output delay
if (arr < 99) arr = 99; // Sanity check
TIM_ARR(IOTIM) = arr; // Preload output delay
TIM_CCR1(IOTIM) = 0; // Preload high level
TIM_EGR(IOTIM) = TIM_EGR_UG; // Update registers and trigger DMA to preload the first bit
TIM_ARR(IOTIM) = CLK_CNT(750000) - 1; // Preload bit time
TIM_ARR(IOTIM) = dshotarr2; // Preload bit time
TIM_CCER(IOTIM) = TIM_CCER_CC1E; // Enable output
__enable_irq();
if (!rep || !--rep) dshotval = 0;
Expand Down
Loading

0 comments on commit b7a902c

Please sign in to comment.