Skip to content

Conversation

@functionpointer
Copy link
Contributor

@functionpointer functionpointer commented Nov 22, 2025

User description

Adds support for FlyDragon Pro flight controllers.

There are two variants, one with ICM42688P IMU and one with MPU6000.
Both variants use the same target.

I have tested:

  • ICM42688P variant: gyro works and has correct orientation
  • MPU6000 variant: gyro works and has correct orientation
  • barometer works
  • blackbox works
  • vbat adc works
  • vbat adc calibrated using multimeter
  • internal ELRS receiver works
  • UART1 works. tested using internal ELRS receiver
  • UART2 works. tested using external CRSF receiver
  • UART3 works. tested using external CRSF receiver; no telemetry as only RX pin is exposed
  • UART4 works. tested using external SBUS and SBUS2 receiver
  • UART5 works. tested using external CRSF receiver
  • onboard RGB led works and is configured as indicator led by default
  • all 9 servo/motor outputs work. tested using a servo.
  • USB-C port 5.1k pulldowns exist

PR Type

Enhancement


Description

  • Adds complete support for FlyDragon Pro flight controller

  • Supports two IMU variants: ICM42688P and MPU6000

  • Configures 9 servo/motor outputs with flexible pin mapping

  • Enables internal ExpressLRS receiver, multiple UARTs, barometer, blackbox


Diagram Walkthrough

flowchart LR
  A["FlyDragon Pro<br/>STM32F722RET6"] --> B["IMU Variants<br/>ICM42688P/MPU6000"]
  A --> C["Peripherals<br/>Barometer, Blackbox"]
  A --> D["Connectivity<br/>5x UART, I2C, SPI"]
  A --> E["Outputs<br/>9 Servo/Motor Pins"]
  A --> F["RGB LED<br/>WS2812B Indicator"]
Loading

File Walkthrough

Relevant files
Configuration changes
target.h
Complete hardware configuration and pin definitions           

src/main/target/FLYDRAGONPRO/target.h

  • Defines STM32F722RET6 MCU configuration with board identifier "RTFL"
  • Configures dual IMU support: ICM42605 (ICM42688P) with CW0_DEG
    alignment and MPU6000 with CW90_DEG alignment
  • Sets up SPI1 for IMU, SPI2 for W25N01G blackbox flash storage
  • Defines 5 UARTs with specific pin mappings for ELRS receiver, GPS, and
    external receivers
  • Configures I2C buses for SPL06 barometer and other sensors
  • Sets up ADC for battery voltage monitoring (VBAT_SCALE_DEFAULT 1898)
  • Enables WS2812B LED strip on PB8 and buzzer on PA8
  • Defines 9 PWM output ports with DShot and ESC sensor support
+157/-0 
target.c
Timer hardware and output pin mappings                                     

src/main/target/FLYDRAGONPRO/target.c

  • Defines timer hardware mappings for 9 servo/motor outputs
  • Maps TIM8, TIM3, TIM2, TIM5, TIM11, TIM4 to output pins (PC9, PC8,
    PC7, PC6, PA0, PA1, PA3, PA2, PB9)
  • Configures TIM4 CH3 on PB8 for WS2812B LED control
  • Includes detailed comments on pin labeling and UART conflicts
+45/-0   
config.c
LED and indicator configuration                                                   

src/main/target/FLYDRAGONPRO/config.c

  • Configures WS2812B RGB LED as indicator LED with blue color for
    warning overlay
  • Sets up PINIO box for USER1 permanent ID
  • Initializes LED strip configuration for single LED at index 0
+46/-0   
CMakeLists.txt
Build system configuration                                                             

src/main/target/FLYDRAGONPRO/CMakeLists.txt

  • Specifies STM32F722XE target for CMake build system
+1/-0     
Documentation
README.md
Hardware documentation and pin mapping reference                 

src/main/target/FLYDRAGONPRO/README.md

  • Documents FlyDragon Pro hardware specifications and two IMU variants
  • Provides comprehensive pin configuration table showing servo/motor
    output behavior with different UART configurations
  • Includes hardware layout table mapping case markings to STM32 pins and
    their functions
  • Notes UART4 baud rate limitation (115200 max) due to filtering circuit
  • Explains internal ELRS receiver control via PINIO and expansion port
    capabilities
+82/-0   

@qodo-merge-pro
Copy link
Contributor

qodo-merge-pro bot commented Nov 22, 2025

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No auditing: The new target configuration adds hardware setups (LED, PINIO, timers, UARTs) but does not
add any audit logging for critical actions, which may be acceptable for low-level firmware
targets but cannot be confirmed from this diff alone.

Referred Code
void targetConfiguration(void)
{
  pinioBoxConfigMutable()->permanentId[0] = BOX_PERMANENT_ID_USER1;

  // configure the built-in WS2812B led as makeshift indicator led
  ledStripConfig_t *config = ledStripConfigMutable();
  ledConfig_t *lc = config->ledConfigs;
  DEFINE_LED(lc, 0, 0, COLOR_BLUE, 0, LED_FUNCTION_COLOR, LED_FLAG_OVERLAY(LED_OVERLAY_WARNING), 0);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
No error handling: Hardware mapping definitions are added without any visible validation or error handling;
for target configuration files this may be handled elsewhere, but the diff shows no checks
for conflicts or misconfiguration.

Referred Code
timerHardware_t timerHardware[] = {
    DEF_TIM(TIM8, CH4, PC9,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "TAIL"

    DEF_TIM(TIM3, CH3, PC8,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH3"
    DEF_TIM(TIM3, CH2, PC7,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH2"
    DEF_TIM(TIM3, CH1, PC6,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH1"

    DEF_TIM(TIM2, CH1, PA0,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "ESC", clashes with UART4 TX
    DEF_TIM(TIM2, CH2, PA1,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "RPM", clashes with UART4 RX

    DEF_TIM(TIM5, CH4, PA3,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "RX2", clashes with UART2 RX
    DEF_TIM(TIM5, CH3, PA2,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "TX2", clashes with UART2 TX

    DEF_TIM(TIM11, CH1, PB9,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "AUX"

    DEF_TIM(TIM4, CH3, PB8, TIM_USE_LED, 0, 0),           // WS2812B
};

const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-merge-pro
Copy link
Contributor

qodo-merge-pro bot commented Nov 22, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Implement dynamic servo output remapping

The current implementation of servo outputs is static, which contradicts the
dynamic remapping behavior described in the README when UARTs are enabled. The
suggestion is to implement logic to dynamically configure the servo outputs at
boot based on the active UART configuration to match the documentation.

Examples:

src/main/target/FLYDRAGONPRO/README.md [30-44]
The ESC, RPM, RX2 and TX2 pins are Servo/Motor outputs by default. However, when UART4 or UART2 are assigned a function in the ports tab, the pins will become a UART instead. See the table below.

**The ESC and RPM pins feature a filtering circuit that limits UART4 to 115200 baud. This means CRSF won't work on UART4, while slower protocols like SBUS and SBUS2 will.**

| Marking on the case | Both UART2 and UART4 unused | UART2 in use            | UART4 in use            | Both UART2 and UART4 in use |
|---------------------|-----------------------------|-------------------------|-------------------------|-----------------------------|
| TAIL                | Output S1                   | Output S1               | Output S1               | Output S1                   |
| CH3                 | Output S2                   | Output S2               | Output S2               | Output S2                   |
| CH2                 | Output S3                   | Output S3               | Output S3               | Output S3                   |
| CH1                 | Output S4                   | Output S4               | Output S4               | Output S4                   |

 ... (clipped 5 lines)
src/main/target/FLYDRAGONPRO/target.c [27-45]
timerHardware_t timerHardware[] = {
    DEF_TIM(TIM8, CH4, PC9,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "TAIL"

    DEF_TIM(TIM3, CH3, PC8,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH3"
    DEF_TIM(TIM3, CH2, PC7,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH2"
    DEF_TIM(TIM3, CH1, PC6,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "CH1"

    DEF_TIM(TIM2, CH1, PA0,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "ESC", clashes with UART4 TX
    DEF_TIM(TIM2, CH2, PA1,  TIM_USE_OUTPUT_AUTO, 0, 0),   // labelled "RPM", clashes with UART4 RX


 ... (clipped 9 lines)

Solution Walkthrough:

Before:

// src/main/target/FLYDRAGONPRO/target.c

// Static definition of all 9 servo outputs.
// If UARTs are enabled, corresponding outputs are simply lost.
// No remapping occurs.
timerHardware_t timerHardware[] = {
    DEF_TIM(TIM8, CH4, PC9,  ...),   // S1
    DEF_TIM(TIM3, CH3, PC8,  ...),   // S2
    DEF_TIM(TIM3, CH2, PC7,  ...),   // S3
    DEF_TIM(TIM3, CH1, PC6,  ...),   // S4
    DEF_TIM(TIM2, CH1, PA0,  ...),   // S5 (clashes with UART4 TX)
    DEF_TIM(TIM2, CH2, PA1,  ...),   // S6 (clashes with UART4 RX)
    DEF_TIM(TIM5, CH4, PA3,  ...),   // S7 (clashes with UART2 RX)
    DEF_TIM(TIM5, CH3, PA2,  ...),   // S8 (clashes with UART2 TX)
    DEF_TIM(TIM11, CH1, PB9, ...),   // S9
};
const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);

After:

// src/main/target/FLYDRAGONPRO/target.c

// Dynamically build the timerHardware array based on UART configuration.
void targetBuildTimerHardware(void)
{
    bool uart2_in_use = isSerialPortInUse(SERIAL_PORT_USART2);
    bool uart4_in_use = isSerialPortInUse(SERIAL_PORT_UART4);

    addTimer(TIM8, CH4, PC9, ...); // S1
    addTimer(TIM3, CH3, PC8, ...); // S2
    addTimer(TIM3, CH2, PC7, ...); // S3
    addTimer(TIM3, CH1, PC6, ...); // S4

    if (!uart4_in_use) {
        addTimer(TIM2, CH1, PA0, ...); // S5
        addTimer(TIM2, CH2, PA1, ...); // S6
    }
    if (!uart2_in_use) {
        addTimer(TIM5, CH4, PA3, ...); // S7 (or S5 if UART4 used)
        addTimer(TIM5, CH3, PA2, ...); // S8 (or S6 if UART4 used)
    }
    addTimer(TIM11, CH1, PB9, ...); // S9 (or S7/S5 depending on UARTs)
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical discrepancy between the documented servo remapping behavior and the static implementation, which would lead to user confusion and incorrect output configuration.

High
Possible issue
Use correct IMU definition macro

Replace the USE_IMU_ICM42605 macro and its related definitions with the correct
ones for the ICM42688P IMU, as indicated by the code comment and README.md. This
ensures the correct driver is used for the sensor.

src/main/target/FLYDRAGONPRO/target.h [42-46]

-#define USE_IMU_ICM42605 // is actually ICM42688P
-#define IMU_ICM42605_ALIGN     CW0_DEG
-#define ICM42605_CS_PIN        PB0
-#define ICM42605_EXTI_PIN      PB3
-#define ICM42605_SPI_BUS       BUS_SPI1
+#define USE_IMU_ICM42688P
+#define IMU_ICM42688P_ALIGN     CW0_DEG
+#define ICM42688P_CS_PIN        PB0
+#define ICM42688P_EXTI_PIN      PB3
+#define ICM42688P_SPI_BUS       BUS_SPI1
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical mismatch between the IMU hardware (ICM42688P) specified in the README.md and the driver macro (USE_IMU_ICM42605) used in the code. Using the correct driver is essential for the IMU's proper function, which is fundamental to flight stability.

High
Learned
best practice
Use consistent hex I2C address

Use a clear hex address constant to match datasheets/docs and avoid ambiguity;
update the README to reference the same address/value.

src/main/target/FLYDRAGONPRO/target.h [55-69]

 // *************** I2C /Baro/Mag *********************
 #define USE_I2C
 #define USE_I2C_DEVICE_1
 #define I2C1_SCL                PB6
 #define I2C1_SDA                PB7
-#define DEFAULT_I2C BUS_I2C1
+#define DEFAULT_I2C             BUS_I2C1
 
 #define USE_I2C_DEVICE_2
 #define I2C2_SCL                PB10
 #define I2C2_SDA                PB11
 
 #define USE_BARO
 #define BARO_I2C_BUS            BUS_I2C2
 #define USE_BARO_SPL06
-#define SPL06_I2C_ADDR 118
+#define SPL06_I2C_ADDR          0x76
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Align mode/enum priorities and max values across modules and documentation to maintain a single source of truth.

Low
  • Update

@sensei-hacker
Copy link
Member

sensei-hacker commented Nov 23, 2025

This checklist can be very handy to see at a glance what has been tested and what still needs to be tested:

  • Samples received
  • Flash firmware
  • Calibrate
  • Orientation matches
  • Gyro working
  • Accel working
  • Baro working
  • Blackbox
  • UART1
  • UART2
  • UART3
  • UART4
  • UART5
  • Motor outputs
  • DShot support on m1-4
  • Servo outputs
  • Voltage ADC
  • Mag I2C Bus
  • PINIO1

The available UARTs have to be adjusted for each board, of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants