diff --git a/speeduino/comms_CAN.cpp b/speeduino/comms_CAN.cpp index 4624f3e614..bfaddec01b 100644 --- a/speeduino/comms_CAN.cpp +++ b/speeduino/comms_CAN.cpp @@ -305,7 +305,7 @@ void DashMessage(uint16_t DashMessageID) case CAN_HALTECH_DATA3: temp_Advance = currentStatus.advance * 10U; //Note: Signed value //Convert PW into duty cycle - temp_DutyCycle = (fuelSchedule1.pw * 100UL * currentStatus.nSquirts) / revolutionTime; + temp_DutyCycle = (fuelSchedule1.pw * 100UL * currentStatus.nSquirts) / getRevolutionTime(currentStatus); if (configPage2.strokes == FOUR_STROKE) { temp_DutyCycle = temp_DutyCycle / 2U; } outMsg.len = 8; diff --git a/speeduino/corrections.cpp b/speeduino/corrections.cpp index 820caf8740..e311a6bcc8 100644 --- a/speeduino/corrections.cpp +++ b/speeduino/corrections.cpp @@ -30,6 +30,7 @@ There are 2 top level functions that call more detailed corrections for Fuel and #include "maths.h" #include "sensors.h" #include "src/PID_v1/PID_v1.h" +#include "crankMaths.h" long PID_O2, PID_output, PID_AFRTarget; /** Instance of the PID object in case that algorithm is used (Always instantiated). @@ -1096,11 +1097,11 @@ uint16_t correctionsDwell(uint16_t dwell) pulsesPerRevolution = (configPage2.nCylinders >> 1); dwellPerRevolution = dwellPerRevolution * pulsesPerRevolution; } - if(dwellPerRevolution > revolutionTime) + if(dwellPerRevolution > getRevolutionTime(currentStatus)) { //Possibly need some method of reducing spark duration here as well, but this is a start - uint16_t adjustedSparkDur = udiv_32_16(sparkDur_uS * revolutionTime, dwellPerRevolution); - tempDwell = udiv_32_16(revolutionTime, (uint16_t)pulsesPerRevolution) - adjustedSparkDur; + uint16_t adjustedSparkDur = udiv_32_16(sparkDur_uS * getRevolutionTime(currentStatus), dwellPerRevolution); + tempDwell = udiv_32_16(getRevolutionTime(currentStatus), (uint16_t)pulsesPerRevolution) - adjustedSparkDur; } return tempDwell; diff --git a/speeduino/crankMaths.cpp b/speeduino/crankMaths.cpp index efa079f24f..fe3769f08b 100644 --- a/speeduino/crankMaths.cpp +++ b/speeduino/crankMaths.cpp @@ -1,4 +1,3 @@ -#include "globals.h" #include "crankMaths.h" #include "bit_shifts.h" @@ -13,23 +12,37 @@ int rpmDelta; typedef uint32_t UQ24X8_t; static constexpr uint8_t UQ24X8_Shift = 8U; -/** @brief uS per degree at current RPM in UQ24.8 fixed point */ +/** @brief µS per degree at current RPM in UQ24.8 fixed point + * + * Ranges between + * * 1040649 (4065.039 µS/°) at MIN_RPM/MIN_REVOLUTION_TIME + * * 2370 (9.258333 µS/°) at MAX_RPM/MAX_REVOLUTION_TIME +*/ static UQ24X8_t microsPerDegree; static constexpr uint8_t microsPerDegree_Shift = UQ24X8_Shift; typedef uint16_t UQ1X15_t; static constexpr uint8_t UQ1X15_Shift = 15U; -/** @brief Degrees per uS in UQ1.15 fixed point. +/** @brief Degrees per µS in UQ1.15 fixed point. * - * Ranges from 8 (0.000246) at MIN_RPM to 3542 (0.108) at MAX_RPM + * Ranges between + * * 8 (0.000246 °/µS) at MIN_RPM/MIN_REVOLUTION_TIME + * * 3539 (0.108011 °/µS) at MAX_RPM/MAX_REVOLUTION_TIME */ static UQ1X15_t degreesPerMicro; static constexpr uint8_t degreesPerMicro_Shift = UQ1X15_Shift; -void setAngleConverterRevolutionTime(uint32_t revolutionTime) { - microsPerDegree = div360(lshift(revolutionTime)); - degreesPerMicro = (uint16_t)UDIV_ROUND_CLOSEST(lshift(UINT32_C(360)), revolutionTime, uint32_t); +bool setRevolutionTime(uint32_t revTime, statuses ¤t) { + bool hasChanged = (revTime!=current.revolutionTime) && (revTime>=MIN_REVOLUTION_TIME) && (revTime(revTime)); + degreesPerMicro = (uint16_t)UDIV_ROUND_CLOSEST(lshift(UINT32_C(360)), revTime, uint32_t); + } + + return hasChanged; } uint32_t angleToTimeMicroSecPerDegree(uint16_t angle) { @@ -38,8 +51,8 @@ uint32_t angleToTimeMicroSecPerDegree(uint16_t angle) { } uint16_t timeToAngleDegPerMicroSec(uint32_t time) { - uint32_t degFixed = time * (uint32_t)degreesPerMicro; - return rshift_round(degFixed); + uint32_t degFixed = time * (uint32_t)degreesPerMicro; + return rshift_round(degFixed); } #if SECOND_DERIV_ENABLED!=0 @@ -83,4 +96,4 @@ void doCrankSpeedCalcs(void) timePerDegreex16 = ldiv( 2666656L, currentStatus.RPM + rpmDelta).quot; //This gives accuracy down to 0.1 of a degree and can provide noticeably better timing results on low resolution triggers } } -#endif \ No newline at end of file +#endif diff --git a/speeduino/crankMaths.h b/speeduino/crankMaths.h index c3e6537350..97d8ab3e17 100644 --- a/speeduino/crankMaths.h +++ b/speeduino/crankMaths.h @@ -1,8 +1,45 @@ #ifndef CRANKMATHS_H #define CRANKMATHS_H +/** + * @file + * + * @brief Crank revolution based mathemtical functions. + * + */ + #include "maths.h" -#include "globals.h" + +/** @brief At 1 RPM, each degree of angular rotation takes this many microseconds */ +static constexpr uint32_t MICROS_PER_DEG_1_RPM = UDIV_ROUND_CLOSEST(MICROS_PER_MIN, 360UL, uint32_t); + +/** @brief The maximum rpm that the ECU will attempt to run at. + * + * It is NOT related to the rev limiter, but is instead dictates how fast certain operations will be + * allowed to run. Lower number gives better performance + **/ +static constexpr uint16_t MAX_RPM = 18000U; + +/** @brief Absolute minimum RPM that the crank math (& therefore all of Speeduino) can be used with. + * + * This is dictated by the use of uint16_t as the base type for storing + * time --> angle conversion factor (degreesPerMicro) +*/ +static constexpr uint16_t MIN_RPM = (uint16_t)UDIV_ROUND_UP(MICROS_PER_DEG_1_RPM, (uint32_t)UINT16_MAX/16UL, uint32_t); + +/** + * @brief Minumum time in µS that one crank revolution can take. + * + * @note: many calculations are done over 2 revolutions (cycles), in which case this would be doubled + */ +static constexpr uint16_t MIN_REVOLUTION_TIME = MICROS_PER_MIN/MAX_RPM; + +/** + * @brief Maximum time in µS that one crank revolution can take. + * + * @note: many calculations are done over 2 revolutions (cycles), in which case this would be doubled + */ +static constexpr uint32_t MAX_REVOLUTION_TIME = MICROS_PER_MIN/MIN_RPM; /** * @brief Makes one pass at nudging the angle to within [0,CRANK_ANGLE_MAX_IGN] @@ -20,59 +57,71 @@ static inline int16_t ignitionLimits(int16_t angle) { * @param angle A crank angle in degrees * @return int16_t */ -static inline int16_t injectorLimits(int16_t angle) +static inline uint16_t injectorLimits(uint16_t angle) { - int16_t tempAngle = angle; - if(tempAngle < 0) { tempAngle = tempAngle + CRANK_ANGLE_MAX_INJ; } - while(tempAngle > CRANK_ANGLE_MAX_INJ ) { tempAngle -= CRANK_ANGLE_MAX_INJ; } - return tempAngle; + while(angle > (uint16_t)CRANK_ANGLE_MAX_INJ ) { angle -= (uint16_t)CRANK_ANGLE_MAX_INJ; } + return angle; } -/** @brief At 1 RPM, each degree of angular rotation takes this many microseconds */ -#define MICROS_PER_DEG_1_RPM INT32_C(166667) - -/** @brief The maximum rpm that the ECU will attempt to run at. +/** + * @brief Set the revolution time, from which the degree<-->angle conversions are derived * - * It is NOT related to the rev limiter, but is instead dictates how fast certain operations will be - * allowed to run. Lower number gives better performance - **/ -#define MAX_RPM INT16_C(18000) - -/** @brief Absolute minimum RPM that the crank math (& therefore all of Speeduino) can be used with + * If the return value is true, then the calculated RPM (@ref rpmFromRevolutionTime) and + * degree<-->angle conversions (@ref angleToTimeMicroSecPerDegree, @ref timeToAngleDegPerMicroSec) will change. * - * This is dictated by the use of uint16_t as the base type for storing - * angle<->time conversion factor (degreesPerMicro) -*/ -#define MIN_RPM ((MICROS_PER_DEG_1_RPM/(UINT16_MAX/16UL))+1UL) + * @param revTime The crank revolution time in µS. *Must be between MIN_REVOLUTION_TIME and MAX_REVOLUTION_TIME* + * @return true If the revolution time has changed + * @return false If the new time is the same as the current revolution time. + */ +bool setRevolutionTime(uint32_t revTime, statuses ¤t); /** - * @brief Set the revolution time, from which some of the degree<-->angle conversions are derived + * @brief Get the latest revolution time * - * @param revolutionTime The crank revolution time. + * @return uint32_t The revolution time, limited to [MIN_REVOLUTION_TIME, MAX_REVOLUTION_TIME) */ -void setAngleConverterRevolutionTime(uint32_t revolutionTime); +static inline uint32_t getRevolutionTime(const statuses ¤t) { + return current.revolutionTime; +} + /** - * @name Converts angular degrees to the time interval that amount of rotation - * will take at current RPM. + * @brief Converts angular degrees to the time interval that amount of rotation + * will take at the current crank revolution time (@ref setRevolutionTime). * * Based on angle of [0,720] and min/max RPM, result ranges from - * 9 (MAX_RPM, 1 deg) to 2926828 (MIN_RPM, 720 deg) + * 9 (MAX_RPM, 1 deg) to 2926828 (MIN_RPM, 720 deg). I.e. 24 bits * * @param angle Angle in degrees - * @return Time interval in uS + * @return Time interval in µS */ uint32_t angleToTimeMicroSecPerDegree(uint16_t angle); /** - * @name Converts a time interval in microsecods to the equivalent degrees of angular (crank) - * rotation at current RPM. + * @brief Converts a time interval in µS to the equivalent degrees of angular (crank) + * rotation at the current crank revolution time (@ref setRevolutionTime). * * Inverse of angleToTimeMicroSecPerDegree * - * @param time Time interval in uS + * @param time Time interval in µS * @return Angle in degrees */ uint16_t timeToAngleDegPerMicroSec(uint32_t time); +/** @brief Calculate RPM based on the current crank revolution time (@ref setRevolutionTime). */ + +/** + * @brief Calculate RPM based on the revolution time + * + * @param revTime Time for one 360° rotation in µS. Typically the result of a call to getRevolutionTime() + * @return uint16_t + */ +static inline uint16_t rpmFromRevolutionTime(uint32_t revTime) { + if (revTime<=(uint32_t)UINT16_MAX) { + return udiv_32_16_closest(MICROS_PER_MIN, revTime); + } else { + return UDIV_ROUND_CLOSEST(MICROS_PER_MIN, revTime, uint32_t); + } +} + #endif \ No newline at end of file diff --git a/speeduino/decoders.cpp b/speeduino/decoders.cpp index 8a98bcd5d8..345912658b 100644 --- a/speeduino/decoders.cpp +++ b/speeduino/decoders.cpp @@ -67,7 +67,7 @@ volatile unsigned long curGap3; volatile unsigned long lastGap; volatile unsigned long targetGap; -TESTABLE_STATIC unsigned long MAX_STALL_TIME = MICROS_PER_SEC/2U; //The maximum time (in uS) that the system will continue to function before the engine is considered stalled/stopped. This is unique to each decoder, depending on the number of teeth etc. 500000 (half a second) is used as the default value, most decoders will be much less. +TESTABLE_STATIC unsigned long MAX_STALL_TIME = MICROS_PER_SEC/2UL; //The maximum time (in uS) that the system will continue to function before the engine is considered stalled/stopped. This is unique to each decoder, depending on the number of teeth etc. 500000 (half a second) is used as the default value, most decoders will be much less. volatile uint16_t toothCurrentCount = 0; //The current number of teeth (Once sync has been achieved, this can never actually be 0 static volatile byte toothSystemCount = 0; //Used for decoders such as Audi 135 where not every tooth is used for calculating crank angle. This variable stores the actual number of teeth, not the number being used to calculate crank angle volatile unsigned long toothSystemLastToothTime = 0; //As below, but used for decoders where not every tooth count is used for calculation @@ -361,20 +361,6 @@ void resetDecoder(void) { secondaryToothCount = 0; } -#if defined(UNIT_TEST) -bool SetRevolutionTime(uint32_t revTime) -#else -static __attribute__((noinline)) bool SetRevolutionTime(uint32_t revTime) -#endif -{ - if (revTime!=revolutionTime) { - revolutionTime = revTime; - setAngleConverterRevolutionTime(revolutionTime); - return true; - } - return false; -} - static bool UpdateRevolutionTimeFromTeeth(bool isCamTeeth) { noInterrupts(); bool updatedRevTime = HasAnySync(currentStatus) @@ -382,24 +368,12 @@ static bool UpdateRevolutionTimeFromTeeth(bool isCamTeeth) { && (toothOneMinusOneTime!=UINT32_C(0)) && (toothOneTime>toothOneMinusOneTime) //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) - && SetRevolutionTime((toothOneTime - toothOneMinusOneTime) >> (isCamTeeth ? 1U : 0U)); + && setRevolutionTime((toothOneTime - toothOneMinusOneTime) >> (isCamTeeth ? 1U : 0U), currentStatus); interrupts(); return updatedRevTime; } -static inline uint16_t clampRpm(uint16_t rpm) { - return rpm>=MAX_RPM ? currentStatus.RPM : rpm; -} - -static inline uint16_t RpmFromRevolutionTimeUs(uint32_t revTime) { - if (revTime 0) && (toothLastToothTime > toothLastMinusOneToothTime) ) { noInterrupts(); - bool newRevtime = SetRevolutionTime(((toothLastToothTime - toothLastMinusOneToothTime) * totalTeeth) >> (isCamTeeth ? 1U : 0U)); + bool newRevtime = setRevolutionTime(((toothLastToothTime - toothLastMinusOneToothTime) * totalTeeth) >> (isCamTeeth ? 1U : 0U), currentStatus); interrupts(); if (newRevtime) { - return RpmFromRevolutionTimeUs(revolutionTime); + return rpmFromRevolutionTime(getRevolutionTime(currentStatus)); } } } @@ -544,14 +518,14 @@ void triggerSetup_missingTooth(void) BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); } triggerActualTeeth = configPage4.triggerTeeth - configPage4.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / configPage4.triggerTeeth; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise if (configPage4.trigPatternSec == SEC_TRIGGER_4_1) { - triggerSecFilterTime = MICROS_PER_MIN / MAX_RPM / 4U / 2U; + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL / 2UL; } else { - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U)); + triggerSecFilterTime = MIN_REVOLUTION_TIME; } BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); checkSyncToothCount = (configPage4.triggerTeeth) >> 1; //50% of the total teeth. @@ -910,8 +884,8 @@ void triggerSetup_DualWheel(void) triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth if(configPage4.TrigSpeed == CAM_SPEED) { triggerToothAngle = 720 / configPage4.triggerTeeth; } //Account for cam speed toothCurrentCount = UINT8_MAX; //Default value - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerFilterTime = MIN_REVOLUTION_TIME / configPage4.triggerTeeth; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_SET(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT); //This is always true for this pattern @@ -998,7 +972,7 @@ void triggerSec_DualWheel(void) } else { - triggerSecFilterTime = revolutionTime >> 1; //Set filter at 25% of the current cam speed. This needs to be performed here to prevent a situation where the RPM and triggerSecFilterTime get out of alignment and curGap2 never exceeds the filter value + triggerSecFilterTime = getRevolutionTime(currentStatus) >> 1; //Set filter at 25% of the current cam speed. This needs to be performed here to prevent a situation where the RPM and triggerSecFilterTime get out of alignment and curGap2 never exceeds the filter value } //Trigger filter } /** Dual Wheel - Get RPM. @@ -1109,7 +1083,7 @@ void triggerSetup_BasicDistributor(void) if(configPage2.strokes == FOUR_STROKE) { triggerToothAngle = 720U / triggerActualTeeth; } else { triggerToothAngle = 360U / triggerActualTeeth; } - triggerFilterTime = MICROS_PER_MIN / MAX_RPM / configPage2.nCylinders; // Minimum time required between teeth + triggerFilterTime = MIN_REVOLUTION_TIME / configPage2.nCylinders; // Minimum time required between teeth triggerFilterTime = triggerFilterTime / 2; //Safety margin triggerFilterTime = 0; BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); @@ -1192,8 +1166,8 @@ uint16_t getRPM_BasicDistributor(void) } else { tempRPM = stdGetRPM(distributorSpeed); } - MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this - if(triggerActualTeeth == 1) { MAX_STALL_TIME = revolutionTime << 1; } //Special case for 1 cylinder engines that only get 1 pulse every 720 degrees + MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + if(triggerActualTeeth == 1) { MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; } //Special case for 1 cylinder engines that only get 1 pulse every 720 degrees if(MAX_STALL_TIME < 366667UL) { MAX_STALL_TIME = 366667UL; } //Check for 50rpm minimum return tempRPM; @@ -1309,7 +1283,7 @@ void triggerSetEndTeeth_BasicDistributor(void) */ void triggerSetup_GM7X(void) { - triggerToothAngle = 360 / 6; //The number of degrees that passes from tooth to tooth + triggerToothAngle = 360U / 6U; //The number of degrees that passes from tooth to tooth BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_CLEAR(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_CLEAR(decoderState, BIT_DECODER_HAS_SECONDARY); @@ -1490,7 +1464,7 @@ void triggerSetup_4G63(void) } triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth. - triggerSecFilterTime = (int)(MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) triggerSecFilterTime_duration = 4000; secondaryLastToothTime = 0; } @@ -1782,7 +1756,7 @@ uint16_t getRPM_4G63(void) interrupts(); toothTime = toothTime * 36; tempRPM = ((unsigned long)tempToothAngle * (MICROS_PER_MIN/10U)) / toothTime; - SetRevolutionTime((10UL * toothTime) / tempToothAngle); + setRevolutionTime((10UL * toothTime) / tempToothAngle, currentStatus); MAX_STALL_TIME = 366667UL; // 50RPM } } @@ -1791,7 +1765,7 @@ uint16_t getRPM_4G63(void) tempRPM = stdGetRPM(CAM_SPEED); //EXPERIMENTAL! Add/subtract RPM based on the last rpmDOT calc //tempRPM += (micros() - toothOneTime) * currentStatus.rpmDOT - MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this if(MAX_STALL_TIME < 366667UL) { MAX_STALL_TIME = 366667UL; } //Check for 50rpm minimum } } @@ -2105,8 +2079,8 @@ void triggerSetup_Audi135(void) triggerToothAngle = 8; //135/3 = 45, 360/45 = 8 degrees every 3 teeth toothCurrentCount = UINT8_MAX; //Default value toothSystemCount = 0; - triggerFilterTime = (unsigned long)(MICROS_PER_SEC / (MAX_RPM / 60U * 135UL)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (int)(MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerFilterTime = MIN_REVOLUTION_TIME / 135UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); @@ -2220,7 +2194,7 @@ void triggerSetEndTeeth_Audi135(void) */ void triggerSetup_HondaD17(void) { - triggerToothAngle = 360 / 12; //The number of degrees that passes from tooth to tooth + triggerToothAngle = 360UL / 12UL; //The number of degrees that passes from tooth to tooth MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_CLEAR(decoderState, BIT_DECODER_IS_SEQUENTIAL); @@ -2330,14 +2304,14 @@ void triggerSetEndTeeth_HondaD17(void) */ void triggerSetup_HondaJ32(void) { - triggerToothAngle = 360 / 24; //The number of degrees that passes from tooth to tooth + triggerToothAngle = 360UL / 24UL; //The number of degrees that passes from tooth to tooth MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/10U) * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_CLEAR(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_CLEAR(decoderState, BIT_DECODER_HAS_SECONDARY); // Filter (ignore) triggers that are faster than this. - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60 * 24)); + triggerFilterTime = MIN_REVOLUTION_TIME / 24UL; toothLastToothTime = 0; toothCurrentCount = 0; toothOneTime = 0; @@ -2366,7 +2340,7 @@ void triggerPri_HondaJ32(void) toothOneMinusOneTime = toothOneTime; toothOneTime = curTime; currentStatus.startRevolutions++; - SetRevolutionTime(toothOneTime - toothOneMinusOneTime); + setRevolutionTime(toothOneTime - toothOneMinusOneTime, currentStatus); } else if (toothCurrentCount == 23 || toothCurrentCount == 15) // This is the first tooth after a missing tooth { @@ -2412,7 +2386,7 @@ void triggerSec_HondaJ32(void) uint16_t getRPM_HondaJ32(void) { - return RpmFromRevolutionTimeUs(revolutionTime); // revolutionTime set by SetRevolutionTime() + return rpmFromRevolutionTime(getRevolutionTime(currentStatus)); // revolutionTime set by setRevolutionTime() } int getCrankAngle_HondaJ32(void) @@ -2633,14 +2607,14 @@ uint16_t getRPM_Miata9905(void) interrupts(); toothTime = toothTime * 36; tempRPM = ((unsigned long)tempToothAngle * (MICROS_PER_MIN/10U)) / toothTime; - SetRevolutionTime((10UL * toothTime) / tempToothAngle); + setRevolutionTime((10UL * toothTime) / tempToothAngle, currentStatus); MAX_STALL_TIME = 366667UL; // 50RPM } } else { tempRPM = stdGetRPM(CAM_SPEED); - MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this if(MAX_STALL_TIME < 366667UL) { MAX_STALL_TIME = 366667UL; } //Check for 50rpm minimum } @@ -2748,7 +2722,7 @@ void triggerSetup_MazdaAU(void) MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth. - triggerSecFilterTime = (int)(MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) BIT_SET(decoderState, BIT_DECODER_HAS_FIXED_CRANKING); BIT_SET(decoderState, BIT_DECODER_HAS_SECONDARY); } @@ -2835,9 +2809,9 @@ uint16_t getRPM_MazdaAU(void) int tempToothAngle; noInterrupts(); tempToothAngle = triggerToothAngle; - SetRevolutionTime(36*(toothLastToothTime - toothLastMinusOneToothTime)); //Note that trigger tooth angle changes between 72 and 108 depending on the last tooth that was seen + setRevolutionTime(36*(toothLastToothTime - toothLastMinusOneToothTime), currentStatus); //Note that trigger tooth angle changes between 72 and 108 depending on the last tooth that was seen interrupts(); - tempRPM = (tempToothAngle * MICROS_PER_MIN) / revolutionTime; + tempRPM = (tempToothAngle * MICROS_PER_MIN) / getRevolutionTime(currentStatus); } else { tempRPM = stdGetRPM(CRANK_SPEED); } } @@ -2886,8 +2860,8 @@ void triggerSetup_non360(void) { triggerToothAngle = (360U * configPage4.TrigAngMul) / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth multiplied by the additional multiplier toothCurrentCount = UINT8_MAX; //Default value - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerFilterTime = MIN_REVOLUTION_TIME / configPage4.triggerTeeth; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = MIN_REVOLUTION_TIME / 4UL; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_SET(decoderState, BIT_DECODER_HAS_SECONDARY); @@ -2957,8 +2931,8 @@ See http://wiki.r31skylineclub.com/index.php/Crank_Angle_Sensor . */ void triggerSetup_Nissan360(void) { - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 360UL)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (int)(MICROS_PER_SEC / (MAX_RPM / 60U * 2U)) / 2U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) + triggerFilterTime = MIN_REVOLUTION_TIME / 360UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = (int)MIN_REVOLUTION_TIME / 4U; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed) secondaryToothCount = 0; //Initially set to 0 prior to calculating the secondary window duration BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); @@ -3113,17 +3087,17 @@ uint16_t getRPM_Nissan360(void) if(currentStatus.startRevolutions < 2) { noInterrupts(); - SetRevolutionTime((toothLastToothTime - toothLastMinusOneToothTime) * 180); //Each tooth covers 2 crank degrees, so multiply by 180 to get a full revolution time. + setRevolutionTime((toothLastToothTime - toothLastMinusOneToothTime) * 180, currentStatus); //Each tooth covers 2 crank degrees, so multiply by 180 to get a full revolution time. interrupts(); } else { noInterrupts(); - SetRevolutionTime((toothOneTime - toothOneMinusOneTime) >> 1); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) + setRevolutionTime((toothOneTime - toothOneMinusOneTime) >> 1, currentStatus); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) interrupts(); } - tempRPM = RpmFromRevolutionTimeUs(revolutionTime); //Calc RPM based on last full revolution time (Faster as /) - MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + tempRPM = rpmFromRevolutionTime(getRevolutionTime(currentStatus)); //Calc RPM based on last full revolution time (Faster as /) + MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this } else { tempRPM = 0; } @@ -3146,7 +3120,7 @@ int getCrankAngle_Nissan360(void) interrupts(); crankAngle = ( (tempToothCurrentCount - 1) * 2) + configPage4.triggerAngle; - unsigned long halfTooth = (tempToothLastToothTime - tempToothLastMinusOneToothTime) / 2; + unsigned long halfTooth = (tempToothLastToothTime - tempToothLastMinusOneToothTime) / 2UL; elapsedTime = (lastCrankAngleCalc - tempToothLastToothTime); if (elapsedTime > halfTooth) { @@ -3187,7 +3161,7 @@ This seems to be present in late 90's Subaru. In 2001 Subaru moved to 36-2-2-2 ( */ void triggerSetup_Subaru67(void) { - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 360UL)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 360UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise triggerSecFilterTime = 0; secondaryToothCount = 0; //Initially set to 0 prior to calculating the secondary window duration BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); @@ -3463,7 +3437,7 @@ void triggerSetup_Daihatsu(void) { triggerActualTeeth = configPage2.nCylinders + 1; triggerToothAngle = 720 / triggerActualTeeth; //The number of degrees that passes from tooth to tooth - triggerFilterTime = MICROS_PER_MIN / MAX_RPM / configPage2.nCylinders; // Minimum time required between teeth + triggerFilterTime = MIN_REVOLUTION_TIME / configPage2.nCylinders; // Minimum time required between teeth triggerFilterTime = triggerFilterTime / 2; //Safety margin BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); @@ -3572,9 +3546,9 @@ uint16_t getRPM_Daihatsu(void) else { noInterrupts(); - SetRevolutionTime((toothLastToothTime - toothLastMinusOneToothTime) * (triggerActualTeeth-1)); + (void)setRevolutionTime((toothLastToothTime - toothLastMinusOneToothTime) * (triggerActualTeeth-1UL), currentStatus); interrupts(); - tempRPM = RpmFromRevolutionTimeUs(revolutionTime); + tempRPM = rpmFromRevolutionTime(getRevolutionTime(currentStatus)); } //is tooth #2 } else { tempRPM = 0; } //No sync @@ -3700,7 +3674,7 @@ uint16_t getRPM_Harley(void) if(toothCurrentCount == 1) { tempToothAngle = 129; } else { tempToothAngle = toothAngles[toothCurrentCount-1] - toothAngles[toothCurrentCount-2]; } */ - SetRevolutionTime(toothOneTime - toothOneMinusOneTime); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) + setRevolutionTime(toothOneTime - toothOneMinusOneTime, currentStatus); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) toothTime = (toothLastToothTime - toothLastMinusOneToothTime); //Note that trigger tooth angle changes between 129 and 332 depending on the last tooth that was seen interrupts(); toothTime = toothTime * 36; @@ -3768,7 +3742,7 @@ void triggerSetup_ThirtySixMinus222(void) { triggerToothAngle = 10; //The number of degrees that passes from tooth to tooth triggerActualTeeth = 30; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt - triggerFilterTime = (int)(MICROS_PER_SEC / (MAX_RPM / 60U * 36)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 36UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_CLEAR(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_SET(decoderState, BIT_DECODER_HAS_SECONDARY); @@ -3777,7 +3751,7 @@ void triggerSetup_ThirtySixMinus222(void) toothCurrentCount = 0; toothOneTime = 0; toothOneMinusOneTime = 0; - MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2U ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2UL ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) } void triggerPri_ThirtySixMinus222(void) @@ -3948,7 +3922,7 @@ void triggerSetup_ThirtySixMinus21(void) { triggerToothAngle = 10; //The number of degrees that passes from tooth to tooth triggerActualTeeth = 33; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt. Not Used - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 36)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 36UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_CLEAR(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_SET(decoderState, BIT_DECODER_HAS_SECONDARY); @@ -3957,7 +3931,7 @@ void triggerSetup_ThirtySixMinus21(void) toothCurrentCount = 0; toothOneTime = 0; toothOneMinusOneTime = 0; - MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2U ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2UL ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) } void triggerPri_ThirtySixMinus21(void) @@ -4077,7 +4051,7 @@ void triggerSetEndTeeth_ThirtySixMinus21(void) */ void triggerSetup_420a(void) { - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 360UL)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 360UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise triggerSecFilterTime = 0; secondaryToothCount = 0; //Initially set to 0 prior to calculating the secondary window duration BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); @@ -4327,7 +4301,7 @@ void triggerSec_Webber(void) } else { - if ( (toothCurrentCount != (configPage4.triggerTeeth-1U)) && (currentStatus.startRevolutions > 2U)) { currentStatus.syncLossCounter++; } //Indicates likely sync loss. + if ( (toothCurrentCount != (configPage4.triggerTeeth-1U)) && (currentStatus.startRevolutions > 2UL)) { currentStatus.syncLossCounter++; } //Indicates likely sync loss. if (configPage4.useResync == 1) { toothCurrentCount = configPage4.triggerTeeth-1; } } revolutionOne = 1; //Sequential revolution reset @@ -4372,9 +4346,9 @@ void triggerSetup_FordST170(void) triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth triggerActualTeeth = configPage4.triggerTeeth - configPage4.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / configPage4.triggerTeeth; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = MICROS_PER_MIN / MAX_RPM / 8U / 2U; //Cam pattern is 8-3, so 2 nearest teeth are 90 deg crank angle apart. Cam can be advanced by 60 deg, so going from fully retarded to fully advanced closes the gap to 30 deg. Zetec cam pulleys aren't keyed from factory, so I subtracted additional 10 deg to avoid filter to be too aggressive. And there you have it 720/20=36. + triggerSecFilterTime = MIN_REVOLUTION_TIME / 8UL / 2UL; //Cam pattern is 8-3, so 2 nearest teeth are 90 deg crank angle apart. Cam can be advanced by 60 deg, so going from fully retarded to fully advanced closes the gap to 30 deg. Zetec cam pulleys aren't keyed from factory, so I subtracted additional 10 deg to avoid filter to be too aggressive. And there you have it 720/20=36. BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); @@ -4385,7 +4359,7 @@ void triggerSetup_FordST170(void) secondaryToothCount = 0; toothOneTime = 0; toothOneMinusOneTime = 0; - MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * (1U + 1U)); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + MAX_STALL_TIME = (uint32_t)((MICROS_PER_DEG_1_RPM/50UL) * triggerToothAngle * (1UL + 1UL)); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) #ifdef USE_LIBDIVIDE divTriggerToothAngle = libdivide::libdivide_s16_gen(triggerToothAngle); #endif @@ -4515,8 +4489,8 @@ void triggerSetup_DRZ400(void) triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth if(configPage4.TrigSpeed == 1) { triggerToothAngle = 720 / configPage4.triggerTeeth; } //Account for cam speed toothCurrentCount = UINT8_MAX; //Default value - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * configPage4.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 2U)); //Same as above, but fixed at 2 teeth on the secondary input + triggerFilterTime = MIN_REVOLUTION_TIME / configPage4.triggerTeeth; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = MIN_REVOLUTION_TIME / 2UL; //Same as above, but fixed at 2 teeth on the secondary input BIT_CLEAR(decoderState, BIT_DECODER_2ND_DERIV); BIT_SET(decoderState, BIT_DECODER_IS_SEQUENTIAL); BIT_SET(decoderState, BIT_DECODER_TOOTH_ANG_CORRECT); //This is always true for this pattern @@ -4570,19 +4544,19 @@ void triggerSetup_NGC(void) //Primary trigger configPage4.triggerTeeth = 36; //The number of teeth on the wheel incl missing teeth. triggerToothAngle = 10; //The number of degrees that passes from tooth to tooth - triggerFilterTime = MICROS_PER_SEC / (MAX_RPM/60U) / (360U/triggerToothAngle); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / (360UL/triggerToothAngle); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise toothCurrentCount = 0; toothOneTime = 0; toothOneMinusOneTime = 0; toothLastMinusOneToothTime = 0; toothLastToothRisingTime = 0; - MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2U ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2UL ); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) //Secondary trigger if (configPage2.nCylinders == 4) { - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM/60U) / (360U/36U) * 2U); //Two nearest edges are 36 degrees apart. Multiply by 2 for half cam speed. + triggerSecFilterTime = MIN_REVOLUTION_TIME / (360UL/36UL) * 2UL; //Two nearest edges are 36 degrees apart. Multiply by 2 for half cam speed. } else { - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM/60U) / (360U/21U) * 2U); //Two nearest edges are 21 degrees apart. Multiply by 2 for half cam speed. + triggerSecFilterTime = MIN_REVOLUTION_TIME / (360UL/21UL) * 2UL; //Two nearest edges are 21 degrees apart. Multiply by 2 for half cam speed. } secondaryToothCount = 0; toothSystemCount = 0; @@ -5042,7 +5016,7 @@ uint16_t getRPM_Vmax(void) { noInterrupts(); tempToothAngle = triggerToothAngle; - SetRevolutionTime(toothOneTime - toothOneMinusOneTime); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) + setRevolutionTime(toothOneTime - toothOneMinusOneTime, currentStatus); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) toothTime = (toothLastToothTime - toothLastMinusOneToothTime); interrupts(); toothTime = toothTime * 36; @@ -5108,7 +5082,7 @@ void triggerSetup_Renix(void) configPage4.triggerTeeth = 4; // wheel has 44 teeth but we use these to work out which tooth angle to use, therefore speeduino thinks we only have 8 teeth. configPage4.triggerMissingTeeth = 0; triggerActualTeeth = 4; //The number of teeth we're pretending physically existing on the wheel. - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 44U)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 44UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise } else if (configPage2.nCylinders == 6) { @@ -5116,7 +5090,7 @@ void triggerSetup_Renix(void) configPage4.triggerTeeth = 6; // wheel has 44 teeth but we use these to work out which tooth angle to use, therefore speeduino thinks we only have 6 teeth. configPage4.triggerMissingTeeth = 0; triggerActualTeeth = 6; //The number of teeth we're pretending physically existing on the wheel. - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 66U)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerFilterTime = MIN_REVOLUTION_TIME / 66UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise } MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle); //Minimum 50rpm. (3333uS is the time per degree at 50rpm). Largest gap between teeth is 90 or 60 degrees depending on decoder. @@ -5271,8 +5245,8 @@ void triggerSetup_RoverMEMS() for(toothOneTime = 0; toothOneTime < 10; toothOneTime++) // repurpose variable temporarily to help clear ToothAngles. { toothAngles[toothOneTime] = 0; }// Repurpose ToothAngles to store data needed for this implementation. - triggerFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U * 36U)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise - triggerSecFilterTime = (MICROS_PER_SEC / (MAX_RPM / 60U)); // only 1 tooth on the wheel not 36 + triggerFilterTime = MIN_REVOLUTION_TIME / 36UL; //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be discarded as noise + triggerSecFilterTime = MIN_REVOLUTION_TIME; // only 1 tooth on the wheel not 36 configPage4.triggerTeeth = 36; triggerToothAngle = 360 / configPage4.triggerTeeth; //The number of degrees that passes from tooth to tooth 360 / 36 theortical teeth @@ -5285,7 +5259,7 @@ void triggerSetup_RoverMEMS() toothOneMinusOneTime = 0; revolutionOne=0; - MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2U); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) + MAX_STALL_TIME = ((MICROS_PER_DEG_1_RPM/50U) * triggerToothAngle * 2UL); //Minimum 50rpm. (3333uS is the time per degree at 50rpm) BIT_SET(decoderState, BIT_DECODER_HAS_SECONDARY); } @@ -5912,7 +5886,8 @@ uint16_t getRPM_SuzukiK6A(void) uint16_t tempRPM = stdGetRPM(CAM_SPEED); - MAX_STALL_TIME = revolutionTime << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this + tempRPM = stdGetRPM(720); + MAX_STALL_TIME = getRevolutionTime(currentStatus) << 1; //Set the stall time to be twice the current RPM. This is a safe figure as there should be no single revolution where this changes more than this if(MAX_STALL_TIME < 366667UL) { MAX_STALL_TIME = 366667UL; } //Check for 50rpm minimum return tempRPM; diff --git a/speeduino/globals.cpp b/speeduino/globals.cpp index 4989f2fbc4..2ea6f738c0 100644 --- a/speeduino/globals.cpp +++ b/speeduino/globals.cpp @@ -102,7 +102,6 @@ volatile PINMASK_TYPE triggerThird_pin_mask; byte fpPrimeTime = 0; ///< The time (in seconds, based on @ref statuses.secl) that the fuel pump started priming uint8_t softLimitTime = 0; //The time (in 0.1 seconds, based on seclx10) that the soft limiter started volatile uint16_t mainLoopCount; //Main loop counter (incremented at each main loop rev., used for maintaining currentStatus.loopsPerSecond) -uint32_t revolutionTime; //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) volatile unsigned long timer5_overflow_count = 0; //Increments every time counter 5 overflows. Used for the fast version of micros() volatile unsigned long ms_counter = 0; //A counter that increments once per ms uint16_t fixedCrankingOverride = 0; diff --git a/speeduino/globals.h b/speeduino/globals.h index 01675f148c..70720ee91a 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -38,9 +38,9 @@ #define CRANK_ANGLE_MAX (max(CRANK_ANGLE_MAX_IGN, CRANK_ANGLE_MAX_INJ)) -#define MICROS_PER_SEC INT32_C(1000000) -#define MICROS_PER_MIN INT32_C(MICROS_PER_SEC*60U) -#define MICROS_PER_HOUR INT32_C(MICROS_PER_MIN*60U) +#define MICROS_PER_SEC UINT32_C(1000000) +#define MICROS_PER_MIN (MICROS_PER_SEC*60UL) +#define MICROS_PER_HOUR (MICROS_PER_MIN*60UL) #define SERIAL_PORT_PRIMARY 0 #define SERIAL_PORT_SECONDARY 3 @@ -435,7 +435,6 @@ extern byte triggerInterrupt3; extern byte fpPrimeTime; //The time (in seconds, based on currentStatus.secl) that the fuel pump started priming extern uint8_t softLimitTime; //The time (in 0.1 seconds, based on seclx10) that the soft limiter started extern volatile uint16_t mainLoopCount; -extern uint32_t revolutionTime; //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that) extern volatile unsigned long timer5_overflow_count; //Increments every time counter 5 overflows. Used for the fast version of micros() extern volatile unsigned long ms_counter; //A counter that increments once per ms extern uint16_t fixedCrankingOverride; @@ -597,6 +596,14 @@ struct statuses { byte outputsStatus; byte TS_SD_Status; //TunerStudios SD card status byte airConStatus; + + /** + * @brief The crank revolution time in µS (for one 360° revolution). + * + * Will be between MIN_REVOLUTION_TIME & MAX_REVOLUTION_TIME + * @warning Do not set this directly. Instead use the setRevolutionTime() function. + */ + uint32_t revolutionTime; }; /** diff --git a/speeduino/maths.h b/speeduino/maths.h index 079d12e2e5..6df9664768 100644 --- a/speeduino/maths.h +++ b/speeduino/maths.h @@ -92,6 +92,9 @@ uint8_t random1to100(void); */ #define UDIV_ROUND_CLOSEST(n, d, t) ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d)) +/** @brief Rounding up \em unsigned integer division */ +#define UDIV_ROUND_UP(n, d, t) ((t)((n) + (t)((d)+1U))/(t)(d)) + ///@} /** @brief Test whether the parameter is an integer or not. */ diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 66fa172893..f3b1c643c8 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -57,7 +57,7 @@ uint16_t staged_req_fuel_mult_sec = 0; TESTABLE_INLINE_STATIC uint16_t calculatePWLimit(void) { - uint32_t tempLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution + uint32_t tempLimit = percentage(configPage2.dutyLim, getRevolutionTime(currentStatus)); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution //Handle multiple squirts per rev if (configPage2.strokes == FOUR_STROKE) { tempLimit = tempLimit * 2; } //Optimise for power of two divisions where possible diff --git a/test/test_fuel/test_PW.cpp b/test/test_fuel/test_PW.cpp index 4577eecdde..95248a216c 100644 --- a/test/test_fuel/test_PW.cpp +++ b/test/test_fuel/test_PW.cpp @@ -159,7 +159,7 @@ void test_PW_Limit_90pct(void) { test_PW_setCommon(); - revolutionTime = 10000UL; //6000 rpm + setRevolutionTime(10000UL, currentStatus); //6000 rpm configPage2.dutyLim = 90; //Duty limit of 90% for 10,000uS should give 9,000 @@ -172,7 +172,7 @@ void test_PW_Limit_Long_Revolution(void) { test_PW_setCommon(); - revolutionTime = 100000UL; //600 rpm, below 915rpm cutover point + setRevolutionTime(100000UL, currentStatus); //600 rpm, below 915rpm cutover point configPage2.dutyLim = 90; configPage2.strokes = TWO_STROKE; currentStatus.nSquirts = 1U; diff --git a/test/test_ign/test_corrections.cpp b/test/test_ign/test_corrections.cpp index a14359c3d7..67fff68dfe 100644 --- a/test/test_ign/test_corrections.cpp +++ b/test/test_ign/test_corrections.cpp @@ -1,10 +1,10 @@ #include #include "globals.h" #include "corrections.h" -// #include "init.h" #include "idle.h" #include "../test_utils.h" #include "sensors.h" +#include "crankMaths.h" extern void construct2dTables(void); @@ -776,7 +776,8 @@ static void setup_correctionsDwell(void) { currentStatus.actualDwell = 770; currentStatus.battery10 = 95; - revolutionTime = 666; + setRevolutionTime(MIN_REVOLUTION_TIME, currentStatus); + TEST_ASSERT_TRUE(setRevolutionTime(6660, currentStatus)); TEST_DATA_P uint8_t bins[] = { 60, 70, 80, 90, 100, 110 }; TEST_DATA_P uint8_t values[] = { 130, 125, 120, 115, 110, 90 }; @@ -790,18 +791,18 @@ static void test_correctionsDwell_nopertooth(void) { configPage2.nCylinders = 8; configPage4.sparkMode = IGN_MODE_WASTED; - TEST_ASSERT_EQUAL(296, correctionsDwell(800)); + TEST_ASSERT_EQUAL(5920, correctionsDwell(8000)); configPage4.sparkMode = IGN_MODE_SINGLE; - TEST_ASSERT_EQUAL(74, correctionsDwell(800)); + TEST_ASSERT_EQUAL(1480, correctionsDwell(8000)); configPage4.sparkMode = IGN_MODE_ROTARY; configPage10.rotaryType = ROTARY_IGN_RX8; - TEST_ASSERT_EQUAL(296, correctionsDwell(800)); + TEST_ASSERT_EQUAL(5920, correctionsDwell(8000)); configPage4.sparkMode = IGN_MODE_ROTARY; configPage10.rotaryType = ROTARY_IGN_FC; - TEST_ASSERT_EQUAL(74, correctionsDwell(800)); + TEST_ASSERT_EQUAL(1480, correctionsDwell(8000)); } static void test_correctionsDwell_pertooth(void) { @@ -813,10 +814,10 @@ static void test_correctionsDwell_pertooth(void) { configPage4.sparkMode = IGN_MODE_WASTED; currentStatus.actualDwell = 200; - TEST_ASSERT_EQUAL(444, correctionsDwell(800)); + TEST_ASSERT_EQUAL(6390, correctionsDwell(8000)); currentStatus.actualDwell = 1400; - TEST_ASSERT_EQUAL(296, correctionsDwell(800)); + TEST_ASSERT_EQUAL(6360, correctionsDwell(8000)); } static void test_correctionsDwell_wasted_nopertooth_largerevolutiontime(void) { @@ -824,16 +825,16 @@ static void test_correctionsDwell_wasted_nopertooth_largerevolutiontime(void) { currentStatus.dwellCorrection = 55; currentStatus.battery10 = 105; - revolutionTime = 5000; - TEST_ASSERT_EQUAL(800, correctionsDwell(800)); + setRevolutionTime(5000, currentStatus); + TEST_ASSERT_EQUAL(4445, correctionsDwell(8000)); } static void test_correctionsDwell_initialises_current_actualDwell(void) { setup_correctionsDwell(); currentStatus.actualDwell = 0; - correctionsDwell(777); - TEST_ASSERT_EQUAL(777, currentStatus.actualDwell); + correctionsDwell(7770); + TEST_ASSERT_EQUAL(7770, currentStatus.actualDwell); } static void test_correctionsDwell_sets_dwellCorrection(void) { @@ -841,7 +842,7 @@ static void test_correctionsDwell_sets_dwellCorrection(void) { currentStatus.dwellCorrection = UINT8_MAX; currentStatus.battery10 = 90; - correctionsDwell(777); + correctionsDwell(7770); TEST_ASSERT_EQUAL(115, currentStatus.dwellCorrection); } @@ -851,10 +852,10 @@ static void test_correctionsDwell_uses_batvcorrection(void) { configPage4.sparkMode = IGN_MODE_WASTED; currentStatus.battery10 = 105; - TEST_ASSERT_EQUAL(296, correctionsDwell(800)); + TEST_ASSERT_EQUAL(5920, correctionsDwell(8000)); currentStatus.battery10 = 65; - TEST_ASSERT_EQUAL(337, correctionsDwell(800)); + TEST_ASSERT_EQUAL(6068, correctionsDwell(8000)); } static void test_correctionsDwell(void) { diff --git a/test/test_math/test_division.cpp b/test/test_math/test_division.cpp index 4354d256ee..8ea1cdc79f 100644 --- a/test/test_math/test_division.cpp +++ b/test/test_math/test_division.cpp @@ -98,8 +98,8 @@ void test_maths_div360(void) test_div360((10000000UL+180UL)+1UL); test_div360(10000000UL+360UL); - test_div360((360UL*MICROS_PER_DEG_1_RPM)/MAX_RPM); // Min revolution time - test_div360((360UL*MICROS_PER_DEG_1_RPM)/MIN_RPM); // Max revolution time + test_div360(MIN_REVOLUTION_TIME); // Min revolution time + test_div360(MAX_REVOLUTION_TIME); // Max revolution time } void assert_udiv_32_16(uint32_t dividend, uint16_t divisor) { diff --git a/test/test_math/tests_crankmaths.cpp b/test/test_math/tests_crankmaths.cpp index 7d000bce7a..c697a35905 100644 --- a/test/test_math/tests_crankmaths.cpp +++ b/test/test_math/tests_crankmaths.cpp @@ -3,10 +3,7 @@ #include "decoders.h" #include "../test_utils.h" -extern void SetRevolutionTime(uint32_t revTime); - struct crankmaths_rev_testdata { - uint16_t rpm; unsigned long revolutionTime; uint16_t angle; unsigned long expected; @@ -14,7 +11,7 @@ struct crankmaths_rev_testdata { void test_crankmaths_angletotime_revolution_execute() { crankmaths_rev_testdata *testdata = crankmaths_rev_testdata_current; - SetRevolutionTime(testdata->revolutionTime); + setRevolutionTime(testdata->revolutionTime, currentStatus); TEST_ASSERT_INT32_WITHIN(1, testdata->expected, angleToTimeMicroSecPerDegree(testdata->angle)); } @@ -44,20 +41,23 @@ void testCrankMaths() char testName[testNameLength]; const crankmaths_rev_testdata crankmaths_rev_testdatas[] = { - { .rpm = 50, .revolutionTime = 1200000, .angle = 0, .expected = 0 }, - { .rpm = 50, .revolutionTime = 1200000, .angle = 25, .expected = 83333 }, // 83333,3333 - { .rpm = 50, .revolutionTime = 1200000, .angle = 720, .expected = 2400000 }, - { .rpm = 2500, .revolutionTime = 24000, .angle = 0, .expected = 0 }, - { .rpm = 2500, .revolutionTime = 24000, .angle = 25, .expected = 1667 }, // 1666,6666 - { .rpm = 2500, .revolutionTime = 24000, .angle = 720, .expected = 48000 }, - { .rpm = 20000, .revolutionTime = 3000, .angle = 0, .expected = 0 }, - { .rpm = 20000, .revolutionTime = 3000, .angle = 25, .expected = 208 }, // 208,3333 - { .rpm = 20000, .revolutionTime = 3000, .angle = 720, .expected = 6000 } + { .revolutionTime = 1200000, .angle = 0, .expected = 0 }, + { .revolutionTime = 1200000, .angle = 25, .expected = 83333 }, // 83333,3333 + { .revolutionTime = 1200000, .angle = 720, .expected = 2400000 }, + { .revolutionTime = 24000, .angle = 0, .expected = 0 }, + { .revolutionTime = 24000, .angle = 25, .expected = 1667 }, // 1666,6666 + { .revolutionTime = 24000, .angle = 720, .expected = 48000 }, + { .revolutionTime = MIN_REVOLUTION_TIME, .angle = 0, .expected = 0 }, + { .revolutionTime = MIN_REVOLUTION_TIME, .angle = 25, .expected = 231 }, // 208,3333 + { .revolutionTime = MIN_REVOLUTION_TIME, .angle = 720, .expected = 6666 }, + { .revolutionTime = MAX_REVOLUTION_TIME-1, .angle = 0, .expected = 0 }, + { .revolutionTime = MAX_REVOLUTION_TIME-1, .angle = 25, .expected = 101626 }, // 208,3333 + { .revolutionTime = MAX_REVOLUTION_TIME-1, .angle = 720, .expected = 2926825 } }; for (auto testdata : crankmaths_rev_testdatas) { crankmaths_rev_testdata_current = &testdata; - snprintf(testName, testNameLength, "crankmaths/angletotime/revolution/%urpm/%uangle", testdata.rpm, testdata.angle); + snprintf(testName, testNameLength, "crankmaths/angletotime/revolution/%urpm/%uangle", (unsigned int)(MICROS_PER_MIN/testdata.revolutionTime), testdata.angle); UnityDefaultTestRun(test_crankmaths_angletotime_revolution_execute, testName, __LINE__); } diff --git a/test/test_schedule_calcs/test_ign_calcs.cpp b/test/test_schedule_calcs/test_ign_calcs.cpp index a33d9bfd96..6d406fbd0b 100644 --- a/test/test_schedule_calcs/test_ign_calcs.cpp +++ b/test/test_schedule_calcs/test_ign_calcs.cpp @@ -8,14 +8,12 @@ #define _countof(x) (sizeof(x) / sizeof (x[0])) -extern void SetRevolutionTime(uint32_t revTime); - constexpr uint16_t DWELL_TIME_MS = 4; uint16_t dwellAngle; void setEngineSpeed(uint16_t rpm, int16_t max_crank) { - SetRevolutionTime(UDIV_ROUND_CLOSEST(60UL*1000000UL, rpm, uint32_t)); + setRevolutionTime(UDIV_ROUND_CLOSEST(60UL*1000000UL, rpm, uint32_t), currentStatus); CRANK_ANGLE_MAX_IGN = max_crank; CRANK_ANGLE_MAX_INJ = max_crank; dwellAngle = timeToAngleDegPerMicroSec(DWELL_TIME_MS*1000UL); @@ -66,7 +64,7 @@ static void test_calc_ign_timeout_360() { setEngineSpeed(4000, 360); - TEST_ASSERT_EQUAL(15000, revolutionTime); + TEST_ASSERT_EQUAL(15000, getRevolutionTime(currentStatus)); TEST_ASSERT_EQUAL(96, dwellAngle); // Expected test values were generated using floating point calculations (in Excel)