diff --git a/firmware/console/binary/output_channels.txt b/firmware/console/binary/output_channels.txt index 40e862e249..92da36fa44 100644 --- a/firmware/console/binary/output_channels.txt +++ b/firmware/console/binary/output_channels.txt @@ -321,6 +321,8 @@ uint16_t rpmAcceleration;dRPM;"RPM/s",1, 0, 0, 5, 2 int16_t[LUA_DIGITAL_INPUT_COUNT iterate] autoscale rawAnalogInput;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3 uint8_t[4 iterate] autoscale gppwmOutput;GPPWM Output;"%", 0.5, 0, 0, 100, 2 + int16_t[4 iterate] autoscale gppwmXAxis;;"", 1, 0, -30000, 30000, 0 + int16_t[4 iterate] autoscale gppwmYAxis;;"", 0.1, 0, -1000, 1000, 1 int16_t autoscale rawBattery;;"V",{1/@@PACK_MULT_VOLTAGE@@}, 0, 0, 5, 3 diff --git a/firmware/controllers/actuators/gppwm/gppwm.cpp b/firmware/controllers/actuators/gppwm/gppwm.cpp index 8f0a6de087..2cfbc67165 100644 --- a/firmware/controllers/actuators/gppwm/gppwm.cpp +++ b/firmware/controllers/actuators/gppwm/gppwm.cpp @@ -58,8 +58,10 @@ void updateGppwm() { static_assert(efi::size(channels) <= 8); for (size_t i = 0; i < efi::size(channels); i++) { - float result = channels[i].update(); + auto result = channels[i].update(); - engine->outputChannels.gppwmOutput[i] = result; + engine->outputChannels.gppwmOutput[i] = result.Result; + engine->outputChannels.gppwmXAxis[i] = result.X; + engine->outputChannels.gppwmYAxis[i] = result.X; } } diff --git a/firmware/controllers/actuators/gppwm/gppwm_channel.cpp b/firmware/controllers/actuators/gppwm/gppwm_channel.cpp index 9746099393..7d394de45e 100644 --- a/firmware/controllers/actuators/gppwm/gppwm_channel.cpp +++ b/firmware/controllers/actuators/gppwm/gppwm_channel.cpp @@ -10,6 +10,8 @@ expected readGppwmChannel(gppwm_channel_e channel) { switch (channel) { case GPPWM_Zero: return 0; + case GPPWM_Rpm: + return Sensor::get(SensorType::Rpm); case GPPWM_Tps: return Sensor::get(SensorType::Tps1); case GPPWM_Map: @@ -109,31 +111,35 @@ void GppwmChannel::init(bool usePwm, IPwm* pwm, OutputPin* outputPin, const Valu m_config = config; } -percent_t GppwmChannel::getOutput() const { - expected loadAxisValue = readGppwmChannel(m_config->loadAxis); +GppwmResult GppwmChannel::getOutput() const { + expected xAxisValue = readGppwmChannel(m_config->rpmAxis); + expected yAxisValue = readGppwmChannel(m_config->loadAxis); + + GppwmResult result { (float)m_config->dutyIfError, xAxisValue.value_or(0), yAxisValue.value_or(0) }; // If we couldn't get load axis value, fall back on error value - if (!loadAxisValue) { - return m_config->dutyIfError; + if (!xAxisValue || !yAxisValue) { + return result; } - float rpm = Sensor::getOrZero(SensorType::Rpm); + float resultVal = m_table->getValue(xAxisValue.Value, yAxisValue.Value); - float result = m_table->getValue(rpm, loadAxisValue.Value); - - if (cisnan(result)) { - return m_config->dutyIfError; + if (cisnan(result.Result)) { + return result; } + result.Result = resultVal; return result; } -float GppwmChannel::update() { +GppwmResult GppwmChannel::update() { // Without a config, nothing to do. if (!m_config) { - return 0; + return {}; } - float output = getOutput(); - return setOutput(output); + auto output = getOutput(); + output.Result = setOutput(output.Result); + + return output; } diff --git a/firmware/controllers/actuators/gppwm/gppwm_channel.h b/firmware/controllers/actuators/gppwm/gppwm_channel.h index de3da9eee2..7933b6087b 100644 --- a/firmware/controllers/actuators/gppwm/gppwm_channel.h +++ b/firmware/controllers/actuators/gppwm/gppwm_channel.h @@ -9,11 +9,17 @@ class OutputPin; struct IPwm; class ValueProvider3D; +struct GppwmResult { + percent_t Result; + float X; + float Y; +}; + class GppwmChannel { public: void init(bool usePwm, IPwm* pwm, OutputPin* outputPin, const ValueProvider3D* table, const gppwm_channel* config); - float update(); - percent_t getOutput() const; + GppwmResult update(); + GppwmResult getOutput() const; // Returns actual output duty, with hysteresis applied float setOutput(float result); diff --git a/firmware/controllers/algo/engine_configuration.cpp b/firmware/controllers/algo/engine_configuration.cpp index 94244d82b1..d78ab1f245 100644 --- a/firmware/controllers/algo/engine_configuration.cpp +++ b/firmware/controllers/algo/engine_configuration.cpp @@ -333,6 +333,10 @@ void setDefaultGppwmParameters() { auto& cfg = engineConfiguration->gppwm[i]; chsnprintf(engineConfiguration->gpPwmNote[i], sizeof(engineConfiguration->gpPwmNote[0]), "GPPWM%d", i); + // Set default axes + cfg.loadAxis = GPPWM_Zero; + cfg.rpmAxis = GPPWM_Rpm; + cfg.pin = Gpio::Unassigned; cfg.dutyIfError = 0; cfg.onAboveDuty = 60; diff --git a/firmware/controllers/algo/rusefi_enums.h b/firmware/controllers/algo/rusefi_enums.h index 8bdfe45482..f556991b85 100644 --- a/firmware/controllers/algo/rusefi_enums.h +++ b/firmware/controllers/algo/rusefi_enums.h @@ -563,6 +563,7 @@ typedef enum __attribute__ ((__packed__)) { GPPWM_GppwmOutput4 = 21, GPPWM_LuaGauge1 = 22, GPPWM_LuaGauge2 = 23, + GPPWM_Rpm = 24, } gppwm_channel_e; typedef enum __attribute__ ((__packed__)) { diff --git a/firmware/integration/rusefi_config.txt b/firmware/integration/rusefi_config.txt index 761155b1c1..397797ecd1 100644 --- a/firmware/integration/rusefi_config.txt +++ b/firmware/integration/rusefi_config.txt @@ -93,7 +93,7 @@ ! Any time an incompatible change is made to the configuration format stored in flash, ! update this string to the current date! It is required to also update TS_SIGNATURE above ! when this happens. -#define FLASH_DATA_VERSION 10018 +#define FLASH_DATA_VERSION 10019 ! this offset is part of console compatibility mechanism, please DO NOT change this offset #define TS_FILE_VERSION_OFFSET 124 @@ -349,7 +349,7 @@ struct spi_pins end_struct -#define gppwm_channel_e_enum "Zero", "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "Aux Temp 1", "Aux Temp 2", "Accel Pedal", "Battery Voltage", "VVT 1 I", "VVT 1 E", "VVT 2 I", "VVT 2 E", "Ethanol (Flex) %", "Aux Linear 1", "Aux Linear 2", "GPPWM Output 1", "GPPWM Output 2", "GPPWM Output 3", "GPPWM Output 4", "Lua Gauge 1", "Lua Gauge 2" +#define gppwm_channel_e_enum "Zero", "TPS", "MAP", "CLT", "IAT", "Fuel Load", "Ignition Load", "Aux Temp 1", "Aux Temp 2", "Accel Pedal", "Battery Voltage", "VVT 1 I", "VVT 1 E", "VVT 2 I", "VVT 2 E", "Ethanol (Flex) %", "Aux Linear 1", "Aux Linear 2", "GPPWM Output 1", "GPPWM Output 2", "GPPWM Output 3", "GPPWM Output 4", "Lua Gauge 1", "Lua Gauge 2", "RPM" custom gppwm_channel_e 1 bits, U08, @OFFSET@, [0:4], @@gppwm_channel_e_enum@@ struct gppwm_channel @@ -360,12 +360,12 @@ struct gppwm_channel uint8_t onAboveDuty;Hysteresis: in on-off mode, turn the output on when the table value is above this duty.;"%", 1, 0, 0, 100, 0 uint8_t offBelowDuty;Hysteresis: in on-off mode, turn the output off when the table value is below this duty.;"%", 1, 0, 0, 100, 0 - gppwm_channel_e loadAxis;Selects the load axis to use for the table.; - uint8_t alignmentFill_map;;"unit", 1, 0, 0, 100, 0 + gppwm_channel_e loadAxis;Selects the Y axis to use for the table.; + gppwm_channel_e rpmAxis;Selects the X axis to use for the table.; - uint8_t[GPPWM_LOAD_COUNT] loadBins;;"load", 1, 0, 0, 250, 0 - uint8_t[GPPWM_RPM_COUNT] autoscale rpmBins;;"RPM", 100, 0, 0, 25000, 0 - uint8_t[GPPWM_RPM_COUNT x GPPWM_LOAD_COUNT] table;;"duty", 1, 0, 0, 100, 0 + int16_t[GPPWM_LOAD_COUNT] autoscale loadBins;;"load", 0.1, 0, -1000, 1000, 1 + int16_t[GPPWM_RPM_COUNT] autoscale rpmBins;;"RPM", 1, 0, -30000, 30000, 0 + uint8_t[GPPWM_RPM_COUNT x GPPWM_LOAD_COUNT] autoscale table;;"duty", 0.5, 0, 0, 100, 1 end_struct custom air_pressure_sensor_type_e 1 bits, U08, @OFFSET@, [0:4], "Custom", "DENSO183", "MPX4250", "HONDA3BAR", "NEON_2003", "22012AA090", "GM 3 Bar", "MPX4100", "Toyota 89420-02010", "MPX4250A", "Bosch 2.5", "Mazda1Bar", "GM 2 Bar", "GM 1 Bar", "MPXH6400" diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index de386faff5..47d5988e4c 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -194,11 +194,6 @@ enable2ndByteCanID = false egoCorrectionForVeAnalyze = { 100 + fuelPidCorrection1 } ; These "synthetic" channels provide the Y-axis (load) value for gen purp PWM table's Y axes - gppwm1_load = {(gppwm1_loadAxis == 0) ? 0 : (gppwm1_loadAxis == 1) ? TPSValue : (gppwm1_loadAxis == 2) ? MAPValue : (gppwm1_loadAxis == 3) ? coolant : (gppwm1_loadAxis == 4) ? intake : (gppwm1_loadAxis == 5) ? fuelingLoad : (gppwm1_loadAxis == 6) ? ignitionLoad : (gppwm1_loadAxis == 7) ? auxTemp1 : (gppwm1_loadAxis == 8) ? auxTemp2 : (gppwm1_loadAxis == 9) ? throttlePedalPosition : (gppwm1_loadAxis == 10) ? VBatt : (gppwm1_loadAxis == 11) ? vvtPositionB1I : (gppwm1_loadAxis == 12) ? vvtPositionB1E : (gppwm1_loadAxis == 13) ? vvtPositionB2I : (gppwm1_loadAxis == 14) ? vvtPositionB2E : (gppwm1_loadAxis == 15) ? flexPercent : (gppwm1_loadAxis == 16) ? auxLinear1 : (gppwm1_loadAxis == 17) ? auxLinear2 : 0} - gppwm2_load = {(gppwm2_loadAxis == 0) ? 0 : (gppwm2_loadAxis == 1) ? TPSValue : (gppwm2_loadAxis == 2) ? MAPValue : (gppwm2_loadAxis == 3) ? coolant : (gppwm2_loadAxis == 4) ? intake : (gppwm2_loadAxis == 5) ? fuelingLoad : (gppwm2_loadAxis == 6) ? ignitionLoad : (gppwm2_loadAxis == 7) ? auxTemp1 : (gppwm2_loadAxis == 8) ? auxTemp2 : (gppwm2_loadAxis == 9) ? throttlePedalPosition : (gppwm2_loadAxis == 10) ? VBatt : (gppwm2_loadAxis == 11) ? vvtPositionB1I : (gppwm2_loadAxis == 12) ? vvtPositionB1E : (gppwm2_loadAxis == 13) ? vvtPositionB2I : (gppwm2_loadAxis == 14) ? vvtPositionB2E : (gppwm2_loadAxis == 15) ? flexPercent : (gppwm2_loadAxis == 16) ? auxLinear1 : (gppwm2_loadAxis == 17) ? auxLinear2 : 0} - gppwm3_load = {(gppwm3_loadAxis == 0) ? 0 : (gppwm3_loadAxis == 1) ? TPSValue : (gppwm3_loadAxis == 2) ? MAPValue : (gppwm3_loadAxis == 3) ? coolant : (gppwm3_loadAxis == 4) ? intake : (gppwm3_loadAxis == 5) ? fuelingLoad : (gppwm3_loadAxis == 6) ? ignitionLoad : (gppwm3_loadAxis == 7) ? auxTemp1 : (gppwm3_loadAxis == 8) ? auxTemp2 : (gppwm3_loadAxis == 9) ? throttlePedalPosition : (gppwm3_loadAxis == 10) ? VBatt : (gppwm3_loadAxis == 11) ? vvtPositionB1I : (gppwm3_loadAxis == 12) ? vvtPositionB1E : (gppwm3_loadAxis == 13) ? vvtPositionB2I : (gppwm3_loadAxis == 14) ? vvtPositionB2E : (gppwm3_loadAxis == 15) ? flexPercent : (gppwm3_loadAxis == 16) ? auxLinear1 : (gppwm3_loadAxis == 17) ? auxLinear2 : 0} - gppwm4_load = {(gppwm4_loadAxis == 0) ? 0 : (gppwm4_loadAxis == 1) ? TPSValue : (gppwm4_loadAxis == 2) ? MAPValue : (gppwm4_loadAxis == 3) ? coolant : (gppwm4_loadAxis == 4) ? intake : (gppwm4_loadAxis == 5) ? fuelingLoad : (gppwm4_loadAxis == 6) ? ignitionLoad : (gppwm4_loadAxis == 7) ? auxTemp1 : (gppwm4_loadAxis == 8) ? auxTemp2 : (gppwm4_loadAxis == 9) ? throttlePedalPosition : (gppwm4_loadAxis == 10) ? VBatt : (gppwm4_loadAxis == 11) ? vvtPositionB1I : (gppwm4_loadAxis == 12) ? vvtPositionB1E : (gppwm4_loadAxis == 13) ? vvtPositionB2I : (gppwm4_loadAxis == 14) ? vvtPositionB2E : (gppwm4_loadAxis == 15) ? flexPercent : (gppwm4_loadAxis == 16) ? auxLinear1 : (gppwm4_loadAxis == 17) ? auxLinear2 : 0} - ignBlends1_blendVal = {(ignBlends1_blendParameter == 0) ? 0 : (ignBlends1_blendParameter == 1) ? TPSValue : (ignBlends1_blendParameter == 2) ? MAPValue : (ignBlends1_blendParameter == 3) ? coolant : (ignBlends1_blendParameter == 4) ? intake : (ignBlends1_blendParameter == 5) ? fuelingLoad : (ignBlends1_blendParameter == 6) ? ignitionLoad : (ignBlends1_blendParameter == 7) ? auxTemp1 : (ignBlends1_blendParameter == 8) ? auxTemp2 : (ignBlends1_blendParameter == 9) ? throttlePedalPosition : (ignBlends1_blendParameter == 10) ? VBatt : (ignBlends1_blendParameter == 11) ? vvtPositionB1I : (ignBlends1_blendParameter == 12) ? vvtPositionB1E : (ignBlends1_blendParameter == 13) ? vvtPositionB2I : (ignBlends1_blendParameter == 14) ? vvtPositionB2E : (ignBlends1_blendParameter == 15) ? flexPercent : (ignBlends1_blendParameter == 16) ? auxLinear1 : (ignBlends1_blendParameter == 17) ? auxLinear2 : 0} ignBlends2_blendVal = {(ignBlends2_blendParameter == 0) ? 0 : (ignBlends2_blendParameter == 1) ? TPSValue : (ignBlends2_blendParameter == 2) ? MAPValue : (ignBlends2_blendParameter == 3) ? coolant : (ignBlends2_blendParameter == 4) ? intake : (ignBlends2_blendParameter == 5) ? fuelingLoad : (ignBlends2_blendParameter == 6) ? ignitionLoad : (ignBlends2_blendParameter == 7) ? auxTemp1 : (ignBlends2_blendParameter == 8) ? auxTemp2 : (ignBlends2_blendParameter == 9) ? throttlePedalPosition : (ignBlends2_blendParameter == 10) ? VBatt : (ignBlends2_blendParameter == 11) ? vvtPositionB1I : (ignBlends2_blendParameter == 12) ? vvtPositionB1E : (ignBlends2_blendParameter == 13) ? vvtPositionB2I : (ignBlends2_blendParameter == 14) ? vvtPositionB2E : (ignBlends2_blendParameter == 15) ? flexPercent : (ignBlends2_blendParameter == 16) ? auxLinear1 : (ignBlends2_blendParameter == 17) ? auxLinear2 : 0} ignBlends3_blendVal = {(ignBlends3_blendParameter == 0) ? 0 : (ignBlends3_blendParameter == 1) ? TPSValue : (ignBlends3_blendParameter == 2) ? MAPValue : (ignBlends3_blendParameter == 3) ? coolant : (ignBlends3_blendParameter == 4) ? intake : (ignBlends3_blendParameter == 5) ? fuelingLoad : (ignBlends3_blendParameter == 6) ? ignitionLoad : (ignBlends3_blendParameter == 7) ? auxTemp1 : (ignBlends3_blendParameter == 8) ? auxTemp2 : (ignBlends3_blendParameter == 9) ? throttlePedalPosition : (ignBlends3_blendParameter == 10) ? VBatt : (ignBlends3_blendParameter == 11) ? vvtPositionB1I : (ignBlends3_blendParameter == 12) ? vvtPositionB1E : (ignBlends3_blendParameter == 13) ? vvtPositionB2I : (ignBlends3_blendParameter == 14) ? vvtPositionB2E : (ignBlends3_blendParameter == 15) ? flexPercent : (ignBlends3_blendParameter == 16) ? auxLinear1 : (ignBlends3_blendParameter == 17) ? auxLinear2 : 0} @@ -1144,26 +1139,26 @@ curve = 32Curve, "3-2 Shift Solenoid Percent by Speed" table = gppwm1Tbl, gppwm1Map, "GP#1", 1 xyLabels = "RPM", "" - xBins = gppwm1_rpmBins, RPMValue - yBins = gppwm1_loadBins, gppwm1_load + xBins = gppwm1_rpmBins, gppwmXAxis1 + yBins = gppwm1_loadBins, gppwmYAxis1 zBins = gppwm1_table table = gppwm2Tbl, gppwm2Map, "GP#2", 1 xyLabels = "RPM", "" - xBins = gppwm2_rpmBins, RPMValue - yBins = gppwm2_loadBins, gppwm2_load + xBins = gppwm2_rpmBins, gppwmXAxis2 + yBins = gppwm2_loadBins, gppwmYAxis2 zBins = gppwm2_table table = gppwm3Tbl, gppwm3Map, "GP#3", 1 xyLabels = "RPM", "" - xBins = gppwm3_rpmBins, RPMValue - yBins = gppwm3_loadBins, gppwm3_load + xBins = gppwm3_rpmBins, gppwmXAxis3 + yBins = gppwm3_loadBins, gppwmYAxis3 zBins = gppwm3_table table = gppwm4Tbl, gppwm4Map, "GP#4", 1 xyLabels = "RPM", "" - xBins = gppwm4_rpmBins, RPMValue - yBins = gppwm4_loadBins, gppwm4_load + xBins = gppwm4_rpmBins, gppwmXAxis4 + yBins = gppwm4_loadBins, gppwmYAxis4 zBins = gppwm4_table table = tcuSolenoidTableTbl, tcuSolenoidTableMap, "Solenoids Active By Gear", 1 @@ -4349,7 +4344,8 @@ dialog = tcuControls, "Transmission Settings" field = "Off below duty", gppwm1_offBelowDuty, {gppwm1_pin != 0 && gppwm1_pwmFrequency == 0} field = "Duty if error", gppwm1_dutyIfError, {gppwm1_pin != 0} field = "" - field = "Load Axis", gppwm1_loadAxis, {gppwm1_pin != 0} + field = "X Axis", gppwm1_rpmAxis, {gppwm1_pin != 0} + field = "Y Axis", gppwm1_loadAxis, {gppwm1_pin != 0} field = "Note", gpPwmNote1 field = "" field = "" @@ -4371,7 +4367,8 @@ dialog = tcuControls, "Transmission Settings" field = "Off below duty", gppwm2_offBelowDuty, {gppwm2_pin != 0 && gppwm2_pwmFrequency == 0} field = "Duty if error", gppwm2_dutyIfError, {gppwm2_pin != 0} field = "" - field = "Load Axis", gppwm2_loadAxis, {gppwm2_pin != 0} + field = "X Axis", gppwm2_rpmAxis, {gppwm2_pin != 0} + field = "Y Axis", gppwm2_loadAxis, {gppwm2_pin != 0} field = "Note", gpPwmNote2 field = "" field = "" @@ -4393,7 +4390,8 @@ dialog = tcuControls, "Transmission Settings" field = "Off below duty", gppwm3_offBelowDuty, {gppwm3_pin != 0 && gppwm3_pwmFrequency == 0} field = "Duty if error", gppwm3_dutyIfError, {gppwm3_pin != 0} field = "" - field = "Load Axis", gppwm3_loadAxis, {gppwm3_pin != 0} + field = "X Axis", gppwm3_rpmAxis, {gppwm3_pin != 0} + field = "Y Axis", gppwm3_loadAxis, {gppwm3_pin != 0} field = "Note", gpPwmNote3 field = "" field = "" @@ -4415,7 +4413,8 @@ dialog = tcuControls, "Transmission Settings" field = "Off below duty", gppwm4_offBelowDuty, {gppwm4_pin != 0 && gppwm4_pwmFrequency == 0} field = "Duty if error", gppwm4_dutyIfError, {gppwm4_pin != 0} field = "" - field = "Load Axis", gppwm4_loadAxis, {gppwm4_pin != 0} + field = "X Axis", gppwm4_rpmAxis, {gppwm4_pin != 0} + field = "Y Axis", gppwm4_loadAxis, {gppwm4_pin != 0} field = "Note", gpPwmNote4 field = "" field = "" diff --git a/firmware/util/containers/table_helper.h b/firmware/util/containers/table_helper.h index 8f02828168..0f7a9159e5 100644 --- a/firmware/util/containers/table_helper.h +++ b/firmware/util/containers/table_helper.h @@ -124,7 +124,7 @@ typedef Map3D baroCorr_Map3 typedef Map3D pedal2tps_t; typedef Map3D boostOpenLoop_Map3D_t; typedef Map3D boostClosedLoop_Map3D_t; -typedef Map3D gppwm_Map3D_t; +typedef Map3D gppwm_Map3D_t; typedef Map3D mapEstimate_Map3D_t; /** diff --git a/unit_tests/tests/actuators/test_gppwm.cpp b/unit_tests/tests/actuators/test_gppwm.cpp index 7cb19782ab..9e33030a27 100644 --- a/unit_tests/tests/actuators/test_gppwm.cpp +++ b/unit_tests/tests/actuators/test_gppwm.cpp @@ -79,6 +79,7 @@ TEST(GpPwm, TestGetOutput) { gppwm_channel cfg; cfg.loadAxis = GPPWM_Tps; + cfg.rpmAxis = GPPWM_Rpm; cfg.dutyIfError = 21.0f; MockVp3d table; @@ -93,10 +94,10 @@ TEST(GpPwm, TestGetOutput) { Sensor::resetAllMocks(); // Should return dutyIfError - EXPECT_FLOAT_EQ(21.0f, ch.getOutput()); + EXPECT_FLOAT_EQ(21.0f, ch.getOutput().Result); // Set TPS, should return tps value Sensor::setMockValue(SensorType::Tps1, 35.0f); Sensor::setMockValue(SensorType::Rpm, 1200); - EXPECT_FLOAT_EQ(35.0f, ch.getOutput()); + EXPECT_FLOAT_EQ(35.0f, ch.getOutput().Result); }