fome-fw/firmware/controllers/trigger/trigger_structure.cpp

436 lines
11 KiB
C++
Raw Normal View History

2014-08-29 07:52:33 -07:00
/**
* @file trigger_structure.cpp
*
* @date Jan 20, 2014
2015-01-12 15:04:10 -08:00
* @author Andrey Belomutskiy, (c) 2012-2015
2014-08-29 07:52:33 -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/>.
*/
#include "main.h"
#include "trigger_structure.h"
#include "error_handling.h"
#include "trigger_decoder.h"
2014-11-06 07:06:08 -08:00
#include "engine_math.h"
2014-08-29 07:52:33 -07:00
2014-11-25 08:04:15 -08:00
EXTERN_ENGINE;
2014-08-29 07:52:33 -07:00
trigger_shape_helper::trigger_shape_helper() {
for (int i = 0; i < TRIGGER_CHANNEL_COUNT; i++) {
waves[i].init(pinStates[i]);
}
}
2015-01-13 05:04:00 -08:00
TriggerShape::TriggerShape() :
2014-08-29 07:52:33 -07:00
wave(switchTimesBuffer, NULL) {
2015-02-02 21:04:02 -08:00
reset(OM_NONE, false);
2014-08-29 07:52:33 -07:00
wave.waves = h.waves;
2014-10-29 18:03:02 -07:00
useRiseEdge = false;
gapBothDirections = false;
2014-11-03 11:03:05 -08:00
isSynchronizationNeeded = false;
invertOnAdd = false;
2015-02-02 08:10:08 -08:00
tdcPosition = 0;
2014-08-29 07:52:33 -07:00
}
2015-01-13 05:04:00 -08:00
int TriggerShape::getSize() const {
2014-08-29 07:52:33 -07:00
return size;
}
2015-01-13 05:04:00 -08:00
int TriggerShape::getTriggerShapeSynchPointIndex() {
2014-08-29 07:52:33 -07:00
return triggerShapeSynchPointIndex;
}
2015-01-13 05:04:00 -08:00
void TriggerShape::calculateTriggerSynchPoint(engine_configuration_s *engineConfiguration, Engine *engine) {
2015-01-23 09:04:28 -08:00
trigger_config_s const*triggerConfig = &engineConfiguration->trigger;
2014-11-26 12:04:04 -08:00
setTriggerShapeSynchPointIndex(engineConfiguration, findTriggerZeroEventIndex(this, triggerConfig PASS_ENGINE_PARAMETER), engine);
2014-08-29 07:52:33 -07:00
}
2015-01-13 05:04:00 -08:00
void TriggerShape::setTriggerShapeSynchPointIndex(engine_configuration_s *engineConfiguration, int triggerShapeSynchPointIndex, Engine *engine) {
2014-08-29 07:52:33 -07:00
this->triggerShapeSynchPointIndex = triggerShapeSynchPointIndex;
2014-11-25 09:05:03 -08:00
engine->engineCycleEventCount = getLength();
2014-08-29 07:52:33 -07:00
float firstAngle = getAngle(triggerShapeSynchPointIndex);
2014-11-25 09:05:03 -08:00
for (int i = 0; i < engine->engineCycleEventCount; i++) {
2014-08-29 07:52:33 -07:00
if (i == 0) {
// explicit check for zero to avoid issues where logical zero is not exactly zero due to float nature
eventAngles[i] = 0;
} else {
2014-11-25 09:05:03 -08:00
float angle = getAngle((triggerShapeSynchPointIndex + i) % engine->engineCycleEventCount) - firstAngle;
2014-11-25 08:04:15 -08:00
fixAngle(angle);
2014-11-25 07:03:25 -08:00
eventAngles[i] = angle;
2014-08-29 07:52:33 -07:00
}
}
}
2015-02-04 16:04:18 -08:00
void TriggerShape::clear() {
tdcPosition = 0;
2015-02-05 07:04:08 -08:00
setTriggerSynchronizationGap(2);
useRiseEdge = true;
2015-02-04 16:04:18 -08:00
}
2015-02-02 21:04:02 -08:00
void TriggerShape::reset(operation_mode_e operationMode, bool needSecondTriggerInput) {
2014-08-29 07:52:33 -07:00
this->operationMode = operationMode;
size = 0;
2015-02-07 12:04:45 -08:00
this->needSecondTriggerInput = needSecondTriggerInput;
2014-08-29 07:52:33 -07:00
triggerShapeSynchPointIndex = 0;
memset(initialState, 0, sizeof(initialState));
memset(switchTimesBuffer, 0, sizeof(switchTimesBuffer));
memset(expectedEventCount, 0, sizeof(expectedEventCount));
wave.reset();
previousAngle = 0;
}
int multi_wave_s::getChannelState(int channelIndex, int phaseIndex) const {
return waves[channelIndex].pinStates[phaseIndex];
}
int multi_wave_s::waveIndertionAngle(float angle, int size) const {
for (int i = size - 1; i >= 0; i--) {
if (angle > switchTimes[i])
return i + 1;
}
return 0;
}
int multi_wave_s::findAngleMatch(float angle, int size) const {
for (int i = 0; i < size; i++) {
if (isSameF(switchTimes[i], angle))
return i;
}
return EFI_ERROR_CODE;
}
void multi_wave_s::setSwitchTime(int index, float value) {
switchTimes[index] = value;
}
TriggerState::TriggerState() {
cycleCallback = NULL;
shaft_is_synchronized = false;
toothed_previous_time = 0;
toothed_previous_duration = 0;
2015-01-18 07:06:08 -08:00
2014-08-29 07:52:33 -07:00
totalRevolutionCounter = 0;
2014-11-13 13:03:09 -08:00
totalTriggerErrorCounter = 0;
2015-01-18 07:06:08 -08:00
orderingErrorCounter = 0;
resetRunningCounters();
2014-08-29 07:52:33 -07:00
clear();
memset(expectedTotalTime, 0, sizeof(expectedTotalTime));
totalEventCountBase = 0;
isFirstEvent = true;
}
int TriggerState::getCurrentIndex() {
return current_index;
}
uint64_t TriggerState::getStartOfRevolutionIndex() {
return totalEventCountBase;
}
2015-01-18 07:06:08 -08:00
void TriggerState::resetRunningCounters() {
runningRevolutionCounter = 0;
runningTriggerErrorCounter = 0;
runningOrderingErrorCounter = 0;
}
2014-08-29 07:52:33 -07:00
uint64_t TriggerState::getTotalEventCounter() {
return totalEventCountBase + current_index;
}
int TriggerState::getTotalRevolutionCounter() {
return totalRevolutionCounter;
}
void TriggerState::clear() {
memset(eventCount, 0, sizeof(eventCount));
2014-11-15 17:03:22 -08:00
memset(eventCountExt, 0, sizeof(eventCountExt));
2014-11-14 14:03:57 -08:00
memset(timeOfPreviousEventNt, 0, sizeof(timeOfPreviousEventNt));
memset(totalTimeNt, 0, sizeof(totalTimeNt));
2014-08-29 07:52:33 -07:00
current_index = 0;
}
2014-11-25 09:05:03 -08:00
/**
* Trigger event count equals engine cycle event count if we have a cam sensor.
* Two trigger cycles make one engine cycle in case of a four stroke engine If we only have a cranksensor.
*/
2015-01-13 05:04:00 -08:00
uint32_t TriggerShape::getLength() const {
2014-11-25 06:03:01 -08:00
return operationMode == FOUR_STROKE_CAM_SENSOR ? getSize() : 2 * getSize();
2014-08-29 07:52:33 -07:00
}
2015-01-13 05:04:00 -08:00
float TriggerShape::getAngle(int index) const {
2014-08-29 07:52:33 -07:00
if (operationMode == FOUR_STROKE_CAM_SENSOR) {
return getSwitchAngle(index);
}
/**
* FOUR_STROKE_CRANK_SENSOR magic:
* We have two crank shaft revolutions for each engine cycle
* See also trigger_central.cpp
* See also getEngineCycleEventCount()
*/
int triggerEventCounter = size;
if (index < triggerEventCounter) {
return getSwitchAngle(index);
} else {
return 360 + getSwitchAngle(index - triggerEventCounter);
}
}
2015-01-13 05:04:00 -08:00
void TriggerShape::addEvent(float angle, trigger_wheel_e const waveIndex, trigger_value_e const stateParam) {
2014-08-29 07:52:33 -07:00
efiAssertVoid(operationMode != OM_NONE, "operationMode not set");
2014-11-03 11:03:05 -08:00
2015-02-07 12:04:45 -08:00
efiAssertVoid(waveIndex!= T_SECONDARY || needSecondTriggerInput, "secondary needed or not?");
2014-11-03 11:03:05 -08:00
trigger_value_e state;
if (invertOnAdd) {
state = (stateParam == TV_LOW) ? TV_HIGH : TV_LOW;
} else {
state = stateParam;
}
2014-08-29 07:52:33 -07:00
/**
* While '720' value works perfectly it has not much sense for crank sensor-only scenario.
* todo: accept angle as a value in the 0..1 range?
*/
angle /= 720;
expectedEventCount[waveIndex]++;
efiAssertVoid(angle > 0, "angle should be positive");
if (size > 0) {
if (angle <= previousAngle) {
firmwareError("invalid angle order: %f and %f", angle, previousAngle);
return;
}
}
previousAngle = angle;
if (size == 0) {
size = 1;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
single_wave_s *wave = &this->wave.waves[i];
if (wave == NULL) {
firmwareError("wave is NULL");
return;
}
if (wave->pinStates == NULL) {
firmwareError("wave pinStates is NULL");
return;
}
wave->pinStates[0] = initialState[i];
}
wave.setSwitchTime(0, angle);
wave.waves[waveIndex].pinStates[0] = state;
return;
}
int exactMatch = wave.findAngleMatch(angle, size);
if (exactMatch != EFI_ERROR_CODE) {
firmwareError("same angle: not supported");
return;
}
int index = wave.waveIndertionAngle(angle, size);
// shifting existing data
for (int i = size - 1; i >= index; i--) {
for (int j = 0; j < PWM_PHASE_MAX_WAVE_PER_PWM; j++) {
wave.waves[j].pinStates[i + 1] = wave.getChannelState(j, index);
}
wave.setSwitchTime(i + 1, wave.getSwitchTime(i));
}
// int index = size;
size++;
for (int i = 0; i < PWM_PHASE_MAX_WAVE_PER_PWM; i++) {
wave.waves[i].pinStates[index] = wave.getChannelState(i, index - 1);
}
wave.setSwitchTime(index, angle);
wave.waves[waveIndex].pinStates[index] = state;
}
2015-01-13 05:04:00 -08:00
int TriggerShape::getCycleDuration() const {
2014-08-29 07:52:33 -07:00
return (operationMode == FOUR_STROKE_CAM_SENSOR) ? 720 : 360;
}
2015-01-13 05:04:00 -08:00
float TriggerShape::getSwitchAngle(int index) const {
2014-08-29 07:52:33 -07:00
return getCycleDuration() * wave.getSwitchTime(index);
}
void multi_wave_s::checkSwitchTimes(int size) {
checkSwitchTimes2(size, switchTimes);
}
2015-01-13 05:04:00 -08:00
void setToothedWheelConfiguration(TriggerShape *s, int total, int skipped,
2014-08-29 07:52:33 -07:00
engine_configuration_s const *engineConfiguration) {
2015-02-08 15:08:14 -08:00
#if EFI_ENGINE_CONTROL
2014-08-29 07:52:33 -07:00
s->useRiseEdge = true;
2015-02-08 15:08:14 -08:00
initializeSkippedToothTriggerShapeExt(s, total, skipped,
2014-08-29 07:52:33 -07:00
getOperationMode(engineConfiguration));
2015-01-20 15:04:01 -08:00
#endif
2014-08-29 07:52:33 -07:00
}
2015-02-05 07:04:08 -08:00
void TriggerShape::setTriggerSynchronizationGap2(float syncRatioFrom, float syncRatioTo) {
isSynchronizationNeeded = true;
this->syncRatioFrom = syncRatioFrom;
this->syncRatioTo = syncRatioTo;
2014-11-02 12:03:03 -08:00
}
2015-02-05 07:04:08 -08:00
void TriggerShape::setTriggerSynchronizationGap(float synchRatio) {
setTriggerSynchronizationGap2(synchRatio * 0.75f, synchRatio * 1.25f);
2014-08-29 07:52:33 -07:00
}
#define S24 (720.0f / 24 / 2)
2015-01-13 05:04:00 -08:00
static float addAccordPair(TriggerShape *s, float sb) {
2014-08-29 07:52:33 -07:00
s->addEvent(sb, T_SECONDARY, TV_HIGH);
sb += S24;
s->addEvent(sb, T_SECONDARY, TV_LOW);
sb += S24;
return sb;
}
#define DIP 7.5f
2015-01-13 05:04:00 -08:00
static float addAccordPair3(TriggerShape *s, float sb) {
2014-08-29 07:52:33 -07:00
sb += DIP;
s->addEvent(sb, T_CHANNEL_3, TV_HIGH);
sb += DIP;
s->addEvent(sb, T_CHANNEL_3, TV_LOW);
sb += 2 * DIP;
return sb;
}
/**
* Thank you Dip!
* http://forum.pgmfi.org/viewtopic.php?f=2&t=15570start=210#p139007
*/
2015-01-13 05:04:00 -08:00
void configureHondaAccordCDDip(TriggerShape *s) {
2015-02-02 21:04:02 -08:00
s->reset(FOUR_STROKE_CAM_SENSOR, true);
2014-08-29 07:52:33 -07:00
s->initialState[T_SECONDARY] = TV_HIGH;
float sb = 0;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(90, T_SECONDARY, TV_LOW);
sb = 90;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(180, T_SECONDARY, TV_HIGH);
sb = 180;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(270, T_SECONDARY, TV_LOW);
sb = 270;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(360.0f - DIP, T_PRIMARY, TV_HIGH);
s->addEvent(360, T_SECONDARY, TV_HIGH);
sb = 360;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(450, T_SECONDARY, TV_LOW);
sb = 450;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(540, T_SECONDARY, TV_HIGH);
sb = 540;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(630, T_SECONDARY, TV_LOW);
sb = 630;
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
sb = addAccordPair3(s, sb);
s->addEvent(720.0f - DIP, T_PRIMARY, TV_LOW);
// s->addEvent(720.0f - 12 * sb, T_SECONDARY, TV_LOW);
// s->addEvent(720.0f, T_SECONDARY, TV_LOW);
s->addEvent(720.0f, T_SECONDARY, TV_HIGH);
s->isSynchronizationNeeded = false;
}
2015-01-13 05:04:00 -08:00
void configureHondaAccordCD(TriggerShape *s, bool with3rdSignal) {
2015-02-02 21:04:02 -08:00
s->reset(FOUR_STROKE_CAM_SENSOR, true);
2014-08-29 07:52:33 -07:00
float sb = 5.0f;
float tdcWidth = 0.1854 * 720 / 4;
s->isSynchronizationNeeded = false;
sb = addAccordPair(s, sb);
if (with3rdSignal)
s->addEvent(sb - S24 / 2, T_CHANNEL_3, TV_HIGH);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
if (with3rdSignal)
s->addEvent(sb - S24 / 2, T_CHANNEL_3, TV_LOW);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
s->addEvent(1 * 180.0f - tdcWidth, T_PRIMARY, TV_HIGH);
sb = addAccordPair(s, sb);
s->addEvent(1 * 180.0f, T_PRIMARY, TV_LOW);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
s->addEvent(2 * 180.0f - tdcWidth, T_PRIMARY, TV_HIGH);
sb = addAccordPair(s, sb);
s->addEvent(2 * 180.0f, T_PRIMARY, TV_LOW);
for (int i = 3; i <= 4; i++) {
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
sb = addAccordPair(s, sb);
s->addEvent(i * 180.0f - tdcWidth, T_PRIMARY, TV_HIGH);
sb = addAccordPair(s, sb);
s->addEvent(i * 180.0f, T_PRIMARY, TV_LOW);
}
}