| Line | Branch | Decision | Exec | Source |
|---|---|---|---|---|
| 1 | /* | |||
| 2 | * boost_control.cpp | |||
| 3 | * | |||
| 4 | * Created on: 13. des. 2019 | |||
| 5 | * Author: Ola Ruud | |||
| 6 | */ | |||
| 7 | #include "pch.h" | |||
| 8 | ||||
| 9 | #if EFI_BOOST_CONTROL | |||
| 10 | ||||
| 11 | #include "boost_control.h" | |||
| 12 | #include "electronic_throttle.h" | |||
| 13 | #include "gppwm_channel_reader.h" | |||
| 14 | ||||
| 15 | #if defined(HAS_OS_ACCESS) | |||
| 16 | #error "Unexpected OS ACCESS HERE" | |||
| 17 | #endif | |||
| 18 | ||||
| 19 | namespace { | |||
| 20 | Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint16_t> boostMapOpen{"bo"}; | |||
| 21 | Map3D<BOOST_RPM_COUNT, BOOST_LOAD_COUNT, uint8_t, uint8_t, uint16_t> boostMapClosed{"bc"}; | |||
| 22 | Map2D<BOOST_CURVE_SIZE, float, float> boostCltCorr { "clt" }; | |||
| 23 | Map2D<BOOST_CURVE_SIZE, float, float> boostIatCorr { "iat" }; | |||
| 24 | Map2D<BOOST_CURVE_SIZE, float, float> boostCltAdder { "clt (adder)" }; | |||
| 25 | Map2D<BOOST_CURVE_SIZE, float, float> boostIatAdder { "iat (adder)" }; | |||
| 26 | SimplePwm boostPwmControl("boost"); | |||
| 27 | } | |||
| 28 | ||||
| 29 | 608 | void BoostController::init( | ||
| 30 | IPwm* const pwm, | |||
| 31 | const ValueProvider3D* const openLoopMap, | |||
| 32 | const ValueProvider3D* const closedLoopTargetMap, | |||
| 33 | const ValueProvider2D& cltMultiplierProvider, | |||
| 34 | const ValueProvider2D& iatMultiplierProvider, | |||
| 35 | const ValueProvider2D& cltAdderProvider, | |||
| 36 | const ValueProvider2D& iatAdderProvider, | |||
| 37 | pid_s* const pidParams | |||
| 38 | ) { | |||
| 39 | 608 | m_pwm = pwm; | ||
| 40 | 608 | m_openLoopMap = openLoopMap; | ||
| 41 | 608 | m_closedLoopTargetMap = closedLoopTargetMap; | ||
| 42 | 608 | m_cltBoostCorrMap = &cltMultiplierProvider; | ||
| 43 | 608 | m_iatBoostCorrMap = &iatMultiplierProvider; | ||
| 44 | 608 | m_cltBoostAdderMap = &cltAdderProvider; | ||
| 45 | 608 | m_iatBoostAdderMap = &iatAdderProvider; | ||
| 46 | ||||
| 47 | 608 | m_pid.initPidClass(pidParams); | ||
| 48 | 608 | resetLua(); | ||
| 49 | ||||
| 50 | 608 | hasInitBoost = true; | ||
| 51 | 608 | } | ||
| 52 | ||||
| 53 | 608 | void BoostController::resetLua() { | ||
| 54 | 608 | luaTargetAdd = 0; | ||
| 55 | 608 | luaTargetMult = 1; | ||
| 56 | 608 | luaOpenLoopAdd = 0; | ||
| 57 | 608 | } | ||
| 58 | ||||
| 59 | 221 | void BoostController::onConfigurationChange(engine_configuration_s const * previousConfig) { | ||
| 60 | #if EFI_PROD_CODE | |||
| 61 | initBoostCtrl(); | |||
| 62 | #endif | |||
| 63 | ||||
| 64 |
3/6✓ Branch 0 taken 221 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 221 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 221 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 221 times.
|
221 | if (!previousConfig || !m_pid.isSame(&previousConfig->boostPid)) { |
| 65 | ✗ | m_shouldResetPid = true; | ||
| 66 | } | |||
| 67 | 221 | } | ||
| 68 | ||||
| 69 | 2 | expected<float> BoostController::observePlant() { | ||
| 70 |
1/1✓ Branch 2 taken 2 times.
|
2 | expected<float> map = Sensor::get(SensorType::Map); | |
| 71 |
3/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (!map.Valid && engineConfiguration->boostType != CLOSED_LOOP) { |
| 72 | // if we're in open loop only let's somewhat operate even without valid Map sensor | |||
| 73 | ✗ | map = 0; | ||
| 74 | } | |||
| 75 | 2 | isPlantValid = map.Valid; | ||
| 76 | 2 | return map; | ||
| 77 | } | |||
| 78 | ||||
| 79 | 36 | expected<float> BoostController::getSetpoint() { | ||
| 80 | // If we're in open loop only mode, disregard any target computation. | |||
| 81 | // Open loop needs to work even in case of invalid closed loop config | |||
| 82 | 36 | isNotClosedLoop = engineConfiguration->boostType != CLOSED_LOOP; | ||
| 83 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 35 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 35 times.
|
36 | if (isNotClosedLoop) { |
| 84 | 1 | boostControllerClosedLoopPart = 0; | ||
| 85 | 1 | return (float)boostControllerClosedLoopPart; | ||
| 86 | } | |||
| 87 | ||||
| 88 |
1/1✓ Branch 1 taken 35 times.
|
35 | float rpm = Sensor::getOrZero(SensorType::Rpm); | |
| 89 | ||||
| 90 |
1/1✓ Branch 1 taken 35 times.
|
35 | auto driverIntent = Sensor::get(SensorType::DriverThrottleIntent); | |
| 91 | 35 | isTpsInvalid = !driverIntent.Valid; | ||
| 92 | ||||
| 93 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 33 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 33 times.
|
35 | if (isTpsInvalid) { |
| 94 | 2 | return unexpected; | ||
| 95 | } | |||
| 96 | ||||
| 97 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
✗ Branch 3 not taken.
|
33 | efiAssert(ObdCode::OBD_PCM_Processor_Fault, m_closedLoopTargetMap != nullptr, "boost closed loop target", unexpected); | |
| 98 | ||||
| 99 |
1/1✓ Branch 2 taken 33 times.
|
33 | float target = m_closedLoopTargetMap->getValue(rpm, driverIntent.Value); | |
| 100 | #if EFI_ENGINE_CONTROL | |||
| 101 | // Add any blends if configured | |||
| 102 |
2/2✓ Branch 1 taken 66 times.
✓ Branch 2 taken 33 times.
|
2/2✓ Decision 'true' taken 66 times.
✓ Decision 'false' taken 33 times.
|
99 | for (size_t i = 0; i < efi::size(config->boostClosedLoopBlends); i++) { |
| 103 |
1/1✓ Branch 2 taken 66 times.
|
66 | auto result = calculateBlend(config->boostClosedLoopBlends[i], rpm, driverIntent.Value); | |
| 104 | ||||
| 105 | 66 | engine->outputChannels.boostClosedLoopBlendParameter[i] = result.BlendParameter; | ||
| 106 | 66 | engine->outputChannels.boostClosedLoopBlendBias[i] = result.Bias; | ||
| 107 | 66 | engine->outputChannels.boostClosedLoopBlendOutput[i] = result.Value; | ||
| 108 | 66 | engine->outputChannels.boostClosedLoopBlendYAxis[i] = result.TableYAxis; | ||
| 109 | ||||
| 110 | 66 | target += result.Value; | ||
| 111 | } | |||
| 112 | #endif //EFI_ENGINE_CONTROL | |||
| 113 | ||||
| 114 | 33 | target *= luaTargetMult; | ||
| 115 | 33 | target += luaTargetAdd; | ||
| 116 |
1/1✓ Branch 2 taken 33 times.
|
33 | const std::optional<float> temperatureAdder = getBoostControlTargetTemperatureAdder(); | |
| 117 |
2/2✓ Branch 1 taken 31 times.
✓ Branch 2 taken 2 times.
|
2/2✓ Decision 'true' taken 31 times.
✓ Decision 'false' taken 2 times.
|
33 | if (temperatureAdder.has_value()) { |
| 118 |
1/1✓ Branch 1 taken 31 times.
|
31 | target += temperatureAdder.value(); | |
| 119 | } | |||
| 120 | 33 | return target; | ||
| 121 | } | |||
| 122 | ||||
| 123 | 64 | expected<percent_t> BoostController::getOpenLoop(float target) { | ||
| 124 | // Boost control open loop doesn't care about target - only TPS/RPM | |||
| 125 | UNUSED(target); | |||
| 126 | ||||
| 127 |
1/1✓ Branch 1 taken 64 times.
|
64 | float rpm = Sensor::getOrZero(SensorType::Rpm); | |
| 128 |
1/1✓ Branch 1 taken 64 times.
|
64 | auto driverIntent = readGppwmChannel(engineConfiguration->boostOpenLoopYAxis); | |
| 129 | ||||
| 130 | 64 | isTpsInvalid = !driverIntent.Valid; | ||
| 131 | ||||
| 132 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 63 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 63 times.
|
64 | if (isTpsInvalid) { |
| 133 | 1 | return unexpected; | ||
| 134 | } | |||
| 135 | ||||
| 136 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
✗ Branch 3 not taken.
|
63 | efiAssert(ObdCode::OBD_PCM_Processor_Fault, m_openLoopMap != nullptr, "boost open loop", unexpected); | |
| 137 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
✗ Branch 3 not taken.
|
63 | efiAssert(ObdCode::OBD_PCM_Processor_Fault, m_cltBoostCorrMap != nullptr, "boost CLT multiplier", unexpected); | |
| 138 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
✗ Branch 3 not taken.
|
63 | efiAssert(ObdCode::OBD_PCM_Processor_Fault, m_iatBoostCorrMap != nullptr, "boost IAT multiplier", unexpected); | |
| 139 | ||||
| 140 |
1/1✓ Branch 2 taken 63 times.
|
63 | percent_t openLoop = luaOpenLoopAdd + getBoostControlDutyCycleWithTemperatureCorrections(rpm, driverIntent.Value); | |
| 141 | 63 | openLoopYAxis = driverIntent.Value; | ||
| 142 | ||||
| 143 | #if EFI_ENGINE_CONTROL | |||
| 144 | // Add any blends if configured | |||
| 145 |
2/2✓ Branch 1 taken 126 times.
✓ Branch 2 taken 63 times.
|
2/2✓ Decision 'true' taken 126 times.
✓ Decision 'false' taken 63 times.
|
189 | for (size_t i = 0; i < efi::size(config->boostOpenLoopBlends); i++) { |
| 146 |
1/1✓ Branch 2 taken 126 times.
|
126 | auto result = calculateBlend(config->boostOpenLoopBlends[i], rpm, driverIntent.Value); | |
| 147 | ||||
| 148 | 126 | engine->outputChannels.boostOpenLoopBlendParameter[i] = result.BlendParameter; | ||
| 149 | 126 | engine->outputChannels.boostOpenLoopBlendBias[i] = result.Bias; | ||
| 150 | 126 | engine->outputChannels.boostOpenLoopBlendOutput[i] = result.Value; | ||
| 151 | 126 | engine->outputChannels.boostOpenLoopBlendYAxis[i] = result.TableYAxis; | ||
| 152 | ||||
| 153 | 126 | openLoop += result.Value; | ||
| 154 | } | |||
| 155 | #endif // EFI_ENGINE_CONTROL | |||
| 156 | ||||
| 157 | // Add gear-based adder | |||
| 158 |
1/1✓ Branch 1 taken 63 times.
|
63 | auto gear = Sensor::getOrZero(SensorType::DetectedGear); | |
| 159 | 63 | float gearAdder = engineConfiguration->gearBasedOpenLoopBoostAdder[static_cast<int>(gear) + 1]; | ||
| 160 | 63 | openLoop += gearAdder; | ||
| 161 | ||||
| 162 | 63 | openLoopPart = openLoop; | ||
| 163 | 63 | return openLoop; | ||
| 164 | } | |||
| 165 | ||||
| 166 | 10 | percent_t BoostController::getClosedLoopImpl(float target, float manifoldPressure) { | ||
| 167 | // If we're in open loop only mode, make no closed loop correction. | |||
| 168 | 10 | isNotClosedLoop = engineConfiguration->boostType != CLOSED_LOOP; | ||
| 169 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
|
2/2✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 8 times.
|
10 | if (isNotClosedLoop) { |
| 170 | 2 | return 0; | ||
| 171 | } | |||
| 172 | ||||
| 173 | // Reset PID if requested | |||
| 174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
|
8 | if (m_shouldResetPid) { |
| 175 | ✗ | m_pid.reset(); | ||
| 176 | ✗ | m_shouldResetPid = false; | ||
| 177 | } | |||
| 178 | ||||
| 179 | // If the engine isn't running, don't correct. | |||
| 180 | 8 | isZeroRpm = Sensor::getOrZero(SensorType::Rpm) == 0; | ||
| 181 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 4 times.
|
8 | if (isZeroRpm) { |
| 182 | 4 | m_pid.reset(); | ||
| 183 | 4 | return 0; | ||
| 184 | } | |||
| 185 | ||||
| 186 | 4 | isBelowClosedLoopThreshold = manifoldPressure < engineConfiguration->minimumBoostClosedLoopMap; | ||
| 187 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 3 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 3 times.
|
4 | if (isBelowClosedLoopThreshold) { |
| 188 | // We're below the CL threshold, inhibit CL for now | |||
| 189 | 1 | m_pid.reset(); | ||
| 190 | 1 | return 0; | ||
| 191 | } | |||
| 192 | ||||
| 193 | 3 | return m_pid.getOutput(target, manifoldPressure, FAST_CALLBACK_PERIOD_MS / 1000.0f); | ||
| 194 | } | |||
| 195 | ||||
| 196 | 63 | float BoostController::getBoostControlDutyCycleWithTemperatureCorrections( | ||
| 197 | const float rpm, | |||
| 198 | const float driverIntent | |||
| 199 | ) const { | |||
| 200 |
1/1✓ Branch 1 taken 63 times.
|
63 | float result = m_openLoopMap->getValue(rpm, driverIntent); | |
| 201 |
1/1✓ Branch 2 taken 63 times.
|
63 | std::optional<float> cltBoostMultiplier = getBoostTemperatureCorrection(SensorType::Clt, *m_cltBoostCorrMap); | |
| 202 |
2/2✓ Branch 1 taken 56 times.
✓ Branch 2 taken 7 times.
|
2/2✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 7 times.
|
63 | if (cltBoostMultiplier.has_value()) { |
| 203 |
1/1✓ Branch 1 taken 56 times.
|
56 | result *= cltBoostMultiplier.value(); | |
| 204 | } | |||
| 205 |
1/1✓ Branch 2 taken 63 times.
|
63 | std::optional<float> iatBoostMultiplier = getBoostTemperatureCorrection(SensorType::Iat, *m_iatBoostCorrMap); | |
| 206 |
2/2✓ Branch 1 taken 56 times.
✓ Branch 2 taken 7 times.
|
2/2✓ Decision 'true' taken 56 times.
✓ Decision 'false' taken 7 times.
|
63 | if (iatBoostMultiplier.has_value()) { |
| 207 |
1/1✓ Branch 1 taken 56 times.
|
56 | result *= iatBoostMultiplier.value(); | |
| 208 | } | |||
| 209 | 126 | return result; | ||
| 210 | } | |||
| 211 | ||||
| 212 | 33 | std::optional<float> BoostController::getBoostControlTargetTemperatureAdder() const { | ||
| 213 |
1/1✓ Branch 2 taken 33 times.
|
33 | std::optional<float> result = getBoostTemperatureCorrection(SensorType::Clt, *m_cltBoostAdderMap); | |
| 214 |
1/1✓ Branch 2 taken 33 times.
|
33 | const std::optional<float> iatBoostAdder = getBoostTemperatureCorrection(SensorType::Iat, *m_iatBoostAdderMap); | |
| 215 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 7 times.
|
2/2✓ Decision 'true' taken 26 times.
✓ Decision 'false' taken 7 times.
|
33 | if (iatBoostAdder.has_value()) { |
| 216 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 5 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 5 times.
|
26 | if (result.has_value()) { |
| 217 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 4 taken 21 times.
|
21 | result.value() += iatBoostAdder.value(); | |
| 218 | } else { | |||
| 219 | 5 | result = iatBoostAdder; | ||
| 220 | } | |||
| 221 | } | |||
| 222 | 66 | return result; | ||
| 223 | } | |||
| 224 | ||||
| 225 | 192 | std::optional<float> BoostController::getBoostTemperatureCorrection( | ||
| 226 | const SensorType sensorType, | |||
| 227 | const ValueProvider2D& correctionCurve | |||
| 228 | ) const { | |||
| 229 | 192 | const SensorResult temperature = Sensor::get(sensorType); | ||
| 230 |
2/2✓ Branch 0 taken 164 times.
✓ Branch 1 taken 28 times.
|
2/2✓ Decision 'true' taken 164 times.
✓ Decision 'false' taken 28 times.
|
192 | if (temperature.Valid) { |
| 231 |
1/1✓ Branch 2 taken 164 times.
|
164 | const std::optional<float> boostCorrection = correctionCurve.getValue(temperature.Value); | |
| 232 |
1/2✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 164 times.
✗ Decision 'false' not taken.
|
164 | if (boostCorrection.has_value()) { |
| 233 |
1/1✓ Branch 1 taken 164 times.
|
164 | return std::make_optional<float>(boostCorrection.value()); | |
| 234 | } | |||
| 235 | } | |||
| 236 | 28 | return {}; | ||
| 237 | } | |||
| 238 | ||||
| 239 | ||||
| 240 | 10 | expected<percent_t> BoostController::getClosedLoop(float target, float manifoldPressure) { | ||
| 241 |
1/1✓ Branch 2 taken 10 times.
|
10 | boostControllerClosedLoopPart = getClosedLoopImpl(target, manifoldPressure); | |
| 242 | ||||
| 243 | 10 | m_pid.postState(engine->outputChannels.boostStatus); | ||
| 244 | ||||
| 245 | 10 | boostControlTarget = target; | ||
| 246 | ||||
| 247 | 10 | return (float)boostControllerClosedLoopPart; | ||
| 248 | } | |||
| 249 | ||||
| 250 | 1103 | bool isBoostControlSolenoidMode() { | ||
| 251 | 1103 | return isBrainPinValid(engineConfiguration->boostControlPin); | ||
| 252 | } | |||
| 253 | ||||
| 254 | 1105 | void BoostController::setOutput(expected<float> output) { | ||
| 255 | // this clamping is just for happier gauge #6339 | |||
| 256 |
1/1✓ Branch 3 taken 1105 times.
|
1105 | boostOutput = clampPercentValue(output.value_or(engineConfiguration->boostControlSafeDutyCycle)); | |
| 257 | ||||
| 258 |
2/2✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 1101 times.
✓ Decision 'false' taken 4 times.
|
1105 | if (!engineConfiguration->isBoostControlEnabled) { |
| 259 | // If not enabled, force 0% output | |||
| 260 | 1101 | boostOutput = 0; | ||
| 261 | } | |||
| 262 | ||||
| 263 | 1105 | float duty = PERCENT_TO_DUTY(boostOutput); | ||
| 264 | ||||
| 265 |
6/6✓ Branch 0 taken 1103 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1102 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1104 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1104 times.
|
1105 | if (m_pwm && isBoostControlSolenoidMode()) { |
| 266 | 1 | m_pwm->setSimplePwmDutyCycle(duty); | ||
| 267 | } else { | |||
| 268 | #if EFI_ELECTRONIC_THROTTLE_BODY | |||
| 269 | // inject wastegate position into DC controllers, pretty weird workflow to be honest | |||
| 270 | // todo: should it be DC controller pulling? | |||
| 271 | 1104 | setEtbWastegatePosition(boostOutput); | ||
| 272 | #endif // EFI_ELECTRONIC_THROTTLE_BODY | |||
| 273 | } | |||
| 274 | 1105 | } | ||
| 275 | ||||
| 276 | 1101 | void BoostController::onFastCallback() { | ||
| 277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1101 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1101 times.
|
1101 | if (!hasInitBoost) { |
| 278 | ✗ | return; | ||
| 279 | } | |||
| 280 | ||||
| 281 | 1101 | m_pid.iTermMin = -20; | ||
| 282 | 1101 | m_pid.iTermMax = 20; | ||
| 283 | ||||
| 284 | 1101 | rpmTooLow = Sensor::getOrZero(SensorType::Rpm) < engineConfiguration->boostControlMinRpm; | ||
| 285 | 1101 | tpsTooLow = Sensor::getOrZero(SensorType::Tps1) < engineConfiguration->boostControlMinTps; | ||
| 286 | 1101 | mapTooLow = Sensor::getOrZero(SensorType::Map) < engineConfiguration->boostControlMinMap; | ||
| 287 | ||||
| 288 |
3/6✓ Branch 0 taken 213 times.
✓ Branch 1 taken 888 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 213 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1101 | isBoostControlled = !(rpmTooLow || tpsTooLow || mapTooLow); | |
| 289 | ||||
| 290 |
1/2✓ Branch 0 taken 1101 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 1101 times.
✗ Decision 'false' not taken.
|
1101 | if (!isBoostControlled) { |
| 291 | // Passing unexpected will use the safe duty cycle configured by the user | |||
| 292 |
1/1✓ Branch 3 taken 1101 times.
|
1101 | setOutput(unexpected); | |
| 293 | } else { | |||
| 294 | ✗ | ClosedLoopController::update(); | ||
| 295 | } | |||
| 296 | } | |||
| 297 | ||||
| 298 | 587 | void setDefaultBoostParameters() { | ||
| 299 | 587 | engineConfiguration->boostPwmFrequency = 33; | ||
| 300 | 587 | engineConfiguration->boostPid.offset = 0; | ||
| 301 | 587 | engineConfiguration->boostPid.pFactor = 0.5; | ||
| 302 | 587 | engineConfiguration->boostPid.iFactor = 0.3; | ||
| 303 | 587 | engineConfiguration->boostPid.maxValue = 20; | ||
| 304 | 587 | engineConfiguration->boostPid.minValue = -20; | ||
| 305 | 587 | engineConfiguration->boostControlPinMode = OM_DEFAULT; | ||
| 306 | ||||
| 307 | 587 | setRpmTableBin(config->boostRpmBins); | ||
| 308 | 587 | setLinearCurve(config->boostOpenLoopLoadBins, 0, 100, 1); | ||
| 309 | 587 | setLinearCurve(config->boostClosedLoopLoadBins, 0, 100, 1); | ||
| 310 | ||||
| 311 |
2/2✓ Branch 0 taken 4696 times.
✓ Branch 1 taken 587 times.
|
2/2✓ Decision 'true' taken 4696 times.
✓ Decision 'false' taken 587 times.
|
5283 | for (int loadIndex = 0; loadIndex < BOOST_LOAD_COUNT; loadIndex++) { |
| 312 |
2/2✓ Branch 0 taken 37568 times.
✓ Branch 1 taken 4696 times.
|
2/2✓ Decision 'true' taken 37568 times.
✓ Decision 'false' taken 4696 times.
|
42264 | for (int rpmIndex = 0; rpmIndex < BOOST_RPM_COUNT; rpmIndex++) { |
| 313 | 37568 | config->boostTableClosedLoop[loadIndex][rpmIndex] = (float)config->boostClosedLoopLoadBins[loadIndex]; | ||
| 314 | } | |||
| 315 | } | |||
| 316 | ||||
| 317 | // Defaults for ETB-style wastegate actuator | |||
| 318 | 587 | engineConfiguration->etbWastegatePid.pFactor = 1; | ||
| 319 | 587 | engineConfiguration->etbWastegatePid.minValue = -60; | ||
| 320 | 587 | engineConfiguration->etbWastegatePid.maxValue = 60; | ||
| 321 | 587 | } | ||
| 322 | ||||
| 323 | 221 | void startBoostPin() { | ||
| 324 | #if !EFI_UNIT_TEST | |||
| 325 | // Only init if a pin is set, no need to start PWM without a pin | |||
| 326 | if (!engineConfiguration->isBoostControlEnabled || !isBrainPinValid(engineConfiguration->boostControlPin)) { | |||
| 327 | return; | |||
| 328 | } | |||
| 329 | ||||
| 330 | startSimplePwm( | |||
| 331 | &boostPwmControl, | |||
| 332 | "Boost", | |||
| 333 | &engine->scheduler, | |||
| 334 | &enginePins.boostPin, | |||
| 335 | engineConfiguration->boostPwmFrequency, | |||
| 336 | /*dutyCycle*/0 | |||
| 337 | ); | |||
| 338 | #endif /* EFI_UNIT_TEST */ | |||
| 339 | 221 | } | ||
| 340 | ||||
| 341 | 601 | void initBoostCtrl() { | ||
| 342 | #if EFI_PROD_CODE | |||
| 343 | if (engine->module<BoostController>().unmock().hasInitBoost) { | |||
| 344 | // already initialized - nothing to do here | |||
| 345 | return; | |||
| 346 | } | |||
| 347 | // todo: why do we have 'isBoostControlEnabled' setting exactly? | |||
| 348 | // 'initVvtActuators' is an example of a subsystem without explicit enable | |||
| 349 | if (!engineConfiguration->isBoostControlEnabled) { | |||
| 350 | return; | |||
| 351 | } | |||
| 352 | ||||
| 353 | bool hasAnyEtbWastegate = false; | |||
| 354 | ||||
| 355 | for (size_t i = 0; i < efi::size(engineConfiguration->etbFunctions); i++) { | |||
| 356 | hasAnyEtbWastegate |= engineConfiguration->etbFunctions[i] == DC_Wastegate; | |||
| 357 | } | |||
| 358 | ||||
| 359 | // If we have neither a boost PWM pin nor ETB wastegate, nothing more to do | |||
| 360 | if (!isBrainPinValid(engineConfiguration->boostControlPin) && !hasAnyEtbWastegate) { | |||
| 361 | return; | |||
| 362 | } | |||
| 363 | #endif | |||
| 364 | ||||
| 365 | // Set up open & closed loop tables | |||
| 366 | 601 | boostMapOpen.initTable(config->boostTableOpenLoop, config->boostRpmBins, config->boostOpenLoopLoadBins); | ||
| 367 | 601 | boostMapClosed.initTable(config->boostTableClosedLoop, config->boostRpmBins, config->boostClosedLoopLoadBins); | ||
| 368 | 601 | boostCltCorr.initTable(config->cltBoostCorr, config->cltBoostCorrBins); | ||
| 369 | 601 | boostIatCorr.initTable(config->iatBoostCorr, config->iatBoostCorrBins); | ||
| 370 | 601 | boostCltAdder.initTable(config->cltBoostAdder, config->cltBoostAdderBins); | ||
| 371 | 601 | boostIatAdder.initTable(config->iatBoostAdder, config->iatBoostAdderBins); | ||
| 372 | ||||
| 373 | // Set up boost controller instance | |||
| 374 | 601 | engine->module<BoostController>().unmock().init( | ||
| 375 | &boostPwmControl, | |||
| 376 | &boostMapOpen, | |||
| 377 | &boostMapClosed, | |||
| 378 | boostCltCorr, | |||
| 379 | boostIatCorr, | |||
| 380 | boostCltAdder, | |||
| 381 | boostIatAdder, | |||
| 382 | 601 | &engineConfiguration->boostPid | ||
| 383 | ); | |||
| 384 | ||||
| 385 | #if !EFI_UNIT_TEST | |||
| 386 | startBoostPin(); | |||
| 387 | #endif | |||
| 388 | 601 | } | ||
| 389 | ||||
| 390 | 587 | void BoostController::setDefaultConfiguration(){ | ||
| 391 | 587 | engineConfiguration->boostCutPressure = 300; | ||
| 392 | 587 | engineConfiguration->boostCutPressureHyst = 20; | ||
| 393 | 587 | engineConfiguration->boostControlMinRpm = 2000; | ||
| 394 | 587 | engineConfiguration->boostControlMinTps = 30; | ||
| 395 | 587 | engineConfiguration->boostControlMinMap = 110; | ||
| 396 | 587 | } | ||
| 397 | ||||
| 398 | #endif // EFI_BOOST_CONTROL | |||
| 399 |