rusEFI
The most advanced open source ECU
Functions
rpm_calculator.cpp File Reference

Detailed Description

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.

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.

Date
Jan 1, 2013
Author
Andrey Belomutskiy, (c) 2012-2020

Definition in file rpm_calculator.cpp.

Functions

operation_mode_e lookupOperationMode ()
 
static bool doesTriggerImplyOperationMode (trigger_type_e type)
 
void rpmShaftPositionCallback (trigger_event_e ckpSignalType, uint32_t trgEventIndex, efitick_t nowNt)
 Shaft position callback used by RPM calculation logic. More...
 
static void onTdcCallback (void *)
 
void tdcMarkCallback (uint32_t trgEventIndex, efitick_t nowNt)
 
efitick_t scheduleByAngle (scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s action)
 

Function Documentation

◆ doesTriggerImplyOperationMode()

static bool doesTriggerImplyOperationMode ( trigger_type_e  type)
static

Definition at line 72 of file rpm_calculator.cpp.

72  {
73  switch (type) {
76  case trigger_type_e::TT_3_1_CAM: // huh why is this trigger with CAM suffix right in the name on this exception list?!
77  case trigger_type_e::TT_36_2_2_2: // this trigger is special due to rotary application https://github.com/rusefi/rusefi/issues/5566
80  // These modes could be either cam or crank speed
81  return false;
82  default:
83  return true;
84  }
85 }

Referenced by RpmCalculator::getOperationMode().

Here is the caller graph for this function:

◆ lookupOperationMode()

operation_mode_e lookupOperationMode ( )

Definition at line 61 of file rpm_calculator.cpp.

Referenced by RpmCalculator::getOperationMode(), and TriggerCentral::updateWaveform().

Here is the caller graph for this function:

◆ onTdcCallback()

static void onTdcCallback ( void *  )
static

This callback has nothing to do with actual engine control, it just sends a Top Dead Center mark to the rusEfi console digital sniffer.

Definition at line 346 of file rpm_calculator.cpp.

346  {
347 #if EFI_UNIT_TEST
348  if (!engine->needTdcCallback) {
349  return;
350  }
351 #endif /* EFI_UNIT_TEST */
352 
355 #if EFI_TOOTH_LOGGER
357 #endif /* EFI_TOOTH_LOGGER */
358 }
bool needTdcCallback
Definition: engine.h:226
static float getOrZero(SensorType type)
Definition: sensor.h:92
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
Engine * engine
void addEngineSnifferTdcEvent(int rpm)
void LogTriggerTopDeadCenter(efitick_t timestamp)

Referenced by tdcMarkCallback().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rpmShaftPositionCallback()

void rpmShaftPositionCallback ( trigger_event_e  ckpSignalType,
uint32_t  trgEventIndex,
efitick_t  nowNt 
)

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.

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

Definition at line 260 of file rpm_calculator.cpp.

261  {
262 
263  bool alwaysInstantRpm = engineConfiguration->alwaysInstantRpm;
264 
265  RpmCalculator *rpmState = &engine->rpmCalculator;
266 
267  if (trgEventIndex == 0) {
268  if (HAVE_CAM_INPUT()) {
270  }
271 
272 
273  bool hadRpmRecently = rpmState->checkIfSpinning(nowNt);
274 
275  float periodSeconds = engine->rpmCalculator.lastTdcTimer.getElapsedSecondsAndReset(nowNt);
276 
277  if (hadRpmRecently) {
278  /**
279  * Four stroke cycle is two crankshaft revolutions
280  *
281  * We always do '* 2' because the event signal is already adjusted to 'per engine cycle'
282  * and each revolution of crankshaft consists of two engine cycles revolutions
283  *
284  */
285  if (!alwaysInstantRpm) {
286  if (periodSeconds == 0) {
287  rpmState->setRpmValue(NOISY_RPM);
288  rpmState->rpmRate = 0;
289  } else {
290  // todo: extract utility method? see duplication with high_pressure_pump.cpp
291  int mult = (int)getEngineCycle(getEngineRotationState()->getOperationMode()) / 360;
292  float rpm = 60 * mult / periodSeconds;
293 
294  auto rpmDelta = rpm - rpmState->previousRpmValue;
295  rpmState->rpmRate = rpmDelta / (mult * periodSeconds);
296 
297  rpmState->setRpmValue(rpm > UNREALISTIC_RPM ? NOISY_RPM : rpm);
298  }
299  }
300  } else {
301  // we are here only once trigger is synchronized for the first time
302  // while transitioning from 'spinning' to 'running'
304  }
305 
306  rpmState->onNewEngineCycle();
307  }
308 
309 #if EFI_SENSOR_CHART
310  // this 'index==0' case is here so that it happens after cycle callback so
311  // it goes into sniffer report into the first position
312  if (getEngineState()->sensorChartMode == SC_TRIGGER) {
313  angle_t crankAngle = engine->triggerCentral.getCurrentEnginePhase(nowNt).value_or(0);
314  int signal = 1000 * ckpSignalType + trgEventIndex;
315  scAddData(crankAngle, signal);
316  }
317 #endif /* EFI_SENSOR_CHART */
318 
319  // Always update instant RPM even when not spinning up
322 
324  trgEventIndex, nowNt);
325 
327  if (alwaysInstantRpm) {
328  rpmState->setRpmValue(instantRpm);
329  } else if (rpmState->isSpinningUp()) {
330  rpmState->assignRpmValue(instantRpm);
331 #if 0
332  efiPrintf("** RPM: idx=%d sig=%d iRPM=%d", trgEventIndex, ckpSignalType, instantRpm);
333 #endif
334  }
335 }
TriggerCentral triggerCentral
Definition: engine.h:286
RpmCalculator rpmCalculator
Definition: engine.h:273
virtual operation_mode_e getOperationMode() const =0
sensor_chart_e sensorChartMode
Definition: engine_state.h:32
void updateInstantRpm(uint32_t current_index, TriggerWaveform const &triggerShape, TriggerFormDetails *triggerFormDetails, uint32_t index, efitick_t nowNt)
bool isSpinningUp() const
float previousRpmValue
bool checkIfSpinning(efitick_t nowNt) const
void setRpmValue(float value)
void assignRpmValue(float value)
InstantRpmCalculator instantRpm
PrimaryTriggerDecoder triggerState
TriggerWaveform triggerShape
TriggerFormDetails triggerFormDetails
expected< float > getCurrentEnginePhase(efitick_t nowNt) const
current_cycle_state_s currentCycle
EngineRotationState * getEngineRotationState()
Definition: engine.cpp:592
EngineState * getEngineState()
Definition: engine.cpp:596
float angle_t
Definition: rusefi_types.h:59
void scAddData(float angle, float value)
instantRpm("sync: instant RPM", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 316, 1.0, 0.0, 0.0, "rpm")
angle_t getEngineCycle(operation_mode_e operationMode)

Referenced by TriggerCentral::handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ scheduleByAngle()

efitick_t scheduleByAngle ( scheduling_s timer,
efitick_t  nowNt,
angle_t  angle,
action_s  action 
)

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.

Returns
tick time of scheduled action

Definition at line 395 of file rpm_calculator.cpp.

396  {
397  float delayUs = engine->rpmCalculator.oneDegreeUs * angle;
398 
399  efitick_t actionTimeNt = sumTickAndFloat(nowNt, USF2NT(delayUs));
400 
401  engine->executor.scheduleByTimestampNt("angle", timer, actionTimeNt, action);
402 
403  return actionTimeNt;
404 }
SingleTimerExecutor executor
Definition: engine.h:241
floatus_t oneDegreeUs
void scheduleByTimestampNt(const char *msg, scheduling_s *scheduling, efitick_t timeNt, action_s action) override
Schedule an action to be executed in the future.
efitick_t sumTickAndFloat(efitick_t ticks, float extra)
Definition: efitime.h:36

Referenced by fireSparkAndPrepareNextSchedule(), hip9011_onFireEvent(), mapAveragingTriggerCallback(), Engine::onSparkFireKnockSense(), InjectionEvent::onTriggerTooth(), HpfpController::pinTurnOn(), TriggerScheduler::scheduleEventsUntilNextTriggerTooth(), TriggerScheduler::scheduleOrQueue(), scheduleSparkEvent(), startAveraging(), tdcMarkCallback(), and turnSparkPinHighStartCharging().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tdcMarkCallback()

void tdcMarkCallback ( uint32_t  trgEventIndex,
efitick_t  nowNt 
)

This trigger callback schedules the actual physical TDC callback in relation to trigger synchronization point.

Definition at line 363 of file rpm_calculator.cpp.

364  {
365  bool isTriggerSynchronizationPoint = trgEventIndex == 0;
366  if (isTriggerSynchronizationPoint && getTriggerCentral()->isEngineSnifferEnabled) {
367 
368 #if EFI_UNIT_TEST
369  if (!engine->tdcMarkEnabled) {
370  return;
371  }
372 #endif // EFI_UNIT_TEST
373 
374 
375  // two instances of scheduling_s are needed to properly handle event overlap
376  int revIndex2 = getRevolutionCounter() % 2;
378  // todo: use tooth event-based scheduling, not just time-based scheduling
379  if (isValidRpm(rpm)) {
380  angle_t tdcPosition = tdcPosition();
381  // we need a positive angle offset here
382  wrapAngle(tdcPosition, "tdcPosition", ObdCode::CUSTOM_ERR_6553);
383  scheduleByAngle(&engine->tdcScheduler[revIndex2], nowNt, tdcPosition, onTdcCallback);
384  }
385  }
386 }
scheduling_s tdcScheduler[2]
Definition: engine.h:260
bool tdcMarkEnabled
Definition: engine.h:267
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:609
@ CUSTOM_ERR_6553
static void onTdcCallback(void *)
efitick_t scheduleByAngle(scheduling_s *timer, efitick_t nowNt, angle_t angle, action_s action)
void wrapAngle(angle_t &angle, const char *msg, ObdCode code)

Referenced by TriggerCentral::handleShaftSignal().

Here is the call graph for this function:
Here is the caller graph for this function:

Go to the source code of this file.