rusefi-1/firmware/hw_layer/HIP9011.cpp

273 lines
7.8 KiB
C++
Raw Normal View History

2014-08-29 07:52:33 -07:00
/**
2014-12-15 17:03:49 -08:00
* @file HIP9011.cpp
2014-08-29 07:52:33 -07:00
* @brief HIP9011/TPIC8101 driver
*
* pin1 VDD
* pin2 GND
*
* pin8 Chip Select - CS
* pin11 Slave Data Out - MISO-
* pin12 Slave Data In - MOSI
* pin13 SPI clock - SCLK
*
2015-01-04 18:03:36 -08:00
*
*
2014-12-15 17:03:49 -08:00
* http://www.ti.com/lit/ds/symlink/tpic8101.pdf
2014-12-24 18:03:45 -08:00
* http://www.intersil.com/content/dam/Intersil/documents/hip9/hip9011.pdf
2014-12-15 17:03:49 -08:00
* 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
2014-08-29 07:52:33 -07:00
*
2015-01-04 18:03:36 -08:00
* max SPI frequency: 5MHz max
2014-08-29 07:52:33 -07:00
*
* @date Nov 27, 2013
2015-01-12 15:04:10 -08:00
* @author Andrey Belomutskiy, (c) 2012-2015
2014-08-29 07:52:33 -07:00
*/
#include "main.h"
2014-12-05 09:03:16 -08:00
#include "engine.h"
2014-12-15 17:03:49 -08:00
#include "settings.h"
#include "pin_repository.h"
2014-12-18 10:05:24 -08:00
#include "hardware.h"
#include "rpm_calculator.h"
#include "trigger_central.h"
2015-01-04 18:03:36 -08:00
#include "hip9011_lookup.h"
2015-01-04 21:03:44 -08:00
#include "HIP9011.h"
2015-01-14 20:03:40 -08:00
#include "adc_inputs.h"
2014-08-29 07:52:33 -07:00
2014-12-23 19:06:10 -08:00
#if EFI_HIP_9011 || defined(__DOXYGEN__)
2014-08-29 07:52:33 -07:00
2015-01-10 16:03:38 -08:00
static OutputPin intHold;
static OutputPin hipCs;
2014-12-26 12:04:16 -08:00
2014-12-19 05:03:42 -08:00
extern pin_output_mode_e DEFAULT_OUTPUT;
2015-01-04 19:03:31 -08:00
/**
* band index is only send to HIP chip on startup
*/
2014-12-19 05:03:42 -08:00
static int bandIndex;
2015-01-04 21:03:44 -08:00
static int currentGainIndex = -1;
2015-01-04 19:03:31 -08:00
static int currentIntergratorIndex = -1;
2015-01-04 21:03:44 -08:00
static int settingUpdateCount = 0;
2015-01-14 20:03:40 -08:00
static int totalKnockEventsCount = 0;
static efitimeus_t timeOfLastKnockEvent = 0;
2015-01-04 18:03:36 -08:00
/**
* Int/Hold pin is controlled from scheduler callbacks which are set according to current RPM
*
2015-01-15 17:04:01 -08:00
* The following state make sure that we only have SPI communication while not integrating and that we take
* a good ADC reading after integrating.
*
* Once integtation window is over, we wait for the 2nd ADC callback and then initiate SPI communication if needed
*
* hipOutput should be set to used FAST adc device
2015-01-04 21:03:44 -08:00
*/
2015-01-15 17:04:01 -08:00
static hip_state_e state = READY_TO_INTEGRATE;
2015-01-10 09:03:53 -08:00
2014-12-18 10:05:24 -08:00
static scheduling_s startTimer[2];
static scheduling_s endTimer[2];
2015-01-14 16:03:39 -08:00
static Logging *logger;
2014-08-29 07:52:33 -07:00
// SPI_CR1_BR_1 // 5MHz
2014-12-24 18:03:45 -08:00
// SPI_CR1_CPHA Clock Phase
2014-12-23 18:03:36 -08:00
// todo: nicer method which would mention SPI speed explicitly?
2014-08-29 07:52:33 -07:00
2014-12-25 18:04:36 -08:00
static SPIConfig spicfg = { NULL,
2014-08-29 07:52:33 -07:00
/* HW dependent part.*/
2014-12-25 19:03:24 -08:00
NULL, 0,
SPI_CR1_MSTR |
2014-08-29 07:52:33 -07:00
//SPI_CR1_BR_1 // 5MHz
2014-12-25 19:03:24 -08:00
SPI_CR1_CPHA | SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2 };
2014-08-29 07:52:33 -07:00
2014-12-25 18:04:36 -08:00
static unsigned char tx_buff[1];
static unsigned char rx_buff[1];
2015-01-05 15:03:30 -08:00
static int nonZeroResponse = 0;
2014-08-29 07:52:33 -07:00
2014-12-26 12:04:16 -08:00
#define SPI_SYNCHRONOUS(value) \
spiSelect(driver); \
tx_buff[0] = value; \
spiExchange(driver, 1, tx_buff, rx_buff); \
2015-01-05 15:03:30 -08:00
spiUnselect(driver); \
if (rx_buff[0] != 0) nonZeroResponse++;
2014-12-26 12:04:16 -08:00
// todo: make this configurable
2014-08-29 07:52:33 -07:00
static SPIDriver *driver = &SPID2;
2015-01-04 21:03:44 -08:00
EXTERN_ENGINE
;
2014-12-15 17:03:49 -08:00
static void showHipInfo(void) {
2015-01-14 16:03:39 -08:00
printSpiState(logger, boardConfiguration);
scheduleMsg(logger, "bore=%f freq=%f", engineConfiguration->cylinderBore, BAND(engineConfiguration->cylinderBore));
2014-12-15 17:03:49 -08:00
2015-01-14 16:03:39 -08:00
scheduleMsg(logger, "band_index=%d gain %f/index=%d", bandIndex, boardConfiguration->hip9011Gain, currentGainIndex);
2015-01-14 20:03:40 -08:00
scheduleMsg(logger, "integrator index=%d hip_threshold=%f totalKnockEventsCount=%d", currentIntergratorIndex,
engineConfiguration->hipThreshold, totalKnockEventsCount);
2014-12-26 12:04:16 -08:00
2015-01-14 20:03:40 -08:00
scheduleMsg(logger, "spi= int=%s response count=%d", hwPortname(boardConfiguration->hip9011IntHoldPin),
nonZeroResponse);
2015-01-14 16:03:39 -08:00
scheduleMsg(logger, "CS=%s updateCount=%d", hwPortname(boardConfiguration->hip9011CsPin), settingUpdateCount);
2015-01-15 16:03:56 -08:00
scheduleMsg(logger, "value=%f@#%d", getVoltageDivided(engineConfiguration->hipOutputChannel),
engineConfiguration->hipOutputChannel);
2014-12-15 17:03:49 -08:00
}
void setHip9011FrankensoPinout(void) {
/**
* SPI on PB13/14/15
*/
boardConfiguration->isHip9011Enabled = true;
2015-01-05 21:03:38 -08:00
boardConfiguration->hip9011CsPin = GPIOD_0;
2014-12-15 17:03:49 -08:00
boardConfiguration->hip9011IntHoldPin = GPIOB_11;
2014-12-18 10:05:24 -08:00
boardConfiguration->is_enabled_spi_2 = true;
2015-01-14 20:03:40 -08:00
engineConfiguration->hipThreshold = 2;
2015-01-15 16:03:56 -08:00
boardConfiguration->adcHwChannelEnabled[10] = ADC_FAST; // HIP9011
engineConfiguration->hipOutputChannel = EFI_ADC_10;
2014-12-18 10:05:24 -08:00
}
2014-12-26 12:04:16 -08:00
static void startIntegration(void) {
2015-01-15 17:04:01 -08:00
if (state == READY_TO_INTEGRATE) {
2015-01-04 18:03:36 -08:00
/**
2015-01-05 15:03:30 -08:00
* SPI communication is only allowed while not integrating, so we postpone the exchange
* until we are done integrating
2015-01-04 18:03:36 -08:00
*/
2015-01-14 20:03:40 -08:00
state = IS_INTEGRATING;
2015-01-10 16:03:38 -08:00
intHold.setValue(true);
2015-01-04 18:03:36 -08:00
}
2014-12-26 12:04:16 -08:00
}
static void endIntegration(void) {
/**
2015-01-04 18:03:36 -08:00
* isIntegrating could be 'false' if an SPI command was pending thus we did not integrate during this
* engine cycle
2014-12-26 12:04:16 -08:00
*/
2015-01-15 17:04:01 -08:00
if (state == IS_INTEGRATING) {
2015-01-10 16:03:38 -08:00
intHold.setValue(false);
2015-01-15 17:04:01 -08:00
state = WAITING_FOR_ADC_TO_SKIP;
2014-12-26 12:04:16 -08:00
}
}
2014-12-18 10:05:24 -08:00
/**
* Shaft Position callback used to start or finish HIP integration
*/
2015-01-04 18:03:36 -08:00
static void intHoldCallback(trigger_event_e ckpEventType, uint32_t index DECLARE_ENGINE_PARAMETER_S) {
2014-12-18 10:05:24 -08:00
// this callback is invoked on interrupt thread
if (index != 0)
return;
int rpm = engine->rpmCalculator.rpmValue;
if (!isValidRpm(rpm))
return;
int structIndex = getRevolutionCounter() % 2;
// todo: schedule this based on closest trigger event, same as ignition works
2015-01-04 18:03:36 -08:00
scheduleByAngle(rpm, &startTimer[structIndex], engineConfiguration->knockDetectionWindowStart,
2014-12-26 12:04:16 -08:00
(schfunc_t) &startIntegration, NULL);
2015-01-04 18:03:36 -08:00
scheduleByAngle(rpm, &endTimer[structIndex], engineConfiguration->knockDetectionWindowEnd,
2014-12-26 12:04:16 -08:00
(schfunc_t) &endIntegration,
NULL);
2014-12-15 17:03:49 -08:00
}
2015-01-02 06:03:46 -08:00
static void setGain(float value) {
2015-01-02 10:04:02 -08:00
boardConfiguration->hip9011Gain = value;
showHipInfo();
2015-01-02 06:03:46 -08:00
}
2015-01-08 14:03:40 -08:00
static void endOfSpiCommunication(SPIDriver *spip) {
2015-01-10 09:03:53 -08:00
spiUnselectI(driver);
2015-01-15 17:04:01 -08:00
state = READY_TO_INTEGRATE;
2015-01-08 14:03:40 -08:00
}
2015-01-14 19:04:08 -08:00
void hipAdcCallback(adcsample_t value) {
2015-01-14 20:03:40 -08:00
if (state == WAITING_FOR_ADC_TO_SKIP) {
state = WAITING_FOR_RESULT_ADC;
} else if (state == WAITING_FOR_RESULT_ADC) {
if (adcToVoltsDivided(value) > engineConfiguration->hipThreshold) {
totalKnockEventsCount++;
timeOfLastKnockEvent = getTimeNowUs();
}
2015-01-15 17:04:01 -08:00
int integratorIndex = getIntegrationIndexByRpm(engine->rpmCalculator.rpmValue);
int gainIndex = getHip9011GainIndex(boardConfiguration->hip9011Gain);
if (currentGainIndex != gainIndex) {
state = IS_SENDING_SPI_COMMAND;
tx_buff[0] = gainIndex;
currentGainIndex = gainIndex;
spiSelectI(driver);
spiStartExchangeI(driver, 1, tx_buff, rx_buff);
} else if (currentIntergratorIndex != integratorIndex) {
state = IS_SENDING_SPI_COMMAND;
tx_buff[0] = integratorIndex;
currentIntergratorIndex = integratorIndex;
spiSelectI(driver);
spiStartExchangeI(driver, 1, tx_buff, rx_buff);
} else {
state = READY_TO_INTEGRATE;
}
2015-01-14 20:03:40 -08:00
}
2015-01-14 19:04:08 -08:00
}
2015-01-14 16:03:39 -08:00
void initHip9011(Logging *sharedLogger) {
2014-12-05 09:03:16 -08:00
if (!boardConfiguration->isHip9011Enabled)
return;
2015-01-14 16:03:39 -08:00
logger = sharedLogger;
2014-08-29 07:52:33 -07:00
2015-01-04 21:03:44 -08:00
// todo: apply new properties on the fly
prepareHip9011RpmLookup(
engineConfiguration->knockDetectionWindowEnd - engineConfiguration->knockDetectionWindowStart);
2015-01-04 19:03:31 -08:00
2015-01-04 21:03:44 -08:00
// todo: configurable
// driver = getSpiDevice(boardConfiguration->hip9011SpiDevice);
2014-12-18 10:05:24 -08:00
spicfg.ssport = getHwPort(boardConfiguration->hip9011CsPin);
spicfg.sspad = getHwPin(boardConfiguration->hip9011CsPin);
2015-01-10 16:03:38 -08:00
outputPinRegisterExt2("hip int/hold", &intHold, boardConfiguration->hip9011IntHoldPin, &DEFAULT_OUTPUT);
outputPinRegisterExt2("hip CS", &hipCs, boardConfiguration->hip9011CsPin, &DEFAULT_OUTPUT);
2014-12-26 12:04:16 -08:00
2015-01-14 16:03:39 -08:00
scheduleMsg(logger, "Starting HIP9011/TPIC8101 driver");
2014-08-29 07:52:33 -07:00
spiStart(driver, &spicfg);
2014-12-26 12:04:16 -08:00
2015-01-04 19:03:31 -08:00
bandIndex = getHip9011BandIndex(engineConfiguration->cylinderBore);
2014-12-15 17:03:49 -08:00
2015-01-04 21:03:44 -08:00
/**
* this engine cycle callback would be scheduling actual integration start and end callbacks
*/
2014-12-18 10:05:24 -08:00
addTriggerEventListener(&intHoldCallback, "DD int/hold", engine);
2014-12-25 19:03:24 -08:00
// 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);
2014-12-15 17:03:49 -08:00
addConsoleAction("hipinfo", showHipInfo);
2015-01-02 06:03:46 -08:00
addConsoleActionF("set_gain", setGain);
2015-01-04 21:03:44 -08:00
// '0' for 4MHz
SPI_SYNCHRONOUS(SET_PRESCALER_CMD + 0);
// '0' for channel #1
SPI_SYNCHRONOUS(SET_CHANNEL_CMD + 0);
// band index depends on cylinder bore
SPI_SYNCHRONOUS(SET_BAND_PASS_CMD + bandIndex);
2015-01-08 14:03:40 -08:00
/**
* Let's restart SPI to switch it from synchronous mode into
* asynchronous mode
*/
2015-01-10 16:03:38 -08:00
spiStop(driver);
spicfg.end_cb = endOfSpiCommunication;
spiStart(driver, &spicfg);
2014-08-29 07:52:33 -07:00
}
#endif