mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-20 06:33:33 +08:00
[Sponsored by ARK] Bidirectional DShot (#23863)
* Bidirectional DShot Co-authored-by: Julian Oes <julian@oes.ch> * f4/f1 support, not supported * fix f1 build target * sanity check timer_channel value, fix CCxNP ifdef, debug stuff * removed debug code, added define for H7 HAVE_GTIM_CCXNP * round robin sampling for less than 4 DMA * unlimited esc_status logging * dshot: fix formatting * dshot: add define for number of DMA channels to use This allows individual boards to override the number of DShot channels and hence avoid round robin capture of the RPM feedback. * ARK: enable 4 DMA channels for DShot on 6X * dshot: publish when all channels are updated This slows down the ESC_STATUS publication in the case of round robin capture. E.g. for 800 Hz output with one DMA channel, the ESC_STATUS is now published at 200 Hz. * dshot: avoid duplicate publications for bidir and telem Instead of publishing both bidirectional dshot updates as well as telemetry updates, we now combine the data from both streams, and publish whenever we get RPM updates, as the latter arrives with higher rate, e.g. 200 Hz with round robin, or faster otherwise. When combining the data, we take RPM from bidirectional dshot, and the rest from telemetry. When we have only one of the two, either telemetry or bidirectional dshot, we just publish that one. * boards: add ark fpv and pi6x BOARD_DMA_NUM_DSHOT_CHANNELS * dshot: turn off debug build --------- Co-authored-by: Julian Oes <julian@oes.ch> Co-authored-by: alexklimaj <alex@arkelectron.com>
This commit is contained in:
co-authored by
Julian Oes
alexklimaj
parent
2280e94a47
commit
543851db50
@@ -418,6 +418,21 @@ void up_bdshot_erpm(void)
|
||||
}
|
||||
|
||||
|
||||
int up_bdshot_num_erpm_ready(void)
|
||||
{
|
||||
int num_ready = 0;
|
||||
|
||||
for (unsigned i = 0; i < DSHOT_TIMERS; ++i) {
|
||||
// We only check that data has been received, rather than if it's valid.
|
||||
// This ensures data is published even if one channel has bit errors.
|
||||
if (bdshot_recv_mask & (1 << i)) {
|
||||
++num_ready;
|
||||
}
|
||||
}
|
||||
|
||||
return num_ready;
|
||||
}
|
||||
|
||||
|
||||
int up_bdshot_get_erpm(uint8_t channel, int *erpm)
|
||||
{
|
||||
|
||||
@@ -151,9 +151,6 @@ __EXPORT int io_timer_free_channel(unsigned channel);
|
||||
__EXPORT int io_timer_get_channel_mode(unsigned channel);
|
||||
__EXPORT int io_timer_get_mode_channels(io_timer_channel_mode_t mode);
|
||||
__EXPORT extern void io_timer_trigger(void);
|
||||
__EXPORT void io_timer_update_dma_req(uint8_t timer, bool enable);
|
||||
|
||||
__EXPORT extern int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_rate, uint8_t dma_burst_length);
|
||||
|
||||
/**
|
||||
* Returns the pin configuration for a specific channel, to be used as GPIO output.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2024 PX4 Development Team. All rights reserved.
|
||||
* Author: Igor Misic <igy1000mb@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -58,5 +58,6 @@
|
||||
*/
|
||||
typedef struct dshot_conf_t {
|
||||
uint32_t dma_base;
|
||||
uint32_t dmamap;
|
||||
uint32_t dma_map_up;
|
||||
uint32_t dma_map_ch[4];
|
||||
} dshot_conf_t;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012, 2017 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -81,6 +81,8 @@ typedef enum io_timer_channel_mode_t {
|
||||
IOTimerChanMode_PPS = 8,
|
||||
IOTimerChanMode_RPM = 9,
|
||||
IOTimerChanMode_Other = 10,
|
||||
IOTimerChanMode_DshotInverted = 11,
|
||||
IOTimerChanMode_CaptureDMA = 12,
|
||||
IOTimerChanModeSize
|
||||
} io_timer_channel_mode_t;
|
||||
|
||||
@@ -159,7 +161,12 @@ __EXPORT int io_timer_unallocate_channel(unsigned channel);
|
||||
__EXPORT int io_timer_get_channel_mode(unsigned channel);
|
||||
__EXPORT int io_timer_get_mode_channels(io_timer_channel_mode_t mode);
|
||||
__EXPORT extern void io_timer_trigger(unsigned channels_mask);
|
||||
|
||||
__EXPORT void io_timer_update_dma_req(uint8_t timer, bool enable);
|
||||
__EXPORT int io_timer_set_dshot_burst_mode(uint8_t timer, unsigned dshot_pwm_rate, uint8_t dma_burst_length);
|
||||
|
||||
__EXPORT void io_timer_capture_dma_req(uint8_t timer, uint8_t timer_channel_index, bool enable);
|
||||
__EXPORT int io_timer_set_dshot_capture_mode(uint8_t timer, uint8_t timer_channel_index, unsigned dshot_pwm_freq);
|
||||
|
||||
/**
|
||||
* Reserve a timer
|
||||
@@ -169,7 +176,6 @@ __EXPORT int io_timer_allocate_timer(unsigned timer, io_timer_channel_mode_t mod
|
||||
|
||||
__EXPORT int io_timer_unallocate_timer(unsigned timer);
|
||||
|
||||
__EXPORT extern int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_rate, uint8_t dma_burst_length);
|
||||
|
||||
/**
|
||||
* Returns the pin configuration for a specific channel, to be used as GPIO output.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -103,7 +103,7 @@ static inline constexpr timer_io_channels_t initIOTimerChannelOutputClear(const
|
||||
}
|
||||
|
||||
|
||||
static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dshot_dma = {})
|
||||
static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dma = {})
|
||||
{
|
||||
bool nuttx_config_timer_enabled = false;
|
||||
io_timers_t ret{};
|
||||
@@ -268,9 +268,10 @@ static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dshot_dm
|
||||
constexpr_assert(!nuttx_config_timer_enabled, "IO Timer requires NuttX timer config to be disabled (STM32_TIMx)");
|
||||
|
||||
// DShot
|
||||
if (dshot_dma.index != DMA::Invalid) {
|
||||
ret.dshot.dma_base = getDMABaseRegister(dshot_dma);
|
||||
ret.dshot.dmamap = getTimerUpdateDMAMap(timer, dshot_dma);
|
||||
if (dma.index != DMA::Invalid) {
|
||||
ret.dshot.dma_base = getDMABaseRegister(dma);
|
||||
ret.dshot.dma_map_up = getTimerUpdateDMAMap(timer, dma);
|
||||
getTimerChannelDMAMap(timer, dma, ret.dshot.dma_map_ch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012-2016 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -365,8 +365,10 @@ int up_input_capture_set_trigger(unsigned channel, input_capture_edge edge)
|
||||
rv = -ENXIO;
|
||||
|
||||
/* Any pins in capture mode */
|
||||
int mode = io_timer_get_channel_mode(channel);
|
||||
|
||||
if (io_timer_get_channel_mode(channel) == IOTimerChanMode_Capture) {
|
||||
if (mode == IOTimerChanMode_Capture ||
|
||||
mode == IOTimerChanMode_CaptureDMA) {
|
||||
|
||||
uint16_t edge_bits = 0xffff;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012, 2017 PX4 Development Team. All rights reserved.
|
||||
* Copyright (C) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -61,7 +61,6 @@
|
||||
#include <stm32_gpio.h>
|
||||
#include <stm32_tim.h>
|
||||
|
||||
|
||||
static int io_timer_handler0(int irq, void *context, void *arg);
|
||||
static int io_timer_handler1(int irq, void *context, void *arg);
|
||||
static int io_timer_handler2(int irq, void *context, void *arg);
|
||||
@@ -73,8 +72,14 @@ static int io_timer_handler7(int irq, void *context, void *arg);
|
||||
|
||||
#if defined(HAVE_GTIM_CCXNP)
|
||||
#define HW_GTIM_CCER_CC1NP GTIM_CCER_CC1NP
|
||||
#define HW_GTIM_CCER_CC2NP GTIM_CCER_CC2NP
|
||||
#define HW_GTIM_CCER_CC3NP GTIM_CCER_CC3NP
|
||||
#define HW_GTIM_CCER_CC4NP GTIM_CCER_CC4NP
|
||||
#else
|
||||
# define HW_GTIM_CCER_CC1NP 0
|
||||
# define HW_GTIM_CCER_CC2NP 0
|
||||
# define HW_GTIM_CCER_CC3NP 0
|
||||
# define HW_GTIM_CCER_CC4NP 0
|
||||
#endif
|
||||
|
||||
#define arraySize(a) (sizeof((a))/sizeof(((a)[0])))
|
||||
@@ -96,41 +101,42 @@ static int io_timer_handler7(int irq, void *context, void *arg);
|
||||
|
||||
#define MAX_CHANNELS_PER_TIMER 4
|
||||
|
||||
#define _REG32(_base, _reg) (*(volatile uint32_t *)(_base + _reg))
|
||||
#define REG(_tmr, _reg) _REG32(io_timers[_tmr].base, _reg)
|
||||
#define _REG32(_base, _reg) (*(volatile uint32_t *)(_base + _reg))
|
||||
#define REG(_tmr, _reg) _REG32(io_timers[_tmr].base, _reg)
|
||||
|
||||
#define rCR1(_tmr) REG(_tmr, STM32_GTIM_CR1_OFFSET)
|
||||
#define rCR2(_tmr) REG(_tmr, STM32_GTIM_CR2_OFFSET)
|
||||
#define rSMCR(_tmr) REG(_tmr, STM32_GTIM_SMCR_OFFSET)
|
||||
#define rDIER(_tmr) REG(_tmr, STM32_GTIM_DIER_OFFSET)
|
||||
#define rSR(_tmr) REG(_tmr, STM32_GTIM_SR_OFFSET)
|
||||
#define rEGR(_tmr) REG(_tmr, STM32_GTIM_EGR_OFFSET)
|
||||
#define rCCMR1(_tmr) REG(_tmr, STM32_GTIM_CCMR1_OFFSET)
|
||||
#define rCCMR2(_tmr) REG(_tmr, STM32_GTIM_CCMR2_OFFSET)
|
||||
#define rCCER(_tmr) REG(_tmr, STM32_GTIM_CCER_OFFSET)
|
||||
#define rCNT(_tmr) REG(_tmr, STM32_GTIM_CNT_OFFSET)
|
||||
#define rPSC(_tmr) REG(_tmr, STM32_GTIM_PSC_OFFSET)
|
||||
#define rARR(_tmr) REG(_tmr, STM32_GTIM_ARR_OFFSET)
|
||||
#define rCCR1(_tmr) REG(_tmr, STM32_GTIM_CCR1_OFFSET)
|
||||
#define rCCR2(_tmr) REG(_tmr, STM32_GTIM_CCR2_OFFSET)
|
||||
#define rCCR3(_tmr) REG(_tmr, STM32_GTIM_CCR3_OFFSET)
|
||||
#define rCCR4(_tmr) REG(_tmr, STM32_GTIM_CCR4_OFFSET)
|
||||
#define rDCR(_tmr) REG(_tmr, STM32_GTIM_DCR_OFFSET)
|
||||
#define rDMAR(_tmr) REG(_tmr, STM32_GTIM_DMAR_OFFSET)
|
||||
#define rBDTR(_tmr) REG(_tmr, STM32_ATIM_BDTR_OFFSET)
|
||||
#define rCR1(_tmr) REG(_tmr, STM32_GTIM_CR1_OFFSET)
|
||||
#define rCR2(_tmr) REG(_tmr, STM32_GTIM_CR2_OFFSET)
|
||||
#define rSMCR(_tmr) REG(_tmr, STM32_GTIM_SMCR_OFFSET)
|
||||
#define rDIER(_tmr) REG(_tmr, STM32_GTIM_DIER_OFFSET)
|
||||
#define rSR(_tmr) REG(_tmr, STM32_GTIM_SR_OFFSET)
|
||||
#define rEGR(_tmr) REG(_tmr, STM32_GTIM_EGR_OFFSET)
|
||||
#define rCCMR1(_tmr) REG(_tmr, STM32_GTIM_CCMR1_OFFSET)
|
||||
#define rCCMR2(_tmr) REG(_tmr, STM32_GTIM_CCMR2_OFFSET)
|
||||
#define rCCER(_tmr) REG(_tmr, STM32_GTIM_CCER_OFFSET)
|
||||
#define rCNT(_tmr) REG(_tmr, STM32_GTIM_CNT_OFFSET)
|
||||
#define rPSC(_tmr) REG(_tmr, STM32_GTIM_PSC_OFFSET)
|
||||
#define rARR(_tmr) REG(_tmr, STM32_GTIM_ARR_OFFSET)
|
||||
#define rCCR1(_tmr) REG(_tmr, STM32_GTIM_CCR1_OFFSET)
|
||||
#define rCCR2(_tmr) REG(_tmr, STM32_GTIM_CCR2_OFFSET)
|
||||
#define rCCR3(_tmr) REG(_tmr, STM32_GTIM_CCR3_OFFSET)
|
||||
#define rCCR4(_tmr) REG(_tmr, STM32_GTIM_CCR4_OFFSET)
|
||||
#define rDCR(_tmr) REG(_tmr, STM32_GTIM_DCR_OFFSET)
|
||||
#define rDMAR(_tmr) REG(_tmr, STM32_GTIM_DMAR_OFFSET)
|
||||
#define rBDTR(_tmr) REG(_tmr, STM32_ATIM_BDTR_OFFSET)
|
||||
|
||||
#define GTIM_SR_CCIF (GTIM_SR_CC4IF|GTIM_SR_CC3IF|GTIM_SR_CC2IF|GTIM_SR_CC1IF)
|
||||
#define GTIM_SR_CCOF (GTIM_SR_CC4OF|GTIM_SR_CC3OF|GTIM_SR_CC2OF|GTIM_SR_CC1OF)
|
||||
|
||||
#define CCMR_C1_RESET 0x00ff
|
||||
#define CCMR_C1_NUM_BITS 8
|
||||
#define CCER_C1_NUM_BITS 4
|
||||
#define CCMR_C1_RESET 0x00ff
|
||||
#define CCMR_C1_NUM_BITS 8
|
||||
#define CCER_C1_NUM_BITS 4
|
||||
|
||||
#define CCMR_C1_CAPTURE_INIT (GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC1S_SHIFT) | \
|
||||
(GTIM_CCMR_ICPSC_NOPSC << GTIM_CCMR1_IC1PSC_SHIFT) | \
|
||||
(GTIM_CCMR_ICF_NOFILT << GTIM_CCMR1_IC1F_SHIFT)
|
||||
|
||||
#define CCMR_C1_PWMOUT_INIT (GTIM_CCMR_MODE_PWM1 << GTIM_CCMR1_OC1M_SHIFT) | GTIM_CCMR1_OC1PE
|
||||
#define CCMR_C1_PWMOUT_INVERTED_INIT (GTIM_CCMR_MODE_PWM2 << GTIM_CCMR1_OC1M_SHIFT) | GTIM_CCMR1_OC1PE
|
||||
|
||||
#define CCMR_C1_PWMIN_INIT 0 // TBD
|
||||
|
||||
@@ -141,15 +147,15 @@ static int io_timer_handler7(int irq, void *context, void *arg);
|
||||
#endif
|
||||
|
||||
/* The transfer is done to 1 register starting from TIMx_CR1 + TIMx_DCR.DBA */
|
||||
#define TIM_DMABURSTLENGTH_1TRANSFER 0x00000000U
|
||||
#define TIM_DMABURSTLENGTH_1TRANSFER 0x00000000U
|
||||
/* The transfer is done to 2 registers starting from TIMx_CR1 + TIMx_DCR.DBA */
|
||||
#define TIM_DMABURSTLENGTH_2TRANSFERS 0x00000100U
|
||||
#define TIM_DMABURSTLENGTH_2TRANSFERS 0x00000100U
|
||||
/* The transfer is done to 3 registers starting from TIMx_CR1 + TIMx_DCR.DBA */
|
||||
#define TIM_DMABURSTLENGTH_3TRANSFERS 0x00000200U
|
||||
#define TIM_DMABURSTLENGTH_3TRANSFERS 0x00000200U
|
||||
/* The transfer is done to 4 registers starting from TIMx_CR1 + TIMx_DCR.DBA */
|
||||
#define TIM_DMABURSTLENGTH_4TRANSFERS 0x00000300U
|
||||
#define TIM_DMABURSTLENGTH_4TRANSFERS 0x00000300U
|
||||
|
||||
// NotUsed PWMOut PWMIn Capture OneShot Trigger Dshot LED PPS Other
|
||||
// NotUsed PWMOut PWMIn Capture OneShot Trigger Dshot LED PPS Other
|
||||
io_timer_channel_allocation_t channel_allocations[IOTimerChanModeSize] = { UINT16_MAX, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
typedef uint8_t io_timer_allocation_t; /* big enough to hold MAX_IO_TIMERS */
|
||||
@@ -161,15 +167,15 @@ io_timer_channel_allocation_t timer_allocations[MAX_IO_TIMERS] = { };
|
||||
/* Stats and handlers are only useful for Capture */
|
||||
|
||||
typedef struct channel_stat_t {
|
||||
uint32_t isr_cout;
|
||||
uint32_t overflows;
|
||||
uint32_t isr_cout;
|
||||
uint32_t overflows;
|
||||
} channel_stat_t;
|
||||
|
||||
static channel_stat_t io_timer_channel_stats[MAX_TIMER_IO_CHANNELS];
|
||||
|
||||
static struct channel_handler_entry {
|
||||
channel_handler_t callback;
|
||||
void *context;
|
||||
void *context;
|
||||
} channel_handlers[MAX_TIMER_IO_CHANNELS];
|
||||
#endif // !defined(BOARD_HAS_NO_CAPTURE)
|
||||
|
||||
@@ -519,7 +525,57 @@ void io_timer_update_dma_req(uint8_t timer, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_freq, uint8_t dma_burst_length)
|
||||
void io_timer_capture_dma_req(uint8_t timer, uint8_t timer_channel_index, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
switch (timer_channel_index) {
|
||||
case 0:
|
||||
rDIER(timer) |= ATIM_DIER_CC1DE;
|
||||
rEGR(timer) |= (ATIM_EGR_UG | ATIM_EGR_CC1G);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rDIER(timer) |= ATIM_DIER_CC2DE;
|
||||
rEGR(timer) |= (ATIM_EGR_UG | ATIM_EGR_CC2G);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rDIER(timer) |= ATIM_DIER_CC3DE;
|
||||
rEGR(timer) |= (ATIM_EGR_UG | ATIM_EGR_CC3G);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
rDIER(timer) |= ATIM_DIER_CC4DE;
|
||||
rEGR(timer) |= (ATIM_EGR_UG | ATIM_EGR_CC4G);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
switch (timer_channel_index) {
|
||||
case 0:
|
||||
rEGR(timer) &= ~(ATIM_EGR_UG | ATIM_EGR_CC1G);
|
||||
rDIER(timer) &= ~ATIM_DIER_CC1DE;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rEGR(timer) &= ~(ATIM_EGR_UG | ATIM_EGR_CC2G);
|
||||
rDIER(timer) &= ~ATIM_DIER_CC2DE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rEGR(timer) &= ~(ATIM_EGR_UG | ATIM_EGR_CC3G);
|
||||
rDIER(timer) &= ~ATIM_DIER_CC3DE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
rEGR(timer) &= ~(ATIM_EGR_UG | ATIM_EGR_CC4G);
|
||||
rDIER(timer) &= ~ATIM_DIER_CC4DE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int io_timer_set_dshot_burst_mode(uint8_t timer, unsigned dshot_pwm_freq, uint8_t dma_burst_length)
|
||||
{
|
||||
int ret_val = OK;
|
||||
uint32_t tim_dma_burst_length;
|
||||
@@ -545,7 +601,7 @@ int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_freq, uint8_t dma_
|
||||
rPSC(timer) = ((int)(io_timers[timer].clock_freq / dshot_pwm_freq) / DSHOT_MOTOR_PWM_BIT_WIDTH) - 1;
|
||||
rEGR(timer) = ATIM_EGR_UG;
|
||||
|
||||
// find the lowest channel index for the timer (they are not necesarily in ascending order)
|
||||
// find the lowest channel index for the timer (they are not necessarily in ascending order)
|
||||
unsigned lowest_timer_channel = 4;
|
||||
uint32_t first_channel_index = io_timers_channel_mapping.element[timer].first_channel_index;
|
||||
uint32_t last_channel_index = first_channel_index + io_timers_channel_mapping.element[timer].channel_count;
|
||||
@@ -574,6 +630,47 @@ int io_timer_set_dshot_mode(uint8_t timer, unsigned dshot_pwm_freq, uint8_t dma_
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int io_timer_set_dshot_capture_mode(uint8_t timer, uint8_t timer_channel_index, unsigned dshot_pwm_freq)
|
||||
{
|
||||
// Timer Autor Reload Register max value
|
||||
rARR(timer) = 0xFFFFFFFF;
|
||||
// Timer Prescalar
|
||||
rPSC(timer) = ((int)(io_timers[timer].clock_freq / (dshot_pwm_freq * 5 / 4)) / DSHOT_MOTOR_PWM_BIT_WIDTH) - 1;
|
||||
|
||||
switch (timer_channel_index) {
|
||||
case 0:
|
||||
rEGR(timer) |= ATIM_EGR_UG | GTIM_EGR_CC1G;
|
||||
rCCER(timer) &= ~(GTIM_CCER_CC1E | GTIM_CCER_CC1P | HW_GTIM_CCER_CC1NP);
|
||||
rCCMR1(timer) |= (GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC1S_SHIFT);
|
||||
rCCER(timer) |= (GTIM_CCER_CC1E | GTIM_CCER_CC1P | HW_GTIM_CCER_CC1NP);
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
rEGR(timer) |= ATIM_EGR_UG | GTIM_EGR_CC2G;
|
||||
rCCER(timer) &= ~(GTIM_CCER_CC2E | GTIM_CCER_CC2P | HW_GTIM_CCER_CC2NP);
|
||||
rCCMR1(timer) |= (GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR1_CC2S_SHIFT);
|
||||
rCCER(timer) |= (GTIM_CCER_CC2E | GTIM_CCER_CC2P | HW_GTIM_CCER_CC2NP);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rEGR(timer) |= ATIM_EGR_UG | GTIM_EGR_CC3G;
|
||||
rCCER(timer) &= ~(GTIM_CCER_CC3E | GTIM_CCER_CC3P | HW_GTIM_CCER_CC3NP);
|
||||
rCCMR2(timer) |= (GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR2_CC3S_SHIFT);
|
||||
rCCER(timer) |= (GTIM_CCER_CC3E | GTIM_CCER_CC3P | HW_GTIM_CCER_CC3NP);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
rEGR(timer) |= ATIM_EGR_UG | GTIM_EGR_CC4G;
|
||||
rCCER(timer) &= ~(GTIM_CCER_CC4E | GTIM_CCER_CC4P | HW_GTIM_CCER_CC4NP);
|
||||
rCCMR2(timer) |= (GTIM_CCMR_CCS_CCIN1 << GTIM_CCMR2_CC4S_SHIFT);
|
||||
rCCER(timer) |= (GTIM_CCER_CC4E | GTIM_CCER_CC4P | HW_GTIM_CCER_CC4NP);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void io_timer_set_PWM_mode(unsigned timer)
|
||||
{
|
||||
rPSC(timer) = (io_timers[timer].clock_freq / BOARD_PWM_FREQ) - 1;
|
||||
@@ -773,6 +870,12 @@ int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode,
|
||||
setbits = CCMR_C1_PWMOUT_INIT;
|
||||
break;
|
||||
|
||||
case IOTimerChanMode_DshotInverted:
|
||||
ccer_setbits = 0;
|
||||
dier_setbits = 0;
|
||||
setbits = CCMR_C1_PWMOUT_INVERTED_INIT;
|
||||
break;
|
||||
|
||||
case IOTimerChanMode_PWMIn:
|
||||
setbits = CCMR_C1_PWMIN_INIT;
|
||||
gpio = timer_io_channels[channel].gpio_in;
|
||||
@@ -781,6 +884,7 @@ int io_timer_channel_init(unsigned channel, io_timer_channel_mode_t mode,
|
||||
#if !defined(BOARD_HAS_NO_CAPTURE)
|
||||
|
||||
case IOTimerChanMode_Capture:
|
||||
case IOTimerChanMode_CaptureDMA:
|
||||
setbits = CCMR_C1_CAPTURE_INIT;
|
||||
gpio = timer_io_channels[channel].gpio_in;
|
||||
break;
|
||||
@@ -897,10 +1001,12 @@ int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_chann
|
||||
break;
|
||||
|
||||
case IOTimerChanMode_Dshot:
|
||||
case IOTimerChanMode_DshotInverted:
|
||||
dier_bit = 0;
|
||||
|
||||
/* fallthrough */
|
||||
case IOTimerChanMode_Capture:
|
||||
case IOTimerChanMode_CaptureDMA:
|
||||
cr1_bit = state ? GTIM_CR1_CEN : 0;
|
||||
|
||||
/* fallthrough */
|
||||
@@ -946,6 +1052,7 @@ int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_chann
|
||||
(mode == IOTimerChanMode_PWMOut ||
|
||||
mode == IOTimerChanMode_OneShot ||
|
||||
mode == IOTimerChanMode_Dshot ||
|
||||
mode == IOTimerChanMode_DshotInverted ||
|
||||
mode == IOTimerChanMode_Trigger))) {
|
||||
action_cache[timer].gpio[shifts] = timer_io_channels[chan_index].gpio_out;
|
||||
}
|
||||
@@ -985,7 +1092,7 @@ int io_timer_set_enable(bool state, io_timer_channel_mode_t mode, io_timer_chann
|
||||
/* arm requires the timer be enabled */
|
||||
rCR1(actions) |= cr1_bit;
|
||||
|
||||
} else {
|
||||
} else {
|
||||
|
||||
rCR1(actions) = 0;
|
||||
}
|
||||
@@ -1006,6 +1113,7 @@ int io_timer_set_ccr(unsigned channel, uint16_t value)
|
||||
if ((mode != IOTimerChanMode_PWMOut) &&
|
||||
(mode != IOTimerChanMode_OneShot) &&
|
||||
(mode != IOTimerChanMode_Dshot) &&
|
||||
(mode != IOTimerChanMode_DshotInverted) &&
|
||||
(mode != IOTimerChanMode_Trigger)) {
|
||||
|
||||
rv = -EIO;
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
|
||||
#include "../../../stm32_common/include/px4_arch/hw_description.h"
|
||||
|
||||
static inline constexpr void getTimerChannelDMAMap(Timer::Timer timer, const DMA &dma, uint32_t *dma_map_ch)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const DMA &dma)
|
||||
{
|
||||
// not used on STM32F1
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
|
||||
#include "../../../stm32_common/include/px4_arch/hw_description.h"
|
||||
|
||||
static inline constexpr void getTimerChannelDMAMap(Timer::Timer timer, const DMA &dma, uint32_t *dma_map_ch)
|
||||
{
|
||||
// Not supported
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const DMA &dma)
|
||||
{
|
||||
uint32_t dma_map = 0;
|
||||
|
||||
@@ -35,6 +35,47 @@
|
||||
|
||||
#include "../../../stm32_common/include/px4_arch/hw_description.h"
|
||||
|
||||
static inline constexpr void getTimerChannelDMAMap(Timer::Timer timer, const DMA &dma, uint32_t *dma_map_ch)
|
||||
{
|
||||
switch (timer) {
|
||||
case Timer::Timer1:
|
||||
if (dma.index == DMA::Index2) {
|
||||
dma_map_ch[0] = DMAMAP_TIM1_CH1;
|
||||
dma_map_ch[1] = DMAMAP_TIM1_CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_TIM1_CH3_2;
|
||||
dma_map_ch[3] = DMAMAP_TIM1_CH4;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer2:
|
||||
case Timer::Timer3:
|
||||
break;
|
||||
|
||||
case Timer::Timer4:
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_TIM4_CH1;
|
||||
dma_map_ch[1] = DMAMAP_TIM4_CH2;
|
||||
dma_map_ch[2] = DMAMAP_TIM4_CH3;
|
||||
dma_map_ch[3] = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer5:
|
||||
case Timer::Timer6:
|
||||
case Timer::Timer7:
|
||||
case Timer::Timer8:
|
||||
case Timer::Timer9:
|
||||
case Timer::Timer10:
|
||||
case Timer::Timer11:
|
||||
case Timer::Timer12:
|
||||
case Timer::Timer13:
|
||||
case Timer::Timer14:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const DMA &dma)
|
||||
{
|
||||
uint32_t dma_map = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,47 +35,211 @@
|
||||
|
||||
#include "../../../stm32_common/include/px4_arch/hw_description.h"
|
||||
|
||||
static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const DMA &dma)
|
||||
static inline constexpr void getTimerChannelDMAMap(Timer::Timer timer, const DMA &dma, uint32_t *dma_map_ch)
|
||||
{
|
||||
uint32_t dma_map = 0;
|
||||
|
||||
switch (timer) {
|
||||
case Timer::Timer1:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM1UP_0 : DMAMAP_DMA12_TIM1UP_1;
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM1CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM1CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM1CH3_0;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM1CH4_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM1CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM1CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM1CH3_1;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM1CH4_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer2:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM2UP_0 : DMAMAP_DMA12_TIM2UP_1;
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM2CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM2CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM2CH3_0;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM2CH4_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM2CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM2CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM2CH3_1;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM2CH4_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer3:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM3UP_0 : DMAMAP_DMA12_TIM3UP_1;
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM3CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM3CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM3CH3_0;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM3CH4_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM3CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM3CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM3CH3_1;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM3CH4_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer4:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM4UP_0 : DMAMAP_DMA12_TIM4UP_1;
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM4CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM4CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM4CH3_0;
|
||||
dma_map_ch[3] = 0;
|
||||
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM4CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM4CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM4CH3_1;
|
||||
dma_map_ch[3] = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer5:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM5UP_0 : DMAMAP_DMA12_TIM5UP_1;
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM5CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM5CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM5CH3_0;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM5CH4_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM5CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM5CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM5CH3_1;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM5CH4_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer6:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM6UP_0 : DMAMAP_DMA12_TIM6UP_1;
|
||||
// No channels available
|
||||
break;
|
||||
|
||||
case Timer::Timer7:
|
||||
// No channels available
|
||||
break;
|
||||
|
||||
case Timer::Timer8:
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM8CH1_0;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM8CH2_0;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM8CH3_0;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM8CH4_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM8CH1_1;
|
||||
dma_map_ch[1] = DMAMAP_DMA12_TIM8CH2_1;
|
||||
dma_map_ch[2] = DMAMAP_DMA12_TIM8CH3_1;
|
||||
dma_map_ch[3] = DMAMAP_DMA12_TIM8CH4_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer9:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer10:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer11:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer12:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer13:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer14:
|
||||
// Non-existent
|
||||
break;
|
||||
|
||||
case Timer::Timer15:
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM15CH1_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM15CH1_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer16:
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM16CH1_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM16CH1_1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer17:
|
||||
if (dma.index == DMA::Index1) {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM17CH1_0;
|
||||
|
||||
} else {
|
||||
dma_map_ch[0] = DMAMAP_DMA12_TIM17CH1_1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const DMA &dma)
|
||||
{
|
||||
uint32_t dma_map_up = 0;
|
||||
|
||||
switch (timer) {
|
||||
case Timer::Timer1:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM1UP_0 : DMAMAP_DMA12_TIM1UP_1;
|
||||
break;
|
||||
|
||||
case Timer::Timer2:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM2UP_0 : DMAMAP_DMA12_TIM2UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer3:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM3UP_0 : DMAMAP_DMA12_TIM3UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer4:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM4UP_0 : DMAMAP_DMA12_TIM4UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer5:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM5UP_0 : DMAMAP_DMA12_TIM5UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer6:
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM6UP_0 : DMAMAP_DMA12_TIM6UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer7:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM7UP_0 : DMAMAP_DMA12_TIM7UP_1;
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM7UP_0 : DMAMAP_DMA12_TIM7UP_1;
|
||||
|
||||
break;
|
||||
|
||||
case Timer::Timer8:
|
||||
dma_map = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM8UP_0 : DMAMAP_DMA12_TIM8UP_1;
|
||||
dma_map_up = (dma.index == DMA::Index1) ? DMAMAP_DMA12_TIM8UP_0 : DMAMAP_DMA12_TIM8UP_1;
|
||||
|
||||
break;
|
||||
|
||||
@@ -91,6 +255,6 @@ static inline constexpr uint32_t getTimerUpdateDMAMap(Timer::Timer timer, const
|
||||
break;
|
||||
}
|
||||
|
||||
constexpr_assert(dma_map != 0, "Invalid DMA config for given timer");
|
||||
return dma_map;
|
||||
constexpr_assert(dma_map_up != 0, "Invalid DMA config for given timer");
|
||||
return dma_map_up;
|
||||
}
|
||||
|
||||
@@ -33,3 +33,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../../stm32_common/include/px4_arch/io_timer.h"
|
||||
|
||||
#define HAVE_GTIM_CCXNP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
|
||||
* Copyright (c) 2024 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -135,7 +135,7 @@ static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dshot_dma = {})
|
||||
static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dma = {})
|
||||
{
|
||||
bool nuttx_config_timer_enabled = false;
|
||||
io_timers_t ret{};
|
||||
@@ -306,9 +306,10 @@ static inline constexpr io_timers_t initIOTimer(Timer::Timer timer, DMA dshot_dm
|
||||
constexpr_assert(!nuttx_config_timer_enabled, "IO Timer requires NuttX timer config to be disabled (STM32_TIMx)");
|
||||
|
||||
// DShot
|
||||
if (dshot_dma.index != DMA::Invalid) {
|
||||
ret.dshot.dma_base = getDMABaseRegister(dshot_dma);
|
||||
ret.dshot.dmamap = getTimerUpdateDMAMap(timer, dshot_dma);
|
||||
if (dma.index != DMA::Invalid) {
|
||||
ret.dshot.dma_base = getDMABaseRegister(dma);
|
||||
ret.dshot.dma_map_up = getTimerUpdateDMAMap(timer, dma);
|
||||
getTimerChannelDMAMap(timer, dma, ret.dshot.dma_map_ch);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user