From b7e00c8254397ee76014eda565597f12c3b2be2d Mon Sep 17 00:00:00 2001 From: neoxic Date: Sun, 15 Oct 2023 21:59:54 -0700 Subject: [PATCH] Firmware revision 8 + Music format extensions to better accommodate for RTTTL + Fix bug when watchdog reset was delayed while playing music + Fix brushed mode (broken in Rev7) + Require power cycling for brushed mode Support for PWM/EN bridge (PWM_ENABLE build option) Support for two-wire serial (PA2+PA15) Tune current sensor for AIRBOT1 and ESCAPE1 targets Cosmetics --- CMakeLists.txt | 4 +- README.md | 1 - boot/mcu/STM32F0/config.c | 5 +- boot/mcu/STM32G0/config.c | 5 +- boot/src/io.c | 2 +- mcu/AT32F421/config.c | 5 +- mcu/GD32E230/config.c | 5 +- mcu/GD32F350/config.c | 5 +- mcu/STM32F051/config.c | 5 +- mcu/STM32G071/config.c | 5 +- src/cli.c | 62 +++++++++---------- src/common.h | 4 +- src/io.c | 16 ++--- src/main.c | 124 ++++++++++++++++++++++++++++++-------- src/util.c | 74 ++++++++++++++++++----- 15 files changed, 226 insertions(+), 96 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dea90e..9ba3e51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,10 +48,10 @@ endfunction() add_subdirectory(boot) add_target(AIKON1 STM32G071 DEAD_TIME=35 COMP_MAP=213 IO_PA6) -add_target(AIRBOT1 AT32F421 DEAD_TIME=66 COMP_MAP=321 SENS_MAP=0xA3A6 VOLT_MUL=74 CURR_MUL=20 LED_MAP=0xA15B3B4) +add_target(AIRBOT1 AT32F421 DEAD_TIME=66 COMP_MAP=321 SENS_MAP=0xA3A6 VOLT_MUL=74 CURR_MUL=30 LED_MAP=0xA15B3B4) add_target(AIRBOT2 STM32F051 DEAD_TIME=26 COMP_MAP=321 SENS_MAP=0xA3 VOLT_MUL=74 IO_PA2) 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(ESCAPE1 STM32G071 DEAD_TIME=35 COMP_MAP=123 SENS_MAP=0xA5A4 VOLT_MUL=110 CURR_MUL=30 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) diff --git a/README.md b/README.md index e472005..d00fd7c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ Features + Temperature/voltage/current protection + Variable PWM frequency, active freewheeling + Customizable startup music -+ Configuration via CLI using a USB-TTL adapter or Betaflight passthrough Installation diff --git a/boot/mcu/STM32F0/config.c b/boot/mcu/STM32F0/config.c index 968042f..95e2132 100644 --- a/boot/mcu/STM32F0/config.c +++ b/boot/mcu/STM32F0/config.c @@ -32,8 +32,9 @@ void init(void) { #ifdef IO_PA2 RCC_APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) - GPIOA_PUPDR |= 0x10; // A2 (pull-up) - GPIOA_MODER &= ~0x10; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) + GPIOA_MODER &= ~0x40000010; // A2 (USART2_TX), A15 (USART2_RX) #else RCC_APB1ENR |= RCC_APB1ENR_TIM3EN; #ifdef IO_PA6 diff --git a/boot/mcu/STM32G0/config.c b/boot/mcu/STM32G0/config.c index 526f84a..a58020a 100644 --- a/boot/mcu/STM32G0/config.c +++ b/boot/mcu/STM32G0/config.c @@ -31,8 +31,9 @@ void init(void) { #ifdef IO_PA2 RCC_APBENR1 |= RCC_APBENR1_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) - GPIOA_PUPDR |= 0x10; // A2 (pull-up) - GPIOA_MODER &= ~0x10; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) + GPIOA_MODER &= ~0x40000010; // A2 (USART2_TX), A15 (USART2_RX) #else RCC_APBENR1 |= RCC_APBENR1_TIM3EN; #ifdef IO_PA6 diff --git a/boot/src/io.c b/boot/src/io.c index 5376fed..e3763f9 100644 --- a/boot/src/io.c +++ b/boot/src/io.c @@ -32,7 +32,7 @@ void initio(void) { #ifdef IO_PA2 USART2_BRR = CLK_CNT(38400); - USART2_CR3 = USART_CR3_HDSEL; + if (!(GPIOA_IDR & 0x8000)) USART2_CR3 = USART_CR3_HDSEL; // A15 low USART2_CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; #else TIM3_SMCR = TIM_SMCR_SMS_RM | TIM_SMCR_TS_TI1F_ED; // Reset on any edge on TI1 diff --git a/mcu/AT32F421/config.c b/mcu/AT32F421/config.c index d5d2f74..949e76e 100644 --- a/mcu/AT32F421/config.c +++ b/mcu/AT32F421/config.c @@ -55,7 +55,7 @@ void init(void) { GPIOB_MODER = 0xffffeffa; // B0 (TIM1_CH2N), B1 (TIM1_CH3N), B6 (USART1_TX) #ifndef ANALOG RCC_APB2ENR |= RCC_APB2ENR_TIM15EN; - GPIOA_PUPDR |= 0x10; // A2 (pull-up) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) GPIOA_MODER &= ~0x10; // A2 (TIM15_CH1) #endif @@ -171,6 +171,9 @@ void io_serial(void) { RCC_APB2ENR &= ~RCC_APB2ENR_TIM15EN; RCC_APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_MODER |= 0x80000000; // In case A15 is LED + GPIOA_MODER &= ~0x40000000; // A15 (USART2_RX) } void io_analog(void) { diff --git a/mcu/GD32E230/config.c b/mcu/GD32E230/config.c index 265e067..94f8733 100644 --- a/mcu/GD32E230/config.c +++ b/mcu/GD32E230/config.c @@ -55,7 +55,7 @@ void init(void) { GPIOB_MODER = 0xffffeffa; // B0 (TIM1_CH2N), B1 (TIM1_CH3N), B6 (USART1_TX) #ifndef ANALOG RCC_APB2ENR |= RCC_APB2ENR_TIM15EN; - GPIOA_PUPDR |= 0x10; // A2 (pull-up) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) GPIOA_MODER &= ~0x10; // A2 (TIM15_CH1) #endif @@ -130,6 +130,9 @@ void io_serial(void) { RCC_APB2ENR &= ~RCC_APB2ENR_TIM15EN; RCC_APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_MODER |= 0x80000000; // In case A15 is LED + GPIOA_MODER &= ~0x40000000; // A15 (USART2_RX) } void io_analog(void) { diff --git a/mcu/GD32F350/config.c b/mcu/GD32F350/config.c index eed9462..4476cce 100644 --- a/mcu/GD32F350/config.c +++ b/mcu/GD32F350/config.c @@ -55,7 +55,7 @@ void init(void) { #ifndef ANALOG #ifdef IO_PA2 RCC_APB2ENR |= RCC_APB2ENR_TIM15EN; - GPIOA_PUPDR |= 0x10; // A2 (pull-up) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) GPIOA_MODER &= ~0x10; // A2 (TIM15_CH1) #else RCC_APB1ENR |= RCC_APB1ENR_TIM3EN; @@ -138,6 +138,9 @@ void io_serial(void) { RCC_APB2ENR &= ~RCC_APB2ENR_TIM15EN; RCC_APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_MODER |= 0x80000000; // In case A15 is LED + GPIOA_MODER &= ~0x40000000; // A15 (USART2_RX) } void io_analog(void) { diff --git a/mcu/STM32F051/config.c b/mcu/STM32F051/config.c index 5072e15..f6f46b7 100644 --- a/mcu/STM32F051/config.c +++ b/mcu/STM32F051/config.c @@ -46,7 +46,7 @@ void init(void) { #ifndef ANALOG #ifdef IO_PA2 RCC_APB2ENR |= RCC_APB2ENR_TIM15EN; - GPIOA_PUPDR |= 0x10; // A2 (pull-up) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) GPIOA_MODER &= ~0x10; // A2 (TIM15_CH1) #else RCC_APB1ENR |= RCC_APB1ENR_TIM3EN; @@ -122,6 +122,9 @@ void io_serial(void) { RCC_APB2ENR &= ~RCC_APB2ENR_TIM15EN; RCC_APB1ENR |= RCC_APB1ENR_USART2EN; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_MODER |= 0x80000000; // In case A15 is LED + GPIOA_MODER &= ~0x40000000; // A15 (USART2_RX) } void io_analog(void) { diff --git a/mcu/STM32G071/config.c b/mcu/STM32G071/config.c index fead219..d707d2a 100644 --- a/mcu/STM32G071/config.c +++ b/mcu/STM32G071/config.c @@ -65,7 +65,7 @@ void init(void) { #ifdef IO_PA2 RCC_APBENR2 |= RCC_APBENR2_TIM15EN; GPIOA_AFRL |= 0x500; // A2 (TIM15_CH1) - GPIOA_PUPDR |= 0x10; // A2 (pull-up) + GPIOA_PUPDR |= 0x80000010; // A2 (pull-up), A15 (pull-down) GPIOA_MODER &= ~0x10; // A2 (TIM15_CH1) #else RCC_APBENR1 |= RCC_APBENR1_TIM3EN; @@ -242,6 +242,9 @@ void io_serial(void) { RCC_APBENR1 |= RCC_APBENR1_USART2EN; GPIOA_AFRL &= ~0xf00; GPIOA_AFRL |= 0x100; // A2 (USART2_TX) + GPIOA_AFRH |= 0x10000000; // A15 (USART2_RX) + GPIOA_MODER |= 0x80000000; // In case A15 is LED + GPIOA_MODER &= ~0x40000000; // A15 (USART2_RX) DMAMUX1_CxCR(1) = DMAMUX_CxCR_DMAREQ_ID_USART2_RX; } diff --git a/src/cli.c b/src/cli.c index 76deb0b..6349583 100644 --- a/src/cli.c +++ b/src/cli.c @@ -21,37 +21,37 @@ XX( 0, val, arm) \ XX( 1, val, damp) \ XX( 2, val, revdir) \ - XX( 3, val, timing) \ - XX( 4, val, sine_range) \ - XX( 5, val, sine_power) \ - XX( 6, val, freq_min) \ - XX( 7, val, freq_max) \ - XX( 8, val, duty_min) \ - XX( 9, val, duty_max) \ - XX(10, val, duty_spup) \ - XX(11, val, duty_ramp) \ - XX(12, val, duty_rate) \ - XX(13, val, duty_drag) \ - XX(14, val, throt_mode) \ - XX(15, val, throt_set) \ - XX(16, val, throt_cal) \ - XX(17, val, throt_min) \ - XX(18, val, throt_mid) \ - XX(19, val, throt_max) \ - XX(20, val, input_mode) \ - XX(21, val, input_chid) \ - XX(22, val, telem_mode) \ - XX(23, val, telem_phid) \ - XX(24, val, telem_poles) \ - XX(25, val, prot_temp) \ - XX(26, val, prot_volt) \ - XX(27, val, prot_cells) \ - XX(28, val, prot_curr) \ - XX(29, str, music) \ - XX(30, val, volume) \ - XX(31, val, beacon) \ - XX(32, val, led) \ - XX(33, val, brushed) \ + XX( 3, val, brushed) \ + XX( 4, val, timing) \ + XX( 5, val, sine_range) \ + XX( 6, val, sine_power) \ + XX( 7, val, freq_min) \ + XX( 8, val, freq_max) \ + XX( 9, val, duty_min) \ + XX(10, val, duty_max) \ + XX(11, val, duty_spup) \ + XX(12, val, duty_ramp) \ + XX(13, val, duty_rate) \ + XX(14, val, duty_drag) \ + XX(15, val, throt_mode) \ + XX(16, val, throt_set) \ + XX(17, val, throt_cal) \ + XX(18, val, throt_min) \ + XX(19, val, throt_mid) \ + XX(20, val, throt_max) \ + XX(21, val, input_mode) \ + XX(22, val, input_chid) \ + XX(23, val, telem_mode) \ + XX(24, val, telem_phid) \ + XX(25, val, telem_poles) \ + XX(26, val, prot_temp) \ + XX(27, val, prot_volt) \ + XX(28, val, prot_cells) \ + XX(29, val, prot_curr) \ + XX(30, str, music) \ + XX(31, val, volume) \ + XX(32, val, beacon) \ + XX(33, val, led) \ static int beep = -1; diff --git a/src/common.h b/src/common.h index 4bd930d..19512ed 100644 --- a/src/common.h +++ b/src/common.h @@ -66,6 +66,7 @@ typedef struct { char arm; char damp; char revdir; + char brushed; char timing; char sine_range; char sine_power; @@ -92,11 +93,10 @@ typedef struct { char prot_volt; char prot_cells; char prot_curr; - char music[128]; + char music[256]; char volume; char beacon; char led; - char brushed; } Cfg; typedef struct { diff --git a/src/io.c b/src/io.c index 4215f02..dea2633 100644 --- a/src/io.c +++ b/src/io.c @@ -75,7 +75,7 @@ static void entryirq(void) { #ifdef IO_PA2 io_serial(); USART2_BRR = CLK_CNT(38400); - USART2_CR3 = USART_CR3_HDSEL; + if (!(GPIOA_IDR & 0x8000)) USART2_CR3 = USART_CR3_HDSEL; // A15 low USART2_CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; #else TIM3_CCER = 0; @@ -202,13 +202,13 @@ static void servoirq(void) { int w = TIM_CCR2(IOTIM); // Pulse width if (p < 2000) return; // Invalid signal if (w >= 28 && w <= 32) { // Telemetry request - telreq = 1; IWDG_KR = IWDG_KR_RESET; + telreq = 1; return; } if (w < 800 || w > 2200) return; // Invalid signal - servoval(w); IWDG_KR = IWDG_KR_RESET; + servoval(w); } static void dshotirq(void) { @@ -491,10 +491,10 @@ static void throtdma(void) { resync(); return; } + IWDG_KR = IWDG_KR_RESET; x &= 0xfff; if (x & 0x800) x -= 0x1000; // Propagate sign throt = x; - IWDG_KR = IWDG_KR_RESET; } static void ibusdma(void) { @@ -520,8 +520,8 @@ static void ibusdma(void) { u -= a + b; if (i == n) x = v & 0xfff; } - servoval(x); IWDG_KR = IWDG_KR_RESET; + servoval(x); } static void sbusdma(void) { @@ -529,6 +529,7 @@ static void sbusdma(void) { resync(); return; } + IWDG_KR = IWDG_KR_RESET; int n = cfg.input_chid - 1; int i = (n * 11) >> 3; int a = (n * 3) & 7; @@ -540,7 +541,6 @@ static void sbusdma(void) { x < 946 ? scale(x, 240, 946, -2000, 0): x > 1101 ? scale(x, 1101, 1807, 0, 2000): 0: x > 318 ? scale(x, 318, 1807, 0, 2000): 0; - IWDG_KR = IWDG_KR_RESET; } static void cliirq(void) { @@ -569,7 +569,7 @@ static void cliirq(void) { if (USART2_ISR & USART_ISR_FE || i == sizeof iobuf - 1) WWDG_CR = WWDG_CR_WDGA; // Data error char b = USART2_RDR; // Clear RXNE if (b == '\b' || b == 0x7f) { // Backspace - if (i > 0) --i; + if (i) --i; return; } iobuf[i++] = b; @@ -628,7 +628,7 @@ static void cliirq(void) { TIM3_DIER = TIM_DIER_CC2IE; n = 0; if (b == '\b' || b == 0x7f) { // Backspace - if (i > 0) --i; + if (i) --i; break; } iobuf[i++] = b; diff --git a/src/main.c b/src/main.c index bbba923..562fbf5 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ #include "common.h" -#define REVISION 7 +#define REVISION 8 const Cfg cfgdata = { .id = 0x32ea, @@ -27,6 +27,7 @@ const Cfg cfgdata = { .arm = ARM, // Wait for 250ms zero throttle on startup .damp = DAMP, // Complementary PWM (active freewheeling) .revdir = REVDIR, // Reversed motor direction + .brushed = BRUSHED, // Brushed mode .timing = TIMING, // Motor timing (3.75*X degrees) [1..7] .sine_range = SINE_RANGE, // Sine startup range (%) [0 - off, 5..25] .sine_power = SINE_POWER, // Sine startup power (%) [1..15] @@ -57,7 +58,6 @@ const Cfg cfgdata = { .volume = VOLUME, // Sound volume (%) [0..100] .beacon = BEACON, // Beacon volume (%) [0..100] .led = LED, // LED bits - .brushed = BRUSHED, // Brushed mode }; __attribute__((__section__(".cfg"))) @@ -68,7 +68,7 @@ char analog, telreq, flipdir, beacon, dshotext; volatile uint32_t tickms; static int step, sine, sync, ival; -static char prep, accl, tick, reverse, ready; +static char prep, accl, tick, reverse, ready, brushed; static void reset(void) { __disable_irq(); @@ -89,7 +89,7 @@ static void resync(void) { sync = 0; accl = 0; ival = 10000; - ertm = 100000000; + ertm = 60000000; } #endif @@ -105,14 +105,21 @@ static void resync(void) { */ static void nextstep(void) { - if (cfg.brushed) { +#ifndef SENSORED + if (brushed) { int m1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC2PE; int m2 = TIM_CCMR2_OC3PE; -#ifdef INVERTED_HIGH - int er = TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#ifdef PWM_ENABLE + int er = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E; + if (reverse) { + m1 |= TIM_CCMR1_OC1M_FORCE_LOW | TIM_CCMR1_OC2M_PWM1; + m2 |= TIM_CCMR2_OC3M_FORCE_LOW; + } else { + m1 |= TIM_CCMR1_OC1M_PWM1 | TIM_CCMR1_OC2M_FORCE_LOW; + m2 |= TIM_CCMR2_OC3M_PWM1; + } #else int er = 0; -#endif if (reverse) { m1 |= TIM_CCMR1_OC1M_FORCE_HIGH | TIM_CCMR1_OC2M_PWM1; m2 |= TIM_CCMR2_OC3M_FORCE_HIGH; @@ -124,6 +131,13 @@ static void nextstep(void) { er |= TIM_CCER_CC1E | TIM_CCER_CC2NE | TIM_CCER_CC3E; if (cfg.damp) er |= TIM_CCER_CC1NE | TIM_CCER_CC3NE; } +#endif +#ifdef INVERTED_HIGH + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif TIM1_CCMR1 = m1; TIM1_CCMR2 = m2; TIM1_CCER = er; @@ -131,7 +145,6 @@ static void nextstep(void) { sync = 6; return; } -#ifndef SENSORED if (sine) { // Sine startup IFTIM_OCR = sine; TIM_ARR(IFTIM) = sine; @@ -154,11 +167,18 @@ static void nextstep(void) { if (prep) return; TIM1_CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_PWM1 | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_PWM1; TIM1_CCMR2 = TIM_CCMR2_OC3PE | TIM_CCMR2_OC3M_PWM1; -#ifdef INVERTED_HIGH - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE | TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#ifdef PWM_ENABLE + int er = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E; #else - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE | TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E; + int er = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE; +#endif +#ifdef INVERTED_HIGH + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; #endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif + TIM1_CCER = er; TIM1_EGR = TIM_EGR_UG | TIM_EGR_COMG; TIM_DIER(IFTIM) = 0; compctl(0); @@ -185,23 +205,31 @@ static void nextstep(void) { int z = (step & 1) ^ reverse; // BEMF rising int m1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC2PE; int m2 = TIM_CCMR2_OC3PE | TIM_CCMR2_OC4PE | TIM_CCMR2_OC4M_PWM1; -#ifdef INVERTED_HIGH - int er = TIM_CCER_CC4E | TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; -#else int er = TIM_CCER_CC4E; -#endif #ifndef SENSORED int cc = z ? 4 : 0; #endif if (p & 1) { m1 |= TIM_CCMR1_OC1M_PWM1; - er |= cfg.damp ? TIM_CCER_CC1NE | TIM_CCER_CC1E : TIM_CCER_CC1E; +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1E; +#else + er |= cfg.damp ? TIM_CCER_CC1E | TIM_CCER_CC1NE : TIM_CCER_CC1E; +#endif } else if (n & 1) { +#ifdef PWM_ENABLE + m1 |= TIM_CCMR1_OC1M_FORCE_LOW; +#else m1 |= TIM_CCMR1_OC1M_FORCE_HIGH; +#endif er |= TIM_CCER_CC1NE; } else { if (!z) { +#ifdef PWM_ENABLE + m1 |= TIM_CCMR1_OC1M_FORCE_HIGH; +#else m1 |= TIM_CCMR1_OC1M_FORCE_LOW; +#endif er |= TIM_CCER_CC1NE; } #ifndef SENSORED @@ -210,13 +238,25 @@ static void nextstep(void) { } if (p & 2) { m1 |= TIM_CCMR1_OC2M_PWM1; - er |= cfg.damp ? TIM_CCER_CC2NE | TIM_CCER_CC2E : TIM_CCER_CC2E; +#ifdef PWM_ENABLE + er |= TIM_CCER_CC2E; +#else + er |= cfg.damp ? TIM_CCER_CC2E | TIM_CCER_CC2NE : TIM_CCER_CC2E; +#endif } else if (n & 2) { +#ifdef PWM_ENABLE + m1 |= TIM_CCMR1_OC2M_FORCE_LOW; +#else m1 |= TIM_CCMR1_OC2M_FORCE_HIGH; +#endif er |= TIM_CCER_CC2NE; } else { if (!z) { +#ifdef PWM_ENABLE + m1 |= TIM_CCMR1_OC2M_FORCE_HIGH; +#else m1 |= TIM_CCMR1_OC2M_FORCE_LOW; +#endif er |= TIM_CCER_CC2NE; } #ifndef SENSORED @@ -225,19 +265,37 @@ static void nextstep(void) { } if (p & 4) { m2 |= TIM_CCMR2_OC3M_PWM1; - er |= cfg.damp ? TIM_CCER_CC3NE | TIM_CCER_CC3E : TIM_CCER_CC3E; +#ifdef PWM_ENABLE + er |= TIM_CCER_CC3E; +#else + er |= cfg.damp ? TIM_CCER_CC3E | TIM_CCER_CC3NE : TIM_CCER_CC3E; +#endif } else if (n & 4) { +#ifdef PWM_ENABLE + m2 |= TIM_CCMR2_OC3M_FORCE_LOW; +#else m2 |= TIM_CCMR2_OC3M_FORCE_HIGH; +#endif er |= TIM_CCER_CC3NE; } else { if (!z) { +#ifdef PWM_ENABLE + m2 |= TIM_CCMR2_OC3M_FORCE_HIGH; +#else m2 |= TIM_CCMR2_OC3M_FORCE_LOW; +#endif er |= TIM_CCER_CC3NE; } #ifndef SENSORED cc |= 3; #endif } +#ifdef INVERTED_HIGH + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif TIM1_CCMR1 = m1; TIM1_CCMR2 = m2; TIM1_CCER = er; @@ -274,15 +332,28 @@ static void nextstep(void) { } static void laststep(void) { +#ifdef PWM_ENABLE + TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_HIGH | TIM_CCMR1_OC2M_FORCE_HIGH; + TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_HIGH; +#else TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_LOW | TIM_CCMR1_OC2M_FORCE_LOW; TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_LOW; +#endif + int er = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE; +#ifdef INVERTED_HIGH + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif + TIM1_CCER = er; TIM1_EGR = TIM_EGR_COMG; +#ifdef PWM_ENABLE + TIM1_CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_PWM2 | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_PWM2; + TIM1_CCMR2 = TIM_CCMR2_OC3PE | TIM_CCMR2_OC3M_PWM2; +#else TIM1_CCMR1 = TIM_CCMR1_OC1PE | TIM_CCMR1_OC1M_PWM1 | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_PWM1; TIM1_CCMR2 = TIM_CCMR2_OC3PE | TIM_CCMR2_OC3M_PWM1; -#ifdef INVERTED_HIGH - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE | TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; -#else - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE; #endif TIM1_EGR = TIM_EGR_UG | TIM_EGR_COMG; #ifndef SENSORED @@ -404,6 +475,7 @@ static void beep(void) { void main(void) { memcpy(_cfg_start, _cfg, _cfg_end - _cfg_start); // Copy configuration to SRAM checkcfg(); + brushed = cfg.brushed; throt = cfg.throt_set * 20; #if defined ANALOG || defined ANALOG_PIN analog = IO_ANALOG; @@ -473,7 +545,7 @@ void main(void) { SCB_SCR = SCB_SCR_SLEEPONEXIT; // Suspend main loop __WFI(); int input = throt; - int range = cfg.sine_range * 20; + int range = brushed ? 0 : cfg.sine_range * 20; int margin = range && sine ? 20 : 0; int newduty = 0; if (!running) curduty = 0; @@ -539,7 +611,7 @@ void main(void) { if (++r == 8) r = 0; if (curduty >= newduty || (curduty += b) > newduty) curduty = newduty; // Acceleration slew rate limiting } - int ccr = scale(curduty, 0, 2000, running && cfg.damp ? DEAD_TIME : 0, cfg.brushed ? arr - (CLK_MHZ * 3 >> 1) : arr); + int ccr = scale(curduty, 0, 2000, running && cfg.damp ? DEAD_TIME : 0, brushed ? arr - (CLK_MHZ * 3 >> 1) : arr); TIM1_CR1 = TIM_CR1_CEN | TIM_CR1_ARPE | TIM_CR1_UDIS; TIM1_ARR = arr; TIM1_CCR1 = ccr; @@ -550,7 +622,7 @@ void main(void) { if (running && !step) { // Start motor __disable_irq(); ival = 10000; - ertm = 100000000; + ertm = 60000000; nextstep(); TIM1_EGR = TIM_EGR_UG | TIM_EGR_COMG; TIM1_DIER |= TIM_DIER_COMIE; diff --git a/src/util.c b/src/util.c index c26098d..d74ad60 100644 --- a/src/util.c +++ b/src/util.c @@ -63,15 +63,21 @@ void checkcfg(void) { #endif cfg.arm = !!cfg.arm; #endif +#ifdef PWM_ENABLE + cfg.damp = 1; +#else cfg.damp = !!cfg.damp; +#endif cfg.revdir = !!cfg.revdir; #ifdef SENSORED + cfg.brushed = 0; cfg.timing = 0; cfg.sine_range = 0; cfg.sine_power = 0; #else + cfg.brushed = !!cfg.brushed; cfg.timing = clamp(cfg.timing, 1, 7); - cfg.sine_range = cfg.damp && cfg.sine_range && !cfg.brushed ? clamp(cfg.sine_range, 5, 25) : 0; + cfg.sine_range = cfg.damp && cfg.sine_range ? clamp(cfg.sine_range, 5, 25) : 0; cfg.sine_power = clamp(cfg.sine_power, 1, 15); #endif cfg.freq_min = clamp(cfg.freq_min, 16, 48); @@ -120,7 +126,6 @@ void checkcfg(void) { #else cfg.led = 0; #endif - cfg.brushed = !!cfg.brushed; } int savecfg(void) { @@ -174,40 +179,77 @@ int resetcfg(void) { int playmusic(const char *str, int vol) { static const uint16_t arr[] = {30575, 28859, 27240, 25713, 24268, 22906, 21621, 20407, 19261, 18181, 17160, 16196, 15287}; static char flag; + char *end; + int tmp = strtol(str, &end, 10); // Tempo + if (str == end) tmp = 125; // 120BPM by default + else { + if (tmp < 10 || tmp > 999) return 0; // Sanity check + tmp = 15000 / tmp; + str = end; + } if (!vol || ertm || flag) return 0; flag = 1; vol <<= 1; +#ifdef PWM_ENABLE + TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_LOW | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_PWM1; + TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_LOW; + int er = TIM_CCER_CC2E; +#else TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_HIGH | TIM_CCMR1_OC2PE | TIM_CCMR1_OC2M_PWM1; TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_HIGH; + int er = TIM_CCER_CC1NE | TIM_CCER_CC2E | TIM_CCER_CC2NE | TIM_CCER_CC3NE; +#endif #ifdef INVERTED_HIGH - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE | TIM_CCER_CC2E | TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; -#else - TIM1_CCER = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE | TIM_CCER_CC2E; + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; #endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif + TIM1_CCER = er; TIM1_PSC = CLK_MHZ / 8 - 1; // 8MHz - for (int a, b; (a = *str++);) { + for (int a, b, c = 0; (a = *str++);) { if (a >= 'a' && a <= 'g') a -= 'c', b = 0; // Low note else if (a >= 'A' && a <= 'G') a -= 'C', b = 1; // High note - else if (a == '_') goto set; // Pause - else break; + else if (a == '_') goto update; // Pause + else { + if (a == '+' && !c++) continue; // Octave up + if (a == '-' && c--) continue; // Octave down + break; // Invalid specifier + } a = (a + 7) % 7 << 1; if (a > 4) --a; if (*str == '#') ++a, ++str; - TIM1_ARR = arr[a] >> b; // Frequency + TIM1_ARR = arr[a] >> (b + c); // Frequency TIM1_CCR2 = vol; // Volume - set: + update: TIM1_EGR = TIM_EGR_UG | TIM_EGR_COMG; - a = *str; - if (a >= '1' && a <= '8') a -= '0', ++str; - else a = 1; - for (uint32_t t = tickms + a * 125; t != tickms;) { // Duration 125*X ms - if (TIM14_CR1 & TIM_CR1_CEN) TIM14_EGR = TIM_EGR_UG; // Reset arming timeout - IWDG_KR = IWDG_KR_RESET; + a = strtol(str, &end, 10); // Duration + if (str == end) a = 1; + else { + if (a < 1 || a > 99) break; // Sanity check + str = end; + } + for (uint32_t t = tickms + tmp * a; t != tickms;) { + if (!(TIM14_CR1 & TIM_CR1_CEN)) continue; + TIM14_EGR = TIM_EGR_UG; // Reset arming timeout } TIM1_CCR2 = 0; // Preload silence } +#ifdef PWM_ENABLE + TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_HIGH | TIM_CCMR1_OC2M_FORCE_HIGH; + TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_HIGH; +#else TIM1_CCMR1 = TIM_CCMR1_OC1M_FORCE_LOW | TIM_CCMR1_OC2M_FORCE_LOW; TIM1_CCMR2 = TIM_CCMR2_OC3M_FORCE_LOW; +#endif + er = TIM_CCER_CC1NE | TIM_CCER_CC2NE | TIM_CCER_CC3NE; +#ifdef INVERTED_HIGH + er |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P; +#endif +#ifdef PWM_ENABLE + er |= TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC3NP; +#endif + TIM1_CCER = er; TIM1_PSC = 0; TIM1_ARR = CLK_KHZ / 24 - 1; TIM1_EGR = TIM_EGR_UG | TIM_EGR_COMG;