AP_HAL_ChibiOS: add support for @SYS/timers.txt
move out prescaler calculation and use closest prescaler everywhere include timer id in PWM groups
This commit is contained in:
parent
ea1af70f2b
commit
83ac78e969
@ -24,6 +24,7 @@
|
||||
#include "hwdef/common/watchdog.h"
|
||||
#include <AP_InternalError/AP_InternalError.h>
|
||||
#include <AP_Vehicle/AP_Vehicle_Type.h>
|
||||
#include <AP_Common/ExpandingString.h>
|
||||
#ifndef HAL_NO_UARTDRIVER
|
||||
#include <GCS_MAVLink/GCS.h>
|
||||
#endif
|
||||
@ -719,7 +720,7 @@ void RCOutput::print_group_setup_error(pwm_group &group, const char* error_strin
|
||||
|
||||
This is used for both DShot and serial output
|
||||
*/
|
||||
bool RCOutput::setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_width, bool active_high, const uint16_t buffer_length, bool choose_high,
|
||||
bool RCOutput::setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_width, bool active_high, const uint16_t buffer_length,
|
||||
uint32_t pulse_time_us, bool is_dshot)
|
||||
{
|
||||
#ifndef DISABLE_DSHOT
|
||||
@ -768,32 +769,15 @@ bool RCOutput::setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_
|
||||
}
|
||||
|
||||
const uint32_t target_frequency = bitrate * bit_width;
|
||||
uint32_t prescaler;
|
||||
if (is_dshot) {
|
||||
// original prescaler calculation from betaflight. bi-dir dshot is incredibly sensitive to the bitrate
|
||||
prescaler = uint32_t(lrintf((float) group.pwm_drv->clock / (bitrate * bit_width) + 0.01f) - 1);
|
||||
} else {
|
||||
// adjust frequency to give an allowed value given the clock, erring on the high side
|
||||
const uint32_t clock_hz = group.pwm_drv->clock;
|
||||
prescaler = group.pwm_drv->clock / target_frequency;
|
||||
while ((clock_hz / prescaler) < target_frequency && prescaler > 1) {
|
||||
prescaler--;
|
||||
}
|
||||
}
|
||||
const uint32_t prescaler = calculate_bitrate_prescaler(group.pwm_drv->clock, target_frequency, is_dshot);
|
||||
|
||||
uint32_t freq = group.pwm_drv->clock / prescaler;
|
||||
if (freq > target_frequency && !choose_high) {
|
||||
prescaler++;
|
||||
} else if (freq < target_frequency && choose_high) {
|
||||
prescaler--;
|
||||
}
|
||||
if (prescaler > 0x8000) {
|
||||
group.dma_handle->unlock();
|
||||
print_group_setup_error(group, "failed to match clock speed");
|
||||
return false;
|
||||
}
|
||||
|
||||
freq = group.pwm_drv->clock / prescaler;
|
||||
const uint32_t freq = group.pwm_drv->clock / prescaler;
|
||||
group.pwm_cfg.frequency = freq;
|
||||
group.pwm_cfg.period = bit_width;
|
||||
group.pwm_cfg.dier = TIM_DIER_UDE;
|
||||
@ -878,7 +862,7 @@ void RCOutput::set_group_mode(pwm_group &group)
|
||||
// calculate min time between pulses taking into account the DMAR parallelism
|
||||
const uint32_t pulse_time_us = 1000000UL * bit_length / rate;
|
||||
|
||||
if (!setup_group_DMA(group, rate, bit_period, active_high, buffer_length, true, pulse_time_us, false)) {
|
||||
if (!setup_group_DMA(group, rate, bit_period, active_high, buffer_length, pulse_time_us, false)) {
|
||||
group.current_mode = MODE_PWM_NONE;
|
||||
break;
|
||||
}
|
||||
@ -894,8 +878,7 @@ void RCOutput::set_group_mode(pwm_group &group)
|
||||
|
||||
// configure timer driver for DMAR at requested rate
|
||||
if (!setup_group_DMA(group, rate, bit_period, active_high,
|
||||
// choosing the low frequency for DSHOT150 is based on experimentation with BLHeli32 and bi-directional dshot
|
||||
MAX(DSHOT_BUFFER_LENGTH, GCR_TELEMETRY_BUFFER_LEN), group.current_mode != MODE_PWM_DSHOT150, pulse_send_time_us, true)) {
|
||||
MAX(DSHOT_BUFFER_LENGTH, GCR_TELEMETRY_BUFFER_LEN), pulse_send_time_us, true)) {
|
||||
group.current_mode = MODE_PWM_NORMAL;
|
||||
break;
|
||||
}
|
||||
@ -1639,7 +1622,7 @@ bool RCOutput::serial_setup_output(uint8_t chan, uint32_t baudrate, uint16_t cha
|
||||
// channels in blheli pass-thru fast
|
||||
for (auto &group : pwm_group_list) {
|
||||
if (group.ch_mask & chanmask) {
|
||||
if (!setup_group_DMA(group, baudrate, 10, false, DSHOT_BUFFER_LENGTH, false, 10, false)) {
|
||||
if (!setup_group_DMA(group, baudrate, 10, false, DSHOT_BUFFER_LENGTH, 10, false)) {
|
||||
serial_end();
|
||||
return false;
|
||||
}
|
||||
@ -2350,4 +2333,18 @@ void RCOutput::serial_led_send(const uint16_t chan)
|
||||
}
|
||||
}
|
||||
|
||||
void RCOutput::timer_info(ExpandingString &str)
|
||||
{
|
||||
// a header to allow for machine parsers to determine format
|
||||
str.printf("TIMERV1\n");
|
||||
|
||||
for (auto &group : pwm_group_list) {
|
||||
const uint32_t target_freq = &group == serial_group ? 19200 * 10 : protocol_bitrate(group.current_mode) * 20;
|
||||
const uint32_t prescaler = calculate_bitrate_prescaler(group.pwm_drv->clock, target_freq, is_dshot_protocol(group.current_mode));
|
||||
str.printf("TIM%-2u CLK=%4uMhz MODE=%5s FREQ=%8u TGT=%8u\n", group.timer_id, unsigned(group.pwm_drv->clock / 1000000),
|
||||
get_output_mode_string(group.current_mode),
|
||||
unsigned(group.pwm_drv->clock / prescaler), unsigned(target_freq));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAL_USE_PWM
|
||||
|
@ -248,6 +248,11 @@ public:
|
||||
*/
|
||||
void rcout_thread();
|
||||
|
||||
/*
|
||||
timer information
|
||||
*/
|
||||
void timer_info(ExpandingString &str) override;
|
||||
|
||||
private:
|
||||
enum class DshotState {
|
||||
IDLE = 0,
|
||||
@ -282,6 +287,7 @@ private:
|
||||
uint8_t chan[4]; // chan number, zero based, 255 for disabled
|
||||
PWMConfig pwm_cfg;
|
||||
PWMDriver* pwm_drv;
|
||||
uint8_t timer_id;
|
||||
bool have_up_dma; // can we do DMAR outputs for DShot?
|
||||
uint8_t dma_up_stream_id;
|
||||
uint8_t dma_up_channel;
|
||||
@ -294,7 +300,6 @@ private:
|
||||
#endif
|
||||
uint8_t alt_functions[4];
|
||||
ioline_t pal_lines[4];
|
||||
|
||||
// below this line is not initialised by hwdef.h
|
||||
enum output_mode current_mode;
|
||||
uint16_t frequency_hz;
|
||||
@ -597,7 +602,7 @@ private:
|
||||
void dma_cancel(pwm_group& group);
|
||||
bool mode_requires_dma(enum output_mode mode) const;
|
||||
bool setup_group_DMA(pwm_group &group, uint32_t bitrate, uint32_t bit_width, bool active_high,
|
||||
const uint16_t buffer_length, bool choose_high, uint32_t pulse_time_us,
|
||||
const uint16_t buffer_length, uint32_t pulse_time_us,
|
||||
bool is_dshot);
|
||||
void send_pulses_DMAR(pwm_group &group, uint32_t buffer_length);
|
||||
void set_group_mode(pwm_group &group);
|
||||
|
@ -606,6 +606,14 @@ void Util::uart_info(ExpandingString &str)
|
||||
}
|
||||
#endif
|
||||
|
||||
// request information on uart I/O
|
||||
#if HAL_USE_PWM == TRUE
|
||||
void Util::timer_info(ExpandingString &str)
|
||||
{
|
||||
hal.rcout->timer_info(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This method will generate random values with set size. It will fall back to AP_Math's get_random16()
|
||||
* if True RNG fails or enough entropy is not present.
|
||||
|
@ -91,7 +91,9 @@ public:
|
||||
// request information on uart I/O
|
||||
virtual void uart_info(ExpandingString &str) override;
|
||||
#endif
|
||||
|
||||
#if HAL_USE_PWM == TRUE
|
||||
void timer_info(ExpandingString &str) override;
|
||||
#endif
|
||||
// returns random values
|
||||
bool get_random_vals(uint8_t* data, size_t size) override;
|
||||
|
||||
|
@ -1986,7 +1986,7 @@ def write_PWM_config(f, ordered_timers):
|
||||
{%s, NULL}, \\
|
||||
{%s, NULL}, \\
|
||||
{%s, NULL} \\
|
||||
}, 0, 0}, &PWMD%u, \\
|
||||
}, 0, 0}, &PWMD%u, %u, \\
|
||||
HAL_PWM%u_DMA_CONFIG, \\%s
|
||||
{ %u, %u, %u, %u }, \\
|
||||
{ %s, %s, %s, %s }}\n''' %
|
||||
@ -1994,7 +1994,7 @@ def write_PWM_config(f, ordered_timers):
|
||||
chan_list[0], chan_list[1], chan_list[2], chan_list[3],
|
||||
pwm_clock, period,
|
||||
chan_mode[0], chan_mode[1], chan_mode[2], chan_mode[3],
|
||||
n, n, hal_icu_cfg,
|
||||
n, n, n, hal_icu_cfg,
|
||||
alt_functions[0], alt_functions[1], alt_functions[2], alt_functions[3],
|
||||
pal_lines[0], pal_lines[1], pal_lines[2], pal_lines[3]))
|
||||
f.write('#define HAL_PWM_GROUPS %s\n\n' % ','.join(groups))
|
||||
|
Loading…
Reference in New Issue
Block a user