Compare commits

...

6 Commits

Author SHA1 Message Date
Peter van der Perk 7f2f71d99b tropic-community: Set FlexIO2 clocking for DShot 2025-07-17 22:00:30 +02:00
Peter van der Perk 8edc071e8c imxrt: dshot clean/up simplification 2025-07-17 22:00:00 +02:00
dirksavage88 2ce745568f fold both flexio's into one irq handler
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2025-07-17 12:26:52 -04:00
dirksavage88 2d0eedc71d replace flexio number with actual base value
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2025-07-17 09:45:31 -04:00
dirksavage88 e5b2584da7 revert board config
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2025-07-17 08:19:52 -04:00
dirksavage88 b23a7fc314 implement dshot on pwm 4
Signed-off-by: dirksavage88 <dirksavage88@gmail.com>
2025-07-17 08:17:08 -04:00
6 changed files with 203 additions and 92 deletions
@@ -138,6 +138,9 @@
#define CONFIG_FLEXIO1_CLK 1 #define CONFIG_FLEXIO1_CLK 1
#define CONFIG_FLEXIO1_PRED_DIVIDER 5 #define CONFIG_FLEXIO1_PRED_DIVIDER 5
#define CONFIG_FLEXIO1_PODF_DIVIDER 1 #define CONFIG_FLEXIO1_PODF_DIVIDER 1
#define CONFIG_FLEXIO2_CLK 1
#define CONFIG_FLEXIO2_PRED_DIVIDER 5
#define CONFIG_FLEXIO2_PODF_DIVIDER 1
#define CONFIG_PLL3_PFD2_FRAC 16 #define CONFIG_PLL3_PFD2_FRAC 16
#define BOARD_FLEXIO_PREQ 108000000 #define BOARD_FLEXIO_PREQ 108000000
+14
View File
@@ -301,6 +301,20 @@ void imxrt_flexio_clocking(void)
reg |= CCM_CDCDR_FLEXIO1_CLK_PRED reg |= CCM_CDCDR_FLEXIO1_CLK_PRED
(CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO1_PRED_DIVIDER)); (CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO1_PRED_DIVIDER));
putreg32(reg, IMXRT_CCM_CDCDR); putreg32(reg, IMXRT_CCM_CDCDR);
reg = getreg32(IMXRT_CCM_CSCMR2);
reg &= ~(CCM_CSCMR2_FLEXIO2_CLK_SEL_MASK);
reg |= CCM_CSCMR2_FLEXIO2_CLK_SEL(CONFIG_FLEXIO2_CLK);
putreg32(reg, IMXRT_CCM_CSCMR2);
reg = getreg32(IMXRT_CCM_CS1CDR);
reg &= ~(CCM_CS1CDR_FLEXIO2_CLK_PRED_MASK |
CCM_CS1CDR_FLEXIO2_CLK_PODF_MASK);
reg |= CCM_CS1CDR_FLEXIO2_CLK_PODF
(CCM_PODF_FROM_DIVISOR(CONFIG_FLEXIO2_PODF_DIVIDER));
reg |= CCM_CS1CDR_FLEXIO2_CLK_PRED
(CCM_PRED_FROM_DIVISOR(CONFIG_FLEXIO2_PRED_DIVIDER));
putreg32(reg, IMXRT_CCM_CS1CDR);
} }
@@ -77,19 +77,22 @@
constexpr io_timers_t io_timers[MAX_IO_TIMERS] = { constexpr io_timers_t io_timers[MAX_IO_TIMERS] = {
initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule0), // PWM_1, PMW_5 initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule0), // PWM_1, PMW_5
initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule1), // PWM_0 initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule1), // PWM_0
initIOPWM(PWM::FlexPWM2, PWM::Submodule2), // PWM_4 initIOPWMDshot(PWM::FlexPWM2, PWM::Submodule2), // PWM_4
initIOPWMDshot(PWM::FlexPWM4, PWM::Submodule2), // PWM_2, PWM_3 initIOPWMDshot(PWM::FlexPWM4, PWM::Submodule2), // PWM_2, PWM_3
}; };
#define FXIO_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER) #define FXIO_IOMUX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER)
//TODO: distinguish between the different FlexIO instances
//
constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = { constexpr timer_io_channels_t timer_io_channels[MAX_TIMER_IO_CHANNELS] = {
initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_06, GPIO_FLEXIO1_FLEXIO06_1 | FXIO_IOMUX, 6), /* RevA. PWM_1 RevB. PWM1 */ initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_06, GPIO_FLEXIO1_FLEXIO06_1 | FXIO_IOMUX, IMXRT_FLEXIO1_BASE, 6), /* RevA. PWM_1 RevB. PWM1 */
initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_07, GPIO_FLEXIO1_FLEXIO07_1 | FXIO_IOMUX, 7), /* RevA. PWM_5 RevB. PWM2 */ initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule0}, IOMUX::Pad::GPIO_EMC_07, GPIO_FLEXIO1_FLEXIO07_1 | FXIO_IOMUX, IMXRT_FLEXIO1_BASE, 7), /* RevA. PWM_5 RevB. PWM2 */
initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_08, GPIO_FLEXIO1_FLEXIO08_1 | FXIO_IOMUX, 8), /* RevA. PWM_0 RevB. PWM3 */ initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_A, PWM::Submodule1}, IOMUX::Pad::GPIO_EMC_08, GPIO_FLEXIO1_FLEXIO08_1 | FXIO_IOMUX, IMXRT_FLEXIO1_BASE, 8), /* RevA. PWM_0 RevB. PWM3 */
initIOTimerChannel(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule2}, IOMUX::Pad::GPIO_B0_11), /* RevA. PWM_4 RevB. PWM4 */ initIOTimerChannelDshot(io_timers, {PWM::PWM2_PWM_B, PWM::Submodule2}, IOMUX::Pad::GPIO_B0_11, GPIO_FLEXIO2_FLEXIO11_1 | FXIO_IOMUX, IMXRT_FLEXIO2_BASE, 11), /* RevA. PWM_4 RevB. PWM4 */
initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_A, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_04, GPIO_FLEXIO1_FLEXIO04_1 | FXIO_IOMUX, 4), /* RevA. PWM_3 RevB. PWM5 */ initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_A, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_04, GPIO_FLEXIO1_FLEXIO04_1 | FXIO_IOMUX, IMXRT_FLEXIO1_BASE, 4), /* RevA. PWM_3 RevB. PWM5 */
initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_B, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_05, GPIO_FLEXIO1_FLEXIO05_1 | FXIO_IOMUX, 5), /* RevA. PWM_2 RevB. PWM6 */ initIOTimerChannelDshot(io_timers, {PWM::PWM4_PWM_B, PWM::Submodule2}, IOMUX::Pad::GPIO_EMC_05, GPIO_FLEXIO1_FLEXIO05_1 | FXIO_IOMUX, IMXRT_FLEXIO1_BASE, 5), /* RevA. PWM_2 RevB. PWM6 */
}; };
constexpr io_timers_channel_mapping_t io_timers_channel_mapping = constexpr io_timers_channel_mapping_t io_timers_channel_mapping =
+162 -71
View File
@@ -45,7 +45,9 @@
#include "arm_internal.h" #include "arm_internal.h"
#define FLEXIO_BASE IMXRT_FLEXIO1_BASE #define FLEXIO1_BASE IMXRT_FLEXIO1_BASE
#define FLEXIO2_BASE IMXRT_FLEXIO2_BASE
#define DSHOT_TIMERS FLEXIO_SHIFTBUFNIS_COUNT #define DSHOT_TIMERS FLEXIO_SHIFTBUFNIS_COUNT
#define DSHOT_THROTTLE_POSITION 5u #define DSHOT_THROTTLE_POSITION 5u
#define DSHOT_TELEMETRY_POSITION 4u #define DSHOT_TELEMETRY_POSITION 4u
@@ -98,77 +100,80 @@ static uint32_t dshot_mask;
static uint32_t bdshot_recv_mask; static uint32_t bdshot_recv_mask;
static uint32_t bdshot_parsed_recv_mask; static uint32_t bdshot_parsed_recv_mask;
static inline uint32_t flexio_getreg32(uint32_t offset) static uint32_t flexio1_base_addr = FLEXIO1_BASE;
static uint32_t flexio2_base_addr = FLEXIO2_BASE;
static inline uint32_t flexio_getreg32(uint32_t flexio_base, uint32_t offset)
{ {
return getreg32(FLEXIO_BASE + offset); return getreg32(flexio_base + offset);
} }
static inline void flexio_modifyreg32(unsigned int offset, static inline void flexio_modifyreg32(uint32_t flexio_base, unsigned int offset,
uint32_t clearbits, uint32_t clearbits,
uint32_t setbits) uint32_t setbits)
{ {
modifyreg32(FLEXIO_BASE + offset, clearbits, setbits); modifyreg32(flexio_base + offset, clearbits, setbits);
} }
static inline void flexio_putreg32(uint32_t value, uint32_t offset) static inline void flexio_putreg32(uint32_t flexio_base, uint32_t value, uint32_t offset)
{ {
putreg32(value, FLEXIO_BASE + offset); putreg32(value, flexio_base + offset);
} }
static inline void enable_shifter_status_interrupts(uint32_t mask) static inline void enable_shifter_status_interrupts(uint32_t flexio_base, uint32_t mask)
{ {
flexio_modifyreg32(IMXRT_FLEXIO_SHIFTSIEN_OFFSET, 0, mask); flexio_modifyreg32(flexio_base, IMXRT_FLEXIO_SHIFTSIEN_OFFSET, 0, mask);
} }
static inline void disable_shifter_status_interrupts(uint32_t mask) static inline void disable_shifter_status_interrupts(uint32_t flexio_base, uint32_t mask)
{ {
flexio_modifyreg32(IMXRT_FLEXIO_SHIFTSIEN_OFFSET, mask, 0); flexio_modifyreg32(flexio_base, IMXRT_FLEXIO_SHIFTSIEN_OFFSET, mask, 0);
} }
static inline uint32_t get_shifter_status_flags(void) static inline uint32_t get_shifter_status_flags(uint32_t flexio_base)
{ {
return flexio_getreg32(IMXRT_FLEXIO_SHIFTSTAT_OFFSET); return flexio_getreg32(flexio_base, IMXRT_FLEXIO_SHIFTSTAT_OFFSET);
} }
static inline void clear_shifter_status_flags(uint32_t mask) static inline void clear_shifter_status_flags(uint32_t flexio_base, uint32_t mask)
{ {
flexio_putreg32(mask, IMXRT_FLEXIO_SHIFTSTAT_OFFSET); flexio_putreg32(flexio_base, mask, IMXRT_FLEXIO_SHIFTSTAT_OFFSET);
} }
static inline void enable_timer_status_interrupts(uint32_t mask) static inline void enable_timer_status_interrupts(uint32_t flexio_base, uint32_t mask)
{ {
flexio_modifyreg32(IMXRT_FLEXIO_TIMIEN_OFFSET, 0, mask); flexio_modifyreg32(flexio_base, IMXRT_FLEXIO_TIMIEN_OFFSET, 0, mask);
} }
static inline void disable_timer_status_interrupts(uint32_t mask) static inline void disable_timer_status_interrupts(uint32_t flexio_base, uint32_t mask)
{ {
flexio_modifyreg32(IMXRT_FLEXIO_TIMIEN_OFFSET, mask, 0); flexio_modifyreg32(flexio_base, IMXRT_FLEXIO_TIMIEN_OFFSET, mask, 0);
} }
static inline uint32_t get_timer_status_flags(void) static inline uint32_t get_timer_status_flags(uint32_t flexio_base)
{ {
return flexio_getreg32(IMXRT_FLEXIO_TIMSTAT_OFFSET); return flexio_getreg32(flexio_base, IMXRT_FLEXIO_TIMSTAT_OFFSET);
} }
static inline void clear_timer_status_flags(uint32_t mask) static inline void clear_timer_status_flags(uint32_t flexio_base, uint32_t mask)
{ {
flexio_putreg32(mask, IMXRT_FLEXIO_TIMSTAT_OFFSET); flexio_putreg32(flexio_base, mask, IMXRT_FLEXIO_TIMSTAT_OFFSET);
} }
static void flexio_dshot_output(uint32_t channel, uint32_t pin, uint32_t timcmp, bool inverted) static void flexio_dshot_output(uint32_t flexio_base, uint32_t channel, uint32_t pin, uint32_t timcmp, bool inverted)
{ {
/* Disable Shifter */ /* Disable Shifter */
flexio_putreg32(0, IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4); flexio_putreg32(flexio_base, 0, IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4);
/* No start bit, stop bit low */ /* No start bit, stop bit low */
flexio_putreg32(FLEXIO_SHIFTCFG_INSRC(FLEXIO_SHIFTER_INPUT_FROM_PIN) | flexio_putreg32(flexio_base, FLEXIO_SHIFTCFG_INSRC(FLEXIO_SHIFTER_INPUT_FROM_PIN) |
FLEXIO_SHIFTCFG_PWIDTH(0) | FLEXIO_SHIFTCFG_PWIDTH(0) |
FLEXIO_SHIFTCFG_SSTOP(FLEXIO_SHIFTER_STOP_BIT_LOW) | FLEXIO_SHIFTCFG_SSTOP(FLEXIO_SHIFTER_STOP_BIT_LOW) |
FLEXIO_SHIFTCFG_SSTART(FLEXIO_SHIFTER_START_BIT_DISABLED_LOAD_DATA_ON_ENABLE), FLEXIO_SHIFTCFG_SSTART(FLEXIO_SHIFTER_START_BIT_DISABLED_LOAD_DATA_ON_ENABLE),
IMXRT_FLEXIO_SHIFTCFG0_OFFSET + channel * 0x4); IMXRT_FLEXIO_SHIFTCFG0_OFFSET + channel * 0x4);
/* Transmit mode, output to FXIO pin, inverted output for bdshot */ /* Transmit mode, output to FXIO pin, inverted output for bdshot */
flexio_putreg32(FLEXIO_SHIFTCTL_TIMSEL(channel) | flexio_putreg32(flexio_base, FLEXIO_SHIFTCTL_TIMSEL(channel) |
FLEXIO_SHIFTCTL_TIMPOL(FLEXIO_SHIFTER_TIMER_POLARITY_ON_POSITIVE) | FLEXIO_SHIFTCTL_TIMPOL(FLEXIO_SHIFTER_TIMER_POLARITY_ON_POSITIVE) |
FLEXIO_SHIFTCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT) | FLEXIO_SHIFTCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT) |
FLEXIO_SHIFTCTL_PINSEL(pin) | FLEXIO_SHIFTCTL_PINSEL(pin) |
@@ -177,7 +182,7 @@ static void flexio_dshot_output(uint32_t channel, uint32_t pin, uint32_t timcmp,
IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4); IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4);
/* Start transmitting on trigger, disable on compare */ /* Start transmitting on trigger, disable on compare */
flexio_putreg32(FLEXIO_TIMCFG_TIMOUT(FLEXIO_TIMER_OUTPUT_ONE_NOT_AFFECTED_BY_RESET) | flexio_putreg32(flexio_base, FLEXIO_TIMCFG_TIMOUT(FLEXIO_TIMER_OUTPUT_ONE_NOT_AFFECTED_BY_RESET) |
FLEXIO_TIMCFG_TIMDEC(FLEXIO_TIMER_DEC_SRC_ON_FLEX_IO_CLOCK_SHIFT_TIMER_OUTPUT) | FLEXIO_TIMCFG_TIMDEC(FLEXIO_TIMER_DEC_SRC_ON_FLEX_IO_CLOCK_SHIFT_TIMER_OUTPUT) |
FLEXIO_TIMCFG_TIMRST(FLEXIO_TIMER_RESET_NEVER) | FLEXIO_TIMCFG_TIMRST(FLEXIO_TIMER_RESET_NEVER) |
FLEXIO_TIMCFG_TIMDIS(FLEXIO_TIMER_DISABLE_ON_TIMER_COMPARE) | FLEXIO_TIMCFG_TIMDIS(FLEXIO_TIMER_DISABLE_ON_TIMER_COMPARE) |
@@ -186,10 +191,10 @@ static void flexio_dshot_output(uint32_t channel, uint32_t pin, uint32_t timcmp,
FLEXIO_TIMCFG_TSTART(FLEXIO_TIMER_START_BIT_DISABLED), FLEXIO_TIMCFG_TSTART(FLEXIO_TIMER_START_BIT_DISABLED),
IMXRT_FLEXIO_TIMCFG0_OFFSET + channel * 0x4); IMXRT_FLEXIO_TIMCFG0_OFFSET + channel * 0x4);
flexio_putreg32(timcmp, IMXRT_FLEXIO_TIMCMP0_OFFSET + channel * 0x4); flexio_putreg32(flexio_base, timcmp, IMXRT_FLEXIO_TIMCMP0_OFFSET + channel * 0x4);
/* Baud mode, Trigger on shifter write */ /* Baud mode, Trigger on shifter write */
flexio_putreg32(FLEXIO_TIMCTL_TRGSEL((4 * channel) + 1) | flexio_putreg32(flexio_base, FLEXIO_TIMCTL_TRGSEL((4 * channel) + 1) |
FLEXIO_TIMCTL_TRGPOL(FLEXIO_TIMER_TRIGGER_POLARITY_ACTIVE_LOW) | FLEXIO_TIMCTL_TRGPOL(FLEXIO_TIMER_TRIGGER_POLARITY_ACTIVE_LOW) |
FLEXIO_TIMCTL_TRGSRC(FLEXIO_TIMER_TRIGGER_SOURCE_INTERNAL) | FLEXIO_TIMCTL_TRGSRC(FLEXIO_TIMER_TRIGGER_SOURCE_INTERNAL) |
FLEXIO_TIMCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) | FLEXIO_TIMCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) |
@@ -202,20 +207,22 @@ static void flexio_dshot_output(uint32_t channel, uint32_t pin, uint32_t timcmp,
static int flexio_irq_handler(int irq, void *context, void *arg) static int flexio_irq_handler(int irq, void *context, void *arg)
{ {
uint32_t flags = get_shifter_status_flags(); uint32_t flexio_base = *(uint32_t *) arg;
uint32_t flags = get_shifter_status_flags(flexio_base);
uint32_t channel; uint32_t channel;
for (channel = 0; flags && channel < DSHOT_TIMERS; channel++) { for (channel = 0; flags && channel < DSHOT_TIMERS; channel++) {
if (flags & (1 << channel)) { if ((flags & (1 << channel)) && timer_io_channels[channel].flex_io_base == flexio_base) {
disable_shifter_status_interrupts(1 << channel); disable_shifter_status_interrupts(flexio_base, 1 << channel);
if (dshot_inst[channel].state == DSHOT_START) { if (dshot_inst[channel].state == DSHOT_START) {
dshot_inst[channel].state = DSHOT_12BIT_FIFO; dshot_inst[channel].state = DSHOT_12BIT_FIFO;
flexio_putreg32(dshot_inst[channel].irq_data, IMXRT_FLEXIO_SHIFTBUF0_OFFSET + channel * 0x4); flexio_putreg32(flexio_base, dshot_inst[channel].irq_data, IMXRT_FLEXIO_SHIFTBUF0_OFFSET + channel * 0x4);
} else if (dshot_inst[channel].state == BDSHOT_RECEIVE) { } else if (dshot_inst[channel].state == BDSHOT_RECEIVE) {
dshot_inst[channel].state = BDSHOT_RECEIVE_COMPLETE; dshot_inst[channel].state = BDSHOT_RECEIVE_COMPLETE;
dshot_inst[channel].raw_response = flexio_getreg32(IMXRT_FLEXIO_SHIFTBUFBIS0_OFFSET + channel * 0x4); dshot_inst[channel].raw_response = flexio_getreg32(flexio_base, IMXRT_FLEXIO_SHIFTBUFBIS0_OFFSET + channel * 0x4);
bdshot_recv_mask |= (1 << channel); bdshot_recv_mask |= (1 << channel);
@@ -227,13 +234,13 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
} }
} }
flags = get_timer_status_flags(); flags = get_timer_status_flags(flexio_base);
for (channel = 0; flags; (channel = (channel + 1) % DSHOT_TIMERS)) { for (channel = 0; flags; (channel = (channel + 1) % DSHOT_TIMERS)) {
flags = get_timer_status_flags(); flags = get_timer_status_flags(flexio_base);
if (flags & (1 << channel)) { if ((flags & (1 << channel)) && timer_io_channels[channel].flex_io_base == flexio_base) {
clear_timer_status_flags(1 << channel); clear_timer_status_flags(flexio_base, 1 << channel);
if (dshot_inst[channel].state == DSHOT_12BIT_FIFO) { if (dshot_inst[channel].state == DSHOT_12BIT_FIFO) {
dshot_inst[channel].state = DSHOT_12BIT_TRANSFERRED; dshot_inst[channel].state = DSHOT_12BIT_TRANSFERRED;
@@ -242,21 +249,21 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
dshot_inst[channel].state = DSHOT_TRANSMIT_COMPLETE; dshot_inst[channel].state = DSHOT_TRANSMIT_COMPLETE;
} else if (dshot_inst[channel].bdshot && dshot_inst[channel].state == DSHOT_12BIT_TRANSFERRED) { } else if (dshot_inst[channel].bdshot && dshot_inst[channel].state == DSHOT_12BIT_TRANSFERRED) {
disable_shifter_status_interrupts(1 << channel); disable_shifter_status_interrupts(flexio_base, 1 << channel);
dshot_inst[channel].state = BDSHOT_RECEIVE; dshot_inst[channel].state = BDSHOT_RECEIVE;
/* Transmit done, disable timer and reconfigure to receive*/ /* Transmit done, disable timer and reconfigure to receive*/
flexio_putreg32(0x0, IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4); flexio_putreg32(flexio_base, 0x0, IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4);
/* Input data from pin, no start/stop bit*/ /* Input data from pin, no start/stop bit*/
flexio_putreg32(FLEXIO_SHIFTCFG_INSRC(FLEXIO_SHIFTER_INPUT_FROM_PIN) | flexio_putreg32(flexio_base, FLEXIO_SHIFTCFG_INSRC(FLEXIO_SHIFTER_INPUT_FROM_PIN) |
FLEXIO_SHIFTCFG_PWIDTH(0) | FLEXIO_SHIFTCFG_PWIDTH(0) |
FLEXIO_SHIFTCFG_SSTOP(FLEXIO_SHIFTER_STOP_BIT_DISABLE) | FLEXIO_SHIFTCFG_SSTOP(FLEXIO_SHIFTER_STOP_BIT_DISABLE) |
FLEXIO_SHIFTCFG_SSTART(FLEXIO_SHIFTER_START_BIT_DISABLED_LOAD_DATA_ON_SHIFT), FLEXIO_SHIFTCFG_SSTART(FLEXIO_SHIFTER_START_BIT_DISABLED_LOAD_DATA_ON_SHIFT),
IMXRT_FLEXIO_SHIFTCFG0_OFFSET + channel * 0x4); IMXRT_FLEXIO_SHIFTCFG0_OFFSET + channel * 0x4);
/* Shifter receive mdoe, on FXIO pin input */ /* Shifter receive mdoe, on FXIO pin input */
flexio_putreg32(FLEXIO_SHIFTCTL_TIMSEL(channel) | flexio_putreg32(flexio_base, FLEXIO_SHIFTCTL_TIMSEL(channel) |
FLEXIO_SHIFTCTL_TIMPOL(FLEXIO_SHIFTER_TIMER_POLARITY_ON_POSITIVE) | FLEXIO_SHIFTCTL_TIMPOL(FLEXIO_SHIFTER_TIMER_POLARITY_ON_POSITIVE) |
FLEXIO_SHIFTCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) | FLEXIO_SHIFTCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) |
FLEXIO_SHIFTCTL_PINSEL(timer_io_channels[channel].dshot.flexio_pin) | FLEXIO_SHIFTCTL_PINSEL(timer_io_channels[channel].dshot.flexio_pin) |
@@ -265,10 +272,10 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4); IMXRT_FLEXIO_SHIFTCTL0_OFFSET + channel * 0x4);
/* Make sure there no shifter flags high from transmission */ /* Make sure there no shifter flags high from transmission */
clear_shifter_status_flags(1 << channel); clear_shifter_status_flags(flexio_base, 1 << channel);
/* Enable on pin transition, resychronize through reset on rising edge */ /* Enable on pin transition, resychronize through reset on rising edge */
flexio_putreg32(FLEXIO_TIMCFG_TIMOUT(FLEXIO_TIMER_OUTPUT_ONE_AFFECTED_BY_RESET) | flexio_putreg32(flexio_base, FLEXIO_TIMCFG_TIMOUT(FLEXIO_TIMER_OUTPUT_ONE_AFFECTED_BY_RESET) |
FLEXIO_TIMCFG_TIMDEC(FLEXIO_TIMER_DEC_SRC_ON_FLEX_IO_CLOCK_SHIFT_TIMER_OUTPUT) | FLEXIO_TIMCFG_TIMDEC(FLEXIO_TIMER_DEC_SRC_ON_FLEX_IO_CLOCK_SHIFT_TIMER_OUTPUT) |
FLEXIO_TIMCFG_TIMRST(FLEXIO_TIMER_RESET_ON_TIMER_PIN_RISING_EDGE) | FLEXIO_TIMCFG_TIMRST(FLEXIO_TIMER_RESET_ON_TIMER_PIN_RISING_EDGE) |
FLEXIO_TIMCFG_TIMDIS(FLEXIO_TIMER_DISABLE_ON_TIMER_COMPARE) | FLEXIO_TIMCFG_TIMDIS(FLEXIO_TIMER_DISABLE_ON_TIMER_COMPARE) |
@@ -278,10 +285,10 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
IMXRT_FLEXIO_TIMCFG0_OFFSET + channel * 0x4); IMXRT_FLEXIO_TIMCFG0_OFFSET + channel * 0x4);
/* Enable on pin transition, resychronize through reset on rising edge */ /* Enable on pin transition, resychronize through reset on rising edge */
flexio_putreg32(bdshot_tcmp, IMXRT_FLEXIO_TIMCMP0_OFFSET + channel * 0x4); flexio_putreg32(flexio_base, bdshot_tcmp, IMXRT_FLEXIO_TIMCMP0_OFFSET + channel * 0x4);
/* Trigger on FXIO pin transition, Baud mode */ /* Trigger on FXIO pin transition, Baud mode */
flexio_putreg32(FLEXIO_TIMCTL_TRGSEL(2 * timer_io_channels[channel].dshot.flexio_pin) | flexio_putreg32(flexio_base, FLEXIO_TIMCTL_TRGSEL(2 * timer_io_channels[channel].dshot.flexio_pin) |
FLEXIO_TIMCTL_TRGPOL(FLEXIO_TIMER_TRIGGER_POLARITY_ACTIVE_HIGH) | FLEXIO_TIMCTL_TRGPOL(FLEXIO_TIMER_TRIGGER_POLARITY_ACTIVE_HIGH) |
FLEXIO_TIMCTL_TRGSRC(FLEXIO_TIMER_TRIGGER_SOURCE_INTERNAL) | FLEXIO_TIMCTL_TRGSRC(FLEXIO_TIMER_TRIGGER_SOURCE_INTERNAL) |
FLEXIO_TIMCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) | FLEXIO_TIMCTL_PINCFG(FLEXIO_PIN_CONFIG_OUTPUT_DISABLED) |
@@ -291,7 +298,7 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4); IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4);
/* Enable shifter interrupt for receiving data */ /* Enable shifter interrupt for receiving data */
enable_shifter_status_interrupts(1 << channel); enable_shifter_status_interrupts(flexio_base, 1 << channel);
} }
} }
@@ -300,23 +307,61 @@ static int flexio_irq_handler(int irq, void *context, void *arg)
return OK; return OK;
} }
int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq, bool enable_bidirectional_dshot) int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq, bool enable_bidirectional_dshot)
{ {
/* Calculate dshot timings based on dshot_pwm_freq */ /* Calculate dshot timings based on dshot_pwm_freq */
dshot_tcmp = 0x2F00 | (((BOARD_FLEXIO_PREQ / (dshot_pwm_freq * 3) / 2) - 1) & 0xFF); dshot_tcmp = 0x2F00 | (((BOARD_FLEXIO_PREQ / (dshot_pwm_freq * 3) / 2) - 1) & 0xFF);
bdshot_tcmp = 0x2900 | (((BOARD_FLEXIO_PREQ / (dshot_pwm_freq * 5 / 4) / 2) - 3) & 0xFF); bdshot_tcmp = 0x2900 | (((BOARD_FLEXIO_PREQ / (dshot_pwm_freq * 5 / 4) / 2) - 3) & 0xFF);
bool flexio1_channels = false;
bool flexio2_channels = false;
for (unsigned i = 0; (channel_mask != 0) && (i < DSHOT_TIMERS); i++) {
if (channel_mask & (1 << i)) {
if (timer_io_channels[i].flex_io_base == FLEXIO1_BASE) {
PX4_INFO("Flexio1 channel found");
flexio1_channels = true;
} else if (timer_io_channels[i].flex_io_base == FLEXIO2_BASE) {
PX4_INFO("Flexio2 channel found");
flexio2_channels = true;
} else {PX4_ERR("Invalid flexio base defined");}
}
}
if (flexio1_channels) { // FlexIO peripheral 1
/* Clock FlexIO peripheral */ /* Clock FlexIO peripheral */
imxrt_clockall_flexio1(); imxrt_clockall_flexio1();
/* Reset FlexIO 1 peripheral */
/* Reset FlexIO peripheral */ flexio_modifyreg32(FLEXIO1_BASE, IMXRT_FLEXIO_CTRL_OFFSET, 0,
flexio_modifyreg32(IMXRT_FLEXIO_CTRL_OFFSET, 0,
FLEXIO_CTRL_SWRST_MASK); FLEXIO_CTRL_SWRST_MASK);
flexio_putreg32(0, IMXRT_FLEXIO_CTRL_OFFSET); flexio_putreg32(FLEXIO1_BASE, 0, IMXRT_FLEXIO_CTRL_OFFSET);
/* Initialize FlexIO peripheral */ /* Initialize FlexIO 1 peripheral */
flexio_modifyreg32(IMXRT_FLEXIO_CTRL_OFFSET, flexio_modifyreg32(FLEXIO1_BASE, IMXRT_FLEXIO_CTRL_OFFSET,
(FLEXIO_CTRL_DOZEN_MASK |
FLEXIO_CTRL_DBGE_MASK |
FLEXIO_CTRL_FASTACC_MASK |
FLEXIO_CTRL_FLEXEN_MASK),
(FLEXIO_CTRL_DBGE(1) |
FLEXIO_CTRL_FASTACC(1) |
FLEXIO_CTRL_FLEXEN(0)));
/* FlexIO IRQ handling */
up_enable_irq(IMXRT_IRQ_FLEXIO1);
irq_attach(IMXRT_IRQ_FLEXIO1, flexio_irq_handler, &flexio1_base_addr);
}
if (flexio2_channels) { // FlexIO peripheral 2
/* Clock FlexIO peripheral */
imxrt_clockall_flexio2();
/* Reset FlexIO 2 peripheral */
flexio_modifyreg32(FLEXIO2_BASE, IMXRT_FLEXIO_CTRL_OFFSET, 0,
FLEXIO_CTRL_SWRST_MASK);
flexio_putreg32(FLEXIO2_BASE, 0, IMXRT_FLEXIO_CTRL_OFFSET);
/* Initialize FlexIO 2 peripheral */
flexio_modifyreg32(FLEXIO2_BASE, IMXRT_FLEXIO_CTRL_OFFSET,
(FLEXIO_CTRL_DOZEN_MASK | (FLEXIO_CTRL_DOZEN_MASK |
FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_DBGE_MASK |
FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FASTACC_MASK |
@@ -325,9 +370,9 @@ int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq, bool enable_bi
FLEXIO_CTRL_FASTACC(1) | FLEXIO_CTRL_FASTACC(1) |
FLEXIO_CTRL_FLEXEN(0))); FLEXIO_CTRL_FLEXEN(0)));
/* FlexIO IRQ handling */ up_enable_irq(IMXRT_IRQ_FLEXIO2);
up_enable_irq(IMXRT_IRQ_FLEXIO1); irq_attach(IMXRT_IRQ_FLEXIO2, flexio_irq_handler, &flexio2_base_addr);
irq_attach(IMXRT_IRQ_FLEXIO1, flexio_irq_handler, 0); }
dshot_mask = 0x0; dshot_mask = 0x0;
@@ -342,7 +387,9 @@ int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq, bool enable_bi
dshot_inst[channel].bdshot = enable_bidirectional_dshot; dshot_inst[channel].bdshot = enable_bidirectional_dshot;
flexio_dshot_output(channel, timer_io_channels[channel].dshot.flexio_pin, dshot_tcmp, dshot_inst[channel].bdshot); flexio_dshot_output(timer_io_channels[channel].flex_io_base, channel, timer_io_channels[channel].dshot.flexio_pin,
dshot_tcmp,
dshot_inst[channel].bdshot);
dshot_inst[channel].init = true; dshot_inst[channel].init = true;
@@ -351,8 +398,16 @@ int up_dshot_init(uint32_t channel_mask, unsigned dshot_pwm_freq, bool enable_bi
} }
} }
flexio_modifyreg32(IMXRT_FLEXIO_CTRL_OFFSET, 0, if (flexio1_channels) {
flexio_modifyreg32(FLEXIO1_BASE, IMXRT_FLEXIO_CTRL_OFFSET, 0,
FLEXIO_CTRL_FLEXEN_MASK); FLEXIO_CTRL_FLEXEN_MASK);
}
if (flexio2_channels) {
flexio_modifyreg32(FLEXIO2_BASE, IMXRT_FLEXIO_CTRL_OFFSET, 0,
FLEXIO_CTRL_FLEXEN_MASK);
}
return channel_mask; return channel_mask;
} }
@@ -417,7 +472,6 @@ void up_bdshot_erpm(void)
} }
} }
int up_bdshot_num_erpm_ready(void) int up_bdshot_num_erpm_ready(void)
{ {
int num_ready = 0; int num_ready = 0;
@@ -470,12 +524,36 @@ void up_bdshot_status(void)
void up_dshot_trigger(void) void up_dshot_trigger(void)
{ {
bool flexio1_channels = false;
bool flexio2_channels = false;
for (unsigned i = 0; (i < DSHOT_TIMERS); i++) {
if (dshot_inst[i].init && dshot_inst[i].data_seg1 != 0) {
if (timer_io_channels[i].flex_io_base == FLEXIO1_BASE) {
flexio1_channels = true;
} else if (timer_io_channels[i].flex_io_base == FLEXIO2_BASE) {
flexio2_channels = true;
} else {PX4_ERR("Invalid flexio base defined");}
}
}
// Calc data now since we're not event driven // Calc data now since we're not event driven
if (bdshot_recv_mask != 0x0) { if (bdshot_recv_mask != 0x0) {
up_bdshot_erpm(); up_bdshot_erpm();
} }
clear_timer_status_flags(0xFF); if (flexio1_channels) {
clear_timer_status_flags(FLEXIO1_BASE, 0xFF);
}
if (flexio2_channels) {
clear_timer_status_flags(FLEXIO2_BASE, 0xFF);
}
for (uint8_t channel = 0; (channel < DSHOT_TIMERS); channel++) { for (uint8_t channel = 0; (channel < DSHOT_TIMERS); channel++) {
if (dshot_inst[channel].bdshot && (bdshot_recv_mask & (1 << channel)) == 0) { if (dshot_inst[channel].bdshot && (bdshot_recv_mask & (1 << channel)) == 0) {
@@ -483,15 +561,26 @@ void up_dshot_trigger(void)
} }
if (dshot_inst[channel].init && dshot_inst[channel].data_seg1 != 0) { if (dshot_inst[channel].init && dshot_inst[channel].data_seg1 != 0) {
flexio_putreg32(dshot_inst[channel].data_seg1, IMXRT_FLEXIO_SHIFTBUF0_OFFSET + channel * 0x4); flexio_putreg32(timer_io_channels[channel].flex_io_base, dshot_inst[channel].data_seg1,
IMXRT_FLEXIO_SHIFTBUF0_OFFSET + channel * 0x4);
} }
} }
bdshot_recv_mask = 0x0; bdshot_recv_mask = 0x0;
clear_timer_status_flags(0xFF); if (flexio1_channels) {
enable_shifter_status_interrupts(0xFF); clear_timer_status_flags(FLEXIO1_BASE, 0xFF);
enable_timer_status_interrupts(0xFF); enable_shifter_status_interrupts(FLEXIO1_BASE, 0xFF);
enable_timer_status_interrupts(FLEXIO1_BASE, 0xFF);
}
if (flexio2_channels) {
clear_timer_status_flags(FLEXIO2_BASE, 0xFF);
enable_shifter_status_interrupts(FLEXIO2_BASE, 0xFF);
enable_timer_status_interrupts(FLEXIO2_BASE, 0xFF);
}
} }
/* Expand packet from 16 bits 48 to get T0H and T1H timing */ /* Expand packet from 16 bits 48 to get T0H and T1H timing */
@@ -522,6 +611,7 @@ uint64_t dshot_expand_data(uint16_t packet)
**/ **/
void dshot_motor_data_set(unsigned channel, uint16_t throttle, bool telemetry) void dshot_motor_data_set(unsigned channel, uint16_t throttle, bool telemetry)
{ {
if (channel < DSHOT_TIMERS && dshot_inst[channel].init) { if (channel < DSHOT_TIMERS && dshot_inst[channel].init) {
uint16_t csum_data; uint16_t csum_data;
uint16_t packet = 0; uint16_t packet = 0;
@@ -554,13 +644,14 @@ void dshot_motor_data_set(unsigned channel, uint16_t throttle, bool telemetry)
dshot_inst[channel].state = DSHOT_START; dshot_inst[channel].state = DSHOT_START;
if (dshot_inst[channel].bdshot) { if (dshot_inst[channel].bdshot) {
flexio_putreg32(timer_io_channels[channel].flex_io_base, 0x0, IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4);
disable_shifter_status_interrupts(timer_io_channels[channel].flex_io_base, 1 << channel);
flexio_putreg32(0x0, IMXRT_FLEXIO_TIMCTL0_OFFSET + channel * 0x4); flexio_dshot_output(timer_io_channels[channel].flex_io_base, channel, timer_io_channels[channel].dshot.flexio_pin,
disable_shifter_status_interrupts(1 << channel); dshot_tcmp,
dshot_inst[channel].bdshot);
flexio_dshot_output(channel, timer_io_channels[channel].dshot.flexio_pin, dshot_tcmp, dshot_inst[channel].bdshot); clear_timer_status_flags(timer_io_channels[channel].flex_io_base, 0xFF);
clear_timer_status_flags(0xFF);
} }
} }
} }
@@ -107,11 +107,12 @@ typedef struct timer_io_channels_t {
uint32_t gpio_out; /* The timer valn_offset GPIO for PWM (this is the IOMUX Pad, e.g. PWM_IOMUX | GPIO_FLEXPWM2_PWMA00_2) */ uint32_t gpio_out; /* The timer valn_offset GPIO for PWM (this is the IOMUX Pad, e.g. PWM_IOMUX | GPIO_FLEXPWM2_PWMA00_2) */
uint32_t gpio_in; /* The timer valn_offset GPIO for Capture */ uint32_t gpio_in; /* The timer valn_offset GPIO for Capture */
uint32_t gpio_portpin; /* The GPIO Port + Pin (e.g. GPIO_PORT2 | GPIO_PIN6) */ uint32_t gpio_portpin; /* The GPIO Port + Pin (e.g. GPIO_PORT2 | GPIO_PIN6) */
uint32_t flex_io_base;
uint8_t timer_index; /* 0 based index in the io_timers_t table */ uint8_t timer_index; /* 0 based index in the io_timers_t table */
uint8_t val_offset; /* IMXRT_FLEXPWM_SM0VAL3_OFFSET or IMXRT_FLEXPWM_SM0VAL5_OFFSET */ uint8_t val_offset; /* IMXRT_FLEXPWM_SM0VAL3_OFFSET or IMXRT_FLEXPWM_SM0VAL5_OFFSET */
uint8_t sub_module; /* 0 based sub module offset */ uint8_t sub_module; /* 0 based sub module offset */
uint8_t sub_module_bits; /* LDOK and CLDOK bits */ uint8_t sub_module_bits; /* LDOK and CLDOK bits */
uint8_t timer_channel; /* Unused */ uint8_t timer_channel;/* Unused */
dshot_conf_t dshot; dshot_conf_t dshot;
} timer_io_channels_t; } timer_io_channels_t;
@@ -600,14 +600,13 @@ static inline constexpr timer_io_channels_t initIOTimerChannel(const io_timers_t
return ret; return ret;
} }
static inline constexpr timer_io_channels_t initIOTimerChannelDshot(const io_timers_t io_timers_conf[MAX_IO_TIMERS], static inline constexpr timer_io_channels_t initIOTimerChannelDshot(const io_timers_t io_timers_conf[MAX_IO_TIMERS],
PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad, uint32_t dshot_pinmux, uint32_t flexio_pin) PWM::FlexPWMConfig pwm_config, IOMUX::Pad pad, uint32_t dshot_pinmux, uint32_t flexio, uint32_t flexio_pin)
{ {
timer_io_channels_t ret = initIOTimerChannel(io_timers_conf, pwm_config, pad); timer_io_channels_t ret = initIOTimerChannel(io_timers_conf, pwm_config, pad);
ret.dshot.pinmux = dshot_pinmux; ret.dshot.pinmux = dshot_pinmux;
ret.dshot.flexio_pin = flexio_pin; ret.dshot.flexio_pin = flexio_pin;
ret.flex_io_base = flexio;
return ret; return ret;
} }