hip9011 and friends (#2527)

* engine math: extrant getFiringOrderTable for reuse

* engine math: getNextFiringCylinderId helper

* introduce knock_logic: first member is getCylinderKnockBank()

moved from software_knock.cpp

* hip9011: support two inputs/banks

* fix CI

* Board Subaru EG33: populated with TPIC8101 with Advanced mode

* hip9011: test communication in advanced mode

* hip9011: handle situation when chip is already in advanced mode

* Board Subaru EG33: cylinder to knock bank mapping

* hip9011: count spi transactions in advansed mode too

* hip9011: reset incalid responce counter after chip initialization

* hip9011: make debug output more structured
This commit is contained in:
Andrey G 2021-04-05 01:13:21 +03:00 committed by GitHub
parent c785a5705c
commit fa840a7593
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 375 additions and 158 deletions

View File

@ -195,6 +195,8 @@ void setBoardDefaultConfiguration(void) {
engineConfiguration->hip9011IntHoldPinMode = OM_OPENDRAIN; engineConfiguration->hip9011IntHoldPinMode = OM_OPENDRAIN;
engineConfiguration->hipOutputChannel = EFI_ADC_7; /* PA7 */ engineConfiguration->hipOutputChannel = EFI_ADC_7; /* PA7 */
engineConfiguration->isHip9011Enabled = true; engineConfiguration->isHip9011Enabled = true;
/* this board has TPIC8101, that supports advanced mode */
engineConfiguration->useTpicAdvancedMode = true;
engineConfiguration->hip9011PrescalerAndSDO = (0x6 << 1); //HIP_16MHZ_PRESCALER; engineConfiguration->hip9011PrescalerAndSDO = (0x6 << 1); //HIP_16MHZ_PRESCALER;
@ -204,6 +206,14 @@ void setBoardDefaultConfiguration(void) {
engineConfiguration->cylinderBore = 96.9; engineConfiguration->cylinderBore = 96.9;
engineConfiguration->maxKnockSubDeg = 20.0; engineConfiguration->maxKnockSubDeg = 20.0;
/* Cylinder to knock bank mapping */
engineConfiguration->knockBankCyl1 = 0;
engineConfiguration->knockBankCyl2 = 1;
engineConfiguration->knockBankCyl3 = 0;
engineConfiguration->knockBankCyl4 = 1;
engineConfiguration->knockBankCyl5 = 0;
engineConfiguration->knockBankCyl6 = 1;
#if 0 #if 0
engineConfiguration->cj125SpiDevice = SPI_DEVICE_3; engineConfiguration->cj125SpiDevice = SPI_DEVICE_3;
engineConfiguration->cj125ua = EFI_ADC_9; engineConfiguration->cj125ua = EFI_ADC_9;

View File

@ -34,6 +34,7 @@ CONTROLLERS_SRC_CPP = \
$(CONTROLLERS_DIR)/engine_cycle/high_pressure_fuel_pump.cpp \ $(CONTROLLERS_DIR)/engine_cycle/high_pressure_fuel_pump.cpp \
$(CONTROLLERS_DIR)/engine_cycle/rpm_calculator.cpp \ $(CONTROLLERS_DIR)/engine_cycle/rpm_calculator.cpp \
$(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \ $(CONTROLLERS_DIR)/engine_cycle/spark_logic.cpp \
$(CONTROLLERS_DIR)/engine_cycle/knock_logic.cpp \
$(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \ $(CONTROLLERS_DIR)/engine_cycle/main_trigger_callback.cpp \
$(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \ $(CONTROLLERS_DIR)/engine_cycle/aux_valves.cpp \
$(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \ $(CONTROLLERS_DIR)/engine_cycle/fuel_schedule.cpp \

View File

@ -0,0 +1,46 @@
/*
* @file knock_logic.c
*
* @date Apr 04, 2021
* @author Andrey Gusakov
*/
#include "engine.h"
#include "knock_logic.h"
#include "os_access.h"
EXTERN_ENGINE;
int getCylinderKnockBank(uint8_t cylinderIndex) {
// C/C++ can't index in to bit fields, we have to provide lookup ourselves
switch (cylinderIndex) {
#if EFI_PROD_CODE
case 0:
return CONFIG(knockBankCyl1);
case 1:
return CONFIG(knockBankCyl2);
case 2:
return CONFIG(knockBankCyl3);
case 3:
return CONFIG(knockBankCyl4);
case 4:
return CONFIG(knockBankCyl5);
case 5:
return CONFIG(knockBankCyl6);
case 6:
return CONFIG(knockBankCyl7);
case 7:
return CONFIG(knockBankCyl8);
case 8:
return CONFIG(knockBankCyl9);
case 9:
return CONFIG(knockBankCyl10);
case 10:
return CONFIG(knockBankCyl11);
case 11:
return CONFIG(knockBankCyl12);
#endif
default:
return 0;
}
}

View File

@ -0,0 +1,10 @@
/*
* @file knock_logic.h
*
* @date Apr 04, 2021
* @author Andrey Gusakov
*/
#pragma once
int getCylinderKnockBank(uint8_t cylinderIndex);

View File

@ -131,6 +131,7 @@ floatms_t getSparkDwell(int rpm DECLARE_ENGINE_PARAMETER_SUFFIX) {
#endif #endif
} }
static const int order_1[] = {1};
static const int order_1_2[] = {1, 2}; static const int order_1_2[] = {1, 2};
@ -239,6 +240,87 @@ static int getFiringOrderLength(DECLARE_ENGINE_PARAMETER_SIGNATURE) {
return 1; return 1;
} }
static const int *getFiringOrderTable(DECLARE_ENGINE_PARAMETER_SIGNATURE)
{
switch (CONFIG(specs.firingOrder)) {
case FO_1:
return order_1;
// 2 cylinder
case FO_1_2:
return order_1_2;
// 3 cylinder
case FO_1_2_3:
return order_1_2_3;
case FO_1_3_2:
return order_1_3_2;
// 4 cylinder
case FO_1_3_4_2:
return order_1_THEN_3_THEN_4_THEN2;
case FO_1_2_4_3:
return order_1_THEN_2_THEN_4_THEN3;
case FO_1_3_2_4:
return order_1_THEN_3_THEN_2_THEN4;
case FO_1_4_3_2:
return order_1_THEN_4_THEN_3_THEN2;
// 5 cylinder
case FO_1_2_4_5_3:
return order_1_2_4_5_3;
// 6 cylinder
case FO_1_5_3_6_2_4:
return order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4;
case FO_1_4_2_5_3_6:
return order_1_THEN_4_THEN_2_THEN_5_THEN_3_THEN_6;
case FO_1_2_3_4_5_6:
return order_1_THEN_2_THEN_3_THEN_4_THEN_5_THEN_6;
case FO_1_6_3_2_5_4:
return order_1_6_3_2_5_4;
// 8 cylinder
case FO_1_8_4_3_6_5_7_2:
return order_1_8_4_3_6_5_7_2;
case FO_1_8_7_2_6_5_4_3:
return order_1_8_7_2_6_5_4_3;
case FO_1_5_4_2_6_3_7_8:
return order_1_5_4_2_6_3_7_8;
case FO_1_2_7_8_4_5_6_3:
return order_1_2_7_8_4_5_6_3;
case FO_1_3_7_2_6_5_4_8:
return order_1_3_7_2_6_5_4_8;
case FO_1_2_3_4_5_6_7_8:
return order_1_2_3_4_5_6_7_8;
case FO_1_5_4_8_6_3_7_2:
return order_1_5_4_8_6_3_7_2;
// 9 cylinder
case FO_1_2_3_4_5_6_7_8_9:
return order_1_2_3_4_5_6_7_8_9;
// 10 cylinder
case FO_1_10_9_4_3_6_5_8_7_2:
return order_1_10_9_4_3_6_5_8_7_2;
// 12 cylinder
case FO_1_7_5_11_3_9_6_12_2_8_4_10:
return order_1_7_5_11_3_9_6_12_2_8_4_10;
case FO_1_7_4_10_2_8_6_12_3_9_5_11:
return order_1_7_4_10_2_8_6_12_3_9_5_11;
case FO_1_12_5_8_3_10_6_7_2_11_4_9:
return order_1_12_5_8_3_10_6_7_2_11_4_9;
case FO_1_2_3_4_5_6_7_8_9_10_11_12:
return order_1_2_3_4_5_6_7_8_9_10_11_12;
// do not ask
case FO_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10:
return order_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10;
default:
firmwareError(CUSTOM_OBD_UNKNOWN_FIRING_ORDER, "Invalid firing order: %d", CONFIG(specs.firingOrder));
}
return NULL;
}
/** /**
* @param index from zero to cylindersCount - 1 * @param index from zero to cylindersCount - 1
@ -264,81 +346,27 @@ int getCylinderId(int index DECLARE_ENGINE_PARAMETER_SUFFIX) {
return 1; return 1;
} }
switch (CONFIG(specs.firingOrder)) { const int *firingOrderTable = getFiringOrderTable(PASS_ENGINE_PARAMETER_SIGNATURE);
case FO_1: if (firingOrderTable)
return 1; return firingOrderTable[index];
// 2 cylinder /* else
case FO_1_2: error already reported */
return order_1_2[index];
// 3 cylinder
case FO_1_2_3:
return order_1_2_3[index];
case FO_1_3_2:
return order_1_3_2[index];
// 4 cylinder
case FO_1_3_4_2:
return order_1_THEN_3_THEN_4_THEN2[index];
case FO_1_2_4_3:
return order_1_THEN_2_THEN_4_THEN3[index];
case FO_1_3_2_4:
return order_1_THEN_3_THEN_2_THEN4[index];
case FO_1_4_3_2:
return order_1_THEN_4_THEN_3_THEN2[index];
// 5 cylinder
case FO_1_2_4_5_3:
return order_1_2_4_5_3[index];
// 6 cylinder return 1;
case FO_1_5_3_6_2_4: }
return order_1_THEN_5_THEN_3_THEN_6_THEN_2_THEN_4[index];
case FO_1_4_2_5_3_6:
return order_1_THEN_4_THEN_2_THEN_5_THEN_3_THEN_6[index];
case FO_1_2_3_4_5_6:
return order_1_THEN_2_THEN_3_THEN_4_THEN_5_THEN_6[index];
case FO_1_6_3_2_5_4:
return order_1_6_3_2_5_4[index];
// 8 cylinder /**
case FO_1_8_4_3_6_5_7_2: * @param prevCylinderId from one to cylindersCount
return order_1_8_4_3_6_5_7_2[index]; * @return cylinderId from one to cylindersCount
case FO_1_8_7_2_6_5_4_3: */
return order_1_8_7_2_6_5_4_3[index]; int getNextFiringCylinderId(int prevCylinderId DECLARE_ENGINE_PARAMETER_SUFFIX) {
case FO_1_5_4_2_6_3_7_8: const int firingOrderLength = getFiringOrderLength(PASS_ENGINE_PARAMETER_SIGNATURE);
return order_1_5_4_2_6_3_7_8[index]; const int *firingOrderTable = getFiringOrderTable(PASS_ENGINE_PARAMETER_SIGNATURE);
case FO_1_2_7_8_4_5_6_3:
return order_1_2_7_8_4_5_6_3[index];
case FO_1_3_7_2_6_5_4_8:
return order_1_3_7_2_6_5_4_8[index];
case FO_1_2_3_4_5_6_7_8:
return order_1_2_3_4_5_6_7_8[index];
case FO_1_5_4_8_6_3_7_2:
return order_1_5_4_8_6_3_7_2[index];
// 9 cylinder if (firingOrderTable) {
case FO_1_2_3_4_5_6_7_8_9: for (size_t i = 0; i < firingOrderLength; i++)
return order_1_2_3_4_5_6_7_8_9[index]; if (firingOrderTable[i] == prevCylinderId)
return firingOrderTable[(i + 1) % firingOrderLength];
// 10 cylinder
case FO_1_10_9_4_3_6_5_8_7_2:
return order_1_10_9_4_3_6_5_8_7_2[index];
// 12 cylinder
case FO_1_7_5_11_3_9_6_12_2_8_4_10:
return order_1_7_5_11_3_9_6_12_2_8_4_10[index];
case FO_1_7_4_10_2_8_6_12_3_9_5_11:
return order_1_7_4_10_2_8_6_12_3_9_5_11[index];
case FO_1_12_5_8_3_10_6_7_2_11_4_9:
return order_1_12_5_8_3_10_6_7_2_11_4_9[index];
case FO_1_2_3_4_5_6_7_8_9_10_11_12:
return order_1_2_3_4_5_6_7_8_9_10_11_12[index];
// do not ask
case FO_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10:
return order_1_14_9_4_7_12_15_6_13_8_3_16_11_2_5_10[index];
default:
firmwareError(CUSTOM_OBD_UNKNOWN_FIRING_ORDER, "Invalid firing order: %d", CONFIG(specs.firingOrder));
} }
return 1; return 1;
} }

View File

@ -53,6 +53,7 @@ ignition_mode_e getCurrentIgnitionMode(DECLARE_ENGINE_PARAMETER_SIGNATURE);
void prepareIgnitionPinIndices(ignition_mode_e ignitionMode DECLARE_ENGINE_PARAMETER_SUFFIX); void prepareIgnitionPinIndices(ignition_mode_e ignitionMode DECLARE_ENGINE_PARAMETER_SUFFIX);
int getCylinderId(int index DECLARE_ENGINE_PARAMETER_SUFFIX); int getCylinderId(int index DECLARE_ENGINE_PARAMETER_SUFFIX);
int getNextFiringCylinderId(int prevCylinderId DECLARE_ENGINE_PARAMETER_SUFFIX);
void setTimingRpmBin(float from, float to DECLARE_CONFIG_PARAMETER_SUFFIX); void setTimingRpmBin(float from, float to DECLARE_CONFIG_PARAMETER_SUFFIX);
void setTimingLoadBin(float from, float to DECLARE_CONFIG_PARAMETER_SUFFIX); void setTimingLoadBin(float from, float to DECLARE_CONFIG_PARAMETER_SUFFIX);

View File

@ -4,6 +4,7 @@
#include "biquad.h" #include "biquad.h"
#include "perf_trace.h" #include "perf_trace.h"
#include "thread_controller.h" #include "thread_controller.h"
#include "knock_logic.h"
#include "software_knock.h" #include "software_knock.h"
#include "thread_priority.h" #include "thread_priority.h"
@ -93,31 +94,11 @@ static const ADCConversionGroup adcConvGroupCh2 = { FALSE, 1, &completionCallbac
0, // sqr2 0, // sqr2
ADC_SQR3_SQ1_N(KNOCK_ADC_CH2) ADC_SQR3_SQ1_N(KNOCK_ADC_CH2)
}; };
static bool cylinderUsesChannel2(uint8_t cylinderIndex) {
// C/C++ can't index in to bit fields, we have to provide lookup ourselves
switch (cylinderIndex) {
case 0: return CONFIG(knockBankCyl1);
case 1: return CONFIG(knockBankCyl2);
case 2: return CONFIG(knockBankCyl3);
case 3: return CONFIG(knockBankCyl4);
case 4: return CONFIG(knockBankCyl5);
case 5: return CONFIG(knockBankCyl6);
case 6: return CONFIG(knockBankCyl7);
case 7: return CONFIG(knockBankCyl8);
case 8: return CONFIG(knockBankCyl9);
case 9: return CONFIG(knockBankCyl10);
case 10: return CONFIG(knockBankCyl11);
case 11: return CONFIG(knockBankCyl12);
default: return false;
}
}
#endif // KNOCK_HAS_CH2 #endif // KNOCK_HAS_CH2
const ADCConversionGroup* getConversionGroup(uint8_t cylinderIndex) { const ADCConversionGroup* getConversionGroup(uint8_t cylinderIndex) {
#if KNOCK_HAS_CH2 #if KNOCK_HAS_CH2
if (cylinderUsesChannel2(cylinderIndex)) { if (getCylinderKnockBank(cylinderIndex)) {
return &adcConvGroupCh2; return &adcConvGroupCh2;
} }
#else #else

View File

@ -116,17 +116,21 @@ static void hip_addconsoleActions(void);
/* Local functions. */ /* Local functions. */
/*==========================================================================*/ /*==========================================================================*/
static int checkResponse(uint8_t tx, uint8_t rx) { static int checkResponseDefMode(uint8_t tx, uint8_t rx) {
/* TODO: implement response check for Advanced SPI mode too */ /* in default SPI mode SDO is directly equals the SDI (echo function) */
if (tx == rx) { if (tx == rx) {
instance.correctResponsesCount++;
return 0; return 0;
} else { } else {
instance.invalidResponsesCount++;
return -1; return -1;
} }
} }
static int checkResponseAdvMode(uint8_t tx, uint8_t rx) {
UNUSED(tx); UNUSED(rx);
/* TODO: no check for advanced mode yet */
return 0;
}
int Hip9011Hardware::sendSyncCommand(uint8_t tx, uint8_t *rx_ptr) { int Hip9011Hardware::sendSyncCommand(uint8_t tx, uint8_t *rx_ptr) {
int ret; int ret;
uint8_t rx; uint8_t rx;
@ -143,20 +147,22 @@ int Hip9011Hardware::sendSyncCommand(uint8_t tx, uint8_t *rx_ptr) {
spiUnselect(spi); spiUnselect(spi);
/* Ownership release. */ /* Ownership release. */
spiReleaseBus(spi); spiReleaseBus(spi);
/* check response */ /* received data */
if (instance.adv_mode == false) { if (rx_ptr)
/* only default SPI mode SDO is directly equals the SDI (echo function) */
ret = checkResponse(tx, rx);
if (ret)
return ret;
}
if (rx_ptr) {
*rx_ptr = rx; *rx_ptr = rx;
} /* check response */
if (instance.adv_mode == false)
ret = checkResponseDefMode(tx, rx);
else
ret = checkResponseAdvMode(tx, rx);
return 0; /* statistic counters */
if (ret)
instance.invalidResponsesCount++;
else
instance.correctResponsesCount++;
return ret;
} }
EXTERN_ENGINE; EXTERN_ENGINE;
@ -214,13 +220,25 @@ void hip9011_startKnockSampling(uint8_t cylinderNumber, efitick_t nowNt) {
return; return;
} }
instance.cylinderNumber = cylinderNumber; if (cylinderNumber == instance.expectedCylinderNumber) {
startIntegration(NULL); /* save currect cylinder */
instance.cylinderNumber = cylinderNumber;
startIntegration(NULL);
/* TODO: reference to knockDetectionWindowStart */ /* TODO: reference to knockDetectionWindowStart */
scheduleByAngle(&endTimer, nowNt, scheduleByAngle(&endTimer, nowNt,
engineConfiguration->knockDetectionWindowEnd - engineConfiguration->knockDetectionWindowStart, engineConfiguration->knockDetectionWindowEnd - engineConfiguration->knockDetectionWindowStart,
&endIntegration); &endIntegration);
} else {
/* out of sync */
if (instance.expectedCylinderNumber >= 0)
instance.unsync++;
/* save currect cylinder */
instance.cylinderNumber = cylinderNumber;
/* Skip integration, call driver task to prepare for next cylinder */
instance.state = NOT_READY;
hip_wake_driver();
}
} }
void hipAdcCallback(adcsample_t adcValue) { void hipAdcCallback(adcsample_t adcValue) {
@ -234,26 +252,82 @@ void hipAdcCallback(adcsample_t adcValue) {
} }
} }
static int hip_testAdvMode(void) {
int ret;
uint8_t ret0, ret1, ret2;
/* do not care about configuration values, we meed replyes only.
* correct values will be uploaded later */
/* A control byte is written to the SDI and shifted with the MSB
* first. The response byte on the SDO is shifted out with the MSB
* first. The response byte corresponds to the previous command.
* Therefore, the SDI shifts in a control byte n and shifts out a
* response command byte n 1. */
ret = instance.hw->sendSyncCommand(SET_BAND_PASS_CMD(0), NULL);
if (ret)
return ret;
ret = instance.hw->sendSyncCommand(SET_GAIN_CMD(0), &ret0);
if (ret)
return ret;
ret = instance.hw->sendSyncCommand(SET_INTEGRATOR_CMD(0), &ret1);
if (ret)
return ret;
ret = instance.hw->sendSyncCommand(SET_INTEGRATOR_CMD(0), &ret2);
if (ret)
return ret;
/* magic reply bytes from DS Table 2 */
if ((ret0 == SET_BAND_PASS_REP) &&
(ret1 == SET_GAIN_REP) &&
(ret2 == SET_INTEGRATOR_REP))
return 0;
return -1;
}
static int hip_init(void) { static int hip_init(void) {
int ret; int ret;
ret = instance.hw->sendSyncCommand(SET_PRESCALER_CMD(instance.prescaler), NULL); ret = instance.hw->sendSyncCommand(SET_PRESCALER_CMD(instance.prescaler), NULL);
if (ret) if (ret) {
return ret; /* NOTE: hip9011/tpic8101 can be in default or advansed mode at this point
* If we supposed not to support advanced mode this is definitely error */
// '0' for channel #1 if (!CONFIG(useTpicAdvancedMode))
ret = instance.hw->sendSyncCommand(SET_CHANNEL_CMD(instance.channelIdx), NULL);
if (ret)
return ret;
if (CONFIG(useTpicAdvancedMode)) {
// enable advanced mode for digital integrator output
ret = instance.hw->sendSyncCommand(SET_ADVANCED_MODE_CMD, NULL);
if (ret)
return ret; return ret;
instance.adv_mode = true;
} }
/* ...othervice or when no error is reported lets try to switch to advanced mode */
if (CONFIG(useTpicAdvancedMode)) {
/* enable advanced mode */
ret = instance.hw->sendSyncCommand(SET_ADVANCED_MODE_CMD, NULL);
if (ret) {
uint8_t rx;
/* communication error is detected for default mode...
* may be we are in advanced mode already?
* Now we dont care for return value */
instance.hw->sendSyncCommand(SET_ADVANCED_MODE_CMD, &rx);
if (rx != SET_ADVANCED_MODE_REP) {
/* this is realy a communication problem */
return ret;
}
}
/* now we should be in advanced mode... if chip supports...
* set advanced mode flag now so checkResponse will switch to
* advanced mode checkig (not implemented) */
instance.adv_mode = true;
ret = hip_testAdvMode();
if (ret) {
warning(CUSTOM_OBD_KNOCK_PROCESSOR, "TPIC/HIP does not support advanced mode");
instance.adv_mode = false;
}
}
/* reset error counter now */
instance.invalidResponsesCount = 0;
instance.state = READY_TO_INTEGRATE; instance.state = READY_TO_INTEGRATE;
return 0; return 0;
@ -296,6 +370,8 @@ static msg_t hipThread(void *arg) {
/* load new/updated settings */ /* load new/updated settings */
instance.handleSettings(GET_RPM() DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS)); instance.handleSettings(GET_RPM() DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
/* switch input channel */
instance.handleChannel(DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
/* State */ /* State */
instance.state = READY_TO_INTEGRATE; instance.state = READY_TO_INTEGRATE;
@ -303,8 +379,8 @@ static msg_t hipThread(void *arg) {
if (msg == MSG_TIMEOUT) { if (msg == MSG_TIMEOUT) {
/* ??? */ /* ??? */
} else { } else {
/* TODO: check for correct cylinder/input */ /* Check for correct cylinder/input */
if (1) { if (instance.cylinderNumber == instance.expectedCylinderNumber) {
/* calculations */ /* calculations */
float knockVolts = instance.raw_value * adcToVolts(1) * CONFIG(analogInputDividerCoefficient); float knockVolts = instance.raw_value * adcToVolts(1) * CONFIG(analogInputDividerCoefficient);
hipValueMax = maxF(knockVolts, hipValueMax); hipValueMax = maxF(knockVolts, hipValueMax);
@ -313,6 +389,11 @@ static msg_t hipThread(void *arg) {
/* TunerStudio */ /* TunerStudio */
tsOutputChannels.knockLevels[instance.cylinderNumber] = knockVolts; tsOutputChannels.knockLevels[instance.cylinderNumber] = knockVolts;
tsOutputChannels.knockLevel = knockVolts; tsOutputChannels.knockLevel = knockVolts;
/* counters */
instance.samples++;
} else {
/* out of sync event already calculated, nothing to do */
} }
} }
} }
@ -357,7 +438,6 @@ void initHip9011(Logging *sharedLogger) {
startHip9001_pins(); startHip9001_pins();
/* load settings */ /* load settings */
instance.channelIdx = 0;
instance.prescaler = CONFIG(hip9011PrescalerAndSDO); instance.prescaler = CONFIG(hip9011PrescalerAndSDO);
scheduleMsg(logger, "Starting HIP9011/TPIC8101 driver"); scheduleMsg(logger, "Starting HIP9011/TPIC8101 driver");
@ -377,20 +457,30 @@ static void showHipInfo(void) {
return; return;
} }
scheduleMsg(logger, "enabled=%s state=%s", scheduleMsg(logger, "HIP9011: enabled %s state %s",
boolToString(CONFIG(isHip9011Enabled)), boolToString(CONFIG(isHip9011Enabled)),
getHip_state_e(instance.state)); getHip_state_e(instance.state));
scheduleMsg(logger, " bore=%.2fmm freq=%.2fkHz", scheduleMsg(logger, " Advanced mode: enabled %d used %d",
engineConfiguration->cylinderBore, CONFIG(useTpicAdvancedMode),
instance.getBand(PASS_HIP_PARAMS)); instance.adv_mode);
scheduleMsg(logger, " band idx=%d integrator idx=%d gain %.2f (idx %d) output=%s", scheduleMsg(logger, " Input Ch %d (cylinder %d next %d)",
instance.bandIdx, instance.channelIdx,
instance.intergratorIdx, instance.cylinderNumber,
instance.expectedCylinderNumber);
scheduleMsg(logger, " Cyl bore %.2fmm freq %.2fkHz band idx 0x%x",
engineConfiguration->cylinderBore,
instance.getBand(PASS_HIP_PARAMS),
instance.bandIdx);
scheduleMsg(logger, " Integrator idx 0x%x",
instance.intergratorIdx);
scheduleMsg(logger, " Gain %.2f idx 0x%x",
engineConfiguration->hip9011Gain, engineConfiguration->hip9011Gain,
instance.gainIdx, instance.gainIdx);
getAdc_channel_e(engineConfiguration->hipOutputChannel));
scheduleMsg(logger, " PaSDO=0x%x", scheduleMsg(logger, " PaSDO=0x%x",
instance.prescaler); instance.prescaler);
@ -400,31 +490,37 @@ static void showHipInfo(void) {
engine->knockCount, engine->knockCount,
engineConfiguration->maxKnockSubDeg); engineConfiguration->maxKnockSubDeg);
scheduleMsg(logger, " spi=%s IntHold@%s(0x%x) correct response=%d incorrect response=%d (%s)", scheduleMsg(logger, " Adc input %s (%.2f V)",
getSpi_device_e(engineConfiguration->hip9011SpiDevice), getAdc_channel_e(engineConfiguration->hipOutputChannel),
getVoltage("hipinfo", engineConfiguration->hipOutputChannel));
scheduleMsg(logger, " IntHold %s (mode 0x%x)",
hwPortname(CONFIG(hip9011IntHoldPin)), hwPortname(CONFIG(hip9011IntHoldPin)),
CONFIG(hip9011IntHoldPinMode), CONFIG(hip9011IntHoldPinMode));
instance.correctResponsesCount,
instance.invalidResponsesCount, scheduleMsg(logger, " Spi %s CS %s (mode 0x%x)",
instance.invalidResponsesCount > 0 ? "NOT GOOD" : "ok"); getSpi_device_e(engineConfiguration->hip9011SpiDevice),
hwPortname(CONFIG(hip9011CsPin)),
CONFIG(hip9011CsPinMode));
#if EFI_PROD_CODE #if EFI_PROD_CODE
scheduleMsg(logger, "hip %.2fv/last=%.2f/max=%.2f adv=%d",
engine->knockVolts,
getVoltage("hipinfo", engineConfiguration->hipOutputChannel),
hipValueMax,
CONFIG(useTpicAdvancedMode));
scheduleMsg(logger, "hip9011 CS@%s",
hwPortname(CONFIG(hip9011CsPin)));
printSpiConfig(logger, "hip9011", CONFIG(hip9011SpiDevice)); printSpiConfig(logger, "hip9011", CONFIG(hip9011SpiDevice));
#endif /* EFI_PROD_CODE */ #endif /* EFI_PROD_CODE */
scheduleMsg(logger, "start %.2f end %.2f", scheduleMsg(logger, " SPI good response %d incorrect response %d",
instance.correctResponsesCount,
instance.invalidResponsesCount);
scheduleMsg(logger, " hip %.2f vmax=%.2f",
engine->knockVolts,
hipValueMax);
scheduleMsg(logger, " Window start %.2f end %.2f",
engineConfiguration->knockDetectionWindowStart, engineConfiguration->knockDetectionWindowStart,
engineConfiguration->knockDetectionWindowEnd); engineConfiguration->knockDetectionWindowEnd);
scheduleMsg(logger, "Status: overruns %d", scheduleMsg(logger, " Counters: samples %d overruns %d sync miss %d",
instance.overrun); instance.samples, instance.overrun, instance.unsync);
hipValueMax = 0; hipValueMax = 0;
engine->printKnockState(); engine->printKnockState();

View File

@ -7,6 +7,10 @@
#include "global.h" #include "global.h"
#include "engine.h" #include "engine.h"
/* getNextFiringCylinderId */
#include "engine_math.h"
/* getCylinderKnockBank */
#include "knock_logic.h"
#include "hip9011_logic.h" #include "hip9011_logic.h"
/*==========================================================================*/ /*==========================================================================*/
@ -183,3 +187,28 @@ void HIP9011::handleSettings(int rpm DEFINE_PARAM_SUFFIX(DEFINE_HIP_PARAMS)) {
prescaler = new_prescaler; prescaler = new_prescaler;
} }
} }
int HIP9011::cylinderToChannelIdx(int cylinder) {
/* TODO: hip9011 inputs to bank mapping? */
return getCylinderKnockBank(cylinder);
}
void HIP9011::handleChannel(DEFINE_HIP_PARAMS) {
int ret;
/* we did not receive any callback from spark logic with valid cylinder yet */
if (cylinderNumber < 0)
return;
/* find next firing cylinder */
/* MAGIC +1 -1, couse getNextFiringCylinderId expect cylinders to start from 1 */
expectedCylinderNumber = getNextFiringCylinderId((cylinderNumber + 1) PASS_ENGINE_PARAMETER_SUFFIX) - 1;
int nextChannelIdx = cylinderToChannelIdx(expectedCylinderNumber);
if (nextChannelIdx == channelIdx)
return;
ret = sendCommand(SET_CHANNEL_CMD(nextChannelIdx));
if (ret == 0)
channelIdx = nextChannelIdx;
}

View File

@ -61,6 +61,8 @@ public:
class HIP9011 { class HIP9011 {
public: public:
DECLARE_ENGINE_PTR;
explicit HIP9011(Hip9011HardwareInterface *hardware); explicit HIP9011(Hip9011HardwareInterface *hardware);
int sendCommand(uint8_t cmd); int sendCommand(uint8_t cmd);
@ -68,6 +70,8 @@ public:
void prepareRpmLookup(void); void prepareRpmLookup(void);
void setAngleWindowWidth(DEFINE_HIP_PARAMS); void setAngleWindowWidth(DEFINE_HIP_PARAMS);
void handleSettings(int rpm DEFINE_PARAM_SUFFIX(DEFINE_HIP_PARAMS)); void handleSettings(int rpm DEFINE_PARAM_SUFFIX(DEFINE_HIP_PARAMS));
int cylinderToChannelIdx(int cylinder);
void handleChannel(DEFINE_HIP_PARAMS);
float getBand(DEFINE_HIP_PARAMS); float getBand(DEFINE_HIP_PARAMS);
int getIntegrationIndexByRpm(float rpm); int getIntegrationIndexByRpm(float rpm);
int getBandIndex(DEFINE_HIP_PARAMS); int getBandIndex(DEFINE_HIP_PARAMS);
@ -98,11 +102,14 @@ public:
* hipOutput should be set to used FAST adc device * hipOutput should be set to used FAST adc device
*/ */
hip_state_e state; hip_state_e state;
uint8_t cylinderNumber; int8_t cylinderNumber = -1;
int8_t expectedCylinderNumber = -1;
int raw_value; int raw_value;
/* error counters */ /* counters */
int samples = 0;
int overrun = 0; int overrun = 0;
int unsync = 0;
float rpmLookup[INT_LOOKUP_SIZE]; float rpmLookup[INT_LOOKUP_SIZE];
}; };
@ -113,12 +120,20 @@ public:
#define SET_CHANNEL_CMD(v) (0xE0 | ((v) & 0x01)) #define SET_CHANNEL_CMD(v) (0xE0 | ((v) & 0x01))
// 0b00xx.xxxx // 0b00xx.xxxx
#define SET_BAND_PASS_CMD(v) (0x00 | ((v) & 0x3f)) #define SET_BAND_PASS_CMD(v) (0x00 | ((v) & 0x3f))
/* magic replyed on SET_BAND_PASS_CMD in advanced mode */
#define SET_BAND_PASS_REP (0x01)
// 0b10xx.xxxx // 0b10xx.xxxx
#define SET_GAIN_CMD(v) (0x80 | ((v) & 0x3f)) #define SET_GAIN_CMD(v) (0x80 | ((v) & 0x3f))
/* magic replyed on SET_GAIN_CMD in advanced mode */
#define SET_GAIN_REP (0xe0)
// 0b110x.xxxx // 0b110x.xxxx
#define SET_INTEGRATOR_CMD(v) (0xC0 | ((v) & 0x1f)) #define SET_INTEGRATOR_CMD(v) (0xC0 | ((v) & 0x1f))
/* magic replyed on SET_INTEGRATOR_CMD in advanced mode */
#define SET_INTEGRATOR_REP (0x71)
// 0b0111.0001 // 0b0111.0001
#define SET_ADVANCED_MODE_CMD (0x71) #define SET_ADVANCED_MODE_CMD (0x71)
/* magic replyed on SET_ADVANCED_MODE_CMD in advanced mode */
#define SET_ADVANCED_MODE_REP ((~SET_ADVANCED_MODE_CMD) & 0xff)
// D[4:1] = 0000 : 4 MHz // D[4:1] = 0000 : 4 MHz
#define HIP_4MHZ_PRESCALER (0x0 << 1) #define HIP_4MHZ_PRESCALER (0x0 << 1)