mirror of https://github.com/FOME-Tech/fome-fw.git
sorry ADC trigger, your performance was never proven and you're in the way now
This commit is contained in:
parent
2e7425d037
commit
08c878dbb9
|
@ -7,7 +7,6 @@ DDEFS += -DEFI_MAIN_RELAY_CONTROL=TRUE
|
|||
# Add them all together
|
||||
DDEFS += -DFIRMWARE_ID=\"hellen81\"
|
||||
#DDEFS += -DEFI_SOFTWARE_KNOCK=TRUE -DSTM32_ADC_USE_ADC3=TRUE
|
||||
DDEFS += -DHAL_TRIGGER_USE_ADC=TRUE
|
||||
|
||||
# we need fast ADC for software trigger detector
|
||||
#DDEFS += -DADC_FAST_DEVICE=ADCD1 -DADC_SLOW_DEVICE=ADCD3 -DSTM32_ADC_USE_ADC3=TRUE
|
||||
|
|
|
@ -79,10 +79,6 @@
|
|||
#define HAL_TRIGGER_USE_PAL TRUE
|
||||
#endif /* HAL_TRIGGER_USE_PAL */
|
||||
|
||||
#ifndef HAL_TRIGGER_USE_ADC
|
||||
#define HAL_TRIGGER_USE_ADC FALSE
|
||||
#endif /* HAL_TRIGGER_USE_ADC */
|
||||
|
||||
/**
|
||||
* TunerStudio support.
|
||||
*/
|
||||
|
|
|
@ -14,42 +14,14 @@
|
|||
|
||||
#if (EFI_SHAFT_POSITION_INPUT) || defined(__DOXYGEN__)
|
||||
|
||||
#if (HAL_TRIGGER_USE_PAL == TRUE) || (HAL_TRIGGER_USE_ADC == TRUE)
|
||||
|
||||
#if (HAL_TRIGGER_USE_PAL == TRUE)
|
||||
int extiTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft);
|
||||
void extiTriggerTurnOffInputPin(brain_pin_e brainPin);
|
||||
#else
|
||||
int extiTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft) {
|
||||
UNUSED(msg);
|
||||
UNUSED(index);
|
||||
UNUSED(isTriggerShaft);
|
||||
|
||||
return -2;
|
||||
}
|
||||
#define extiTriggerTurnOffInputPin(brainPin) ((void)0)
|
||||
#endif
|
||||
|
||||
#if (HAL_TRIGGER_USE_ADC == TRUE)
|
||||
void adcTriggerTurnOnInputPins();
|
||||
int adcTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft);
|
||||
void adcTriggerTurnOffInputPin(brain_pin_e brainPin);
|
||||
#else
|
||||
#define adcTriggerTurnOnInputPins() ((void)0)
|
||||
int adcTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft) {
|
||||
UNUSED(msg);
|
||||
UNUSED(index);
|
||||
UNUSED(isTriggerShaft);
|
||||
|
||||
return -2;
|
||||
}
|
||||
#define adcTriggerTurnOffInputPin(brainPin) ((void)0)
|
||||
#endif
|
||||
int extiTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft);
|
||||
void extiTriggerTurnOffInputPin(brain_pin_e brainPin);
|
||||
|
||||
enum triggerType {
|
||||
TRIGGER_NONE,
|
||||
TRIGGER_EXTI,
|
||||
TRIGGER_ADC,
|
||||
};
|
||||
|
||||
static triggerType shaftTriggerType[TRIGGER_INPUT_PIN_COUNT];
|
||||
|
@ -69,18 +41,6 @@ static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ... then ADC */
|
||||
#if HAL_TRIGGER_USE_ADC
|
||||
if (adcTriggerTurnOnInputPin(msg, index, isTriggerShaft) >= 0) {
|
||||
if (isTriggerShaft) {
|
||||
shaftTriggerType[index] = TRIGGER_ADC;
|
||||
} else {
|
||||
camTriggerType[index] = TRIGGER_ADC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ... then EXTI */
|
||||
if (extiTriggerTurnOnInputPin(msg, index, isTriggerShaft) >= 0) {
|
||||
if (isTriggerShaft) {
|
||||
|
@ -101,20 +61,12 @@ static void turnOffTriggerInputPin(int index, bool isTriggerShaft) {
|
|||
activeConfiguration.triggerInputPins[index] : activeConfiguration.camInputs[index];
|
||||
|
||||
if (isTriggerShaft) {
|
||||
if (shaftTriggerType[index] == TRIGGER_ADC) {
|
||||
adcTriggerTurnOffInputPin(brainPin);
|
||||
}
|
||||
|
||||
if (shaftTriggerType[index] == TRIGGER_EXTI) {
|
||||
extiTriggerTurnOffInputPin(brainPin);
|
||||
}
|
||||
|
||||
shaftTriggerType[index] = TRIGGER_NONE;
|
||||
} else {
|
||||
if (camTriggerType[index] == TRIGGER_ADC) {
|
||||
adcTriggerTurnOffInputPin(brainPin);
|
||||
}
|
||||
|
||||
if (camTriggerType[index] == TRIGGER_EXTI) {
|
||||
extiTriggerTurnOffInputPin(brainPin);
|
||||
}
|
||||
|
@ -161,7 +113,7 @@ void turnOnTriggerInputPins() {
|
|||
applyNewTriggerInputPins();
|
||||
}
|
||||
|
||||
#endif /* (HAL_TRIGGER_USE_PAL == TRUE) || (HAL_TRIGGER_USE_ADC == TRUE) */
|
||||
#endif /* (HAL_TRIGGER_USE_PAL == TRUE) */
|
||||
|
||||
|
||||
void stopTriggerDebugPins() {
|
||||
|
|
|
@ -19,22 +19,4 @@ void stopTriggerInputPins();
|
|||
void stopTriggerDebugPins();
|
||||
void startTriggerDebugPins();
|
||||
|
||||
#if HAL_USE_ADC
|
||||
typedef adcsample_t triggerAdcSample_t;
|
||||
#else
|
||||
typedef uint16_t triggerAdcSample_t;
|
||||
#endif /* HAL_USE_ADC */
|
||||
|
||||
// This detector has 2 modes for low-RPM (ADC) and fast-RPM (EXTI)
|
||||
enum triggerAdcMode_t {
|
||||
TRIGGER_ADC_NONE = 0,
|
||||
TRIGGER_ADC_ADC,
|
||||
TRIGGER_ADC_EXTI,
|
||||
};
|
||||
|
||||
adc_channel_e getAdcChannelForTrigger(void);
|
||||
void addAdcChannelForTrigger(void);
|
||||
void triggerAdcCallback(triggerAdcSample_t value);
|
||||
|
||||
void setTriggerAdcMode(triggerAdcMode_t adcMode);
|
||||
void onTriggerChanged(efitick_t stamp, bool isPrimary, bool isRising);
|
||||
|
|
|
@ -1,430 +0,0 @@
|
|||
/**
|
||||
* @file trigger_input_adc.cpp
|
||||
* @brief Position sensor hardware layer, Using ADC and software comparator
|
||||
*
|
||||
* @date Jan 27, 2020
|
||||
* @author andreika <prometheus.pcb@gmail.com>
|
||||
* @author Andrey Belomutskiy, (c) 2012-2020
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include "trigger_input_adc.h"
|
||||
|
||||
|
||||
/*static*/ TriggerAdcDetector trigAdcState;
|
||||
|
||||
#define DELTA_THRESHOLD_CNT_LOW (GPT_FREQ_FAST / GPT_PERIOD_FAST / 32) // ~1/32 second?
|
||||
#define DELTA_THRESHOLD_CNT_HIGH (GPT_FREQ_FAST / GPT_PERIOD_FAST / 4) // ~1/4 second?
|
||||
|
||||
#define triggerVoltsToAdcDivided(volts) (voltsToAdc(volts) / trigAdcState.triggerInputDividerCoefficient)
|
||||
|
||||
// hardware-dependent part
|
||||
#if (EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC) || defined(__DOXYGEN__)
|
||||
|
||||
#include "digital_input_exti.h"
|
||||
|
||||
#ifndef TRIGGER_ADC_DEBUG_LED
|
||||
#define TRIGGER_ADC_DEBUG_LED FALSE
|
||||
#endif
|
||||
//#define DEBUG_OUTPUT_IGN1 TRUE
|
||||
//#define TRIGGER_ADC_DUMP_BUF TRUE
|
||||
|
||||
#ifdef TRIGGER_ADC_DEBUG_LED
|
||||
#define TRIGGER_ADC_DEBUG_LED1_PORT GPIOH
|
||||
#define TRIGGER_ADC_DEBUG_LED1_PIN 9
|
||||
|
||||
#ifdef TRIGGER_ADC_DUMP_BUF
|
||||
static const int dumpBufNum = 100;
|
||||
static triggerAdcSample_t dumpBuf[dumpBufNum];
|
||||
static int dumpBufCnt = 0;
|
||||
#endif /* TRIGGER_ADC_DUMP_BUF */
|
||||
|
||||
void toggleLed(int led, int mode) {
|
||||
#if 1
|
||||
static uint8_t st[5] = { 0 };
|
||||
if ((st[led] == 0 && mode == 0) || mode == 1) {
|
||||
palClearPad(TRIGGER_ADC_DEBUG_LED1_PORT, TRIGGER_ADC_DEBUG_LED1_PIN);
|
||||
#ifdef DEBUG_OUTPUT_IGN1
|
||||
palClearPad(GPIOI, 8);
|
||||
#endif
|
||||
}
|
||||
else if ((st[led] != 0 && mode == 0) || mode == -1) {
|
||||
palSetPad(TRIGGER_ADC_DEBUG_LED1_PORT, TRIGGER_ADC_DEBUG_LED1_PIN);
|
||||
#ifdef DEBUG_OUTPUT_IGN1
|
||||
palSetPad(GPIOI, 8);
|
||||
#endif
|
||||
}
|
||||
st[led] = (st[led] + 1) % 2/*10*/; //!!!!!!!!!!!
|
||||
#endif
|
||||
}
|
||||
#endif /* TRIGGER_ADC_DEBUG_LED */
|
||||
|
||||
// used for fast pin mode switching between ADC and EXTINT
|
||||
static ioportid_t triggerInputPort;
|
||||
static ioportmask_t triggerInputPin;
|
||||
|
||||
#ifndef PAL_MODE_EXTINT
|
||||
#define PAL_MODE_EXTINT PAL_MODE_INPUT
|
||||
#endif /* PAL_MODE_EXTINT */
|
||||
|
||||
void setTriggerAdcMode(triggerAdcMode_t adcMode) {
|
||||
trigAdcState.curAdcMode = adcMode;
|
||||
trigAdcState.modeSwitchCnt++;
|
||||
|
||||
palSetPadMode(triggerInputPort, triggerInputPin,
|
||||
(adcMode == TRIGGER_ADC_ADC) ? PAL_MODE_INPUT_ANALOG : PAL_MODE_EXTINT);
|
||||
}
|
||||
|
||||
static void shaft_callback(void *arg, efitick_t stamp) {
|
||||
// do the time sensitive things as early as possible!
|
||||
ioline_t pal_line = (ioline_t)arg;
|
||||
bool rise = (palReadLine(pal_line) == PAL_HIGH);
|
||||
|
||||
trigAdcState.digitalCallback(stamp, true, rise);
|
||||
}
|
||||
|
||||
static void cam_callback(void *, efitick_t stamp) {
|
||||
// TODO: implement...
|
||||
}
|
||||
|
||||
void triggerAdcCallback(triggerAdcSample_t value) {
|
||||
efitick_t stamp = getTimeNowNt();
|
||||
trigAdcState.analogCallback(stamp, value);
|
||||
}
|
||||
|
||||
#ifdef TRIGGER_ADC_DUMP_BUF
|
||||
static void printDumpBuf(void) {
|
||||
efiPrintf("------");
|
||||
for (int i = 0; i < dumpBufNum; i++) {
|
||||
int pos = (dumpBufCnt - i - 1 + dumpBufNum) % dumpBufNum;
|
||||
triggerAdcSample_t v = dumpBuf[pos];
|
||||
efiPrintf("[%d] %d", i, v);
|
||||
}
|
||||
}
|
||||
#endif /* TRIGGER_ADC_DUMP_BUF */
|
||||
|
||||
|
||||
int adcTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft) {
|
||||
brain_pin_e brainPin = isTriggerShaft ?
|
||||
engineConfiguration->triggerInputPins[index] : engineConfiguration->camInputs[index];
|
||||
|
||||
if (!isBrainPinValid(brainPin))
|
||||
return 0;
|
||||
|
||||
trigAdcState.init();
|
||||
|
||||
triggerInputPort = getHwPort("trg", brainPin);
|
||||
triggerInputPin = getHwPin("trg", brainPin);
|
||||
|
||||
ioline_t pal_line = PAL_LINE(triggerInputPort, triggerInputPin);
|
||||
efiPrintf("turnOnTriggerInputPin %s l=%d", hwPortname(brainPin), pal_line);
|
||||
|
||||
efiExtiEnablePin(msg, brainPin, PAL_EVENT_MODE_BOTH_EDGES, isTriggerShaft ? shaft_callback : cam_callback, (void *)pal_line);
|
||||
|
||||
// ADC mode is default, because we don't know if the wheel is already spinning
|
||||
setTriggerAdcMode(TRIGGER_ADC_ADC);
|
||||
|
||||
#ifdef TRIGGER_ADC_DEBUG_LED
|
||||
palSetPadMode(TRIGGER_ADC_DEBUG_LED1_PORT, TRIGGER_ADC_DEBUG_LED1_PIN, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
#ifdef DEBUG_OUTPUT_IGN1
|
||||
palSetPadMode(GPIOI, 8, PAL_MODE_OUTPUT_PUSHPULL);
|
||||
#endif
|
||||
#endif /* TRIGGER_ADC_DEBUG_LED */
|
||||
|
||||
#ifdef TRIGGER_ADC_DUMP_BUF
|
||||
addConsoleAction("trigger_adc_dump", printDumpBuf);
|
||||
#endif /* TRIGGER_ADC_DUMP_BUF */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void adcTriggerTurnOffInputPin(brain_pin_e brainPin) {
|
||||
efiExtiDisablePin(brainPin);
|
||||
}
|
||||
|
||||
void adcTriggerTurnOnInputPins() {
|
||||
}
|
||||
|
||||
adc_channel_e getAdcChannelForTrigger(void) {
|
||||
// todo: add other trigger or cam channels?
|
||||
brain_pin_e brainPin = engineConfiguration->triggerInputPins[0];
|
||||
if (!isBrainPinValid(brainPin))
|
||||
return EFI_ADC_NONE;
|
||||
return getAdcChannel(brainPin);
|
||||
}
|
||||
|
||||
void addAdcChannelForTrigger(void) {
|
||||
adc_channel_e ch = getAdcChannelForTrigger();
|
||||
if (isAdcChannelValid(ch)) {
|
||||
addFastAdcChannel("TRIG", ch);
|
||||
}
|
||||
}
|
||||
|
||||
void onTriggerChanged(efitick_t stamp, bool isPrimary, bool isRising) {
|
||||
#ifdef TRIGGER_ADC_DEBUG_LED
|
||||
toggleLed(0, 0);
|
||||
#endif /* TRIGGER_ADC_DEBUG_LED */
|
||||
|
||||
#if 1
|
||||
// todo: support for 3rd trigger input channel
|
||||
// todo: start using real event time from HW event, not just software timer?
|
||||
|
||||
// call the main trigger handler
|
||||
hwHandleShaftSignal(isPrimary ? 0 : 1, isRising, stamp);
|
||||
#endif // 1
|
||||
}
|
||||
|
||||
#endif // EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
|
||||
|
||||
void TriggerAdcDetector::init() {
|
||||
#if ! EFI_SIMULATOR
|
||||
|
||||
// todo: move some of these to config
|
||||
|
||||
// 4.7k||5.1k + 4.7k
|
||||
triggerInputDividerCoefficient = 1.52f; // = analogInputDividerCoefficient
|
||||
|
||||
// we need to make at least minNumAdcMeasurementsPerTooth for 1 tooth (i.e. between two consequent events)
|
||||
const int minNumAdcMeasurementsPerTooth = 10; // for 60-2 wheel: 1/(10*2*60/10000/60) = 500 RPM
|
||||
minDeltaTimeForStableAdcDetectionNt = US2NT(US_PER_SECOND_LL * minNumAdcMeasurementsPerTooth * GPT_PERIOD_FAST / GPT_FREQ_FAST);
|
||||
// we assume that the transition occurs somewhere in the middle of the measurement period, so we take the half of it
|
||||
stampCorrectionForAdc = US2NT(US_PER_SECOND_LL * GPT_PERIOD_FAST / GPT_FREQ_FAST / 2);
|
||||
|
||||
analogToDigitalTransitionCnt = 4;
|
||||
digitalToAnalogTransitionCnt = 4;
|
||||
|
||||
// used to filter out low signals
|
||||
minDeltaThresholdWeakSignal = triggerVoltsToAdcDivided(0.05f); // 50mV
|
||||
// we need to shift the default threshold even for strong signals because of the possible loss of the first tooth (after the sync)
|
||||
minDeltaThresholdStrongSignal = triggerVoltsToAdcDivided(0.04f); // 5mV
|
||||
|
||||
const triggerAdcSample_t adcDeltaThreshold = triggerVoltsToAdcDivided(0.25f);
|
||||
adcDefaultThreshold = triggerVoltsToAdcDivided(2.5f); // this corresponds to VREF1 on Hellen boards
|
||||
adcMinThreshold = adcDefaultThreshold - adcDeltaThreshold;
|
||||
adcMaxThreshold = adcDefaultThreshold - adcDeltaThreshold;
|
||||
|
||||
// these thresholds allow to switch from ADC mode to EXTI mode, indicating the clamping of the signal
|
||||
// they should exceed the MCU schmitt trigger thresholds (usually 0.3*Vdd and 0.7*Vdd)
|
||||
switchingThresholdLow = triggerVoltsToAdcDivided(1.0f); // = 0.2*Vdd (<0.3*Vdd)
|
||||
switchingThresholdHigh = triggerVoltsToAdcDivided(4.0f); // = 0.8*Vdd (>0.7*Vdd)
|
||||
|
||||
modeSwitchCnt = 0;
|
||||
|
||||
reset();
|
||||
#endif // ! EFI_SIMULATOR
|
||||
}
|
||||
|
||||
void TriggerAdcDetector::reset() {
|
||||
switchingCnt = 0;
|
||||
switchingTeethCnt = 0;
|
||||
// when the strong signal becomes weak, we want to ignore the increased noise
|
||||
// so we create a dead-zone between the pos. and neg. thresholds
|
||||
zeroThreshold = minDeltaThresholdWeakSignal / 2;
|
||||
triggerAdcITerm = triggerAdcITermMin;
|
||||
|
||||
adcThreshold = adcDefaultThreshold;
|
||||
|
||||
isSignalWeak = true;
|
||||
integralSum = 0;
|
||||
transitionCooldownCnt = 0;
|
||||
prevValue = 0; // not set
|
||||
prevStamp = {};
|
||||
minDeltaThresholdCntPos = 0;
|
||||
minDeltaThresholdCntNeg = 0;
|
||||
}
|
||||
|
||||
void TriggerAdcDetector::digitalCallback(efitick_t stamp, bool isPrimary, bool rise) {
|
||||
#if ! EFI_SIMULATOR
|
||||
if (curAdcMode != TRIGGER_ADC_EXTI) {
|
||||
return;
|
||||
}
|
||||
|
||||
UNUSED(isPrimary);
|
||||
|
||||
#if EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
onTriggerChanged(stamp, isPrimary, rise);
|
||||
#endif // EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
|
||||
if ((stamp - prevStamp) > minDeltaTimeForStableAdcDetectionNt) {
|
||||
switchingCnt++;
|
||||
} else {
|
||||
switchingCnt = 0;
|
||||
switchingTeethCnt = 0;
|
||||
}
|
||||
|
||||
if (switchingCnt >= digitalToAnalogTransitionCnt) {
|
||||
switchingCnt = 0;
|
||||
// we need at least 3 wide teeth to be certain!
|
||||
// we don't want to confuse them with a sync.gap
|
||||
if (switchingTeethCnt++ > 3) {
|
||||
switchingTeethCnt = 0;
|
||||
prevValue = rise ? 1: -1;
|
||||
#if EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
setTriggerAdcMode(TRIGGER_ADC_ADC);
|
||||
#endif // EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
}
|
||||
}
|
||||
|
||||
prevStamp = stamp;
|
||||
#endif // ! EFI_SIMULATOR
|
||||
}
|
||||
|
||||
void TriggerAdcDetector::analogCallback(efitick_t stamp, triggerAdcSample_t value) {
|
||||
#if ! EFI_SIMULATOR
|
||||
if (curAdcMode != TRIGGER_ADC_ADC) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TRIGGER_ADC_DUMP_BUF
|
||||
dumpBuf[dumpBufCnt] = value;
|
||||
dumpBufCnt = (dumpBufCnt + 1) % dumpBufNum;
|
||||
#endif /* TRIGGER_ADC_DUMP_BUF */
|
||||
|
||||
// <1V or >4V?
|
||||
if (value >= switchingThresholdHigh || value <= switchingThresholdLow) {
|
||||
switchingCnt++;
|
||||
} else {
|
||||
//switchingCnt = 0;
|
||||
switchingCnt = maxI(switchingCnt - 1, 0);
|
||||
}
|
||||
|
||||
int delta = value - adcThreshold;
|
||||
int aDelta = absI(delta);
|
||||
if (isSignalWeak) {
|
||||
// todo: detect if the sensor is disconnected (where the signal is always near 'ADC_MAX_VALUE')
|
||||
|
||||
// filter out low signals (noise)
|
||||
if (delta >= minDeltaThresholdWeakSignal) {
|
||||
minDeltaThresholdCntPos++;
|
||||
}
|
||||
if (delta <= -minDeltaThresholdWeakSignal) {
|
||||
minDeltaThresholdCntNeg++;
|
||||
}
|
||||
} else {
|
||||
// we just had a strong signal, let's reset the counter
|
||||
if (delta >= minDeltaThresholdWeakSignal) {
|
||||
minDeltaThresholdCntPos = DELTA_THRESHOLD_CNT_HIGH;
|
||||
}
|
||||
if (delta <= -minDeltaThresholdWeakSignal) {
|
||||
minDeltaThresholdCntNeg = DELTA_THRESHOLD_CNT_HIGH;
|
||||
}
|
||||
minDeltaThresholdCntPos--;
|
||||
minDeltaThresholdCntNeg--;
|
||||
// we haven't seen the strong signal (pos or neg) for too long, maybe it's lost or too weak?
|
||||
if (minDeltaThresholdCntPos <= 0 || minDeltaThresholdCntNeg <= 0) {
|
||||
// reset to the weak signal mode
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// the threshold should always correspond to the averaged signal.
|
||||
integralSum += delta;
|
||||
// we need some limits for the integral sum
|
||||
// we use a simple I-regulator to move the threshold
|
||||
adcThreshold += (float)integralSum * triggerAdcITerm;
|
||||
// limit the threshold for safety
|
||||
adcThreshold = maxF(minF(adcThreshold, adcMaxThreshold), adcMinThreshold);
|
||||
|
||||
// now to the transition part... First, we need a cooldown to pre-filter the transition noise
|
||||
if (transitionCooldownCnt-- < 0)
|
||||
transitionCooldownCnt = 0;
|
||||
|
||||
// we need at least 2 different measurements to detect a transition
|
||||
if (prevValue == 0) {
|
||||
// we can take the measurement only from outside the dead-zone
|
||||
if (aDelta > minDeltaThresholdWeakSignal) {
|
||||
prevValue = (delta > 0) ? 1 : -1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// detect the edge
|
||||
int transition = 0;
|
||||
if (delta > zeroThreshold && prevValue == -1) {
|
||||
// a rising transition found!
|
||||
transition = 1;
|
||||
}
|
||||
else if (delta <= -zeroThreshold && prevValue == 1) {
|
||||
// a falling transition found!
|
||||
transition = -1;
|
||||
}
|
||||
else {
|
||||
return; // both are positive/negative/zero: not interested!
|
||||
}
|
||||
|
||||
if (isSignalWeak) {
|
||||
if (minDeltaThresholdCntPos >= DELTA_THRESHOLD_CNT_LOW && minDeltaThresholdCntNeg >= DELTA_THRESHOLD_CNT_LOW) {
|
||||
// ok, now we have a legit strong signal, let's restore the threshold
|
||||
isSignalWeak = false;
|
||||
integralSum = 0;
|
||||
zeroThreshold = minDeltaThresholdStrongSignal;
|
||||
} else {
|
||||
// we cannot trust the weak signal!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (transitionCooldownCnt <= 0) {
|
||||
#if EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
onTriggerChanged(stamp - stampCorrectionForAdc, true, transition == 1);
|
||||
#endif // EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
// let's skip some nearest possible measurements:
|
||||
// the transition cannot be SO fast, but the jitter can!
|
||||
transitionCooldownCnt = transitionCooldown;
|
||||
|
||||
// it should not accumulate too much
|
||||
integralSum = 0;
|
||||
#if 0
|
||||
// update triggerAdcITerm
|
||||
efitimeus_t deltaTimeUs = NT2US(stamp - prevStamp);
|
||||
if (deltaTimeUs > 200) { // 200 us = ~2500 RPM (we don't need this correction for large RPM)
|
||||
triggerAdcITerm = 1.0f / (triggerAdcITermCoef * deltaTimeUs);
|
||||
triggerAdcITerm = maxF(triggerAdcITerm, triggerAdcITermMin);
|
||||
}
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
if (switchingCnt >= analogToDigitalTransitionCnt) {
|
||||
switchingCnt = 0;
|
||||
// we need at least 3 high-signal teeth to be certain!
|
||||
if (switchingTeethCnt++ > 3) {
|
||||
switchingTeethCnt = 0;
|
||||
#if EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
setTriggerAdcMode(TRIGGER_ADC_EXTI);
|
||||
#endif // EFI_SHAFT_POSITION_INPUT && HAL_TRIGGER_USE_ADC && HAL_USE_ADC
|
||||
// we don't want to loose the signal on return
|
||||
minDeltaThresholdCntPos = DELTA_THRESHOLD_CNT_HIGH;
|
||||
minDeltaThresholdCntNeg = DELTA_THRESHOLD_CNT_HIGH;
|
||||
// we want to reset the thresholds on return
|
||||
zeroThreshold = minDeltaThresholdStrongSignal;
|
||||
adcThreshold = adcDefaultThreshold;
|
||||
// reset integrator
|
||||
triggerAdcITerm = triggerAdcITermMin;
|
||||
integralSum = 0;
|
||||
transitionCooldownCnt = 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// we don't see "big teeth" anymore
|
||||
switchingTeethCnt = 0;
|
||||
}
|
||||
|
||||
prevValue = transition;
|
||||
prevStamp = stamp;
|
||||
#endif // ! EFI_SIMULATOR
|
||||
}
|
||||
|
||||
triggerAdcMode_t getTriggerAdcMode(void) {
|
||||
return trigAdcState.curAdcMode;
|
||||
}
|
||||
|
||||
float getTriggerAdcThreshold(void) {
|
||||
return trigAdcState.adcThreshold;
|
||||
}
|
||||
|
||||
int getTriggerAdcModeCnt(void) {
|
||||
return trigAdcState.modeSwitchCnt;
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/**
|
||||
* @file trigger_input_adc.h
|
||||
* @brief Position sensor hardware layer, Using ADC and software comparator
|
||||
*
|
||||
* @date Jan 27, 2020
|
||||
* @author andreika <prometheus.pcb@gmail.com>
|
||||
* @author Andrey Belomutskiy, (c) 2012-2020
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "global.h"
|
||||
#include "trigger_input.h"
|
||||
#include "adc_inputs.h"
|
||||
|
||||
|
||||
#define DELTA_THRESHOLD_CNT_LOW (GPT_FREQ_FAST / GPT_PERIOD_FAST / 32) // ~1/32 second?
|
||||
#define DELTA_THRESHOLD_CNT_HIGH (GPT_FREQ_FAST / GPT_PERIOD_FAST / 4) // ~1/4 second?
|
||||
|
||||
class TriggerAdcDetector {
|
||||
public:
|
||||
void init();
|
||||
void reset();
|
||||
|
||||
void digitalCallback(efitick_t stamp, bool isPrimary, bool rise);
|
||||
void analogCallback(efitick_t stamp, triggerAdcSample_t value);
|
||||
|
||||
public:
|
||||
triggerAdcSample_t adcDefaultThreshold;
|
||||
triggerAdcSample_t adcMinThreshold;
|
||||
triggerAdcSample_t adcMaxThreshold;
|
||||
|
||||
float triggerInputDividerCoefficient;
|
||||
|
||||
float triggerAdcITermCoef = 1600.0f;
|
||||
float triggerAdcITermMin = 3.125e-8f; // corresponds to rpm=25
|
||||
|
||||
int transitionCooldown = 5;
|
||||
|
||||
int analogToDigitalTransitionCnt;
|
||||
int digitalToAnalogTransitionCnt;
|
||||
|
||||
triggerAdcMode_t curAdcMode = TRIGGER_ADC_NONE;
|
||||
float adcThreshold = adcDefaultThreshold;
|
||||
float triggerAdcITerm = triggerAdcITermMin;
|
||||
|
||||
// these thresholds allow to switch from ADC mode (low-rpm) to EXTI mode (fast-rpm), indicating the clamping of the signal
|
||||
triggerAdcSample_t switchingThresholdLow = 0, switchingThresholdHigh = 0;
|
||||
efidur_t minDeltaTimeForStableAdcDetectionNt;
|
||||
efidur_t stampCorrectionForAdc;
|
||||
int switchingCnt = 0, switchingTeethCnt = 0;
|
||||
int prevValue = 0; // not set
|
||||
efitick_t prevStamp;
|
||||
|
||||
// we need to distinguish between weak and strong signals because of different SNR and thresholds.
|
||||
bool isSignalWeak = true;
|
||||
int zeroThreshold = 0;
|
||||
|
||||
// the 'center' of the signal is variable, so we need to adjust the thresholds.
|
||||
int minDeltaThresholdWeakSignal = 0, minDeltaThresholdStrongSignal = 0;
|
||||
|
||||
// this is the number of measurements while we store the counter before we reset to 'isSignalWeak'
|
||||
int minDeltaThresholdCntPos = 0, minDeltaThresholdCntNeg = 0;
|
||||
int integralSum = 0;
|
||||
int transitionCooldownCnt = 0;
|
||||
|
||||
int modeSwitchCnt = 0;
|
||||
};
|
|
@ -145,10 +145,6 @@ SPIDriver * getSpiDevice(spi_device_e spiDevice) {
|
|||
|
||||
static FastAdcToken fastMapSampleIndex;
|
||||
|
||||
#if HAL_TRIGGER_USE_ADC
|
||||
static FastAdcToken triggerSampleIndex;
|
||||
#endif
|
||||
|
||||
extern AdcDevice fastAdc;
|
||||
|
||||
/**
|
||||
|
@ -157,11 +153,6 @@ extern AdcDevice fastAdc;
|
|||
void onFastAdcComplete(adcsample_t*) {
|
||||
ScopePerf perf(PE::AdcCallbackFast);
|
||||
|
||||
#if HAL_TRIGGER_USE_ADC
|
||||
// we need to call this ASAP, because trigger processing is time-critical
|
||||
triggerAdcCallback(getFastAdc(triggerSampleIndex));
|
||||
#endif /* HAL_TRIGGER_USE_ADC */
|
||||
|
||||
/**
|
||||
* this callback is executed 10 000 times a second, it needs to be as fast as possible
|
||||
*/
|
||||
|
@ -182,10 +173,6 @@ void onFastAdcComplete(adcsample_t*) {
|
|||
static void calcFastAdcIndexes() {
|
||||
#if HAL_USE_ADC
|
||||
fastMapSampleIndex = enableFastAdcChannel("Fast MAP", engineConfiguration->map.sensor.hwChannel);
|
||||
#if HAL_TRIGGER_USE_ADC
|
||||
triggerSampleIndex = enableFastAdcChannel("Trigger ADC", getAdcChannelForTrigger());
|
||||
#endif /* HAL_TRIGGER_USE_ADC */
|
||||
|
||||
#endif/* HAL_USE_ADC */
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ HW_LAYER_EMS_CPP = \
|
|||
$(PROJECT_DIR)/hw_layer/digital_input/digital_input_exti.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/digital_input/trigger/trigger_input.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/digital_input/trigger/trigger_input_exti.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/digital_input/trigger/trigger_input_adc.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/hardware.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/kline.cpp \
|
||||
$(PROJECT_DIR)/hw_layer/smart_gpio.cpp \
|
||||
|
|
|
@ -4,7 +4,6 @@ TESTS_SRC_CPP = \
|
|||
tests/trigger/test_trigger_decoder.cpp \
|
||||
tests/trigger/test_trigger_decoder_2.cpp \
|
||||
tests/trigger/test_trigger_multi_sync.cpp \
|
||||
tests/trigger/test_trigger_input_adc.cpp \
|
||||
tests/trigger/test_miata_na_tdc.cpp \
|
||||
tests/trigger/test_cam_vvt_input.cpp \
|
||||
tests/trigger/test_2jz_vvt.cpp \
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/**
|
||||
* @file test_trigger_input_adc.cpp
|
||||
*
|
||||
* @date Jul 24, 2021
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include "engine_test_helper.h"
|
||||
#include "trigger_decoder.h"
|
||||
#include "engine_math.h"
|
||||
#include "allsensors.h"
|
||||
#include "rpm_calculator.h"
|
||||
#include "event_queue.h"
|
||||
#include "trigger_central.h"
|
||||
#include "main_trigger_callback.h"
|
||||
#include "engine.h"
|
||||
#include "advance_map.h"
|
||||
#include "speed_density.h"
|
||||
#include "fuel_math.h"
|
||||
#include "spark_logic.h"
|
||||
#include "trigger_universal.h"
|
||||
|
||||
#include "trigger_input_adc.h"
|
||||
#include "logicdata_csv_reader.h"
|
||||
|
||||
|
||||
extern TriggerAdcDetector trigAdcState;
|
||||
|
||||
void setTriggerAdcMode(triggerAdcMode_t adcMode) {
|
||||
trigAdcState.curAdcMode = adcMode;
|
||||
}
|
||||
|
||||
void onTriggerChanged(efitick_t stamp, bool isPrimary, bool isRising) {
|
||||
printf("*\r\n");
|
||||
}
|
||||
|
||||
static void simulateTrigger(TriggerAdcDetector &state, CsvReader &reader, float voltageDiv, float adcMaxVoltage) {
|
||||
static const float Vil = 0.3f * adcMaxVoltage;
|
||||
static const float Vih = 0.7f * adcMaxVoltage;
|
||||
|
||||
int prevLogicValue = -1;
|
||||
while (reader.haveMore()) {
|
||||
double value = 0;
|
||||
double stamp = reader.readTimestampAndValues(&value);
|
||||
efitick_t stampUs = (efitick_t)(stamp * 1'000'000);
|
||||
// printf("--simulateTrigger %lld %f\r\n", stamp, (float)value);
|
||||
// convert into mcu-adc voltage
|
||||
value = minF(maxF(value / voltageDiv, 0), adcMaxVoltage);
|
||||
if (state.curAdcMode == TRIGGER_ADC_EXTI) {
|
||||
int logicValue = 0;
|
||||
// imitate Schmitt trigger input
|
||||
if (value < Vil || value > Vih) {
|
||||
logicValue = value > Vih;
|
||||
// we need at least two values to detect an edge
|
||||
if (prevLogicValue != -1) {
|
||||
// printf("--> DIGITAL %d %d\r\n", logicValue, prevLogicValue);
|
||||
|
||||
state.digitalCallback(stampUs, true, logicValue > prevLogicValue ? true : false);
|
||||
}
|
||||
prevLogicValue = logicValue;
|
||||
}
|
||||
} else if (state.curAdcMode == TRIGGER_ADC_ADC) {
|
||||
triggerAdcSample_t sampleValue = value * ADC_MAX_VALUE / adcMaxVoltage;
|
||||
|
||||
// printf("--> ANALOG %d\r\n", sampleValue);
|
||||
|
||||
state.analogCallback(stampUs, sampleValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(big, testTriggerInputAdc) {
|
||||
printf("====================================================================================== testTriggerInputAdc\r\n");
|
||||
|
||||
EngineTestHelper eth(engine_type_e::TEST_ENGINE);
|
||||
|
||||
engineConfiguration->ignitionMode = IM_WASTED_SPARK;
|
||||
|
||||
engineConfiguration->adcVcc = 3.3f;
|
||||
engineConfiguration->analogInputDividerCoefficient = 2.0f;
|
||||
|
||||
// we'll test on 60-2 wheel
|
||||
eth.setTriggerType(trigger_type_e::TT_TOOTHED_WHEEL_60_2);
|
||||
|
||||
ASSERT_EQ(0, engine->triggerCentral.triggerState.totalTriggerErrorCounter);
|
||||
ASSERT_EQ(0, Sensor::getOrZero(SensorType::Rpm)) << "testTriggerInputAdc RPM #1";
|
||||
|
||||
trigAdcState.init();
|
||||
setTriggerAdcMode(TRIGGER_ADC_ADC);
|
||||
|
||||
CsvReader reader(1, 0);
|
||||
|
||||
reader.open("tests/trigger/resources/trigger_adc_1.csv");
|
||||
simulateTrigger(trigAdcState, reader, 2.0f, 3.3f);
|
||||
|
||||
ASSERT_EQ(0, engine->triggerCentral.triggerState.totalTriggerErrorCounter);
|
||||
ASSERT_EQ(0, Sensor::getOrZero(SensorType::Rpm)) << "testTriggerInputAdc RPM #2";
|
||||
}
|
||||
|
Loading…
Reference in New Issue