2020-11-03 15:06:32 -08:00
|
|
|
/**
|
|
|
|
* @file idle_hardware.cpp
|
|
|
|
* @brief Idle Air Control valve hardware
|
|
|
|
*
|
|
|
|
* @date November 3, 2020
|
2024-02-16 12:21:33 -08:00
|
|
|
*
|
2020-11-03 15:06:32 -08:00
|
|
|
* This is just the hardware interface - deciding where to put the valve happens in idle_thread.cpp
|
|
|
|
*/
|
|
|
|
|
2021-07-25 22:05:17 -07:00
|
|
|
#include "pch.h"
|
2020-11-03 15:06:32 -08:00
|
|
|
|
|
|
|
#if EFI_IDLE_CONTROL
|
|
|
|
#include "idle_hardware.h"
|
|
|
|
|
|
|
|
#include "electronic_throttle.h"
|
|
|
|
|
|
|
|
#include "dc_motors.h"
|
|
|
|
#if ! EFI_UNIT_TEST
|
|
|
|
#include "stepper.h"
|
2022-01-07 07:09:48 -08:00
|
|
|
/* Storing two following structs in CCM memory cause HardFault (at least on F4)
|
|
|
|
* This need deep debuging. Until it is moved out of CMM. */
|
|
|
|
static StepDirectionStepper iacStepperHw /*CCM_OPTIONAL*/;
|
|
|
|
static DualHBridgeStepper iacHbridgeHw /*CCM_OPTIONAL*/;
|
2021-08-27 03:18:05 -07:00
|
|
|
StepperMotor iacMotor CCM_OPTIONAL;
|
2020-11-03 15:06:32 -08:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
|
|
|
|
static SimplePwm idleSolenoidOpen("idle open");
|
|
|
|
static SimplePwm idleSolenoidClose("idle close");
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void applyIACposition(percent_t position) {
|
2020-11-03 15:06:32 -08:00
|
|
|
/**
|
|
|
|
* currently idle level is an percent value (0-100 range), and PWM takes a float in the 0..1 range
|
|
|
|
* todo: unify?
|
|
|
|
*/
|
|
|
|
float duty = PERCENT_TO_DUTY(position);
|
|
|
|
|
|
|
|
#if EFI_ELECTRONIC_THROTTLE_BODY
|
2023-02-12 13:49:12 -08:00
|
|
|
setEtbIdlePosition(position);
|
2020-11-03 15:06:32 -08:00
|
|
|
#endif // EFI_ELECTRONIC_THROTTLE_BODY
|
2023-02-12 13:49:12 -08:00
|
|
|
|
|
|
|
#if EFI_UNIT_TEST
|
|
|
|
if (false) {
|
|
|
|
#endif // EFI_UNIT_TEST
|
|
|
|
|
2020-11-03 15:06:32 -08:00
|
|
|
#if ! EFI_UNIT_TEST
|
2023-02-12 13:49:12 -08:00
|
|
|
if (engineConfiguration->useStepperIdle) {
|
2020-11-03 15:06:32 -08:00
|
|
|
iacMotor.setTargetPosition(duty * engineConfiguration->idleStepperTotalSteps);
|
|
|
|
#endif /* EFI_UNIT_TEST */
|
|
|
|
} else {
|
2021-02-04 14:04:37 -08:00
|
|
|
// if not spinning or running a bench test, turn off the idle valve(s) to be quieter and save power
|
2022-12-17 11:43:51 -08:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2021-10-16 21:27:12 -07:00
|
|
|
if (!engine->triggerCentral.engineMovedRecently() && engine->timeToStopIdleTest == 0) {
|
2021-02-04 14:04:37 -08:00
|
|
|
idleSolenoidOpen.setSimplePwmDutyCycle(0);
|
|
|
|
idleSolenoidClose.setSimplePwmDutyCycle(0);
|
|
|
|
return;
|
|
|
|
}
|
2022-12-17 11:43:51 -08:00
|
|
|
#endif // EFI_SHAFT_POSITION_INPUT
|
2021-02-04 14:04:37 -08:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
if (!engineConfiguration->isDoubleSolenoidIdle) {
|
2020-11-03 15:06:32 -08:00
|
|
|
idleSolenoidOpen.setSimplePwmDutyCycle(duty);
|
|
|
|
} else {
|
2023-05-07 01:39:09 -07:00
|
|
|
// use 0.01..0.99 range
|
|
|
|
float idle_range = 0.98; // move to config?
|
2020-11-03 15:06:32 -08:00
|
|
|
|
2023-05-07 01:39:09 -07:00
|
|
|
float idle_open = 0.01 + idle_range * duty;
|
|
|
|
float idle_close = 0.01 + idle_range * (1.0 - duty);
|
2020-11-03 15:06:32 -08:00
|
|
|
|
|
|
|
idleSolenoidOpen.setSimplePwmDutyCycle(idle_open);
|
|
|
|
idleSolenoidClose.setSimplePwmDutyCycle(idle_close);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !EFI_UNIT_TEST
|
|
|
|
|
|
|
|
bool isIdleHardwareRestartNeeded() {
|
|
|
|
return isConfigurationChanged(stepperEnablePin) ||
|
|
|
|
isConfigurationChanged(stepperEnablePinMode) ||
|
|
|
|
isConfigurationChanged(idle.stepperStepPin) ||
|
|
|
|
isConfigurationChanged(idle.solenoidFrequency) ||
|
|
|
|
isConfigurationChanged(useStepperIdle) ||
|
|
|
|
isConfigurationChanged(idle.solenoidPin) ||
|
2022-01-07 08:38:48 -08:00
|
|
|
isConfigurationChanged(secondSolenoidPin) ||
|
|
|
|
isConfigurationChanged(useRawOutputToDriveIdleStepper) ||
|
|
|
|
isConfigurationChanged(stepper_raw_output[0]) ||
|
|
|
|
isConfigurationChanged(stepper_raw_output[1]) ||
|
|
|
|
isConfigurationChanged(stepper_raw_output[2]) ||
|
|
|
|
isConfigurationChanged(stepper_raw_output[3]);
|
2020-11-03 15:06:32 -08:00
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
bool isIdleMotorBusy() {
|
2021-11-17 00:54:21 -08:00
|
|
|
if (!engineConfiguration->useStepperIdle) {
|
2020-11-03 15:06:32 -08:00
|
|
|
// todo: check other motor types?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return iacMotor.isBusy();
|
|
|
|
}
|
|
|
|
|
2021-11-16 01:15:29 -08:00
|
|
|
void initIdleHardware() {
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engineConfiguration->useStepperIdle) {
|
2020-11-03 15:06:32 -08:00
|
|
|
StepperHw* hw;
|
|
|
|
|
2022-01-07 08:38:48 -08:00
|
|
|
if (engineConfiguration->useRawOutputToDriveIdleStepper) {
|
2024-02-16 12:21:33 -08:00
|
|
|
// four Push-Pull outputs to directly drive stepper idle air valve coils
|
2022-01-07 08:38:48 -08:00
|
|
|
auto motorA = initDcMotor(engineConfiguration->stepper_raw_output[0],
|
|
|
|
engineConfiguration->stepper_raw_output[1], ETB_COUNT + 0);
|
|
|
|
auto motorB = initDcMotor(engineConfiguration->stepper_raw_output[2],
|
|
|
|
engineConfiguration->stepper_raw_output[3], ETB_COUNT + 1);
|
|
|
|
|
2022-11-03 06:40:44 -07:00
|
|
|
iacHbridgeHw.initialize(
|
|
|
|
motorA,
|
|
|
|
motorB,
|
|
|
|
engineConfiguration->idleStepperReactionTime
|
|
|
|
);
|
2022-01-07 08:38:48 -08:00
|
|
|
|
|
|
|
hw = &iacHbridgeHw;
|
|
|
|
} else if (engineConfiguration->useHbridgesToDriveIdleStepper) {
|
2023-03-27 08:00:01 -07:00
|
|
|
auto motorA = initDcMotor("DC dis-1", engineConfiguration->stepperDcIo[0],
|
2023-03-26 04:28:35 -07:00
|
|
|
ETB_COUNT + 0, engineConfiguration->stepper_dc_use_two_wires);
|
2023-03-27 08:00:01 -07:00
|
|
|
auto motorB = initDcMotor("DC dis-2", engineConfiguration->stepperDcIo[1],
|
2023-03-26 04:28:35 -07:00
|
|
|
ETB_COUNT + 1, engineConfiguration->stepper_dc_use_two_wires);
|
2020-11-03 15:06:32 -08:00
|
|
|
|
2022-11-03 06:40:44 -07:00
|
|
|
iacHbridgeHw.initialize(
|
|
|
|
motorA,
|
|
|
|
motorB,
|
|
|
|
engineConfiguration->idleStepperReactionTime
|
|
|
|
);
|
2020-11-03 15:06:32 -08:00
|
|
|
|
|
|
|
hw = &iacHbridgeHw;
|
|
|
|
} else {
|
2024-02-16 12:21:33 -08:00
|
|
|
// like DRV8825?
|
2020-11-03 15:06:32 -08:00
|
|
|
iacStepperHw.initialize(
|
2021-11-17 00:54:21 -08:00
|
|
|
engineConfiguration->idle.stepperStepPin,
|
|
|
|
engineConfiguration->idle.stepperDirectionPin,
|
|
|
|
engineConfiguration->stepperDirectionPinMode,
|
|
|
|
engineConfiguration->idleStepperReactionTime,
|
|
|
|
engineConfiguration->stepperEnablePin,
|
|
|
|
engineConfiguration->stepperEnablePinMode
|
2020-11-03 15:06:32 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
hw = &iacStepperHw;
|
|
|
|
}
|
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
iacMotor.initialize(hw, engineConfiguration->idleStepperTotalSteps);
|
2023-02-12 13:49:12 -08:00
|
|
|
} else if (isBrainPinValid(engineConfiguration->idle.solenoidPin)) {
|
2020-12-13 16:23:26 -08:00
|
|
|
// we are here for single or double solenoid idle
|
|
|
|
|
2020-11-03 15:06:32 -08:00
|
|
|
/**
|
|
|
|
* Start PWM for idleValvePin
|
|
|
|
*/
|
|
|
|
// todo: even for double-solenoid mode we can probably use same single SimplePWM
|
2020-12-13 16:23:26 -08:00
|
|
|
startSimplePwm(&idleSolenoidOpen, "Idle Valve Open",
|
2024-07-11 17:03:13 -07:00
|
|
|
&engine->scheduler,
|
2020-12-13 16:23:26 -08:00
|
|
|
&enginePins.idleSolenoidPin,
|
2021-11-17 00:54:21 -08:00
|
|
|
engineConfiguration->idle.solenoidFrequency, PERCENT_TO_DUTY(engineConfiguration->manIdlePosition));
|
2020-12-13 16:23:26 -08:00
|
|
|
|
2021-11-17 00:54:21 -08:00
|
|
|
if (engineConfiguration->isDoubleSolenoidIdle) {
|
|
|
|
if (!isBrainPinValid(engineConfiguration->secondSolenoidPin)) {
|
2023-08-20 19:23:44 -07:00
|
|
|
criticalError("Second idle pin should be configured for double solenoid mode.");
|
2020-12-13 16:23:26 -08:00
|
|
|
return;
|
|
|
|
}
|
2020-11-03 15:06:32 -08:00
|
|
|
|
|
|
|
startSimplePwm(&idleSolenoidClose, "Idle Valve Close",
|
2024-07-11 17:03:13 -07:00
|
|
|
&engine->scheduler,
|
2020-11-15 21:06:11 -08:00
|
|
|
&enginePins.secondIdleSolenoidPin,
|
2021-11-17 00:54:21 -08:00
|
|
|
engineConfiguration->idle.solenoidFrequency, PERCENT_TO_DUTY(engineConfiguration->manIdlePosition));
|
2020-11-03 15:06:32 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // EFI_IDLE_HARDWARE
|