From 9a21297cd1bc2a4a7f214bb176aab00312b5437c Mon Sep 17 00:00:00 2001 From: bugobliterator Date: Thu, 25 Aug 2022 11:06:10 +0530 Subject: [PATCH] AP_HAL_ChibiOS: add support for DShot on IOMCU set timer counter size to be a byte wide use HAL_DSHOT_ENABLED instead of DISABLE_DSHOT build iomcu-dshot from existing iomcu correct defines for DMAR size on iomcu allow iomcu dshot rate to be configured from FMU correct DMA allocation for dshot on iomcu allow debug builds on iofirmware ensure dshot is enabled on iomcu dshot support proper iomcu dshot output thread triggered by FMU allow selective disablement of serial LEDs and passthrough disable serial LEDs and passthrough on iomcu-dshot propagate ESC telemetry to iomcu dshot_send_groups() for iomcu remove use of ICU on iomcu for dshot. only allocate possible DMA channels rename serial passthrough and dshot defines update dshot docs resize dshot iomcu main stack to minimum correct dshot prescaler usage and bit_width_mul calculation use ChibiOS in tickless mode on iomcu-dshot so that virtual timers can be used propagate dshot commands to iomcu passthrough oneshot125 to iomcu --- libraries/AP_HAL_ChibiOS/RCOutput.cpp | 343 ++++++++++++------ libraries/AP_HAL_ChibiOS/RCOutput.h | 84 ++++- libraries/AP_HAL_ChibiOS/RCOutput_serial.cpp | 20 +- libraries/AP_HAL_ChibiOS/Util.cpp | 2 +- .../AP_HAL_ChibiOS/hwdef/CubeOrange/hwdef.inc | 1 + .../hwdef/iomcu-dshot/hwdef.dat | 43 +++ .../AP_HAL_ChibiOS/hwdef/iomcu/hwdef.dat | 5 +- .../hwdef/iomcu_f103_8MHz/hwdef.dat | 2 + 8 files changed, 371 insertions(+), 129 deletions(-) create mode 100644 libraries/AP_HAL_ChibiOS/hwdef/iomcu-dshot/hwdef.dat diff --git a/libraries/AP_HAL_ChibiOS/RCOutput.cpp b/libraries/AP_HAL_ChibiOS/RCOutput.cpp index 0e2f647a37..0cad6f8930 100644 --- a/libraries/AP_HAL_ChibiOS/RCOutput.cpp +++ b/libraries/AP_HAL_ChibiOS/RCOutput.cpp @@ -14,6 +14,10 @@ * * Code by Andrew Tridgell and Siddharth Bharat Purohit * Bi-directional dshot based on Betaflight, code by Andy Piper and Siddharth Bharat Purohit + * + * There really is no dshot reference. For information try these resources: + * https://blck.mn/2016/11/dshot-the-new-kid-on-the-block/ + * https://www.swallenhardware.io/battlebots/2019/4/20/a-developers-guide-to-dshot-escs */ #include @@ -23,6 +27,7 @@ #include #include "GPIO.h" #include "Util.h" +#include "Scheduler.h" #include "hwdef/common/stm32_util.h" #include "hwdef/common/watchdog.h" #include @@ -61,7 +66,9 @@ extern AP_IOMCU iomcu; #define TELEM_IC_SAMPLE 16 struct RCOutput::pwm_group RCOutput::pwm_group_list[] = { HAL_PWM_GROUPS }; +#if HAL_SERIAL_ESC_COMM_ENABLED struct RCOutput::irq_state RCOutput::irq; +#endif const uint8_t RCOutput::NUM_GROUPS = ARRAY_SIZE(RCOutput::pwm_group_list); // event mask for triggering a PWM send @@ -97,7 +104,7 @@ void RCOutput::init() group.dshot_event_mask = EVENT_MASK(i); for (uint8_t j = 0; j < 4; j++ ) { -#if !APM_BUILD_TYPE(APM_BUILD_iofirmware) +#if !defined(IOMCU_FW) uint8_t chan = group.chan[j]; if (SRV_Channels::is_GPIO(chan+chan_offset)) { group.chan[j] = CHAN_DISABLED; @@ -153,6 +160,7 @@ void RCOutput::init() _initialised = true; } +#if HAL_SERIALLED_ENABLED // start the led thread bool RCOutput::start_led_thread(void) { @@ -198,10 +206,12 @@ void RCOutput::led_thread() led_timer_tick(LED_OUTPUT_PERIOD_US + AP_HAL::micros64()); } } +#endif // HAL_SERIAL_ENABLED /* - thread for handling RCOutput send + thread for handling RCOutput send on FMU */ +#if !defined(IOMCU_FW) void RCOutput::rcout_thread() { uint64_t last_thread_run_us = 0; // last time we did a 1kHz run of rcout @@ -240,7 +250,7 @@ void RCOutput::rcout_thread() // main thread requested a new dshot send or we timed out - if we are not running // as a multiple of loop rate then ignore EVT_PWM_SEND events to preserve periodicity - if (!serial_group && have_pwm_event) { + if (!in_soft_serial() && have_pwm_event) { dshot_send_groups(time_out_us); // now unlock everything @@ -257,14 +267,15 @@ void RCOutput::rcout_thread() static bool output_masks = true; if (AP_HAL::millis() > 5000 && output_masks) { output_masks = false; - hal.console->printf("bdmask 0x%x, en_mask 0x%lx, 3dmask 0x%x:\n", _bdshot.mask, en_mask, _reversible_mask); + hal.console->printf("bdmask 0x%lx, en_mask 0x%lx, 3dmask 0x%lx:\n", _bdshot.mask, en_mask, _reversible_mask); for (auto &group : pwm_group_list) { - hal.console->printf(" timer %u: ch_mask 0x%x, en_mask 0x%x\n", group.timer_id, group.ch_mask, group.en_mask); + hal.console->printf(" timer %u: ch_mask 0x%lx, en_mask 0x%lx\n", group.timer_id, group.ch_mask, group.en_mask); } } #endif } } +#endif __RAMFUNC__ void RCOutput::dshot_update_tick(virtual_timer_t* vt, void* p) { @@ -496,6 +507,12 @@ void RCOutput::set_default_rate(uint16_t freq_hz) */ void RCOutput::set_dshot_rate(uint8_t dshot_rate, uint16_t loop_rate_hz) { +#if HAL_WITH_IO_MCU + if (AP_BoardConfig::io_dshot()) { + iomcu.set_dshot_period(1000UL, 0); + } +#endif + // for low loop rates simply output at 1Khz on a timer if (loop_rate_hz <= 100 || dshot_rate == 0) { _dshot_period_us = 1000UL; @@ -528,9 +545,14 @@ void RCOutput::set_dshot_rate(uint8_t dshot_rate, uint16_t loop_rate_hz) drate = _dshot_rate * loop_rate_hz; } _dshot_period_us = 1000000UL / drate; +#if HAL_WITH_IO_MCU + if (AP_BoardConfig::io_dshot()) { + iomcu.set_dshot_period(_dshot_period_us, _dshot_rate); + } +#endif } -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED /* Set/get the dshot esc_type */ @@ -551,7 +573,7 @@ void RCOutput::set_dshot_esc_type(DshotEscType dshot_esc_type) break; } } -#endif +#endif // #if HAL_DSHOT_ENABLED /* find pwm_group and index in group given a channel number @@ -622,6 +644,12 @@ uint16_t RCOutput::get_freq(uint8_t chan) void RCOutput::enable_ch(uint8_t chan) { +#if HAL_WITH_IO_MCU + if (chan < chan_offset && AP_BoardConfig::io_enabled()) { + iomcu.enable_ch(chan); + return; + } +#endif uint8_t i; pwm_group *grp = find_chan(chan, i); if (grp) { @@ -632,6 +660,12 @@ void RCOutput::enable_ch(uint8_t chan) void RCOutput::disable_ch(uint8_t chan) { +#if HAL_WITH_IO_MCU + if (chan < chan_offset && AP_BoardConfig::io_enabled()) { + iomcu.disable_ch(chan); + return; + } +#endif uint8_t i; pwm_group *grp = find_chan(chan, i); if (grp) { @@ -659,13 +693,7 @@ void RCOutput::write(uint8_t chan, uint16_t period_us) #if HAL_WITH_IO_MCU // handle IO MCU channels if (AP_BoardConfig::io_enabled()) { - uint16_t io_period_us = period_us; - if ((iomcu_mode == MODE_PWM_ONESHOT125) && ((1U<safety_switch_state() == AP_HAL::Util::SAFETY_DISARMED; for (auto &group : pwm_group_list) { - if (serial_group) { + if (in_soft_serial()) { continue; } if (!group.pwm_started) { @@ -745,12 +773,12 @@ void RCOutput::push_local(void) uint32_t width = (group.pwm_cfg.frequency/1000000U) * period_us; pwmEnableChannel(group.pwm_drv, j, width); } -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED else if (is_dshot_protocol(group.current_mode) || is_led_protocol(group.current_mode)) { // set period_us to time for pulse output, to enable very fast rates period_us = group.dshot_pulse_time_us; } -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED if (group.current_mode == MODE_PWM_ONESHOT || group.current_mode == MODE_PWM_ONESHOT125 || group.current_mode == MODE_NEOPIXEL || @@ -786,12 +814,7 @@ uint16_t RCOutput::read(uint8_t chan) } #if HAL_WITH_IO_MCU if (chan < chan_offset) { - uint16_t period_us = iomcu.read_channel(chan); - if ((iomcu_mode == MODE_PWM_ONESHOT125) && ((1U<lock(); +#endif if (!group.dma_buffer || buffer_length != group.dma_buffer_len) { if (group.dma_buffer) { hal.util->free_type(group.dma_buffer, group.dma_buffer_len, AP_HAL::Util::MEM_DMA_SAFE); group.dma_buffer_len = 0; } - group.dma_buffer = (uint32_t *)hal.util->malloc_type(buffer_length, AP_HAL::Util::MEM_DMA_SAFE); + group.dma_buffer = (dmar_uint_t *)hal.util->malloc_type(buffer_length, AP_HAL::Util::MEM_DMA_SAFE); if (!group.dma_buffer) { +#if AP_HAL_SHARED_DMA_ENABLED group.dma_handle->unlock(); +#endif print_group_setup_error(group, "failed to allocate DMA buffer"); return false; } @@ -927,25 +963,30 @@ bool RCOutput::setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_ pwmStop(group.pwm_drv); group.pwm_started = false; } - const uint32_t target_frequency = bitrate * bit_width; const uint32_t prescaler = calculate_bitrate_prescaler(group.pwm_drv->clock, target_frequency, is_dshot); - - if (prescaler > 0x8000) { + if (prescaler == 0 || prescaler > 0x8000) { +#if AP_HAL_SHARED_DMA_ENABLED group.dma_handle->unlock(); +#endif print_group_setup_error(group, "failed to match clock speed"); return false; } - const uint32_t freq = group.pwm_drv->clock / prescaler; + const uint32_t freq = group.pwm_drv->clock / (prescaler + 1); + // PSC is calculated by ChibiOS as (pwm_drv.clock / pwm_cfg.frequency) - 1; group.pwm_cfg.frequency = freq; - group.pwm_cfg.period = bit_width; group.pwm_cfg.dier = TIM_DIER_UDE; group.pwm_cfg.cr2 = 0; group.bit_width_mul = (freq + (target_frequency/2)) / target_frequency; + // ARR is calculated by ChibiOS as pwm_cfg.period -1 + group.pwm_cfg.period = bit_width * group.bit_width_mul; //hal.console->printf("CLOCK=%u BW=%u FREQ=%u BR=%u MUL=%u PRE=%u\n", unsigned(group.pwm_drv->clock), unsigned(bit_width), unsigned(group.pwm_cfg.frequency), // unsigned(bitrate), unsigned(group.bit_width_mul), unsigned(prescaler)); + //static char clock_setup[64]; + //hal.util->snprintf(clock_setup, 64, "CLOCK=%u BW=%u FREQ=%u BR=%u MUL=%u PRE=%u\n", unsigned(group.pwm_drv->clock), unsigned(bit_width), unsigned(group.pwm_cfg.frequency), + // unsigned(bitrate), unsigned(group.bit_width_mul), unsigned(prescaler)); for (uint8_t j=0; j<4; j++) { pwmmode_t mode = group.pwm_cfg.channels[j].mode; @@ -967,11 +1008,13 @@ bool RCOutput::setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_ } } +#if AP_HAL_SHARED_DMA_ENABLED group.dma_handle->unlock(); +#endif return true; #else return false; -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED } /* @@ -984,9 +1027,9 @@ void RCOutput::set_group_mode(pwm_group &group) pwmStop(group.pwm_drv); group.pwm_started = false; } - +#ifdef HAL_WITH_BIDIR_DSHOT memset(group.bdshot.erpm, 0, 4*sizeof(uint16_t)); - +#endif switch (group.current_mode) { case MODE_PWM_BRUSHED: // force zero output initially @@ -1001,6 +1044,7 @@ void RCOutput::set_group_mode(pwm_group &group) case MODE_NEOPIXEL: case MODE_PROFILED: +#if HAL_SERIALLED_ENABLED { uint8_t bits_per_pixel = 24; bool active_high = true; @@ -1032,6 +1076,7 @@ void RCOutput::set_group_mode(pwm_group &group) } break; } +#endif case MODE_PWM_DSHOT150 ... MODE_PWM_DSHOT1200: { const uint32_t rate = protocol_bitrate(group.current_mode); @@ -1110,26 +1155,33 @@ void RCOutput::set_output_mode(uint32_t mask, const enum output_mode mode) } #if HAL_WITH_IO_MCU if ((mode == MODE_PWM_ONESHOT || - mode == MODE_PWM_ONESHOT125) && + mode == MODE_PWM_ONESHOT125 || + mode == MODE_PWM_BRUSHED || + (mode >= MODE_PWM_DSHOT150 && mode <= MODE_PWM_DSHOT600)) && (mask & ((1U<> chan_offset); +} + /* * get output mode banner to inform user of how outputs are configured */ @@ -1252,7 +1304,7 @@ void RCOutput::trigger_groups(void) osalSysLock(); for (auto &group : pwm_group_list) { - if (irq.waiter) { + if (soft_serial_waiting()) { // doing serial output, don't send pulses continue; } @@ -1266,9 +1318,9 @@ void RCOutput::trigger_groups(void) } } osalSysUnlock(); -#ifndef HAL_NO_RCOUT_THREAD +#if !defined(HAL_NO_RCOUT_THREAD) || HAL_DSHOT_ENABLED // trigger a PWM send - if (!serial_group && hal.scheduler->in_main_thread()) { + if (!in_soft_serial() && hal.scheduler->in_main_thread() && rcout_thread_ctx) { chEvtSignal(rcout_thread_ctx, EVT_PWM_SEND); } #endif @@ -1287,7 +1339,7 @@ void RCOutput::trigger_groups(void) */ void RCOutput::timer_tick(uint64_t time_out_us) { - if (serial_group) { + if (in_soft_serial()) { return; } @@ -1309,7 +1361,7 @@ void RCOutput::timer_tick(uint64_t time_out_us) */ void RCOutput::led_timer_tick(uint64_t time_out_us) { - if (serial_group) { + if (in_soft_serial()) { return; } @@ -1325,11 +1377,73 @@ void RCOutput::led_timer_tick(uint64_t time_out_us) } } +#if defined(IOMCU_FW) && HAL_DSHOT_ENABLED +THD_WORKING_AREA(dshot_thread_wa, 64); +void RCOutput::timer_tick() +{ + if (dshot_timer_setup) { + return; + } + + bool dshot_enabled = false; + for (uint8_t i = 0; i < NUM_GROUPS; i++ ) { + pwm_group &group = pwm_group_list[i]; + if (is_dshot_protocol(group.current_mode)) { + dshot_enabled = true; + break; + } + } + if (!dshot_timer_setup && dshot_enabled) { + chThdCreateStatic(dshot_thread_wa, sizeof(dshot_thread_wa), + APM_RCOUT_PRIORITY, &RCOutput::dshot_send_trampoline, this); + dshot_timer_setup = true; + } +} + +void RCOutput::dshot_send_trampoline(void *p) +{ + RCOutput *rcout = (RCOutput *)p; + rcout->rcout_thread(); +} + +/* + thread for handling RCOutput send on IOMCU + */ +void RCOutput::rcout_thread() { + // don't start outputting until fully configured + while (!hal.scheduler->is_system_initialized()) { + hal.scheduler->delay_microseconds(1000); + } + + rcout_thread_ctx = chThdGetSelfX(); + + while (true) { + chEvtWaitOne(EVT_PWM_SEND | EVT_PWM_SYNTHETIC_SEND); + + // this is when the cycle is supposed to start + if (_dshot_cycle == 0) { + // register a timer for the next tick if push() will not be providing it + if (_dshot_rate != 1) { + chVTSet(&_dshot_rate_timer, chTimeUS2I(_dshot_period_us), dshot_update_tick, this); + } + } + + // main thread requested a new dshot send or we timed out - if we are not running + // as a multiple of loop rate then ignore EVT_PWM_SEND events to preserve periodicity + dshot_send_groups(0); + + if (_dshot_rate > 0) { + _dshot_cycle = (_dshot_cycle + 1) % _dshot_rate; + } + } +} +#endif // IOMCU_FW && DISABLE_DSHOT + // send dshot for all groups that support it void RCOutput::dshot_send_groups(uint64_t time_out_us) { -#ifndef DISABLE_DSHOT - if (serial_group) { +#if HAL_DSHOT_ENABLED + if (in_soft_serial()) { return; } @@ -1354,7 +1468,7 @@ void RCOutput::dshot_send_groups(uint64_t time_out_us) if (command_sent) { _dshot_current_command.cycle--; } -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED } __RAMFUNC__ void RCOutput::dshot_send_next_group(void* p) @@ -1369,6 +1483,7 @@ __RAMFUNC__ void RCOutput::dshot_send_next_group(void* p) /* allocate DMA channel */ +#if AP_HAL_SHARED_DMA_ENABLED void RCOutput::dma_allocate(Shared_DMA *ctx) { for (auto &group : pwm_group_list) { @@ -1399,6 +1514,7 @@ void RCOutput::dma_deallocate(Shared_DMA *ctx) } } } +#endif // AP_HAL_SHARED_DMA_ENABLED /* create a DSHOT 16 bit packet. Based on prepareDshotPacket from betaflight @@ -1432,11 +1548,15 @@ uint16_t RCOutput::create_dshot_packet(const uint16_t value, bool telem_request, /* fill in a DMA buffer for dshot + the buffer format is (stride is always 4 for 4 channels): + [ch0b0][ch1b0][ch2b0][ch3b0][ch0b1][ch1b1][ch2b1][ch3b1]...[ch0bN][ch1bN][ch2bN][ch3bN] + where N = dshot_bit_length - 1 + each value is a number of beats for the DMA engine to send in burst via DMAR to the 4 CCR registers */ -void RCOutput::fill_DMA_buffer_dshot(uint32_t *buffer, uint8_t stride, uint16_t packet, uint16_t clockmul) +void RCOutput::fill_DMA_buffer_dshot(dmar_uint_t *buffer, uint8_t stride, uint16_t packet, uint16_t clockmul) { - const uint32_t DSHOT_MOTOR_BIT_0 = DSHOT_BIT_0_TICKS * clockmul; - const uint32_t DSHOT_MOTOR_BIT_1 = DSHOT_BIT_1_TICKS * clockmul; + const dmar_uint_t DSHOT_MOTOR_BIT_0 = DSHOT_BIT_0_TICKS * clockmul; + const dmar_uint_t DSHOT_MOTOR_BIT_1 = DSHOT_BIT_1_TICKS * clockmul; uint16_t i = 0; for (; i < dshot_pre; i++) { buffer[i * stride] = 0; @@ -1457,23 +1577,25 @@ void RCOutput::fill_DMA_buffer_dshot(uint32_t *buffer, uint8_t stride, uint16_t */ void RCOutput::dshot_send(pwm_group &group, uint64_t time_out_us) { -#ifndef DISABLE_DSHOT - if (irq.waiter || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { +#if HAL_DSHOT_ENABLED + if (soft_serial_waiting() || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { // doing serial output or DMAR input, don't send DShot pulses return; } +#if AP_HAL_SHARED_DMA_ENABLED // first make sure we have the DMA channel before anything else osalDbgAssert(!group.dma_handle->is_locked(), "DMA handle is already locked"); group.dma_handle->lock(); - +#endif // if we are sharing UP channels then it might have taken a long time to get here, // if there's not enough time to actually send a pulse then cancel - +#if AP_HAL_SHARED_DMA_ENABLED if (AP_HAL::micros64() + group.dshot_pulse_time_us > time_out_us) { group.dma_handle->unlock(); return; } +#endif // only the timer thread releases the locks group.dshot_waiter = rcout_thread_ctx; @@ -1524,8 +1646,9 @@ void RCOutput::dshot_send(pwm_group &group, uint64_t time_out_us) } #endif bool safety_on = hal.util->safety_switch_state() == AP_HAL::Util::SAFETY_DISARMED; +#if !defined(IOMCU_FW) bool armed = hal.util->get_soft_armed(); - +#endif memset((uint8_t *)group.dma_buffer, 0, DSHOT_BUFFER_LENGTH); for (uint8_t i=0; i<4; i++) { @@ -1569,15 +1692,21 @@ void RCOutput::dshot_send(pwm_group &group, uint64_t time_out_us) if (value != 0) { value += DSHOT_ZERO_THROTTLE; } - +#if !defined(IOMCU_FW) if (!armed) { // when disarmed we always send a zero value value = 0; } - +#endif // according to sskaug requesting telemetry while trying to arm may interfere with the good frame calc bool request_telemetry = telem_request_mask & chan_mask; - uint16_t packet = create_dshot_packet(value, request_telemetry, group.bdshot.enabled); + uint16_t packet = create_dshot_packet(value, request_telemetry, +#ifdef HAL_WITH_BIDIR_DSHOT + group.bdshot.enabled +#else + false +#endif + ); if (request_telemetry) { telem_request_mask &= ~chan_mask; } @@ -1588,7 +1717,7 @@ void RCOutput::dshot_send(pwm_group &group, uint64_t time_out_us) chEvtGetAndClearEvents(group.dshot_event_mask); // start sending the pulses out send_pulses_DMAR(group, DSHOT_BUFFER_LENGTH); -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED } /* @@ -1596,14 +1725,15 @@ void RCOutput::dshot_send(pwm_group &group, uint64_t time_out_us) return true if send was successful called from led thread */ +#if HAL_SERIALLED_ENABLED bool RCOutput::serial_led_send(pwm_group &group) { if (!group.serial_led_pending || !is_led_protocol(group.current_mode)) { return true; } -#ifndef DISABLE_DSHOT - if (irq.waiter || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { +#if HAL_DSHOT_ENABLED + if (soft_serial_waiting() || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { // doing serial output or DMAR input, don't send DShot pulses return false; } @@ -1627,10 +1757,10 @@ bool RCOutput::serial_led_send(pwm_group &group) // start sending the pulses out send_pulses_DMAR(group, group.dma_buffer_len); -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED return true; } - +#endif // HAL_SERIALLED_ENABLED /* send a series of pulses for a group using DMAR. Pulses must have @@ -1639,7 +1769,7 @@ bool RCOutput::serial_led_send(pwm_group &group) */ void RCOutput::send_pulses_DMAR(pwm_group &group, uint32_t buffer_length) { -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED osalDbgAssert(group.dma && group.dma_buffer, "DMA structures are corrupt"); /* The DMA approach we are using is based on the DMAR method from @@ -1660,18 +1790,24 @@ void RCOutput::send_pulses_DMAR(pwm_group &group, uint32_t buffer_length) dmaStreamSetPeripheral(group.dma, &(group.pwm_drv->tim->DMAR)); stm32_cacheBufferFlush(group.dma_buffer, buffer_length); dmaStreamSetMemory0(group.dma, group.dma_buffer); - dmaStreamSetTransactionSize(group.dma, buffer_length/sizeof(uint32_t)); + dmaStreamSetTransactionSize(group.dma, buffer_length / sizeof(dmar_uint_t)); #if STM32_DMA_ADVANCED dmaStreamSetFIFO(group.dma, STM32_DMA_FCR_DMDIS | STM32_DMA_FCR_FTH_FULL); #endif dmaStreamSetMode(group.dma, STM32_DMA_CR_CHSEL(group.dma_up_channel) | - STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD | + STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_PSIZE_WORD | +#if defined(IOMCU_FW) + STM32_DMA_CR_MSIZE_BYTE | +#else + STM32_DMA_CR_MSIZE_WORD | +#endif STM32_DMA_CR_MINC | STM32_DMA_CR_PL(3) | STM32_DMA_CR_TEIE | STM32_DMA_CR_TCIE); // setup for burst strided transfers into the timers 4 CCR registers const uint8_t ccr_ofs = offsetof(stm32_tim_t, CCR)/4; + // burst address (BA) of the CCR register, burst length (BL) of 4 (0b11) group.pwm_drv->tim->DCR = STM32_TIM_DCR_DBA(ccr_ofs) | STM32_TIM_DCR_DBL(3); group.dshot_state = DshotState::SEND_START; @@ -1680,7 +1816,7 @@ void RCOutput::send_pulses_DMAR(pwm_group &group, uint32_t buffer_length) dmaStreamEnable(group.dma); // record when the transaction was started group.last_dmar_send_us = AP_HAL::micros64(); -#endif //#ifndef DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED } /* @@ -1709,10 +1845,13 @@ __RAMFUNC__ void RCOutput::dma_up_irq_callback(void *p, uint32_t flags) pwm_group *group = (pwm_group *)p; chSysLockFromISR(); dmaStreamDisable(group->dma); - if (group->in_serial_dma && irq.waiter) { +#if HAL_SERIAL_ESC_COMM_ENABLED + if (group->in_serial_dma && soft_serial_waiting()) { // tell the waiting process we've done the DMA chEvtSignalI(irq.waiter, serial_event_mask); - } else { + } else +#endif + { // this prevents us ever having two dshot pulses too close together // dshot mandates a minimum pulse separation of 40us, WS2812 mandates 50us so we // pick the higher value @@ -1763,6 +1902,7 @@ void RCOutput::dma_cancel(pwm_group& group) While serial output is active normal output to the channel group is suspended. */ +#if HAL_SERIAL_ESC_COMM_ENABLED bool RCOutput::serial_setup_output(uint8_t chan, uint32_t baudrate, uint32_t chanmask) { // account for IOMCU channels @@ -1788,7 +1928,7 @@ bool RCOutput::serial_setup_output(uint8_t chan, uint32_t baudrate, uint32_t cha } if (!new_serial_group) { - if (serial_group) { + if (in_soft_serial()) { // shutdown old group serial_end(); } @@ -1831,10 +1971,10 @@ bool RCOutput::serial_setup_output(uint8_t chan, uint32_t baudrate, uint32_t cha /* fill in a DMA buffer for a serial byte, assuming 1 start bit and 1 stop bit */ -void RCOutput::fill_DMA_buffer_byte(uint32_t *buffer, uint8_t stride, uint8_t b, uint32_t bitval) +void RCOutput::fill_DMA_buffer_byte(dmar_uint_t *buffer, uint8_t stride, uint8_t b, uint32_t bitval) { - const uint32_t BIT_0 = bitval; - const uint32_t BIT_1 = 0; + const dmar_uint_t BIT_0 = bitval; + const dmar_uint_t BIT_1 = 0; // start bit buffer[0] = BIT_0; @@ -1877,8 +2017,8 @@ bool RCOutput::serial_write_byte(uint8_t b) */ bool RCOutput::serial_write_bytes(const uint8_t *bytes, uint16_t len) { -#ifndef DISABLE_DSHOT - if (!serial_group) { +#if HAL_DSHOT_ENABLED + if (!in_soft_serial()) { return false; } serial_group->dma_handle->lock(); @@ -2001,8 +2141,7 @@ bool RCOutput::serial_read_byte(uint8_t &b) */ uint16_t RCOutput::serial_read_bytes(uint8_t *buf, uint16_t len) { -#ifndef DISABLE_SERIAL_ESC_COMM - if (serial_group == nullptr) { + if (!in_soft_serial()) { return 0; } pwm_group &group = *serial_group; @@ -2062,10 +2201,6 @@ uint16_t RCOutput::serial_read_bytes(uint8_t *buf, uint16_t len) palWriteLine(HAL_GPIO_LINE_GPIO54, 0); #endif return i; -#else - return false; -#endif //#ifndef DISABLE_SERIAL_ESC_COMM - } /* @@ -2073,8 +2208,7 @@ uint16_t RCOutput::serial_read_bytes(uint8_t *buf, uint16_t len) */ void RCOutput::serial_end(void) { -#ifndef DISABLE_SERIAL_ESC_COMM - if (serial_group) { + if (in_soft_serial()) { if (serial_thread == chThdGetSelfX()) { chThdSetPriority(serial_priority); serial_thread = nullptr; @@ -2087,8 +2221,8 @@ void RCOutput::serial_end(void) } } serial_group = nullptr; -#endif //#ifndef DISABLE_SERIAL_ESC_COMM } +#endif // HAL_SERIAL_ESC_COMM_ENABLED /* get safety switch state for Util.cpp @@ -2228,6 +2362,7 @@ uint32_t RCOutput::protocol_bitrate(const enum output_mode mode) setup serial led output for a given channel number, with the given max number of LEDs in the chain. */ +#if HAL_SERIALLED_ENABLED bool RCOutput::set_serial_led_num_LEDs(const uint16_t chan, uint8_t num_leds, output_mode mode, uint32_t clock_mask) { if (!_initialised || num_leds == 0) { @@ -2280,8 +2415,6 @@ bool RCOutput::set_serial_led_num_LEDs(const uint16_t chan, uint8_t num_leds, ou } - - #pragma GCC push_options #pragma GCC optimize("O2") // Fill the group DMA buffer with data to be output @@ -2332,7 +2465,7 @@ void RCOutput::_set_neopixel_rgb_data(pwm_group *grp, uint8_t idx, uint8_t led, const uint8_t pad_start_bits = 1; const uint8_t neopixel_bit_length = 24; const uint8_t stride = 4; - uint32_t *buf = grp->dma_buffer + (led * neopixel_bit_length + pad_start_bits) * stride + idx; + dmar_uint_t *buf = grp->dma_buffer + (led * neopixel_bit_length + pad_start_bits) * stride + idx; uint32_t bits = (green<<16) | (red<<8) | blue; const uint32_t BIT_0 = NEOP_BIT_0_TICKS * grp->bit_width_mul; const uint32_t BIT_1 = NEOP_BIT_1_TICKS * grp->bit_width_mul; @@ -2351,7 +2484,7 @@ void RCOutput::_set_profiled_rgb_data(pwm_group *grp, uint8_t idx, uint8_t led, const uint8_t pad_start_bits = 1; const uint8_t bit_length = 25; const uint8_t stride = 4; - uint32_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; + dmar_uint_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; uint32_t bits = 0x1000000 | (blue<<16) | (red<<8) | green; const uint32_t BIT_1 = PROFI_BIT_1_TICKS * grp->bit_width_mul; for (uint16_t b=0; b < bit_length; b++) { @@ -2369,7 +2502,7 @@ void RCOutput::_set_profiled_blank_frame(pwm_group *grp, uint8_t idx, uint8_t le const uint8_t pad_start_bits = 1; const uint8_t bit_length = 25; const uint8_t stride = 4; - uint32_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; + dmar_uint_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; const uint32_t BIT_1 = PROFI_BIT_1_TICKS * grp->bit_width_mul; for (uint16_t b=0; b < bit_length; b++) { buf[b * stride] = BIT_1; @@ -2384,7 +2517,7 @@ void RCOutput::_set_profiled_clock(pwm_group *grp, uint8_t idx, uint8_t led) const uint8_t pad_start_bits = 1; const uint8_t bit_length = 25; const uint8_t stride = 4; - uint32_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; + dmar_uint_t *buf = grp->dma_buffer + (led * bit_length + pad_start_bits) * stride + idx; const uint32_t BIT_1 = PROFI_BIT_0_TICKS * grp->bit_width_mul; for (uint16_t b=0; b < bit_length; b++) { buf[b * stride] = BIT_1; @@ -2520,6 +2653,7 @@ void RCOutput::serial_led_send(const uint16_t chan) serial_led_pending = true; } } +#endif // HAL_SERIALLED_ENABLED void RCOutput::timer_info(ExpandingString &str) { @@ -2528,9 +2662,12 @@ void RCOutput::timer_info(ExpandingString &str) for (auto &group : pwm_group_list) { uint32_t target_freq; +#if HAL_SERIAL_ESC_COMM_ENABLED if (&group == serial_group) { target_freq = 19200 * 10; - } else if (is_dshot_protocol(group.current_mode)) { + } else +#endif // HAL_SERIAL_ESC_COMM_ENABLED + if (is_dshot_protocol(group.current_mode)) { target_freq = protocol_bitrate(group.current_mode) * DSHOT_BIT_WIDTH_TICKS; } else { target_freq = protocol_bitrate(group.current_mode) * NEOP_BIT_WIDTH_TICKS; diff --git a/libraries/AP_HAL_ChibiOS/RCOutput.h b/libraries/AP_HAL_ChibiOS/RCOutput.h index c8a97bbf80..75cfbcf4a4 100644 --- a/libraries/AP_HAL_ChibiOS/RCOutput.h +++ b/libraries/AP_HAL_ChibiOS/RCOutput.h @@ -16,18 +16,19 @@ */ #pragma once +#include #include "AP_HAL_ChibiOS.h" #include #include #include "shared_dma.h" -#include "ch.h" -#include "hal.h" #if HAL_USE_PWM == TRUE -#if !STM32_DMA_ADVANCED && !defined(STM32G4) && !defined(STM32L4) -#define DISABLE_DSHOT +#if defined(IOMCU_FW) +typedef uint8_t dmar_uint_t; // save memory to allow dshot on IOMCU +#else +typedef uint32_t dmar_uint_t; #endif #define RCOU_DSHOT_TIMING_DEBUG 0 @@ -109,12 +110,17 @@ public: */ void led_timer_tick(uint64_t last_run_us); +#if defined(IOMCU_FW) && HAL_DSHOT_ENABLED + void timer_tick() override; + static void dshot_send_trampoline(void *p); +#endif /* setup for serial output to a set of ESCs, using the given baudrate. Assumes 1 start bit, 1 stop bit, LSB first and 8 databits. This is used for ESC configuration and firmware flashing */ +#if HAL_SERIAL_ESC_COMM_ENABLED bool setup_serial_output(uint32_t chan_mask, ByteBuffer *buffer, uint32_t baudrate); /* @@ -148,13 +154,14 @@ public: serial_setup_output() */ void serial_end(void) override; +#endif /* enable telemetry request for a mask of channels. This is used with Dshot to get telemetry feedback The mask uses servo channel numbering */ - void set_telem_request_mask(uint32_t mask) override { telem_request_mask = (mask >> chan_offset); } + void set_telem_request_mask(uint32_t mask) override; #ifdef HAL_WITH_BIDIR_DSHOT /* @@ -172,7 +179,18 @@ public: */ void set_dshot_rate(uint8_t dshot_rate, uint16_t loop_rate_hz) override; -#ifndef DISABLE_DSHOT +#if defined(IOMCU_FW) + /* + Get/Set the dshot period in us, only for use by the IOMCU + */ + void set_dshot_period(uint32_t period_us, uint8_t dshot_rate) override { + _dshot_period_us = period_us; + _dshot_rate = dshot_rate; + } + uint32_t get_dshot_period_us() const override { return _dshot_period_us; } +#endif + +#if HAL_DSHOT_ENABLED /* Set/get the dshot esc_type */ @@ -196,7 +214,7 @@ public: */ void set_safety_mask(uint32_t mask) { safety_mask = mask; } -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED /* * mark the channels in chanmask as reversible. This is needed for some ESC types (such as Dshot) * so that output scaling can be performed correctly. The chanmask passed is added (ORed) into any existing mask. @@ -240,6 +258,7 @@ public: setup serial LED output for a given channel number, with the given max number of LEDs in the chain. */ +#if HAL_SERIALLED_ENABLED bool set_serial_led_num_LEDs(const uint16_t chan, uint8_t num_leds, output_mode mode = MODE_PWM_NONE, uint32_t clock_mask = 0) override; /* @@ -252,7 +271,7 @@ public: trigger send of serial LED data */ void serial_led_send(const uint16_t chan) override; - +#endif /* rcout thread */ @@ -285,7 +304,7 @@ private: static const uint8_t dshot_pre = 1; static const uint8_t dshot_post = 2; static const uint16_t dshot_bit_length = 16 + dshot_pre + dshot_post; - static const uint16_t DSHOT_BUFFER_LENGTH = dshot_bit_length * 4 * sizeof(uint32_t); + static const uint16_t DSHOT_BUFFER_LENGTH = dshot_bit_length * 4 * sizeof(dmar_uint_t); static const uint16_t MIN_GCR_BIT_LEN = 7; static const uint16_t MAX_GCR_BIT_LEN = 22; static const uint16_t GCR_TELEMETRY_BIT_LEN = MAX_GCR_BIT_LEN; @@ -318,8 +337,10 @@ private: // mask of channels that are enabled and active uint32_t en_mask; const stm32_dma_stream_t *dma; +#if AP_HAL_SHARED_DMA_ENABLED Shared_DMA *dma_handle; - uint32_t *dma_buffer; +#endif + dmar_uint_t *dma_buffer; uint16_t dma_buffer_len; bool pwm_started; uint32_t bit_width_mul; @@ -329,7 +350,7 @@ private: uint64_t dshot_pulse_time_us; uint64_t dshot_pulse_send_time_us; virtual_timer_t dma_timeout; - +#if HAL_SERIALLED_ENABLED // serial LED support volatile uint8_t serial_nleds; uint8_t clock_mask; @@ -340,10 +361,11 @@ private: // structure to hold serial LED data until it can be transferred // to the DMA buffer SerialLed* serial_led_data[4]; +#endif eventmask_t dshot_event_mask; thread_t* dshot_waiter; - +#if HAL_SERIAL_ESC_COMM_ENABLED // serial output struct { // expected time per bit @@ -355,10 +377,11 @@ private: // thread waiting for byte to be written thread_t *waiter; } serial; +#endif // support for bi-directional dshot volatile DshotState dshot_state; - +#ifdef HAL_WITH_BIDIR_DSHOT struct { uint16_t erpm[4]; volatile bool enabled; @@ -378,7 +401,7 @@ private: #endif #endif } bdshot; - +#endif #ifdef HAL_WITH_BIDIR_DSHOT // do we have an input capture dma channel bool has_ic_dma() const { @@ -418,6 +441,7 @@ private: */ thread_t *rcout_thread_ctx; +#if HAL_SERIALLED_ENABLED /* timer thread for use by led events */ @@ -428,7 +452,9 @@ private: */ HAL_Semaphore led_thread_sem; bool led_thread_created; +#endif +#if HAL_SERIAL_ESC_COMM_ENABLED /* structure for IRQ handler for soft-serial input */ @@ -462,11 +488,27 @@ private: bool timed_out; } irq; - // the group being used for serial output struct pwm_group *serial_group; thread_t *serial_thread; tprio_t serial_priority; +#endif + + static bool soft_serial_waiting() { +#if HAL_SERIAL_ESC_COMM_ENABLED + return irq.waiter != nullptr; +#else + return false; +#endif + } + + bool in_soft_serial() const { +#if HAL_SERIAL_ESC_COMM_ENABLED + return serial_group != nullptr; +#else + return false; +#endif + } static pwm_group pwm_group_list[]; static const uint8_t NUM_GROUPS; @@ -516,7 +558,7 @@ private: // virtual timer for post-push() pulses virtual_timer_t _dshot_rate_timer; -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED // dshot commands // RingBuffer to store outgoing request. struct DshotCommandPacket { @@ -561,6 +603,8 @@ private: // widest pulse for oneshot triggering uint16_t trigger_widest_pulse; + bool dshot_timer_setup; + // iomcu output mode (pwm, oneshot or oneshot125) enum output_mode iomcu_mode = MODE_PWM_NORMAL; @@ -617,7 +661,7 @@ private: void dma_allocate(Shared_DMA *ctx); void dma_deallocate(Shared_DMA *ctx); uint16_t create_dshot_packet(const uint16_t value, bool telem_request, bool bidir_telem); - void fill_DMA_buffer_dshot(uint32_t *buffer, uint8_t stride, uint16_t packet, uint16_t clockmul); + void fill_DMA_buffer_dshot(dmar_uint_t *buffer, uint8_t stride, uint16_t packet, uint16_t clockmul); void dshot_send_groups(uint64_t time_out_us); void dshot_send(pwm_group &group, uint64_t time_out_us); @@ -665,14 +709,14 @@ private: void _set_profiled_rgb_data(pwm_group *grp, uint8_t idx, uint8_t led, uint8_t red, uint8_t green, uint8_t blue); void _set_profiled_clock(pwm_group *grp, uint8_t idx, uint8_t led); void _set_profiled_blank_frame(pwm_group *grp, uint8_t idx, uint8_t led); - +#if AP_HAL_SHARED_DMA_ENABLED // serial output support bool serial_write_byte(uint8_t b); bool serial_read_byte(uint8_t &b); - void fill_DMA_buffer_byte(uint32_t *buffer, uint8_t stride, uint8_t b , uint32_t bitval); + void fill_DMA_buffer_byte(dmar_uint_t *buffer, uint8_t stride, uint8_t b , uint32_t bitval); static void serial_bit_irq(void); static void serial_byte_timeout(virtual_timer_t* vt, void *ctx); - +#endif }; #if RCOU_DSHOT_TIMING_DEBUG diff --git a/libraries/AP_HAL_ChibiOS/RCOutput_serial.cpp b/libraries/AP_HAL_ChibiOS/RCOutput_serial.cpp index 733a7e44b5..4f6d50f131 100644 --- a/libraries/AP_HAL_ChibiOS/RCOutput_serial.cpp +++ b/libraries/AP_HAL_ChibiOS/RCOutput_serial.cpp @@ -16,12 +16,18 @@ #include #include "RCOutput.h" #include +#include #include "hwdef/common/stm32_util.h" #include #include #if HAL_USE_PWM == TRUE -#ifndef DISABLE_DSHOT +#if HAL_DSHOT_ENABLED + +#if HAL_WITH_IO_MCU +#include +extern AP_IOMCU iomcu; +#endif using namespace ChibiOS; @@ -33,7 +39,7 @@ bool RCOutput::dshot_send_command(pwm_group& group, uint8_t command, uint8_t cha return false; } - if (irq.waiter || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { + if (soft_serial_waiting() || (group.dshot_state != DshotState::IDLE && group.dshot_state != DshotState::RECV_COMPLETE)) { // doing serial output or DMAR input, don't send DShot pulses return false; } @@ -42,9 +48,10 @@ bool RCOutput::dshot_send_command(pwm_group& group, uint8_t command, uint8_t cha TOGGLE_PIN_DEBUG(81); #endif // first make sure we have the DMA channel before anything else - +#if AP_HAL_SHARED_DMA_ENABLED osalDbgAssert(!group.dma_handle->is_locked(), "DMA handle is already locked"); group.dma_handle->lock(); +#endif // only the timer thread releases the locks group.dshot_waiter = rcout_thread_ctx; @@ -102,6 +109,11 @@ void RCOutput::send_dshot_command(uint8_t command, uint8_t chan, uint32_t comman } // not an FMU channel if (chan < chan_offset) { +#if HAL_WITH_IO_MCU + if (AP_BoardConfig::io_dshot()) { + iomcu.send_dshot_command(command, chan, command_timeout_ms, repeat_count, priority); + } +#endif return; } @@ -167,5 +179,5 @@ void RCOutput::update_channel_masks() { #endif } -#endif // DISABLE_DSHOT +#endif // HAL_DSHOT_ENABLED #endif // HAL_USE_PWM diff --git a/libraries/AP_HAL_ChibiOS/Util.cpp b/libraries/AP_HAL_ChibiOS/Util.cpp index a27d4ad86a..7e9045cf61 100644 --- a/libraries/AP_HAL_ChibiOS/Util.cpp +++ b/libraries/AP_HAL_ChibiOS/Util.cpp @@ -137,7 +137,7 @@ void *Util::heap_realloc(void *heap, void *ptr, size_t old_size, size_t new_size void *new_mem = chHeapAlloc((memory_heap_t *)heap, new_size); if (new_mem != nullptr) { const size_t old_size2 = chHeapGetSize(ptr); -#ifdef HAL_DEBUG_BUILD +#if defined(HAL_DEBUG_BUILD) && !defined(IOMCU_FW) if (new_size != 0 && old_size2 != old_size) { INTERNAL_ERROR(AP_InternalError::error_t::invalid_arg_or_result); } diff --git a/libraries/AP_HAL_ChibiOS/hwdef/CubeOrange/hwdef.inc b/libraries/AP_HAL_ChibiOS/hwdef/CubeOrange/hwdef.inc index 7eb82cd3ec..07c108f434 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/CubeOrange/hwdef.inc +++ b/libraries/AP_HAL_ChibiOS/hwdef/CubeOrange/hwdef.inc @@ -322,6 +322,7 @@ define HAL_GPIO_PWM_VOLT_3v3 1 # is "ROMFS ROMFS-filename source-filename". Paths are relative to the # ardupilot root. ROMFS io_firmware.bin Tools/IO_Firmware/iofirmware_highpolh.bin +ROMFS io_firmware_dshot.bin Tools/IO_Firmware/iofirmware_dshot_highpolh.bin DMA_NOSHARE SPI1* SPI4* USART6* diff --git a/libraries/AP_HAL_ChibiOS/hwdef/iomcu-dshot/hwdef.dat b/libraries/AP_HAL_ChibiOS/hwdef/iomcu-dshot/hwdef.dat new file mode 100644 index 0000000000..965050ab92 --- /dev/null +++ b/libraries/AP_HAL_ChibiOS/hwdef/iomcu-dshot/hwdef.dat @@ -0,0 +1,43 @@ +# hw definition file for processing by chibios_pins.py + +include ../iomcu/hwdef.dat + +undef AP_FASTBOOT_ENABLED AP_BOOTLOADER_FLASHING_ENABLED +undef HAL_DSHOT_ENABLED + +# PPM uses a DMA channel that is required for TIM2, and no remapping of PA8 is possible +undef PA8 +undef STM32_ICU_USE_TIM1 RCIN_ICU_TIMER STM32_RCIN_DMA_STREAM HAL_USE_ICU +undef PORT_INT_REQUIRED_STACK MAIN_STACK +undef CH_CFG_ST_TIMEDELTA CH_CFG_ST_FREQUENCY + +define HAL_NO_LED_THREAD 1 + +# TIM2_UP required for PWM1/2 +define STM32_TIM_TIM2_UP_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +define STM32_TIM_TIM2_UP_DMA_CHAN 1 + +# TIM4_UP (PWM 3/4) cannot be used as channels used by high speed USART2 RX/TX +# It's possible that DMA sharing might make this workable +#define STM32_TIM_TIM4_UP_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_TIM_TIM4_UP_DMA_CHAN 1 + +# TIM3_UP required for PWM5-8 +define STM32_TIM_TIM3_UP_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +define STM32_TIM_TIM3_UP_DMA_CHAN 1 + +define NO_FASTBOOT +define HAL_WITH_DSP FALSE +define HAL_DSHOT_ENABLED TRUE +define HAL_SERIALLED_ENABLED FALSE + +# Tickless mode is required in order for the virtual timers used by dshot to work correctly +STM32_ST_USE_TIMER 15 +define CH_CFG_ST_RESOLUTION 16 +define CH_CFG_ST_TIMEDELTA 2 +define CH_CFG_ST_FREQUENCY 1000000 + +# ChibiOS already correctly sets stack sizes and considers 64 extra as conservative +define PORT_INT_REQUIRED_STACK 64 +# "main" stack is only used for exceptions and ISR, but they can be nested +MAIN_STACK 0x100 diff --git a/libraries/AP_HAL_ChibiOS/hwdef/iomcu/hwdef.dat b/libraries/AP_HAL_ChibiOS/hwdef/iomcu/hwdef.dat index 7d8f9daf93..abd46a4df8 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/iomcu/hwdef.dat +++ b/libraries/AP_HAL_ChibiOS/hwdef/iomcu/hwdef.dat @@ -134,7 +134,7 @@ define SOFTSIG_MAX_SIGNAL_TRANSITIONS 128 define IOMCU_FW TRUE define AP_FASTBOOT_ENABLED 0 IOMCU_FW 1 -MAIN_STACK 0x200 +MAIN_STACK 0x100 PROCESS_STACK 0x250 define HAL_DISABLE_LOOP_DELAY define AP_BOOTLOADER_FLASHING_ENABLED 0 @@ -150,3 +150,6 @@ define AP_RCPROTOCOL_ST24_ENABLED 1 define AP_RCPROTOCOL_FPORT_ENABLED 1 AUTOBUILD_TARGETS iofirmware +define HAL_WITH_DSP FALSE + +define HAL_DSHOT_ENABLED FALSE diff --git a/libraries/AP_HAL_ChibiOS/hwdef/iomcu_f103_8MHz/hwdef.dat b/libraries/AP_HAL_ChibiOS/hwdef/iomcu_f103_8MHz/hwdef.dat index 98b205087d..743beaa2ea 100644 --- a/libraries/AP_HAL_ChibiOS/hwdef/iomcu_f103_8MHz/hwdef.dat +++ b/libraries/AP_HAL_ChibiOS/hwdef/iomcu_f103_8MHz/hwdef.dat @@ -151,3 +151,5 @@ define AP_RCPROTOCOL_ST24_ENABLED 1 define AP_RCPROTOCOL_FPORT_ENABLED 1 AUTOBUILD_TARGETS iofirmware +define HAL_WITH_DSP FALSE +define HAL_DSHOT_ENABLED FALSE