diff --git a/reference/speeduino.ini b/reference/speeduino.ini index 24782145..b82674d9 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -1405,7 +1405,38 @@ page = 15 unused15_1_3 = bits, U08, 80, [7:7], "False", "INVALID" boostDCWhenDisabled = scalar, U08, 81, "%", 1, 0, 0, 100, 0 boostControlEnableThreshold = scalar, U08, 82, "kpa", 1, 0.0, 0.0, 255, 0 - unused15_3_176 = array, U08, 83, [173], "%", 1.0, 0.0, 0.0, 255, 0 + + +; Air conditioning control + airConEnable = bits, U08, 83, [0:0], "Off", "On" + airConCompPol = bits, U08, 83, [1:1], "Normal", "Inverted" + airConReqPol = bits, U08, 83, [2:2], "Normal", "Inverted" + airConTurnsFanOn = bits, U08, 83, [3:3], "No", "Yes" + airConFanEnabled = bits, U08, 83, [4:4], "Disabled", "Enabled" + airConFanPol = bits, U08, 83, [5:5], "Normal", "Inverted" + airConUnused1 = bits, U08, 83, [6:7], "0", "1", "2", "3" + airConCompPin = bits, U08, 84, [0:5], "Unused", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID" + airConUnused2 = bits, U08, 84, [6:7], "0", "1", "2", "3" + airConReqPin = bits, U08, 85, [0:5], "Unused", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID" + airConUnused3 = bits, U08, 85, [6:7], "0", "1", "2", "3" + airConTPSCut = scalar, U08, 86, "%", 0.5, 0.0, 0.0, 100.0, 1 + airConMinRPM = scalar, U08, 87, "RPM", 10, 0.0, 0.0, 2550, 0 + airConMaxRPM = scalar, U08, 88, "RPM", 100, 0.0, 0.0, 25500, 0 +#if CELSIUS + airConClTempCut = scalar, U08, 89, "C", 1.0, -40, -40, 215, 0 +#else + airConClTempCut = scalar, U08, 89, "F", 1.8, -22.23, -40, 419, 0 +#endif + airConIdleSteps = scalar, U08, 90, "%/Steps", 1.0, 0.0, 0.0, 255, 0 + airConTPSCutTime = scalar, U08, 91, "s", 0.1, 0.0, 0.0, 25.5, 1 + airConCompOnDelay = scalar, U08, 92, "s", 0.1, 0.0, 0.0, 25.5, 1 + airConAfterStartDelay = scalar, U08, 93, "s", 0.1, 0.0, 0.0, 25.5, 1 + airConRPMCutTime = scalar, U08, 94, "s", 0.1, 0.0, 0.0, 25.5, 1 + airConFanPin = bits, U08, 95, [0:5], "Unused", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID" + airConUnused4 = bits, U08, 95, [6:7], "0", "1", "2", "3" + airConIdleUpRPMAdder = scalar, U08, 96, "Added Target RPM", 10.0, 0.0, 0.0, 250.0, 0 + airConPwmFanMinDuty = scalar, U08, 97, "%", 0.5, 0.0, 0.0, 100.0, 1 + Unused15_98_255 = array, U08, 98, [158], "%", 1.0, 0.0, 0.0, 255, 0 ;------------------------------------------------------------------------------- @@ -1508,6 +1539,15 @@ page = 15 requiresPowerCycle = caninput_sel15b requiresPowerCycle = outputPin + requiresPowerCycle = airConEnable + requiresPowerCycle = airConCompPin + requiresPowerCycle = airConReqPin + requiresPowerCycle = airConFanPin + requiresPowerCycle = airConReqPol + requiresPowerCycle = airConCompPol + requiresPowerCycle = airConFanPol + requiresPowerCycle = airConFanEnabled + defaultValue = pinLayout, 1 defaultValue = TrigPattern, 0 defaultValue = useResync, 1 @@ -1586,6 +1626,8 @@ page = 15 defaultValue = ANGLEFILTER_VVT, 0 defaultValue = idleAdvStartDelay, 0.2 ;0.2S for a quick gear change without change the table advance defaultValue = boostByGearEnabled, 0 + defaultValue = airConIdleUpRPMAdder, 100 + defaultValue = airConPwmFanMinDuty, 80 #if CELSIUS defaultValue = vvtMinClt, 70 #else @@ -1630,6 +1672,30 @@ page = 15 defaultValue = ADCFILTER_BARO, 64 defaultValue = FILTER_FLEX, 75 + ; AirCon Default Values + defaultValue = airConEnable, 0 + defaultValue = airConCompPol, 0 + defaultValue = airConReqPol, 0 + defaultValue = airConTurnsFanOn, 1 + defaultValue = airConCompPin, 0 + defaultValue = airConReqPin, 0 + defaultValue = airConFanPin, 0 + defaultValue = airConFanPol, 0 + defaultValue = airConFanEnabled, 0 + defaultValue = airConTPSCut, 65 + defaultValue = airConMinRPM, 500 + defaultValue = airConMaxRPM, 4700 + defaultValue = airConClTempCut, 120 + defaultValue = airConIdleSteps, 0 + defaultValue = airConTPSCutTime, 5.00 + defaultValue = airConCompOnDelay, 0.4 + defaultValue = airConAfterStartDelay, 5.00 + defaultValue = airConRPMCutTime, 5.00 + + ;Again, force the setting from the controller for the trigger edges. This is particularly useful for the Oct 2018 update where the names of the edges changed + controllerPriority = TrigEdge + controllerPriority = TrigEdgeSec + ;VSS Ratios and calibration need controller priority so they can be set with the command buttons controllerPriority = vssPulsesPerKm controllerPriority = vssRatio1 @@ -1840,6 +1906,7 @@ menuDialog = main subMenu = fuelpump, "Fuel Pump" subMenu = NitrousControl, "Nitrous" subMenu = vssSettings, "VSS and Gear detection" + subMenu = airCon, "Air Conditioning Control" subMenu = std_separator subMenu = boostSettings, "Boost Control" subMenu = boostLoad, "Boost Targets/Duty", 8, { boostEnabled } @@ -1954,6 +2021,27 @@ menuDialog = main fanPin = "The Arduino pin that the fan control signal will output on. This is NOT necessarily the same as the connector pin on any particular board" fanSP = "The trigger temperature for the fan. Fan will be enabled above this temp" + airConEnable = "Whether we are doing A/C control" + airConCompPol = "Normal should be used in most cases - where a logic HIGH output turns on the output power transistor, which is the ON state. Inverted makes logic LOW the ON state, in the rare case that turning off the transistor turns the compressor on, or you are using some sort of depletion mode FET". + airConReqPol = "Normal should be used in most cases - where the A/C button provides a ground when pressed. Inverted removes the internal pullup resistor, and makes +5V the ON signal instead of ground." + airConTurnsFanOn = "Whether the cooling fan turns on when the A/C compressor is running." + airConCompPin = "The Arduino pin that the A/C request compressor signal is output on. This is NOT necesarrily the same as the connector pin on any particlar board." + airConReqPin = "The Arduino pin that the A/C request control signal is input on. This is NOT necesarrily the same as the connector pin on any particlar board." + airConFanPin = "The Arduino pin that the A/C fan control signal is output on (if enabled). This is only needed if you have a stand-alone A/C fan, separate to the cooling fan (which can be enabled to come on with the A/C compressor). This is NOT necesarrily the same as the connector pin on any particlar board." + airConFanPol = "Normal should be used in most cases - where a logic HIGH output turns on the output power transistor, which is the ON state. Inverted makes logic LOW the ON state, in the rare case that turning off the transistor turns the fan on, or you are using some sort of depletion mode FET". + airConFanEnabled = "Enable/disable stand-alone A/C fan. This would be a separate fan that only comes on when the A/C compressor is engaged, and should not be needed if the main cooling fan comes on with the A/C." + airConTPSCut = "The TPS position at which the air compressor will be locked out and turn off. When TPS falls below this level (minus a 5% hysteresis), the A/C compressor will kick back in after the delay period (TPS Cut Time), provided the A/C request signal is still present." + airConMinRPM = "The minimum RPM at which we will allow the A/C compressor to run (this setting is in 10 RPM steps)." + airConMaxRPM = "The maximum RPM at which we will allow the A/C compressor to run (this setting is in 100 RPM steps)." + airConClTempCut = "The coolant temperature above which we will NOT allow the A/C compressor to run." + airConIdleSteps = "Increase the idle PWM (%) or stepper motor (steps) up by this amount when the A/C request is active. Note that some cars have a separate idle-up valve that switches on automatically in tandem with the A/C compressor. In this case, this setting might be set to zero." + airConTPSCutTime = "The TPS lockout time, for which the A/C compressor will not run after a high TPS condition has gone away. This prevents the compressor cutting in on gear changes if the car is being driven hard." + airConCompOnDelay = "The delay period between a successful A/C request signal, and the compressor kicking in. This gives the idle-up time to kick in before the compressor loads the engine." + airConAfterStartDelay = "The delay period after first starting the car, during which the A/C compressor will not run." + airConRPMCutTime = "The RPM lockout time, for which the A/C compressor will not run after a high or low RPM condition has gone away. This prevents the compressor cutting in on gear changes if the car is being driven hard, or cutting in to early after nearly stalling the engine." + airConIdleUpRPMAdder = "Increase the idle RPM target (as used by Idle Advance and Closed-Loop Idle) by this amount when the A/C request is active." + airConPwmFanMinDuty = "If you are using a PWM cooling fan, the fan duty will be clamped to this value or higher (based on the coolant temp./duty cycle table) when the A/C compressor is engaged." + vssPulsesPerKm = "The number of pulses on the VSS signal per KM/Mile" vssSmoothing = "A smoothing factor to help reduce noise in the VSS signal. Typical values are between 0 and 50" @@ -2644,6 +2732,43 @@ menuDialog = main dialog = pwmFan, "PWM Fan Curve", panel = pwm_fan_curve, + dialog = airConIdleUp, "Idle Up When A/C Compressor On" + field = "Idle-Up Amount", airConIdleSteps, { airConEnable } + field = "Idle-Up RPM Adder", airConIdleUpRPMAdder, { airConEnable } + + dialog = airConRPMLimit,"RPM Limiting" + field = "Min. RPM for A/C Operation", airConMinRPM, { airConEnable } + field = "Max. RPM for A/C Operation", airConMaxRPM, { airConEnable } + field = "Lockout time after high/low RPM", airConRPMCutTime, { airConEnable } + + dialog = airConTPSLimit,"TPS Limiting" + field = "Cut A/C at TPS Position", airConTPSCut, { airConEnable } + field = "Lockout time after high TPS", airConTPSCutTime, { airConEnable } + + dialog = airConCoolantTempLimit,"Coolant Temp. Limiting" + field = "Coolant A/C Cutout Temp.", airConClTempCut, { airConEnable } + + dialog = airConFanSettings + field = "Run Engine Cooling Fan with A/C", airConTurnsFanOn, { airConEnable } + field = "Min. Duty for PWM Cooling Fan", airConPwmFanMinDuty, { airConEnable } + field = "Stand-Alone A/C Fan", airConFanEnabled, { airConEnable } + field = "Stand-Alone A/C Fan Output Pin", airConFanPin, { airConEnable && airConFanEnabled } + field = "Stand-Alone A/C Fan Output Polarity", airConFanPol, {airConEnable && airConFanEnabled } + + dialog = airCon,"Air Conditioning" + field = "Air Conditioning Enable", airConEnable + field = "A/C Request Input Pin", airConReqPin, { airConEnable } + field = "A/C Compressor Output Pin", airConCompPin, { airConEnable } + field = "A/C Request Input Polarity", airConReqPol, { airConEnable } + field = "A/C Comp. Output Polarity", airConCompPol, { airConEnable } + field = "A/C Comp. On Delay (During Operation)", airConCompOnDelay, { airConEnable } + field = "A/C Initial Delay After Cranking", airConAfterStartDelay, { airConEnable } + panel = airConRPMLimit + panel = airConTPSLimit + panel = airConCoolantTempLimit + panel = airConFanSettings + panel = airConIdleUp + dialog = stepper_idle, "Stepper Idle" field = "Step time (ms)", iacStepTime, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } field = "Cool time (ms)", iacCoolTime, { iacAlgorithm == 4 || iacAlgorithm == 5 || iacAlgorithm == 7 } @@ -4988,6 +5113,11 @@ cmdVSSratio6 = "E\x99\x06" indicator = { outputsStatus6 }, "Programmable out 7 Off", "Programmable out 7 ON", white, black, green, black indicator = { outputsStatus7 }, "Programmable out 8 Off", "Programmable out 8 ON", white, black, green, black + ;AC stuff + indicator = { airConRequest }, "A/C Request OFF", "A/C Request ON", white, black, green, black + indicator = { airConCompressor }, "A/C Comp OFF", "A/C Comp ON", white, black, green, black + indicator = { airConFanStatus }, "A/C Fan OFF", "A/C Fan ON", white, black, green, black + ;sd card indicators indicator = { sd_status & 1}, "No SD Card", "SD Present", white, black, green, black indicator = { sd_status & 4}, "SD ready", "SD ready", white, black, green, black @@ -5003,7 +5133,7 @@ cmdVSSratio6 = "E\x99\x06" ; you change it. ochGetCommand = "r\$tsCanId\x30%2o%2c" - ochBlockSize = 122 + ochBlockSize = 123 secl = scalar, U08, 0, "sec", 1.000, 0.000 status1 = scalar, U08, 1, "bits", 1.000, 0.000 @@ -5148,9 +5278,19 @@ cmdVSSratio6 = "E\x99\x06" sd_status = scalar, U08, 118, "", 1.0, 0.0 emap = scalar, U16, 119, "kpa", 1.000, 0.000 fanDuty = scalar, U08, 121, "%", 0.5, 0.000 - ;sd_filenum = scalar, U16, 122, "", 1, 0 - ;sd_error = scalar, U08, 124, "", 1, 0 - ;sd_phase = scalar, U08, 125, "", 1, 0 + airConStatus = scalar, U08, 122, "bits", 1.000, 0.000 + airConRequest = bits, U08, 122, [0:0] + airConCompressor = bits, U08, 122, [1:1] + airConRPMMLockout = bits, U08, 122, [2:2] + airConTPSLockout = bits, U08, 122, [3:3] + airConTurningOn = bits, U08, 122, [4:4] + airConCLTLockout = bits, U08, 122, [5:5] + airConFanStatus = bits, U08, 122, [6:6] + airConUnusedBits = bits, U08, 122, [7:7] + ;sd_filenum = scalar, U16, 123, "", 1, 0 + ;sd_error = scalar, U08, 125, "", 1, 0 + ;sd_phase = scalar, U08, 126, "", 1, 0 + #if CELSIUS coolant = { coolantRaw - 40 } ; Temperature readings are offset by 40 to allow for negatives diff --git a/speeduino/auxiliaries.h b/speeduino/auxiliaries.h index a8ccfaa0..ac9e1b60 100644 --- a/speeduino/auxiliaries.h +++ b/speeduino/auxiliaries.h @@ -10,10 +10,17 @@ void boostByGear(); void idleControl(); void vvtControl(); void initialiseFan(); +void initialiseAirCon(); void nitrousControl(); void fanControl(); +void airConControl(); +bool READ_AIRCON_REQUEST(); void wmiControl(); +static inline void checkAirConCoolantLockout(); +static inline void checkAirConTPSLockout(); +static inline void checkAirConRPMLockout(); + #define SIMPLE_BOOST_P 1 #define SIMPLE_BOOST_I 1 #define SIMPLE_BOOST_D 1 @@ -31,6 +38,10 @@ void wmiControl(); #define N2O_STAGE1_PIN_HIGH() (digitalWrite(configPage10.n2o_stage1_pin, HIGH)) #define N2O_STAGE2_PIN_LOW() (digitalWrite(configPage10.n2o_stage2_pin, LOW)) #define N2O_STAGE2_PIN_HIGH() (digitalWrite(configPage10.n2o_stage2_pin, HIGH)) +#define AIRCON_PIN_LOW() (digitalWrite(pinAirConComp, LOW)) +#define AIRCON_PIN_HIGH() (digitalWrite(pinAirConComp, HIGH)) +#define AIRCON_FAN_PIN_LOW() (digitalWrite(pinAirConFan, LOW)) +#define AIRCON_FAN_PIN_HIGH() (digitalWrite(pinAirConFan, HIGH)) #else #define BOOST_PIN_LOW() *boost_pin_port &= ~(boost_pin_mask) #define BOOST_PIN_HIGH() *boost_pin_port |= (boost_pin_mask) @@ -44,15 +55,24 @@ void wmiControl(); #define N2O_STAGE1_PIN_HIGH() *n2o_stage1_pin_port |= (n2o_stage1_pin_mask) #define N2O_STAGE2_PIN_LOW() *n2o_stage2_pin_port &= ~(n2o_stage2_pin_mask) #define N2O_STAGE2_PIN_HIGH() *n2o_stage2_pin_port |= (n2o_stage2_pin_mask) +#define AIRCON_PIN_LOW() *aircon_comp_pin_port &= ~(aircon_comp_pin_mask) +#define AIRCON_PIN_HIGH() *aircon_comp_pin_port |= (aircon_comp_pin_mask) +#define AIRCON_FAN_PIN_LOW() *aircon_fan_pin_port &= ~(aircon_fan_pin_mask) +#define AIRCON_FAN_PIN_HIGH() *aircon_fan_pin_port |= (aircon_fan_pin_mask) #endif #define READ_N2O_ARM_PIN() ((*n2o_arming_pin_port & n2o_arming_pin_mask) ? true : false) + +#define AIRCON_ON() {((((configPage15.airConCompPol&1)==1)) ? AIRCON_PIN_LOW() : AIRCON_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR);} +#define AIRCON_OFF() {((((configPage15.airConCompPol&1)==1)) ? AIRCON_PIN_HIGH() : AIRCON_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR);} +#define AIRCON_FAN_ON() {((((configPage15.airConFanPol&1)==1)) ? AIRCON_FAN_PIN_LOW() : AIRCON_FAN_PIN_HIGH()); BIT_SET(currentStatus.airConStatus, BIT_AIRCON_FAN);} +#define AIRCON_FAN_OFF() {((((configPage15.airConFanPol&1)==1)) ? AIRCON_FAN_PIN_HIGH() : AIRCON_FAN_PIN_LOW()); BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_FAN);} + #define VVT1_PIN_ON() VVT1_PIN_HIGH(); #define VVT1_PIN_OFF() VVT1_PIN_LOW(); #define VVT2_PIN_ON() VVT2_PIN_HIGH(); #define VVT2_PIN_OFF() VVT2_PIN_LOW(); - #define VVT_TIME_DELAY_MULTIPLIER 50 #define FAN_ON() ((configPage6.fanInv) ? FAN_PIN_LOW() : FAN_PIN_HIGH()) @@ -74,6 +94,12 @@ volatile PORT_TYPE *n2o_stage2_pin_port; volatile PINMASK_TYPE n2o_stage2_pin_mask; volatile PORT_TYPE *n2o_arming_pin_port; volatile PINMASK_TYPE n2o_arming_pin_mask; +volatile PORT_TYPE *aircon_comp_pin_port; +volatile PINMASK_TYPE aircon_comp_pin_mask; +volatile PORT_TYPE *aircon_fan_pin_port; +volatile PINMASK_TYPE aircon_fan_pin_mask; +volatile PORT_TYPE *aircon_req_pin_port; +volatile PINMASK_TYPE aircon_req_pin_mask; volatile bool boost_pwm_state; unsigned int boost_pwm_max_count; //Used for variable PWM frequency @@ -111,5 +137,12 @@ long vvt2_pid_current_angle; void boostInterrupt(); void vvtInterrupt(); +bool acIsEnabled; +bool acStandAloneFanIsEnabled; +uint8_t acStartDelay; +uint8_t acTPSLockoutDelay; +uint8_t acRPMLockoutDelay; +uint8_t acAfterEngineStartDelay; +bool waitedAfterCranking; // This starts false and prevents the A/C from running until a few seconds after cranking -#endif +#endif \ No newline at end of file diff --git a/speeduino/auxiliaries.ino b/speeduino/auxiliaries.ino index 60b07633..afcc0af8 100644 --- a/speeduino/auxiliaries.ino +++ b/speeduino/auxiliaries.ino @@ -16,6 +16,234 @@ integerPID_ideal boostPID(¤tStatus.MAP, ¤tStatus.boostDuty , ¤ integerPID vvtPID(&vvt_pid_current_angle, ¤tStatus.vvt1Duty, &vvt_pid_target_angle, configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD, configPage6.vvtPWMdir); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call integerPID vvt2PID(&vvt2_pid_current_angle, ¤tStatus.vvt2Duty, &vvt2_pid_target_angle, configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD, configPage4.vvt2PWMdir); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call + +/* +Air Conditioning Control +*/ +void initialiseAirCon() +{ + if( (configPage15.airConEnable&1) == 1 && + pinAirConRequest != 0 && + pinAirConComp != 0 ) + { + // Hold the A/C off until a few seconds after cranking + acAfterEngineStartDelay = 0; + waitedAfterCranking = false; + + acStartDelay = 0; + acTPSLockoutDelay = 0; + acRPMLockoutDelay = 0; + + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_REQUEST); // Bit 0 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_COMPRESSOR); // Bit 1 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_RPM_LOCKOUT); // Bit 2 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_TPS_LOCKOUT); // Bit 3 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON); // Bit 4 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_CLT_LOCKOUT); // Bit 5 + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_FAN); // Bit 6 + aircon_req_pin_port = portInputRegister(digitalPinToPort(pinAirConRequest)); + aircon_req_pin_mask = digitalPinToBitMask(pinAirConRequest); + aircon_comp_pin_port = portOutputRegister(digitalPinToPort(pinAirConComp)); + aircon_comp_pin_mask = digitalPinToBitMask(pinAirConComp); + + AIRCON_OFF(); + + if((configPage15.airConFanEnabled > 0) && (pinAirConFan != 0)) + { + aircon_fan_pin_port = portOutputRegister(digitalPinToPort(pinAirConFan)); + aircon_fan_pin_mask = digitalPinToBitMask(pinAirConFan); + AIRCON_FAN_OFF(); + acStandAloneFanIsEnabled = true; + } + else + { + acStandAloneFanIsEnabled = false; + } + + acIsEnabled = true; + + } + else + { + acIsEnabled = false; + } +} + +void airConControl() +{ + if(acIsEnabled == true) + { + // ------------------------------------------------------------------------------------------------------ + // Check that the engine has been running past the post-start delay period before enabling the compressor + // ------------------------------------------------------------------------------------------------------ + if (BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN)) + { + if(acAfterEngineStartDelay >= configPage15.airConAfterStartDelay) + { + waitedAfterCranking = true; + } + else + { + acAfterEngineStartDelay++; + } + } + else + { + acAfterEngineStartDelay = 0; + waitedAfterCranking = false; + } + + // -------------------------------------------------------------------- + // Determine the A/C lockouts based on the noted parameters + // These functions set/clear the globl currentStatus.airConStatus bits. + // -------------------------------------------------------------------- + checkAirConCoolantLockout(); + checkAirConTPSLockout(); + checkAirConRPMLockout(); + + // ----------------------------------------- + // Check the A/C Request Signal (A/C Button) + // ----------------------------------------- + if( READ_AIRCON_REQUEST() == true && + waitedAfterCranking == true && + BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TPS_LOCKOUT) == false && + BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_RPM_LOCKOUT) == false && + BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_CLT_LOCKOUT) == false ) + { + // Set the BIT_AIRCON_TURNING_ON bit to notify the idle system to idle up & the cooling fan to start (if enabled) + BIT_SET(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON); + + // Stand-alone fan operation + if(acStandAloneFanIsEnabled == true) + { + AIRCON_FAN_ON(); + } + + // Start the A/C compressor after the "Compressor On" delay period + if(acStartDelay >= configPage15.airConCompOnDelay) + { + AIRCON_ON(); + } + else + { + acStartDelay++; + } + } + else + { + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON); + + // Stand-alone fan operation + if(acStandAloneFanIsEnabled == true) + { + AIRCON_FAN_OFF(); + } + + AIRCON_OFF(); + acStartDelay = 0; + } + } +} + +bool READ_AIRCON_REQUEST() +{ + if(acIsEnabled == false) + { + return false; + } + // Read the status of the A/C request pin (A/C button), taking into account the pin's polarity + bool acReqPinStatus = ( ((configPage15.airConReqPol&1)==1) ? + !!(*aircon_req_pin_port & aircon_req_pin_mask) : + !(*aircon_req_pin_port & aircon_req_pin_mask)); + BIT_WRITE(currentStatus.airConStatus, BIT_AIRCON_REQUEST, acReqPinStatus); + return acReqPinStatus; +} + +static inline void checkAirConCoolantLockout() +{ + // --------------------------- + // Coolant Temperature Lockout + // --------------------------- + int offTemp = (int)configPage15.airConClTempCut - CALIBRATION_TEMPERATURE_OFFSET; + if (currentStatus.coolant > offTemp) + { + // A/C is cut off due to high coolant + BIT_SET(currentStatus.airConStatus, BIT_AIRCON_CLT_LOCKOUT); + } + else if (currentStatus.coolant < (offTemp - 1)) + { + // Adds a bit of hysteresis (2 degrees) to removing the lockout + // Yes, it is 2 degrees (not 1 degree or 3 degrees) because we go "> offTemp" to enable and "< (offtemp-1)" to disable, + // e.g. if offTemp is 100, it needs to go GREATER than 100 to enable, i.e. 101, and then 98 to disable, + // because the coolant temp is an integer. So 98.5 degrees to 100.5 degrees is the analog null zone where nothing happens, + // depending on sensor calibration and table interpolation. + // Hopefully offTemp wasn't -40... otherwise underflow... but that would be ridiculous + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_CLT_LOCKOUT); + } +} + +static inline void checkAirConTPSLockout() +{ + // ------------------------------ + // High Throttle Position Lockout + // ------------------------------ + if (currentStatus.TPS > configPage15.airConTPSCut) + { + // A/C is cut off due to high TPS + BIT_SET(currentStatus.airConStatus, BIT_AIRCON_TPS_LOCKOUT); + acTPSLockoutDelay = 0; + } + else if ( (BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TPS_LOCKOUT) == true) && + (currentStatus.TPS <= configPage15.airConTPSCut) ) + { + // No need for hysteresis as we have the stand-down delay period after the high TPS condition goes away. + if (acTPSLockoutDelay >= configPage15.airConTPSCutTime) + { + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_TPS_LOCKOUT); + } + else + { + acTPSLockoutDelay++; + } + } + else + { + acTPSLockoutDelay = 0; + } +} + +static inline void checkAirConRPMLockout() +{ + // -------------------- + // High/Low RPM Lockout + // -------------------- + if ( (currentStatus.RPM < (configPage15.airConMinRPMdiv10 * 10)) || + (currentStatus.RPMdiv100 > configPage15.airConMaxRPMdiv100) ) + { + // A/C is cut off due to high/low RPM + BIT_SET(currentStatus.airConStatus, BIT_AIRCON_RPM_LOCKOUT); + acRPMLockoutDelay = 0; + } + else if ( (currentStatus.RPM >= (configPage15.airConMinRPMdiv10 * 10)) && + (currentStatus.RPMdiv100 <= configPage15.airConMaxRPMdiv100) ) + { + // No need to add hysteresis as we have the stand-down delay period after the high/low RPM condition goes away. + if (acRPMLockoutDelay >= configPage15.airConRPMCutTime) + { + BIT_CLEAR(currentStatus.airConStatus, BIT_AIRCON_RPM_LOCKOUT); + } + else + { + acRPMLockoutDelay++; + } + } + else + { + acRPMLockoutDelay = 0; + } +} + + /* Fan control */ @@ -47,12 +275,16 @@ void fanControl() int offTemp = onTemp - configPage6.fanHyster; bool fanPermit = false; + if ( configPage2.fanWhenOff == true) { fanPermit = true; } else { fanPermit = BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN); } - if ( (currentStatus.coolant >= onTemp) && (fanPermit == true) ) + if ( (fanPermit == true) && + ((currentStatus.coolant >= onTemp) || + ((configPage15.airConTurnsFanOn&1) == 1 && + BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true)) ) { - //Fan needs to be turned on. + //Fan needs to be turned on - either by high coolant temp, or from an A/C request (to ensure there is airflow over the A/C radiator). if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && (configPage2.fanWhenCranking == 0)) { //If the user has elected to disable the fan during cranking, make sure it's off @@ -89,7 +321,17 @@ void fanControl() } else { - currentStatus.fanDuty = table2D_getValue(&fanPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //In normal situation read PWM duty from the table + byte tempFanDuty = table2D_getValue(&fanPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //In normal situation read PWM duty from the table + if((configPage15.airConTurnsFanOn&1) == 1 && + BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) + { + // Clamp the fan duty to airConPwmFanMinDuty or above, to ensure there is airflow over the A/C radiator + if(tempFanDuty < configPage15.airConPwmFanMinDuty) + { + tempFanDuty = configPage15.airConPwmFanMinDuty; + } + } + currentStatus.fanDuty = tempFanDuty; #if defined(PWM_FAN_AVAILABLE) fan_pwm_value = halfPercentage(currentStatus.fanDuty, fan_pwm_max_count); //update FAN PWM value last if (currentStatus.fanDuty > 0) diff --git a/speeduino/cancomms.h b/speeduino/cancomms.h index f62829da..a890edde 100644 --- a/speeduino/cancomms.h +++ b/speeduino/cancomms.h @@ -1,7 +1,7 @@ #ifndef CANCOMMS_H #define CANCOMMS_H -#define NEW_CAN_PACKET_SIZE 122 +#define NEW_CAN_PACKET_SIZE 123 #define CAN_PACKET_SIZE 75 #if ( defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ) diff --git a/speeduino/cancomms.ino b/speeduino/cancomms.ino index f5f9806c..8cb85407 100644 --- a/speeduino/cancomms.ino +++ b/speeduino/cancomms.ino @@ -343,6 +343,7 @@ void sendcanValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portTy fullStatus[119] = lowByte(currentStatus.EMAP); //2 bytes for EMAP fullStatus[120] = highByte(currentStatus.EMAP); fullStatus[121] = currentStatus.fanDuty; + fullStatus[122] = currentStatus.airConStatus; for(byte x=0; x 0)) + || ((pin == pinAirConFan) && (configPage15.airConEnable > 0) && (configPage15.airConFanEnabled > 0)) ) { used = true; } diff --git a/speeduino/idle.ino b/speeduino/idle.ino index 066970a3..5fa33b92 100644 --- a/speeduino/idle.ino +++ b/speeduino/idle.ino @@ -473,9 +473,12 @@ void idleControl() //Standard running currentStatus.idleLoad = table2D_getValue(&iacPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees } + // Add air conditioning idle-up - we only do this if the engine is running (A/C should never engage with engine off). + if(configPage15.airConIdleSteps>0 && BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) { currentStatus.idleLoad += configPage15.airConIdleSteps; } } if(currentStatus.idleUpActive == true) { currentStatus.idleLoad += configPage2.idleUpAdder; } //Add Idle Up amount if active + if( currentStatus.idleLoad > 100 ) { currentStatus.idleLoad = 100; } //Safety Check idle_pwm_target_value = percentage(currentStatus.idleLoad, idle_pwm_max_count); @@ -504,17 +507,38 @@ void idleControl() { idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //Multiply the byte target value back out by 10 if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ) ) { idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); } //Re-read the PID settings once per second - + PID_computed = idlePID.Compute(true); + long TEMP_idle_pwm_target_value; if(PID_computed == true) { - idle_pwm_target_value = idle_pid_target_value>>2; //increased resolution - currentStatus.idleLoad = ((unsigned long)(idle_pwm_target_value * 100UL) / idle_pwm_max_count); - if(currentStatus.idleUpActive == true) { currentStatus.idleLoad += configPage2.idleUpAdder; } //Add Idle Up amount if active + TEMP_idle_pwm_target_value = idle_pid_target_value; + + // Add an offset to the duty cycle, outside of the closed loop. When tuned correctly, the extra load from + // the air conditioning should exactly cancel this out and the PID loop will be relatively unaffected. + if(configPage15.airConIdleSteps>0 && BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) + { + // Add air conditioning idle-up + // We are adding percentage steps, but the loop doesn't operate in percentage steps - it works in PWM count + TEMP_idle_pwm_target_value += percentage(configPage15.airConIdleSteps, idle_pwm_max_count<<2); + if(TEMP_idle_pwm_target_value > (idle_pwm_max_count<<2)) { TEMP_idle_pwm_target_value = (idle_pwm_max_count<<2); } + } + // Fixed this by putting it here, however I have not tested it. It used to be after the calculation of idle_pwm_target_value, meaning the percentage would update in currentStatus, but the idle would not actually increase. + if(currentStatus.idleUpActive == true) + { + // Add Idle Up amount if active + // Again, we use configPage15.airConIdleSteps * idle_pwm_max_count / 100 because we are adding percentage steps, but the loop doesn't operate in percentage steps - it works in PWM count + TEMP_idle_pwm_target_value += percentage(configPage2.idleUpAdder, idle_pwm_max_count<<2); + if(TEMP_idle_pwm_target_value > (idle_pwm_max_count<<2)) { TEMP_idle_pwm_target_value = (idle_pwm_max_count<<2); } + } + + // Now assign the real PWM value + idle_pwm_target_value = TEMP_idle_pwm_target_value>>2; //increased resolution + currentStatus.idleLoad = ((unsigned long)(idle_pwm_target_value * 100UL) / idle_pwm_max_count); } idleCounter++; - } + } break; @@ -541,19 +565,39 @@ void idleControl() { //Read the OL table as feedforward term FeedForwardTerm = percentage(table2D_getValue(&iacPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET), idle_pwm_max_count<<2); //All temps are offset by 40 degrees + + // Add an offset to the feed forward term. When tuned correctly, the extra load from the air conditioning + // should exactly cancel this out and the PID loop will be relatively unaffected. + if(configPage15.airConIdleSteps>0 && BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) + { + // Add air conditioning idle-up + // We are adding percentage steps, but the loop doesn't operate in percentage steps - it works in PWM count <<2 (PWM count * 4) + FeedForwardTerm += percentage(configPage15.airConIdleSteps, (idle_pwm_max_count<<2)); + if(FeedForwardTerm > (idle_pwm_max_count<<2)) { FeedForwardTerm = (idle_pwm_max_count<<2); } + } + + // Fixed this by putting it here, however I have not tested it. It used to be after the calculation of idle_pwm_target_value, meaning the percentage would update in currentStatus, but the idle would not actually increase. + if(currentStatus.idleUpActive == true) + { + // Add Idle Up amount if active + // Again, we are adding percentage steps, but the loop doesn't operate in percentage steps - it works in PWM count <<2 (PWM count * 4) + FeedForwardTerm += percentage(configPage2.idleUpAdder, (idle_pwm_max_count<<2)); + if(FeedForwardTerm > (idle_pwm_max_count<<2)) { FeedForwardTerm = (idle_pwm_max_count<<2); } + } + idle_cl_target_rpm = (uint16_t)currentStatus.CLIdleTarget * 10; //Multiply the byte target value back out by 10 if( BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ) ) { idlePID.SetTunings(configPage6.idleKP, configPage6.idleKI, configPage6.idleKD); } //Re-read the PID settings once per second if((currentStatus.RPM - idle_cl_target_rpm > configPage2.iacRPMlimitHysteresis*10) || (currentStatus.TPS > configPage2.iacTPSlimit)){ //reset integral to zero when TPS is bigger than set value in TS (opening throttle so not idle anymore). OR when RPM higher than Idle Target + RPM Histeresis (coming back from high rpm with throttle closed) idlePID.ResetIntegeral(); } + PID_computed = idlePID.Compute(true, FeedForwardTerm); if(PID_computed == true) { idle_pwm_target_value = idle_pid_target_value>>2; //increased resolution currentStatus.idleLoad = ((unsigned long)(idle_pwm_target_value * 100UL) / idle_pwm_max_count); - if(currentStatus.idleUpActive == true) { currentStatus.idleLoad += configPage2.idleUpAdder; } //Add Idle Up amount if active } idleCounter++; } @@ -600,6 +644,10 @@ void idleControl() idleStepper.targetIdleStep = table2D_getValue(&iacStepTable, (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET)) * 3; //All temps are offset by 40 degrees. Step counts are divided by 3 in TS. Multiply back out here } if(currentStatus.idleUpActive == true) { idleStepper.targetIdleStep += configPage2.idleUpAdder; } //Add Idle Up amount if active + + // Add air conditioning idle-up - we only do this if the engine is running (A/C should never engage with engine off). + if(configPage15.airConIdleSteps>0 && BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) { idleStepper.targetIdleStep += configPage15.airConIdleSteps; } + iacStepTime_uS = configPage6.iacStepTime * 1000; iacCoolTime_uS = configPage9.iacCoolTime * 1000; @@ -680,8 +728,12 @@ void idleControl() } idleStepper.targetIdleStep = idle_pid_target_value>>2; //Increase resolution + // Add air conditioning idle-up - we only do this if the engine is running (A/C should never engage with engine off). + if(configPage15.airConIdleSteps>0 && BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON) == true) { idleStepper.targetIdleStep += configPage15.airConIdleSteps; } } + if(currentStatus.idleUpActive == true) { idleStepper.targetIdleStep += configPage2.idleUpAdder; } //Add Idle Up amount if active + //limit to the configured max steps. This must include any idle up adder, to prevent over-opening. if (idleStepper.targetIdleStep > (configPage9.iacMaxSteps * 3) ) { diff --git a/speeduino/init.ino b/speeduino/init.ino index 43f854b5..5ca4cdc2 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -344,6 +344,7 @@ void initialiseAll() //initialiseDisplay(); initialiseIdle(); initialiseFan(); + initialiseAirCon(); initialiseAuxPWM(); initialiseCorrections(); BIT_CLEAR(currentStatus.engineProtectStatus, PROTECT_IO_ERROR); //Clear the I/O error bit. The bit will be set in initialiseADC() if there is problem in there. @@ -2629,7 +2630,12 @@ void setPinMapping(byte boardID) //Currently there's no default pin for closed throttle position sensor pinCTPS = pinTranslate(configPage2.CTPSPin); - + + // Air conditioning control initialisation + if (((configPage15.airConCompPin&63) != 0) && ((configPage15.airConCompPin&63) < BOARD_MAX_IO_PINS) ) { pinAirConComp = pinTranslate(configPage15.airConCompPin&63); } + if (((configPage15.airConFanPin&63) != 0) && ((configPage15.airConFanPin&63) < BOARD_MAX_IO_PINS) ) { pinAirConFan = pinTranslate(configPage15.airConFanPin&63); } + if (((configPage15.airConReqPin&63) != 0) && ((configPage15.airConReqPin&63) < BOARD_MAX_IO_PINS) ) { pinAirConRequest = pinTranslate(configPage15.airConReqPin&63); } + /* Reset control is a special case. If reset control is enabled, it needs its initial state set BEFORE its pinMode. If that doesn't happen and reset control is in "Serial Command" mode, the Arduino will end up in a reset loop because the control pin will go low as soon as the pinMode is set to OUTPUT. */ @@ -2839,6 +2845,32 @@ void setPinMapping(byte boardID) if (configPage10.wmiEmptyPolarity == 0) { pinMode(pinWMIEmpty, INPUT_PULLUP); } //Normal setting else { pinMode(pinWMIEmpty, INPUT); } //inverted setting } + } + + if((pinAirConComp>0) && ((configPage15.airConEnable&1) == 1)) + { + pinMode(pinAirConComp, OUTPUT); + } + + if((pinAirConRequest > 0) && ((configPage15.airConEnable&1) == 1) && (!pinIsOutput(pinAirConRequest))) + { + if((configPage15.airConReqPol&1) == 1) + { + // Inverted + // +5V is ON, Use external pull-down resistor for OFF + pinMode(pinAirConRequest, INPUT); + } + else + { + //Normal + // Pin pulled to Ground is ON. Floating (internally pulled up to +5V) is OFF. + pinMode(pinAirConRequest, INPUT_PULLUP); + } + } + + if((pinAirConFan > 0) && ((configPage15.airConEnable&1) == 1) && ((configPage15.airConFanEnabled&1) == 1)) + { + pinMode(pinAirConFan, OUTPUT); } //These must come after the above pinMode statements diff --git a/speeduino/logger.h b/speeduino/logger.h index 28ddcfbf..5a0ced30 100644 --- a/speeduino/logger.h +++ b/speeduino/logger.h @@ -12,14 +12,14 @@ #include #ifndef UNIT_TEST // Scope guard for unit testing - #define LOG_ENTRY_SIZE 122 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ - #define SD_LOG_ENTRY_SIZE 122 /**< The size of the live data packet used by the SD card.*/ + #define LOG_ENTRY_SIZE 123 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ + #define SD_LOG_ENTRY_SIZE 123 /**< The size of the live data packet used by the SD card.*/ #else #define LOG_ENTRY_SIZE 1 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ #define SD_LOG_ENTRY_SIZE 1 /**< The size of the live data packet used by the SD card.*/ #endif -#define SD_LOG_NUM_FIELDS 89 /**< The number of fields that are in the log. This is always smaller than the entry size due to some fields being 2 bytes */ +#define SD_LOG_NUM_FIELDS 90 /**< The number of fields that are in the log. This is always smaller than the entry size due to some fields being 2 bytes */ byte getTSLogEntry(uint16_t); int16_t getReadableLogEntry(uint16_t); @@ -123,8 +123,8 @@ const char header_85[] PROGMEM = "Advance 2"; const char header_86[] PROGMEM = "SD Status"; const char header_87[] PROGMEM = "EMAP"; const char header_88[] PROGMEM = "Fan Duty"; +const char header_89[] PROGMEM = "AirConStatus"; /* -const char header_89[] PROGMEM = ""; const char header_90[] PROGMEM = ""; const char header_91[] PROGMEM = ""; const char header_92[] PROGMEM = ""; @@ -248,8 +248,8 @@ const char* const header_table[] PROGMEM = { header_0,\ header_86,\ header_87,\ header_88,\ - /* header_89,\ + /* header_90,\ header_91,\ header_92,\ diff --git a/speeduino/logger.ino b/speeduino/logger.ino index 13c74120..c670e5ce 100644 --- a/speeduino/logger.ino +++ b/speeduino/logger.ino @@ -164,6 +164,7 @@ byte getTSLogEntry(uint16_t byteNum) case 119: statusValue = lowByte(currentStatus.EMAP); break; //2 bytes for EMAP case 120: statusValue = highByte(currentStatus.EMAP); break; case 121: statusValue = currentStatus.fanDuty; break; + case 122: statusValue = currentStatus.airConStatus; break; } return statusValue; @@ -285,6 +286,7 @@ int16_t getReadableLogEntry(uint16_t logIndex) case 86: statusValue = currentStatus.TS_SD_Status; break; //SD card status case 87: statusValue = currentStatus.EMAP; break; case 88: statusValue = currentStatus.fanDuty; break; + case 89: statusValue = currentStatus.airConStatus; break; } return statusValue; diff --git a/speeduino/pages.h b/speeduino/pages.h index 6fd88da1..4b8caf7e 100644 --- a/speeduino/pages.h +++ b/speeduino/pages.h @@ -29,7 +29,6 @@ uint16_t getPageSize(byte pageNum /**< [in] The page number */ ); #define ignMap2Page 14 #define boostvvtPage2 15 - // ============================== Per-byte page access ========================== /** diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 7e5a35c8..0226efd3 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -293,6 +293,9 @@ void loop() //updateFullStatus(); checkProgrammableIO(); idleControl(); //Perform any idle related actions. This needs to be run at 10Hz to align with the idle taper resolution of 0.1s + + // Air conditioning control + airConControl(); //if( (isEepromWritePending() == true) && (serialReceivePending == false) && (micros() > deferEEPROMWritesUntil)) { writeAllConfig(); } //Used for slower EEPROM writes (Currently this runs in the 30Hz block) @@ -342,6 +345,7 @@ void loop() if( (configPage2.idleAdvEnabled >= 1) || (configPage6.iacAlgorithm != IAC_ALGORITHM_NONE) ) { currentStatus.CLIdleTarget = (byte)table2D_getValue(&idleTargetTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees + if(BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON)) { currentStatus.CLIdleTarget += configPage15.airConIdleUpRPMAdder; } //Adds Idle Up RPM amount if active } #ifdef SD_LOGGING @@ -350,7 +354,7 @@ void loop() currentStatus.fuelPressure = getFuelPressure(); currentStatus.oilPressure = getOilPressure(); - + if(auxIsEnabled == true) { //TODO dazq to clean this right up :) diff --git a/speeduino/storage.cpp b/speeduino/storage.cpp index ca95d1ef..5c7611b6 100644 --- a/speeduino/storage.cpp +++ b/speeduino/storage.cpp @@ -287,7 +287,7 @@ void writeConfig(uint8_t pageNum) result = writeTable(&dwellTable, decltype(dwellTable)::type_key, result.changeWriteAddress(EEPROM_CONFIG12_MAP3)); break; - case progOutsPage: + case progOutsPage: /*--------------------------------------------------- | Config page 13 (See storage.h for data layout) -----------------------------------------------------*/ diff --git a/speeduino/storage.h b/speeduino/storage.h index 5c7c558e..b192f810 100644 --- a/speeduino/storage.h +++ b/speeduino/storage.h @@ -99,7 +99,11 @@ * | 3201 |64 | boostLUT table (8x8) | @ref EEPROM_CONFIG15_MAP | * | 3265 |8 | boostLUT table (X axis) (RPM) | | * | 3273 |8 | boostLUT table (Y axis) (targetBoost)| | - * | 3281 |176 | Page 15 settings | @ref EEPROM_CONFIG15_START | + * | 3281 |1 | boostLUT enable | @ref EEPROM_CONFIG15_START | + * | 3282 |1 | boostDCWhenDisabled | | + * | 3283 |1 | boostControlEnableThreshold | | + * | 3284 |14 | A/C Control Settings | | + * | 3298 |159 | Page 15 spare | | * | 3457 |217 | EMPTY | | * | 3674 |4 | CLT Calibration CRC32 | | * | 3678 |4 | IAT Calibration CRC32 | | diff --git a/speeduino/updates.ino b/speeduino/updates.ino index 3436b288..0ad1caa1 100644 --- a/speeduino/updates.ino +++ b/speeduino/updates.ino @@ -625,7 +625,6 @@ void doUpdates() configPage2.canBMWCluster = 0; configPage2.canVAGCluster = 0; - configPage15.boostDCWhenDisabled = 0; configPage15.boostControlEnable = EN_BOOST_CONTROL_BARO; @@ -668,8 +667,8 @@ void doUpdates() configPage9.afrProtectMinMAP = 90; //Is divided by 2, vlue represents 180kPa configPage9.afrProtectMinRPM = 40; //4000 RPM min configPage9.afrProtectMinTPS = 160; //80% TPS min - configPage9.afrProtectDeviation = 14; //1.4 AFR deviation - + configPage9.afrProtectDeviation = 14; //1.4 AFR deviation + writeAllConfig(); storeEEPROMVersion(20); } @@ -679,6 +678,10 @@ void doUpdates() //202210 configPage2.taeMinChange = 4; //Default is 2% minimum change to match prior behaviour. (4 = 2% account for 0.5 resolution) configPage2.maeMinChange = 2; //Default is 2% minimum change to match prior behaviour. + + //AC Control (configPage15) + //Set A/C default values - these line up with the ini file defaults + configPage15.airConEnable = 0; writeAllConfig(); storeEEPROMVersion(21);