From 5de27e0b92c62ee024c845859d622308e8eea5be Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Tue, 21 Sep 2021 14:39:21 -0700 Subject: [PATCH] more knock sense unification (#3250) * more unification * hip stub * comment * guard * channel idx * include * hip * move in to engine * hip9011 --- firmware/controllers/algo/engine.h | 5 ++ .../controllers/engine_cycle/knock_logic.cpp | 48 ++++++++++++++++++- .../controllers/engine_cycle/knock_logic.h | 2 - .../controllers/engine_cycle/spark_logic.cpp | 10 +--- .../controllers/sensors/software_knock.cpp | 34 +++---------- firmware/hw_layer/sensors/hip9011.cpp | 15 +++++- 6 files changed, 74 insertions(+), 40 deletions(-) diff --git a/firmware/controllers/algo/engine.h b/firmware/controllers/algo/engine.h index 4f5c8fa950..8d9d5a6bed 100644 --- a/firmware/controllers/algo/engine.h +++ b/firmware/controllers/algo/engine.h @@ -386,6 +386,11 @@ public: */ float getTimeIgnitionSeconds(void) const; + void onSparkFireKnockSense(uint8_t cylinderIndex, efitick_t nowNt); + + // onKnockSenseCompleted is the callback from the knock sense driver to report a sensed knock level + bool onKnockSenseCompleted(uint8_t cylinderIndex, float levelDbv, efitick_t lastKnockTime); + void knockLogic(float knockVolts DECLARE_ENGINE_PARAMETER_SUFFIX); void printKnockState(void); diff --git a/firmware/controllers/engine_cycle/knock_logic.cpp b/firmware/controllers/engine_cycle/knock_logic.cpp index 1e256cb9d8..da0a5fedb7 100644 --- a/firmware/controllers/engine_cycle/knock_logic.cpp +++ b/firmware/controllers/engine_cycle/knock_logic.cpp @@ -10,6 +10,8 @@ #include "os_access.h" #include "peak_detect.h" +#include "hip9011.h" + int getCylinderKnockBank(uint8_t cylinderIndex) { // C/C++ can't index in to bit fields, we have to provide lookup ourselves switch (cylinderIndex) { @@ -48,7 +50,9 @@ using PD = PeakDetect; static PD peakDetectors[12]; static PD allCylinderPeakDetector; -void onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, efitick_t lastKnockTime) { +bool Engine::onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, efitick_t lastKnockTime) { + bool isKnock = dbv > ENGINE(engineState).knockThreshold; + #if EFI_TUNER_STUDIO // Pass through per-cylinder peak detector float cylPeak = peakDetectors[cylinderIndex].detect(dbv, lastKnockTime); @@ -58,11 +62,51 @@ void onKnockSenseCompleted(uint8_t cylinderIndex, float dbv, efitick_t lastKnock tsOutputChannels.knockLevel = allCylinderPeakDetector.detect(dbv, lastKnockTime); // If this was a knock, count it! - bool isKnock = dbv > ENGINE(engineState).knockThreshold; if (isKnock) { tsOutputChannels.knockCount++; } #endif // EFI_TUNER_STUDIO // TODO: retard timing, then put it back! + + return isKnock; +} + +// This callback is to be implemented by the knock sense driver +void onStartKnockSampling(uint8_t cylinderIndex, float samplingTimeSeconds, uint8_t channelIdx); + +static uint8_t cylinderIndexCopy; + +// Called when its time to start listening for knock +// Does some math, then hands off to the driver to start any sampling hardware +static void startKnockSampling(Engine* engine) { + EXPAND_Engine; + + if (!engine->rpmCalculator.isRunning()) { + return; + } + + // Convert sampling angle to time + float samplingSeconds = ENGINE(rpmCalculator).oneDegreeUs * CONFIG(knockSamplingDuration) / US_PER_SECOND_F; + + // Look up which channel this cylinder uses + auto channel = getCylinderKnockBank(cylinderIndexCopy); + + // Call the driver to begin sampling + onStartKnockSampling(cylinderIndexCopy, samplingSeconds, channel); +} + +static scheduling_s startSampling; + +void Engine::onSparkFireKnockSense(uint8_t cylinderIndex, efitick_t nowNt) { + cylinderIndexCopy = cylinderIndex; + +#if EFI_HIP_9011 || EFI_SOFTWARE_KNOCK + scheduleByAngle(&startSampling, nowNt, + /*angle*/CONFIG(knockDetectionWindowStart), { startKnockSampling, engine } PASS_ENGINE_PARAMETER_SUFFIX); +#endif + +#if EFI_HIP_9011 + hip9011_onFireEvent(cylinderIndex, nowNt); +#endif } diff --git a/firmware/controllers/engine_cycle/knock_logic.h b/firmware/controllers/engine_cycle/knock_logic.h index 34c839d667..6badc2fd95 100644 --- a/firmware/controllers/engine_cycle/knock_logic.h +++ b/firmware/controllers/engine_cycle/knock_logic.h @@ -8,5 +8,3 @@ #pragma once int getCylinderKnockBank(uint8_t cylinderIndex); - -void onKnockSenseCompleted(uint8_t cylinderIndex, float levelDbv, efitick_t lastKnockTime); diff --git a/firmware/controllers/engine_cycle/spark_logic.cpp b/firmware/controllers/engine_cycle/spark_logic.cpp index 022bd68c21..c5c56f05e7 100644 --- a/firmware/controllers/engine_cycle/spark_logic.cpp +++ b/firmware/controllers/engine_cycle/spark_logic.cpp @@ -7,7 +7,6 @@ #include "pch.h" -#include "software_knock.h" #include "spark_logic.h" #include "os_access.h" @@ -15,7 +14,7 @@ #include "event_queue.h" #include "tooth_logger.h" -#include "hip9011.h" +#include "knock_logic.h" #if EFI_ENGINE_CONTROL @@ -215,12 +214,7 @@ if (engineConfiguration->debugMode == DBG_DWELL_METRIC) { prepareCylinderIgnitionSchedule(dwellAngleDuration, sparkDwell, event PASS_ENGINE_PARAMETER_SUFFIX); } -#if EFI_SOFTWARE_KNOCK - knockSamplingCallback(event->cylinderNumber, nowNt); -#endif -#if EFI_HIP_9011 - hip9011_onFireEvent(event->cylinderNumber, nowNt); -#endif + engine->onSparkFireKnockSense(event->cylinderNumber, nowNt); } static void startDwellByTurningSparkPinHigh(IgnitionEvent *event, IgnitionOutputPin *output) { diff --git a/firmware/controllers/sensors/software_knock.cpp b/firmware/controllers/sensors/software_knock.cpp index c9e28e8832..e44270fc3f 100644 --- a/firmware/controllers/sensors/software_knock.cpp +++ b/firmware/controllers/sensors/software_knock.cpp @@ -18,7 +18,6 @@ static Biquad knockFilter; static volatile bool knockIsSampling = false; static volatile bool knockNeedsProcess = false; static volatile size_t sampleCount = 0; -static int cylinderIndexCopy; chibios_rt::BinarySemaphore knockSem(/* taken =*/ true); @@ -93,27 +92,23 @@ static const ADCConversionGroup adcConvGroupCh2 = { FALSE, 1, &completionCallbac }; #endif // KNOCK_HAS_CH2 -const ADCConversionGroup* getConversionGroup(uint8_t cylinderIndex) { +const ADCConversionGroup* getConversionGroup(uint8_t channelIdx) { #if KNOCK_HAS_CH2 - if (getCylinderKnockBank(cylinderIndex)) { + if (channelIdx == 1) { return &adcConvGroupCh2; } #else - (void)cylinderIndex; + (void)channelIdx; #endif // KNOCK_HAS_CH2 return &adcConvGroupCh1; } -static void startKnockSampling(uint8_t cylinderIndex) { +void onStartKnockSampling(uint8_t cylinderIndex, float samplingSeconds, uint8_t channelIdx) { if (!CONFIG(enableSoftwareKnock)) { return; } - if (!engine->rpmCalculator.isRunning()) { - return; - } - // Cancel if ADC isn't ready if (!((KNOCK_ADC.state == ADC_READY) || (KNOCK_ADC.state == ADC_COMPLETE) || @@ -126,13 +121,12 @@ static void startKnockSampling(uint8_t cylinderIndex) { return; } - // Sample for XX degrees - float samplingSeconds = ENGINE(rpmCalculator).oneDegreeUs * CONFIG(knockSamplingDuration) / US_PER_SECOND_F; + // Convert sampling time to number of samples constexpr int sampleRate = KNOCK_SAMPLE_RATE; sampleCount = 0xFFFFFFFE & static_cast(clampF(100, samplingSeconds * sampleRate, efi::size(sampleBuffer))); // Select the appropriate conversion group - it will differ depending on which sensor this cylinder should listen on - auto conversionGroup = getConversionGroup(cylinderIndex); + auto conversionGroup = getConversionGroup(channelIdx); // Stash the current cylinder's index so we can store the result appropriately currentCylinderIndex = cylinderIndex; @@ -141,20 +135,6 @@ static void startKnockSampling(uint8_t cylinderIndex) { lastKnockSampleTime = getTimeNowNt(); } -static void startKnockSamplingNoParam(void*) { - // ugly as hell but that's error: cast between incompatible function types from 'void (*)(uint8_t)' {aka 'void (*)(unsigned char)'} to 'schfunc_t' {aka 'void (*)(void*)'} [-Werror=cast-function-type] - startKnockSampling(cylinderIndexCopy); -} - -static scheduling_s startSampling; - -void knockSamplingCallback(uint8_t cylinderIndex, efitick_t nowNt) { - cylinderIndexCopy = cylinderIndex; - - scheduleByAngle(&startSampling, nowNt, - /*angle*/CONFIG(knockDetectionWindowStart), startKnockSamplingNoParam PASS_ENGINE_PARAMETER_SUFFIX); -} - class KnockThread : public ThreadController<256> { public: KnockThread() : ThreadController("knock", PRIO_KNOCK_PROCESS) {} @@ -221,7 +201,7 @@ void processLastKnockEvent() { // clamp to reasonable range db = clampF(-100, db, 100); - onKnockSenseCompleted(currentCylinderIndex, db, lastKnockTime); + engine->onKnockSenseCompleted(currentCylinderIndex, db, lastKnockTime); } void KnockThread::ThreadTask() { diff --git a/firmware/hw_layer/sensors/hip9011.cpp b/firmware/hw_layer/sensors/hip9011.cpp index a98284b2a9..458d8ef84b 100644 --- a/firmware/hw_layer/sensors/hip9011.cpp +++ b/firmware/hw_layer/sensors/hip9011.cpp @@ -257,6 +257,19 @@ static void endIntegration(HIP9011 *hip) { } } +void onStartKnockSampling(uint8_t cylinderIndex, float samplingTimeSeconds, uint8_t channelIdx) { + /* TODO: @dron0gus: not sure if we need the expectedCylinderNumber logic at all + + Something like this might be right: + + startIntegration(&instance); + + efitick_t windowLength = USF2NT(1e6 * samplingTimeSeconds); + + engine->executor.scheduleByTimestampNt("knock", &hardware.endTimer, getTimeNowNt() + windowLength, { endIntegration, &instance }); + */ +} + /** * Ignition callback used to start HIP integration and schedule finish */ @@ -491,7 +504,7 @@ static msg_t hipThread(void *arg) { engine->knockLogic(knockVolts); // TODO: convert knock level to dBv - onKnockSenseCompleted(instance.cylinderNumber, knockVolts, instance.knockSampleTimestamp); + engine->onKnockSenseCompleted(instance.cylinderNumber, knockVolts, instance.knockSampleTimestamp); #if EFI_HIP_9011_DEBUG /* debug */