2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file idle_thread.cpp
|
|
|
|
* @brief Idle Air Control valve thread.
|
|
|
|
*
|
|
|
|
* This thread looks at current RPM and decides if it should increase or decrease IAC duty cycle.
|
2019-05-02 19:12:43 -07:00
|
|
|
* This file has the hardware & scheduling logic, desired idle level lives separately.
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* @date May 23, 2013
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
2019-09-29 12:14:08 -07:00
|
|
|
* enable verbose_idle
|
2019-09-13 18:07:34 -07:00
|
|
|
* disable verbose_idle
|
|
|
|
*
|
2015-07-10 06:01:56 -07:00
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi 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.
|
|
|
|
*
|
|
|
|
* rusEfi 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 this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
2015-11-09 16:03:32 -08:00
|
|
|
*
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2019-04-09 19:52:03 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_IDLE_CONTROL
|
2019-01-27 21:52:21 -08:00
|
|
|
#include "engine_configuration.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "rpm_calculator.h"
|
|
|
|
#include "idle_thread.h"
|
2020-11-03 15:06:32 -08:00
|
|
|
#include "idle_hardware.h"
|
2019-12-03 21:37:32 -08:00
|
|
|
#include "engine_math.h"
|
2019-08-25 21:19:13 -07:00
|
|
|
|
2019-08-28 21:10:47 -07:00
|
|
|
#include "engine.h"
|
|
|
|
#include "periodic_task.h"
|
|
|
|
#include "allsensors.h"
|
2020-04-01 17:21:03 -07:00
|
|
|
#include "sensor.h"
|
2020-05-08 18:39:35 -07:00
|
|
|
#include "dc_motors.h"
|
2019-08-25 21:19:13 -07:00
|
|
|
|
2020-11-03 15:06:32 -08:00
|
|
|
#if EFI_TUNER_STUDIO
|
|
|
|
#include "stepper.h"
|
|
|
|
#endif
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
static Logging *logger;
|
2019-10-08 18:02:51 -07:00
|
|
|
|
2020-03-29 16:06:03 -07:00
|
|
|
EXTERN_ENGINE;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2020-07-22 08:39:09 -07:00
|
|
|
// todo: move all static vars to engine->engineState.idle?
|
|
|
|
|
2017-05-28 10:44:26 -07:00
|
|
|
static bool shouldResetPid = false;
|
2019-08-31 12:38:01 -07:00
|
|
|
// The idea of 'mightResetPid' is to reset PID only once - each time when TPS > idlePidDeactivationTpsThreshold.
|
|
|
|
// The throttle pedal can be pressed for a long time, making the PID data obsolete (thus the reset is required).
|
|
|
|
// We set 'mightResetPid' to true only if PID was actually used (i.e. idlePid.getOutput() was called) to save some CPU resources.
|
|
|
|
// See automaticIdleController().
|
2018-03-30 05:42:13 -07:00
|
|
|
static bool mightResetPid = false;
|
2017-05-16 19:13:40 -07:00
|
|
|
|
2020-07-22 08:39:09 -07:00
|
|
|
// This is needed to slowly turn on the PID back after it was reset.
|
|
|
|
static bool wasResetPid = false;
|
|
|
|
// This is used when the PID configuration is changed, to guarantee the reset
|
|
|
|
static bool mustResetPid = false;
|
|
|
|
static efitimeus_t restoreAfterPidResetTimeUs = 0;
|
|
|
|
|
|
|
|
|
2020-07-10 11:19:51 -07:00
|
|
|
class PidWithOverrides : public PidIndustrial {
|
2019-09-11 17:46:50 -07:00
|
|
|
public:
|
|
|
|
float getOffset() const override {
|
2020-07-04 19:01:12 -07:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
EXPAND_Engine;
|
|
|
|
#endif
|
2020-07-07 22:12:08 -07:00
|
|
|
float result = parameters->offset;
|
2020-07-04 19:01:12 -07:00
|
|
|
#if EFI_FSIO
|
2019-09-11 17:46:50 -07:00
|
|
|
if (engineConfiguration->useFSIO12ForIdleOffset) {
|
2020-07-07 22:12:08 -07:00
|
|
|
return result + ENGINE(fsioState.fsioIdleOffset);
|
2019-09-11 17:46:50 -07:00
|
|
|
}
|
|
|
|
#endif /* EFI_FSIO */
|
2020-07-07 22:12:08 -07:00
|
|
|
return result;
|
2019-09-11 17:46:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
float getMinValue() const override {
|
2020-07-04 19:01:12 -07:00
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
EXPAND_Engine;
|
|
|
|
#endif
|
2020-07-07 22:12:08 -07:00
|
|
|
float result = parameters->minValue;
|
2020-07-04 19:01:12 -07:00
|
|
|
#if EFI_FSIO
|
2019-09-11 17:46:50 -07:00
|
|
|
if (engineConfiguration->useFSIO13ForIdleMinValue) {
|
2020-07-07 22:12:08 -07:00
|
|
|
return result + ENGINE(fsioState.fsioIdleMinValue);
|
2019-09-11 17:46:50 -07:00
|
|
|
}
|
|
|
|
#endif /* EFI_FSIO */
|
2020-07-07 22:12:08 -07:00
|
|
|
return result;
|
2019-09-11 17:46:50 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-12 18:35:01 -07:00
|
|
|
static PidWithOverrides industrialWithOverrideIdlePid;
|
2017-05-16 19:13:40 -07:00
|
|
|
|
2020-07-12 18:35:01 -07:00
|
|
|
#if EFI_IDLE_PID_CIC
|
|
|
|
// Use PID with CIC integrator
|
|
|
|
static PidCic idleCicPid;
|
|
|
|
#endif //EFI_IDLE_PID_CIC
|
|
|
|
|
|
|
|
Pid * getIdlePid(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
|
|
#if EFI_IDLE_PID_CIC
|
|
|
|
if (CONFIG(useCicPidForIdle)) {
|
|
|
|
return &idleCicPid;
|
|
|
|
}
|
|
|
|
#endif /* EFI_IDLE_PID_CIC */
|
|
|
|
return &industrialWithOverrideIdlePid;
|
2020-07-12 15:11:10 -07:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:06:26 -07:00
|
|
|
float getIdlePidOffset(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2020-07-12 18:35:01 -07:00
|
|
|
return getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->getOffset();
|
2020-07-04 19:01:12 -07:00
|
|
|
}
|
|
|
|
|
2020-07-12 16:06:26 -07:00
|
|
|
float getIdlePidMinValue(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2020-07-12 18:35:01 -07:00
|
|
|
return getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->getMinValue();
|
2020-07-07 22:12:08 -07:00
|
|
|
}
|
|
|
|
|
2017-08-01 13:27:16 -07:00
|
|
|
static uint32_t lastCrankingCyclesCounter = 0;
|
|
|
|
static float lastCrankingIacPosition;
|
|
|
|
|
2019-12-03 21:37:32 -08:00
|
|
|
static iacPidMultiplier_t iacPidMultMap("iacPidMultiplier");
|
|
|
|
|
2019-08-25 21:19:13 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void idleDebug(const char *msg, percent_t value) {
|
2018-01-23 09:05:14 -08:00
|
|
|
scheduleMsg(logger, "idle debug: %s%.2f", msg, value);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2020-07-12 18:13:04 -07:00
|
|
|
static void showIdleInfo(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2017-01-28 22:04:16 -08:00
|
|
|
const char * idleModeStr = getIdle_mode_e(engineConfiguration->idleMode);
|
2020-05-08 17:05:05 -07:00
|
|
|
scheduleMsg(logger, "useStepperIdle=%s useHbridges=%s",
|
|
|
|
boolToString(CONFIG(useStepperIdle)), boolToString(CONFIG(useHbridges)));
|
|
|
|
scheduleMsg(logger, "idleMode=%s position=%.2f",
|
|
|
|
idleModeStr, getIdlePosition());
|
2017-05-16 17:52:52 -07:00
|
|
|
|
2019-12-11 14:48:55 -08:00
|
|
|
if (CONFIG(useStepperIdle)) {
|
2020-05-06 17:06:50 -07:00
|
|
|
if (CONFIG(useHbridges)) {
|
2020-05-08 17:05:05 -07:00
|
|
|
scheduleMsg(logger, "Coil A:");
|
2020-11-16 17:05:35 -08:00
|
|
|
scheduleMsg(logger, " pin1=%s", hwPortname(CONFIG(stepperDcIo[0].directionPin1)));
|
|
|
|
scheduleMsg(logger, " pin2=%s", hwPortname(CONFIG(stepperDcIo[0].directionPin2)));
|
2020-05-08 17:05:05 -07:00
|
|
|
showDcMotorInfo(logger, 2);
|
|
|
|
scheduleMsg(logger, "Coil B:");
|
2020-11-16 17:05:35 -08:00
|
|
|
scheduleMsg(logger, " pin1=%s", hwPortname(CONFIG(stepperDcIo[1].directionPin1)));
|
|
|
|
scheduleMsg(logger, " pin2=%s", hwPortname(CONFIG(stepperDcIo[1].directionPin2)));
|
2020-05-08 17:05:05 -07:00
|
|
|
showDcMotorInfo(logger, 3);
|
2020-05-06 17:06:50 -07:00
|
|
|
} else {
|
|
|
|
scheduleMsg(logger, "directionPin=%s reactionTime=%.2f", hwPortname(CONFIG(idle).stepperDirectionPin),
|
|
|
|
engineConfiguration->idleStepperReactionTime);
|
|
|
|
scheduleMsg(logger, "stepPin=%s steps=%d", hwPortname(CONFIG(idle).stepperStepPin),
|
|
|
|
engineConfiguration->idleStepperTotalSteps);
|
|
|
|
scheduleMsg(logger, "enablePin=%s/%d", hwPortname(engineConfiguration->stepperEnablePin),
|
|
|
|
engineConfiguration->stepperEnablePinMode);
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
} else {
|
2020-04-06 14:55:41 -07:00
|
|
|
if (!CONFIG(isDoubleSolenoidIdle)) {
|
|
|
|
scheduleMsg(logger, "idle valve freq=%d on %s", CONFIG(idle).solenoidFrequency,
|
|
|
|
hwPortname(CONFIG(idle).solenoidPin));
|
|
|
|
} else {
|
|
|
|
scheduleMsg(logger, "idle valve freq=%d on %s", CONFIG(idle).solenoidFrequency,
|
|
|
|
hwPortname(CONFIG(idle).solenoidPin));
|
|
|
|
scheduleMsg(logger, " and %s", hwPortname(CONFIG(secondSolenoidPin)));
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-05-16 17:52:52 -07:00
|
|
|
|
|
|
|
if (engineConfiguration->idleMode == IM_AUTO) {
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->showPidStatus(logger, "idle");
|
2017-01-28 22:04:16 -08:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2020-07-12 18:13:04 -07:00
|
|
|
void setIdleMode(idle_mode_e value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
engineConfiguration->idleMode = value ? IM_AUTO : IM_MANUAL;
|
|
|
|
showIdleInfo();
|
|
|
|
}
|
|
|
|
|
2020-11-11 18:47:19 -08:00
|
|
|
percent_t getIdlePosition() {
|
2019-08-25 21:19:13 -07:00
|
|
|
return engine->engineState.idle.currentIdlePosition;
|
|
|
|
}
|
|
|
|
|
2020-07-26 09:03:36 -07:00
|
|
|
void setManualIdleValvePosition(int positionPercent) {
|
2019-08-28 21:10:47 -07:00
|
|
|
if (positionPercent < 1 || positionPercent > 99)
|
|
|
|
return;
|
|
|
|
scheduleMsg(logger, "setting idle valve position %d", positionPercent);
|
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
showIdleInfo();
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
// todo: this is not great that we have to write into configuration here
|
2019-12-11 14:48:55 -08:00
|
|
|
CONFIG(manIdlePosition) = positionPercent;
|
2019-08-28 21:10:47 -07:00
|
|
|
}
|
|
|
|
|
2019-08-25 21:19:13 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
|
2020-12-17 14:46:51 -08:00
|
|
|
int IdleController::getTargetRpm(float clt) const {
|
|
|
|
// TODO: bump target rpm based on AC and/or fan(s)?
|
|
|
|
|
|
|
|
float fsioBump = engine->fsioState.fsioIdleTargetRPMAdjustment;
|
|
|
|
|
|
|
|
return fsioBump + interpolate2d("cltRpm", clt, CONFIG(cltIdleRpmBins), CONFIG(cltIdleRpm));
|
|
|
|
}
|
|
|
|
|
2020-12-26 05:32:01 -08:00
|
|
|
IIdleController::Phase IdleController::determinePhase(int rpm, int targetRpm, SensorResult tps) const {
|
|
|
|
if (!engine->rpmCalculator.isRunning()) {
|
|
|
|
return Phase::Cranking;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tps) {
|
|
|
|
// If the TPS has failed, assume the engine is running
|
|
|
|
return Phase::Running;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if throttle pressed, we're out of the idle corner
|
|
|
|
if (tps.Value > CONFIG(idlePidDeactivationTpsThreshold)) {
|
|
|
|
return Phase::Running;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If rpm too high (but throttle not pressed), we're coasting
|
|
|
|
int maximumIdleRpm = targetRpm + CONFIG(idlePidRpmUpperLimit);
|
|
|
|
if (rpm > maximumIdleRpm) {
|
|
|
|
return Phase::Coasting;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No other conditions met, we are idling!
|
|
|
|
return Phase::Idling;
|
|
|
|
}
|
|
|
|
|
2020-12-26 16:34:42 -08:00
|
|
|
float IdleController::getCrankingOpenLoop(float clt) const {
|
|
|
|
return
|
|
|
|
CONFIG(crankingIACposition) // Base cranking position (cranking page)
|
|
|
|
* interpolate2d("cltCrankingT", clt, config->cltCrankingCorrBins, config->cltCrankingCorr);
|
|
|
|
}
|
|
|
|
|
|
|
|
float IdleController::getRunningOpenLoop(float clt, SensorResult tps) const {
|
|
|
|
float running =
|
|
|
|
CONFIG(manIdlePosition) // Base idle position (slider)
|
|
|
|
* interpolate2d("cltT", clt, config->cltIdleCorrBins, config->cltIdleCorr);
|
|
|
|
|
|
|
|
// Now we bump it by the AC/fan amount if necessary
|
|
|
|
running += engine->acSwitchState ? CONFIG(acIdleExtraOffset) : 0;
|
|
|
|
// TODO: fan idle bump needs its own config field
|
|
|
|
running += enginePins.fanRelay.getLogicValue() ? CONFIG(acIdleExtraOffset) : 0;
|
|
|
|
|
|
|
|
// Now bump it by the specified amount when the throttle is opened (if configured)
|
|
|
|
// nb: invalid tps will make no change, no explicit check required
|
|
|
|
running += interpolateClamped(
|
|
|
|
0, 0,
|
|
|
|
CONFIG(idlePidDeactivationTpsThreshold), CONFIG(iacByTpsTaper),
|
|
|
|
tps.value_or(0));
|
|
|
|
|
|
|
|
return clampF(0, running, 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
float IdleController::getOpenLoop(Phase phase, float clt, SensorResult tps) const {
|
|
|
|
float running = getRunningOpenLoop(clt, tps);
|
|
|
|
|
|
|
|
// Cranking value is either its own table, or the running value if not overriden
|
|
|
|
float cranking = CONFIG(overrideCrankingIacSetting) ? getCrankingOpenLoop(clt) : running;
|
|
|
|
|
|
|
|
// if we're cranking, nothing more to do.
|
|
|
|
if (phase == Phase::Cranking) {
|
|
|
|
return cranking;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interpolate between cranking and running over a short time
|
|
|
|
// This clamps once you fall off the end, so no explicit check for running required
|
|
|
|
auto revsSinceStart = engine->rpmCalculator.getRevolutionCounterSinceStart();
|
|
|
|
return interpolateClamped(0, cranking, CONFIG(afterCrankingIACtaperDuration), running, revsSinceStart);
|
|
|
|
}
|
|
|
|
|
2019-08-28 21:10:47 -07:00
|
|
|
static percent_t manualIdleController(float cltCorrection DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2016-02-15 15:02:03 -08:00
|
|
|
|
2019-12-11 14:48:55 -08:00
|
|
|
percent_t correctedPosition = cltCorrection * CONFIG(manIdlePosition);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-16 19:13:40 -07:00
|
|
|
return correctedPosition;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-09-07 18:35:55 -07:00
|
|
|
/**
|
|
|
|
* idle blip is a development tool: alternator PID research for instance have benefited from a repetitive change of RPM
|
|
|
|
*/
|
2018-07-29 09:23:55 -07:00
|
|
|
static percent_t blipIdlePosition;
|
2015-09-01 20:02:49 -07:00
|
|
|
static efitimeus_t timeToStopBlip = 0;
|
2020-11-03 15:06:32 -08:00
|
|
|
efitimeus_t timeToStopIdleTest = 0;
|
2015-09-01 20:02:49 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* I use this questionable feature to tune acceleration enrichment
|
|
|
|
*/
|
|
|
|
static void blipIdle(int idlePosition, int durationMs) {
|
|
|
|
if (timeToStopBlip != 0) {
|
|
|
|
return; // already in idle blip
|
|
|
|
}
|
2017-05-16 19:13:40 -07:00
|
|
|
blipIdlePosition = idlePosition;
|
2015-09-01 20:02:49 -07:00
|
|
|
timeToStopBlip = getTimeNowUs() + 1000 * durationMs;
|
|
|
|
}
|
|
|
|
|
2015-12-24 19:01:26 -08:00
|
|
|
static void finishIdleTestIfNeeded() {
|
|
|
|
if (timeToStopIdleTest != 0 && getTimeNowUs() > timeToStopIdleTest)
|
|
|
|
timeToStopIdleTest = 0;
|
|
|
|
}
|
|
|
|
|
2015-09-01 20:02:49 -07:00
|
|
|
static void undoIdleBlipIfNeeded() {
|
|
|
|
if (timeToStopBlip != 0 && getTimeNowUs() > timeToStopBlip) {
|
|
|
|
timeToStopBlip = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-29 09:23:55 -07:00
|
|
|
/**
|
|
|
|
* @return idle valve position percentage for automatic closed loop mode
|
|
|
|
*/
|
2020-12-29 04:49:10 -08:00
|
|
|
static percent_t automaticIdleController(float tpsPos, float rpm, int targetRpm, IIdleController::Phase phase DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
if (shouldResetPid) {
|
|
|
|
// we reset only if I-term is negative, because the positive I-term is good - it keeps RPM from dropping too low
|
|
|
|
if (getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->getIntegration() <= 0 || mustResetPid) {
|
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->reset();
|
|
|
|
mustResetPid = false;
|
|
|
|
}
|
|
|
|
// alternatorPidResetCounter++;
|
|
|
|
shouldResetPid = false;
|
|
|
|
wasResetPid = true;
|
|
|
|
}
|
2020-07-10 12:06:55 -07:00
|
|
|
|
2020-07-10 11:03:07 -07:00
|
|
|
// todo: move this to pid_s one day
|
2020-07-12 18:35:01 -07:00
|
|
|
industrialWithOverrideIdlePid.antiwindupFreq = engineConfiguration->idle_antiwindupFreq;
|
|
|
|
industrialWithOverrideIdlePid.derivativeFilterLoss = engineConfiguration->idle_derivativeFilterLoss;
|
2020-07-10 11:03:07 -07:00
|
|
|
|
2020-07-22 08:39:09 -07:00
|
|
|
efitimeus_t nowUs = getTimeNowUs();
|
2019-09-10 20:03:55 -07:00
|
|
|
|
2020-12-29 04:49:10 -08:00
|
|
|
if (phase != IIdleController::Phase::Idling) {
|
2020-07-22 08:39:09 -07:00
|
|
|
// Don't store old I and D terms if PID doesn't work anymore.
|
|
|
|
// Otherwise they will affect the idle position much later, when the throttle is closed.
|
|
|
|
if (mightResetPid) {
|
|
|
|
mightResetPid = false;
|
|
|
|
shouldResetPid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
engine->engineState.idle.idleState = TPS_THRESHOLD;
|
|
|
|
// just leave IAC position as is (but don't return currentIdlePosition - it may already contain additionalAir)
|
|
|
|
return engine->engineState.idle.baseIdlePosition;
|
|
|
|
}
|
|
|
|
|
2020-07-06 13:40:16 -07:00
|
|
|
// #1553 we need to give FSIO variable offset or minValue a chance
|
2020-07-22 08:39:09 -07:00
|
|
|
bool acToggleJustTouched = (nowUs - engine->acSwitchLastChangeTime) < MS2US(500);
|
2019-09-11 17:46:50 -07:00
|
|
|
// check if within the dead zone
|
2020-07-06 13:40:16 -07:00
|
|
|
if (!acToggleJustTouched && absI(rpm - targetRpm) <= CONFIG(idlePidRpmDeadZone)) {
|
2019-07-21 15:34:37 -07:00
|
|
|
engine->engineState.idle.idleState = RPM_DEAD_ZONE;
|
2018-07-29 09:23:55 -07:00
|
|
|
// current RPM is close enough, no need to change anything
|
2019-07-21 14:06:16 -07:00
|
|
|
return engine->engineState.idle.baseIdlePosition;
|
2018-07-29 09:23:55 -07:00
|
|
|
}
|
2018-03-30 05:42:13 -07:00
|
|
|
|
|
|
|
// When rpm < targetRpm, there's a risk of dropping RPM too low - and the engine dies out.
|
|
|
|
// So PID reaction should be increased by adding extra percent to PID-error:
|
|
|
|
percent_t errorAmpCoef = 1.0f;
|
|
|
|
if (rpm < targetRpm)
|
|
|
|
errorAmpCoef += (float)CONFIG(pidExtraForLowRpm) / PERCENT_MULT;
|
2020-07-22 08:39:09 -07:00
|
|
|
|
|
|
|
// if PID was previously reset, we store the time when it turned on back (see errorAmpCoef correction below)
|
|
|
|
if (wasResetPid) {
|
|
|
|
restoreAfterPidResetTimeUs = nowUs;
|
|
|
|
wasResetPid = false;
|
|
|
|
}
|
|
|
|
// increase the errorAmpCoef slowly to restore the process correctly after the PID reset
|
|
|
|
// todo: move restoreAfterPidResetTimeUs to engineState.idle?
|
|
|
|
efitimeus_t timeSincePidResetUs = nowUs - /*engine->engineState.idle.*/restoreAfterPidResetTimeUs;
|
|
|
|
// todo: add 'pidAfterResetDampingPeriodMs' setting
|
|
|
|
errorAmpCoef = interpolateClamped(0.0f, 0.0f, MS2US(/*CONFIG(pidAfterResetDampingPeriodMs)*/1000), errorAmpCoef, timeSincePidResetUs);
|
2018-03-30 05:42:13 -07:00
|
|
|
// If errorAmpCoef > 1.0, then PID thinks that RPM is lower than it is, and controls IAC more aggressively
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->setErrorAmplification(errorAmpCoef);
|
2018-03-30 05:42:13 -07:00
|
|
|
|
2020-11-11 18:47:19 -08:00
|
|
|
percent_t newValue = getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->getOutput(targetRpm, rpm, SLOW_CALLBACK_PERIOD_MS / 1000.0f);
|
2019-07-21 15:34:37 -07:00
|
|
|
engine->engineState.idle.idleState = PID_VALUE;
|
2019-03-21 20:50:50 -07:00
|
|
|
|
2018-03-30 05:42:13 -07:00
|
|
|
// the state of PID has been changed, so we might reset it now, but only when needed (see idlePidDeactivationTpsThreshold)
|
|
|
|
mightResetPid = true;
|
2016-06-26 18:02:40 -07:00
|
|
|
|
2019-12-03 21:37:32 -08:00
|
|
|
// Apply PID Multiplier if used
|
|
|
|
if (CONFIG(useIacPidMultTable)) {
|
2020-07-05 15:14:55 -07:00
|
|
|
float engineLoad = getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2019-12-03 21:37:32 -08:00
|
|
|
float multCoef = iacPidMultMap.getValue(rpm / RPM_1_BYTE_PACKING_MULT, engineLoad);
|
|
|
|
// PID can be completely disabled of multCoef==0, or it just works as usual if multCoef==1
|
|
|
|
newValue = interpolateClamped(0.0f, engine->engineState.idle.baseIdlePosition, 1.0f, newValue, multCoef);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply PID Deactivation Threshold as a smooth taper for TPS transients.
|
|
|
|
// if tps==0 then PID just works as usual, or we completely disable it if tps>=threshold
|
2019-12-11 14:48:55 -08:00
|
|
|
newValue = interpolateClamped(0.0f, newValue, CONFIG(idlePidDeactivationTpsThreshold), engine->engineState.idle.baseIdlePosition, tpsPos);
|
2017-12-27 14:56:04 -08:00
|
|
|
|
2018-03-30 05:42:13 -07:00
|
|
|
// Interpolate to the manual position when RPM is close to the upper RPM limit (if idlePidRpmUpperLimit is set).
|
|
|
|
// If RPM increases and the throttle is closed, then we're in coasting mode, and we should smoothly disable auto-pid.
|
|
|
|
// If we just leave IAC at baseIdlePosition (as in case of TPS deactivation threshold), RPM would get stuck.
|
|
|
|
// That's why there's 'useIacTableForCoasting' setting which involves a separate IAC position table for coasting (iacCoasting).
|
|
|
|
// Currently it's user-defined. But eventually we'll use a real calculated and stored IAC position instead.
|
|
|
|
int idlePidLowerRpm = targetRpm + CONFIG(idlePidRpmDeadZone);
|
|
|
|
if (CONFIG(idlePidRpmUpperLimit) > 0) {
|
2019-07-21 15:34:37 -07:00
|
|
|
engine->engineState.idle.idleState = PID_UPPER;
|
2020-04-15 06:48:17 -07:00
|
|
|
const auto [cltValid, clt] = Sensor::get(SensorType::Clt);
|
|
|
|
if (CONFIG(useIacTableForCoasting) && cltValid) {
|
|
|
|
percent_t iacPosForCoasting = interpolate2d("iacCoasting", clt, CONFIG(iacCoastingBins), CONFIG(iacCoasting));
|
2018-03-30 05:42:13 -07:00
|
|
|
newValue = interpolateClamped(idlePidLowerRpm, newValue, idlePidLowerRpm + CONFIG(idlePidRpmUpperLimit), iacPosForCoasting, rpm);
|
|
|
|
} else {
|
|
|
|
// Well, just leave it as is, without PID regulation...
|
2019-07-21 14:06:16 -07:00
|
|
|
newValue = engine->engineState.idle.baseIdlePosition;
|
2018-03-30 05:42:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-16 19:13:40 -07:00
|
|
|
return newValue;
|
2016-06-26 18:02:40 -07:00
|
|
|
}
|
|
|
|
|
2020-11-11 18:47:19 -08:00
|
|
|
float IdleController::getIdlePosition() {
|
|
|
|
efiAssert(OBD_PCM_Processor_Fault, engineConfiguration != NULL, "engineConfiguration pointer", 0);
|
2017-02-11 23:02:24 -08:00
|
|
|
/*
|
|
|
|
* Here we have idle logic thread - actual stepper movement is implemented in a separate
|
|
|
|
* working thread,
|
|
|
|
* @see stepper.cpp
|
|
|
|
*/
|
|
|
|
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->iTermMin = engineConfiguration->idlerpmpid_iTermMin;
|
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->iTermMax = engineConfiguration->idlerpmpid_iTermMax;
|
2019-09-01 21:19:06 -07:00
|
|
|
|
2020-12-26 16:44:40 -08:00
|
|
|
|
|
|
|
// On failed sensor, use 0 deg C - should give a safe highish idle
|
|
|
|
float clt = Sensor::get(SensorType::Clt).value_or(0);
|
|
|
|
auto tps = Sensor::get(SensorType::DriverThrottleIntent);
|
|
|
|
|
|
|
|
float rpm;
|
|
|
|
if (CONFIG(useInstantRpmForIdle)) {
|
|
|
|
efitick_t nowNt = getTimeNowNt();
|
|
|
|
rpm = engine->triggerCentral.triggerState.calculateInstantRpm(&engine->triggerCentral.triggerFormDetails, NULL, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
} else {
|
|
|
|
rpm = GET_RPM();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the target we're shooting for
|
|
|
|
auto targetRpm = getTargetRpm(clt);
|
2020-04-03 16:59:08 -07:00
|
|
|
|
2020-12-29 04:49:10 -08:00
|
|
|
// Determine what operation phase we're in - idling or not
|
|
|
|
auto phase = determinePhase(rpm, targetRpm, tps);
|
|
|
|
|
2020-04-03 16:59:08 -07:00
|
|
|
engine->engineState.isAutomaticIdle = tps.Valid && engineConfiguration->idleMode == IM_AUTO;
|
2019-09-01 12:46:40 -07:00
|
|
|
|
|
|
|
if (engineConfiguration->isVerboseIAC && engine->engineState.isAutomaticIdle) {
|
2020-11-03 15:06:32 -08:00
|
|
|
scheduleMsg(logger, "Idle state %s", getIdle_state_e(engine->engineState.idle.idleState));
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->showPidStatus(logger, "idle");
|
2018-07-29 09:23:55 -07:00
|
|
|
}
|
|
|
|
|
2015-12-24 19:01:26 -08:00
|
|
|
finishIdleTestIfNeeded();
|
2015-09-01 20:02:49 -07:00
|
|
|
undoIdleBlipIfNeeded();
|
|
|
|
|
2018-03-30 05:42:13 -07:00
|
|
|
// cltCorrection is used only for cranking or running in manual mode
|
2017-12-27 14:56:04 -08:00
|
|
|
float cltCorrection;
|
|
|
|
// Use separate CLT correction table for cranking
|
2020-12-29 04:49:10 -08:00
|
|
|
if (engineConfiguration->overrideCrankingIacSetting && phase == IIdleController::Phase::Cranking) {
|
2019-07-09 11:16:36 -07:00
|
|
|
cltCorrection = interpolate2d("cltCrankingT", clt, config->cltCrankingCorrBins, config->cltCrankingCorr);
|
2019-02-26 18:50:58 -08:00
|
|
|
} else {
|
|
|
|
// this value would be ignored if running in AUTO mode
|
|
|
|
// but we need it while cranking in AUTO mode
|
2019-07-09 11:16:36 -07:00
|
|
|
cltCorrection = interpolate2d("cltT", clt, config->cltIdleCorrBins, config->cltIdleCorr);
|
2019-02-26 18:50:58 -08:00
|
|
|
}
|
2017-05-16 19:13:40 -07:00
|
|
|
|
2018-07-29 09:23:55 -07:00
|
|
|
percent_t iacPosition;
|
2017-05-16 19:13:40 -07:00
|
|
|
|
|
|
|
if (timeToStopBlip != 0) {
|
|
|
|
iacPosition = blipIdlePosition;
|
2019-07-21 14:06:16 -07:00
|
|
|
engine->engineState.idle.baseIdlePosition = iacPosition;
|
2019-07-21 15:34:37 -07:00
|
|
|
engine->engineState.idle.idleState = BLIP;
|
2020-12-29 04:49:10 -08:00
|
|
|
} else if (phase == IIdleController::Phase::Cranking) {
|
2019-05-25 10:36:29 -07:00
|
|
|
// during cranking it's always manual mode, PID would make no sense during cranking
|
2020-04-20 11:11:40 -07:00
|
|
|
iacPosition = clampPercentValue(cltCorrection * engineConfiguration->crankingIACposition);
|
2017-08-01 13:27:16 -07:00
|
|
|
// save cranking position & cycles counter for taper transition
|
|
|
|
lastCrankingIacPosition = iacPosition;
|
|
|
|
lastCrankingCyclesCounter = engine->rpmCalculator.getRevolutionCounterSinceStart();
|
2019-07-21 14:06:16 -07:00
|
|
|
engine->engineState.idle.baseIdlePosition = iacPosition;
|
2016-06-26 18:02:40 -07:00
|
|
|
} else {
|
2020-04-03 16:59:08 -07:00
|
|
|
if (!tps.Valid || engineConfiguration->idleMode == IM_MANUAL) {
|
2017-08-01 13:27:16 -07:00
|
|
|
// let's re-apply CLT correction
|
2019-08-28 21:10:47 -07:00
|
|
|
iacPosition = manualIdleController(cltCorrection PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-08-01 13:27:16 -07:00
|
|
|
} else {
|
2020-12-29 04:49:10 -08:00
|
|
|
iacPosition = automaticIdleController(tps.Value, rpm, targetRpm, phase PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-08-01 13:27:16 -07:00
|
|
|
}
|
2017-11-03 15:04:24 -07:00
|
|
|
|
2020-04-20 11:11:40 -07:00
|
|
|
iacPosition = clampPercentValue(iacPosition);
|
|
|
|
|
2017-12-27 14:56:04 -08:00
|
|
|
// store 'base' iacPosition without adjustments
|
2019-07-21 14:06:16 -07:00
|
|
|
engine->engineState.idle.baseIdlePosition = iacPosition;
|
2020-04-03 16:59:08 -07:00
|
|
|
|
2017-11-03 15:04:24 -07:00
|
|
|
float additionalAir = (float)engineConfiguration->iacByTpsTaper;
|
2020-04-03 16:59:08 -07:00
|
|
|
|
|
|
|
if (tps.Valid) {
|
|
|
|
iacPosition += interpolateClamped(0.0f, 0.0f, CONFIG(idlePidDeactivationTpsThreshold), additionalAir, tps.Value);
|
|
|
|
}
|
2017-11-03 15:04:24 -07:00
|
|
|
|
2017-08-01 13:27:16 -07:00
|
|
|
// taper transition from cranking to running (uint32_t to float conversion is safe here)
|
|
|
|
if (engineConfiguration->afterCrankingIACtaperDuration > 0)
|
|
|
|
iacPosition = interpolateClamped(lastCrankingCyclesCounter, lastCrankingIacPosition,
|
|
|
|
lastCrankingCyclesCounter + engineConfiguration->afterCrankingIACtaperDuration, iacPosition,
|
|
|
|
engine->rpmCalculator.getRevolutionCounterSinceStart());
|
2017-05-16 19:13:40 -07:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-22 12:30:39 -07:00
|
|
|
if (engineConfiguration->debugMode == DBG_IDLE_CONTROL) {
|
|
|
|
if (engineConfiguration->idleMode == IM_AUTO) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
2017-07-23 07:29:10 -07:00
|
|
|
// see also tsOutputChannels->idlePosition
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->postState(&tsOutputChannels, 1000000);
|
2019-07-21 15:34:37 -07:00
|
|
|
tsOutputChannels.debugIntField4 = engine->engineState.idle.idleState;
|
2018-11-16 04:40:06 -08:00
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
2017-07-23 07:29:10 -07:00
|
|
|
} else {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_TUNER_STUDIO
|
2017-07-23 07:29:10 -07:00
|
|
|
tsOutputChannels.debugFloatField1 = iacPosition;
|
2020-11-03 15:06:32 -08:00
|
|
|
extern StepperMotor iacMotor;
|
2018-03-30 05:42:13 -07:00
|
|
|
tsOutputChannels.debugIntField1 = iacMotor.getTargetPosition();
|
2018-11-16 04:40:06 -08:00
|
|
|
#endif /* EFI_TUNER_STUDIO */
|
2017-05-22 12:30:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-21 14:06:16 -07:00
|
|
|
engine->engineState.idle.currentIdlePosition = iacPosition;
|
2020-11-11 18:47:19 -08:00
|
|
|
|
|
|
|
return iacPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IdleController::update() {
|
|
|
|
float position = getIdlePosition();
|
|
|
|
applyIACposition(position PASS_ENGINE_PARAMETER_SUFFIX);
|
2020-07-26 12:22:14 -07:00
|
|
|
}
|
2019-09-19 19:56:54 -07:00
|
|
|
|
|
|
|
IdleController idleControllerInstance;
|
2019-08-28 21:10:47 -07:00
|
|
|
|
2020-11-11 18:47:19 -08:00
|
|
|
void updateIdleControl()
|
|
|
|
{
|
|
|
|
idleControllerInstance.update();
|
|
|
|
}
|
|
|
|
|
2019-08-28 21:10:47 -07:00
|
|
|
static void applyPidSettings(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->updateFactors(engineConfiguration->idleRpmPid.pFactor, engineConfiguration->idleRpmPid.iFactor, engineConfiguration->idleRpmPid.dFactor);
|
2019-12-03 21:37:32 -08:00
|
|
|
iacPidMultMap.init(CONFIG(iacPidMultTable), CONFIG(iacPidMultLoadBins), CONFIG(iacPidMultRpmBins));
|
2019-08-28 21:10:47 -07:00
|
|
|
}
|
|
|
|
|
2019-08-29 20:50:20 -07:00
|
|
|
void setDefaultIdleParameters(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
|
|
|
|
engineConfiguration->idleRpmPid.pFactor = 0.1f;
|
|
|
|
engineConfiguration->idleRpmPid.iFactor = 0.05f;
|
|
|
|
engineConfiguration->idleRpmPid.dFactor = 0.0f;
|
2019-09-01 21:19:06 -07:00
|
|
|
|
2020-12-29 04:47:18 -08:00
|
|
|
engineConfiguration->idlerpmpid_iTermMin = -20;
|
|
|
|
engineConfiguration->idlerpmpid_iTermMax = 20;
|
|
|
|
|
|
|
|
// Good starting point is 10 degrees per 100 rpm, aka 0.1 deg/rpm
|
|
|
|
CONFIG(idleTimingPid).pFactor = 0.1f;
|
|
|
|
CONFIG(idleTimingPid).iFactor = 0;
|
|
|
|
CONFIG(idleTimingPid).dFactor = 0;
|
|
|
|
|
|
|
|
// Allow +- 10 degrees adjustment
|
|
|
|
CONFIG(idleTimingPid).minValue = -10;
|
|
|
|
CONFIG(idleTimingPid).minValue = 10;
|
|
|
|
|
|
|
|
// Idle region is target + 100 RPM
|
|
|
|
CONFIG(idlePidRpmUpperLimit) = 100;
|
2019-08-29 20:50:20 -07:00
|
|
|
}
|
|
|
|
|
2019-08-28 21:10:47 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-08-25 21:19:13 -07:00
|
|
|
void onConfigurationChangeIdleCallback(engine_configuration_s *previousConfiguration) {
|
2020-07-12 18:35:01 -07:00
|
|
|
shouldResetPid = !getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->isSame(&previousConfiguration->idleRpmPid);
|
2020-07-22 08:39:09 -07:00
|
|
|
mustResetPid = shouldResetPid;
|
2019-08-25 21:19:13 -07:00
|
|
|
}
|
|
|
|
|
2017-01-06 14:01:28 -08:00
|
|
|
void setTargetIdleRpm(int value) {
|
2017-12-24 19:05:16 -08:00
|
|
|
setTargetRpmCurve(value PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
scheduleMsg(logger, "target idle RPM %d", value);
|
2017-05-22 20:25:34 -07:00
|
|
|
showIdleInfo();
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2015-11-09 16:03:32 -08:00
|
|
|
|
2017-05-22 20:25:34 -07:00
|
|
|
void setIdleOffset(float value) {
|
|
|
|
engineConfiguration->idleRpmPid.offset = value;
|
|
|
|
showIdleInfo();
|
2015-10-19 19:02:51 -07:00
|
|
|
}
|
|
|
|
|
2017-01-06 13:03:41 -08:00
|
|
|
void setIdlePFactor(float value) {
|
2016-02-05 13:01:55 -08:00
|
|
|
engineConfiguration->idleRpmPid.pFactor = value;
|
2019-08-28 21:10:47 -07:00
|
|
|
applyPidSettings();
|
2015-10-19 19:02:51 -07:00
|
|
|
showIdleInfo();
|
|
|
|
}
|
|
|
|
|
2017-01-06 13:03:41 -08:00
|
|
|
void setIdleIFactor(float value) {
|
2016-02-05 13:01:55 -08:00
|
|
|
engineConfiguration->idleRpmPid.iFactor = value;
|
2019-08-28 21:10:47 -07:00
|
|
|
applyPidSettings();
|
2015-10-19 19:02:51 -07:00
|
|
|
showIdleInfo();
|
|
|
|
}
|
|
|
|
|
2017-01-06 13:03:41 -08:00
|
|
|
void setIdleDFactor(float value) {
|
2016-02-05 13:01:55 -08:00
|
|
|
engineConfiguration->idleRpmPid.dFactor = value;
|
2019-08-28 21:10:47 -07:00
|
|
|
applyPidSettings();
|
2015-10-19 19:02:51 -07:00
|
|
|
showIdleInfo();
|
|
|
|
}
|
|
|
|
|
2019-01-13 16:41:39 -08:00
|
|
|
/**
|
|
|
|
* Idle test would activate the solenoid for three seconds
|
|
|
|
*/
|
2016-12-26 18:04:16 -08:00
|
|
|
void startIdleBench(void) {
|
2015-12-24 19:01:26 -08:00
|
|
|
timeToStopIdleTest = getTimeNowUs() + MS2US(3000); // 3 seconds
|
2015-12-26 13:01:56 -08:00
|
|
|
scheduleMsg(logger, "idle valve bench test");
|
|
|
|
showIdleInfo();
|
2015-12-24 19:01:26 -08:00
|
|
|
}
|
|
|
|
|
2019-08-28 21:10:47 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
|
|
|
|
void startIdleThread(Logging*sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-11-09 16:03:32 -08:00
|
|
|
logger = sharedLogger;
|
2019-12-02 20:08:18 -08:00
|
|
|
INJECT_ENGINE_REFERENCE(&idleControllerInstance);
|
2020-11-18 16:51:51 -08:00
|
|
|
INJECT_ENGINE_REFERENCE(&industrialWithOverrideIdlePid);
|
2015-11-09 16:03:32 -08:00
|
|
|
|
2020-12-17 14:46:51 -08:00
|
|
|
ENGINE(idleController) = &idleControllerInstance;
|
|
|
|
|
2020-07-12 18:35:01 -07:00
|
|
|
getIdlePid(PASS_ENGINE_PARAMETER_SIGNATURE)->initPidClass(&engineConfiguration->idleRpmPid);
|
2019-08-28 21:10:47 -07:00
|
|
|
|
2019-10-30 17:51:20 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
// todo: we still have to explicitly init all hardware on start in addition to handling configuration change via
|
|
|
|
// 'applyNewHardwareSettings' todo: maybe unify these two use-cases?
|
2020-11-03 15:06:32 -08:00
|
|
|
initIdleHardware(sharedLogger PASS_ENGINE_PARAMETER_SUFFIX);
|
2019-10-30 17:51:20 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-08-31 21:45:36 -07:00
|
|
|
DISPLAY_STATE(Engine)
|
2019-07-21 15:34:37 -07:00
|
|
|
DISPLAY_TEXT(Idle_State);
|
|
|
|
engine->engineState.idle.DISPLAY_FIELD(idleState) = INIT;
|
|
|
|
DISPLAY_TEXT(EOL);
|
|
|
|
DISPLAY_TEXT(Base_Position);
|
|
|
|
engine->engineState.idle.DISPLAY_FIELD(baseIdlePosition) = -100.0f;
|
|
|
|
DISPLAY_TEXT(Position_with_Adjustments);
|
|
|
|
engine->engineState.idle.DISPLAY_FIELD(currentIdlePosition) = -100.0f;
|
|
|
|
DISPLAY_TEXT(EOL);
|
2019-08-30 15:17:10 -07:00
|
|
|
DISPLAY_TEXT(EOL);
|
|
|
|
DISPLAY_SENSOR(TPS);
|
2019-08-31 14:07:21 -07:00
|
|
|
DISPLAY_TEXT(EOL);
|
2019-07-21 15:34:37 -07:00
|
|
|
DISPLAY_TEXT(Throttle_Up_State);
|
2019-08-30 15:17:10 -07:00
|
|
|
DISPLAY(DISPLAY_FIELD(throttlePedalUpState));
|
2019-07-21 15:34:37 -07:00
|
|
|
DISPLAY(DISPLAY_CONFIG(throttlePedalUpPin));
|
2019-07-21 14:06:16 -07:00
|
|
|
|
2019-09-01 12:46:40 -07:00
|
|
|
DISPLAY_TEXT(eol);
|
|
|
|
DISPLAY(DISPLAY_IF(isAutomaticIdle))
|
|
|
|
|
|
|
|
DISPLAY_STATE(idle_pid)
|
|
|
|
DISPLAY_TEXT(Output);
|
|
|
|
DISPLAY(DISPLAY_FIELD(output));
|
|
|
|
DISPLAY_TEXT(iTerm);
|
|
|
|
DISPLAY(DISPLAY_FIELD(iTerm));
|
|
|
|
DISPLAY_TEXT(eol);
|
|
|
|
|
|
|
|
DISPLAY_TEXT(Settings);
|
|
|
|
DISPLAY(DISPLAY_CONFIG(IDLERPMPID_PFACTOR));
|
|
|
|
DISPLAY(DISPLAY_CONFIG(IDLERPMPID_IFACTOR));
|
|
|
|
DISPLAY(DISPLAY_CONFIG(IDLERPMPID_DFACTOR));
|
|
|
|
DISPLAY(DISPLAY_CONFIG(IDLERPMPID_OFFSET));
|
|
|
|
|
2019-09-25 21:02:47 -07:00
|
|
|
|
|
|
|
DISPLAY_TEXT(eol);
|
|
|
|
DISPLAY_TEXT(ETB_Idle);
|
|
|
|
DISPLAY_STATE(Engine)
|
|
|
|
DISPLAY(DISPLAY_FIELD(etbIdleAddition));
|
2019-09-01 12:46:40 -07:00
|
|
|
/* DISPLAY_ELSE */
|
|
|
|
DISPLAY_TEXT(Manual_idle_control);
|
|
|
|
/* DISPLAY_ENDIF */
|
|
|
|
|
2019-07-21 14:06:16 -07:00
|
|
|
|
2017-05-16 17:18:28 -07:00
|
|
|
//scheduleMsg(logger, "initial idle %d", idlePositionController.value);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-08-25 21:19:13 -07:00
|
|
|
#if ! EFI_UNIT_TEST
|
2019-01-26 21:02:58 -08:00
|
|
|
// this is neutral/no gear switch input. on Miata it's wired both to clutch pedal and neutral in gearbox
|
2015-07-10 06:01:56 -07:00
|
|
|
// this switch is not used yet
|
2019-12-11 14:48:55 -08:00
|
|
|
if (CONFIG(clutchDownPin) != GPIO_UNASSIGNED) {
|
|
|
|
efiSetPadMode("clutch down switch", CONFIG(clutchDownPin),
|
|
|
|
getInputMode(CONFIG(clutchDownPinMode)));
|
2017-05-15 02:08:17 -07:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-11-30 07:24:37 -08:00
|
|
|
if (CONFIG(clutchUpPin) != GPIO_UNASSIGNED) {
|
|
|
|
efiSetPadMode("clutch up switch", CONFIG(clutchUpPin),
|
|
|
|
getInputMode(CONFIG(clutchUpPinMode)));
|
2017-05-15 02:08:17 -07:00
|
|
|
}
|
|
|
|
|
2019-07-21 14:06:16 -07:00
|
|
|
if (CONFIG(throttlePedalUpPin) != GPIO_UNASSIGNED) {
|
2019-07-21 17:11:12 -07:00
|
|
|
efiSetPadMode("throttle pedal up switch", CONFIG(throttlePedalUpPin),
|
2019-12-11 14:48:55 -08:00
|
|
|
getInputMode(CONFIG(throttlePedalUpPinMode)));
|
2019-07-21 14:06:16 -07:00
|
|
|
}
|
|
|
|
|
2017-05-15 02:08:17 -07:00
|
|
|
if (engineConfiguration->brakePedalPin != GPIO_UNASSIGNED) {
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_PROD_CODE
|
2017-05-15 05:40:54 -07:00
|
|
|
efiSetPadMode("brake pedal switch", engineConfiguration->brakePedalPin,
|
2017-05-15 02:08:17 -07:00
|
|
|
getInputMode(engineConfiguration->brakePedalPinMode));
|
2018-11-01 12:57:50 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2017-05-15 02:08:17 -07:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
addConsoleAction("idleinfo", showIdleInfo);
|
|
|
|
|
2015-09-01 20:02:49 -07:00
|
|
|
addConsoleActionII("blipidle", blipIdle);
|
2015-10-19 19:02:51 -07:00
|
|
|
|
2015-11-09 16:03:32 -08:00
|
|
|
// split this whole file into manual controller and auto controller? move these commands into the file
|
|
|
|
// which would be dedicated to just auto-controller?
|
2015-10-19 19:02:51 -07:00
|
|
|
|
2015-12-24 19:01:26 -08:00
|
|
|
addConsoleAction("idlebench", startIdleBench);
|
2019-08-25 21:19:13 -07:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2019-08-28 21:10:47 -07:00
|
|
|
applyPidSettings(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2018-10-30 05:21:50 -07:00
|
|
|
#endif /* EFI_IDLE_CONTROL */
|