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.

61  {
63  return TWO_STROKE;
64  } else {
66  }
67 }
engine_configuration_s * engineConfiguration
@ FOUR_STROKE_CRANK_SENSOR
Definition: rusefi_enums.h:254
@ FOUR_STROKE_CAM_SENSOR
Definition: rusefi_enums.h:258
@ TWO_STROKE
Definition: rusefi_enums.h:262

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:225
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:278
RpmCalculator rpmCalculator
Definition: engine.h:265
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
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:572
EngineState * getEngineState()
Definition: engine.cpp:576
float angle_t
Definition: rusefi_types.h:61
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  // 'delayNt' is below 10 seconds here so we use 32 bit type for performance reasons
400  int32_t delayNt = USF2NT(delayUs);
401  efitick_t actionTimeNt = nowNt + delayNt;
402 
403  engine->executor.scheduleByTimestampNt("angle", timer, actionTimeNt, action);
404 
405  return actionTimeNt;
406 }
SingleTimerExecutor executor
Definition: engine.h:237
floatus_t oneDegreeUs
void scheduleByTimestampNt(const char *msg, scheduling_s *scheduling, efitick_t timeNt, action_s action) override

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:252
bool tdcMarkEnabled
Definition: engine.h:259
TriggerCentral * getTriggerCentral()
Definition: engine.cpp:589
@ 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.