diff --git a/firmware/hw_layer/sensors/hip9011.cpp b/firmware/hw_layer/sensors/hip9011.cpp index 1061e387bc..5f9958fbf9 100644 --- a/firmware/hw_layer/sensors/hip9011.cpp +++ b/firmware/hw_layer/sensors/hip9011.cpp @@ -67,6 +67,13 @@ static NamedOutputPin Cs(PROTOCOL_HIP_NAME); class Hip9011Hardware : public Hip9011HardwareInterface { int sendSyncCommand(uint8_t command, uint8_t *rx_ptr) override; + +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 */ @@ -77,7 +84,8 @@ static SPIDriver *spi; static Hip9011Hardware hardware; -static float hipValueMax = 0; +static float normalizedValue[HIP_INPUT_CHANNELS]; +static float normalizedValueMax[HIP_INPUT_CHANNELS]; HIP9011 instance(&hardware); @@ -114,7 +122,7 @@ static void hip_addconsoleActions(void); /* Local functions. */ /*==========================================================================*/ -static int checkResponseDefMode(uint8_t tx, uint8_t rx) { +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; @@ -123,10 +131,41 @@ static int checkResponseDefMode(uint8_t tx, uint8_t rx) { } } -static int checkResponseAdvMode(uint8_t tx, uint8_t rx) { - UNUSED(tx); UNUSED(rx); - /* TODO: no check for advanced mode yet */ - return 0; +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) { @@ -149,10 +188,10 @@ int Hip9011Hardware::sendSyncCommand(uint8_t tx, uint8_t *rx_ptr) { if (rx_ptr) *rx_ptr = rx; /* check response */ - if (instance.adv_mode == false) - ret = checkResponseDefMode(tx, rx); - else + if (instance.adv_mode) ret = checkResponseAdvMode(tx, rx); + else + ret = checkResponseDefMode(tx, rx); /* statistic counters */ if (ret) @@ -201,7 +240,14 @@ static void endIntegration(void *) { */ if (instance.state == IS_INTEGRATING) { intHold.setLow(); - instance.state = WAITING_FOR_ADC_TO_SKIP; + if (instance.adv_mode) { + /* read value over SPI in thread mode */ + instance.state = NOT_READY; + hip_wake_driver(); + } else { + /* wait for ADC samples */ + instance.state = WAITING_FOR_ADC_TO_SKIP; + } } } @@ -240,11 +286,16 @@ void hip9011_startKnockSampling(uint8_t cylinderNumber, efitick_t nowNt) { } 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 */ - instance.raw_value = adcValue; + if (instance.channelIdx < HIP_INPUT_CHANNELS) { + instance.rawValue[instance.channelIdx] = adcValue; + } instance.state = NOT_READY; hip_wake_driver(); } @@ -368,8 +419,11 @@ static msg_t hipThread(void *arg) { /* load new/updated settings */ instance.handleSettings(GET_RPM() DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS)); - /* switch input channel */ - instance.handleChannel(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; @@ -377,11 +431,50 @@ static msg_t hipThread(void *arg) { 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) * CONFIG(analogInputDividerCoefficient); + /* and then normalize */ + knockNormalized = knockVolts / HIP9011_DESIRED_OUTPUT_VALUE; + } + /* Check for correct cylinder/input */ - if (instance.cylinderNumber == instance.expectedCylinderNumber) { - /* calculations */ - float knockVolts = instance.raw_value * adcToVolts(1) * CONFIG(analogInputDividerCoefficient); - hipValueMax = maxF(knockVolts, hipValueMax); + if (correctCylinder) { + /* debug */ + normalizedValue[idx] = knockNormalized; + normalizedValueMax[idx] = maxF(knockNormalized, normalizedValueMax[idx]); + + /* report */ engine->knockLogic(knockVolts); /* TunerStudio */ @@ -486,10 +579,6 @@ static void showHipInfo(void) { engine->knockCount, engineConfiguration->maxKnockSubDeg); - efiPrintf(" Adc input %s (%.2f V)", - getAdc_channel_e(engineConfiguration->hipOutputChannel), - getVoltage("hipinfo", engineConfiguration->hipOutputChannel)); - efiPrintf(" IntHold %s (mode 0x%x)", hwPortname(CONFIG(hip9011IntHoldPin)), CONFIG(hip9011IntHoldPinMode)); @@ -503,22 +592,32 @@ static void showHipInfo(void) { printSpiConfig("hip9011", CONFIG(hip9011SpiDevice)); #endif /* EFI_PROD_CODE */ - efiPrintf(" SPI good response %d incorrect response %d", + efiPrintf(" SPI: good response %d incorrect response %d", instance.correctResponsesCount, instance.invalidResponsesCount); - efiPrintf(" hip %.2f vmax=%.2f", - engine->knockVolts, - hipValueMax); + 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); - efiPrintf(" Counters: samples %d overruns %d sync miss %d", - instance.samples, instance.overrun, instance.unsync); + 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; + } - hipValueMax = 0; engine->printKnockState(); } diff --git a/firmware/hw_layer/sensors/hip9011_logic.cpp b/firmware/hw_layer/sensors/hip9011_logic.cpp index 6555c9d4c9..a3ba405139 100644 --- a/firmware/hw_layer/sensors/hip9011_logic.cpp +++ b/firmware/hw_layer/sensors/hip9011_logic.cpp @@ -17,8 +17,6 @@ /* Local definitions. */ /*==========================================================================*/ -#define DESIRED_OUTPUT_VALUE 5.0f - /*==========================================================================*/ /* Local variables and types. */ /*==========================================================================*/ @@ -73,6 +71,10 @@ int HIP9011::sendCommand(uint8_t cmd) { return hw->sendSyncCommand(cmd, NULL); } +int HIP9011::sendCommandGetReply(uint8_t cmd, uint8_t *reply) { + return hw->sendSyncCommand(cmd, reply); +} + /** * @return frequency band we are interested in */ @@ -112,7 +114,7 @@ float HIP9011::getRpmByAngleWindowAndTimeUs(int timeUs, float angleWindowWidth) /** * TINT = TC * 2 * PI * VOUT */ - float integrationTimeUs = timeUs * 2 * PIF * DESIRED_OUTPUT_VALUE; + float integrationTimeUs = timeUs * 2 * PIF * HIP9011_DESIRED_OUTPUT_VALUE; /** * rpm = 60 seconds / time * '60000000' because revolutions per MINUTE in uS conversion @@ -193,12 +195,12 @@ int HIP9011::cylinderToChannelIdx(int cylinder) { return getCylinderKnockBank(cylinder); } -void HIP9011::handleChannel(DEFINE_HIP_PARAMS) { +int HIP9011::handleChannel(DEFINE_HIP_PARAMS) { int ret; /* we did not receive any callback from spark logic with valid cylinder yet */ if (cylinderNumber < 0) - return; + return -1; /* find next firing cylinder */ /* MAGIC +1 -1, couse getNextFiringCylinderId expect cylinders to start from 1 */ @@ -206,9 +208,53 @@ void HIP9011::handleChannel(DEFINE_HIP_PARAMS) { int nextChannelIdx = cylinderToChannelIdx(expectedCylinderNumber); if (nextChannelIdx == channelIdx) - return; + return 0; ret = sendCommand(SET_CHANNEL_CMD(nextChannelIdx)); - if (ret == 0) - channelIdx = nextChannelIdx; + if (ret) + return ret; + + channelIdx = nextChannelIdx; + + return 0; +} + +int HIP9011::readValueAndHandleChannel(DEFINE_HIP_PARAMS) { + int ret; + uint8_t rx[2]; + + /* we did not receive any callback from spark logic with valid cylinder yet */ + if (cylinderNumber < 0) + return -1; + + /* 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); + + /* use cached values, let handleSettings take care of settings update */ + /* don't care about rx'ed data now */ + ret = sendCommand(SET_PRESCALER_CMD(prescaler)); + if (ret) + return ret; + + /* reply from Set Prescaler CMD -> D7 to D0 of the digital integrator output */ + ret = sendCommandGetReply(SET_CHANNEL_CMD(nextChannelIdx), &rx[0]); + if (ret) + return ret; + + /* Same connand to get reply for previous command: + * reply from Select the channel CMD -> D9 to D8 of difital integrator output and six zeroes */ + ret = sendCommandGetReply(SET_CHANNEL_CMD(nextChannelIdx), &rx[1]); + if (ret) + return ret; + + channelIdx = nextChannelIdx; + + /* D9..D8 in high bits */ + rx[1] = (rx[1] >> 6) & 0x03; + + /* return digital integrator value */ + return (rx[0] | (rx[1] << 8)); } diff --git a/firmware/hw_layer/sensors/hip9011_logic.h b/firmware/hw_layer/sensors/hip9011_logic.h index 2b47c2f585..d139264355 100644 --- a/firmware/hw_layer/sensors/hip9011_logic.h +++ b/firmware/hw_layer/sensors/hip9011_logic.h @@ -11,7 +11,10 @@ #include "rusefi_enums.h" #define PIF 3.14159f -#define HIP9011_BAND(bore) (900 / (PIF * (bore) / 2)) +#define HIP9011_BAND(bore) (900 / (PIF * (bore) / 2)) +#define HIP9011_DESIRED_OUTPUT_VALUE 5.0f +#define HIP9011_DIGITAL_OUTPUT_MAX 0x03ff /* 10 bit max value */ +#define HIP_INPUT_CHANNELS 2 #define INT_LOOKUP_SIZE 32 #define GAIN_LOOKUP_SIZE 64 @@ -65,13 +68,15 @@ public: explicit HIP9011(Hip9011HardwareInterface *hardware); int sendCommand(uint8_t cmd); + int sendCommandGetReply(uint8_t cmd, uint8_t *reply); float getRpmByAngleWindowAndTimeUs(int timeUs, float angleWindowWidth); void prepareRpmLookup(void); void setAngleWindowWidth(DEFINE_HIP_PARAMS); void handleSettings(int rpm DEFINE_PARAM_SUFFIX(DEFINE_HIP_PARAMS)); int cylinderToChannelIdx(int cylinder); - void handleChannel(DEFINE_HIP_PARAMS); + int handleChannel(DEFINE_HIP_PARAMS); + int readValueAndHandleChannel(DEFINE_HIP_PARAMS); float getBand(DEFINE_HIP_PARAMS); int getIntegrationIndexByRpm(float rpm); int getBandIndex(DEFINE_HIP_PARAMS); @@ -104,7 +109,7 @@ public: hip_state_e state; int8_t cylinderNumber = -1; int8_t expectedCylinderNumber = -1; - int raw_value; + int rawValue[HIP_INPUT_CHANNELS]; /* counters */ int samples = 0;