rusefi-1/firmware/hw_layer/trigger_input_comp.cpp

180 lines
6.4 KiB
C++

/**
* @file trigger_input_comp.cpp
* @brief Position sensor hardware layer, Using hardware comparator
*
* @date Apr 13, 2019
* @author Andrey Belomutskiy, (c) 2012-2020
* @author andreika <prometheus.pcb@gmail.com>
*/
#include "global.h"
#if (EFI_SHAFT_POSITION_INPUT && HAL_USE_COMP) || defined(__DOXYGEN__)
#include "hal_comp.h"
#include "trigger_input.h"
#include "digital_input_icu.h"
extern bool hasFirmwareErrorFlag;
EXTERN_ENGINE
;
static Logging *logger;
static volatile int centeredDacValue = 127;
static volatile int toothCnt = 0;
static volatile int dacHysteresisMin = 1; // = 5V * 1/256 (8-bit DAC) = ~20mV
static volatile int dacHysteresisMax = 15; // = ~300mV
static volatile int dacHysteresisDelta = dacHysteresisMin;
static volatile int hystUpdatePeriodNumEvents = 116; // every ~1 turn of 60-2 wheel
static volatile efitick_t prevNt = 0;
// VR-sensor saturation stuff
static volatile float curVrFreqNt = 0, saturatedVrFreqNt = 0;
// We want to interpolate between min and max depending on the signal level (adaptive hysteresis).
// But we don't want to measure the signal amplitude directly, so we estimate it by measuring the signal frequency:
// for VR sensors, the amplitude is inversely proportional to the tooth's 'time-width'.
// We find it by dividing the total time by the teeth count, and use the reciprocal value as signal frequency!
static void setHysteresis(COMPDriver *comp, int sign) {
// update the hysteresis threshold, but not for every tooth
#ifdef EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS
if (toothCnt++ > hystUpdatePeriodNumEvents) {
efitick_t nowNt = getTimeNowNt();
curVrFreqNt = (float)toothCnt / (float)(nowNt - prevNt);
dacHysteresisDelta = (int)efiRound(interpolateClamped(0.0f, dacHysteresisMin, saturatedVrFreqNt, dacHysteresisMax, curVrFreqNt), 1.0f);
toothCnt = 0;
prevNt = nowNt;
#ifdef TRIGGER_COMP_EXTREME_LOGGING
scheduleMsg(logger, "* f=%f d=%d", curVrFreqNt * 1000.0f, dacHysteresisDelta);
#endif /* TRIGGER_COMP_EXTREME_LOGGING */
}
#endif /* EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS */
comp_lld_set_dac_value(comp, centeredDacValue + dacHysteresisDelta * sign);
}
static void comp_shaft_callback(COMPDriver *comp) {
efitick_t stamp = getTimeNowNt();
uint32_t status = comp_lld_get_status(comp);
int isPrimary = (comp == EFI_COMP_PRIMARY_DEVICE);
if (!isPrimary && !TRIGGER_WAVEFORM(needSecondTriggerInput)) {
return;
}
trigger_event_e signal;
if (status & COMP_IRQ_RISING) {
signal = isPrimary ? (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_FALLING : SHAFT_PRIMARY_RISING) :
(engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_FALLING : SHAFT_SECONDARY_RISING);
hwHandleShaftSignal(signal, stamp);
// shift the threshold down a little bit to avoid false-triggering (threshold hysteresis)
setHysteresis(comp, -1);
}
if (status & COMP_IRQ_FALLING) {
signal = isPrimary ? (engineConfiguration->invertPrimaryTriggerSignal ? SHAFT_PRIMARY_RISING : SHAFT_PRIMARY_FALLING) :
(engineConfiguration->invertSecondaryTriggerSignal ? SHAFT_SECONDARY_RISING : SHAFT_SECONDARY_FALLING);
hwHandleShaftSignal(signal, stamp);
// shift the threshold up a little bit to avoid false-triggering (threshold hysteresis)
setHysteresis(comp, 1);
}
}
// todo: add cam support?
#if 0
static void comp_cam_callback(COMPDriver *comp) {
efitick_t stamp = getTimeNowNt();
if (isRising) {
hwHandleVvtCamSignal(TV_RISE, stamp);
} else {
hwHandleVvtCamSignal(TV_FALL, stamp);
}
}
#endif
static COMPConfig comp_shaft_cfg = {
COMP_OUTPUT_NORMAL, COMP_IRQ_BOTH,
comp_shaft_callback,
0
};
static bool isCompEnabled = false;
void turnOnTriggerInputPins(Logging *sharedLogger) {
logger = sharedLogger;
compInit();
compStart(EFI_COMP_PRIMARY_DEVICE, &comp_shaft_cfg);
applyNewTriggerInputPins();
}
static int getDacValue(uint8_t voltage DECLARE_ENGINE_PARAMETER_SUFFIX) {
constexpr float maxDacValue = 255.0f; // 8-bit DAC
return (int)efiRound(maxDacValue * (float)voltage * VOLTAGE_1_BYTE_PACKING_DIV / CONFIG(adcVcc), 1.0f);
}
void startTriggerInputPins(void) {
//efiAssertVoid(CUSTOM_ERR_, !isCompEnabled, "isCompEnabled");
if (isCompEnabled) {
scheduleMsg(logger, "startTIPins(): already enabled!");
return;
}
centeredDacValue = getDacValue(CONFIG(triggerCompCenterVolt) PASS_ENGINE_PARAMETER_SUFFIX); // usually 2.5V resistor divider
dacHysteresisMin = getDacValue(CONFIG(triggerCompHystMin) PASS_ENGINE_PARAMETER_SUFFIX); // usually ~20mV
dacHysteresisMax = getDacValue(CONFIG(triggerCompHystMax) PASS_ENGINE_PARAMETER_SUFFIX); // usually ~300mV
dacHysteresisDelta = dacHysteresisMin;
// 20 rpm (60_2) = 1000*60/((2*60)*20) = 25 ms for 1 tooth event
float satRpm = CONFIG(triggerCompSensorSatRpm) * RPM_1_BYTE_PACKING_MULT;
hystUpdatePeriodNumEvents = ENGINE(triggerCentral.triggerShape).getSize(); // = 116 for "60-2" trigger wheel
float saturatedToothDurationUs = 60.0f * US_PER_SECOND_F / satRpm / hystUpdatePeriodNumEvents;
saturatedVrFreqNt = 1.0f / US2NT(saturatedToothDurationUs);
scheduleMsg(logger, "startTIPins(): cDac=%d hystMin=%d hystMax=%d satRpm=%.0f satFreq*1k=%f period=%d",
centeredDacValue, dacHysteresisMin, dacHysteresisMax, satRpm, saturatedVrFreqNt * 1000.0f, hystUpdatePeriodNumEvents);
#ifdef EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS
scheduleMsg(logger, "startTIPins(): ADAPTIVE_HYSTERESIS enabled!");
#endif /* EFI_TRIGGER_COMP_ADAPTIVE_HYSTERESIS */
int channel = EFI_COMP_TRIGGER_CHANNEL; // todo: use getInputCaptureChannel(hwPin);
// todo: set pin mode to default (analog/comparator)
//palSetPadMode(comp_channel_port[channel], comp_channel_pad[channel], PAL_MODE_INPUT_ANALOG);
// no generic hal support for extended COMP configuration, so we use hal_lld layer...
osalSysLock();
comp_lld_set_dac_value(EFI_COMP_PRIMARY_DEVICE, centeredDacValue);
comp_lld_channel_enable(EFI_COMP_PRIMARY_DEVICE, channel);
osalSysUnlock();
compEnable(EFI_COMP_PRIMARY_DEVICE);
isCompEnabled = true;
}
void stopTriggerInputPins(void) {
if (!isCompEnabled) {
scheduleMsg(logger, "stopTIPins(): already disabled!");
return;
}
scheduleMsg(logger, "stopTIPins();");
compDisable(EFI_COMP_PRIMARY_DEVICE);
isCompEnabled = false;
#if 0
for (int i = 0; i < TRIGGER_SUPPORTED_CHANNELS; i++) {
if (isConfigurationChanged(bc.triggerInputPins[i])) {
turnOffTriggerInputPin(activeConfiguration.bc.triggerInputPins[i]);
}
}
if (isConfigurationChanged(camInput)) {
turnOffTriggerInputPin(activeConfiguration.camInput);
}
#endif
}
#endif /* EFI_SHAFT_POSITION_INPUT && HAL_USE_COMP */