arch/imx9: Add bidirectional dshot driver using i.MX9 FlexIO

Create a bidirectional dshot lower-half driver, using the flexio block.

This driver enables use of DShot protocol for Electronic Speed Controllers
(ESCs) typically used in drone motor control.

Eight channels of DShot per flexio block are supported in:

- Normal mode in all DShot speeds, with telemetry request (uart response
  needs to be handled outside of this driver)
- Bidirectional mode in all DShot speeds, with telemetry request & response
- Configurable to use either independent TX timers for each channel, or to
  use a common TX timer for all channels to synchronize the output
- For bidirectional RX, each channel always uses an own timer.

In normal mode, the driver operates without any interrupts.

In bidirectional mode, the driver reconfigures the FlexIO timers (as needed)
and shifters from TX to RX in the interrupt handler, and reads out the
raw response packet.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
Jukka Laitinen
2026-04-30 12:24:47 +08:00
committed by Xiang Xiao
parent b810cbe4d3
commit 101ff2c2bb
6 changed files with 1355 additions and 0 deletions
+4
View File
@@ -45,6 +45,10 @@ if(CONFIG_IMX9_FLEXIO_PWM)
list(APPEND SRCS imx9_flexio_pwm.c)
endif()
if(CONFIG_IMX9_FLEXIO_DSHOT)
list(APPEND SRCS imx9_flexio_dshot.c)
endif()
if(CONFIG_IMX9_TPM_PWM)
list(APPEND SRCS imx9_tpm_pwm.c)
endif()
+87
View File
@@ -356,6 +356,93 @@ config IMX9_FLEXIO2_PWM_CHANNEL_PINS
hex "FlexIO outputs used for FLEXIO2 timers"
default 0x0000000000000000
config IMX9_FLEXIO_DSHOT
bool
default n
select DSHOT
choice
prompt "DShot timestamp source"
default IMX9_FLEXIO_DSHOT_TS_SYSTIME
depends on IMX9_FLEXIO_DSHOT
config IMX9_FLEXIO_DSHOT_TS_SYSTIME
bool "Use clock_systime"
---help---
Use clock_systime for dshot response timestamping
config IMX9_FLEXIO_DSHOT_TS_BOARDTIME
bool "Use board provided timestamping function"
---help---
Board-specific sources provide "board_systime_timespec"
function, which is called to get timestamp. This can be used
e.g. if some special time base is required for the timestamping.
config IMX9_FLEXIO_DSHOT_TS_NONE
bool "Timestamping disabled"
---help---
No timestamping, timestamps stay at 0
endchoice # DShot timestamp source
config IMX9_FLEXIO1_DSHOT
bool "Enable FLEXIO1 based DShot"
default n
select IMX9_FLEXIO_DSHOT
config IMX9_FLEXIO1_DSHOT_NCHANNELS
int "Number of channels for FLEXIO1 DShot"
depends on IMX9_FLEXIO1_DSHOT
default 4
range 1 8
config IMX9_FLEXIO1_DSHOT_TX_TIMER
int "FlexIO timer to use for TX on all channels"
depends on IMX9_FLEXIO1_DSHOT
default 6
range -1 7
---help---
If set to -1, each DSHOT channel uses it's own individual timer.
When set to timer 0-7, all the DSHOT TX channels use this common
timer to clock out the TX messages. This reduces interrupt load
and synchronizes all the channels to send out messages simultaneously.
config IMX9_FLEXIO1_DSHOT_CHANNEL_PINS
hex "FlexIO outputs used for FLEXIO1 DShot channels"
depends on IMX9_FLEXIO1_DSHOT
default 0x0000000007060504
---help---
Packed pin-index array: one byte per channel, byte 0 is channel 0.
config IMX9_FLEXIO2_DSHOT
bool "Enable FLEXIO2 based DShot"
default n
select IMX9_FLEXIO_DSHOT
config IMX9_FLEXIO2_DSHOT_NCHANNELS
int "Number of channels for FLEXIO2 DShot"
depends on IMX9_FLEXIO2_DSHOT
default 8
range 1 8
config IMX9_FLEXIO2_DSHOT_CHANNEL_PINS
hex "FlexIO outputs used for FLEXIO2 DShot channels"
depends on IMX9_FLEXIO2_DSHOT
default 0x0000000007060504
---help---
Packed pin-index array: one byte per channel, byte 0 is channel 0.
config IMX9_FLEXIO2_DSHOT_TX_TIMER
int "FlexIO timer to use for TX on all channels"
depends on IMX9_FLEXIO2_DSHOT
default 6
range -1 7
---help---
If set to -1, each DSHOT channel uses it's own individual timer.
When set to timer 0-7, all the DSHOT TX channels use this common
timer to clock out the TX messages. This reduces interrupt load
and synchronizes all the channels to send out messages simultaneously.
config IMX9_TPM_PWM
bool
select PWM_MULTICHAN
+4
View File
@@ -56,6 +56,10 @@ ifeq ($(CONFIG_IMX9_FLEXIO_PWM),y)
CHIP_CSRCS += imx9_flexio_pwm.c
endif
ifeq ($(CONFIG_IMX9_FLEXIO_DSHOT),y)
CHIP_CSRCS += imx9_flexio_dshot.c
endif
ifeq ($(CONFIG_IMX9_TPM_PWM),y)
CHIP_CSRCS += imx9_tpm_pwm.c
endif
@@ -66,6 +66,7 @@
#define IMX9_FLEXIO_SHIFTCTL5_OFFSET 0x0094
#define IMX9_FLEXIO_SHIFTCTL6_OFFSET 0x0098
#define IMX9_FLEXIO_SHIFTCTL7_OFFSET 0x009c
#define IMX9_FLEXIO_SHIFTCTL_OFFSET(x) (IMX9_FLEXIO_SHIFTCTL0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_SHIFTCFG0_OFFSET 0x0100 /* Shifter Configuration N Register, array offset: 0x100, array step: 0x4 */
#define IMX9_FLEXIO_SHIFTCFG1_OFFSET 0x0104
#define IMX9_FLEXIO_SHIFTCFG2_OFFSET 0x0108
@@ -74,6 +75,7 @@
#define IMX9_FLEXIO_SHIFTCFG5_OFFSET 0x0114
#define IMX9_FLEXIO_SHIFTCFG6_OFFSET 0x0118
#define IMX9_FLEXIO_SHIFTCFG7_OFFSET 0x011c
#define IMX9_FLEXIO_SHIFTCFG_OFFSET(x) (IMX9_FLEXIO_SHIFTCFG0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_SHIFTBUF0_OFFSET 0x0200 /* Shifter Buffer N Register, array offset: 0x200, array step: 0x4 */
#define IMX9_FLEXIO_SHIFTBUF1_OFFSET 0x0204
#define IMX9_FLEXIO_SHIFTBUF2_OFFSET 0x0208
@@ -82,6 +84,7 @@
#define IMX9_FLEXIO_SHIFTBUF5_OFFSET 0x0214
#define IMX9_FLEXIO_SHIFTBUF6_OFFSET 0x0218
#define IMX9_FLEXIO_SHIFTBUF7_OFFSET 0x021c
#define IMX9_FLEXIO_SHIFTBUF_OFFSET(x) (IMX9_FLEXIO_SHIFTBUF0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_SHIFTBUFBIS0_OFFSET 0x0280 /* Shifter Buffer N Bit Swapped Register, array offset: 0x280, array step: 0x4 */
#define IMX9_FLEXIO_SHIFTBUFBIS1_OFFSET 0x0284
#define IMX9_FLEXIO_SHIFTBUFBIS2_OFFSET 0x0288
@@ -90,6 +93,7 @@
#define IMX9_FLEXIO_SHIFTBUFBIS5_OFFSET 0x0294
#define IMX9_FLEXIO_SHIFTBUFBIS6_OFFSET 0x0298
#define IMX9_FLEXIO_SHIFTBUFBIS7_OFFSET 0x029c
#define IMX9_FLEXIO_SHIFTBUFBIS_OFFSET(x) (IMX9_FLEXIO_SHIFTBUFBIS0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_SHIFTBUFBYS0_OFFSET 0x0300 /* Shifter Buffer N Byte Swapped Register, array offset: 0x300, array step: 0x4 */
#define IMX9_FLEXIO_SHIFTBUFBYS1_OFFSET 0x0304
#define IMX9_FLEXIO_SHIFTBUFBYS2_OFFSET 0x0308
@@ -98,6 +102,7 @@
#define IMX9_FLEXIO_SHIFTBUFBYS5_OFFSET 0x0314
#define IMX9_FLEXIO_SHIFTBUFBYS6_OFFSET 0x0318
#define IMX9_FLEXIO_SHIFTBUFBYS7_OFFSET 0x031c
#define IMX9_FLEXIO_SHIFTBUFBYS_OFFSET(x) (IMX9_FLEXIO_SHIFTBUFBYS0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_SHIFTBUFBBS0_OFFSET 0x0380 /* Shifter Buffer N Bit Byte Swapped Register, array offset: 0x380, array step: 0x4 */
#define IMX9_FLEXIO_SHIFTBUFBBS1_OFFSET 0x0384
#define IMX9_FLEXIO_SHIFTBUFBBS2_OFFSET 0x0388
@@ -106,6 +111,7 @@
#define IMX9_FLEXIO_SHIFTBUFBBS5_OFFSET 0x0394
#define IMX9_FLEXIO_SHIFTBUFBBS6_OFFSET 0x0398
#define IMX9_FLEXIO_SHIFTBUFBBS7_OFFSET 0x039c
#define IMX9_FLEXIO_SHIFTBUFBBS_OFFSET(x) (IMX9_FLEXIO_SHIFTBUFBBS0_OFFSET + (x) * 4)
#define IMX9_FLEXIO_TIMCTL0_OFFSET 0x0400 /* Timer Control N Register, array offset: 0x400, array step: 0x4 */
#define IMX9_FLEXIO_TIMCTL1_OFFSET 0x0404
#define IMX9_FLEXIO_TIMCTL2_OFFSET 0x0408
@@ -603,6 +609,16 @@
#define FLEXIO_TIMCTL_TIMOD(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_TIMOD_SHIFT) & FLEXIO_TIMCTL_TIMOD_MASK)
#define FLEXIO_TIMCTL_ONETIM_MASK (0x20u)
#define FLEXIO_TIMCTL_ONETIM_SHIFT (5u)
/* ONETIM - Timer One Time Operation
* 0b0..Event is generated as normal
* 0b1..Event is blocked unless timer status flag is clear
*/
#define FLEXIO_TIMCTL_ONETIM(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_ONETIM_SHIFT) & FLEXIO_TIMCTL_ONETIM_MASK)
#define FLEXIO_TIMCTL_PINPOL_MASK (0x80u)
#define FLEXIO_TIMCTL_PINPOL_SHIFT (7u)
File diff suppressed because it is too large Load Diff
+107
View File
@@ -0,0 +1,107 @@
/****************************************************************************
* arch/arm64/src/imx9/imx9_flexio_dshot.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_DSHOT_H
#define __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_DSHOT_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdbool.h>
#include <stdint.h>
#include <nuttx/timers/dshot.h>
#ifdef CONFIG_IMX9_FLEXIO_DSHOT
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* There are 8 shifters and timers per one FlexIO IP */
#if CONFIG_DSHOT_NCHANNELS > 8
# error Driver supports max 8 channels per flexio (CONFIG_DSHOT_NCHANNELS)
#endif
#define DSHOT_MAX_CHANNELS CONFIG_DSHOT_NCHANNELS
/****************************************************************************
* Public Types
****************************************************************************/
/* Which FlexIO instance backs this DShot device */
typedef enum
{
DSHOT_FLEXIO1 = 0,
DSHOT_FLEXIO2 = 1,
} flexio_dshot_id_t;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: imx9_flexio_dshot_init
*
* Description:
* Initialise a FlexIO-backed DShot lower-half instance.
*
* Channel count and pin mapping are taken from Kconfig
* (CONFIG_IMX9_FLEXIOx_DSHOT_NCHANNELS,
* CONFIG_IMX9_FLEXIOx_DSHOT_CHANNEL_PINS). These use the same FlexIO
* output numbers as the FlexIO PWM driver. The corresponding board
* IOMUXC macros must be provided, and the driver applies the required
* pinmux configuration during setup.
*
* Input Parameters:
* id - Which FlexIO instance to use (DSHOT_FLEXIO1 / DSHOT_FLEXIO2)
*
* Returned Value:
* A valid pointer to struct dshot_lowerhalf_s on success; NULL on failure.
*
****************************************************************************/
struct dshot_lowerhalf_s *imx9_flexio_dshot_init(flexio_dshot_id_t id);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_IMX9_FLEXIO_DSHOT */
#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_DSHOT_H */