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 | 607 | 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 | 607 | m_pwm = pwm; | ||
40 | 607 | m_openLoopMap = openLoopMap; | ||
41 | 607 | m_closedLoopTargetMap = closedLoopTargetMap; | ||
42 | 607 | m_cltBoostCorrMap = &cltMultiplierProvider; | ||
43 | 607 | m_iatBoostCorrMap = &iatMultiplierProvider; | ||
44 | 607 | m_cltBoostAdderMap = &cltAdderProvider; | ||
45 | 607 | m_iatBoostAdderMap = &iatAdderProvider; | ||
46 | ||||
47 | 607 | m_pid.initPidClass(pidParams); | ||
48 | 607 | resetLua(); | ||
49 | ||||
50 | 607 | hasInitBoost = true; | ||
51 | 607 | } | ||
52 | ||||
53 | 607 | void BoostController::resetLua() { | ||
54 | 607 | luaTargetAdd = 0; | ||
55 | 607 | luaTargetMult = 1; | ||
56 | 607 | luaOpenLoopAdd = 0; | ||
57 | 607 | } | ||
58 | ||||
59 | 219 | void BoostController::onConfigurationChange(engine_configuration_s const * previousConfig) { | ||
60 | #if EFI_PROD_CODE | |||
61 | initBoostCtrl(); | |||
62 | #endif | |||
63 | ||||
64 |
3/6✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 219 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 219 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 219 times.
|
219 | if (!previousConfig || !m_pid.isSame(&previousConfig->boostPid)) { |
65 | ✗ | m_shouldResetPid = true; | ||
66 | } | |||
67 | 219 | } | ||
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 | 1122 | bool isBoostControlSolenoidMode() { | ||
251 | 1122 | return isBrainPinValid(engineConfiguration->boostControlPin); | ||
252 | } | |||
253 | ||||
254 | 1124 | void BoostController::setOutput(expected<float> output) { | ||
255 | // this clamping is just for happier gauge #6339 | |||
256 |
1/1✓ Branch 3 taken 1124 times.
|
1124 | boostOutput = clampPercentValue(output.value_or(engineConfiguration->boostControlSafeDutyCycle)); | |
257 | ||||
258 |
2/2✓ Branch 0 taken 1120 times.
✓ Branch 1 taken 4 times.
|
2/2✓ Decision 'true' taken 1120 times.
✓ Decision 'false' taken 4 times.
|
1124 | if (!engineConfiguration->isBoostControlEnabled) { |
259 | // If not enabled, force 0% output | |||
260 | 1120 | boostOutput = 0; | ||
261 | } | |||
262 | ||||
263 | 1124 | float duty = PERCENT_TO_DUTY(boostOutput); | ||
264 | ||||
265 |
6/6✓ Branch 0 taken 1122 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1121 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1123 times.
|
2/2✓ Decision 'true' taken 1 time.
✓ Decision 'false' taken 1123 times.
|
1124 | 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 | 1123 | setEtbWastegatePosition(boostOutput); | ||
272 | #endif // EFI_ELECTRONIC_THROTTLE_BODY | |||
273 | } | |||
274 | 1124 | } | ||
275 | ||||
276 | 1120 | void BoostController::onFastCallback() { | ||
277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1120 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1120 times.
|
1120 | if (!hasInitBoost) { |
278 | ✗ | return; | ||
279 | } | |||
280 | ||||
281 | 1120 | m_pid.iTermMin = -20; | ||
282 | 1120 | m_pid.iTermMax = 20; | ||
283 | ||||
284 | 1120 | rpmTooLow = Sensor::getOrZero(SensorType::Rpm) < engineConfiguration->boostControlMinRpm; | ||
285 | 1120 | tpsTooLow = Sensor::getOrZero(SensorType::Tps1) < engineConfiguration->boostControlMinTps; | ||
286 | 1120 | mapTooLow = Sensor::getOrZero(SensorType::Map) < engineConfiguration->boostControlMinMap; | ||
287 | ||||
288 |
3/6✓ Branch 0 taken 208 times.
✓ Branch 1 taken 912 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 208 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1120 | isBoostControlled = !(rpmTooLow || tpsTooLow || mapTooLow); | |
289 | ||||
290 |
1/2✓ Branch 0 taken 1120 times.
✗ Branch 1 not taken.
|
1/2✓ Decision 'true' taken 1120 times.
✗ Decision 'false' not taken.
|
1120 | if (!isBoostControlled) { |
291 | // Passing unexpected will use the safe duty cycle configured by the user | |||
292 |
1/1✓ Branch 3 taken 1120 times.
|
1120 | setOutput(unexpected); | |
293 | } else { | |||
294 | ✗ | ClosedLoopController::update(); | ||
295 | } | |||
296 | } | |||
297 | ||||
298 | 586 | void setDefaultBoostParameters() { | ||
299 | 586 | engineConfiguration->boostPwmFrequency = 33; | ||
300 | 586 | engineConfiguration->boostPid.offset = 0; | ||
301 | 586 | engineConfiguration->boostPid.pFactor = 0.5; | ||
302 | 586 | engineConfiguration->boostPid.iFactor = 0.3; | ||
303 | 586 | engineConfiguration->boostPid.maxValue = 20; | ||
304 | 586 | engineConfiguration->boostPid.minValue = -20; | ||
305 | 586 | engineConfiguration->boostControlPinMode = OM_DEFAULT; | ||
306 | ||||
307 | 586 | setRpmTableBin(config->boostRpmBins); | ||
308 | 586 | setLinearCurve(config->boostOpenLoopLoadBins, 0, 100, 1); | ||
309 | 586 | setLinearCurve(config->boostClosedLoopLoadBins, 0, 100, 1); | ||
310 | ||||
311 |
2/2✓ Branch 0 taken 4688 times.
✓ Branch 1 taken 586 times.
|
2/2✓ Decision 'true' taken 4688 times.
✓ Decision 'false' taken 586 times.
|
5274 | for (int loadIndex = 0; loadIndex < BOOST_LOAD_COUNT; loadIndex++) { |
312 |
2/2✓ Branch 0 taken 37504 times.
✓ Branch 1 taken 4688 times.
|
2/2✓ Decision 'true' taken 37504 times.
✓ Decision 'false' taken 4688 times.
|
42192 | for (int rpmIndex = 0; rpmIndex < BOOST_RPM_COUNT; rpmIndex++) { |
313 | 37504 | config->boostTableClosedLoop[loadIndex][rpmIndex] = (float)config->boostClosedLoopLoadBins[loadIndex]; | ||
314 | } | |||
315 | } | |||
316 | ||||
317 | // Defaults for ETB-style wastegate actuator | |||
318 | 586 | engineConfiguration->etbWastegatePid.pFactor = 1; | ||
319 | 586 | engineConfiguration->etbWastegatePid.minValue = -60; | ||
320 | 586 | engineConfiguration->etbWastegatePid.maxValue = 60; | ||
321 | 586 | } | ||
322 | ||||
323 | 219 | 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 | 219 | } | ||
340 | ||||
341 | 600 | 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 | 600 | boostMapOpen.initTable(config->boostTableOpenLoop, config->boostRpmBins, config->boostOpenLoopLoadBins); | ||
367 | 600 | boostMapClosed.initTable(config->boostTableClosedLoop, config->boostRpmBins, config->boostClosedLoopLoadBins); | ||
368 | 600 | boostCltCorr.initTable(config->cltBoostCorr, config->cltBoostCorrBins); | ||
369 | 600 | boostIatCorr.initTable(config->iatBoostCorr, config->iatBoostCorrBins); | ||
370 | 600 | boostCltAdder.initTable(config->cltBoostAdder, config->cltBoostAdderBins); | ||
371 | 600 | boostIatAdder.initTable(config->iatBoostAdder, config->iatBoostAdderBins); | ||
372 | ||||
373 | // Set up boost controller instance | |||
374 | 600 | engine->module<BoostController>().unmock().init( | ||
375 | &boostPwmControl, | |||
376 | &boostMapOpen, | |||
377 | &boostMapClosed, | |||
378 | boostCltCorr, | |||
379 | boostIatCorr, | |||
380 | boostCltAdder, | |||
381 | boostIatAdder, | |||
382 | 600 | &engineConfiguration->boostPid | ||
383 | ); | |||
384 | ||||
385 | #if !EFI_UNIT_TEST | |||
386 | startBoostPin(); | |||
387 | #endif | |||
388 | 600 | } | ||
389 | ||||
390 | 586 | void BoostController::setDefaultConfiguration(){ | ||
391 | 586 | engineConfiguration->boostCutPressure = 300; | ||
392 | 586 | engineConfiguration->boostCutPressureHyst = 20; | ||
393 | 586 | engineConfiguration->boostControlMinRpm = 2000; | ||
394 | 586 | engineConfiguration->boostControlMinTps = 30; | ||
395 | 586 | engineConfiguration->boostControlMinMap = 110; | ||
396 | 586 | } | ||
397 | ||||
398 | #endif // EFI_BOOST_CONTROL | |||
399 |