2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file rpm_calculator.cpp
|
|
|
|
* @brief RPM calculator
|
|
|
|
*
|
|
|
|
* Here we listen to position sensor events in order to figure our if engine is currently running or not.
|
|
|
|
* Actual getRpm() is calculated once per crankshaft revolution, based on the amount of time passed
|
|
|
|
* since the start of previous shaft revolution.
|
|
|
|
*
|
2019-10-14 03:18:08 -07:00
|
|
|
* We also have 'instant RPM' logic separate from this 'cycle RPM' logic. Open question is why do we not use
|
|
|
|
* instant RPM instead of cycle RPM more often.
|
|
|
|
*
|
2015-07-10 06:01:56 -07:00
|
|
|
* @date Jan 1, 2013
|
2020-01-07 21:02:40 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*/
|
|
|
|
|
2019-11-19 22:42:03 -08:00
|
|
|
#include "globalaccess.h"
|
2019-07-05 17:03:32 -07:00
|
|
|
#include "os_access.h"
|
2019-01-20 21:10:09 -08:00
|
|
|
#include "engine.h"
|
2019-01-27 21:44:30 -08:00
|
|
|
#include "rpm_calculator.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#include "trigger_central.h"
|
|
|
|
#include "engine_configuration.h"
|
|
|
|
#include "engine_math.h"
|
2019-10-14 23:34:12 -07:00
|
|
|
#include "perf_trace.h"
|
2020-04-19 17:46:29 -07:00
|
|
|
#include "tooth_logger.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
#if EFI_PROD_CODE
|
2019-07-06 17:15:49 -07:00
|
|
|
#include "os_util.h"
|
2019-10-14 03:18:08 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SENSOR_CHART
|
2015-09-12 16:01:20 -07:00
|
|
|
#include "sensor_chart.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#endif
|
|
|
|
|
2019-03-31 14:44:34 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2015-07-15 18:01:45 -07:00
|
|
|
#if EFI_ENGINE_SNIFFER
|
|
|
|
#include "engine_sniffer.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
extern WaveChart waveChart;
|
2015-07-15 18:01:45 -07:00
|
|
|
#endif /* EFI_ENGINE_SNIFFER */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-03-03 05:55:19 -08:00
|
|
|
// See RpmCalculator::checkIfSpinning()
|
|
|
|
#ifndef NO_RPM_EVENTS_TIMEOUT_SECS
|
|
|
|
#define NO_RPM_EVENTS_TIMEOUT_SECS 2
|
|
|
|
#endif /* NO_RPM_EVENTS_TIMEOUT_SECS */
|
|
|
|
|
2019-06-08 06:51:36 -07:00
|
|
|
float RpmCalculator::getRpmAcceleration() const {
|
2019-01-31 14:55:23 -08:00
|
|
|
return 1.0 * previousRpmValue / rpmValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RpmCalculator::isStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
|
|
|
// Spinning-up with zero RPM means that the engine is not ready yet, and is treated as 'stopped'.
|
|
|
|
return state == STOPPED || (state == SPINNING_UP && rpmValue == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RpmCalculator::isCranking(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
|
|
|
// Spinning-up with non-zero RPM is suitable for all engine math, as good as cranking
|
|
|
|
return state == CRANKING || (state == SPINNING_UP && rpmValue > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RpmCalculator::isSpinningUp(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
|
|
|
return state == SPINNING_UP;
|
|
|
|
}
|
|
|
|
|
2019-06-08 06:51:36 -07:00
|
|
|
uint32_t RpmCalculator::getRevolutionCounterSinceStart(void) const {
|
2019-01-31 14:55:23 -08:00
|
|
|
return revolutionCounterSinceStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return -1 in case of isNoisySignal(), current RPM otherwise
|
2019-05-10 18:56:33 -07:00
|
|
|
* See NOISY_RPM
|
2019-01-31 14:55:23 -08:00
|
|
|
*/
|
|
|
|
// todo: migrate to float return result or add a float version? this would have with calculations
|
|
|
|
int RpmCalculator::getRpm(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
|
|
|
#if !EFI_PROD_CODE
|
|
|
|
if (mockRpm != MOCK_UNDEFINED) {
|
|
|
|
return mockRpm;
|
|
|
|
}
|
|
|
|
#endif /* EFI_PROD_CODE */
|
|
|
|
return rpmValue;
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SHAFT_POSITION_INPUT
|
2019-01-31 14:55:23 -08:00
|
|
|
|
2020-03-29 16:06:03 -07:00
|
|
|
EXTERN_ENGINE;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
static Logging * logger;
|
|
|
|
|
|
|
|
RpmCalculator::RpmCalculator() {
|
|
|
|
#if !EFI_PROD_CODE
|
|
|
|
mockRpm = MOCK_UNDEFINED;
|
2017-07-06 18:21:45 -07:00
|
|
|
#endif /* EFI_PROD_CODE */
|
2018-03-03 06:11:49 -08:00
|
|
|
// todo: reuse assignRpmValue() method which needs PASS_ENGINE_PARAMETER_SUFFIX
|
2019-01-13 20:20:19 -08:00
|
|
|
// which we cannot provide inside this parameter-less constructor. need a solution for this minor mess
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
// we need this initial to have not_running at first invocation
|
2020-01-30 22:21:56 -08:00
|
|
|
lastRpmEventTimeNt = (efitick_t) DEEP_IN_THE_PAST_SECONDS * NT_PER_SECOND;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return true if there was a full shaft revolution within the last second
|
|
|
|
*/
|
2019-01-24 20:44:29 -08:00
|
|
|
bool RpmCalculator::isRunning(DECLARE_ENGINE_PARAMETER_SIGNATURE) const {
|
2017-07-07 05:10:06 -07:00
|
|
|
return state == RUNNING;
|
2017-07-06 17:10:34 -07:00
|
|
|
}
|
|
|
|
|
2019-01-05 20:33:04 -08:00
|
|
|
/**
|
|
|
|
* @return true if engine is spinning (cranking or running)
|
|
|
|
*/
|
2019-01-24 20:44:29 -08:00
|
|
|
bool RpmCalculator::checkIfSpinning(efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) const {
|
2019-01-05 20:33:04 -08:00
|
|
|
if (ENGINE(needToStopEngine(nowNt))) {
|
|
|
|
return false;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-07-06 17:10:34 -07:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* note that the result of this subtraction could be negative, that would happen if
|
|
|
|
* we have a trigger event between the time we've invoked 'getTimeNow' and here
|
|
|
|
*/
|
2020-01-19 19:23:41 -08:00
|
|
|
bool noRpmEventsForTooLong = nowNt - lastRpmEventTimeNt >= NT_PER_SECOND * NO_RPM_EVENTS_TIMEOUT_SECS; // Anything below 60 rpm is not running
|
2018-03-10 17:58:51 -08:00
|
|
|
/**
|
|
|
|
* Also check if there were no trigger events
|
|
|
|
*/
|
2020-01-26 09:02:54 -08:00
|
|
|
bool noTriggerEventsForTooLong = nowNt - engine->triggerCentral.triggerState.previousShaftEventTimeNt >= NT_PER_SECOND;
|
2018-03-10 17:58:51 -08:00
|
|
|
if (noRpmEventsForTooLong || noTriggerEventsForTooLong) {
|
2017-07-06 17:10:34 -07:00
|
|
|
return false;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2017-07-06 17:10:34 -07:00
|
|
|
return true;
|
2017-07-06 16:33:25 -07:00
|
|
|
}
|
2016-03-15 19:03:43 -07:00
|
|
|
|
2019-11-05 21:31:24 -08:00
|
|
|
void RpmCalculator::assignRpmValue(float floatRpmValue DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
previousRpmValue = rpmValue;
|
2019-11-05 21:31:24 -08:00
|
|
|
// we still persist integer RPM! todo: figure out the next steps
|
|
|
|
rpmValue = floatRpmValue;
|
2015-07-10 06:01:56 -07:00
|
|
|
if (rpmValue <= 0) {
|
|
|
|
oneDegreeUs = NAN;
|
|
|
|
} else {
|
2019-11-05 21:31:24 -08:00
|
|
|
// here it's really important to have more precise float RPM value, see #796
|
|
|
|
oneDegreeUs = getOneDegreeTimeUs(floatRpmValue);
|
2018-03-10 17:58:51 -08:00
|
|
|
if (previousRpmValue == 0) {
|
|
|
|
/**
|
|
|
|
* this would make sure that we have good numbers for first cranking revolution
|
|
|
|
* #275 cranking could be improved
|
|
|
|
*/
|
|
|
|
ENGINE(periodicFastCallback(PASS_ENGINE_PARAMETER_SIGNATURE));
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-05 21:10:44 -08:00
|
|
|
void RpmCalculator::setRpmValue(float value DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2018-03-03 05:55:19 -08:00
|
|
|
assignRpmValue(value PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-03-10 17:58:51 -08:00
|
|
|
spinning_state_e oldState = state;
|
|
|
|
// Change state
|
2017-07-07 05:10:06 -07:00
|
|
|
if (rpmValue == 0) {
|
|
|
|
state = STOPPED;
|
2017-07-08 10:42:14 -07:00
|
|
|
} else if (rpmValue >= CONFIG(cranking.rpm)) {
|
2017-07-07 05:10:06 -07:00
|
|
|
state = RUNNING;
|
2018-03-10 17:58:51 -08:00
|
|
|
} else if (state == STOPPED || state == SPINNING_UP) {
|
2017-07-08 12:46:34 -07:00
|
|
|
/**
|
|
|
|
* We are here if RPM is above zero but we have not seen running RPM yet.
|
|
|
|
* This gives us cranking hysteresis - a drop of RPM during running is still running, not cranking.
|
|
|
|
*/
|
2017-07-08 10:42:14 -07:00
|
|
|
state = CRANKING;
|
2017-07-07 05:10:06 -07:00
|
|
|
}
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_ENGINE_CONTROL
|
2018-03-10 17:58:51 -08:00
|
|
|
// This presumably fixes injection mode change for cranking-to-running transition.
|
|
|
|
// 'isSimultanious' flag should be updated for events if injection modes differ for cranking and running.
|
|
|
|
if (state != oldState) {
|
|
|
|
engine->injectionEvents.addFuelEvents(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-01-24 20:44:29 -08:00
|
|
|
spinning_state_e RpmCalculator::getState() const {
|
2018-03-10 17:58:51 -08:00
|
|
|
return state;
|
2016-03-15 19:03:43 -07:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void RpmCalculator::onNewEngineCycle() {
|
|
|
|
revolutionCounterSinceBoot++;
|
|
|
|
revolutionCounterSinceStart++;
|
|
|
|
}
|
|
|
|
|
2019-10-14 03:18:08 -07:00
|
|
|
uint32_t RpmCalculator::getRevolutionCounterM(void) const {
|
2015-07-10 06:01:56 -07:00
|
|
|
return revolutionCounterSinceBoot;
|
|
|
|
}
|
|
|
|
|
2017-07-06 16:33:25 -07:00
|
|
|
void RpmCalculator::setStopped(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
|
|
revolutionCounterSinceStart = 0;
|
|
|
|
if (rpmValue != 0) {
|
2018-03-03 05:55:19 -08:00
|
|
|
assignRpmValue(0 PASS_ENGINE_PARAMETER_SUFFIX);
|
2017-07-06 17:10:34 -07:00
|
|
|
scheduleMsg(logger, "engine stopped");
|
2017-07-06 16:33:25 -07:00
|
|
|
}
|
2017-07-07 04:20:04 -07:00
|
|
|
state = STOPPED;
|
2017-07-06 16:33:25 -07:00
|
|
|
}
|
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
void RpmCalculator::setStopSpinning(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
|
|
|
|
isSpinning = false;
|
|
|
|
setStopped(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:11:09 -08:00
|
|
|
void RpmCalculator::setSpinningUp(efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2019-12-11 14:48:55 -08:00
|
|
|
if (!CONFIG(isFasterEngineSpinUpEnabled))
|
2018-03-10 17:58:51 -08:00
|
|
|
return;
|
|
|
|
// Only a completely stopped and non-spinning engine can enter the spinning-up state.
|
|
|
|
if (isStopped(PASS_ENGINE_PARAMETER_SIGNATURE) && !isSpinning) {
|
|
|
|
state = SPINNING_UP;
|
2019-01-24 18:12:55 -08:00
|
|
|
engine->triggerCentral.triggerState.spinningEventIndex = 0;
|
2018-03-10 17:58:51 -08:00
|
|
|
isSpinning = true;
|
|
|
|
}
|
|
|
|
// update variables needed by early instant RPM calc.
|
|
|
|
if (isSpinningUp(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
|
|
|
engine->triggerCentral.triggerState.setLastEventTimeForInstantRpm(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
}
|
2019-01-20 08:33:40 -08:00
|
|
|
/**
|
|
|
|
* Update ignition pin indices if needed. Here we potentially switch to wasted spark temporarily.
|
|
|
|
*/
|
|
|
|
prepareIgnitionPinIndices(getCurrentIgnitionMode(PASS_ENGINE_PARAMETER_SIGNATURE) PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-03-10 17:58:51 -08:00
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @brief Shaft position callback used by RPM calculation logic.
|
|
|
|
*
|
|
|
|
* This callback should always be the first of trigger callbacks because other callbacks depend of values
|
|
|
|
* updated here.
|
|
|
|
* This callback is invoked on interrupt thread.
|
|
|
|
*/
|
|
|
|
void rpmShaftPositionCallback(trigger_event_e ckpSignalType,
|
2020-01-09 12:45:13 -08:00
|
|
|
uint32_t index, efitick_t nowNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2019-12-13 15:02:24 -08:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6632, getCurrentRemainingStack() > EXPECTED_REMAINING_STACK, "lowstckRCL");
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
RpmCalculator *rpmState = &engine->rpmCalculator;
|
|
|
|
|
2017-05-25 19:49:40 -07:00
|
|
|
if (index == 0) {
|
2019-01-24 20:44:29 -08:00
|
|
|
bool hadRpmRecently = rpmState->checkIfSpinning(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-05-25 19:49:40 -07:00
|
|
|
if (hadRpmRecently) {
|
2019-12-21 18:11:09 -08:00
|
|
|
efitick_t diffNt = nowNt - rpmState->lastRpmEventTimeNt;
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* Four stroke cycle is two crankshaft revolutions
|
|
|
|
*
|
|
|
|
* We always do '* 2' because the event signal is already adjusted to 'per engine cycle'
|
|
|
|
* and each revolution of crankshaft consists of two engine cycles revolutions
|
|
|
|
*
|
|
|
|
*/
|
2017-05-25 19:49:40 -07:00
|
|
|
if (diffNt == 0) {
|
|
|
|
rpmState->setRpmValue(NOISY_RPM PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
} else {
|
2019-08-07 21:19:09 -07:00
|
|
|
int mult = (int)getEngineCycle(engine->getOperationMode(PASS_ENGINE_PARAMETER_SIGNATURE)) / 360;
|
2020-01-19 19:23:41 -08:00
|
|
|
float rpm = 60.0 * NT_PER_SECOND * mult / diffNt;
|
2017-05-25 19:49:40 -07:00
|
|
|
rpmState->setRpmValue(rpm > UNREALISTIC_RPM ? NOISY_RPM : rpm PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-05-25 19:49:40 -07:00
|
|
|
rpmState->onNewEngineCycle();
|
|
|
|
rpmState->lastRpmEventTimeNt = nowNt;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-05-25 19:49:40 -07:00
|
|
|
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_SENSOR_CHART
|
2016-05-28 21:01:59 -07:00
|
|
|
// this 'index==0' case is here so that it happens after cycle callback so
|
|
|
|
// it goes into sniffer report into the first position
|
2016-01-30 19:03:36 -08:00
|
|
|
if (ENGINE(sensorChartMode) == SC_TRIGGER) {
|
2017-05-25 19:49:40 -07:00
|
|
|
angle_t crankAngle = getCrankshaftAngleNt(nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
|
|
|
int signal = 1000 * ckpSignalType + index;
|
2015-07-26 21:01:35 -07:00
|
|
|
scAddData(crankAngle, signal);
|
|
|
|
}
|
2019-12-04 04:33:56 -08:00
|
|
|
#endif /* EFI_SENSOR_CHART */
|
2017-05-25 19:49:40 -07:00
|
|
|
|
2018-03-10 17:58:51 -08:00
|
|
|
if (rpmState->isSpinningUp(PASS_ENGINE_PARAMETER_SIGNATURE)) {
|
2019-01-24 18:12:55 -08:00
|
|
|
// we are here only once trigger is synchronized for the first time
|
|
|
|
// while transitioning from 'spinning' to 'running'
|
|
|
|
// Replace 'normal' RPM with instant RPM for the initial spin-up period
|
|
|
|
engine->triggerCentral.triggerState.movePreSynchTimestamps(PASS_ENGINE_PARAMETER_SIGNATURE);
|
2018-03-10 17:58:51 -08:00
|
|
|
int prevIndex;
|
2019-09-09 16:39:13 -07:00
|
|
|
int instantRpm = engine->triggerCentral.triggerState.calculateInstantRpm(&prevIndex, nowNt PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-03-10 17:58:51 -08:00
|
|
|
// validate instant RPM - we shouldn't skip the cranking state
|
2019-09-09 16:39:13 -07:00
|
|
|
instantRpm = minI(instantRpm, CONFIG(cranking.rpm) - 1);
|
|
|
|
rpmState->assignRpmValue(instantRpm PASS_ENGINE_PARAMETER_SUFFIX);
|
2018-03-10 17:58:51 -08:00
|
|
|
#if 0
|
2019-09-09 16:39:13 -07:00
|
|
|
scheduleMsg(logger, "** RPM: idx=%d sig=%d iRPM=%d", index, ckpSignalType, instantRpm);
|
2018-03-10 17:58:51 -08:00
|
|
|
#endif
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static scheduling_s tdcScheduler[2];
|
|
|
|
|
2016-08-09 21:04:24 -07:00
|
|
|
static char rpmBuffer[_MAX_FILLER];
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
2019-05-02 14:52:48 -07:00
|
|
|
* This callback has nothing to do with actual engine control, it just sends a Top Dead Center mark to the rusEfi console
|
2015-07-10 06:01:56 -07:00
|
|
|
* digital sniffer.
|
|
|
|
*/
|
2019-11-19 22:42:03 -08:00
|
|
|
static void onTdcCallback(Engine *engine) {
|
2019-12-23 18:58:06 -08:00
|
|
|
#if EFI_UNIT_TEST
|
2019-12-23 18:55:08 -08:00
|
|
|
if (!engine->needTdcCallback) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-23 18:58:06 -08:00
|
|
|
#endif /* EFI_UNIT_TEST */
|
2019-11-19 22:42:03 -08:00
|
|
|
EXPAND_Engine;
|
2019-01-21 18:48:58 -08:00
|
|
|
itoa10(rpmBuffer, GET_RPM());
|
2019-05-02 15:42:59 -07:00
|
|
|
#if EFI_ENGINE_SNIFFER
|
|
|
|
waveChart.startDataCollection();
|
|
|
|
#endif
|
2018-09-10 19:29:43 -07:00
|
|
|
addEngineSnifferEvent(TOP_DEAD_CENTER_MESSAGE, (char* ) rpmBuffer);
|
2020-04-19 17:57:01 -07:00
|
|
|
#if EFI_TOOTH_LOGGER
|
2020-04-19 17:46:29 -07:00
|
|
|
LogTriggerTopDeadCenter(getTimeNowNt() PASS_ENGINE_PARAMETER_SUFFIX);
|
2020-04-19 17:57:01 -07:00
|
|
|
#endif /* EFI_TOOTH_LOGGER */
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This trigger callback schedules the actual physical TDC callback in relation to trigger synchronization point.
|
|
|
|
*/
|
|
|
|
static void tdcMarkCallback(trigger_event_e ckpSignalType,
|
2020-01-09 12:45:13 -08:00
|
|
|
uint32_t index0, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
(void) ckpSignalType;
|
|
|
|
bool isTriggerSynchronizationPoint = index0 == 0;
|
2016-01-30 19:03:36 -08:00
|
|
|
if (isTriggerSynchronizationPoint && ENGINE(isEngineChartEnabled)) {
|
2019-12-23 17:19:13 -08:00
|
|
|
// two instances of scheduling_s are needed to properly handle event overlap
|
2019-10-14 03:18:08 -07:00
|
|
|
int revIndex2 = getRevolutionCounter() % 2;
|
2019-01-21 18:48:58 -08:00
|
|
|
int rpm = GET_RPM();
|
2018-08-31 18:11:22 -07:00
|
|
|
// todo: use tooth event-based scheduling, not just time-based scheduling
|
2015-07-10 06:01:56 -07:00
|
|
|
if (isValidRpm(rpm)) {
|
2020-04-20 19:43:55 -07:00
|
|
|
angle_t tdcPosition = tdcPosition();
|
2020-04-20 20:44:59 -07:00
|
|
|
// we need a positive angle offset here
|
2020-04-20 19:43:55 -07:00
|
|
|
fixAngle(tdcPosition, "tdcPosition", CUSTOM_ERR_6553);
|
|
|
|
scheduleByAngle(&tdcScheduler[revIndex2], edgeTimestamp, tdcPosition,
|
2020-01-07 15:10:31 -08:00
|
|
|
{ onTdcCallback, engine } PASS_ENGINE_PARAMETER_SUFFIX);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-19 22:42:03 -08:00
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return Current crankshaft angle, 0 to 720 for four-stroke
|
|
|
|
*/
|
2019-12-21 18:11:09 -08:00
|
|
|
float getCrankshaftAngleNt(efitick_t timeNt DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|
|
|
efitick_t timeSinceZeroAngleNt = timeNt
|
2015-07-10 06:01:56 -07:00
|
|
|
- engine->rpmCalculator.lastRpmEventTimeNt;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* even if we use 'getOneDegreeTimeUs' macros here, it looks like the
|
|
|
|
* compiler is not smart enough to figure out that "A / ( B / C)" could be optimized into
|
|
|
|
* "A * C / B" in order to replace a slower division with a faster multiplication.
|
|
|
|
*/
|
2019-01-21 18:48:58 -08:00
|
|
|
int rpm = GET_RPM();
|
2015-07-10 06:01:56 -07:00
|
|
|
return rpm == 0 ? NAN : timeSinceZeroAngleNt / getOneDegreeTimeNt(rpm);
|
|
|
|
}
|
|
|
|
|
2019-01-20 21:10:09 -08:00
|
|
|
void initRpmCalculator(Logging *sharedLogger DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2015-07-10 06:01:56 -07:00
|
|
|
logger = sharedLogger;
|
2016-06-01 17:01:36 -07:00
|
|
|
if (hasFirmwareError()) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
addTriggerEventListener(tdcMarkCallback, "chart TDC mark", engine);
|
|
|
|
|
|
|
|
addTriggerEventListener(rpmShaftPositionCallback, "rpm reporter", engine);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Schedules a callback 'angle' degree of crankshaft from now.
|
|
|
|
* The callback would be executed once after the duration of time which
|
|
|
|
* it takes the crankshaft to rotate to the specified angle.
|
|
|
|
*/
|
2020-02-01 14:29:55 -08:00
|
|
|
efitick_t scheduleByAngle(scheduling_s *timer, efitick_t edgeTimestamp, angle_t angle,
|
2020-01-06 21:41:18 -08:00
|
|
|
action_s action DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
2019-10-14 03:18:08 -07:00
|
|
|
float delayUs = ENGINE(rpmCalculator.oneDegreeUs) * angle;
|
2020-01-09 12:45:13 -08:00
|
|
|
|
|
|
|
efitime_t delayNt = US2NT(delayUs);
|
|
|
|
efitime_t delayedTime = edgeTimestamp + delayNt;
|
|
|
|
|
|
|
|
ENGINE(executor.scheduleByTimestampNt(timer, delayedTime, action));
|
2020-02-01 14:29:55 -08:00
|
|
|
|
|
|
|
return delayedTime;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
RpmCalculator::RpmCalculator() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* EFI_SHAFT_POSITION_INPUT */
|
|
|
|
|