682 lines
18 KiB
C++
682 lines
18 KiB
C++
/**
|
||
* @file HIP9011.cpp
|
||
* @brief HIP9011/TPIC8101 driver
|
||
*
|
||
* Jan 2017 status:
|
||
* 1) seems to be kind of working - reacts to parameter changes and does produce variable output
|
||
* 2) only one (first) channel is currently used
|
||
* 3) engine control does not yet react to knock since very little actual testing - no engine runs with proven knock yet
|
||
*
|
||
*
|
||
* http://rusefi.com/forum/viewtopic.php?f=4&t=400
|
||
* http://rusefi.com/forum/viewtopic.php?f=5&t=778
|
||
*
|
||
* pin1 VDD
|
||
* pin2 GND
|
||
*
|
||
* pin8 Chip Select - CS
|
||
* pin11 Slave Data Out - MISO
|
||
* pin12 Slave Data In - MOSI
|
||
* pin13 SPI clock - SCLK
|
||
*
|
||
*
|
||
* http://www.ti.com/lit/ds/symlink/tpic8101.pdf
|
||
* http://www.intersil.com/content/dam/Intersil/documents/hip9/hip9011.pdf
|
||
* http://www.intersil.com/content/dam/Intersil/documents/an97/an9770.pdf
|
||
* http://e2e.ti.com/cfs-file/__key/telligent-evolution-components-attachments/00-26-01-00-00-42-36-40/TPIC8101-Training.pdf
|
||
*
|
||
* max SPI frequency: 5MHz max
|
||
*
|
||
* @date Nov 27, 2013
|
||
* @author Andrey Belomutskiy, (c) 2012-2020
|
||
* @Spilly
|
||
*/
|
||
|
||
#include "pch.h"
|
||
|
||
#include "hardware.h"
|
||
#include "trigger_central.h"
|
||
#include "hip9011_logic.h"
|
||
#include "hip9011.h"
|
||
#include "knock_logic.h"
|
||
|
||
#if EFI_PROD_CODE
|
||
#include "mpu_util.h"
|
||
#endif
|
||
|
||
#if EFI_HIP_9011
|
||
|
||
/*==========================================================================*/
|
||
/* Local definitions. */
|
||
/*==========================================================================*/
|
||
|
||
/*==========================================================================*/
|
||
/* Local variables and types. */
|
||
/*==========================================================================*/
|
||
|
||
static NamedOutputPin intHold(PROTOCOL_HIP_NAME);
|
||
static NamedOutputPin Cs(PROTOCOL_HIP_NAME);
|
||
|
||
class Hip9011Hardware : public Hip9011HardwareInterface {
|
||
int sendSyncCommand(uint8_t command, uint8_t *rx_ptr) override;
|
||
|
||
public:
|
||
scheduling_s startTimer;
|
||
scheduling_s endTimer;
|
||
|
||
private:
|
||
int checkResponseDefMode(uint8_t tx, uint8_t rx);
|
||
int checkResponseAdvMode(uint8_t tx, uint8_t rx);
|
||
|
||
uint8_t rep_mask;
|
||
uint8_t rep_value;
|
||
};
|
||
|
||
/* TODO: include following stuff in object */
|
||
/* wake semaphore */
|
||
static semaphore_t wake;
|
||
|
||
static SPIDriver *spi;
|
||
|
||
static Hip9011Hardware hardware;
|
||
|
||
HIP9011 instance(&hardware);
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
static float normalizedValue[HIP_INPUT_CHANNELS];
|
||
static float normalizedValueMax[HIP_INPUT_CHANNELS];
|
||
#endif
|
||
|
||
// SPI_CR1_BR_1 // 5MHz
|
||
// SPI_CR1_CPHA Clock Phase
|
||
// todo: nicer method which would mention SPI speed explicitly?
|
||
|
||
#if EFI_PROD_CODE
|
||
static SPIConfig hipSpiCfg = {
|
||
.circular = false,
|
||
.end_cb = NULL,
|
||
.ssport = NULL,
|
||
.sspad = 0,
|
||
.cr1 =
|
||
SPI_CR1_8BIT_MODE |
|
||
SPI_CR1_MSTR |
|
||
SPI_CR1_CPHA |
|
||
//SPI_CR1_BR_1 // 5MHz
|
||
SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2,
|
||
.cr2 =
|
||
SPI_CR2_8BIT_MODE
|
||
};
|
||
#endif /* EFI_PROD_CODE */
|
||
|
||
/*==========================================================================*/
|
||
/* Forward declarations */
|
||
/*==========================================================================*/
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
static void hip_addconsoleActions();
|
||
#endif
|
||
|
||
/*==========================================================================*/
|
||
/* Local functions. */
|
||
/*==========================================================================*/
|
||
|
||
int Hip9011Hardware::checkResponseDefMode(uint8_t tx, uint8_t rx) {
|
||
/* in default SPI mode SDO is directly equals the SDI (echo function) */
|
||
if (tx == rx) {
|
||
return 0;
|
||
} else {
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
int Hip9011Hardware::checkResponseAdvMode(uint8_t tx, uint8_t rx) {
|
||
int ret = 0;
|
||
|
||
/* check reply */
|
||
if ((rx & rep_mask) != rep_value)
|
||
ret = -1;
|
||
|
||
/* extract mask and value for next reply */
|
||
if ((tx & 0xe0) == SET_PRESCALER_CMD(0)){
|
||
/* D7 to D0 of digital integrator output */
|
||
rep_mask = 0x00;
|
||
rep_value = 0x00;
|
||
} else if ((tx & 0xfe) == SET_CHANNEL_CMD(0)) {
|
||
/* D9 to D8 of digital integrator output and six zeroes */
|
||
rep_mask = 0x3f;
|
||
rep_value = 0x00;
|
||
} else if ((tx & 0xc0) == SET_BAND_PASS_CMD(0)) {
|
||
rep_mask = 0xff;
|
||
rep_value = SET_BAND_PASS_REP;
|
||
} else if ((tx & 0xc0) == SET_GAIN_CMD(0)) {
|
||
rep_mask = 0xff;
|
||
rep_value = SET_GAIN_REP;
|
||
} else if ((tx & 0xe0) == SET_INTEGRATOR_CMD(0)) {
|
||
rep_mask = 0xff;
|
||
rep_value = SET_INTEGRATOR_REP;
|
||
} else if ((tx & 0xff) == SET_ADVANCED_MODE_CMD) {
|
||
rep_mask = 0xff;
|
||
rep_value = SET_ADVANCED_MODE_REP;
|
||
} else {
|
||
/* unknown */
|
||
rep_mask = 0x00;
|
||
rep_value = 0x00;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
int Hip9011Hardware::sendSyncCommand(uint8_t tx, uint8_t *rx_ptr) {
|
||
int ret;
|
||
uint8_t rx;
|
||
|
||
/* Acquire ownership of the bus. */
|
||
spiAcquireBus(spi);
|
||
/* Setup transfer parameters. */
|
||
spiStart(spi, &hipSpiCfg);
|
||
/* Slave Select assertion. */
|
||
spiSelect(spi);
|
||
/* Transfer */
|
||
rx = spiPolledExchange(spi, tx);
|
||
/* Slave Select de-assertion. */
|
||
spiUnselect(spi);
|
||
/* Ownership release. */
|
||
spiReleaseBus(spi);
|
||
/* received data */
|
||
if (rx_ptr)
|
||
*rx_ptr = rx;
|
||
/* check response */
|
||
if (instance.adv_mode)
|
||
ret = checkResponseAdvMode(tx, rx);
|
||
else
|
||
ret = checkResponseDefMode(tx, rx);
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
/* statistic counters */
|
||
if (ret)
|
||
instance.invalidResponsesCount++;
|
||
else
|
||
instance.correctResponsesCount++;
|
||
#endif
|
||
|
||
return ret;
|
||
}
|
||
|
||
static int hip_wake_driver()
|
||
{
|
||
/* Entering a reentrant critical zone.*/
|
||
syssts_t sts = chSysGetStatusAndLockX();
|
||
chSemSignalI(&wake);
|
||
if (!port_is_isr_context()) {
|
||
/**
|
||
* chSemSignalI above requires rescheduling
|
||
* interrupt handlers have implicit rescheduling
|
||
*/
|
||
chSchRescheduleS();
|
||
}
|
||
/* Leaving the critical zone.*/
|
||
chSysRestoreStatusX(sts);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void startIntegration(HIP9011 *hip) {
|
||
if (hip->state == READY_TO_INTEGRATE) {
|
||
/**
|
||
* SPI communication is only allowed while not integrating, so we postpone the exchange
|
||
* until we are done integrating
|
||
*/
|
||
hip->state = IS_INTEGRATING;
|
||
intHold.setHigh();
|
||
} else {
|
||
#if EFI_HIP_9011_DEBUG
|
||
hip->overrun++;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
static void endIntegration(HIP9011 *hip) {
|
||
/**
|
||
* isIntegrating could be 'false' if an SPI command was pending thus we did not integrate during this
|
||
* engine cycle
|
||
*/
|
||
if (hip->state == IS_INTEGRATING) {
|
||
intHold.setLow();
|
||
|
||
hip->knockSampleTimestamp = getTimeNowNt();
|
||
|
||
if (instance.adv_mode) {
|
||
/* read value over SPI in thread mode */
|
||
hip->state = NOT_READY;
|
||
hip_wake_driver();
|
||
} else {
|
||
/* wait for ADC samples */
|
||
hip->state = WAITING_FOR_ADC_TO_SKIP;
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
*/
|
||
void hip9011_onFireEvent(uint8_t cylinderNumber, efitick_t nowNt) {
|
||
if (!engineConfiguration->isHip9011Enabled)
|
||
return;
|
||
|
||
/* We are not checking here for READY_TO_INTEGRATE state as
|
||
* previous integration may be stil in progress, while
|
||
* we are scheduling next integration start only
|
||
* knockDetectionWindowStart from now.
|
||
* Check for correct state will be done at startIntegration () */
|
||
|
||
if (cylinderNumber == instance.expectedCylinderNumber) {
|
||
/* save currect cylinder */
|
||
instance.cylinderNumber = cylinderNumber;
|
||
|
||
/* smart books says we need to sence knock few degrees after TDC
|
||
* currently I have no idea how to hook to cylinder TDC in correct way.
|
||
* So schedule start of integration + knockDetectionWindowStart from fire event
|
||
* Keep this is mind when setting knockDetectionWindowStart */
|
||
scheduleByAngle(&hardware.startTimer, nowNt,
|
||
engineConfiguration->knockDetectionWindowStart,
|
||
{ startIntegration, &instance });
|
||
|
||
scheduleByAngle(&hardware.endTimer, nowNt,
|
||
engineConfiguration->knockDetectionWindowEnd,
|
||
{ endIntegration, &instance });
|
||
} else {
|
||
#if EFI_HIP_9011_DEBUG
|
||
/* out of sync */
|
||
if (instance.expectedCylinderNumber >= 0)
|
||
instance.unsync++;
|
||
#endif
|
||
/* 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) {
|
||
/* we read in digital mode */
|
||
if (instance.adv_mode)
|
||
return;
|
||
if (instance.state == WAITING_FOR_ADC_TO_SKIP) {
|
||
instance.state = WAITING_FOR_RESULT_ADC;
|
||
} else if (instance.state == WAITING_FOR_RESULT_ADC) {
|
||
/* offload calculations to driver thread */
|
||
if (instance.channelIdx < HIP_INPUT_CHANNELS) {
|
||
instance.rawValue[instance.channelIdx] = adcValue;
|
||
}
|
||
instance.state = NOT_READY;
|
||
hip_wake_driver();
|
||
}
|
||
}
|
||
|
||
static int hip_testAdvMode() {
|
||
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() {
|
||
int ret;
|
||
|
||
ret = instance.hw->sendSyncCommand(SET_PRESCALER_CMD(instance.prescaler), NULL);
|
||
if (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 */
|
||
if (!engineConfiguration->useTpicAdvancedMode)
|
||
return ret;
|
||
}
|
||
|
||
/* ...othervice or when no error is reported lets try to switch to advanced mode */
|
||
if (engineConfiguration->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;
|
||
}
|
||
}
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
/* reset error counter now */
|
||
instance.invalidResponsesCount = 0;
|
||
#endif
|
||
|
||
instance.state = READY_TO_INTEGRATE;
|
||
|
||
return 0;
|
||
}
|
||
|
||
static THD_WORKING_AREA(hipThreadStack, UTILITY_THREAD_STACK_SIZE);
|
||
|
||
static msg_t hipThread(void *arg) {
|
||
int ret;
|
||
UNUSED(arg);
|
||
chRegSetThreadName("hip9011 worker");
|
||
|
||
/* This strange code was here before me.
|
||
* Not sure why we need it */
|
||
#if 0
|
||
/* Acquire ownership of the bus. */
|
||
spiAcquireBus(spi);
|
||
// some time to let the hardware start
|
||
Cs.setValue(true);
|
||
chThdSleepMilliseconds(100);
|
||
Cs.setValue(false);
|
||
chThdSleepMilliseconds(100);
|
||
Cs.setValue(true);
|
||
/* Ownership release. */
|
||
spiReleaseBus(spi);
|
||
|
||
chThdSleepMilliseconds(100);
|
||
#endif
|
||
|
||
do {
|
||
/* retry until success */
|
||
ret = hip_init();
|
||
if (ret) {
|
||
warning(CUSTOM_OBD_KNOCK_PROCESSOR, "TPIC/HIP does not respond: %d", ret);
|
||
chThdSleepMilliseconds(10 * 1000);
|
||
}
|
||
} while (ret);
|
||
|
||
while (1) {
|
||
msg_t msg;
|
||
|
||
/* load new/updated settings */
|
||
instance.handleSettings(Sensor::getOrZero(SensorType::Rpm) DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
|
||
/* in advanced more driver will set channel while reading integrator value */
|
||
if (!instance.adv_mode) {
|
||
/* switch input channel */
|
||
instance.handleChannel(DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
|
||
}
|
||
/* State */
|
||
instance.state = READY_TO_INTEGRATE;
|
||
|
||
msg = chSemWaitTimeout(&wake, TIME_INFINITE);
|
||
if (msg == MSG_TIMEOUT) {
|
||
/* ??? */
|
||
} else {
|
||
int rawValue;
|
||
/* check now, before readValueAndHandleChannel did not overwrite expectedCylinderNumber */
|
||
bool correctCylinder = (instance.cylinderNumber == instance.expectedCylinderNumber);
|
||
|
||
/* this needs to be called in any case to set proper channel for next cycle */
|
||
if (instance.adv_mode) {
|
||
rawValue = instance.readValueAndHandleChannel(DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
|
||
|
||
/* spi communication issue? */
|
||
if (rawValue < 0)
|
||
continue;
|
||
}
|
||
|
||
/* check that we know channel for current measurement */
|
||
int idx = instance.channelIdx;
|
||
if (!(idx < HIP_INPUT_CHANNELS))
|
||
continue;
|
||
|
||
float knockNormalized = 0.0f;
|
||
float knockVolts = 0.0f;
|
||
|
||
/* calculations */
|
||
if (instance.adv_mode) {
|
||
/* store for debug */
|
||
instance.rawValue[idx] = rawValue;
|
||
/* convert 10 bit integer value to 0.0 .. 1.0 float */
|
||
knockNormalized = ((float)rawValue) / HIP9011_DIGITAL_OUTPUT_MAX;
|
||
/* convert to magic volts */
|
||
knockVolts = knockNormalized * HIP9011_DESIRED_OUTPUT_VALUE;
|
||
} else {
|
||
rawValue = instance.rawValue[idx];
|
||
/* first calculate ouput volts */
|
||
knockVolts = adcToVolts(rawValue) * engineConfiguration->analogInputDividerCoefficient;
|
||
/* and then normalize */
|
||
knockNormalized = knockVolts / HIP9011_DESIRED_OUTPUT_VALUE;
|
||
}
|
||
|
||
/* Check for correct cylinder/input */
|
||
if (correctCylinder) {
|
||
// TODO: convert knock level to dBv
|
||
engine->module<KnockController>()->onKnockSenseCompleted(instance.cylinderNumber, knockVolts, instance.knockSampleTimestamp);
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
/* debug */
|
||
normalizedValue[idx] = knockNormalized;
|
||
normalizedValueMax[idx] = maxF(knockNormalized, normalizedValueMax[idx]);
|
||
/* counters */
|
||
instance.samples++;
|
||
#endif
|
||
} else {
|
||
/* out of sync event already calculated, nothing to do */
|
||
}
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/*==========================================================================*/
|
||
/* Exported functions. */
|
||
/*==========================================================================*/
|
||
|
||
void stopHip9001_pins() {
|
||
intHold.deInit();
|
||
Cs.deInit();
|
||
#if EFI_PROD_CODE
|
||
hipSpiCfg.ssport = NULL;
|
||
#endif
|
||
}
|
||
|
||
void startHip9001_pins() {
|
||
intHold.initPin("hip int/hold", engineConfiguration->hip9011IntHoldPin, &engineConfiguration->hip9011IntHoldPinMode);
|
||
Cs.initPin("hip CS", engineConfiguration->hip9011CsPin, &engineConfiguration->hip9011CsPinMode);
|
||
}
|
||
|
||
void initHip9011() {
|
||
if (!engineConfiguration->isHip9011Enabled)
|
||
return;
|
||
|
||
#if EFI_PROD_CODE
|
||
spi = getSpiDevice(engineConfiguration->hip9011SpiDevice);
|
||
if (spi == NULL) {
|
||
// error already reported
|
||
return;
|
||
}
|
||
|
||
hipSpiCfg.ssport = getHwPort("hip", engineConfiguration->hip9011CsPin);
|
||
hipSpiCfg.sspad = getHwPin("hip", engineConfiguration->hip9011CsPin);
|
||
#endif /* EFI_PROD_CODE */
|
||
|
||
startHip9001_pins();
|
||
|
||
/* load settings */
|
||
instance.prescaler = engineConfiguration->hip9011PrescalerAndSDO;
|
||
|
||
efiPrintf("Starting HIP9011/TPIC8101 driver");
|
||
|
||
/* init semaphore */
|
||
chSemObjectInit(&wake, 10);
|
||
chThdCreateStatic(hipThreadStack, sizeof(hipThreadStack), PRIO_HIP9011, (tfunc_t)(void*) hipThread, NULL);
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
hip_addconsoleActions();
|
||
#endif
|
||
}
|
||
|
||
/*==========================================================================*/
|
||
/* Debug functions. */
|
||
/*==========================================================================*/
|
||
|
||
#if EFI_HIP_9011_DEBUG
|
||
|
||
static const char *hip_state_names[] =
|
||
{
|
||
"Not ready/calculating",
|
||
"Ready for integration",
|
||
"Integrating",
|
||
"Waiting for first ADC sample",
|
||
"Waiting for second ADC sample"
|
||
};
|
||
|
||
static void showHipInfo() {
|
||
if (!engineConfiguration->isHip9011Enabled) {
|
||
efiPrintf("hip9011 driver not active");
|
||
return;
|
||
}
|
||
|
||
efiPrintf("HIP9011: enabled %s state %s",
|
||
boolToString(engineConfiguration->isHip9011Enabled),
|
||
hip_state_names[instance.state]);
|
||
|
||
efiPrintf(" Advanced mode: enabled %d used %d",
|
||
engineConfiguration->useTpicAdvancedMode,
|
||
instance.adv_mode);
|
||
|
||
efiPrintf(" Input Ch %d (cylinder %d next %d)",
|
||
instance.channelIdx,
|
||
instance.cylinderNumber,
|
||
instance.expectedCylinderNumber);
|
||
|
||
efiPrintf(" Cyl bore %.2fmm freq %.2fkHz band idx 0x%x",
|
||
engineConfiguration->cylinderBore,
|
||
instance.getBand(PASS_HIP_PARAMS),
|
||
instance.bandIdx);
|
||
|
||
efiPrintf(" Integrator idx 0x%x",
|
||
instance.intergratorIdx);
|
||
|
||
efiPrintf(" Gain %.2f idx 0x%x",
|
||
engineConfiguration->hip9011Gain,
|
||
instance.gainIdx);
|
||
|
||
efiPrintf(" PaSDO=0x%x",
|
||
instance.prescaler);
|
||
|
||
efiPrintf(" IntHold %s (mode 0x%x)",
|
||
hwPortname(engineConfiguration->hip9011IntHoldPin),
|
||
engineConfiguration->hip9011IntHoldPinMode);
|
||
|
||
efiPrintf(" Spi %s CS %s (mode 0x%x)",
|
||
getSpi_device_e(engineConfiguration->hip9011SpiDevice),
|
||
hwPortname(engineConfiguration->hip9011CsPin),
|
||
engineConfiguration->hip9011CsPinMode);
|
||
|
||
#if EFI_PROD_CODE
|
||
printSpiConfig("hip9011", engineConfiguration->hip9011SpiDevice);
|
||
#endif /* EFI_PROD_CODE */
|
||
|
||
efiPrintf(" SPI: good response %d incorrect response %d",
|
||
instance.correctResponsesCount,
|
||
instance.invalidResponsesCount);
|
||
|
||
efiPrintf(" Counters: samples %d overruns %d sync miss %d",
|
||
instance.samples, instance.overrun, instance.unsync);
|
||
|
||
efiPrintf(" Window start %.2f end %.2f",
|
||
engineConfiguration->knockDetectionWindowStart,
|
||
engineConfiguration->knockDetectionWindowEnd);
|
||
|
||
if (!instance.adv_mode) {
|
||
efiPrintf(" Adc input %s (%.2f V)",
|
||
getAdc_channel_e(engineConfiguration->hipOutputChannel),
|
||
getVoltage("hipinfo", engineConfiguration->hipOutputChannel));
|
||
}
|
||
|
||
for (int i = 0; i < HIP_INPUT_CHANNELS; i++) {
|
||
efiPrintf(" input[%d] %d -> %.3f (max %.3f)",
|
||
i,
|
||
instance.rawValue[i],
|
||
normalizedValue[i],
|
||
normalizedValueMax[i]);
|
||
normalizedValueMax[i] = 0.0;
|
||
}
|
||
}
|
||
|
||
static void setPrescalerAndSDO(int value) {
|
||
engineConfiguration->hip9011PrescalerAndSDO = value;
|
||
}
|
||
|
||
static void setHipBand(float value) {
|
||
engineConfiguration->knockBandCustom = value;
|
||
showHipInfo();
|
||
}
|
||
|
||
static void setHipGain(float value) {
|
||
engineConfiguration->hip9011Gain = value;
|
||
showHipInfo();
|
||
}
|
||
|
||
static void hip_addconsoleActions() {
|
||
addConsoleAction("hipinfo", showHipInfo);
|
||
addConsoleActionF("set_gain", setHipGain);
|
||
addConsoleActionF("set_band", setHipBand);
|
||
addConsoleActionI("set_hip_prescalerandsdo", setPrescalerAndSDO);
|
||
}
|
||
|
||
#endif /* EFI_HIP_9011_DEBUG */
|
||
|
||
#endif /* EFI_HIP_9011 */
|