diff --git a/firmware/config/boards/hellen/compile_cypress.sh b/firmware/config/boards/hellen/compile_cypress.sh index 4c33d5933a..93e495ef49 100644 --- a/firmware/config/boards/hellen/compile_cypress.sh +++ b/firmware/config/boards/hellen/compile_cypress.sh @@ -7,6 +7,8 @@ export EXTRA_PARAMS="-DDUMMY -D__USE_CMSIS\ -DEFI_ENABLE_ASSERTS=FALSE -DCH_DBG_ENABLE_CHECKS=FALSE -DCH_DBG_ENABLE_ASSERTS=FALSE -DCH_DBG_ENABLE_STACK_CHECK=FALSE -DCH_DBG_FILL_THREADS=FALSE -DCH_DBG_THREADS_PROFILING=FALSE\ -DDEFAULT_ENGINE_TYPE=MINIMAL_PINS" +TRIGGER_USE_ADC = yes + export BUILDDIR="build" export PROJECT_BOARD="hellen/cypress" export PROJECT_CPU="cypress" diff --git a/firmware/hw_layer/digital_input/trigger/trigger_input.cpp b/firmware/hw_layer/digital_input/trigger/trigger_input.cpp index 45e74a9b25..4decdae789 100644 --- a/firmware/hw_layer/digital_input/trigger/trigger_input.cpp +++ b/firmware/hw_layer/digital_input/trigger/trigger_input.cpp @@ -14,7 +14,7 @@ #if (EFI_SHAFT_POSITION_INPUT) || defined(__DOXYGEN__) -#if (HAL_USE_ICU == TRUE) || (HAL_TRIGGER_USE_PAL == TRUE) +#if (HAL_USE_ICU == TRUE) || (HAL_TRIGGER_USE_PAL == TRUE) || (HAL_TRIGGER_USE_ADC == TRUE) #if (HAL_USE_ICU == TRUE) void icuTriggerTurnOnInputPins(); @@ -48,10 +48,27 @@ #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 + enum triggerType { TRIGGER_NONE, TRIGGER_ICU, - TRIGGER_EXTI + TRIGGER_EXTI, + TRIGGER_ADC, }; static triggerType shaftTriggerType[TRIGGER_SUPPORTED_CHANNELS]; @@ -83,6 +100,18 @@ static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft } #endif + /* ... 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) { @@ -108,6 +137,10 @@ static void turnOffTriggerInputPin(int index, bool isTriggerShaft) { icuTriggerTurnOffInputPin(brainPin); } #endif /* EFI_ICU_INPUTS */ + if (shaftTriggerType[index] == TRIGGER_ADC) { + adcTriggerTurnOffInputPin(brainPin); + } + if (shaftTriggerType[index] == TRIGGER_EXTI) { extiTriggerTurnOffInputPin(brainPin); } @@ -119,6 +152,10 @@ static void turnOffTriggerInputPin(int index, bool isTriggerShaft) { icuTriggerTurnOffInputPin(brainPin); } #endif /* EFI_ICU_INPUTS */ + if (camTriggerType[index] == TRIGGER_ADC) { + adcTriggerTurnOffInputPin(brainPin); + } + if (camTriggerType[index] == TRIGGER_EXTI) { extiTriggerTurnOffInputPin(brainPin); } @@ -169,7 +206,7 @@ void turnOnTriggerInputPins() { applyNewTriggerInputPins(); } -#endif /* (HAL_USE_ICU == TRUE) || (HAL_TRIGGER_USE_PAL == TRUE) */ +#endif /* (HAL_USE_ICU == TRUE) || (HAL_TRIGGER_USE_PAL == TRUE) || (HAL_TRIGGER_USE_ADC == TRUE) */ void stopTriggerDebugPins() { diff --git a/firmware/hw_layer/digital_input/trigger/trigger_input_adc.cpp b/firmware/hw_layer/digital_input/trigger/trigger_input_adc.cpp index 1ab8719592..0e2bf4b486 100644 --- a/firmware/hw_layer/digital_input/trigger/trigger_input_adc.cpp +++ b/firmware/hw_layer/digital_input/trigger/trigger_input_adc.cpp @@ -10,14 +10,14 @@ #include "pch.h" #include "trigger_input_adc.h" -#define voltsToAdcDivided(volts) (voltsToAdc(volts) / engineConfiguration->analogInputDividerCoefficient) - /*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__) @@ -25,11 +25,18 @@ //!!!!!!!!!! #define TRIGGER_ADC_DEBUG_LED TRUE +//#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 -//#define DEBUG_OUTPUT_IGN1 + +#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 @@ -60,9 +67,11 @@ static ioportmask_t triggerInputPin; #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); - trigAdcState.curAdcMode = adcMode; } static void shaft_callback(void *arg, efitick_t stamp) { @@ -82,8 +91,19 @@ void triggerAdcCallback(triggerAdcSample_t value) { 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 */ -static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft) { + +int adcTriggerTurnOnInputPin(const char *msg, int index, bool isTriggerShaft) { brain_pin_e brainPin = isTriggerShaft ? engineConfiguration->triggerInputPins[index] : engineConfiguration->camInputs[index]; @@ -110,6 +130,10 @@ static int turnOnTriggerInputPin(const char *msg, int index, bool isTriggerShaft #endif #endif /* TRIGGER_ADC_DEBUG_LED */ +#ifdef TRIGGER_ADC_DUMP_BUF + addConsoleAction("trigger_adc_dump", printDumpBuf); +#endif /* TRIGGER_ADC_DUMP_BUF */ + return 0; } @@ -157,26 +181,35 @@ void TriggerAdcDetector::init() { // 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 = 20; + 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); - // these thresholds allow to switch from ADC mode to EXTI mode, indicating the clamping of the signal - switchingThresholdLow = voltsToAdcDivided(1.0f); - switchingThresholdHigh = voltsToAdcDivided(4.0f); + analogToDigitalTransitionCnt = 4; + digitalToAnalogTransitionCnt = 4; // used to filter out low signals - minDeltaThresholdWeakSignal = voltsToAdcDivided(0.05f); // 50mV + 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 = voltsToAdcDivided(0.04f); // 5mV + minDeltaThresholdStrongSignal = triggerVoltsToAdcDivided(0.04f); // 5mV - const triggerAdcSample_t adcDeltaThreshold = voltsToAdcDivided(0.25f); - adcDefaultThreshold = voltsToAdcDivided(3.4f); // this corresponds to VREF1 on Hellen boards + 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 } @@ -214,7 +247,7 @@ void TriggerAdcDetector::digitalCallback(efitick_t stamp, bool isPrimary, bool r switchingTeethCnt = 0; } - if (switchingCnt > 4) { + 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 @@ -234,12 +267,17 @@ void TriggerAdcDetector::analogCallback(efitick_t stamp, triggerAdcSample_t valu 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; - switchingTeethCnt = 0; + //switchingCnt = 0; + switchingCnt = maxI(switchingCnt - 1, 0); } int delta = value - adcThreshold; @@ -328,16 +366,17 @@ void TriggerAdcDetector::analogCallback(efitick_t stamp, triggerAdcSample_t valu // it should not accumulate too much integralSum = 0; - +#if 0 // update triggerAdcITerm efitime_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 } - if (switchingCnt > 4) { + if (switchingCnt >= analogToDigitalTransitionCnt) { switchingCnt = 0; // we need at least 3 high-signal teeth to be certain! if (switchingTeethCnt++ > 3) { @@ -349,10 +388,15 @@ void TriggerAdcDetector::analogCallback(efitick_t stamp, triggerAdcSample_t valu // 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; @@ -360,3 +404,14 @@ void TriggerAdcDetector::analogCallback(efitick_t stamp, triggerAdcSample_t valu #endif // EFI_SIMULATOR } +triggerAdcMode_t getTriggerAdcMode(void) { + return trigAdcState.curAdcMode; +} + +float getTriggerAdcThreshold(void) { + return trigAdcState.adcThreshold; +} + +int getTriggerAdcModeCnt(void) { + return trigAdcState.modeSwitchCnt; +} diff --git a/firmware/hw_layer/digital_input/trigger/trigger_input_adc.h b/firmware/hw_layer/digital_input/trigger/trigger_input_adc.h index 9ddade3580..8ec4931f9e 100644 --- a/firmware/hw_layer/digital_input/trigger/trigger_input_adc.h +++ b/firmware/hw_layer/digital_input/trigger/trigger_input_adc.h @@ -29,11 +29,16 @@ public: 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; @@ -57,4 +62,6 @@ public: int minDeltaThresholdCntPos = 0, minDeltaThresholdCntNeg = 0; int integralSum = 0; int transitionCooldownCnt = 0; + + int modeSwitchCnt = 0; };