From 31541cca2dda154fb49a698fc6f44699827eeb95 Mon Sep 17 00:00:00 2001 From: "Vitor Moreno B. Sales" Date: Sun, 26 Jul 2020 20:05:02 -0300 Subject: [PATCH] [VVT] PID work (#412) * [VVT] PID work Tested on a half moon CAM pattern as working, it should work on others too. Added option to reverse the PWM output Co-Authored-By: pazi88 <48950874+pazi88@users.noreply.github.com> * Fix typo Co-Authored-By: diy-efi * Add second VVT pwm on same timer All precious VVT variables was renamed to VVT1 and added VVT2 stuff. Tested with logic analyzer. * Define VVT2 for other boards Added vvt2Pin * Just update on first tooth Co-authored-by: pazi88 <48950874+pazi88@users.noreply.github.com> Co-authored-by: diy-efi --- reference/Base Tunes/NA6 PNP base tune.msq | 4 +- reference/Base Tunes/NA8 PNP base tune.msq | 4 +- reference/Base Tunes/NB8B PNP base tune.msq | 4 +- .../Speeduino base tune with wmi.msq | 2 +- reference/Base Tunes/Speeduino base tune.msq | 4 +- reference/speeduino.ini | 61 +++-- speeduino/auxiliaries.h | 24 +- speeduino/auxiliaries.ino | 216 ++++++++++++------ speeduino/comms.ino | 9 +- speeduino/decoders.ino | 19 +- speeduino/globals.h | 26 ++- speeduino/init.ino | 18 +- speeduino/logger.h | 4 +- speeduino/logger.ino | 18 +- speeduino/speeduino.ino | 6 +- speeduino/src/PID_v1/PID_v1.cpp | 58 ++++- speeduino/src/PID_v1/PID_v1.h | 7 +- 17 files changed, 343 insertions(+), 141 deletions(-) diff --git a/reference/Base Tunes/NA6 PNP base tune.msq b/reference/Base Tunes/NA6 PNP base tune.msq index ce9d843c..ce7337fe 100644 --- a/reference/Base Tunes/NA6 PNP base tune.msq +++ b/reference/Base Tunes/NA6 PNP base tune.msq @@ -830,7 +830,7 @@ 16.0 "On/Off" "MAP" - "Advance" + "Advance" "No" "No" "MAP" @@ -840,7 +840,7 @@ 15.0 1200.0 70.0 - "26" + "26" "No" "Simple" "20" diff --git a/reference/Base Tunes/NA8 PNP base tune.msq b/reference/Base Tunes/NA8 PNP base tune.msq index 667bb9e1..7cfbab98 100644 --- a/reference/Base Tunes/NA8 PNP base tune.msq +++ b/reference/Base Tunes/NA8 PNP base tune.msq @@ -700,7 +700,7 @@ 16.0 "On/Off" "MAP" - "Advance" + "Advance" "Yes" "No" "MAP" @@ -710,7 +710,7 @@ 15.0 1200.0 70.0 - "26" + "26" "No" "Simple" "20" diff --git a/reference/Base Tunes/NB8B PNP base tune.msq b/reference/Base Tunes/NB8B PNP base tune.msq index 1a1fa7d5..d07a324c 100644 --- a/reference/Base Tunes/NB8B PNP base tune.msq +++ b/reference/Base Tunes/NB8B PNP base tune.msq @@ -651,7 +651,7 @@ 16.0 "Closed loop" "MAP" - "Advance" + "Advance" "No" "Yes" "MAP" @@ -661,7 +661,7 @@ 15.0 1200.0 70.0 - "Board Default" + "Board Default" "No" "Simple" "Board Default" diff --git a/reference/Base Tunes/Speeduino base tune with wmi.msq b/reference/Base Tunes/Speeduino base tune with wmi.msq index 6d681b75..3204574b 100644 --- a/reference/Base Tunes/Speeduino base tune with wmi.msq +++ b/reference/Base Tunes/Speeduino base tune with wmi.msq @@ -835,7 +835,7 @@ 15.0 1200.0 70.0 -"Board Default" +"Board Default" "No" "Simple" "Board Default" diff --git a/reference/Base Tunes/Speeduino base tune.msq b/reference/Base Tunes/Speeduino base tune.msq index 80d3bc64..90115c8b 100644 --- a/reference/Base Tunes/Speeduino base tune.msq +++ b/reference/Base Tunes/Speeduino base tune.msq @@ -842,7 +842,7 @@ 16.0 "On/Off" "MAP" - "Advance" + "Advance" "No" "No" "MAP" @@ -852,7 +852,7 @@ 15.0 1200.0 70.0 - "Board Default" + "Board Default" "No" "Simple" "Board Default" diff --git a/reference/speeduino.ini b/reference/speeduino.ini index d89b5f8d..90d3073e 100644 --- a/reference/speeduino.ini +++ b/reference/speeduino.ini @@ -541,7 +541,7 @@ page = 6 egoCount = scalar, U08, 5, "", 4.0, 0.0, 4.0, 255.0, 0 ; * ( 1 byte) vvtMode = bits, U08, 6, [0:1], "On/Off", "Open Loop", "Closed loop", "INVALID" vvtLoadSource = bits, U08, 6, [2:3], "MAP", "TPS", "INVALID", "INVALID" - vvtCLDir = bits, U08, 6, [4:4], "Advance", "Retard" + vvtPWMdir = bits, U08, 6, [4:4], "Advance", "Retard" vvtCLUseHold = bits, U08, 6, [5:5], "No", "Yes" vvtCLAlterFuelTiming = bits, U08, 6, [6:6], "No", "Yes" boostCutEnabled = bits, U08, 6, [7:7], "Off", "On" @@ -551,7 +551,7 @@ page = 6 ego_sdelay = scalar, U08, 10, "sec", 1, 0, 0, 120, 0 egoRPM = scalar, U08, 11, "rpm", 100, 0.0, 100, 25500, 0 egoTPSMax = scalar, U08, 12, "%", 1, 0, 0, 120, 0 - vvtPin = bits , U08, 13, [0:5], "Board Default", "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", "54", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" + vvt1Pin = bits , U08, 13, [0:5], "Board Default", "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", "54", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" useExtBaro = bits, U08, 13, [6:6], "No", "Yes" boostMode = bits, U08, 13, [7:7], "Simple", "Full" boostPin = bits, U08, 14, [0:5], "Board Default", "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", "54", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID" @@ -1027,8 +1027,8 @@ page = 10 vvtCLKP = scalar, U08, 127, "%", 0.03125, 0.0, 0.0, 7.96, 2 ; * ( 1 byte) vvtCLKI = scalar, U08, 128, "%", 0.03125, 0.0, 0.0, 7.96, 2 ; * ( 1 byte) vvtCLKD = scalar, U08, 129, "%", 0.00781, 0.0, 0.0, 1.99, 3 ; * ( 1 byte) - vvtCLMinAng = scalar, U16, 130, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) - vvtCLMaxAng = scalar, U16, 132, "deg", 1.0, 0.0, 0.0, 360.0, 0 ; * ( 1 bytes) + vvtCLMinAng = scalar, S16, 130, "deg", 1.0, 0.0, -360.0, 360.0, 0 ; * ( 2 bytes) + vvtCLMaxAng = scalar, S16, 132, "deg", 1.0, 0.0, -360.0, 360.0, 0 ; * ( 2 bytes) crankingEnrichTaper = scalar, U08, 134, "s", 0.1, 0.0, 0.0, 25.5, 1 @@ -1047,7 +1047,7 @@ page = 10 oilPressureProtRPM = array, U08, 141, [ 4], "RPM", 100.0, 0.0, 100.0, 25500, 0 oilPressureProtMins = array, U08, 145, [ 4], "psi", 1.0, 0.0, 0.0, 255, 0 - + wmiEnabled = bits, U08, 149, [0:0], "Off", "On" wmiMode = bits, U08, 149, [1:2], "Simple", "Proportional", "Openloop", "Closedloop" @@ -1077,7 +1077,10 @@ page = 10 wmiAdvBins = array, U08, 159, [6], "kPa", 2.0, 0.0, 0.0, 511.0, 0 wmiAdvAdj = array, U08, 165, [6], "Deg", 1.0, -40, -40, 215.0, 0 - unused11_171_191 = array, U08, 171, [21], "RPM", 100.0, 0.0, 100, 25500, 0 + vvtCLminDuty = scalar, U08, 172, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles when using closed loop + vvtCLmaxDuty = scalar, U08, 173, "%", 1.0, 0.0, 0.0, 100.0, 0 + unused11_174_191 = array, U08, 174, [19], "RPM", 100.0, 0.0, 100, 25500, 0 + ;Page 11 is the fuel map and axis bins only page = 11 @@ -1159,12 +1162,14 @@ page = 12 requiresPowerCycle = wmiIndicatorEnabled requiresPowerCycle = wmiIndicatorPin requiresPowerCycle = wmiIndicatorPolarity + requiresPowerCycle = vvtCLminDuty + requiresPowerCycle = vvtCLmaxDuty requiresPowerCycle = caninput_sel0a requiresPowerCycle = caninput_sel0b requiresPowerCycle = caninput_sel1a requiresPowerCycle = caninput_sel1b - requiresPowerCycle = caninput_sel2a + requiresPowerCycle = caninput_sel2a requiresPowerCycle = caninput_sel2b requiresPowerCycle = caninput_sel3a requiresPowerCycle = caninput_sel3b @@ -1258,10 +1263,12 @@ page = 12 defaultValue = crankingEnrichTaper, 0.1 defaultValue = boostCutEnabled, 1 defaultValue = primingDelay, 0.5 + defaultValue = vvtCLminDuty, 0 + defaultValue = vvtCLmaxDuty, 80 ;80% is a completely arbitrary amount for the max duty cycle, but seems inline with most VVT documentation ;Default pins defaultValue = fanPin, 0 - defaultValue = vvtPin, 0 + defaultValue = vvt1Pin, 0 defaultValue = launchPin, 0 defaultValue = boostPin, 0 defaultValue = fuelPumpPin, 0 @@ -2590,7 +2597,6 @@ menuDialog = main field = "D", boostKD, { boostEnabled && boostMode && boostType == 1 } dialog = vvtClosedLoop, "Closed loop" - field = "Increased duty direction", vvtCLDir field = "Hold duty used", vvtCLUseHold field = "Hold duty", vvtCLholdDuty, { vvtCLUseHold } field = "Adjust fuel timing", vvtCLAlterFuelTiming @@ -2599,6 +2605,8 @@ menuDialog = main field = "Proportional Gain", vvtCLKP field = "Integral Gain", vvtCLKI field = "Differential Gain", vvtCLKD + field = "Minimum valve duty", vvtCLminDuty, { vvtEnabled && vvtMode == 2 } + field = "Maximum valve duty", vvtCLmaxDuty, { vvtEnabled && vvtMode == 2 } dialog = vvtSettings, "VVT Control" @@ -2607,8 +2615,9 @@ menuDialog = main field = "#Please note that close loop is currently experimental for Miata patterns ONLY" field = "Load source", vvtLoadSource, { vvtEnabled } field = "Use VVT map as On / Off only", VVTasOnOff, { vvtEnabled && vvtMode != 2 } - field = "VVT output pin", vvtPin, { vvtEnabled } + field = "VVT output pin", vvt1Pin, { vvtEnabled } field = "VVT solenoid freq.", vvtFreq, { vvtEnabled } + field = "Increased duty direction", vvtPWMdir, { vvtEnabled } panel = vvtClosedLoop, { vvtEnabled && vvtMode == 2 } dialog = wmiSettings, "WMI Control" @@ -2622,7 +2631,7 @@ menuDialog = main field = "WMI min IAT", wmiIAT, { wmiEnabled } field = "WMI offset", wmiOffset, { wmiEnabled && wmiMode == 3} field = "" - field = "WMI PWM output pin", vvtPin, { wmiEnabled } + field = "WMI PWM output pin", vvt1Pin, { wmiEnabled } field = "WMI PWM freq.", vvtFreq, { wmiEnabled } field = "" field = "WMI enabled output pin", wmiEnabledPin, { wmiEnabled } @@ -3315,7 +3324,7 @@ menuDialog = main displayOnlyField = "tachoPin", tachoPin, {tachoDuration} displayOnlyField = "idleUpPin", idleUpPin, {idleUpEnabled} displayOnlyField = "launchPin", launchPin, {launchEnable} - displayOnlyField = "vvtPin", vvtPin, {vvtEnabled} + displayOnlyField = "vvt1Pin", vvt1Pin, {vvtEnabled} displayOnlyField = "vssPin", vssPin, {vssMode > 1} displayOnlyField = "boostPin", boostPin, {boostEnabled} displayOnlyField = "baroPin", baroPin,{useExtBaro} @@ -3851,9 +3860,15 @@ cmdVSSratio6 = "E\x99\x06" boostDutyGauge = boostDuty, "Boost Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1 afrTargetGauge = afrTarget, "Target AFR", "", 7, 25, 12, 13, 15, 16, 2, 2 lambdaTargetGauge = lambdaTarget, "Target Lambda", "", 0.5, 1.5, 0.82, 0.89, 1.02, 1.09, 3, 3 - VVTdutyCycleGauge = vvtDuty, "VVT Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1 IdleTargetGauge = CLIdleTarget, "Idle Target RPM", "RPM", 0, 2000, 300, 600, 1500, 1700, 0, 0 idleLoadGauge = idleLoad, "IAC Value", "%/Steps", 0, {maphigh}, 0, 20, {mapwarn}, {mapdang}, 0, 0 + vvt1DutyCycleGauge= vvt1Duty, "VVT Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1 + vvt1TargetGauge = vvt1Target, "VVT Target Angle", "deg", 0, 100, 15, 25, 65, 75, 0, 0 + vvt1AngleGauge = vvt1Angle, "VVT Angle", "deg", -20, 100, 0, -5, 70, 90, 0, 0 + vvt2DutyCycleGauge= vvt2Duty, "VVT Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1 + vvt2TargetGauge = vvt2Target, "VVT Target Angle", "deg", 0, 100, 15, 25, 65, 75, 0, 0 + vvt2AngleGauge = vvt2Angle, "VVT Angle", "deg", -20, 100, 0, -5, 70, 90, 0, 0 + WMIdutyCycleGauge = wmiPW, "WMI Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1 gaugeCategory = "Sensor inputs" @@ -3970,7 +3985,7 @@ cmdVSSratio6 = "E\x99\x06" ochGetCommand = "r\$tsCanId\x30%2o%2c" ;ochBlockSize = 104 - ochBlockSize = 108 + ochBlockSize = 111 secl = scalar, U08, 0, "sec", 1.000, 0.000 status1 = scalar, U08, 1, "bits", 1.000, 0.000 @@ -4076,9 +4091,9 @@ cmdVSSratio6 = "E\x99\x06" dwell = scalar, U16, 89, "ms", 0.001, 0.000 CLIdleTarget = scalar, U08, 91, "RPM", 10.00, 0.000 MAPdot = scalar, U08, 92, "kPa/s", 10.00, 0.000 - vvtAngle = scalar, S08, 93, "deg", 1.00, 0.000 - vvtTarget = scalar, U08, 94, "deg", 1.00, 0.000 - vvtDuty = scalar, U08, 95, "%", 1.00, 0.000 + vvt1Angle = scalar, S08, 93, "deg", 1.00, 0.000 + vvt1Target = scalar, U08, 94, "deg", 1.00, 0.000 + vvt1Duty = scalar, U08, 95, "%", 1.00, 0.000 flexBoostCor = scalar, S16, 96, "kPa", 1.000, 0.000 baroCorrection = scalar, U08, 98, "%", 1.000, 0.000 veCurr = scalar, U08, 99, "%", 1.000, 0.000 @@ -4090,6 +4105,9 @@ cmdVSSratio6 = "E\x99\x06" wmiPW = scalar, U08, 106, "%", 1.000, 0.000 wmiEmpty = scalar, U08, 107, "bits", 1.000, 0.000 wmiEmptyBit = bits, U08, 107, [0:0] + vvt2Angle = scalar, S08, 108, "deg", 1.00, 0.000 + vvt2Target = scalar, U08, 109, "deg", 1.00, 0.000 + vvt2Duty = scalar, U08, 110, "%", 1.00, 0.000 #sd_status = scalar, U08, 99, "", 1.0, 0.0 #if CELSIUS @@ -4214,13 +4232,16 @@ cmdVSSratio6 = "E\x99\x06" entry = baro, "Baro Pressure",int, "%d" entry = nitrousOn, "Nitrous", int, "%d", { n2o_enable > 0 } entry = syncLossCounter, "Sync Loss #", int, "%d" - entry = vvtAngle, "VVT Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt - entry = vvtTarget, "VVT Target Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt - entry = vvtDuty, "VVT Duty", int, "%d", { vvtEnabled > 0 } + entry = vvt1Angle, "VVT Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvt1Target, "VVT Target Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvt1Duty, "VVT Duty", int, "%d", { vvtEnabled > 0 } entry = vss, "VSS (Speed)", int, "%d", { vssMode > 1 } entry = gear, "Gear", int, "%d", { vssMode > 1 } entry = fuelPressure, "Fuel Pressure",int, "%d", { fuelPressureEnable > 0 } entry = oilPressure, "Oil Pressure", int, "%d", { oilPressureEnable > 0 } + entry = vvt2Angle, "VVT Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvt2Target, "VVT Target Angle", int, "%d", { vvtMode == 2 } ;;Only show when using close loop vvt + entry = vvt2Duty, "VVT Duty", int, "%d", { vvtEnabled > 0 } entry = auxin_gauge0, { stringValue(AUXin00Alias)}, int, "%d", {(caninput_sel0b != 0)} entry = auxin_gauge1, { stringValue(AUXin01Alias)}, int, "%d", { (caninput_sel1b != 0)} diff --git a/speeduino/auxiliaries.h b/speeduino/auxiliaries.h index fb7ee530..04388643 100644 --- a/speeduino/auxiliaries.h +++ b/speeduino/auxiliaries.h @@ -19,8 +19,10 @@ void wmiControl(); #define BOOST_PIN_LOW() *boost_pin_port &= ~(boost_pin_mask) #define BOOST_PIN_HIGH() *boost_pin_port |= (boost_pin_mask) -#define VVT_PIN_LOW() *vvt_pin_port &= ~(vvt_pin_mask) -#define VVT_PIN_HIGH() *vvt_pin_port |= (vvt_pin_mask) +#define VVT1_PIN_LOW() *vvt1_pin_port &= ~(vvt1_pin_mask) +#define VVT1_PIN_HIGH() *vvt1_pin_port |= (vvt1_pin_mask) +#define VVT2_PIN_LOW() *vvt2_pin_port &= ~(vvt2_pin_mask) +#define VVT2_PIN_HIGH() *vvt2_pin_port |= (vvt2_pin_mask) #define FAN_PIN_LOW() *fan_pin_port &= ~(fan_pin_mask) #define FAN_PIN_HIGH() *fan_pin_port |= (fan_pin_mask) #define N2O_STAGE1_PIN_LOW() *n2o_stage1_pin_port &= ~(n2o_stage1_pin_mask) @@ -36,8 +38,10 @@ void wmiControl(); volatile PORT_TYPE *boost_pin_port; volatile PINMASK_TYPE boost_pin_mask; -volatile PORT_TYPE *vvt_pin_port; -volatile PINMASK_TYPE vvt_pin_mask; +volatile PORT_TYPE *vvt1_pin_port; +volatile PINMASK_TYPE vvt1_pin_mask; +volatile PORT_TYPE *vvt2_pin_port; +volatile PINMASK_TYPE vvt2_pin_mask; volatile PORT_TYPE *fan_pin_port; volatile PINMASK_TYPE fan_pin_mask; volatile PORT_TYPE *n2o_stage1_pin_port; @@ -58,10 +62,16 @@ byte vvtCounter; byte fanHIGH = HIGH; // Used to invert the cooling fan output byte fanLOW = LOW; // Used to invert the cooling fan output -volatile bool vvt_pwm_state; +volatile bool vvt1_pwm_state; +volatile bool vvt2_pwm_state; +volatile bool vvt1_max_pwm; +volatile bool vvt2_max_pwm; +volatile char nextVVT; unsigned int vvt_pwm_max_count; //Used for variable PWM frequency -volatile unsigned int vvt_pwm_cur_value; -long vvt_pwm_value; +volatile unsigned int vvt1_pwm_cur_value; +volatile unsigned int vvt2_pwm_cur_value; +long vvt1_pwm_value; +long vvt2_pwm_value; long vvt_pid_target_angle; //long vvt_pid_current_angle; static inline void boostInterrupt(); diff --git a/speeduino/auxiliaries.ino b/speeduino/auxiliaries.ino index b314a044..0e0d6f9f 100644 --- a/speeduino/auxiliaries.ino +++ b/speeduino/auxiliaries.ino @@ -12,7 +12,7 @@ A full copy of the license may be found in the projects root directory //Old PID method. Retained incase the new one has issues //integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT); integerPID_ideal boostPID(¤tStatus.MAP, ¤tStatus.boostDuty , ¤tStatus.boostTarget, &configPage10.boostSens, &configPage10.boostIntv, configPage6.boostKP, configPage6.boostKI, configPage6.boostKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call -integerPID vvtPID(¤tStatus.vvtAngle, &vvt_pwm_value, &vvt_pid_target_angle, configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call +integerPID vvtPID(¤tStatus.vvt1Angle, &vvt1_pwm_value, &vvt_pid_target_angle, configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call /* Fan control @@ -66,8 +66,10 @@ void initialiseAuxPWM() { boost_pin_port = portOutputRegister(digitalPinToPort(pinBoost)); boost_pin_mask = digitalPinToBitMask(pinBoost); - vvt_pin_port = portOutputRegister(digitalPinToPort(pinVVT_1)); - vvt_pin_mask = digitalPinToBitMask(pinVVT_1); + vvt1_pin_port = portOutputRegister(digitalPinToPort(pinVVT_1)); + vvt1_pin_mask = digitalPinToBitMask(pinVVT_1); + vvt2_pin_port = portOutputRegister(digitalPinToPort(pinVVT_2)); + vvt2_pin_mask = digitalPinToBitMask(pinVVT_2); n2o_stage1_pin_port = portOutputRegister(digitalPinToPort(configPage10.n2o_stage1_pin)); n2o_stage1_pin_mask = digitalPinToBitMask(configPage10.n2o_stage1_pin); n2o_stage2_pin_port = portOutputRegister(digitalPinToPort(configPage10.n2o_stage2_pin)); @@ -92,7 +94,8 @@ void initialiseAuxPWM() if( configPage6.vvtEnabled > 0) { - currentStatus.vvtAngle = 0; + currentStatus.vvt1Angle = 0; + currentStatus.vvt2Angle = 0; #if defined(CORE_AVR) vvt_pwm_max_count = 1000000L / (16 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle. Note that the frequency is divided by 2 coming from TS to allow for up to 512hz @@ -102,16 +105,19 @@ void initialiseAuxPWM() if(configPage6.vvtMode == VVT_MODE_CLOSED_LOOP) { - vvtPID.SetOutputLimits(0, percentage(80, vvt_pwm_max_count)); //80% is a completely arbitrary amount for the max duty cycle, but seems inline with most VVT documentation + vvtPID.SetOutputLimits(percentage(configPage10.vvtCLminDuty, vvt_pwm_max_count), percentage(configPage10.vvtCLmaxDuty, vvt_pwm_max_count)); vvtPID.SetTunings(configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD); - vvtPID.SetSampleTime(30); + vvtPID.SetSampleTime(33); //30Hz is 33,33ms vvtPID.SetMode(AUTOMATIC); //Turn PID on } - currentStatus.vvtDuty = 0; - vvt_pwm_value = 0; + currentStatus.vvt1Duty = 0; + vvt1_pwm_value = 0; + currentStatus.vvt2Duty = 0; + vvt2_pwm_value = 0; + ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt) } - if(configPage6.vvtEnabled == 0 && configPage10.wmiEnabled >= 1) + if( (configPage6.vvtEnabled == 0) && (configPage10.wmiEnabled >= 1) ) { // config wmi pwm output to use vvt output #if defined(CORE_AVR) @@ -121,13 +127,14 @@ void initialiseAuxPWM() #endif currentStatus.wmiEmpty = 0; currentStatus.wmiPW = 0; - vvt_pwm_value = 0; + vvt1_pwm_value = 0; + ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt) } - ENABLE_VVT_TIMER(); //Turn on the B compare unit (ie turn on the interrupt) currentStatus.boostDuty = 0; boostCounter = 0; - currentStatus.vvtDuty = 0; + currentStatus.vvt1Duty = 0; + currentStatus.vvt2Duty = 0; vvtCounter = 0; currentStatus.nitrous_status = NITROUS_OFF; @@ -215,89 +222,79 @@ void vvtControl() { if( (configPage6.vvtEnabled == 1) && (currentStatus.RPM > 0) ) { - currentStatus.vvtDuty = 0; + //currentStatus.vvt1Duty = 0; + //Calculate the current cam angle + if( configPage4.TrigPattern == 9 ) { getCamAngle_Miata9905(); } + if( (configPage6.vvtMode == VVT_MODE_OPEN_LOOP) || (configPage6.vvtMode == VVT_MODE_ONOFF) ) { //Lookup VVT duty based on either MAP or TPS - if(configPage6.vvtLoadSource == VVT_LOAD_TPS) - { - currentStatus.vvtDuty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); - } - else - { - currentStatus.vvtDuty = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); - } + if(configPage6.vvtLoadSource == VVT_LOAD_TPS) { currentStatus.vvt1Duty = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); } + else { currentStatus.vvt1Duty = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); } //VVT table can be used for controlling on/off switching. If this is turned on, then disregard any interpolation or non-binary values - if( (configPage6.VVTasOnOff == true) && (currentStatus.vvtDuty < 100) ) { currentStatus.vvtDuty = 0; } + if( (configPage6.VVTasOnOff == true) && (currentStatus.vvt1Duty < 100) ) { currentStatus.vvt1Duty = 0; } - vvt_pwm_value = percentage(currentStatus.vvtDuty, vvt_pwm_max_count); - if(currentStatus.vvtDuty > 0) { ENABLE_VVT_TIMER(); } + vvt1_pwm_value = percentage(currentStatus.vvt1Duty, vvt_pwm_max_count); + if(currentStatus.vvt1Duty > 0) { ENABLE_VVT_TIMER(); } } //Open loop else if( (configPage6.vvtMode == VVT_MODE_CLOSED_LOOP) ) { - //Calculate the current cam angle - getCamAngle_Miata9905(); - //Lookup VVT duty based on either MAP or TPS - if(configPage6.vvtLoadSource == VVT_LOAD_TPS) - { - currentStatus.vvtTargetAngle = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); - } - else - { - currentStatus.vvtTargetAngle = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); - } + if(configPage6.vvtLoadSource == VVT_LOAD_TPS) { currentStatus.vvt1TargetAngle = get3DTableValue(&vvtTable, currentStatus.TPS, currentStatus.RPM); } + else { currentStatus.vvt1TargetAngle = get3DTableValue(&vvtTable, currentStatus.MAP, currentStatus.RPM); } if( (vvtCounter & 31) == 1) { vvtPID.SetTunings(configPage10.vvtCLKP, configPage10.vvtCLKI, configPage10.vvtCLKD); } //This only needs to be run very infrequently, once every 32 calls to vvtControl(). This is approx. once per second //Check that we're not already at the angle we want to be - if((configPage6.vvtCLUseHold > 0) && (currentStatus.vvtTargetAngle == currentStatus.vvtAngle) ) + if((configPage6.vvtCLUseHold > 0) && (currentStatus.vvt1TargetAngle == currentStatus.vvt1Angle) ) { - currentStatus.vvtDuty = configPage10.vvtCLholdDuty; - vvt_pwm_value = percentage(currentStatus.vvtDuty, vvt_pwm_max_count); + currentStatus.vvt1Duty = configPage10.vvtCLholdDuty; + vvt1_pwm_value = percentage(currentStatus.vvt1Duty, vvt_pwm_max_count); vvtPID.Initialize(); } else { - //If not already at target angle, calculate new value from PID - //This is dumb, but need to convert the current angle into a long pointer - vvt_pid_target_angle = currentStatus.vvtTargetAngle; + vvt_pid_target_angle = currentStatus.vvt1TargetAngle; - if(currentStatus.vvtTargetAngle > 0) + if(currentStatus.vvt1TargetAngle >= 0) { + //If not already at target angle, calculate new value from PID bool PID_compute = vvtPID.Compute(false); - //vvtPID.Compute2(currentStatus.vvtTargetAngle, currentStatus.vvtAngle, false); + //vvtPID.Compute2(currentStatus.vvt1TargetAngle, currentStatus.vvt1Angle, false); //vvt_pwm_target_value = percentage(40, vvt_pwm_max_count); - //if (currentStatus.vvtAngle > currentStatus.vvtTargetAngle) { vvt_pwm_target_value = 0; } - if(PID_compute == true) { currentStatus.vvtDuty = (vvt_pwm_value * 100) / vvt_pwm_max_count; } - - } - else - { - currentStatus.vvtDuty = 0; + //if (currentStatus.vvt1Angle > currentStatus.vvt1TargetAngle) { vvt_pwm_target_value = 0; } + if(PID_compute == true) { currentStatus.vvt1Duty = (vvt1_pwm_value * 100) / vvt_pwm_max_count; } + } + else { currentStatus.vvt1Duty = 0; } } - if(currentStatus.vvtDuty > 0) { ENABLE_VVT_TIMER(); } + if( (currentStatus.vvt1Duty > 0) || (currentStatus.vvt2Duty > 0) ) { ENABLE_VVT_TIMER(); } - //currentStatus.vvtDuty = 0; + //currentStatus.vvt1Duty = 0; vvtCounter++; } //Set the PWM state based on the above lookups - if(currentStatus.vvtDuty == 0) + if( (currentStatus.vvt1Duty == 0) && (currentStatus.vvt2Duty == 0) ) { //Make sure solenoid is off (0% duty) - VVT_PIN_LOW(); + if (configPage6.vvtPWMdir == 0) { *vvt1_pin_port &= ~(vvt1_pin_mask); } //Normal direction + else { *vvt1_pin_port |= (vvt1_pin_mask); } //Reversed direction + if (configPage6.vvtPWMdir == 0) { *vvt2_pin_port &= ~(vvt2_pin_mask); } //Normal direction + else { *vvt2_pin_port |= (vvt2_pin_mask); } //Reversed direction DISABLE_VVT_TIMER(); } - else if (currentStatus.vvtDuty >= 100) + else if( (currentStatus.vvt1Duty >= 100) && (currentStatus.vvt2Duty >= 100) ) { //Make sure solenoid is on (100% duty) - VVT_PIN_HIGH(); + if (configPage6.vvtPWMdir == 0) { *vvt1_pin_port |= (vvt1_pin_mask); } //Normal direction + else { *vvt1_pin_port &= ~(vvt1_pin_mask); } //Reversed direction + if (configPage6.vvtPWMdir == 0) { *vvt2_pin_port |= (vvt2_pin_mask); } //Normal direction + else { *vvt2_pin_port &= ~(vvt2_pin_mask); } //Reversed direction DISABLE_VVT_TIMER(); } @@ -306,8 +303,10 @@ void vvtControl() { // Disable timer channel DISABLE_VVT_TIMER(); - currentStatus.vvtDuty = 0; - vvt_pwm_value = 0; + currentStatus.vvt1Duty = 0; + vvt1_pwm_value = 0; + currentStatus.vvt2Duty = 0; + vvt2_pwm_value = 0; } } @@ -407,12 +406,12 @@ void wmiControl() } currentStatus.wmiPW = wmiPW; - vvt_pwm_value = wmiPW; + vvt1_pwm_value = wmiPW; if(wmiPW == 0) { // Make sure water pump is off - VVT_PIN_LOW(); + VVT1_PIN_LOW(); DISABLE_VVT_TIMER(); digitalWrite(pinWMIEnabled, LOW); } @@ -422,7 +421,7 @@ void wmiControl() if (wmiPW >= 100) { // Make sure water pump is on (100% duty) - VVT_PIN_HIGH(); + VVT1_PIN_HIGH(); DISABLE_VVT_TIMER(); } else @@ -470,18 +469,97 @@ void boostDisable() static inline void vvtInterrupt() //Most ARM chips can simply call a function #endif { - if (vvt_pwm_state == true) + if ( ((vvt1_pwm_state == false) || (vvt1_max_pwm == true)) && ((vvt2_pwm_state == false) || (vvt2_max_pwm == true)) ) { - VVT_PIN_LOW(); // Switch pin to low - VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt_pwm_cur_value); - vvt_pwm_state = false; + if( (vvt1_pwm_value > 0) && (vvt1_max_pwm == false) ) //Don't toggle if at 0% + { + if (configPage6.vvtPWMdir == 0) { *vvt1_pin_port |= (vvt1_pin_mask); } //Normal direction + else { *vvt1_pin_port &= ~(vvt1_pin_mask); } //Reversed direction + vvt1_pwm_state = true; + } + if( (vvt2_pwm_value > 0) && (vvt2_max_pwm == false) ) //Don't toggle if at 0% + { + if (configPage6.vvtPWMdir == 0) { *vvt2_pin_port |= (vvt2_pin_mask); } //Normal direction + else { *vvt2_pin_port &= ~(vvt2_pin_mask); } //Reversed direction + vvt2_pwm_state = true; + } + + if( (vvt1_pwm_state == true) && (vvt1_pwm_value <= vvt2_pwm_value) ) + { + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt1_pwm_value; + vvt1_pwm_cur_value = vvt1_pwm_value; + vvt2_pwm_cur_value = vvt2_pwm_value; + if (vvt1_pwm_value == vvt2_pwm_value) { nextVVT = 2; } //Next event is for both PWM + else { nextVVT = 0; } //Next event is for PWM0 + } + else if( vvt2_pwm_state == true ) + { + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt2_pwm_value; + vvt1_pwm_cur_value = vvt1_pwm_value; + vvt2_pwm_cur_value = vvt2_pwm_value; + nextVVT = 1; //Next event is for PWM1 + } + else { VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_max_count; } //Shouldn't ever get here } else { - VVT_PIN_HIGH(); // Switch pin high - VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_value; - vvt_pwm_cur_value = vvt_pwm_value; - vvt_pwm_state = true; + if(nextVVT == 0) + { + if(vvt1_pwm_value < vvt_pwm_max_count) //Don't toggle if at 100% + { + if (configPage6.vvtPWMdir == 0) { *vvt1_pin_port &= ~(vvt1_pin_mask); } //Normal direction + else { *vvt1_pin_port |= (vvt1_pin_mask); } //Reversed direction + vvt1_pwm_state = false; + vvt1_max_pwm = false; + } + else { vvt1_max_pwm = true; } + nextVVT = 1; //Next event is for PWM1 + if(vvt2_pwm_state == true){ VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt2_pwm_cur_value - vvt1_pwm_cur_value); } + else + { + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt1_pwm_cur_value); + nextVVT = 2; //Next event is for both PWM + } + } + else if (nextVVT == 1) + { + if(vvt2_pwm_value < vvt_pwm_max_count) //Don't toggle if at 100% + { + if (configPage6.vvtPWMdir == 0) { *vvt2_pin_port &= ~(vvt2_pin_mask); } //Normal direction + else { *vvt2_pin_port |= (vvt2_pin_mask); } //Reversed direction + vvt2_pwm_state = false; + vvt2_max_pwm = false; + } + else { vvt2_max_pwm = true; } + nextVVT = 0; //Next event is for PWM0 + if(vvt1_pwm_state == true) { VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt1_pwm_cur_value - vvt2_pwm_cur_value); } + else + { + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt2_pwm_cur_value); + nextVVT = 2; //Next event is for both PWM + } + } + else + { + if(vvt1_pwm_value < vvt_pwm_max_count) //Don't toggle if at 100% + { + if (configPage6.vvtPWMdir == 0) { *vvt1_pin_port &= ~(vvt1_pin_mask); } //Normal direction + else { *vvt1_pin_port |= (vvt1_pin_mask); } //Reversed direction + vvt1_pwm_state = false; + vvt1_max_pwm = false; + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt1_pwm_cur_value); + } + else { vvt1_max_pwm = true; } + if(vvt2_pwm_value < vvt_pwm_max_count) //Don't toggle if at 100% + { + if (configPage6.vvtPWMdir == 0) { *vvt2_pin_port &= ~(vvt2_pin_mask); } //Normal direction + else { *vvt2_pin_port |= (vvt2_pin_mask); } //Reversed direction + vvt2_pwm_state = false; + vvt2_max_pwm = false; + VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + (vvt_pwm_max_count - vvt2_pwm_cur_value); + } + else { vvt2_max_pwm = true; } + } } } diff --git a/speeduino/comms.ino b/speeduino/comms.ino index 2faa9e73..e0b5f157 100644 --- a/speeduino/comms.ino +++ b/speeduino/comms.ino @@ -638,9 +638,9 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum) fullStatus[90] = highByte(currentStatus.dwell); fullStatus[91] = currentStatus.CLIdleTarget; fullStatus[92] = currentStatus.mapDOT; - fullStatus[93] = (int8_t)currentStatus.vvtAngle; - fullStatus[94] = currentStatus.vvtTargetAngle; - fullStatus[95] = currentStatus.vvtDuty; + fullStatus[93] = (int8_t)currentStatus.vvt1Angle; + fullStatus[94] = currentStatus.vvt1TargetAngle; + fullStatus[95] = currentStatus.vvt1Duty; fullStatus[96] = lowByte(currentStatus.flexBoostCorrection); fullStatus[97] = highByte(currentStatus.flexBoostCorrection); fullStatus[98] = currentStatus.baroCorrection; @@ -653,6 +653,9 @@ void sendValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portNum) fullStatus[105] = currentStatus.oilPressure; fullStatus[106] = currentStatus.wmiPW; fullStatus[107] = currentStatus.wmiEmpty; + fullStatus[108] = (int8_t)currentStatus.vvt2Angle; + fullStatus[109] = currentStatus.vvt2TargetAngle; + fullStatus[110] = currentStatus.vvt2Duty; for(byte x=0; x 360) { curAngle -= 360; } + curAngle -= configPage4.triggerAngle; //Value at TDC + if( configPage6.vvtMode == VVT_MODE_CLOSED_LOOP ) { curAngle -= configPage10.vvtCLMinAng; } + + currentStatus.vvt1Angle = curAngle; + } } //Trigger filter } @@ -2205,9 +2218,9 @@ int getCamAngle_Miata9905() { //lastVVTtime is the time between tooth #1 (10* BTDC) and the single cam tooth. //All cam angles in in BTDC, so the actual advance angle is 370 - fastTimeToAngle(lastVVTtime) - - currentStatus.vvtAngle = 370 - fastTimeToAngle(lastVVTtime) - configPage10.vvtCLMinAng; + currentStatus.vvt1Angle = 370 - fastTimeToAngle(lastVVTtime) - configPage10.vvtCLMinAng; - return currentStatus.vvtAngle; + return currentStatus.vvt1Angle; } void triggerSetEndTeeth_Miata9905() diff --git a/speeduino/globals.h b/speeduino/globals.h index 8604444d..d3e14674 100644 --- a/speeduino/globals.h +++ b/speeduino/globals.h @@ -579,10 +579,10 @@ struct statuses { bool knockActive; bool toothLogEnabled; bool compositeLogEnabled; - //int8_t vvtAngle; - long vvtAngle; - byte vvtTargetAngle; - byte vvtDuty; + //int8_t vvt1Angle; + long vvt1Angle; + byte vvt1TargetAngle; + byte vvt1Duty; uint16_t injAngle; byte ASEValue; uint16_t vss; /**< Current speed reading. Natively stored in kph and converted to mph in TS if required */ @@ -592,6 +592,9 @@ struct statuses { byte engineProtectStatus; byte wmiPW; bool wmiEmpty; + long vvt2Angle; + byte vvt2TargetAngle; + byte vvt2Duty; }; /** @@ -852,7 +855,7 @@ struct config6 { byte egoCount; //The number of ignition cylces per step byte vvtMode : 2; //Valid VVT modes are 'on/off', 'open loop' and 'closed loop' byte vvtLoadSource : 2; //Load source for VVT (TPS or MAP) - byte vvtCLDir : 1; //VVT direction (advance or retard) + byte vvtPWMdir : 1; //VVT direction (normal or reverse) byte vvtCLUseHold : 1; //Whether or not to use a hold duty cycle (Most cases are Yes) byte vvtCLAlterFuelTiming : 1; byte boostCutEnabled : 1; @@ -862,7 +865,7 @@ struct config6 { byte ego_sdelay; //Time in seconds after engine starts that closed loop becomes available byte egoRPM; //RPM must be above this for closed loop to function byte egoTPSMax; //TPS must be below this for closed loop to function - byte vvtPin : 6; + byte vvt1Pin : 6; byte useExtBaro : 1; byte boostMode : 1; //Simple of full boost control byte boostPin : 6; @@ -1117,8 +1120,8 @@ struct config10 { byte vvtCLKP; //Byte 127 byte vvtCLKI; //Byte 128 byte vvtCLKD; //Byte 129 - uint16_t vvtCLMinAng; //Bytes 130-131 - uint16_t vvtCLMaxAng; //Bytes 132-133 + int16_t vvtCLMinAng; //Bytes 130-131 + int16_t vvtCLMaxAng; //Bytes 132-133 byte crankingEnrichTaper; //Byte 134 @@ -1163,8 +1166,13 @@ struct config10 { byte wmiAdvBins[6]; //Bytes 159-164 byte wmiAdvAdj[6]; //Additional advance (in degrees) //Bytes 165-170 + byte vvtCLminDuty; + byte vvtCLmaxDuty; + byte vvt2Pin : 6; + byte unused11_174_1 : 1; + byte unused11_174_2 : 1; - byte unused11_171_191[21]; //Bytes 171-191 + byte unused11_175_191[18]; //Bytes 175-191 #if defined(CORE_AVR) }; diff --git a/speeduino/init.ino b/speeduino/init.ino index a8fe053b..94967031 100644 --- a/speeduino/init.ino +++ b/speeduino/init.ino @@ -1267,6 +1267,7 @@ void setPinMapping(byte boardID) pinIdle2 = 53; //2 wire idle control pinBoost = 7; //Boost control pinVVT_1 = 6; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinFuelPump = 4; //Fuel pump output pinStepperDir = 16; //Direction pin for DRV8825 driver pinStepperStep = 17; //Step pin for DRV8825 driver @@ -1317,6 +1318,7 @@ void setPinMapping(byte boardID) pinIdle2 = 6; //2 wire idle control pinBoost = 7; //Boost control pinVVT_1 = 4; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinFuelPump = 45; //Fuel pump output (Goes to ULN2803) pinStepperDir = 16; //Direction pin for DRV8825 driver pinStepperStep = 17; //Step pin for DRV8825 driver @@ -1417,13 +1419,11 @@ void setPinMapping(byte boardID) /* = PD0; */ //CANRX /* = PD1; */ //CANTX /* = PD2; */ //(DO NOT USE FOR SPEEDUINO) - SDIO_CMD - /* = PD3; */ // - /* = PD4; */ // + pinVVT_2 = PD3; // pinFlex = PD4; /* = PD5;*/ //TXD2 /* = PD6; */ //RXD2 pinCoil1 = PD7; // - /* = PD7; */ // /* = PD8; */ // pinCoil5 = PD9;// /* = PD10; */ // @@ -1512,6 +1512,7 @@ void setPinMapping(byte boardID) pinIdle1 = 5; //Single wire idle control pinBoost = 4; pinVVT_1 = 11; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinIdle2 = 4; //2 wire idle control (Note this is shared with boost!!!) pinFuelPump = 40; //Fuel pump output pinStepperDir = 16; //Direction pin for DRV8825 driver @@ -1780,6 +1781,7 @@ void setPinMapping(byte boardID) pinIdle2 = 6; //ICV pin3 pinBoost = 7; //Boost control pinVVT_1 = 4; //VVT output + pinVVT_2 = 48; //Default VVT2 output pinFuelPump = 45; //Fuel pump output (Goes to ULN2003) pinStepperDir = 16; //Stepper valve isn't used with these pinStepperStep = 17; //Stepper valve isn't used with these @@ -1818,6 +1820,7 @@ void setPinMapping(byte boardID) pinIdle2 = 47; //2 wire idle control - NOT USED pinBoost = 7; //Boost control pinVVT_1 = 6; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinFuelPump = 4; //Fuel pump output pinStepperDir = 25; //Direction pin for DRV8825 driver pinStepperStep = 24; //Step pin for DRV8825 driver @@ -1863,6 +1866,7 @@ void setPinMapping(byte boardID) pinIdle2 = 10; //2 wire idle control pinFuelPump = 23; //Fuel pump output pinVVT_1 = 11; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinStepperDir = 32; //Direction pin for DRV8825 driver pinStepperStep = 31; //Step pin for DRV8825 driver pinStepperEnable = 30; //Enable pin for DRV8825 driver @@ -1908,6 +1912,7 @@ void setPinMapping(byte boardID) pinIdle2 = 43; //2 wire idle control pinFuelPump = 41; //Fuel pump output pinVVT_1 = 44; //Default VVT output + pinVVT_2 = 48; //Default VVT2 output pinStepperDir = 32; //Direction pin for DRV8825 driver pinStepperStep = 31; //Step pin for DRV8825 driver pinStepperEnable = 30; //Enable pin for DRV8825 driver @@ -2192,6 +2197,7 @@ void setPinMapping(byte boardID) pinIdle2 = PA2; //2 wire idle control pinBoost = PA1; //Boost control pinVVT_1 = PA0; //Default VVT output + pinVVT_2 = PA2; //Default VVT2 output pinStepperDir = PC15; //Direction pin for DRV8825 driver pinStepperStep = PC14; //Step pin for DRV8825 driver pinStepperEnable = PC13; //Enable pin for DRV8825 @@ -2360,7 +2366,7 @@ void setPinMapping(byte boardID) if ( (configPage4.fuelPumpPin != 0) && (configPage4.fuelPumpPin < BOARD_NR_GPIO_PINS) ) { pinFuelPump = pinTranslate(configPage4.fuelPumpPin); } if ( (configPage6.fanPin != 0) && (configPage6.fanPin < BOARD_NR_GPIO_PINS) ) { pinFan = pinTranslate(configPage6.fanPin); } if ( (configPage6.boostPin != 0) && (configPage6.boostPin < BOARD_NR_GPIO_PINS) ) { pinBoost = pinTranslate(configPage6.boostPin); } - if ( (configPage6.vvtPin != 0) && (configPage6.vvtPin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = pinTranslate(configPage6.vvtPin); } + if ( (configPage6.vvt1Pin != 0) && (configPage6.vvt1Pin < BOARD_NR_GPIO_PINS) ) { pinVVT_1 = pinTranslate(configPage6.vvt1Pin); } if ( (configPage6.useExtBaro != 0) && (configPage6.baroPin < BOARD_NR_GPIO_PINS) ) { pinBaro = configPage6.baroPin + A0; } if ( (configPage6.useEMAP != 0) && (configPage10.EMAPPin < BOARD_NR_GPIO_PINS) ) { pinEMAP = configPage10.EMAPPin + A0; } if ( (configPage10.fuel2InputPin != 0) && (configPage10.fuel2InputPin < BOARD_NR_GPIO_PINS) ) { pinFuel2Input = pinTranslate(configPage10.fuel2InputPin); } @@ -2371,6 +2377,7 @@ void setPinMapping(byte boardID) if ( (configPage10.wmiEmptyPin != 0) && (configPage10.wmiEmptyPin < BOARD_NR_GPIO_PINS) ) { pinWMIEmpty = pinTranslate(configPage10.wmiEmptyPin); } if ( (configPage10.wmiIndicatorPin != 0) && (configPage10.wmiIndicatorPin < BOARD_NR_GPIO_PINS) ) { pinWMIIndicator = pinTranslate(configPage10.wmiIndicatorPin); } if ( (configPage10.wmiEnabledPin != 0) && (configPage10.wmiEnabledPin < BOARD_NR_GPIO_PINS) ) { pinWMIEnabled = pinTranslate(configPage10.wmiEnabledPin); } + if ( (configPage10.vvt2Pin != 0) && (configPage10.vvt2Pin < BOARD_NR_GPIO_PINS) ) { pinVVT_2 = pinTranslate(configPage10.vvt2Pin); } //Currently there's no default pin for Idle Up pinIdleUp = pinTranslate(configPage2.idleUpPin); @@ -2401,6 +2408,7 @@ void setPinMapping(byte boardID) pinMode(pinStepperEnable, OUTPUT); pinMode(pinBoost, OUTPUT); pinMode(pinVVT_1, OUTPUT); + pinMode(pinVVT_2, OUTPUT); //This is a legacy mode option to revert the MAP reading behaviour to match what was in place prior to the 201905 firmware if(configPage2.legacyMAP > 0) { digitalWrite(pinMAP, HIGH); } @@ -2478,7 +2486,7 @@ void setPinMapping(byte boardID) //And for inputs #if defined(CORE_STM32) - #ifndef ARDUINO_ARCH_STM32 //libmaple core aka STM32DUINO + #ifdef INPUT_ANALOG pinMode(pinMAP, INPUT_ANALOG); pinMode(pinO2, INPUT_ANALOG); pinMode(pinO2_2, INPUT_ANALOG); diff --git a/speeduino/logger.h b/speeduino/logger.h index 9590b946..cf06ff96 100644 --- a/speeduino/logger.h +++ b/speeduino/logger.h @@ -9,8 +9,8 @@ #ifndef LOGGER_H #define LOGGER_H -#define LOG_ENTRY_SIZE 108 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ -#define SD_LOG_ENTRY_SIZE 108 /**< The size of the live data packet used by the SD car.*/ +#define LOG_ENTRY_SIZE 111 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */ +#define SD_LOG_ENTRY_SIZE 111 /**< The size of the live data packet used by the SD car.*/ void createLog(uint8_t *array); void createSDLog(uint8_t *array); diff --git a/speeduino/logger.ino b/speeduino/logger.ino index e71cf85a..c8a4d959 100644 --- a/speeduino/logger.ino +++ b/speeduino/logger.ino @@ -114,10 +114,22 @@ void createLog(uint8_t *logBuffer) logBuffer[90] = highByte(currentStatus.dwell); logBuffer[91] = currentStatus.CLIdleTarget; logBuffer[92] = currentStatus.mapDOT; - logBuffer[93] = (int8_t)currentStatus.vvtAngle; - logBuffer[94] = currentStatus.vvtTargetAngle; - logBuffer[95] = currentStatus.vvtDuty; + logBuffer[93] = (int8_t)currentStatus.vvt1Angle; + logBuffer[94] = currentStatus.vvt1TargetAngle; + logBuffer[95] = currentStatus.vvt1Duty; logBuffer[96] = lowByte(currentStatus.flexBoostCorrection); logBuffer[97] = highByte(currentStatus.flexBoostCorrection); logBuffer[98] = currentStatus.baroCorrection; + logBuffer[99] = currentStatus.VE; //Current VE (%). Can be equal to VE1 or VE2 or a calculated value from both of them + logBuffer[100] = currentStatus.ASEValue; //Current ASE (%) + logBuffer[101] = lowByte(currentStatus.vss); + logBuffer[102] = highByte(currentStatus.vss); + logBuffer[103] = currentStatus.gear; + logBuffer[104] = currentStatus.fuelPressure; + logBuffer[105] = currentStatus.oilPressure; + logBuffer[106] = currentStatus.wmiPW; + logBuffer[107] = currentStatus.wmiEmpty; + logBuffer[108] = (int8_t)currentStatus.vvt2Angle; + logBuffer[109] = currentStatus.vvt2TargetAngle; + logBuffer[110] = currentStatus.vvt2Duty; } \ No newline at end of file diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 26000cef..38ab3a1c 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -183,7 +183,8 @@ void loop() //This should only be run if the high speed logger are off because it will change the trigger interrupts back to defaults rather than the logger versions if( (currentStatus.toothLogEnabled == false) && (currentStatus.compositeLogEnabled == false) ) { initialiseTriggers(); } - VVT_PIN_LOW(); + VVT1_PIN_LOW(); + VVT2_PIN_LOW(); DISABLE_VVT_TIMER(); boostDisable(); if(configPage4.ignBypassEnabled > 0) { digitalWrite(pinIgnBypass, LOW); } //Reset the ignition bypass ready for next crank attempt @@ -242,6 +243,9 @@ void loop() vvtControl(); //Water methanol injection wmiControl(); + //FOR TEST PURPOSES ONLY!!! + if(vvt2_pwm_value < vvt_pwm_max_count) vvt2_pwm_value++; + else vvt2_pwm_value = 1; } if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ)) { diff --git a/speeduino/src/PID_v1/PID_v1.cpp b/speeduino/src/PID_v1/PID_v1.cpp index 591ef9fd..c48341f1 100755 --- a/speeduino/src/PID_v1/PID_v1.cpp +++ b/speeduino/src/PID_v1/PID_v1.cpp @@ -294,6 +294,41 @@ bool integerPID::Compute(bool pOnE) else return false; } +bool integerPID::ComputeVVT(uint32_t Sample) +{ + if(!inAuto) return false; + /*Compute all the working error variables*/ + long pTerm, iTerm, dTerm; + long input = *myInput; + long error = *mySetpoint - input; + long dInput = error - lastError; + long dTime = lastTime - Sample; + + pTerm = kp * error; + + if (ki != 0) + { + outputSum += (ki * error) * dTime; //integral += error × dt + if(outputSum > outMax*100) { outputSum = outMax*100; } + else if(outputSum < -outMax*100) { outputSum = -outMax*100; } + } + + dTerm = dInput * kd * dTime; + + /*Compute PID Output*/ + long output = (pTerm + outputSum + dTerm) >> 5; + + if(output > outMax) output = outMax; + else if(output < outMin) output = outMin; + *myOutput = output; + + /*Remember some variables for next time*/ + lastError = error; + lastTime = dTime; + + return true; +} + bool integerPID::Compute2(int target, int input, bool pOnE) { if(!inAuto) return false; @@ -363,7 +398,7 @@ bool integerPID::Compute2(int target, int input, bool pOnE) * it's called automatically from the constructor, but tunings can also * be adjusted on the fly during normal operation ******************************************************************************/ -void integerPID::SetTunings(byte Kp, byte Ki, byte Kd) +void integerPID::SetTunings(byte Kp, byte Ki, byte Kd, byte realTime) { if ( dispKp == Kp && dispKi == Ki && dispKd == Kd ) return; //Only do anything if one of the values has changed dispKp = Kp; dispKi = Ki; dispKd = Kd; @@ -374,13 +409,22 @@ void integerPID::SetTunings(byte Kp, byte Ki, byte Kd) ki = Ki * SampleTimeInSec; kd = Kd / SampleTimeInSec; */ - long InverseSampleTimeInSec = 1000 / SampleTime; - //New resolution, 2 shifts to improve ki here | kp 1.563% | ki 1.563% | kd 0.195% - kp = (uint16_t)Kp<<2; - ki = (long)(Ki<<2) / InverseSampleTimeInSec; - kd = (long)(Kd<<2) * InverseSampleTimeInSec; + if(realTime == 0) + { + long InverseSampleTimeInSec = 1000 / SampleTime; + //New resolution, 5 shifts to improve ki here | kp 3.125% | ki 3.125% | kd 0.781% + kp = (uint16_t)Kp<<5; + ki = (long)(Ki<<5) / InverseSampleTimeInSec; + kd = (long)(Kd<<5) * InverseSampleTimeInSec; + } + else + { + kp = Kp; + ki = Ki; + kd = Kd; + } - if(controllerDirection == REVERSE) + if(controllerDirection == REVERSE) { kp = (0 - kp); ki = (0 - ki); diff --git a/speeduino/src/PID_v1/PID_v1.h b/speeduino/src/PID_v1/PID_v1.h index 61af0c40..21d449f6 100755 --- a/speeduino/src/PID_v1/PID_v1.h +++ b/speeduino/src/PID_v1/PID_v1.h @@ -88,7 +88,7 @@ class integerPID #define MANUAL 0 #define DIRECT 0 #define REVERSE 1 - #define PID_SHIFTS 7 //Increased resolution + #define PID_SHIFTS 10 //Increased resolution //commonly used functions ************************************************************************** integerPID(long*, long*, long*, // * constructor. links the PID to the Input, Output, and @@ -102,7 +102,8 @@ class integerPID // calculation frequency can be set using SetMode // SetSampleTime respectively bool Compute2(int, int, bool); - + bool ComputeVVT(uint32_t); + void SetOutputLimits(long, long); //clamps the output to a specific range. 0-255 by default, but //it's likely the user will want to change this depending on //the application @@ -111,7 +112,7 @@ class integerPID //available but not commonly used functions ******************************************************** void SetTunings(byte, byte, // * While most users will set the tunings once in the - byte); // constructor, this function gives the user the option + byte, byte=0); // constructor, this function gives the user the option // of changing tunings during runtime for Adaptive control void SetControllerDirection(byte); // * Sets the Direction, or "Action" of the controller. DIRECT // means the output will increase when error is positive. REVERSE