rusefi-1/firmware/hw_layer/hip9011.cpp

449 lines
12 KiB
C++
Raw Normal View History

2015-07-10 06:01:56 -07:00
/**
* @file HIP9011.cpp
* @brief HIP9011/TPIC8101 driver
*
2017-01-27 09:03:05 -08:00
* 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
*
*
2017-01-27 18:04:23 -08:00
* http://rusefi.com/forum/viewtopic.php?f=4&t=400
* http://rusefi.com/forum/viewtopic.php?f=5&t=778
*
2015-07-10 06:01:56 -07:00
* pin1 VDD
* pin2 GND
*
* pin8 Chip Select - CS
2017-01-27 09:03:05 -08:00
* pin11 Slave Data Out - MISO
2015-07-10 06:01:56 -07:00
* 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
2020-01-13 18:57:43 -08:00
* @author Andrey Belomutskiy, (c) 2012-2020
2015-07-10 06:01:56 -07:00
* @Spilly
*/
2018-09-16 19:26:57 -07:00
#include "global.h"
2015-07-10 06:01:56 -07:00
#include "engine.h"
#include "settings.h"
#include "hardware.h"
#include "rpm_calculator.h"
#include "trigger_central.h"
#include "hip9011_logic.h"
2015-07-10 06:01:56 -07:00
#include "hip9011_lookup.h"
#include "hip9011.h"
2015-07-10 06:01:56 -07:00
#include "adc_inputs.h"
2015-07-10 06:01:56 -07:00
#include "engine_controller.h"
2018-11-03 10:27:48 -07:00
#if EFI_PROD_CODE
#include "pin_repository.h"
#include "mpu_util.h"
2018-11-03 10:27:48 -07:00
#endif
2019-04-12 17:52:51 -07:00
#if EFI_HIP_9011
2015-07-10 06:01:56 -07:00
static NamedOutputPin intHold(PROTOCOL_HIP_NAME);
2015-07-10 06:01:56 -07:00
extern uint32_t lastExecutionCount;
2016-11-03 20:02:58 -07:00
extern EnginePins enginePins;
2015-07-10 06:01:56 -07:00
uint32_t hipLastExecutionCount;
2019-01-07 20:23:50 -08:00
class Hip9011Hardware : public Hip9011HardwareInterface {
void sendSyncCommand(unsigned char command) override;
void sendCommand(unsigned char command) override;
};
static Hip9011Hardware hardware;
2015-07-10 06:01:56 -07:00
static float hipValueMax = 0;
HIP9011 instance(&hardware);
2019-01-03 21:22:35 -08:00
2015-07-10 06:01:56 -07:00
static unsigned char tx_buff[1];
static unsigned char rx_buff[1];
static char pinNameBuffer[16];
static scheduling_s startTimer[2];
static scheduling_s endTimer[2];
static Logging *logger;
// SPI_CR1_BR_1 // 5MHz
// SPI_CR1_CPHA Clock Phase
// todo: nicer method which would mention SPI speed explicitly?
2018-11-03 06:44:34 -07:00
#if EFI_PROD_CODE
static SPIConfig hipSpiCfg = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 =
SPI_CR1_MSTR |
SPI_CR1_CPHA |
//SPI_CR1_BR_1 // 5MHz
SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2 |
SPI_CR1_8BIT_MODE,
.cr2 =
SPI_CR2_8BIT_MODE
};
2019-01-03 19:53:34 -08:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
2015-07-10 15:02:29 -07:00
static void checkResponse(void) {
if (tx_buff[0] == rx_buff[0]) {
instance.correctResponsesCount++;
2015-07-10 15:02:29 -07:00
} else {
instance.invalidHip9011ResponsesCount++;
2015-07-10 15:02:29 -07:00
}
}
// this macro is only used on startup
2015-07-10 06:01:56 -07:00
#define SPI_SYNCHRONOUS(value) \
spiSelect(driver); \
tx_buff[0] = value; \
spiExchange(driver, 1, tx_buff, rx_buff); \
spiUnselect(driver); \
2015-07-10 15:02:29 -07:00
checkResponse();
2015-07-10 06:01:56 -07:00
2015-07-10 20:01:24 -07:00
static SPIDriver *driver;
2015-07-10 06:01:56 -07:00
void Hip9011Hardware::sendSyncCommand(unsigned char command) {
SPI_SYNCHRONOUS(command);
chThdSleepMilliseconds(10);
}
void Hip9011Hardware::sendCommand(unsigned char command) {
tx_buff[0] = command;
spiSelectI(driver);
spiStartExchangeI(driver, 1, tx_buff, rx_buff);
}
2015-07-10 06:01:56 -07:00
EXTERN_ENGINE
;
2017-01-28 16:03:06 -08:00
static char hipPinNameBuffer[16];
2015-07-10 06:01:56 -07:00
static void showHipInfo(void) {
if (!CONFIG(isHip9011Enabled)) {
2015-07-10 06:01:56 -07:00
scheduleMsg(logger, "hip9011 driver not active");
return;
}
printSpiState(logger, engineConfiguration);
2018-05-30 21:36:46 -07:00
scheduleMsg(logger, "enabled=%s state=%s bore=%.2fmm freq=%.2fkHz PaSDO=%d",
boolToString(CONFIG(isHip9011Enabled)),
2019-01-03 21:22:35 -08:00
getHip_state_e(instance.state),
2019-01-03 21:51:32 -08:00
engineConfiguration->cylinderBore, getHIP9011Band(PASS_HIP_PARAMS),
2015-07-10 06:01:56 -07:00
engineConfiguration->hip9011PrescalerAndSDO);
2017-01-28 16:03:06 -08:00
char *outputName = getPinNameByAdcChannel("hip", engineConfiguration->hipOutputChannel, hipPinNameBuffer);
2019-01-07 20:23:50 -08:00
scheduleMsg(logger, "band_index=%d gain %.2f/index=%d output=%s", instance.currentBandIndex, engineConfiguration->hip9011Gain, instance.currentGainIndex,
2017-01-28 16:03:06 -08:00
outputName);
2018-01-23 09:05:14 -08:00
scheduleMsg(logger, "integrator index=%d knockVThreshold=%.2f knockCount=%d maxKnockSubDeg=%.2f",
2019-01-07 20:23:50 -08:00
instance.currentIntergratorIndex, engineConfiguration->knockVThreshold,
2015-07-10 06:01:56 -07:00
engine->knockCount, engineConfiguration->maxKnockSubDeg);
const char * msg = instance.invalidHip9011ResponsesCount > 0 ? "NOT GOOD" : "ok";
2017-01-28 16:03:06 -08:00
scheduleMsg(logger, "spi=%s IntHold@%s/%d response count=%d incorrect response=%d %s",
2017-05-09 15:55:25 -07:00
getSpi_device_e(engineConfiguration->hip9011SpiDevice),
hwPortname(CONFIG(hip9011IntHoldPin)),
CONFIG(hip9011IntHoldPinMode),
instance.correctResponsesCount, instance.invalidHip9011ResponsesCount,
2017-01-27 08:03:45 -08:00
msg);
scheduleMsg(logger, "CS@%s updateCount=%d", hwPortname(CONFIG(hip9011CsPin)), instance.settingUpdateCount);
2015-07-10 06:01:56 -07:00
2018-11-03 06:44:34 -07:00
#if EFI_PROD_CODE
2018-01-23 09:05:14 -08:00
scheduleMsg(logger, "hip %.2fv/last=%.2f@%s/max=%.2f adv=%d",
2015-07-11 13:01:31 -07:00
engine->knockVolts,
2015-07-10 06:01:56 -07:00
getVoltage("hipinfo", engineConfiguration->hipOutputChannel),
2016-12-27 11:04:04 -08:00
getPinNameByAdcChannel("hip", engineConfiguration->hipOutputChannel, pinNameBuffer),
2015-07-10 06:01:56 -07:00
hipValueMax,
CONFIG(useTpicAdvancedMode));
2017-05-09 15:55:25 -07:00
scheduleMsg(logger, "mosi=%s", hwPortname(getMosiPin(engineConfiguration->hip9011SpiDevice)));
scheduleMsg(logger, "miso=%s", hwPortname(getMisoPin(engineConfiguration->hip9011SpiDevice)));
scheduleMsg(logger, "sck=%s", hwPortname(getSckPin(engineConfiguration->hip9011SpiDevice)));
2019-01-03 19:53:34 -08:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
2018-01-23 09:05:14 -08:00
scheduleMsg(logger, "start %.2f end %.2f", engineConfiguration->knockDetectionWindowStart,
2015-07-10 06:01:56 -07:00
engineConfiguration->knockDetectionWindowEnd);
hipValueMax = 0;
engine->printKnockState();
}
void setHip9011FrankensoPinout(void) {
/**
* SPI on PB13/14/15
*/
// CONFIG(hip9011CsPin) = GPIOD_0; // rev 0.1
2015-07-13 18:01:37 -07:00
CONFIG(isHip9011Enabled) = true;
2019-01-07 22:20:18 -08:00
engineConfiguration->hip9011PrescalerAndSDO = _8MHZ_PRESCALER; // 8MHz chip
CONFIG(is_enabled_spi_2) = true;
2018-11-03 06:44:34 -07:00
// todo: convert this to rusEfi, hardware-independent enum
#if EFI_PROD_CODE
2019-08-06 21:36:54 -07:00
#ifdef EFI_HIP_CS_PIN
CONFIG(hip9011CsPin) = EFI_HIP_CS_PIN;
2019-08-06 21:36:54 -07:00
#else
CONFIG(hip9011CsPin) = GPIOB_0; // rev 0.4
2019-08-06 21:36:54 -07:00
#endif
CONFIG(hip9011CsPinMode) = OM_OPENDRAIN;
2018-11-03 06:44:34 -07:00
CONFIG(hip9011IntHoldPin) = GPIOB_11;
CONFIG(hip9011IntHoldPinMode) = OM_OPENDRAIN;
2018-11-03 06:44:34 -07:00
engineConfiguration->spi2SckMode = PO_OPENDRAIN; // 4
engineConfiguration->spi2MosiMode = PO_OPENDRAIN; // 4
engineConfiguration->spi2MisoMode = PO_PULLUP; // 32
2018-11-03 06:44:34 -07:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
2019-01-04 14:18:43 -08:00
engineConfiguration->hip9011Gain = 1;
2015-07-10 06:01:56 -07:00
engineConfiguration->knockVThreshold = 4;
engineConfiguration->maxKnockSubDeg = 20;
if (!CONFIG(useTpicAdvancedMode)) {
2015-07-10 06:01:56 -07:00
engineConfiguration->hipOutputChannel = EFI_ADC_10; // PC0
}
}
static void startIntegration(void *) {
2019-01-03 21:22:35 -08:00
if (instance.state == READY_TO_INTEGRATE) {
2015-07-10 06:01:56 -07:00
/**
* SPI communication is only allowed while not integrating, so we postpone the exchange
* until we are done integrating
*/
2019-01-03 21:22:35 -08:00
instance.state = IS_INTEGRATING;
2017-04-21 16:23:20 -07:00
intHold.setHigh();
2015-07-10 06:01:56 -07:00
}
}
static void endIntegration(void *) {
2015-07-10 06:01:56 -07:00
/**
* isIntegrating could be 'false' if an SPI command was pending thus we did not integrate during this
* engine cycle
*/
2019-01-03 21:22:35 -08:00
if (instance.state == IS_INTEGRATING) {
2017-04-21 16:23:20 -07:00
intHold.setLow();
2019-01-03 21:22:35 -08:00
instance.state = WAITING_FOR_ADC_TO_SKIP;
2015-07-10 06:01:56 -07:00
}
}
/**
* Shaft Position callback used to start or finish HIP integration
*/
static void intHoldCallback(trigger_event_e ckpEventType, uint32_t index, efitick_t edgeTimestamp DECLARE_ENGINE_PARAMETER_SUFFIX) {
2019-03-25 19:41:31 -07:00
(void)ckpEventType;
2015-07-10 06:01:56 -07:00
// this callback is invoked on interrupt thread
if (index != 0)
return;
2019-05-07 16:32:08 -07:00
engine->m.beforeHipCb = getTimeNowLowerNt();
2015-07-10 06:01:56 -07:00
2019-01-21 17:33:21 -08:00
int rpm = GET_RPM_VALUE;
2015-07-10 06:01:56 -07:00
if (!isValidRpm(rpm))
return;
int structIndex = getRevolutionCounter() % 2;
// todo: schedule this based on closest trigger event, same as ignition works
scheduleByAngle(&startTimer[structIndex], edgeTimestamp, engineConfiguration->knockDetectionWindowStart,
&startIntegration);
2018-11-03 10:17:58 -07:00
#if EFI_PROD_CODE
2015-07-10 06:01:56 -07:00
hipLastExecutionCount = lastExecutionCount;
2018-11-03 10:27:48 -07:00
#endif /* EFI_PROD_CODE */
scheduleByAngle(&endTimer[structIndex], edgeTimestamp, engineConfiguration->knockDetectionWindowEnd,
&endIntegration);
2019-05-07 16:32:08 -07:00
engine->m.hipCbTime = getTimeNowLowerNt() - engine->m.beforeHipCb;
2015-07-10 06:01:56 -07:00
}
2017-01-06 14:01:28 -08:00
void setMaxKnockSubDeg(int value) {
2015-07-10 06:01:56 -07:00
engineConfiguration->maxKnockSubDeg = value;
showHipInfo();
}
2017-01-06 14:01:28 -08:00
void setKnockThresh(float value) {
2015-07-10 06:01:56 -07:00
engineConfiguration->knockVThreshold = value;
showHipInfo();
}
2017-01-06 14:01:28 -08:00
void setPrescalerAndSDO(int value) {
2015-07-10 06:01:56 -07:00
engineConfiguration->hip9011PrescalerAndSDO = value;
}
2017-01-06 14:01:28 -08:00
void setHipBand(float value) {
2015-07-10 06:01:56 -07:00
engineConfiguration->knockBandCustom = value;
showHipInfo();
}
2017-01-06 14:01:28 -08:00
void setHipGain(float value) {
2019-01-04 14:18:43 -08:00
engineConfiguration->hip9011Gain = value;
2015-07-10 06:01:56 -07:00
showHipInfo();
}
2015-07-10 15:02:29 -07:00
/**
* this is the end of the non-synchronous exchange
*/
2015-07-10 06:01:56 -07:00
static void endOfSpiExchange(SPIDriver *spip) {
2019-03-25 19:41:31 -07:00
(void)spip;
2015-07-10 06:01:56 -07:00
spiUnselectI(driver);
2019-01-03 21:22:35 -08:00
instance.state = READY_TO_INTEGRATE;
2015-07-10 15:02:29 -07:00
checkResponse();
2015-07-10 06:01:56 -07:00
}
2018-11-03 06:44:34 -07:00
void hipAdcCallback(adcsample_t adcValue) {
2019-01-03 21:22:35 -08:00
if (instance.state == WAITING_FOR_ADC_TO_SKIP) {
instance.state = WAITING_FOR_RESULT_ADC;
} else if (instance.state == WAITING_FOR_RESULT_ADC) {
2018-11-03 06:44:34 -07:00
engine->knockVolts = adcValue * engine->adcToVoltageInputDividerCoefficient;
2015-07-11 13:01:31 -07:00
hipValueMax = maxF(engine->knockVolts, hipValueMax);
engine->knockLogic(engine->knockVolts);
2015-07-10 06:01:56 -07:00
2019-01-21 17:33:21 -08:00
instance.handleValue(GET_RPM_VALUE DEFINE_PARAM_SUFFIX(PASS_HIP_PARAMS));
2015-07-10 06:01:56 -07:00
}
}
static void hipStartupCode(void) {
// D[4:1] = 0000 : 4 MHz
// D[4:1] = 0001 : 5 MHz
// D[4:1] = 0010 : 6 MHz
// D[4:1] = 0011 ; 8 MHz
// D[4:1] = 0100 ; 10 MHz
// D[4:1] = 0101 ; 12 MHz
// D[4:1] = 0110 : 16 MHz
// D[4:1] = 0111 : 20 MHz
// D[4:1] = 1000 : 24 MHz
2015-07-13 06:01:41 -07:00
// 0 for 4MHz
// 6 for 8 MHz
2019-01-07 20:23:50 -08:00
instance.currentPrescaler = engineConfiguration->hip9011PrescalerAndSDO;
instance.hardware->sendSyncCommand(SET_PRESCALER_CMD + instance.currentPrescaler);
2015-07-10 06:01:56 -07:00
// '0' for channel #1
instance.hardware->sendSyncCommand(SET_CHANNEL_CMD + 0);
2015-07-10 06:01:56 -07:00
// band index depends on cylinder bore
instance.hardware->sendSyncCommand(SET_BAND_PASS_CMD + instance.currentBandIndex);
2015-07-10 06:01:56 -07:00
if (instance.correctResponsesCount == 0) {
2017-02-07 14:04:39 -08:00
warning(CUSTOM_OBD_KNOCK_PROCESSOR, "TPIC/HIP does not respond");
2015-07-10 20:01:24 -07:00
}
if (CONFIG(useTpicAdvancedMode)) {
2015-07-10 06:01:56 -07:00
// enable advanced mode for digital integrator output
instance.hardware->sendSyncCommand(SET_ADVANCED_MODE);
2015-07-10 06:01:56 -07:00
}
/**
* Let's restart SPI to switch it from synchronous mode into
* asynchronous mode
*/
spiStop(driver);
2018-11-03 06:44:34 -07:00
#if EFI_PROD_CODE
2016-07-17 00:01:48 -07:00
hipSpiCfg.end_cb = endOfSpiExchange;
2018-11-03 06:44:34 -07:00
#endif
2016-07-17 00:01:48 -07:00
spiStart(driver, &hipSpiCfg);
2019-01-03 21:22:35 -08:00
instance.state = READY_TO_INTEGRATE;
2015-07-10 06:01:56 -07:00
}
static THD_WORKING_AREA(hipTreadStack, UTILITY_THREAD_STACK_SIZE);
static msg_t hipThread(void *arg) {
2019-03-25 19:41:31 -07:00
(void)arg;
2015-07-10 06:01:56 -07:00
chRegSetThreadName("hip9011 init");
2015-07-11 12:01:54 -07:00
// some time to let the hardware start
2016-09-14 16:03:00 -07:00
enginePins.hipCs.setValue(true);
2015-07-11 12:01:54 -07:00
chThdSleepMilliseconds(100);
2016-09-14 16:03:00 -07:00
enginePins.hipCs.setValue(false);
2015-07-11 12:01:54 -07:00
chThdSleepMilliseconds(100);
2016-09-14 16:03:00 -07:00
enginePins.hipCs.setValue(true);
2015-07-11 12:01:54 -07:00
2015-07-10 06:01:56 -07:00
while (true) {
2015-07-11 12:01:54 -07:00
chThdSleepMilliseconds(100);
2019-01-03 21:22:35 -08:00
if (instance.needToInit) {
2015-07-10 06:01:56 -07:00
hipStartupCode();
2019-01-03 21:22:35 -08:00
instance.needToInit = false;
2015-07-10 06:01:56 -07:00
}
}
return -1;
}
void stopHip9001_pins() {
#if EFI_PROD_CODE
brain_pin_markUnused(activeConfiguration.hip9011IntHoldPin);
brain_pin_markUnused(activeConfiguration.hip9011CsPin);
#endif /* EFI_PROD_CODE */
}
void startHip9001_pins() {
intHold.initPin("hip int/hold", CONFIG(hip9011IntHoldPin), &CONFIG(hip9011IntHoldPinMode));
enginePins.hipCs.initPin("hip CS", CONFIG(hip9011CsPin), &CONFIG(hip9011CsPinMode));
}
2015-07-10 06:01:56 -07:00
void initHip9011(Logging *sharedLogger) {
logger = sharedLogger;
addConsoleAction("hipinfo", showHipInfo);
if (!CONFIG(isHip9011Enabled))
2015-07-10 06:01:56 -07:00
return;
2019-01-19 06:40:39 -08:00
instance.setAngleWindowWidth();
2015-07-10 06:01:56 -07:00
2018-11-03 06:44:34 -07:00
#if EFI_PROD_CODE
2016-07-17 00:01:48 -07:00
driver = getSpiDevice(engineConfiguration->hip9011SpiDevice);
if (driver == NULL) {
// error already reported
return;
}
2015-07-10 06:01:56 -07:00
hipSpiCfg.ssport = getHwPort("hip", CONFIG(hip9011CsPin));
hipSpiCfg.sspad = getHwPin("hip", CONFIG(hip9011CsPin));
2019-05-27 14:02:46 -07:00
#endif /* EFI_PROD_CODE */
2015-07-10 06:01:56 -07:00
startHip9001_pins();
2015-07-10 06:01:56 -07:00
scheduleMsg(logger, "Starting HIP9011/TPIC8101 driver");
2016-07-17 00:01:48 -07:00
spiStart(driver, &hipSpiCfg);
2015-07-10 06:01:56 -07:00
2019-01-07 20:23:50 -08:00
instance.currentBandIndex = getBandIndex();
2015-07-10 06:01:56 -07:00
/**
* this engine cycle callback would be scheduling actual integration start and end callbacks
*/
addTriggerEventListener(&intHoldCallback, "DD int/hold", engine);
// MISO PB14
// palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(EFI_SPI2_AF) | PAL_STM32_PUDR_PULLUP);
// MOSI PB15
// palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(EFI_SPI2_AF) | PAL_STM32_OTYPE_OPENDRAIN);
2017-01-06 14:01:28 -08:00
addConsoleActionF("set_gain", setHipGain);
addConsoleActionF("set_band", setHipBand);
2015-07-10 06:01:56 -07:00
addConsoleActionI("set_hip_prescalerandsdo", setPrescalerAndSDO);
addConsoleActionF("set_knock_threshold", setKnockThresh);
addConsoleActionI("set_max_knock_sub_deg", setMaxKnockSubDeg);
2018-12-27 06:40:40 -08:00
chThdCreateStatic(hipTreadStack, sizeof(hipTreadStack), NORMALPRIO, (tfunc_t)(void*) hipThread, NULL);
2015-07-10 06:01:56 -07:00
}
2017-04-09 19:07:41 -07:00
#endif /* EFI_HIP_9011 */