diff --git a/.gitignore b/.gitignore
index 9b72fa8305a..6d7138e6bd5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,7 @@ launch.json
# Assitnow token and files for test script
tokens.yaml
*.ubx
+
+# Local development files
+.semgrepignore
+build_sitl/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc34f9da32b..14db3259720 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,7 +52,7 @@ else()
endif()
-project(INAV VERSION 9.0.0)
+project(INAV VERSION 9.0.1)
enable_language(ASM)
diff --git a/src/main/fc/fc_core.c b/src/main/fc/fc_core.c
index 0cf6240771f..11bbd6cf3cc 100644
--- a/src/main/fc/fc_core.c
+++ b/src/main/fc/fc_core.c
@@ -946,7 +946,12 @@ void taskMainPidLoop(timeUs_t currentTimeUs)
processPilotAndFailSafeActions(dT);
- updateArmingStatus();
+ // Check battery, GPS signal, arming status etc @ 200 Hz
+ static uint8_t armingStatusDivider = 0;
+ if (++armingStatusDivider >= 10) {
+ armingStatusDivider = 0;
+ updateArmingStatus();
+ }
if (rxConfig()->rcFilterFrequency) {
rcInterpolationApply(isRXDataNew, currentTimeUs);
diff --git a/src/main/fc/fc_msp.c b/src/main/fc/fc_msp.c
index 455d5f20897..45379d1caa4 100644
--- a/src/main/fc/fc_msp.c
+++ b/src/main/fc/fc_msp.c
@@ -1550,6 +1550,12 @@ static bool mspFcProcessOutCommand(uint16_t cmdMSP, sbuf_t *dst, mspPostProcessF
sbufWriteU8(dst, vtxDevice->capability.bandCount);
sbufWriteU8(dst, vtxDevice->capability.channelCount);
sbufWriteU8(dst, vtxDevice->capability.powerCount);
+
+ uint8_t minPowerIndex = 1;
+ if (deviceType == VTXDEV_MSP) {
+ minPowerIndex = 0;
+ }
+ sbufWriteU8(dst, minPowerIndex);
}
else {
sbufWriteU8(dst, VTXDEV_UNKNOWN); // no VTX configured
diff --git a/src/main/io/gps_ublox.c b/src/main/io/gps_ublox.c
index f0899aa69d5..82e1a4f655d 100755
--- a/src/main/io/gps_ublox.c
+++ b/src/main/io/gps_ublox.c
@@ -1231,11 +1231,9 @@ STATIC_PROTOTHREAD(gpsProtocolStateThread)
if (gpsState.hwVersion == UBX_HW_VERSION_UNKNOWN)
{
pollVersion();
- ptWaitTimeout((_ack_state == UBX_ACK_GOT_ACK || _ack_state == UBX_ACK_GOT_NAK), GPS_CFG_CMD_TIMEOUT_MS);
}
pollGnssCapabilities();
- ptWaitTimeout((_ack_state == UBX_ACK_GOT_ACK || _ack_state == UBX_ACK_GOT_NAK), GPS_CFG_CMD_TIMEOUT_MS);
}
}
}
diff --git a/src/main/navigation/navigation_pos_estimator.c b/src/main/navigation/navigation_pos_estimator.c
index 35245d9f7f0..4252b952c27 100644
--- a/src/main/navigation/navigation_pos_estimator.c
+++ b/src/main/navigation/navigation_pos_estimator.c
@@ -228,6 +228,7 @@ void onNewGPSData(void)
/* If not the first update - calculate velocities */
if (!isFirstGPSUpdate) {
float dT = US2S(getGPSDeltaTimeFilter(currentTimeUs - lastGPSNewDataTime));
+ posEstimator.gps.updateDt = dT;
/* Use VELNED provided by GPS if available, calculate from coordinates otherwise */
float gpsScaleLonDown = constrainf(cos_approx((ABS(gpsSol.llh.lat) / 10000000.0f) * 0.0174532925f), 0.01f, 1.0f);
@@ -298,12 +299,15 @@ void updatePositionEstimator_BaroTopic(timeUs_t currentTimeUs)
posEstimator.baro.epv = positionEstimationConfig()->baro_epv;
posEstimator.baro.lastUpdateTime = currentTimeUs;
- if (baroDtUs <= MS2US(INAV_BARO_TIMEOUT_MS)) {
- posEstimator.baro.alt = pt1FilterApply3(&posEstimator.baro.avgFilter, posEstimator.baro.alt, US2S(baroDtUs));
+ if (baroDtUs > 0 && baroDtUs <= MS2US(INAV_BARO_TIMEOUT_MS)) {
+ const float baroDtSec = US2S(baroDtUs);
+ posEstimator.baro.updateDt = baroDtSec;
+
+ posEstimator.baro.alt = pt1FilterApply3(&posEstimator.baro.avgFilter, posEstimator.baro.alt, baroDtSec);
// baro altitude rate
static float baroAltPrevious = 0;
- posEstimator.baro.baroAltRate = (posEstimator.baro.alt - baroAltPrevious) / US2S(baroDtUs);
+ posEstimator.baro.baroAltRate = (posEstimator.baro.alt - baroAltPrevious) / baroDtSec;
baroAltPrevious = posEstimator.baro.alt;
updateBaroAltitudeRate(posEstimator.baro.baroAltRate);
}
@@ -354,7 +358,7 @@ static bool gravityCalibrationComplete(void)
static void updateIMUEstimationWeight(const float dt)
{
static float acc_clip_factor = 1.0f;
- // If accelerometer measurement is clipped - drop the acc weight to 0.3
+ // If accelerometer measurement is clipped - drop the acc weight to 0.5
// and gradually restore weight back to 1.0 over time
if (accIsClipped()) {
acc_clip_factor = 0.5f;
@@ -576,72 +580,84 @@ static bool estimationCalculateCorrection_Z(estimationContext_t * ctx)
}
if (ctx->newFlags & EST_BARO_VALID && wBaro) {
- bool isAirCushionEffectDetected = false;
- static float baroGroundAlt = 0.0f;
+ if (posEstimator.baro.updateDt) { // only update corrections once every sensor update
+ ctx->applyCorrections = true;
+ const float dT = posEstimator.baro.updateDt;
- if (STATE(MULTIROTOR)) {
- static bool isBaroGroundValid = false;
+ bool isAirCushionEffectDetected = false;
+ static float baroGroundAlt = 0.0f;
- if (!ARMING_FLAG(ARMED)) {
- baroGroundAlt = posEstimator.baro.alt;
- isBaroGroundValid = true;
- }
- else if (isBaroGroundValid) {
- // We might be experiencing air cushion effect during takeoff - use sonar or baro ground altitude to detect it
- if (isMulticopterThrottleAboveMidHover()) {
- // Disable ground effect detection at lift off when est alt and baro alt converge. Always disable if baro alt > 1m.
- isBaroGroundValid = fabsf(posEstimator.est.pos.z - posEstimator.baro.alt) > 20.0f && posEstimator.baro.alt < 100.0f;
- }
+ if (STATE(MULTIROTOR)) {
+ static bool isBaroGroundValid = false;
- isAirCushionEffectDetected = (isEstimatedAglTrusted() && posEstimator.surface.alt < 20.0f) || posEstimator.baro.alt < baroGroundAlt + 20.0f;
+ if (!ARMING_FLAG(ARMED)) {
+ baroGroundAlt = posEstimator.baro.alt;
+ isBaroGroundValid = true;
+ }
+ else if (isBaroGroundValid) {
+ // We might be experiencing air cushion effect during takeoff - use sonar or baro ground altitude to detect it
+ if (isMulticopterThrottleAboveMidHover()) {
+ // Disable ground effect detection at lift off when est alt and baro alt converge. Always disable if baro alt > 1m.
+ isBaroGroundValid = fabsf(posEstimator.est.pos.z - posEstimator.baro.alt) > 20.0f && posEstimator.baro.alt < 100.0f;
+ }
+
+ isAirCushionEffectDetected = (isEstimatedAglTrusted() && posEstimator.surface.alt < 20.0f) ||
+ posEstimator.baro.alt < baroGroundAlt + 20.0f;
+ }
}
- }
- // Altitude
- float baroAltResidual = wBaro * ((isAirCushionEffectDetected ? baroGroundAlt : posEstimator.baro.alt) - posEstimator.est.pos.z);
+ // Altitude
+ float baroAltResidual = wBaro * ((isAirCushionEffectDetected ? baroGroundAlt : posEstimator.baro.alt) - posEstimator.est.pos.z);
- // Disable alt pos correction at point of lift off if ground effect active
- if (isAirCushionEffectDetected && isMulticopterThrottleAboveMidHover()) {
- baroAltResidual = 0.0f;
- }
+ // Disable alt pos correction at point of lift off if ground effect active
+ if (isAirCushionEffectDetected && isMulticopterThrottleAboveMidHover()) {
+ baroAltResidual = 0.0f;
+ }
- const float baroVelZResidual = isAirCushionEffectDetected ? 0.0f : wBaro * (posEstimator.baro.baroAltRate - posEstimator.est.vel.z);
- const float w_z_baro_p = positionEstimationConfig()->w_z_baro_p;
- const float w_z_baro_v = positionEstimationConfig()->w_z_baro_v;
+ const float baroVelZResidual = isAirCushionEffectDetected ? 0.0f : wBaro * (posEstimator.baro.baroAltRate - posEstimator.est.vel.z);
+ const float w_z_baro_p = positionEstimationConfig()->w_z_baro_p;
+ const float w_z_baro_v = positionEstimationConfig()->w_z_baro_v;
- ctx->estPosCorr.z += baroAltResidual * w_z_baro_p * ctx->dt;
- ctx->estVelCorr.z += baroVelZResidual * w_z_baro_v * ctx->dt;
+ ctx->estPosCorr.z = baroAltResidual * w_z_baro_p * dT;
+ ctx->estVelCorr.z = baroVelZResidual * w_z_baro_v * dT;
- ctx->newEPV = updateEPE(posEstimator.est.epv, ctx->dt, MAX(posEstimator.baro.epv, fabsf(baroAltResidual)), w_z_baro_p);
+ ctx->newEPV = updateEPE(posEstimator.est.epv, dT, MAX(posEstimator.baro.epv, fabsf(baroAltResidual)), w_z_baro_p);
- // Accelerometer bias
- if (!isAirCushionEffectDetected) {
- ctx->accBiasCorr.z += (baroAltResidual * sq(w_z_baro_p) + baroVelZResidual * sq(w_z_baro_v));
+ // Accelerometer bias
+ if (!isAirCushionEffectDetected) {
+ ctx->accBiasCorr.z = dT * (baroAltResidual * sq(w_z_baro_p) + baroVelZResidual * sq(w_z_baro_v));
+ }
}
correctOK = ARMING_FLAG(WAS_EVER_ARMED); // No correction until first armed
}
if (ctx->newFlags & EST_GPS_Z_VALID && (wGps || !(ctx->newFlags & EST_Z_VALID))) {
- // Reset current estimate to GPS altitude if estimate not valid (used for GPS and Baro)
- if (!(ctx->newFlags & EST_Z_VALID)) {
- posEstimator.est.pos.z = posEstimator.gps.pos.z;
- posEstimator.est.vel.z = posEstimator.gps.vel.z;
- ctx->newEPV = posEstimator.gps.epv;
- }
- else {
- // Altitude
- const float gpsAltResidual = wGps * (posEstimator.gps.pos.z - posEstimator.est.pos.z);
- const float gpsVelZResidual = wGps * (posEstimator.gps.vel.z - posEstimator.est.vel.z);
- const float w_z_gps_p = positionEstimationConfig()->w_z_gps_p;
- const float w_z_gps_v = positionEstimationConfig()->w_z_gps_v;
+ if (posEstimator.gps.updateDt) { // only update corrections once every sensor update
+ // Reset current estimate to GPS altitude if estimate not valid (used for GPS and Baro)
+ if (!(ctx->newFlags & EST_Z_VALID)) {
+ posEstimator.est.pos.z = posEstimator.gps.pos.z;
+ posEstimator.est.vel.z = posEstimator.gps.vel.z;
+ ctx->newEPV = posEstimator.gps.epv;
+ }
+ else {
+ ctx->applyCorrections = true;
+ const float dT = posEstimator.gps.updateDt;
- ctx->estPosCorr.z += gpsAltResidual * w_z_gps_p * ctx->dt;
- ctx->estVelCorr.z += gpsVelZResidual * w_z_gps_v * ctx->dt;
- ctx->newEPV = updateEPE(posEstimator.est.epv, ctx->dt, MAX(posEstimator.gps.epv, fabsf(gpsAltResidual)), w_z_gps_p);
+ // Altitude
+ const float gpsAltResidual = wGps * (posEstimator.gps.pos.z - posEstimator.est.pos.z);
+ const float gpsVelZResidual = wGps * (posEstimator.gps.vel.z - posEstimator.est.vel.z);
+ const float w_z_gps_p = positionEstimationConfig()->w_z_gps_p;
+ const float w_z_gps_v = positionEstimationConfig()->w_z_gps_v;
- // Accelerometer bias
- ctx->accBiasCorr.z += (gpsAltResidual * sq(w_z_gps_p) + gpsVelZResidual * sq(w_z_gps_v));
+ ctx->estPosCorr.z += gpsAltResidual * w_z_gps_p * dT;
+ ctx->estVelCorr.z += gpsVelZResidual * w_z_gps_v * dT;
+
+ ctx->newEPV = updateEPE(ctx->newEPV, dT, MAX(posEstimator.gps.epv, fabsf(gpsAltResidual)), w_z_gps_p);
+
+ // Accelerometer bias
+ ctx->accBiasCorr.z += dT * (gpsAltResidual * sq(w_z_gps_p) + gpsVelZResidual * sq(w_z_gps_v));
+ }
}
correctOK = ARMING_FLAG(WAS_EVER_ARMED); // No correction until first armed
@@ -658,6 +674,9 @@ static bool estimationCalculateCorrection_Z(estimationContext_t * ctx)
static bool estimationCalculateCorrection_XY_GPS(estimationContext_t * ctx)
{
if (ctx->newFlags & EST_GPS_XY_VALID) {
+ if (!posEstimator.gps.updateDt) { // only update corrections once every sensor update
+ return true;
+ }
/* If GPS is valid and our estimate is NOT valid - reset it to GPS coordinates and velocity */
if (!(ctx->newFlags & EST_XY_VALID)) {
posEstimator.est.pos.x = posEstimator.gps.pos.x;
@@ -667,6 +686,9 @@ static bool estimationCalculateCorrection_XY_GPS(estimationContext_t * ctx)
ctx->newEPH = posEstimator.gps.eph;
}
else {
+ ctx->applyCorrections = true;
+ const float dT = posEstimator.gps.updateDt;
+
const float gpsPosXResidual = posEstimator.gps.pos.x - posEstimator.est.pos.x;
const float gpsPosYResidual = posEstimator.gps.pos.y - posEstimator.est.pos.y;
const float gpsVelXResidual = posEstimator.gps.vel.x - posEstimator.est.vel.x;
@@ -680,19 +702,19 @@ static bool estimationCalculateCorrection_XY_GPS(estimationContext_t * ctx)
const float w_xy_gps_v = positionEstimationConfig()->w_xy_gps_v * sq(gpsWeightScaler);
// Coordinates
- ctx->estPosCorr.x += gpsPosXResidual * w_xy_gps_p * ctx->dt;
- ctx->estPosCorr.y += gpsPosYResidual * w_xy_gps_p * ctx->dt;
+ ctx->estPosCorr.x = gpsPosXResidual * w_xy_gps_p * dT;
+ ctx->estPosCorr.y = gpsPosYResidual * w_xy_gps_p * dT;
// Velocity from direct measurement
- ctx->estVelCorr.x += gpsVelXResidual * w_xy_gps_v * ctx->dt;
- ctx->estVelCorr.y += gpsVelYResidual * w_xy_gps_v * ctx->dt;
+ ctx->estVelCorr.x = gpsVelXResidual * w_xy_gps_v * dT;
+ ctx->estVelCorr.y = gpsVelYResidual * w_xy_gps_v * dT;
// Accelerometer bias
- ctx->accBiasCorr.x += (gpsPosXResidual * sq(w_xy_gps_p) + gpsVelXResidual * sq(w_xy_gps_v));
- ctx->accBiasCorr.y += (gpsPosYResidual * sq(w_xy_gps_p) + gpsVelYResidual * sq(w_xy_gps_v));
+ ctx->accBiasCorr.x = dT * (gpsPosXResidual * sq(w_xy_gps_p) + gpsVelXResidual * sq(w_xy_gps_v));
+ ctx->accBiasCorr.y = dT * (gpsPosYResidual * sq(w_xy_gps_p) + gpsVelYResidual * sq(w_xy_gps_v));
/* Adjust EPH */
- ctx->newEPH = updateEPE(posEstimator.est.eph, ctx->dt, MAX(posEstimator.gps.eph, gpsPosResidualMag), w_xy_gps_p);
+ ctx->newEPH = updateEPE(posEstimator.est.eph, dT, MAX(posEstimator.gps.eph, gpsPosResidualMag), w_xy_gps_p);
}
return true;
@@ -736,9 +758,9 @@ static void updateEstimatedTopic(timeUs_t currentTimeUs)
return;
}
- /* Calculate new EPH and EPV for the case we didn't update position */
- ctx.newEPH = posEstimator.est.eph * ((posEstimator.est.eph <= max_eph_epv) ? 1.0f + ctx.dt : 1.0f);
- ctx.newEPV = posEstimator.est.epv * ((posEstimator.est.epv <= max_eph_epv) ? 1.0f + ctx.dt : 1.0f);
+ /* Calculate new degraded EPH and EPV for the case we didn't update estimation from sensors - linear degradation in max 10s */
+ ctx.newEPH = posEstimator.est.eph + ((posEstimator.est.eph <= max_eph_epv) ? 100.0f * ctx.dt : 0.0f);
+ ctx.newEPV = posEstimator.est.epv + ((posEstimator.est.epv <= max_eph_epv) ? 100.0f * ctx.dt : 0.0f);
ctx.newFlags = calculateCurrentValidityFlags(currentTimeUs);
vectorZero(&ctx.estPosCorr);
@@ -760,40 +782,53 @@ static void updateEstimatedTopic(timeUs_t currentTimeUs)
// If we can't apply correction or accuracy is off the charts - decay velocity to zero
if (!estXYCorrectOk || ctx.newEPH > max_eph_epv) {
- ctx.estVelCorr.x = -posEstimator.est.vel.x * positionEstimationConfig()->w_xy_res_v * ctx.dt;
- ctx.estVelCorr.y = -posEstimator.est.vel.y * positionEstimationConfig()->w_xy_res_v * ctx.dt;
+ const float w_xy_res_v = positionEstimationConfig()->w_xy_res_v;
+ posEstimator.est.vel.x -= posEstimator.est.vel.x * w_xy_res_v * ctx.dt;
+ posEstimator.est.vel.y -= posEstimator.est.vel.y * w_xy_res_v * ctx.dt;
}
if (!estZCorrectOk || ctx.newEPV > max_eph_epv) {
- ctx.estVelCorr.z = -posEstimator.est.vel.z * positionEstimationConfig()->w_z_res_v * ctx.dt;
+ posEstimator.est.vel.z -= posEstimator.est.vel.z * positionEstimationConfig()->w_z_res_v * ctx.dt;
}
- // Boost the corrections based on accWeight
- vectorScale(&ctx.estPosCorr, &ctx.estPosCorr, 1.0f / posEstimator.imu.accWeightFactor);
- vectorScale(&ctx.estVelCorr, &ctx.estVelCorr, 1.0f / posEstimator.imu.accWeightFactor);
+ // Only apply corrections if new sensor update available
+ if (ctx.applyCorrections) {
+ ctx.applyCorrections = false;
- // Constrain corrections to prevent instability
- const float corrLimit = INAV_EST_CORR_LIMIT_VALUE * ctx.dt;
- for (uint8_t axis = 0; axis < 3; axis++) {
- ctx.estPosCorr.v[axis] = constrainf(ctx.estPosCorr.v[axis], -corrLimit, corrLimit);
- ctx.estVelCorr.v[axis] = constrainf(ctx.estVelCorr.v[axis], -corrLimit, corrLimit);
- }
+ // Boost the corrections based on accWeight
+ vectorScale(&ctx.estPosCorr, &ctx.estPosCorr, 1.0f / posEstimator.imu.accWeightFactor);
+ vectorScale(&ctx.estVelCorr, &ctx.estVelCorr, 1.0f / posEstimator.imu.accWeightFactor);
- // Apply corrections
- vectorAdd(&posEstimator.est.pos, &posEstimator.est.pos, &ctx.estPosCorr);
- vectorAdd(&posEstimator.est.vel, &posEstimator.est.vel, &ctx.estVelCorr);
+ // Constrain corrections to prevent instability
+ float maxUpdateDt = MAX(posEstimator.gps.updateDt, posEstimator.baro.updateDt);
+ maxUpdateDt = MAX(maxUpdateDt, posEstimator.flow.updateDt);
+ const float correctionLimit = INAV_EST_CORR_LIMIT_VALUE * maxUpdateDt;
+ for (uint8_t axis = 0; axis < 3; axis++) {
+ ctx.estPosCorr.v[axis] = constrainf(ctx.estPosCorr.v[axis], -correctionLimit, correctionLimit);
+ ctx.estVelCorr.v[axis] = constrainf(ctx.estVelCorr.v[axis], -correctionLimit, correctionLimit);
+ }
- /* Correct accelerometer bias */
- const float w_acc_bias = positionEstimationConfig()->w_acc_bias;
- if (w_acc_bias > 0.0f) {
- /* Correct accel bias */
- posEstimator.imu.accelBias.x += ctx.accBiasCorr.x * w_acc_bias * ctx.dt;
- posEstimator.imu.accelBias.y += ctx.accBiasCorr.y * w_acc_bias * ctx.dt;
- posEstimator.imu.accelBias.z += ctx.accBiasCorr.z * w_acc_bias * ctx.dt;
+ // Apply corrections
+ vectorAdd(&posEstimator.est.pos, &posEstimator.est.pos, &ctx.estPosCorr);
+ vectorAdd(&posEstimator.est.vel, &posEstimator.est.vel, &ctx.estVelCorr);
+
+ /* Correct accelerometer bias */
+ const float w_acc_bias = positionEstimationConfig()->w_acc_bias;
+ if (w_acc_bias > 0.0f) {
+ /* Correct accel bias */
+ posEstimator.imu.accelBias.x += ctx.accBiasCorr.x * w_acc_bias;
+ posEstimator.imu.accelBias.y += ctx.accBiasCorr.y * w_acc_bias;
+ posEstimator.imu.accelBias.z += ctx.accBiasCorr.z * w_acc_bias;
+
+ posEstimator.imu.accelBias.x = constrainf(posEstimator.imu.accelBias.x, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
+ posEstimator.imu.accelBias.y = constrainf(posEstimator.imu.accelBias.y, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
+ posEstimator.imu.accelBias.z = constrainf(posEstimator.imu.accelBias.z, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
+ }
- posEstimator.imu.accelBias.x = constrainf(posEstimator.imu.accelBias.x, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
- posEstimator.imu.accelBias.y = constrainf(posEstimator.imu.accelBias.y, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
- posEstimator.imu.accelBias.z = constrainf(posEstimator.imu.accelBias.z, -INAV_ACC_BIAS_ACCEPTANCE_VALUE, INAV_ACC_BIAS_ACCEPTANCE_VALUE);
+ // Reset sensor update time deltas once sensor corrections applied after sensor update
+ posEstimator.gps.updateDt = 0.0f;
+ posEstimator.baro.updateDt = 0.0f;
+ posEstimator.flow.updateDt = 0.0f;
}
/* Update ground course */
diff --git a/src/main/navigation/navigation_pos_estimator_agl.c b/src/main/navigation/navigation_pos_estimator_agl.c
index 03b5bd8ccf0..38788e20a77 100644
--- a/src/main/navigation/navigation_pos_estimator_agl.c
+++ b/src/main/navigation/navigation_pos_estimator_agl.c
@@ -149,7 +149,7 @@ void estimationCalculateAGL(estimationContext_t * ctx)
// Update estimate
posEstimator.est.aglAlt += posEstimator.est.aglVel * ctx->dt;
posEstimator.est.aglAlt += posEstimator.imu.accelNEU.z * sq(ctx->dt) / 2.0f * posEstimator.imu.accWeightFactor;
- posEstimator.est.aglVel += posEstimator.imu.accelNEU.z * ctx->dt * sq(posEstimator.imu.accWeightFactor);
+ posEstimator.est.aglVel += posEstimator.imu.accelNEU.z * ctx->dt * posEstimator.imu.accWeightFactor;
// Apply correction
if (posEstimator.est.aglQual == SURFACE_QUAL_HIGH) {
diff --git a/src/main/navigation/navigation_pos_estimator_flow.c b/src/main/navigation/navigation_pos_estimator_flow.c
index 8656c4919f4..36325f5dc1a 100644
--- a/src/main/navigation/navigation_pos_estimator_flow.c
+++ b/src/main/navigation/navigation_pos_estimator_flow.c
@@ -73,6 +73,13 @@ bool estimationCalculateCorrection_XY_FLOW(estimationContext_t * ctx)
return false;
}
+ if (!opflow.updateDt) {
+ return true;
+ }
+ posEstimator.flow.updateDt = opflow.updateDt;
+ opflow.updateDt = 0.0f;
+ const float dt = posEstimator.flow.updateDt;
+
// Calculate linear velocity based on angular velocity and altitude
// Technically we should calculate arc length here, but for fast sampling this is accurate enough
fpVector3_t flowVel = {
@@ -88,8 +95,9 @@ bool estimationCalculateCorrection_XY_FLOW(estimationContext_t * ctx)
const float flowVelXInnov = flowVel.x - posEstimator.est.vel.x;
const float flowVelYInnov = flowVel.y - posEstimator.est.vel.y;
- ctx->estVelCorr.x = flowVelXInnov * positionEstimationConfig()->w_xy_flow_v * ctx->dt;
- ctx->estVelCorr.y = flowVelYInnov * positionEstimationConfig()->w_xy_flow_v * ctx->dt;
+ const float w_xy_flow_v = positionEstimationConfig()->w_xy_flow_v;
+ ctx->estVelCorr.x = flowVelXInnov * w_xy_flow_v * dt;
+ ctx->estVelCorr.y = flowVelYInnov * w_xy_flow_v * dt;
// Calculate position correction if possible/allowed
if ((ctx->newFlags & EST_GPS_XY_VALID)) {
@@ -98,16 +106,17 @@ bool estimationCalculateCorrection_XY_FLOW(estimationContext_t * ctx)
posEstimator.est.flowCoordinates[Y] = posEstimator.gps.pos.y;
}
else if (positionEstimationConfig()->allow_dead_reckoning) {
- posEstimator.est.flowCoordinates[X] += flowVel.x * ctx->dt;
- posEstimator.est.flowCoordinates[Y] += flowVel.y * ctx->dt;
+ posEstimator.est.flowCoordinates[X] += flowVel.x * dt;
+ posEstimator.est.flowCoordinates[Y] += flowVel.y * dt;
const float flowResidualX = posEstimator.est.flowCoordinates[X] - posEstimator.est.pos.x;
const float flowResidualY = posEstimator.est.flowCoordinates[Y] - posEstimator.est.pos.y;
- ctx->estPosCorr.x = flowResidualX * positionEstimationConfig()->w_xy_flow_p * ctx->dt;
- ctx->estPosCorr.y = flowResidualY * positionEstimationConfig()->w_xy_flow_p * ctx->dt;
+ const float w_xy_flow_p = positionEstimationConfig()->w_xy_flow_p;
+ ctx->estPosCorr.x = flowResidualX * w_xy_flow_p * dt;
+ ctx->estPosCorr.y = flowResidualY * w_xy_flow_p * dt;
- ctx->newEPH = updateEPE(posEstimator.est.eph, ctx->dt, calc_length_pythagorean_2D(flowResidualX, flowResidualY), positionEstimationConfig()->w_xy_flow_p);
+ ctx->newEPH = updateEPE(posEstimator.est.eph, dt, calc_length_pythagorean_2D(flowResidualX, flowResidualY), w_xy_flow_p);
}
DEBUG_SET(DEBUG_FLOW, 0, RADIANS_TO_DEGREES(posEstimator.flow.flowRate[X]));
@@ -115,7 +124,7 @@ bool estimationCalculateCorrection_XY_FLOW(estimationContext_t * ctx)
DEBUG_SET(DEBUG_FLOW, 2, posEstimator.est.flowCoordinates[X]);
DEBUG_SET(DEBUG_FLOW, 3, posEstimator.est.flowCoordinates[Y]);
- return true;
+ return ctx->applyCorrections = true;
#else
UNUSED(ctx);
return false;
diff --git a/src/main/navigation/navigation_pos_estimator_private.h b/src/main/navigation/navigation_pos_estimator_private.h
index fc824eb534e..8a91afe268b 100644
--- a/src/main/navigation/navigation_pos_estimator_private.h
+++ b/src/main/navigation/navigation_pos_estimator_private.h
@@ -71,6 +71,7 @@ typedef struct {
fpVector3_t vel; // GPS velocity (cms)
float eph;
float epv;
+ float updateDt;
} navPositionEstimatorGPS_t;
typedef struct {
@@ -79,6 +80,7 @@ typedef struct {
float alt; // Raw barometric altitude (cm)
float epv;
float baroAltRate; // Baro altitude rate of change (cm/s)
+ float updateDt;
} navPositionEstimatorBARO_t;
typedef struct {
@@ -105,6 +107,7 @@ typedef struct {
float quality;
float flowRate[2];
float bodyRate[2];
+ float updateDt;
} navPositionEstimatorFLOW_t;
typedef struct {
@@ -180,6 +183,7 @@ typedef struct {
fpVector3_t estPosCorr;
fpVector3_t estVelCorr;
fpVector3_t accBiasCorr;
+ bool applyCorrections;
} estimationContext_t;
extern navigationPosEstimator_t posEstimator;
diff --git a/src/main/sensors/opflow.c b/src/main/sensors/opflow.c
index f82d8f16a58..024c5d403cf 100755
--- a/src/main/sensors/opflow.c
+++ b/src/main/sensors/opflow.c
@@ -171,6 +171,7 @@ void opflowUpdate(timeUs_t currentTimeUs)
if (opflow.dev.updateFn(&opflow.dev)) {
// Indicate valid update
opflow.isHwHealty = true;
+ opflow.updateDt = US2S(currentTimeUs - opflow.lastValidUpdate);
opflow.lastValidUpdate = currentTimeUs;
opflow.rawQuality = opflow.dev.rawData.quality;
diff --git a/src/main/sensors/opflow.h b/src/main/sensors/opflow.h
index afe94ec79ac..a2f82745816 100755
--- a/src/main/sensors/opflow.h
+++ b/src/main/sensors/opflow.h
@@ -53,6 +53,7 @@ typedef struct opflow_s {
opflowQuality_e flowQuality;
timeUs_t lastValidUpdate;
+ float updateDt;
bool isHwHealty;
float flowRate[2]; // optical flow angular rate in rad/sec measured about the X and Y body axis
float bodyRate[2]; // body inertial angular rate in rad/sec measured about the X and Y body axis
diff --git a/src/main/target/DYSF4/CMakeLists.txt b/src/main/target/DYSF4/CMakeLists.txt
new file mode 100644
index 00000000000..ec00b5acc49
--- /dev/null
+++ b/src/main/target/DYSF4/CMakeLists.txt
@@ -0,0 +1,2 @@
+target_stm32f405xg(DYSF4PRO)
+target_stm32f405xg(DYSF4PROV2)
diff --git a/src/main/target/DYSF4/target.c b/src/main/target/DYSF4/target.c
new file mode 100644
index 00000000000..d6de2e9bf25
--- /dev/null
+++ b/src/main/target/DYSF4/target.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#include
+
+#include
+#include "drivers/io.h"
+#include "drivers/pwm_mapping.h"
+#include "drivers/timer.h"
+#include "drivers/bus.h"
+
+timerHardware_t timerHardware[] = {
+
+ DEF_TIM(TIM3, CH3, PB0, TIM_USE_OUTPUT_AUTO, 0, 0), // S1_OUT D1_ST7
+ DEF_TIM(TIM3, CH4, PB1, TIM_USE_OUTPUT_AUTO, 0, 0), // S2_OUT D1_ST2
+ DEF_TIM(TIM2, CH4, PA3, TIM_USE_OUTPUT_AUTO, 0, 1), // S3_OUT D1_ST6
+ DEF_TIM(TIM2, CH3, PA2, TIM_USE_OUTPUT_AUTO, 0, 0), // S4_OUT D1_ST1
+
+ // { TIM9, IO_TAG(PA3), TIM_Channel_2, 1, IOCFG_AF_PP_PD, GPIO_AF_TIM9, TIM_USE_OUTPUT_AUTO }, // MOTOR_3
+ DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT MOTOR, SERVO or LED
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6_OUT
+
+
+ // DEF_TIM(TIM12, CH1, PB14, TIM_USE_PPM, 0, 0), // PPM
+ DEF_TIM(TIM12, CH2, PB15, TIM_USE_ANY, 0, 0), // S2_IN
+ DEF_TIM(TIM8, CH1, PC6, TIM_USE_ANY, 0, 0), // S3_IN, UART6_TX
+ DEF_TIM(TIM8, CH2, PC7, TIM_USE_ANY, 0, 0), // S4_IN, UART6_RX
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_ANY, 0, 0), // S5_IN
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_ANY, 0, 0), // S6_IN
+
+};
+
+const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);
diff --git a/src/main/target/DYSF4/target.h b/src/main/target/DYSF4/target.h
new file mode 100644
index 00000000000..76e79106afa
--- /dev/null
+++ b/src/main/target/DYSF4/target.h
@@ -0,0 +1,159 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#pragma once
+
+// This directory contains: DYSF4PRO, DYSF4PROV2
+
+#if defined(DYSF4PRO)
+#define TARGET_BOARD_IDENTIFIER "DYS4"
+#elif defined(DYSF4PROV2)
+#define TARGET_BOARD_IDENTIFIER "DY42"
+#endif
+
+#define USBD_PRODUCT_STRING "DysF4Pro"
+
+#define LED0 PB5
+
+#define BEEPER PB4
+#define BEEPER_INVERTED
+
+#if defined(DYSF4PROV2)
+#define USE_I2C
+#define USE_I2C_DEVICE_1
+#define I2C1_SCL PB8
+#define I2C1_SDA PB9
+#define I2C_EXT_BUS BUS_I2C1
+#else
+#define USE_I2C
+#define USE_I2C_DEVICE_2
+#define I2C_DEVICE_2_SHARES_UART3
+#define I2C_EXT_BUS BUS_I2C2
+#endif
+
+#define UG2864_I2C_BUS I2C_EXT_BUS
+
+#define MPU6000_CS_PIN PA4
+#define MPU6000_SPI_BUS BUS_SPI1
+
+#define USE_IMU_MPU6000
+#define IMU_MPU6000_ALIGN CW180_DEG
+
+#define USE_MAG
+#define MAG_I2C_BUS I2C_EXT_BUS
+#define USE_MAG_ALL
+
+#define TEMPERATURE_I2C_BUS I2C_EXT_BUS
+
+#define USE_BARO
+#define BARO_I2C_BUS I2C_EXT_BUS
+#define USE_BARO_BMP085
+#define USE_BARO_BMP280
+#define USE_BARO_MS5611
+
+#define PITOT_I2C_BUS I2C_EXT_BUS
+
+#define USE_RANGEFINDER
+#define RANGEFINDER_I2C_BUS I2C_EXT_BUS
+
+#define USE_VCP
+#define VBUS_SENSING_PIN PC5
+#define VBUS_SENSING_ENABLED
+
+
+#define USE_UART1
+#define UART1_RX_PIN PA10
+#define UART1_TX_PIN PA9
+#define UART1_AHB1_PERIPHERALS RCC_AHB1Periph_DMA2
+
+#define USE_UART3
+#define UART3_RX_PIN PB11
+#define UART3_TX_PIN PB10
+
+#define USE_UART6
+#define UART6_RX_PIN PC7
+#define UART6_TX_PIN PC6
+
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PC8
+#define SOFTSERIAL_1_TX_PIN PC9
+
+#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
+
+#define DEFAULT_RX_TYPE RX_TYPE_SERIAL
+#define SERIALRX_PROVIDER SERIALRX_SBUS
+#define SERIALRX_UART SERIAL_PORT_USART1
+
+#define USE_SPI
+
+#define USE_SPI_DEVICE_1
+
+
+#define USE_SPI_DEVICE_3
+#define SPI3_NSS_PIN PB3
+#define SPI3_SCK_PIN PC10
+#define SPI3_MISO_PIN PC11
+#define SPI3_MOSI_PIN PC12
+
+#define USE_MAX7456
+#define MAX7456_SPI_BUS BUS_SPI3
+#define MAX7456_CS_PIN PA15
+
+#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
+#define M25P16_CS_PIN SPI3_NSS_PIN
+#define M25P16_SPI_BUS BUS_SPI3
+#define USE_FLASHFS
+#define USE_FLASH_M25P16
+
+#define USE_ADC
+#define ADC_CHANNEL_1_PIN PC1
+#define ADC_CHANNEL_2_PIN PC2
+
+#ifdef DYSF4PRO
+ #define ADC_CHANNEL_3_PIN PC3
+#else
+ #define ADC_CHANNEL_3_PIN PA0
+#endif
+
+#define CURRENT_METER_ADC_CHANNEL ADC_CHN_1
+#define VBAT_ADC_CHANNEL ADC_CHN_2
+#define RSSI_ADC_CHANNEL ADC_CHN_3
+
+#define SENSORS_SET (SENSOR_ACC|SENSOR_MAG|SENSOR_BARO)
+
+#define USE_LED_STRIP
+#define WS2811_PIN PA1
+
+#define DISABLE_RX_PWM_FEATURE
+#define DEFAULT_FEATURES (FEATURE_TX_PROF_SEL | FEATURE_BLACKBOX | FEATURE_VBAT | FEATURE_OSD)
+
+#define USE_SPEKTRUM_BIND
+#define BIND_PIN PB11 // USART3 RX
+
+#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+
+// Number of available PWM outputs
+#define MAX_PWM_OUTPUT_PORTS 6
+#define TARGET_MOTOR_COUNT 6
+#define USE_DSHOT
+#define USE_ESC_SENSOR
+
+#define TARGET_IO_PORTA 0xffff
+#define TARGET_IO_PORTB 0xffff
+#define TARGET_IO_PORTC 0xffff
+#define TARGET_IO_PORTD 0xffff
+
diff --git a/src/main/target/NEXUSX/target.h b/src/main/target/NEXUSX/target.h
index 24c035b4cae..abe7bbaef28 100644
--- a/src/main/target/NEXUSX/target.h
+++ b/src/main/target/NEXUSX/target.h
@@ -32,7 +32,7 @@
#define SPI1_MOSI_PIN PA7
#define USE_IMU_ICM42605 // is actually ICM42688P
-#define IMU_ICM42605_ALIGN CW180_DEG
+#define IMU_ICM42605_ALIGN CW0_DEG
#define ICM42605_CS_PIN PA4
#define ICM42605_EXTI_PIN PB8
#define ICM42605_SPI_BUS BUS_SPI1
diff --git a/src/main/target/OMNIBUSF4/CMakeLists.txt b/src/main/target/OMNIBUSF4/CMakeLists.txt
index 0e2bf2002c0..28f13c7cd5b 100644
--- a/src/main/target/OMNIBUSF4/CMakeLists.txt
+++ b/src/main/target/OMNIBUSF4/CMakeLists.txt
@@ -1,12 +1 @@
-target_stm32f405xg(DYSF4PRO)
-target_stm32f405xg(DYSF4PROV2)
target_stm32f405xg(OMNIBUSF4)
-# the OMNIBUSF4SD has an SDCARD instead of flash, a BMP280 baro and therefore a slightly different ppm/pwm and SPI mapping
-target_stm32f405xg(OMNIBUSF4PRO)
-target_stm32f405xg(OMNIBUSF4V3_S5_S6_2SS)
-target_stm32f405xg(OMNIBUSF4V3_S5S6_SS)
-target_stm32f405xg(OMNIBUSF4V3_S6_SS)
-# OMNIBUSF4V3 is a (almost identical) variant of OMNIBUSF4PRO target,
-# except for an inverter on UART6.
-target_stm32f405xg(OMNIBUSF4V3)
-target_stm32f405xg(OMNIBUSF4V3_ICM SKIP_RELEASES)
diff --git a/src/main/target/OMNIBUSF4/target.c b/src/main/target/OMNIBUSF4/target.c
index be85e9fbce3..d6de2e9bf25 100644
--- a/src/main/target/OMNIBUSF4/target.c
+++ b/src/main/target/OMNIBUSF4/target.c
@@ -31,36 +31,16 @@ timerHardware_t timerHardware[] = {
DEF_TIM(TIM2, CH3, PA2, TIM_USE_OUTPUT_AUTO, 0, 0), // S4_OUT D1_ST1
// { TIM9, IO_TAG(PA3), TIM_Channel_2, 1, IOCFG_AF_PP_PD, GPIO_AF_TIM9, TIM_USE_OUTPUT_AUTO }, // MOTOR_3
-#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)) && !(defined(OMNIBUSF4PRO_LEDSTRIPM5) || defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
-
- DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT
- DEF_TIM(TIM1, CH1, PA8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6_OUT
-#elif defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
- DEF_TIM(TIM5, CH2, PA1, TIM_USE_ANY, 0, 0), // S5_OUT SOFTSERIAL
- DEF_TIM(TIM1, CH1, PA8, TIM_USE_ANY, 0, 0), // S6_OUT SOFTSERIAL
-#elif defined(OMNIBUSF4V3_S6_SS)
- DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT
- DEF_TIM(TIM1, CH1, PA8, TIM_USE_ANY, 0, 0), // S6_OUT SOFTSERIAL
-#else
DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT MOTOR, SERVO or LED
DEF_TIM(TIM1, CH1, PA8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6_OUT
-#endif
-#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3))
- DEF_TIM(TIM4, CH1, PB6, TIM_USE_LED, 0, 0), // LED strip for F4 V2 / F4-Pro-0X and later (RCD_CS for F4)
-#endif
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3)
- // DEF_TIM(TIM10, CH1, PB8, TIM_USE_PPM, 0, 0), // PPM
- DEF_TIM(TIM4, CH4, PB9, TIM_USE_ANY, 0, 0), // S2_IN
-#else
// DEF_TIM(TIM12, CH1, PB14, TIM_USE_PPM, 0, 0), // PPM
DEF_TIM(TIM12, CH2, PB15, TIM_USE_ANY, 0, 0), // S2_IN
-#endif
DEF_TIM(TIM8, CH1, PC6, TIM_USE_ANY, 0, 0), // S3_IN, UART6_TX
DEF_TIM(TIM8, CH2, PC7, TIM_USE_ANY, 0, 0), // S4_IN, UART6_RX
- DEF_TIM(TIM8, CH3, PC8, TIM_USE_ANY, 0, 0), // S5_IN // pad labelled CH5 on OMNIBUSF4PRO
- DEF_TIM(TIM8, CH4, PC9, TIM_USE_ANY, 0, 0), // S6_IN // pad labelled CH6 on OMNIBUSF4PRO
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_ANY, 0, 0), // S5_IN
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_ANY, 0, 0), // S6_IN
};
diff --git a/src/main/target/OMNIBUSF4/target.h b/src/main/target/OMNIBUSF4/target.h
index fcd89fb0e46..af906bb8b12 100644
--- a/src/main/target/OMNIBUSF4/target.h
+++ b/src/main/target/OMNIBUSF4/target.h
@@ -17,86 +17,27 @@
#pragma once
-//Same target as OMNIBUSF4PRO with LED strip in M5
-#ifdef OMNIBUSF4PRO_LEDSTRIPM5
-#define OMNIBUSF4PRO
-#endif
-//Same target as OMNIBUSF4V3 with softserial in M5 and M6
-#if defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
-#define OMNIBUSF4V3
-#endif
-
-#ifdef OMNIBUSF4PRO
-#define TARGET_BOARD_IDENTIFIER "OBSD"
-#elif defined(OMNIBUSF4V3)
-#define TARGET_BOARD_IDENTIFIER "OB43"
-#elif defined(OMNIBUSF4V3_ICM)
-#define TARGET_BOARD_IDENTIFIER "OB4I"
-#elif defined(DYSF4PRO)
-#define TARGET_BOARD_IDENTIFIER "DYS4"
-#elif defined(DYSF4PROV2)
-#define TARGET_BOARD_IDENTIFIER "DY42"
-#else
#define TARGET_BOARD_IDENTIFIER "OBF4"
-#endif
-#if defined(DYSF4PRO) || defined(DYSF4PROV2)
-#define USBD_PRODUCT_STRING "DysF4Pro"
-#else
#define USBD_PRODUCT_STRING "Omnibus F4"
-#endif
#define LED0 PB5
#define BEEPER PB4
#define BEEPER_INVERTED
-#if defined(DYSF4PROV2)
-#define USE_I2C
-#define USE_I2C_DEVICE_1
-#define I2C1_SCL PB8
-#define I2C1_SDA PB9
-#define I2C_EXT_BUS BUS_I2C1
-#else
#define USE_I2C
#define USE_I2C_DEVICE_2
#define I2C_DEVICE_2_SHARES_UART3
#define I2C_EXT_BUS BUS_I2C2
-#endif
#define UG2864_I2C_BUS I2C_EXT_BUS
#define MPU6000_CS_PIN PA4
#define MPU6000_SPI_BUS BUS_SPI1
-#if defined(OMNIBUSF4V3_ICM)
- #define USE_IMU_ICM42605
- #define IMU_ICM42605_ALIGN CW180_DEG
- #define ICM42605_CS_PIN PA4
- #define ICM42605_SPI_BUS BUS_SPI1
-#endif
-
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define USE_IMU_MPU6000
- #define IMU_MPU6000_ALIGN CW270_DEG
-#else
- #define USE_IMU_MPU6000
- #define IMU_MPU6000_ALIGN CW180_DEG
-#endif
-
-// Support for OMNIBUS F4 PRO CORNER - it has MPU6500/ICM20608 instead of MPU6000
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define MPU6500_CS_PIN MPU6000_CS_PIN
- #define MPU6500_SPI_BUS MPU6000_SPI_BUS
- #define USE_IMU_MPU6500
- #define IMU_MPU6500_ALIGN IMU_MPU6000_ALIGN
-
- //BMI270
- #define USE_IMU_BMI270
- #define IMU_BMI270_ALIGN IMU_MPU6000_ALIGN
- #define BMI270_SPI_BUS MPU6000_SPI_BUS
- #define BMI270_CS_PIN MPU6000_CS_PIN
-#endif
+#define USE_IMU_MPU6000
+#define IMU_MPU6000_ALIGN CW180_DEG
#define USE_MAG
#define MAG_I2C_BUS I2C_EXT_BUS
@@ -105,21 +46,10 @@
#define TEMPERATURE_I2C_BUS I2C_EXT_BUS
#define USE_BARO
-
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define USE_BARO_BMP280
- #define BMP280_SPI_BUS BUS_SPI3
- #define BMP280_CS_PIN PB3 // v1
- // Support external barometers
- #define BARO_I2C_BUS I2C_EXT_BUS
- #define USE_BARO_BMP085
- #define USE_BARO_MS5611
-#else
- #define BARO_I2C_BUS I2C_EXT_BUS
- #define USE_BARO_BMP085
- #define USE_BARO_BMP280
- #define USE_BARO_MS5611
-#endif
+#define BARO_I2C_BUS I2C_EXT_BUS
+#define USE_BARO_BMP085
+#define USE_BARO_BMP280
+#define USE_BARO_MS5611
#define PITOT_I2C_BUS I2C_EXT_BUS
@@ -130,17 +60,11 @@
#define VBUS_SENSING_PIN PC5
#define VBUS_SENSING_ENABLED
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
-#define USE_UART_INVERTER
-#endif
#define USE_UART1
#define UART1_RX_PIN PA10
#define UART1_TX_PIN PA9
#define UART1_AHB1_PERIPHERALS RCC_AHB1Periph_DMA2
-#if defined(OMNIBUSF4PRO)
-#define INVERTER_PIN_UART1_RX PC0 // PC0 has never been used as inverter control on genuine OMNIBUS F4 variants, but leave it as is since some clones actually implement it.
-#endif
#define USE_UART3
#define UART3_RX_PIN PB11
@@ -149,51 +73,13 @@
#define USE_UART6
#define UART6_RX_PIN PC7
#define UART6_TX_PIN PC6
-#if defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define INVERTER_PIN_UART6_RX PC8
- #define INVERTER_PIN_UART6_TX PC9
-#endif
-
-#if (defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)) && !(defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS))
-#define USE_SOFTSERIAL1
-#define SOFTSERIAL_1_RX_PIN PC6 // shared with UART6 TX
-#define SOFTSERIAL_1_TX_PIN PC6 // shared with UART6 TX
-
-#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
-#elif defined(OMNIBUSF4V3_S6_SS) // one softserial on S6
#define USE_SOFTSERIAL1
-#define SOFTSERIAL_1_RX_PIN PA8 // S6 output
-#define SOFTSERIAL_1_TX_PIN PA8 // S6 output
+#define SOFTSERIAL_1_RX_PIN PC8
+#define SOFTSERIAL_1_TX_PIN PC9
#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
-#elif defined(OMNIBUSF4V3_S5S6_SS) // one softserial on S5/RX S6/TX
-#define USE_SOFTSERIAL1
-#define SOFTSERIAL_1_RX_PIN PA1 // S5 output
-#define SOFTSERIAL_1_TX_PIN PA8 // S6 output
-
-#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
-
-#elif defined(OMNIBUSF4V3_S5_S6_2SS) // two softserials, one on S5 and one on S6
-#define USE_SOFTSERIAL1
-#define SOFTSERIAL_1_RX_PIN PA1 // S5 output
-#define SOFTSERIAL_1_TX_PIN PA1 // S5 output
-
-#define USE_SOFTSERIAL2
-#define SOFTSERIAL_2_RX_PIN PA8 // S6 output
-#define SOFTSERIAL_2_TX_PIN PA8 // S6 output
-
-#define SERIAL_PORT_COUNT 6 // VCP, USART1, USART3, USART6, SOFTSERIAL1, SOFTSERIAL2
-
-#else // One softserial on versions other than OMNIBUSF4V3
-#define USE_SOFTSERIAL1
-#define SOFTSERIAL_1_RX_PIN PC8 // pad labelled CH5 on OMNIBUSF4PRO
-#define SOFTSERIAL_1_TX_PIN PC9 // pad labelled CH6 on OMNIBUSF4PRO
-
-#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
-#endif
-
#define DEFAULT_RX_TYPE RX_TYPE_SERIAL
#define SERIALRX_PROVIDER SERIALRX_SBUS
#define SERIALRX_UART SERIAL_PORT_USART1
@@ -202,20 +88,8 @@
#define USE_SPI_DEVICE_1
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define USE_SPI_DEVICE_2
- #define SPI2_NSS_PIN PB12
- #define SPI2_SCK_PIN PB13
- #define SPI2_MISO_PIN PB14
- #define SPI2_MOSI_PIN PB15
-#endif
-
#define USE_SPI_DEVICE_3
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define SPI3_NSS_PIN PA15
-#else
- #define SPI3_NSS_PIN PB3
-#endif
+#define SPI3_NSS_PIN PB3
#define SPI3_SCK_PIN PC10
#define SPI3_MISO_PIN PC11
#define SPI3_MOSI_PIN PC12
@@ -224,33 +98,16 @@
#define MAX7456_SPI_BUS BUS_SPI3
#define MAX7456_CS_PIN PA15
-#if defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)
- #define ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT
- #define USE_SDCARD
- #define USE_SDCARD_SPI
-
- #define SDCARD_SPI_BUS BUS_SPI2
- #define SDCARD_CS_PIN SPI2_NSS_PIN
-
- #define SDCARD_DETECT_PIN PB7
- #define SDCARD_DETECT_INVERTED
-#else
- #define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
- #define M25P16_CS_PIN SPI3_NSS_PIN
- #define M25P16_SPI_BUS BUS_SPI3
- #define USE_FLASHFS
- #define USE_FLASH_M25P16
-#endif
+#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
+#define M25P16_CS_PIN SPI3_NSS_PIN
+#define M25P16_SPI_BUS BUS_SPI3
+#define USE_FLASHFS
+#define USE_FLASH_M25P16
#define USE_ADC
#define ADC_CHANNEL_1_PIN PC1
#define ADC_CHANNEL_2_PIN PC2
-
-#ifdef DYSF4PRO
- #define ADC_CHANNEL_3_PIN PC3
-#else
- #define ADC_CHANNEL_3_PIN PA0
-#endif
+#define ADC_CHANNEL_3_PIN PA0
#define CURRENT_METER_ADC_CHANNEL ADC_CHN_1
#define VBAT_ADC_CHANNEL ADC_CHN_2
@@ -259,11 +116,7 @@
#define SENSORS_SET (SENSOR_ACC|SENSOR_MAG|SENSOR_BARO)
#define USE_LED_STRIP
-#if (defined(OMNIBUSF4PRO) || defined(OMNIBUSF4V3) || defined(OMNIBUSF4V3_ICM)) && !defined(OMNIBUSF4PRO_LEDSTRIPM5)
- #define WS2811_PIN PB6
-#else
- #define WS2811_PIN PA1
-#endif
+#define WS2811_PIN PA1
#define DISABLE_RX_PWM_FEATURE
#define DEFAULT_FEATURES (FEATURE_TX_PROF_SEL | FEATURE_BLACKBOX | FEATURE_VBAT | FEATURE_OSD)
@@ -283,7 +136,3 @@
#define TARGET_IO_PORTB 0xffff
#define TARGET_IO_PORTC 0xffff
#define TARGET_IO_PORTD 0xffff
-
-#ifdef OMNIBUSF4PRO
-#define CURRENT_METER_SCALE 265
-#endif
diff --git a/src/main/target/OMNIBUSF4PRO/CMakeLists.txt b/src/main/target/OMNIBUSF4PRO/CMakeLists.txt
new file mode 100644
index 00000000000..e09984ac0a9
--- /dev/null
+++ b/src/main/target/OMNIBUSF4PRO/CMakeLists.txt
@@ -0,0 +1,5 @@
+# OMNIBUSF4PRO has SD card, BMP280 baro
+target_stm32f405xg(OMNIBUSF4PRO)
+# OMNIBUSF4V3 is similar to PRO but with UART6 inverter
+target_stm32f405xg(OMNIBUSF4V3)
+target_stm32f405xg(OMNIBUSF4V3_ICM SKIP_RELEASES)
diff --git a/src/main/target/OMNIBUSF4PRO/target.c b/src/main/target/OMNIBUSF4PRO/target.c
new file mode 100644
index 00000000000..29cb945af85
--- /dev/null
+++ b/src/main/target/OMNIBUSF4PRO/target.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#include
+
+#include
+#include "drivers/io.h"
+#include "drivers/pwm_mapping.h"
+#include "drivers/timer.h"
+#include "drivers/bus.h"
+
+timerHardware_t timerHardware[] = {
+
+ DEF_TIM(TIM3, CH3, PB0, TIM_USE_OUTPUT_AUTO, 0, 0), // S1_OUT D1_ST7
+ DEF_TIM(TIM3, CH4, PB1, TIM_USE_OUTPUT_AUTO, 0, 0), // S2_OUT D1_ST2
+ DEF_TIM(TIM2, CH4, PA3, TIM_USE_OUTPUT_AUTO, 0, 1), // S3_OUT D1_ST6
+ DEF_TIM(TIM2, CH3, PA2, TIM_USE_OUTPUT_AUTO, 0, 0), // S4_OUT D1_ST1
+
+ // { TIM9, IO_TAG(PA3), TIM_Channel_2, 1, IOCFG_AF_PP_PD, GPIO_AF_TIM9, TIM_USE_OUTPUT_AUTO }, // MOTOR_3
+ DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_OUTPUT_AUTO, 0, 0), // S6_OUT
+
+ DEF_TIM(TIM4, CH1, PB6, TIM_USE_LED, 0, 0), // LED strip for F4 V2 / F4-Pro-0X and later (RCD_CS for F4)
+
+ // DEF_TIM(TIM10, CH1, PB8, TIM_USE_PPM, 0, 0), // PPM
+ DEF_TIM(TIM4, CH4, PB9, TIM_USE_ANY, 0, 0), // S2_IN
+ DEF_TIM(TIM8, CH1, PC6, TIM_USE_ANY, 0, 0), // S3_IN, UART6_TX
+ DEF_TIM(TIM8, CH2, PC7, TIM_USE_ANY, 0, 0), // S4_IN, UART6_RX
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_ANY, 0, 0), // S5_IN // pad labelled CH5 on OMNIBUSF4PRO
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_ANY, 0, 0), // S6_IN // pad labelled CH6 on OMNIBUSF4PRO
+
+};
+
+const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);
diff --git a/src/main/target/OMNIBUSF4PRO/target.h b/src/main/target/OMNIBUSF4PRO/target.h
new file mode 100644
index 00000000000..f9d7e3af4de
--- /dev/null
+++ b/src/main/target/OMNIBUSF4PRO/target.h
@@ -0,0 +1,202 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#pragma once
+
+// This directory contains: OMNIBUSF4PRO, OMNIBUSF4V3, OMNIBUSF4V3_ICM
+// Softserial variants are in separate OMNIBUSF4V3_SS/ directory
+
+#ifdef OMNIBUSF4V3_ICM
+#define OMNIBUSF4V3
+#endif
+
+#ifdef OMNIBUSF4PRO
+#define TARGET_BOARD_IDENTIFIER "OBSD"
+#elif defined(OMNIBUSF4V3)
+#define TARGET_BOARD_IDENTIFIER "OB43"
+#endif
+
+#define USBD_PRODUCT_STRING "Omnibus F4"
+
+#define LED0 PB5
+
+#define BEEPER PB4
+#define BEEPER_INVERTED
+
+#define USE_I2C
+#define USE_I2C_DEVICE_2
+#define I2C_DEVICE_2_SHARES_UART3
+#define I2C_EXT_BUS BUS_I2C2
+
+#define UG2864_I2C_BUS I2C_EXT_BUS
+
+#define MPU6000_CS_PIN PA4
+#define MPU6000_SPI_BUS BUS_SPI1
+
+#define USE_IMU_MPU6000
+#define IMU_MPU6000_ALIGN CW270_DEG
+
+// Support for OMNIBUS F4 PRO CORNER - it has ICM20608 instead of MPU6000
+#define MPU6500_CS_PIN MPU6000_CS_PIN
+#define MPU6500_SPI_BUS MPU6000_SPI_BUS
+#define USE_IMU_MPU6500
+#define IMU_MPU6500_ALIGN IMU_MPU6000_ALIGN
+
+//BMI270
+#define USE_IMU_BMI270
+#define IMU_BMI270_ALIGN IMU_MPU6000_ALIGN
+#define BMI270_SPI_BUS MPU6000_SPI_BUS
+#define BMI270_CS_PIN MPU6000_CS_PIN
+
+#ifdef OMNIBUSF4V3_ICM
+#define USE_IMU_ICM42605
+#define IMU_ICM42605_ALIGN CW180_DEG
+#define ICM42605_CS_PIN PA4
+#define ICM42605_SPI_BUS BUS_SPI1
+#endif
+
+#define USE_MAG
+#define MAG_I2C_BUS I2C_EXT_BUS
+#define USE_MAG_ALL
+
+#define TEMPERATURE_I2C_BUS I2C_EXT_BUS
+
+#define USE_BARO
+#define USE_BARO_BMP280
+#define BMP280_SPI_BUS BUS_SPI3
+#define BMP280_CS_PIN PB3 // v1
+// Support external barometers
+#define BARO_I2C_BUS I2C_EXT_BUS
+#define USE_BARO_BMP085
+#define USE_BARO_MS5611
+
+#define PITOT_I2C_BUS I2C_EXT_BUS
+
+#define USE_RANGEFINDER
+#define RANGEFINDER_I2C_BUS I2C_EXT_BUS
+
+#define USE_VCP
+#define VBUS_SENSING_PIN PC5
+#define VBUS_SENSING_ENABLED
+
+#define USE_UART_INVERTER
+
+#define USE_UART1
+#define UART1_RX_PIN PA10
+#define UART1_TX_PIN PA9
+#define UART1_AHB1_PERIPHERALS RCC_AHB1Periph_DMA2
+#if defined(OMNIBUSF4PRO)
+#define INVERTER_PIN_UART1_RX PC0 // PC0 has never been used as inverter control on genuine OMNIBUS F4 variants, but leave it as is since some clones actually implement it.
+#endif
+
+#define USE_UART3
+#define UART3_RX_PIN PB11
+#define UART3_TX_PIN PB10
+
+#define USE_UART6
+#define UART6_RX_PIN PC7
+#define UART6_TX_PIN PC6
+#if defined(OMNIBUSF4V3)
+ #define INVERTER_PIN_UART6_RX PC8
+ #define INVERTER_PIN_UART6_TX PC9
+#endif
+
+#if defined(OMNIBUSF4V3)
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PC6 // shared with UART6 TX
+#define SOFTSERIAL_1_TX_PIN PC6 // shared with UART6 TX
+
+#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
+
+#else // OMNIBUSF4PRO
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PC8 // pad labelled CH5 on OMNIBUSF4PRO
+#define SOFTSERIAL_1_TX_PIN PC9 // pad labelled CH6 on OMNIBUSF4PRO
+
+#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
+#endif
+
+#define DEFAULT_RX_TYPE RX_TYPE_SERIAL
+#define SERIALRX_PROVIDER SERIALRX_SBUS
+#define SERIALRX_UART SERIAL_PORT_USART1
+
+#define USE_SPI
+
+#define USE_SPI_DEVICE_1
+
+#define USE_SPI_DEVICE_2
+#define SPI2_NSS_PIN PB12
+#define SPI2_SCK_PIN PB13
+#define SPI2_MISO_PIN PB14
+#define SPI2_MOSI_PIN PB15
+
+#define USE_SPI_DEVICE_3
+#define SPI3_NSS_PIN PA15
+#define SPI3_SCK_PIN PC10
+#define SPI3_MISO_PIN PC11
+#define SPI3_MOSI_PIN PC12
+
+#define USE_MAX7456
+#define MAX7456_SPI_BUS BUS_SPI3
+#define MAX7456_CS_PIN PA15
+
+#define ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT
+#define USE_SDCARD
+#define USE_SDCARD_SPI
+
+#define SDCARD_SPI_BUS BUS_SPI2
+#define SDCARD_CS_PIN SPI2_NSS_PIN
+
+#define SDCARD_DETECT_PIN PB7
+#define SDCARD_DETECT_INVERTED
+
+#define USE_ADC
+#define ADC_CHANNEL_1_PIN PC1
+#define ADC_CHANNEL_2_PIN PC2
+#define ADC_CHANNEL_3_PIN PA0
+
+#define CURRENT_METER_ADC_CHANNEL ADC_CHN_1
+#define VBAT_ADC_CHANNEL ADC_CHN_2
+#define RSSI_ADC_CHANNEL ADC_CHN_3
+
+#define SENSORS_SET (SENSOR_ACC|SENSOR_MAG|SENSOR_BARO)
+
+#define USE_LED_STRIP
+#define WS2811_PIN PB6
+
+#define DISABLE_RX_PWM_FEATURE
+#define DEFAULT_FEATURES (FEATURE_TX_PROF_SEL | FEATURE_BLACKBOX | FEATURE_VBAT | FEATURE_OSD)
+
+#define USE_SPEKTRUM_BIND
+#define BIND_PIN PB11 // USART3 RX
+
+#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+
+// Number of available PWM outputs
+#define MAX_PWM_OUTPUT_PORTS 6
+#define TARGET_MOTOR_COUNT 6
+#define USE_DSHOT
+#define USE_ESC_SENSOR
+
+#define TARGET_IO_PORTA 0xffff
+#define TARGET_IO_PORTB 0xffff
+#define TARGET_IO_PORTC 0xffff
+#define TARGET_IO_PORTD 0xffff
+
+#ifdef OMNIBUSF4PRO
+#define CURRENT_METER_SCALE 265
+#endif
diff --git a/src/main/target/OMNIBUSF4V3_SS/CMakeLists.txt b/src/main/target/OMNIBUSF4V3_SS/CMakeLists.txt
new file mode 100644
index 00000000000..321eeb211d1
--- /dev/null
+++ b/src/main/target/OMNIBUSF4V3_SS/CMakeLists.txt
@@ -0,0 +1,4 @@
+# OMNIBUSF4V3 softserial variants with different S5/S6 timer configurations
+target_stm32f405xg(OMNIBUSF4V3_S6_SS)
+target_stm32f405xg(OMNIBUSF4V3_S5S6_SS)
+target_stm32f405xg(OMNIBUSF4V3_S5_S6_2SS)
diff --git a/src/main/target/OMNIBUSF4V3_SS/target.c b/src/main/target/OMNIBUSF4V3_SS/target.c
new file mode 100644
index 00000000000..95b496e8bfb
--- /dev/null
+++ b/src/main/target/OMNIBUSF4V3_SS/target.c
@@ -0,0 +1,53 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#include
+
+#include
+#include "drivers/io.h"
+#include "drivers/pwm_mapping.h"
+#include "drivers/timer.h"
+#include "drivers/bus.h"
+
+timerHardware_t timerHardware[] = {
+
+ DEF_TIM(TIM3, CH3, PB0, TIM_USE_OUTPUT_AUTO, 0, 0), // S1_OUT D1_ST7
+ DEF_TIM(TIM3, CH4, PB1, TIM_USE_OUTPUT_AUTO, 0, 0), // S2_OUT D1_ST2
+ DEF_TIM(TIM2, CH4, PA3, TIM_USE_OUTPUT_AUTO, 0, 1), // S3_OUT D1_ST6
+ DEF_TIM(TIM2, CH3, PA2, TIM_USE_OUTPUT_AUTO, 0, 0), // S4_OUT D1_ST1
+
+ // { TIM9, IO_TAG(PA3), TIM_Channel_2, 1, IOCFG_AF_PP_PD, GPIO_AF_TIM9, TIM_USE_OUTPUT_AUTO }, // MOTOR_3
+#if defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
+ DEF_TIM(TIM5, CH2, PA1, TIM_USE_ANY, 0, 0), // S5_OUT SOFTSERIAL
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_ANY, 0, 0), // S6_OUT SOFTSERIAL
+#elif defined(OMNIBUSF4V3_S6_SS)
+ DEF_TIM(TIM5, CH2, PA1, TIM_USE_OUTPUT_AUTO, 0, 0), // S5_OUT
+ DEF_TIM(TIM1, CH1, PA8, TIM_USE_ANY, 0, 0), // S6_OUT SOFTSERIAL
+#endif
+
+ DEF_TIM(TIM4, CH1, PB6, TIM_USE_LED, 0, 0), // LED strip for F4 V2 / F4-Pro-0X and later (RCD_CS for F4)
+
+ // DEF_TIM(TIM10, CH1, PB8, TIM_USE_PPM, 0, 0), // PPM
+ DEF_TIM(TIM4, CH4, PB9, TIM_USE_ANY, 0, 0), // S2_IN
+ DEF_TIM(TIM8, CH1, PC6, TIM_USE_ANY, 0, 0), // S3_IN, UART6_TX
+ DEF_TIM(TIM8, CH2, PC7, TIM_USE_ANY, 0, 0), // S4_IN, UART6_RX
+ DEF_TIM(TIM8, CH3, PC8, TIM_USE_ANY, 0, 0), // S5_IN
+ DEF_TIM(TIM8, CH4, PC9, TIM_USE_ANY, 0, 0), // S6_IN
+
+};
+
+const int timerHardwareCount = sizeof(timerHardware) / sizeof(timerHardware[0]);
diff --git a/src/main/target/OMNIBUSF4V3_SS/target.h b/src/main/target/OMNIBUSF4V3_SS/target.h
new file mode 100644
index 00000000000..f3cbf6c4a49
--- /dev/null
+++ b/src/main/target/OMNIBUSF4V3_SS/target.h
@@ -0,0 +1,193 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#pragma once
+
+// This directory contains: OMNIBUSF4V3_S6_SS, OMNIBUSF4V3_S5S6_SS, OMNIBUSF4V3_S5_S6_2SS
+// Softserial variants of OMNIBUSF4V3 with different S5/S6 timer configurations
+#if defined(OMNIBUSF4V3_S6_SS) || defined(OMNIBUSF4V3_S5S6_SS) || defined(OMNIBUSF4V3_S5_S6_2SS)
+#define OMNIBUSF4V3
+#endif
+
+#define TARGET_BOARD_IDENTIFIER "OB43"
+
+#define USBD_PRODUCT_STRING "Omnibus F4"
+
+#define LED0 PB5
+
+#define BEEPER PB4
+#define BEEPER_INVERTED
+
+#define USE_I2C
+#define USE_I2C_DEVICE_2
+#define I2C_DEVICE_2_SHARES_UART3
+#define I2C_EXT_BUS BUS_I2C2
+
+#define UG2864_I2C_BUS I2C_EXT_BUS
+
+#define MPU6000_CS_PIN PA4
+#define MPU6000_SPI_BUS BUS_SPI1
+
+#define USE_IMU_MPU6000
+#define IMU_MPU6000_ALIGN CW270_DEG
+
+// Support for OMNIBUS F4 PRO CORNER - it has ICM20608 instead of MPU6000
+#define MPU6500_CS_PIN MPU6000_CS_PIN
+#define MPU6500_SPI_BUS MPU6000_SPI_BUS
+#define USE_IMU_MPU6500
+#define IMU_MPU6500_ALIGN IMU_MPU6000_ALIGN
+
+//BMI270
+#define USE_IMU_BMI270
+#define IMU_BMI270_ALIGN IMU_MPU6000_ALIGN
+#define BMI270_SPI_BUS MPU6000_SPI_BUS
+#define BMI270_CS_PIN MPU6000_CS_PIN
+
+#define USE_MAG
+#define MAG_I2C_BUS I2C_EXT_BUS
+#define USE_MAG_ALL
+
+#define TEMPERATURE_I2C_BUS I2C_EXT_BUS
+
+#define USE_BARO
+#define USE_BARO_BMP280
+#define BMP280_SPI_BUS BUS_SPI3
+#define BMP280_CS_PIN PB3 // v1
+// Support external barometers
+#define BARO_I2C_BUS I2C_EXT_BUS
+#define USE_BARO_BMP085
+#define USE_BARO_MS5611
+
+#define PITOT_I2C_BUS I2C_EXT_BUS
+
+#define USE_RANGEFINDER
+#define RANGEFINDER_I2C_BUS I2C_EXT_BUS
+
+#define USE_VCP
+#define VBUS_SENSING_PIN PC5
+#define VBUS_SENSING_ENABLED
+
+#define USE_UART_INVERTER
+
+#define USE_UART1
+#define UART1_RX_PIN PA10
+#define UART1_TX_PIN PA9
+#define UART1_AHB1_PERIPHERALS RCC_AHB1Periph_DMA2
+
+#define USE_UART3
+#define UART3_RX_PIN PB11
+#define UART3_TX_PIN PB10
+
+#define USE_UART6
+#define UART6_RX_PIN PC7
+#define UART6_TX_PIN PC6
+#define INVERTER_PIN_UART6_RX PC8
+#define INVERTER_PIN_UART6_TX PC9
+
+#if defined(OMNIBUSF4V3_S6_SS) // one softserial on S6
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PA8 // S6 output
+#define SOFTSERIAL_1_TX_PIN PA8 // S6 output
+
+#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
+
+#elif defined(OMNIBUSF4V3_S5S6_SS) // one softserial on S5/RX S6/TX
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PA1 // S5 output
+#define SOFTSERIAL_1_TX_PIN PA8 // S6 output
+
+#define SERIAL_PORT_COUNT 5 // VCP, USART1, USART3, USART6, SOFTSERIAL1
+
+#elif defined(OMNIBUSF4V3_S5_S6_2SS) // two softserials, one on S5 and one on S6
+#define USE_SOFTSERIAL1
+#define SOFTSERIAL_1_RX_PIN PA1 // S5 output
+#define SOFTSERIAL_1_TX_PIN PA1 // S5 output
+
+#define USE_SOFTSERIAL2
+#define SOFTSERIAL_2_RX_PIN PA8 // S6 output
+#define SOFTSERIAL_2_TX_PIN PA8 // S6 output
+
+#define SERIAL_PORT_COUNT 6 // VCP, USART1, USART3, USART6, SOFTSERIAL1, SOFTSERIAL2
+#endif
+
+#define DEFAULT_RX_TYPE RX_TYPE_SERIAL
+#define SERIALRX_PROVIDER SERIALRX_SBUS
+#define SERIALRX_UART SERIAL_PORT_USART1
+
+#define USE_SPI
+
+#define USE_SPI_DEVICE_1
+
+#define USE_SPI_DEVICE_2
+#define SPI2_NSS_PIN PB12
+#define SPI2_SCK_PIN PB13
+#define SPI2_MISO_PIN PB14
+#define SPI2_MOSI_PIN PB15
+
+#define USE_SPI_DEVICE_3
+#define SPI3_NSS_PIN PA15
+#define SPI3_SCK_PIN PC10
+#define SPI3_MISO_PIN PC11
+#define SPI3_MOSI_PIN PC12
+
+#define USE_MAX7456
+#define MAX7456_SPI_BUS BUS_SPI3
+#define MAX7456_CS_PIN PA15
+
+#define ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT
+#define USE_SDCARD
+#define USE_SDCARD_SPI
+
+#define SDCARD_SPI_BUS BUS_SPI2
+#define SDCARD_CS_PIN SPI2_NSS_PIN
+
+#define SDCARD_DETECT_PIN PB7
+#define SDCARD_DETECT_INVERTED
+
+#define USE_ADC
+#define ADC_CHANNEL_1_PIN PC1
+#define ADC_CHANNEL_2_PIN PC2
+#define ADC_CHANNEL_3_PIN PA0
+
+#define CURRENT_METER_ADC_CHANNEL ADC_CHN_1
+#define VBAT_ADC_CHANNEL ADC_CHN_2
+#define RSSI_ADC_CHANNEL ADC_CHN_3
+
+#define SENSORS_SET (SENSOR_ACC|SENSOR_MAG|SENSOR_BARO)
+
+#define USE_LED_STRIP
+#define WS2811_PIN PB6
+
+#define DISABLE_RX_PWM_FEATURE
+#define DEFAULT_FEATURES (FEATURE_TX_PROF_SEL | FEATURE_BLACKBOX | FEATURE_VBAT | FEATURE_OSD)
+
+#define USE_SPEKTRUM_BIND
+#define BIND_PIN PB11 // USART3 RX
+
+#define USE_SERIAL_4WAY_BLHELI_INTERFACE
+
+// Number of available PWM outputs
+#define MAX_PWM_OUTPUT_PORTS 6
+#define TARGET_MOTOR_COUNT 6
+#define USE_DSHOT
+#define USE_ESC_SENSOR
+
+#define TARGET_IO_PORTA 0xffff
+#define TARGET_IO_PORTB 0xffff
+#define TARGET_IO_PORTC 0xffff
+#define TARGET_IO_PORTD 0xffff
+