dshot: support timer channels without DMA capture

Some timer channels such as timer 4 channel 4 don't support DMA, so we
can only use them to burst/update but not to capture.
This commit is contained in:
Julian Oes
2026-01-27 13:25:10 +13:00
committed by Jacob Dahl
parent d72542a48d
commit 0c51b25391
3 changed files with 69 additions and 6 deletions
@@ -141,6 +141,7 @@ static bool _bdshot_cycle_complete[MAX_IO_TIMERS] = { [0 ...(MAX_IO_TIMERS - 1)]
#define BDSHOT_OFFLINE_COUNT 200
static bool _bdshot_online[MAX_TIMER_IO_CHANNELS] = {};
static bool _bdshot_processed[MAX_TIMER_IO_CHANNELS] = {};
static bool _bdshot_capture_supported[MAX_TIMER_IO_CHANNELS] = {};
static int _consecutive_failures[MAX_TIMER_IO_CHANNELS] = {};
static int _consecutive_successes[MAX_TIMER_IO_CHANNELS] = {};
@@ -353,6 +354,28 @@ int up_dshot_init(uint32_t channel_mask, uint32_t bdshot_channel_mask, unsigned
}
}
// Mark BDShot channels without capture DMA as processed (so they don't block ready count)
// and track which channels support capture
for (uint8_t output_channel = 0; output_channel < MAX_TIMER_IO_CHANNELS; output_channel++) {
if (bdshot_channel_mask & (1 << output_channel)) {
uint8_t timer_index = timer_io_channels[output_channel].timer_index;
uint8_t timer_channel = timer_io_channels[output_channel].timer_channel;
if (timer_channel >= 1 && timer_channel <= 4) {
uint8_t timer_channel_index = timer_channel - 1;
if (io_timers[timer_index].dshot.dma_map_ch[timer_channel_index] != 0) {
_bdshot_capture_supported[output_channel] = true;
} else {
// No DMA for capture on this channel - mark as processed so it doesn't block
_bdshot_processed[output_channel] = true;
PX4_WARN("BDShot capture not supported on output %u (no DMA)", output_channel);
}
}
}
}
return channels_init_mask;
}
@@ -463,7 +486,8 @@ static void select_next_capture_channel(uint8_t timer_index)
if (timer_configs[timer_index].initialized_channels[next]) {
uint8_t output_channel = output_channel_from_timer_channel(timer_index, next);
if (_bdshot_channel_mask & (1 << output_channel)) {
// Only capture from channels that support BDShot (have DMA mapping)
if (_bdshot_capture_supported[output_channel]) {
timer_configs[timer_index].capture_channel = next;
return;
}
@@ -1016,12 +1040,43 @@ int up_bdshot_channel_online(uint8_t channel)
return _bdshot_online[channel];
}
int up_bdshot_channel_capture_supported(uint8_t channel)
{
if (channel >= MAX_TIMER_IO_CHANNELS) {
return 0;
}
return _bdshot_capture_supported[channel];
}
void up_bdshot_status(void)
{
PX4_INFO("dshot driver stats:");
if (_bdshot_channel_mask) {
PX4_INFO("BDShot channel mask: 0x%2x", (unsigned)_bdshot_channel_mask);
// Show timer configuration
for (int i = 0; i < MAX_IO_TIMERS; i++) {
if (timer_configs[i].enabled) {
PX4_INFO("Timer %d: enabled=%d init=%d bidir=%d cap_ch=%d",
i, timer_configs[i].enabled, timer_configs[i].initialized,
timer_configs[i].bidirectional, timer_configs[i].capture_channel);
}
}
// Always show read counters for BDShot
for (int i = 0; i < MAX_TIMER_IO_CHANNELS; i++) {
if (_bdshot_channel_mask & (1 << i)) {
if (_bdshot_capture_supported[i]) {
PX4_INFO("Output %u: read_ok %lu, fail_crc %lu",
i, read_ok[i], read_fail_crc[i]);
} else {
PX4_INFO("Output %u: no DMA for capture", i);
}
}
}
}
if (_edt_enabled) {
@@ -1037,10 +1092,6 @@ void up_bdshot_status(void)
(double)_edt_curr[i].rate_hz);
}
}
for (int i = 0; i < MAX_TIMER_IO_CHANNELS; i++) {
PX4_INFO("Output %u: read %lu, failed CRC %lu", i, read_ok[i], read_fail_crc[i]);
}
}
}
+7
View File
@@ -180,4 +180,11 @@ __EXPORT extern int up_bdshot_get_extended_telemetry(uint8_t channel, int type,
*/
__EXPORT extern int up_bdshot_channel_online(uint8_t channel);
/**
* Check if bidrectional dshot capture is supported for a channel
* @param channel Dshot channel
* @return 0 if not supported (no DMA), 1 if supported
*/
__EXPORT extern int up_bdshot_channel_capture_supported(uint8_t channel);
__END_DECLS
+6 -1
View File
@@ -1070,7 +1070,12 @@ int DShot::print_status()
// Online masks are in motor order
if (_bdshot_output_mask & (1 << actuator_channel)) {
bdshot_status = (_bdshot_telem_online_mask & (1 << motor_index)) ? "Online" : "Offline";
if (!up_bdshot_channel_capture_supported(actuator_channel)) {
bdshot_status = "No DMA";
} else {
bdshot_status = (_bdshot_telem_online_mask & (1 << motor_index)) ? "Online" : "Offline";
}
}
if (_serial_telemetry_enabled) {