more knock sense unification (#3250)

* more unification

* hip stub

* comment

* guard

* channel idx

* include

* hip

* move in to engine

* hip9011
This commit is contained in:
Matthew Kennedy 2021-09-21 14:39:21 -07:00 committed by GitHub
parent 35e1a7cc0c
commit 5de27e0b92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 40 deletions

View File

@ -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);

View File

@ -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<float, MS2NT(100)>;
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
}

View File

@ -8,5 +8,3 @@
#pragma once
int getCylinderKnockBank(uint8_t cylinderIndex);
void onKnockSenseCompleted(uint8_t cylinderIndex, float levelDbv, efitick_t lastKnockTime);

View File

@ -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) {

View File

@ -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<size_t>(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() {

View File

@ -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 */