Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /**
  2.  * @file    HIP9011.cpp
  3.  * @brief   HIP9011/TPIC8101 driver
  4.  *
  5.  *  pin1    VDD
  6.  *  pin2    GND
  7.  *
  8.  *  pin8    Chip Select - CS
  9.  *  pin11   Slave Data Out - MISO-
  10.  *  pin12   Slave Data In - MOSI
  11.  *  pin13   SPI clock - SCLK
  12.  *
  13.  *
  14.  *
  15.  * http://www.ti.com/lit/ds/symlink/tpic8101.pdf
  16.  * http://www.intersil.com/content/dam/Intersil/documents/hip9/hip9011.pdf
  17.  * http://www.intersil.com/content/dam/Intersil/documents/an97/an9770.pdf
  18.  * http://e2e.ti.com/cfs-file/__key/telligent-evolution-components-attachments/00-26-01-00-00-42-36-40/TPIC8101-Training.pdf
  19.  *
  20.  * max SPI frequency: 5MHz max
  21.  *
  22.  * @date Nov 27, 2013
  23.  * @author Andrey Belomutskiy, (c) 2012-2015
  24.  * @Spilly
  25.  */
  26.  
  27. #include "main.h"
  28. #include "engine.h"
  29. #include "settings.h"
  30. #include "pin_repository.h"
  31. #include "hardware.h"
  32. #include "rpm_calculator.h"
  33. #include "trigger_central.h"
  34. #include "hip9011_lookup.h"
  35. #include "HIP9011.h"
  36. #include "adc_inputs.h"
  37. #include "efilib2.h"
  38. #include "engine_controller.h"
  39.  
  40. #if EFI_HIP_9011 || defined(__DOXYGEN__)
  41.  
  42. static NamedOutputPin intHold("HIP");
  43. static OutputPin hipCs;
  44.  
  45. extern pin_output_mode_e DEFAULT_OUTPUT;
  46.  
  47. extern uint32_t lastExecutionCount;
  48.  
  49. uint32_t hipLastExecutionCount;
  50.  
  51. /**
  52.  * band index is only send to HIP chip on startup
  53.  */
  54. static int currentBandIndex;
  55. static int currentGainIndex = -1;
  56. static int currentIntergratorIndex = -1;
  57. static int settingUpdateCount = 0;
  58. static int currentPrescaler = 0;
  59.  
  60. /*
  61.  * maximum total number of degrees to subtract from ignition advance
  62.  * when knocking
  63.  */
  64. static int maxKnockSubDeg = 10;
  65.  
  66. /**
  67.  * Int/Hold pin is controlled from scheduler callbacks which are set according to current RPM
  68.  *
  69.  * The following state makes sure that we only have SPI communication while not integrating and that we take
  70.  * a good ADC reading after integrating.
  71.  *
  72.  * Once integtation window is over, we wait for the 2nd ADC callback and then initiate SPI communication if needed
  73.  *
  74.  * hipOutput should be set to used FAST adc device
  75.  */
  76. static hip_state_e state = NOT_READY;
  77.  
  78. static scheduling_s startTimer[2];
  79. static scheduling_s endTimer[2];
  80.  
  81. static Logging *logger;
  82.  
  83. // SPI_CR1_BR_1 // 5MHz
  84. // SPI_CR1_CPHA Clock Phase
  85. // todo: nicer method which would mention SPI speed explicitly?
  86.  
  87. static SPIConfig spicfg = { NULL,
  88. /* HW dependent part.*/
  89. NULL, 0,
  90. SPI_CR1_MSTR |
  91. //SPI_CR1_BR_1 // 5MHz
  92.         SPI_CR1_CPHA | SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_BR_2 };
  93.  
  94. static unsigned char tx_buff[1];
  95. static unsigned char rx_buff[1];
  96. static int nonZeroResponse = 0;
  97.  
  98. static int spiCount = 0;
  99. static int firstBits = 0;
  100. static int lastBits = 0;
  101. static int knockLevel = 0;
  102. static int knockDebug = 0;
  103. #define SPI_SYNCHRONOUS(value) \
  104.     spiSelect(driver); \
  105.     tx_buff[0] = value; \
  106.     spiExchange(driver, 1, tx_buff, rx_buff); \
  107.     spiUnselect(driver); \
  108.     if (rx_buff[0] != 0) nonZeroResponse++;
  109.  
  110. // todo: make this configurable
  111. static SPIDriver *driver = &SPID2;
  112.  
  113. EXTERN_ENGINE
  114. ;
  115.  
  116. static char pinNameBuffer[16];
  117.  
  118. static float getBand(void) {
  119.     return engineConfiguration->knockBandCustom == 0 ?
  120.             BAND(engineConfiguration->cylinderBore) : engineConfiguration->knockBandCustom;
  121. }
  122.  
  123. static void showHipInfo(void) {
  124.     if (!boardConfiguration->isHip9011Enabled) {
  125.         scheduleMsg(logger, "hip9011 driver not active");
  126.         return;
  127.     }
  128.  
  129.     printSpiState(logger, boardConfiguration);
  130.     scheduleMsg(logger, "enabled=%s state=%d bore=%fmm freq=%fkHz PaSDO=%d",
  131.             boolToString(boardConfiguration->isHip9011Enabled),
  132.             state,
  133.             engineConfiguration->cylinderBore, getBand(),
  134.             engineConfiguration->hip9011PrescalerAndSDO);
  135.  
  136.     scheduleMsg(logger, "band_index=%d gain %f/index=%d", currentBandIndex, boardConfiguration->hip9011Gain, currentGainIndex);
  137.     scheduleMsg(logger, "integrator index=%d hip_threshold=%f knockCount=%d maxKnockSubDeg=%d", currentIntergratorIndex,
  138.             engineConfiguration->hipThreshold, engine->knockCount, maxKnockSubDeg);
  139.  
  140.     scheduleMsg(logger, "spi= IntHold@%s response count=%d", hwPortname(boardConfiguration->hip9011IntHoldPin),
  141.             nonZeroResponse);
  142.     scheduleMsg(logger, "CS@%s updateCount=%d", hwPortname(boardConfiguration->hip9011CsPin), settingUpdateCount);
  143.  
  144.     scheduleMsg(logger, "hip output=%fv@%s", getVoltageDivided("hip", engineConfiguration->hipOutputChannel),
  145.             getPinNameByAdcChannel(engineConfiguration->hipOutputChannel, pinNameBuffer));
  146. }
  147.  
  148. void setHip9011FrankensoPinout(void) {
  149.     /**
  150.      * SPI on PB13/14/15
  151.      */
  152.     boardConfiguration->isHip9011Enabled = true;
  153.     boardConfiguration->hip9011CsPin = GPIOD_0;
  154.     boardConfiguration->hip9011IntHoldPin = GPIOB_11;
  155.     boardConfiguration->is_enabled_spi_2 = true;
  156.  
  157.     boardConfiguration->hip9011Gain = 0.1;
  158.     engineConfiguration->hipThreshold = 2;
  159.  
  160.     engineConfiguration->hipOutputChannel = EFI_ADC_10;
  161. }
  162.  
  163. static void startIntegration(void) {
  164.     if (state == READY_TO_INTEGRATE) {
  165.         /**
  166.          * SPI communication is only allowed while not integrating, so we postpone the exchange
  167.          * until we are done integrating
  168.          */
  169.         state = IS_INTEGRATING;
  170.         turnPinHigh(&intHold);
  171.     }
  172. }
  173.  
  174. static void endIntegration(void) {
  175.     /**
  176.      * isIntegrating could be 'false' if an SPI command was pending thus we did not integrate during this
  177.      * engine cycle
  178.      */
  179.     if (state == IS_INTEGRATING) {
  180.         turnPinLow(&intHold);
  181.         //state = WAITING_FOR_ADC_TO_SKIP;
  182.         state = GET_SPI_DATA_ONE;
  183.     }
  184. }
  185.  
  186. /**
  187.  * Shaft Position callback used to start or finish HIP integration
  188.  */
  189. static void intHoldCallback(trigger_event_e ckpEventType, uint32_t index DECLARE_ENGINE_PARAMETER_S) {
  190.     // this callback is invoked on interrupt thread
  191.     engine->m.beforeHipCb = GET_TIMESTAMP();
  192.     if (index != 0)
  193.         return;
  194.  
  195.     int rpm = engine->rpmCalculator.rpmValue;
  196.     if (!isValidRpm(rpm))
  197.         return;
  198.  
  199.     int structIndex = getRevolutionCounter() % 2;
  200.     // todo: schedule this based on closest trigger event, same as ignition works
  201.     scheduleByAngle(rpm, &startTimer[structIndex], engineConfiguration->knockDetectionWindowStart,
  202.             (schfunc_t) &startIntegration, NULL, &engine->rpmCalculator);
  203.     hipLastExecutionCount = lastExecutionCount;
  204.     scheduleByAngle(rpm, &endTimer[structIndex], engineConfiguration->knockDetectionWindowEnd,
  205.             (schfunc_t) &endIntegration,
  206.             NULL, &engine->rpmCalculator);
  207.     engine->m.hipCbTime = GET_TIMESTAMP() - engine->m.beforeHipCb;
  208. }
  209. static void setMaxKnockSubDeg(int value) {
  210.     maxKnockSubDeg = value;
  211.     showHipInfo();
  212. }
  213. static void setKnockThresh(float value) {
  214.     engineConfiguration->hipThreshold = value;
  215.     showHipInfo();
  216. }
  217. static void setKnockDebug(int value) {
  218.     knockDebug = value;
  219.     if(knockDebug){
  220.         scheduleMsg(logger, "knock debug enabled");
  221.     } else{
  222.         scheduleMsg(logger, "knock debug disabled");
  223.     }
  224. }
  225.  
  226. static void setPrescalerAndSDO(int value) {
  227.     engineConfiguration->hip9011PrescalerAndSDO = value;
  228.     showHipInfo();
  229. }
  230.  
  231. static void setBand(float value) {
  232.     engineConfiguration->knockBandCustom = value;
  233.     showHipInfo();
  234. }
  235.  
  236. static void setGain(float value) {
  237.     boardConfiguration->hip9011Gain = value;
  238.     showHipInfo();
  239. }
  240.  
  241. static int getBandIndex(void) {
  242.     float freq = getBand();
  243.     return getHip9011BandIndex(freq);
  244. }
  245. static void endOfSpiExchange(SPIDriver *spip) {
  246.     spiUnselectI(driver);
  247.  
  248.     float knockVolts = 0;
  249.     switch (spiCount){
  250.     case 0:
  251.         state = GET_SPI_DATA_TWO;
  252.         spiCount ++;
  253.         break;
  254.     case 1:
  255.         state = GET_SPI_DATA_THREE;
  256.         //D7-D0 of digital integrator output
  257.         firstBits = rx_buff[0];
  258.         spiCount ++;
  259.         break;
  260.     case 2:
  261.         state = ALL_SPI_DATA_REC;
  262.         spiCount = 0;
  263.         //D9 to D8 of digital integrator output followed by six zeros
  264.         lastBits = rx_buff[0];
  265.  
  266.  
  267.  
  268.  
  269.         knockLevel = lastBits<<2;
  270.         knockLevel |= firstBits;
  271.         //convert 12-bit digital integrator output to voltage
  272.         knockVolts = knockLevel * KNOCK_VREF / 1024.0f;
  273.  
  274.         engine->knockNow = knockVolts > engineConfiguration->hipThreshold;
  275.  
  276.         /**
  277.          * KnockCount is directly proportional to the degrees of ignition
  278.          * advance removed
  279.          * ex: degrees to subtract = knockCount;
  280.          */
  281.  
  282.         /**
  283.          * TODO use knockLevel as a factor for amount of ignition advance
  284.          * to remove
  285.          * Perhaps allow the user to set a multiplier
  286.          * ex: degrees to subtract = knockCount + (knockLevel * X)
  287.          * X = user configurable multiplier
  288.          */
  289.         if (engine->knockNow){
  290.             /**
  291.              * TODO put maxKnockSubDeg in board_configuration_s
  292.              * Not sure how offsets work
  293.              */
  294.             if(engine->knockCount < maxKnockSubDeg){
  295.                 engine->knockCount++;
  296.             }
  297.         } else if (engine->knockCount >= 1){
  298.             engine->knockCount--;
  299.         } else {
  300.             engine->knockCount = 0;
  301.         }
  302.  
  303.         if(knockDebug){
  304.             //scheduleMsg(logger, "first = %d", firstBits);
  305.             //scheduleMsg(logger, "last = %d", lastBits);
  306.             scheduleMsg(logger, "total = %d voltage = %f knocking = %d", knockLevel, knockVolts, engine->knockNow);
  307.             //scheduleMsg(logger, "total = %d voltage = %f", knockLevel, knockVolts);
  308.         }
  309.  
  310.         break;
  311.     case 9:
  312.         state = READY_TO_INTEGRATE;
  313.         spiCount = 0;
  314.         break;
  315.     }
  316. }
  317.  
  318. //void hipAdcCallback(adcsample_t value) {
  319. void hipCallback(void) {
  320.     if(state == GET_SPI_DATA_ONE){
  321.         tx_buff[0] = SET_PRESCALER_CMD + engineConfiguration->hip9011PrescalerAndSDO;
  322.         state = IS_SENDING_SPI_COMMAND;
  323.         spiSelectI(driver);
  324.         spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  325.     } else if(state == GET_SPI_DATA_TWO){
  326.         //tx_buff[0] = SET_PRESCALER_CMD + engineConfiguration->hip9011PrescalerAndSDO;
  327.         tx_buff[0] = SET_CHANNEL_CMD + 0;
  328.         state = IS_SENDING_SPI_COMMAND;
  329.         spiSelectI(driver);
  330.         spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  331.     } else if(state == GET_SPI_DATA_THREE){
  332.         tx_buff[0] = SET_CHANNEL_CMD + 0;
  333.         state = IS_SENDING_SPI_COMMAND;
  334.         spiSelectI(driver);
  335.         spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  336.     } else if (state == ALL_SPI_DATA_REC) {
  337.  
  338.         int integratorIndex = getIntegrationIndexByRpm(engine->rpmCalculator.rpmValue);
  339.         int gainIndex = getHip9011GainIndex(boardConfiguration->hip9011Gain);
  340.         int bandIndex = getBandIndex();
  341.         int prescalerIndex = engineConfiguration->hip9011PrescalerAndSDO;
  342.  
  343.         if (currentGainIndex != gainIndex) {
  344.             spiCount = 9;
  345.             currentGainIndex = gainIndex;
  346.  
  347.             //added CMD bits
  348.             tx_buff[0] = SET_GAIN_CMD + gainIndex;
  349.  
  350.             state = IS_SENDING_SPI_COMMAND;
  351.             spiSelectI(driver);
  352.             spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  353.         } else if (currentIntergratorIndex != integratorIndex) {
  354.             spiCount = 9;
  355.             currentIntergratorIndex = integratorIndex;
  356.  
  357.             //added CMD bits
  358.             tx_buff[0] = SET_INTEGRATOR_CMD + integratorIndex;
  359.  
  360.             state = IS_SENDING_SPI_COMMAND;
  361.             spiSelectI(driver);
  362.             spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  363.         } else if (currentBandIndex != bandIndex) {
  364.             spiCount = 9;
  365.             currentBandIndex = bandIndex;
  366.  
  367.             //added CMD bits
  368.             tx_buff[0] = SET_BAND_PASS_CMD + bandIndex;
  369.  
  370.             state = IS_SENDING_SPI_COMMAND;
  371.             spiSelectI(driver);
  372.             spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  373.         } else if (currentPrescaler != prescalerIndex) {
  374.             spiCount = 9;
  375.             currentPrescaler = prescalerIndex;
  376.             tx_buff[0] = SET_PRESCALER_CMD + prescalerIndex;
  377.  
  378.             state = IS_SENDING_SPI_COMMAND;
  379.             spiSelectI(driver);
  380.             spiStartExchangeI(driver, 1, tx_buff, rx_buff);
  381.         } else {
  382.             state = READY_TO_INTEGRATE;
  383.         }
  384.     }
  385. }
  386. static bool_t needToInit = true;
  387.  
  388. static void hipStartupCode(void) {
  389. //  D[4:1] = 0000 : 4 MHz
  390. //  D[4:1] = 0001 : 5 MHz
  391. //  D[4:1] = 0010 : 6 MHz
  392. //  D[4:1] = 0011 ; 8 MHz
  393. //  D[4:1] = 0100 ; 10 MHz
  394. //  D[4:1] = 0101 ; 12 MHz
  395. //  D[4:1] = 0110 : 16 MHz
  396. //  D[4:1] = 0111 : 20 MHz
  397. //  D[4:1] = 1000 : 24 MHz
  398.  
  399.  
  400. // '0' for 4MHz
  401.     currentPrescaler = engineConfiguration->hip9011PrescalerAndSDO;
  402.     SPI_SYNCHRONOUS(SET_PRESCALER_CMD + currentPrescaler);
  403.  
  404.     chThdSleepMilliseconds(10);
  405.  
  406.     // '0' for channel #1
  407.     SPI_SYNCHRONOUS(SET_CHANNEL_CMD + 0);
  408.  
  409.     chThdSleepMilliseconds(10);
  410.  
  411.     // band index depends on cylinder bore
  412.     SPI_SYNCHRONOUS(SET_BAND_PASS_CMD + currentBandIndex);
  413.  
  414.     chThdSleepMilliseconds(10);
  415.     // enable advanced mode for digital integrator output
  416.     SPI_SYNCHRONOUS(SET_ADVANCED_MODE);
  417.  
  418.     chThdSleepMilliseconds(10);
  419.     /**
  420.      * Let's restart SPI to switch it from synchronous mode into
  421.      * asynchronous mode
  422.      */
  423.     spiStop(driver);
  424.     spicfg.end_cb = endOfSpiExchange;
  425.     spiStart(driver, &spicfg);
  426.     state = READY_TO_INTEGRATE;
  427. }
  428.  
  429. static THD_WORKING_AREA(hipTreadStack, UTILITY_THREAD_STACK_SIZE);
  430.  
  431. static msg_t hipThread(void *arg) {
  432.     chRegSetThreadName("hip9011 init");
  433.     while (true) {
  434.         // some time to let the hardware start
  435.         chThdSleepMilliseconds(500);
  436.         if (needToInit) {
  437.             hipStartupCode();
  438.             needToInit = false;
  439.         }
  440.     }
  441.     return -1;
  442. }
  443.  
  444. void initHip9011(Logging *sharedLogger) {
  445.     logger = sharedLogger;
  446.     addConsoleAction("hipinfo", showHipInfo);
  447.     if (!boardConfiguration->isHip9011Enabled)
  448.         return;
  449.  
  450.     // todo: apply new properties on the fly
  451.     prepareHip9011RpmLookup(
  452.             engineConfiguration->knockDetectionWindowEnd - engineConfiguration->knockDetectionWindowStart);
  453.  
  454.     // todo: configurable
  455. //  driver = getSpiDevice(boardConfiguration->hip9011SpiDevice);
  456.  
  457.     spicfg.ssport = getHwPort(boardConfiguration->hip9011CsPin);
  458.     spicfg.sspad = getHwPin(boardConfiguration->hip9011CsPin);
  459.  
  460.     outputPinRegisterExt2("hip int/hold", &intHold, boardConfiguration->hip9011IntHoldPin, &DEFAULT_OUTPUT);
  461.     outputPinRegisterExt2("hip CS", &hipCs, boardConfiguration->hip9011CsPin, &DEFAULT_OUTPUT);
  462.  
  463.     scheduleMsg(logger, "Starting HIP9011/TPIC8101 driver");
  464.     spiStart(driver, &spicfg);
  465.  
  466.     currentBandIndex = getBandIndex();
  467.  
  468.     /**
  469.      * this engine cycle callback would be scheduling actual integration start and end callbacks
  470.      */
  471.     addTriggerEventListener(&intHoldCallback, "DD int/hold", engine);
  472.  
  473.     addConsoleActionF("set_gain", setGain);
  474.     addConsoleActionF("set_band", setBand);
  475.     addConsoleActionI("set_hip_prescalerandsdo", setPrescalerAndSDO);
  476.     addConsoleActionI("knock_debug", setKnockDebug);
  477.     addConsoleActionF("set_knock_threshold", setKnockThresh);
  478.     addConsoleActionI("set_max_knock_sub_deg", setMaxKnockSubDeg);
  479.     chThdCreateStatic(hipTreadStack, sizeof(hipTreadStack), NORMALPRIO, (tfunc_t) hipThread, NULL);
  480. }
  481.  
  482. #endif