Merge branch 'master' into pr/73
# Conflicts: # reference/speeduino.ini # speeduino/comms.h # speeduino/comms.ino # speeduino/globals.h
|
@ -34,7 +34,15 @@ framework = arduino
|
||||||
; framework-arduinoststm32
|
; framework-arduinoststm32
|
||||||
board = genericSTM32F103RB
|
board = genericSTM32F103RB
|
||||||
lib_deps = EEPROM
|
lib_deps = EEPROM
|
||||||
build_flags = -fpermissive
|
build_flags = -fpermissive -std=gnu++11
|
||||||
|
|
||||||
|
[env:bluepill_f103c8]
|
||||||
|
platform = ststm32
|
||||||
|
framework = arduino
|
||||||
|
; framework-arduinoststm32
|
||||||
|
board = bluepill_f103c8
|
||||||
|
lib_deps = EEPROM
|
||||||
|
build_flags = -fpermissive -std=gnu++11
|
||||||
|
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
|
@ -44,3 +52,4 @@ env_default = megaatmega2560
|
||||||
;env_default = teensy35
|
;env_default = teensy35
|
||||||
;env_default = LaunchPad_tm4c1294ncpdt
|
;env_default = LaunchPad_tm4c1294ncpdt
|
||||||
;env_default = genericSTM32F103RB
|
;env_default = genericSTM32F103RB
|
||||||
|
;env_default = bluepill_f103c8
|
||||||
|
|
|
@ -41,6 +41,9 @@
|
||||||
rpmhigh = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
rpmhigh = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
||||||
rpmwarn = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
rpmwarn = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
||||||
rpmdang = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
rpmdang = scalar, U16, "rpm", 1, 0, 0, 30000, 0
|
||||||
|
|
||||||
|
idleUnits = bits, U08, [0:2], "None", "On/Off", "Duty Cycle", "Duty Cycle", "Steps", "Steps"
|
||||||
|
|
||||||
[Constants]
|
[Constants]
|
||||||
|
|
||||||
;----------------------------------------------------------------------------
|
;----------------------------------------------------------------------------
|
||||||
|
@ -215,11 +218,11 @@ page = 2
|
||||||
flexFuelLow = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0
|
flexFuelLow = scalar, U08, 57, "%", 1.0, 0.0, 0.0, 250.0, 0
|
||||||
flexFuelHigh = scalar, U08, 58, "%", 1.0, 0.0, 0.0, 250.0, 0
|
flexFuelHigh = scalar, U08, 58, "%", 1.0, 0.0, 0.0, 250.0, 0
|
||||||
flexAdvLow = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0
|
flexAdvLow = scalar, U08, 59, "Deg", 1.0, 0.0, 0.0, 250.0, 0
|
||||||
flexAdvHigh = scalar, U08, 40, "Deg", 1.0, 0.0, 0.0, 250.0, 0
|
flexAdvHigh = scalar, U08, 60, "Deg", 1.0, 0.0, 0.0, 250.0, 0
|
||||||
|
|
||||||
iacCLminDuty = scalar, U08, 61, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles when using closed loop idle
|
iacCLminDuty = scalar, U08, 61, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles when using closed loop idle
|
||||||
iacCLmaxDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0
|
iacCLmaxDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0
|
||||||
boostMinDuty = scalar, U08, 62, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles for boost control
|
boostMinDuty = scalar, U08, 63, "%", 1.0, 0.0, 0.0, 100.0, 0 ; Minimum and maximum duty cycles for boost control
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,7 +258,7 @@ page = 4
|
||||||
TrigPattern= bits, U08, 5,[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "INVALID", "INVALID", "INVALID"
|
TrigPattern= bits, U08, 5,[4:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "INVALID", "INVALID", "INVALID"
|
||||||
TrigEdgeSec= bits, U08, 6,[0:0], "Leading", "Trailing"
|
TrigEdgeSec= bits, U08, 6,[0:0], "Leading", "Trailing"
|
||||||
fuelPumpPin= bits , U08, 6,[1:6], "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"
|
fuelPumpPin= bits , U08, 6,[1:6], "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"
|
||||||
unused4-6h = bits, U08, 6,[7:7], "No", "Yes"
|
useResync = bits, U08, 6,[7:7], "No", "Yes"
|
||||||
unused4-7 = scalar, U08, 7, "ADC", 1, 0, 0, 255, 0
|
unused4-7 = scalar, U08, 7, "ADC", 1, 0, 0, 255, 0
|
||||||
IdleAdvRPM = scalar, U08, 8, "RPM", 100, 0, 0, 1200, 0
|
IdleAdvRPM = scalar, U08, 8, "RPM", 100, 0, 0, 1200, 0
|
||||||
#if CELSIUS
|
#if CELSIUS
|
||||||
|
@ -433,7 +436,7 @@ page = 7
|
||||||
iacCrankBins = array, U08, 48, [4], "F", 1.8, -22.23, -40, 215, 0
|
iacCrankBins = array, U08, 48, [4], "F", 1.8, -22.23, -40, 215, 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
iacAlgorithm = bits , U08, 52, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper", "INVALID", "INVALID", "INVALID"
|
iacAlgorithm = bits , U08, 52, [0:2], "None", "On/Off", "PWM Open loop", "PWM Closed loop", "Stepper Open Loop", "Stepper Closed Loop", "INVALID", "INVALID"
|
||||||
iacStepTime = bits , U08, 52, [3:5], "1", "2", "3", "4", "5", "6"
|
iacStepTime = bits , U08, 52, [3:5], "1", "2", "3", "4", "5", "6"
|
||||||
iacChannels = bits, U08, 52, [6:6], "1", "2"
|
iacChannels = bits, U08, 52, [6:6], "1", "2"
|
||||||
iacPWMdir = bits , U08, 52, [7:7], "Normal", "Reverse"
|
iacPWMdir = bits , U08, 52, [7:7], "Normal", "Reverse"
|
||||||
|
@ -683,6 +686,7 @@ page = 10
|
||||||
|
|
||||||
defaultValue = pinLayout, 1
|
defaultValue = pinLayout, 1
|
||||||
defaultValue = TrigPattern, 0
|
defaultValue = TrigPattern, 0
|
||||||
|
defaultValue = useResync, 1
|
||||||
defaultValue = sparkMode, 0
|
defaultValue = sparkMode, 0
|
||||||
defaultValue = indInjAng, 0
|
defaultValue = indInjAng, 0
|
||||||
defaultValue = inj1Ang, 355
|
defaultValue = inj1Ang, 355
|
||||||
|
@ -788,11 +792,11 @@ menuDialog = main
|
||||||
subMenu = warmup, "Warmup Enrichment"
|
subMenu = warmup, "Warmup Enrichment"
|
||||||
subMenu = std_separator
|
subMenu = std_separator
|
||||||
subMenu = idleSettings, "Idle Control"
|
subMenu = idleSettings, "Idle Control"
|
||||||
subMenu = iacClosedLoop_curve, "Idle - Closed loop targets", 7, { iacAlgorithm == 3 }
|
subMenu = iacClosedLoop_curve, "Idle - Closed loop targets", 7, { iacAlgorithm == 3 || iacAlgorithm == 5 }
|
||||||
subMenu = iacPwm_curve, "Idle - PWM Duty Cycle", 7, { iacAlgorithm == 2 }
|
subMenu = iacPwm_curve, "Idle - PWM Duty Cycle", 7, { iacAlgorithm == 2 }
|
||||||
subMenu = iacPwmCrank_curve, "Idle - PWM Cranking Duty Cycle", 7, { iacAlgorithm == 2 }
|
subMenu = iacPwmCrank_curve, "Idle - PWM Cranking Duty Cycle", 7, { iacAlgorithm == 2 }
|
||||||
subMenu = iacStep_curve, "Idle - Stepper Motor", 7, { iacAlgorithm == 4 || iacAlgorithm == 5 }
|
subMenu = iacStep_curve, "Idle - Stepper Motor", 7, { iacAlgorithm == 4 }
|
||||||
subMenu = iacStepCrank_curve, "Idle - Stepper Motor Cranking", 7, { iacAlgorithm == 4 || iacAlgorithm == 5 }
|
subMenu = iacStepCrank_curve, "Idle - Stepper Motor Cranking", 7, { iacAlgorithm == 4 }
|
||||||
|
|
||||||
menu = "&Accessories"
|
menu = "&Accessories"
|
||||||
subMenu = fanSettings, "Thermo Fan"
|
subMenu = fanSettings, "Thermo Fan"
|
||||||
|
@ -850,6 +854,7 @@ menuDialog = main
|
||||||
injLayout = "The injector layout and timing to be used. Options are: \n 1. Paired - 2 injectors per output. Outputs active is equal to half the number of cylinders. Outputs are timed over 1 crank revolution. \n 2. Semi-sequential: Same as paired except that injector channels are mirrored (1&4, 2&3) meaning the number of outputs used are equal to the number of cylinders. Only valid for 4 cylinders or less. \n 3. Banked: 2 outputs only used. \n 4. Sequential: 1 injector per output and outputs used equals the number of cylinders. Injection is timed over full cycle. "
|
injLayout = "The injector layout and timing to be used. Options are: \n 1. Paired - 2 injectors per output. Outputs active is equal to half the number of cylinders. Outputs are timed over 1 crank revolution. \n 2. Semi-sequential: Same as paired except that injector channels are mirrored (1&4, 2&3) meaning the number of outputs used are equal to the number of cylinders. Only valid for 4 cylinders or less. \n 3. Banked: 2 outputs only used. \n 4. Sequential: 1 injector per output and outputs used equals the number of cylinders. Injection is timed over full cycle. "
|
||||||
|
|
||||||
TrigPattern = "The type of input trigger decoder to be used."
|
TrigPattern = "The type of input trigger decoder to be used."
|
||||||
|
useResync = "If enabled, sync will be rechecked once every full cycle from the cam input. This is good for accuracy, however if your cam input is noisy then this can cause issues."
|
||||||
numteeth = "Number of teeth on Primary Wheel."
|
numteeth = "Number of teeth on Primary Wheel."
|
||||||
TrigSpeed = "Primary trigger speed."
|
TrigSpeed = "Primary trigger speed."
|
||||||
onetwo = "Number of Missing teeth on Primary Wheel."
|
onetwo = "Number of Missing teeth on Primary Wheel."
|
||||||
|
@ -874,8 +879,8 @@ menuDialog = main
|
||||||
iacStepHyster = "The minimum number of steps to move in any one go."
|
iacStepHyster = "The minimum number of steps to move in any one go."
|
||||||
iacAlgorithm = "Selects method of idle control.\nNone = no idle control valve.\nOn/Off valve.\nPWM valve (2,3 wire).\nStepper Valve (4,6,8 wire)."
|
iacAlgorithm = "Selects method of idle control.\nNone = no idle control valve.\nOn/Off valve.\nPWM valve (2,3 wire).\nStepper Valve (4,6,8 wire)."
|
||||||
iacPWMdir = "Normal PWM valves increase RPM with higher duty. If RPM decreases with higher duty then select Reverse"
|
iacPWMdir = "Normal PWM valves increase RPM with higher duty. If RPM decreases with higher duty then select Reverse"
|
||||||
iacCLminDuty= "When using closed loop idle control, this is the minimum duty cycle that the PID loop will allow. Combined with the maximum value, this specifies the working range of your idle valve
|
iacCLminDuty= "When using closed loop idle control, this is the minimum duty cycle that the PID loop will allow. Combined with the maximum value, this specifies the working range of your idle valve"
|
||||||
iacCLmaxDuty= "When using closed loop idle control, this is the maximum duty cycle that the PID loop will allow. Combined with the minimum value, this specifies the working range of your idle valve
|
iacCLmaxDuty= "When using closed loop idle control, this is the maximum duty cycle that the PID loop will allow. Combined with the minimum value, this specifies the working range of your idle valve"
|
||||||
|
|
||||||
oddfire2 = "The ATDC angle of channel 2 for oddfire engines. This is relative to the TDC angle of channel 1"
|
oddfire2 = "The ATDC angle of channel 2 for oddfire engines. This is relative to the TDC angle of channel 1"
|
||||||
oddfire3 = "The ATDC angle of channel 3 for oddfire engines. This is relative to the TDC angle of channel 1 (NOT channel 2)"
|
oddfire3 = "The ATDC angle of channel 3 for oddfire engines. This is relative to the TDC angle of channel 1 (NOT channel 2)"
|
||||||
|
@ -1105,9 +1110,9 @@ menuDialog = main
|
||||||
field = "Idle valve direction", iacPWMdir, { iacAlgorithm == 2 || iacAlgorithm == 3 }
|
field = "Idle valve direction", iacPWMdir, { iacAlgorithm == 2 || iacAlgorithm == 3 }
|
||||||
|
|
||||||
dialog = closedloop_idle, "Closed loop Idle"
|
dialog = closedloop_idle, "Closed loop Idle"
|
||||||
field = "P", idleKP, { iacAlgorithm == 3 }
|
field = "P", idleKP, { iacAlgorithm == 3 || iacAlgorithm == 5 }
|
||||||
field = "I", idleKI, { iacAlgorithm == 3 }
|
field = "I", idleKI, { iacAlgorithm == 3 || iacAlgorithm == 5 }
|
||||||
field = "D", idleKD, { iacAlgorithm == 3 }
|
field = "D", idleKD, { iacAlgorithm == 3 || iacAlgorithm == 5 }
|
||||||
field = "Minimum valve duty", iacCLminDuty, { iacAlgorithm == 3 }
|
field = "Minimum valve duty", iacCLminDuty, { iacAlgorithm == 3 }
|
||||||
field = "Maximum valve duty", iacCLmaxDuty, { iacAlgorithm == 3 }
|
field = "Maximum valve duty", iacCLmaxDuty, { iacAlgorithm == 3 }
|
||||||
|
|
||||||
|
@ -1157,8 +1162,9 @@ menuDialog = main
|
||||||
field = "Note: This is the number of revolutions that will be skipped during"
|
field = "Note: This is the number of revolutions that will be skipped during"
|
||||||
field = "cranking before the injectors and coils are fired"
|
field = "cranking before the injectors and coils are fired"
|
||||||
field = "Trigger edge", TrigEdge
|
field = "Trigger edge", TrigEdge
|
||||||
field = "Secondary trigger edge", TrigEdgeSec, { TrigPattern == 0 || TrigPattern == 2 }
|
field = "Secondary trigger edge", TrigEdgeSec, { TrigPattern == 0 || TrigPattern == 2 } ;Missing tooth and dual wheel
|
||||||
field = "Trigger Filter", TrigFilter
|
field = "Trigger Filter", TrigFilter
|
||||||
|
field = "Re-sync every cycle", useResync, { TrigPattern == 2 || TrigPattern == 4 || TrigPattern == 7 } ;Dual wheel, 4G63 and Audi 135
|
||||||
|
|
||||||
dialog = sparkSettings,"Spark Settings",4
|
dialog = sparkSettings,"Spark Settings",4
|
||||||
field = "Spark output mode", sparkMode
|
field = "Spark output mode", sparkMode
|
||||||
|
@ -1838,8 +1844,8 @@ cmdtestspk450dc = "E\x03\x0C"
|
||||||
deadValue = { 0 } ; Convenient unchanging value.
|
deadValue = { 0 } ; Convenient unchanging value.
|
||||||
|
|
||||||
ochGetCommand = "A"
|
ochGetCommand = "A"
|
||||||
|
ochBlockSize = 41
|
||||||
|
|
||||||
ochBlockSize = 39
|
|
||||||
|
|
||||||
secl = scalar, U08, 0, "sec", 1.000, 0.000
|
secl = scalar, U08, 0, "sec", 1.000, 0.000
|
||||||
squirt = scalar, U08, 1, "bits", 1.000, 0.000
|
squirt = scalar, U08, 1, "bits", 1.000, 0.000
|
||||||
|
@ -1902,10 +1908,11 @@ cmdtestspk450dc = "E\x03\x0C"
|
||||||
errorNum = bits, U08, 36, [0:1]
|
errorNum = bits, U08, 36, [0:1]
|
||||||
currentError = bits, U08, 36, [2:7]
|
currentError = bits, U08, 36, [2:7]
|
||||||
boostTarget = scalar, U08, 37, "kPa", 2.000, 0.000
|
boostTarget = scalar, U08, 37, "kPa", 2.000, 0.000
|
||||||
testoutputs = scalar, U08, 38, "bits", 1.000, 0.000
|
boostDuty = scalar, U08, 38, "%", 1.000, 0.000
|
||||||
testenabled = bits, U08, 38, [0:0]
|
idleLoad = scalar, U08, 39, { bitStringValue( idleUnits , iacAlgorithm ) }, 2.000, 0.000 ; This is a combined variable covering both PWM and stepper IACs. The units used depend on which idle algorithm is chosen
|
||||||
testactive = bits, U08, 38, [1:1]
|
testoutputs = scalar, U08, 40, "bits", 1.000, 0.000
|
||||||
;"", 1.0, 0.0
|
testenabled = bits, U08, 40, [0:0]
|
||||||
|
testactive = bits, U08, 40, [1:1]
|
||||||
|
|
||||||
; Computed output channels. See "megatuneExamples.ini" for all the
|
; Computed output channels. See "megatuneExamples.ini" for all the
|
||||||
; pre-defined variables, search for "???" and you'll see them.
|
; pre-defined variables, search for "???" and you'll see them.
|
||||||
|
@ -1997,6 +2004,7 @@ cmdtestspk450dc = "E\x03\x0C"
|
||||||
entry = spark, "Spark", int, "%d"
|
entry = spark, "Spark", int, "%d"
|
||||||
entry = egoCorrection, "Gego", int, "%d"
|
entry = egoCorrection, "Gego", int, "%d"
|
||||||
entry = airCorrection, "Gair", int, "%d"
|
entry = airCorrection, "Gair", int, "%d"
|
||||||
|
entry = batCorrection, "Gbattery", int, "%d"
|
||||||
entry = warmupEnrich, "Gwarm", int, "%d"
|
entry = warmupEnrich, "Gwarm", int, "%d"
|
||||||
;entry = baroCorrection, "Gbaro", int, "%d"
|
;entry = baroCorrection, "Gbaro", int, "%d"
|
||||||
entry = gammaEnrich, "Gammae", int, "%d"
|
entry = gammaEnrich, "Gammae", int, "%d"
|
||||||
|
@ -2008,14 +2016,19 @@ cmdtestspk450dc = "E\x03\x0C"
|
||||||
entry = dutyCycle, "DutyCycle1", float, "%.1f"
|
entry = dutyCycle, "DutyCycle1", float, "%.1f"
|
||||||
entry = dutyCycle, "DutyCycle2", float, "%.1f"
|
entry = dutyCycle, "DutyCycle2", float, "%.1f"
|
||||||
entry = TPSdot, "TPS DOT", int, "%d"
|
entry = TPSdot, "TPS DOT", int, "%d"
|
||||||
entry = advance, "Ignition Advance", int,"%d"
|
entry = advance, "Advance", int, "%d"
|
||||||
entry = dwell, "Dwell", int, "%d"
|
entry = dwell, "Dwell", int, "%d"
|
||||||
entry = batteryVoltage, "Battery V", float, "%.1f"
|
entry = batteryVoltage, "Battery V", float, "%.1f"
|
||||||
entry = rpmDOT, "rpm/s", int, "%d"
|
entry = rpmDOT, "rpm/s", int, "%d"
|
||||||
entry = flex, "%", int, "%d"
|
entry = flex, "Eth %", int, "%d", { flexEnabled }
|
||||||
entry = errorNum, "Error #", int, "%d"
|
entry = errorNum, "Error #", int, "%d"
|
||||||
entry = currentError, "Error ID", int, "%d"
|
entry = currentError, "Error ID", int, "%d"
|
||||||
entry = boostTarget, "Boost Target",int, "%d"
|
entry = boostTarget, "Boost Target",int, "%d", { boostEnabled }
|
||||||
|
entry = boostDuty, "Boost Duty", int, "%d", { boostEnabled }
|
||||||
|
entry = boostCutOut , "Boost cut", int, "%d"
|
||||||
|
entry = idleLoad, "IAC value", int, "%d"
|
||||||
|
|
||||||
|
; Indicators
|
||||||
|
|
||||||
[LoggerDefinition]
|
[LoggerDefinition]
|
||||||
; valid logger types: composite, tooth, trigger, csv
|
; valid logger types: composite, tooth, trigger, csv
|
||||||
|
|
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 42 KiB |
|
@ -52,6 +52,7 @@ void initialiseAuxPWM()
|
||||||
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
|
boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD);
|
||||||
boostPID.SetMode(AUTOMATIC); //Turn PID on
|
boostPID.SetMode(AUTOMATIC); //Turn PID on
|
||||||
|
|
||||||
|
currentStatus.boostDuty = 0;
|
||||||
boostCounter = 0;
|
boostCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ void boostControl()
|
||||||
if( (boostCounter & 31) == 1) { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); } //This only needs to be run very infrequently, once every 32 calls to boostControl(). This is approx. once per second
|
if( (boostCounter & 31) == 1) { boostPID.SetTunings(configPage3.boostKP, configPage3.boostKI, configPage3.boostKD); } //This only needs to be run very infrequently, once every 32 calls to boostControl(). This is approx. once per second
|
||||||
|
|
||||||
boostPID.Compute();
|
boostPID.Compute();
|
||||||
|
currentStatus.boostDuty = (unsigned long)(boost_pwm_target_value * 100UL) / boost_pwm_max_count;
|
||||||
TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt)
|
TIMSK1 |= (1 << OCIE1A); //Turn on the compare unit (ie turn on the interrupt)
|
||||||
}
|
}
|
||||||
else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel
|
else { TIMSK1 &= ~(1 << OCIE1A); } // Disable timer channel
|
||||||
|
@ -126,7 +127,7 @@ ISR(TIMER1_COMPB_vect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
//YET TO BE IMPLEMENTED ON TEENSY
|
//YET TO BE IMPLEMENTED ON TEENSY
|
||||||
void initialiseAuxPWM() { }
|
void initialiseAuxPWM() { }
|
||||||
void boostControl() { }
|
void boostControl() { }
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#define seqFuelPage 9
|
#define seqFuelPage 9
|
||||||
#define canbusPage 10//Config Page 10
|
#define canbusPage 10//Config Page 10
|
||||||
|
|
||||||
#define packetSize 39
|
#define packetSize 41
|
||||||
|
|
||||||
byte currentPage = 1;//Not the same as the speeduino config page numbers
|
byte currentPage = 1;//Not the same as the speeduino config page numbers
|
||||||
boolean isMap = true;
|
boolean isMap = true;
|
||||||
|
|
|
@ -215,8 +215,13 @@ void sendValues(int packetlength, byte portNum)
|
||||||
if (portNum == 3)
|
if (portNum == 3)
|
||||||
{
|
{
|
||||||
//CAN serial
|
//CAN serial
|
||||||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
|
||||||
Serial3.write("A"); //confirm cmd type
|
Serial3.write("A"); //confirm cmd type
|
||||||
Serial3.write(packetlength); //confirm no of byte to be sent
|
Serial3.write(packetlength); //confirm no of byte to be sent
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
Serial2.write("A"); //confirm cmd type
|
||||||
|
Serial2.write(packetlength); //confirm no of byte to be sent
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -272,11 +277,17 @@ void sendValues(int packetlength, byte portNum)
|
||||||
response[35] = currentStatus.flexIgnCorrection; //Ignition correction (Increased degrees of advance) for flex fuel
|
response[35] = currentStatus.flexIgnCorrection; //Ignition correction (Increased degrees of advance) for flex fuel
|
||||||
response[36] = getNextError();
|
response[36] = getNextError();
|
||||||
response[37] = currentStatus.boostTarget;
|
response[37] = currentStatus.boostTarget;
|
||||||
response[38] = currentStatus.testOutputs;
|
response[38] = currentStatus.boostDuty;
|
||||||
|
response[39] = currentStatus.idleLoad;
|
||||||
|
response[40] = currentStatus.testOutputs;
|
||||||
|
|
||||||
//cli();
|
//cli();
|
||||||
if (portNum == 0) { Serial.write(response, (size_t)packetlength); }
|
if (portNum == 0) { Serial.write(response, (size_t)packetlength); }
|
||||||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //ATmega2561 does not have Serial3
|
||||||
else if (portNum == 3) { Serial3.write(response, (size_t)packetlength); }
|
else if (portNum == 3) { Serial3.write(response, (size_t)packetlength); }
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
else if (portNum == 3) { Serial2.write(response, (size_t)packetlength); }
|
||||||
|
#endif
|
||||||
//sei();
|
//sei();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,12 @@ volatile bool toothLogRead = false; //Flag to indicate whether the current tooth
|
||||||
|
|
||||||
volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
volatile unsigned int secondaryToothCount; //Used for identifying the current secondary (Usually cam) tooth for patterns with multiple secondary teeth
|
||||||
volatile unsigned long secondaryLastToothTime = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
volatile unsigned long secondaryLastToothTime = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
||||||
|
volatile unsigned long secondaryLastToothTime1 = 0; //The time (micros()) that the last tooth was registered (Cam input)
|
||||||
|
|
||||||
volatile int triggerActualTeeth;
|
volatile int triggerActualTeeth;
|
||||||
volatile unsigned long triggerFilterTime; // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering)
|
volatile unsigned long triggerFilterTime; // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering)
|
||||||
unsigned int triggerSecFilterTime; // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering) for the secondary input
|
unsigned int triggerSecFilterTime; // The shortest time (in uS) that pulses will be accepted (Used for debounce filtering) for the secondary input
|
||||||
|
unsigned int triggerSecFilterTime_duration; // The shortest valid time (in uS) pulse DURATION
|
||||||
volatile int triggerToothAngle; //The number of crank degrees that elapse per tooth
|
volatile int triggerToothAngle; //The number of crank degrees that elapse per tooth
|
||||||
unsigned long revolutionTime; //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
|
unsigned long revolutionTime; //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
|
||||||
bool secondDerivEnabled; //The use of the 2nd derivative calculation is limited to certain decoders. This is set to either true or false in each decoders setup routine
|
bool secondDerivEnabled; //The use of the 2nd derivative calculation is limited to certain decoders. This is set to either true or false in each decoders setup routine
|
||||||
|
|
|
@ -88,7 +88,7 @@ Note: This does not currently support dual wheel (ie missing tooth + single toot
|
||||||
void triggerSetup_missingTooth()
|
void triggerSetup_missingTooth()
|
||||||
{
|
{
|
||||||
triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth
|
triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees that passes from tooth to tooth
|
||||||
if(configPage2.TrigSpeed) { triggerToothAngle = triggerToothAngle * 2; } //Account for cam speed missing tooth
|
if(configPage2.TrigSpeed) { triggerToothAngle = 720 / configPage2.triggerTeeth; } //Account for cam speed missing tooth
|
||||||
triggerActualTeeth = configPage2.triggerTeeth - configPage2.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
|
triggerActualTeeth = configPage2.triggerTeeth - configPage2.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt
|
||||||
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
|
triggerFilterTime = (int)(1000000 / (MAX_RPM / 60 * configPage2.triggerTeeth)); //Trigger filter time is the shortest possible time (in uS) that there can be between crank teeth (ie at max RPM). Any pulses that occur faster than this time will be disgarded as noise
|
||||||
secondDerivEnabled = false;
|
secondDerivEnabled = false;
|
||||||
|
@ -232,15 +232,15 @@ void triggerSec_DualWheel()
|
||||||
toothLastSecToothTime = curTime2;
|
toothLastSecToothTime = curTime2;
|
||||||
triggerSecFilterTime = curGap2 >> 2; //Set filter at 25% of the current speed
|
triggerSecFilterTime = curGap2 >> 2; //Set filter at 25% of the current speed
|
||||||
|
|
||||||
toothCurrentCount = configPage2.triggerTeeth;
|
|
||||||
|
|
||||||
if(!currentStatus.hasSync)
|
if(!currentStatus.hasSync)
|
||||||
{
|
{
|
||||||
toothLastToothTime = micros();
|
toothLastToothTime = micros();
|
||||||
toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage2.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place
|
toothLastMinusOneToothTime = (toothOneTime - 6000000) / configPage2.triggerTeeth; //Fixes RPM at 10rpm until a full revolution has taken place
|
||||||
|
toothCurrentCount = configPage2.triggerTeeth;
|
||||||
|
|
||||||
currentStatus.hasSync = true;
|
currentStatus.hasSync = true;
|
||||||
}
|
}
|
||||||
|
else if (configPage2.useResync) { toothCurrentCount = configPage2.triggerTeeth; }
|
||||||
|
|
||||||
revolutionOne = 1; //Sequential revolution reset
|
revolutionOne = 1; //Sequential revolution reset
|
||||||
}
|
}
|
||||||
|
@ -504,6 +504,8 @@ void triggerSetup_4G63()
|
||||||
|
|
||||||
triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth.
|
triggerFilterTime = 1500; //10000 rpm, assuming we're triggering on both edges off the crank tooth.
|
||||||
triggerSecFilterTime = (int)(1000000 / (MAX_RPM / 60 * 2)) / 2; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
|
triggerSecFilterTime = (int)(1000000 / (MAX_RPM / 60 * 2)) / 2; //Same as above, but fixed at 2 teeth on the secondary input and divided by 2 (for cam speed)
|
||||||
|
triggerSecFilterTime_duration = 4000;
|
||||||
|
secondaryLastToothTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void triggerPri_4G63()
|
void triggerPri_4G63()
|
||||||
|
@ -561,20 +563,40 @@ void triggerPri_4G63()
|
||||||
void triggerSec_4G63()
|
void triggerSec_4G63()
|
||||||
{
|
{
|
||||||
//byte crankState = READ_PRI_TRIGGER();
|
//byte crankState = READ_PRI_TRIGGER();
|
||||||
|
//First filter is a duration based one to ensure the pulse was of sufficient length (time)
|
||||||
|
//if(READ_SEC_TRIGGER()) { secondaryLastToothTime1 = micros(); return; }
|
||||||
|
if(currentStatus.hasSync)
|
||||||
|
{
|
||||||
|
//if ( (micros() - secondaryLastToothTime1) < triggerSecFilterTime_duration ) { return; } //1166 is the time taken to cross 70 degrees at 10k rpm
|
||||||
|
//triggerSecFilterTime_duration = (micros() - secondaryLastToothTime1) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
curTime2 = micros();
|
curTime2 = micros();
|
||||||
curGap2 = curTime2 - toothLastSecToothTime;
|
curGap2 = curTime2 - toothLastSecToothTime;
|
||||||
if ( curGap2 < triggerSecFilterTime ) { return; }
|
if ( curGap2 < triggerSecFilterTime ) { return; }
|
||||||
toothLastSecToothTime = curTime2;
|
toothLastSecToothTime = curTime2;
|
||||||
|
|
||||||
|
triggerSecFilterTime = curGap2 >> 1; //Basic 50% filter for the secondary reading
|
||||||
|
//triggerSecFilterTime = (curGap2 * 9) >> 5; //62.5%
|
||||||
|
//triggerSecFilterTime = (curGap2 * 6) >> 3; //75%
|
||||||
|
|
||||||
if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) || !currentStatus.hasSync)
|
if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) || !currentStatus.hasSync)
|
||||||
{
|
{
|
||||||
triggerFilterTime = 1500; //If this is removed, can have trouble getting sync again after the engine is turned off (but ECU not reset).
|
triggerFilterTime = 1500; //If this is removed, can have trouble getting sync again after the engine is turned off (but ECU not reset).
|
||||||
|
if(READ_PRI_TRIGGER())// && (crankState == digitalRead(pinTrigger)))
|
||||||
//Check the status of the crank trigger
|
|
||||||
//bool crank = digitalRead(pinTrigger);
|
|
||||||
if(READ_PRI_TRIGGER())
|
|
||||||
{
|
{
|
||||||
toothCurrentCount = 4; //If the crank trigger is currently HIGH, it means we're on tooth #1
|
toothCurrentCount = 4; //If the crank trigger is currently HIGH, it means we're on tooth #1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (micros() - secondaryLastToothTime1) < triggerSecFilterTime_duration )
|
||||||
|
{
|
||||||
|
triggerSecFilterTime_duration = (micros() - secondaryLastToothTime1) >> 1;
|
||||||
|
if(READ_PRI_TRIGGER())// && (crankState == digitalRead(pinTrigger)))
|
||||||
|
{
|
||||||
|
//toothCurrentCount = 4; //If the crank trigger is currently HIGH, it means we're on tooth #1
|
||||||
|
|
||||||
/* High-res mode
|
/* High-res mode
|
||||||
toothCurrentCount = 7; //If the crank trigger is currently HIGH, it means we're on the falling edge of the narrow crank tooth
|
toothCurrentCount = 7; //If the crank trigger is currently HIGH, it means we're on the falling edge of the narrow crank tooth
|
||||||
toothLastMinusOneToothTime = toothLastToothTime;
|
toothLastMinusOneToothTime = toothLastToothTime;
|
||||||
|
@ -582,20 +604,7 @@ void triggerSec_4G63()
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//triggerSecFilterTime = curGap2 >> 1; //Only set the filter when we have sync
|
|
||||||
//if(toothCurrentCount != 2)
|
|
||||||
{
|
|
||||||
if(READ_PRI_TRIGGER())// && (crankState == digitalRead(pinTrigger)))
|
|
||||||
{
|
|
||||||
toothCurrentCount = 4; //If the crank trigger is currently HIGH, it means we're on tooth #1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//else { triggerFilterTime = 1500; } //reset filter time (ugly)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,11 +875,12 @@ void triggerPri_Audi135()
|
||||||
curGap = curTime - toothSystemLastToothTime;
|
curGap = curTime - toothSystemLastToothTime;
|
||||||
if ( curGap < triggerFilterTime ) { return; }
|
if ( curGap < triggerFilterTime ) { return; }
|
||||||
toothSystemCount++;
|
toothSystemCount++;
|
||||||
toothSystemLastToothTime = curTime;
|
|
||||||
addToothLogEntry(curGap);
|
|
||||||
if ( !currentStatus.hasSync ) { toothLastToothTime = curTime; return; }
|
if ( !currentStatus.hasSync ) { toothLastToothTime = curTime; return; }
|
||||||
if ( toothSystemCount < 3 ) { return; } //We only proceed for every third tooth
|
if ( toothSystemCount < 3 ) { return; } //We only proceed for every third tooth
|
||||||
|
|
||||||
|
addToothLogEntry(curGap);
|
||||||
|
toothSystemLastToothTime = curTime;
|
||||||
toothSystemCount = 0;
|
toothSystemCount = 0;
|
||||||
toothCurrentCount++; //Increment the tooth counter
|
toothCurrentCount++; //Increment the tooth counter
|
||||||
|
|
||||||
|
@ -904,9 +914,7 @@ void triggerSec_Audi135()
|
||||||
currentStatus.hasSync = true;
|
currentStatus.hasSync = true;
|
||||||
toothSystemCount = 3; //Need to set this to 3 so that the next primary tooth is counted
|
toothSystemCount = 3; //Need to set this to 3 so that the next primary tooth is counted
|
||||||
}
|
}
|
||||||
else{
|
else if (configPage2.useResync) { toothCurrentCount = 0; }
|
||||||
toothCurrentCount = 0;
|
|
||||||
}
|
|
||||||
revolutionOne = 1; //Sequential revolution reset
|
revolutionOne = 1; //Sequential revolution reset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
|
||||||
#define CORE_AVR
|
#define CORE_AVR
|
||||||
|
#elif defined(STM32_MCU_SERIES)
|
||||||
|
#define CORE_STM32
|
||||||
|
|
||||||
|
inline unsigned char digitalPinToInterrupt(unsigned char Interrupt_pin) { return Interrupt_pin; } //This isn't included in the stm32duino libs (yet)
|
||||||
|
#define portOutputRegister(port) (volatile byte *)( &(port->regs->ODR) ) //These are defined in STM32F1/variants/generic_stm32f103c/variant.h but return a non byte* value
|
||||||
|
#define portInputRegister(port) (volatile byte *)( &(port->regs->IDR) ) //These are defined in STM32F1/variants/generic_stm32f103c/variant.h but return a non byte* value
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Handy bitsetting macros
|
//Handy bitsetting macros
|
||||||
|
@ -208,6 +214,8 @@ struct statuses {
|
||||||
byte boostTarget;
|
byte boostTarget;
|
||||||
byte testOutputs;
|
byte testOutputs;
|
||||||
bool testActive;
|
bool testActive;
|
||||||
|
byte boostDuty;
|
||||||
|
byte idleLoad; //Either the current steps or current duty cycle for the idle control.
|
||||||
|
|
||||||
//Helpful bitwise operations:
|
//Helpful bitwise operations:
|
||||||
//Useful reference: http://playground.arduino.cc/Code/BitMath
|
//Useful reference: http://playground.arduino.cc/Code/BitMath
|
||||||
|
@ -326,7 +334,7 @@ struct config2 {
|
||||||
|
|
||||||
byte TrigEdgeSec : 1;
|
byte TrigEdgeSec : 1;
|
||||||
byte fuelPumpPin : 6;
|
byte fuelPumpPin : 6;
|
||||||
byte unused4_6b : 1;
|
byte useResync : 1;
|
||||||
|
|
||||||
byte unused4_7;
|
byte unused4_7;
|
||||||
byte IdleAdvRPM;
|
byte IdleAdvRPM;
|
||||||
|
|
|
@ -4,6 +4,13 @@
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
|
|
||||||
|
#define IAC_ALGORITHM_NONE 0
|
||||||
|
#define IAC_ALGORITHM_ONOFF 1
|
||||||
|
#define IAC_ALGORITHM_PWM_OL 2
|
||||||
|
#define IAC_ALGORITHM_PWM_CL 3
|
||||||
|
#define IAC_ALGORITHM_STEP_OL 4
|
||||||
|
#define IAC_ALGORITHM_STEP_CL 5
|
||||||
|
|
||||||
#define STEPPER_FORWARD 0
|
#define STEPPER_FORWARD 0
|
||||||
#define STEPPER_BACKWARD 1
|
#define STEPPER_BACKWARD 1
|
||||||
#define IDLE_TABLE_SIZE 10
|
#define IDLE_TABLE_SIZE 10
|
||||||
|
@ -12,8 +19,8 @@ enum StepperStatus {SOFF, STEPPING, COOLING}; //The 2 statuses that a stepper ca
|
||||||
|
|
||||||
struct StepperIdle
|
struct StepperIdle
|
||||||
{
|
{
|
||||||
unsigned int curIdleStep; //Tracks the current location of the stepper
|
int curIdleStep; //Tracks the current location of the stepper
|
||||||
unsigned int targetIdleStep; //What the targetted step is
|
int targetIdleStep; //What the targetted step is
|
||||||
volatile StepperStatus stepperStatus;
|
volatile StepperStatus stepperStatus;
|
||||||
volatile unsigned long stepStartTime; //The time the curren
|
volatile unsigned long stepStartTime; //The time the curren
|
||||||
};
|
};
|
||||||
|
@ -32,6 +39,15 @@ struct StepperIdle
|
||||||
#define IDLE_TIMER_ENABLE() FTM2_C0SC |= FTM_CSC_CHIE
|
#define IDLE_TIMER_ENABLE() FTM2_C0SC |= FTM_CSC_CHIE
|
||||||
#define IDLE_TIMER_DISABLE() FTM2_C0SC &= ~FTM_CSC_CHIE
|
#define IDLE_TIMER_DISABLE() FTM2_C0SC &= ~FTM_CSC_CHIE
|
||||||
|
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
|
||||||
|
//Placeholders only
|
||||||
|
#define IDLE_COUNTER 0
|
||||||
|
#define IDLE_COMPARE 0
|
||||||
|
|
||||||
|
#define IDLE_TIMER_ENABLE()
|
||||||
|
#define IDLE_TIMER_DISABLE()
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct table2D iacClosedLoopTable;
|
struct table2D iacClosedLoopTable;
|
||||||
|
@ -54,11 +70,16 @@ volatile byte idle2_pin_mask;
|
||||||
volatile bool idle_pwm_state;
|
volatile bool idle_pwm_state;
|
||||||
unsigned int idle_pwm_max_count; //Used for variable PWM frequency
|
unsigned int idle_pwm_max_count; //Used for variable PWM frequency
|
||||||
volatile unsigned int idle_pwm_cur_value;
|
volatile unsigned int idle_pwm_cur_value;
|
||||||
|
long idle_pid_target_value;
|
||||||
long idle_pwm_target_value;
|
long idle_pwm_target_value;
|
||||||
long idle_cl_target_rpm;
|
long idle_cl_target_rpm;
|
||||||
|
byte idleCounter; //Used for tracking the number of calls to the idle control function
|
||||||
|
|
||||||
void initialiseIdle();
|
void initialiseIdle();
|
||||||
static inline void disableIdle();
|
static inline void disableIdle();
|
||||||
static inline void enableIdle();
|
static inline void enableIdle();
|
||||||
|
static inline byte isStepperHomed();
|
||||||
|
static inline byte checkForStepping();
|
||||||
|
static inline void doStep();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,7 @@ These functions cover the PWM and stepper idle control
|
||||||
Idle Control
|
Idle Control
|
||||||
Currently limited to on/off control and open loop PWM and stepper drive
|
Currently limited to on/off control and open loop PWM and stepper drive
|
||||||
*/
|
*/
|
||||||
integerPID idlePID(¤tStatus.longRPM, &idle_pwm_target_value, &idle_cl_target_rpm, configPage3.idleKP, configPage3.idleKI, configPage3.idleKD, 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 idlePID(¤tStatus.longRPM, &idle_pid_target_value, &idle_cl_target_rpm, configPage3.idleKP, configPage3.idleKI, configPage3.idleKD, DIRECT); //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
|
||||||
|
|
||||||
void initialiseIdle()
|
void initialiseIdle()
|
||||||
{
|
{
|
||||||
|
@ -75,16 +75,17 @@ void initialiseIdle()
|
||||||
// enable IRQ Interrupt
|
// enable IRQ Interrupt
|
||||||
NVIC_ENABLE_IRQ(IRQ_FTM2);
|
NVIC_ENABLE_IRQ(IRQ_FTM2);
|
||||||
|
|
||||||
|
#elif defined(MCU_STM32F103RB)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Initialising comprises of setting the 2D tables with the relevant values from the config pages
|
//Initialising comprises of setting the 2D tables with the relevant values from the config pages
|
||||||
switch(configPage4.iacAlgorithm)
|
switch(configPage4.iacAlgorithm)
|
||||||
{
|
{
|
||||||
case 0:
|
case IAC_ALGORITHM_NONE: //Case 0 is no idle control ('None')
|
||||||
//Case 0 is no idle control ('None')
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case IAC_ALGORITHM_ONOFF:
|
||||||
//Case 1 is on/off idle control
|
//Case 1 is on/off idle control
|
||||||
if (currentStatus.coolant < configPage4.iacFastTemp)
|
if (currentStatus.coolant < configPage4.iacFastTemp)
|
||||||
{
|
{
|
||||||
|
@ -92,13 +93,14 @@ void initialiseIdle()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case IAC_ALGORITHM_PWM_OL:
|
||||||
//Case 2 is PWM open loop
|
//Case 2 is PWM open loop
|
||||||
iacPWMTable.xSize = 10;
|
iacPWMTable.xSize = 10;
|
||||||
iacPWMTable.valueSize = SIZE_BYTE;
|
iacPWMTable.valueSize = SIZE_BYTE;
|
||||||
iacPWMTable.values = configPage4.iacOLPWMVal;
|
iacPWMTable.values = configPage4.iacOLPWMVal;
|
||||||
iacPWMTable.axisX = configPage4.iacBins;
|
iacPWMTable.axisX = configPage4.iacBins;
|
||||||
|
|
||||||
|
|
||||||
iacCrankDutyTable.xSize = 4;
|
iacCrankDutyTable.xSize = 4;
|
||||||
iacCrankDutyTable.valueSize = SIZE_BYTE;
|
iacCrankDutyTable.valueSize = SIZE_BYTE;
|
||||||
iacCrankDutyTable.values = configPage4.iacCrankDuty;
|
iacCrankDutyTable.values = configPage4.iacCrankDuty;
|
||||||
|
@ -112,7 +114,7 @@ void initialiseIdle()
|
||||||
enableIdle();
|
enableIdle();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case IAC_ALGORITHM_PWM_CL:
|
||||||
//Case 3 is PWM closed loop
|
//Case 3 is PWM closed loop
|
||||||
iacClosedLoopTable.xSize = 10;
|
iacClosedLoopTable.xSize = 10;
|
||||||
iacClosedLoopTable.valueSize = SIZE_BYTE;
|
iacClosedLoopTable.valueSize = SIZE_BYTE;
|
||||||
|
@ -132,9 +134,11 @@ void initialiseIdle()
|
||||||
idlePID.SetOutputLimits(percentage(configPage1.iacCLminDuty, idle_pwm_max_count), percentage(configPage1.iacCLmaxDuty, idle_pwm_max_count));
|
idlePID.SetOutputLimits(percentage(configPage1.iacCLminDuty, idle_pwm_max_count), percentage(configPage1.iacCLmaxDuty, idle_pwm_max_count));
|
||||||
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
|
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
|
||||||
idlePID.SetMode(AUTOMATIC); //Turn PID on
|
idlePID.SetMode(AUTOMATIC); //Turn PID on
|
||||||
|
|
||||||
|
idleCounter = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case IAC_ALGORITHM_STEP_OL:
|
||||||
//Case 2 is Stepper open loop
|
//Case 2 is Stepper open loop
|
||||||
iacStepTable.xSize = 10;
|
iacStepTable.xSize = 10;
|
||||||
iacStepTable.valueSize = SIZE_BYTE;
|
iacStepTable.valueSize = SIZE_BYTE;
|
||||||
|
@ -148,12 +152,14 @@ void initialiseIdle()
|
||||||
|
|
||||||
//homeStepper(); //Returns the stepper to the 'home' position
|
//homeStepper(); //Returns the stepper to the 'home' position
|
||||||
completedHomeSteps = 0;
|
completedHomeSteps = 0;
|
||||||
|
idleStepper.curIdleStep = 0;
|
||||||
idleStepper.stepperStatus = SOFF;
|
idleStepper.stepperStatus = SOFF;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case IAC_ALGORITHM_STEP_CL:
|
||||||
//Case 5 is Stepper closed loop
|
//Case 5 is Stepper closed loop
|
||||||
iacClosedLoopTable.xSize = 10;
|
iacClosedLoopTable.xSize = 10;
|
||||||
|
iacClosedLoopTable.valueSize = SIZE_BYTE;
|
||||||
iacClosedLoopTable.values = configPage4.iacCLValues;
|
iacClosedLoopTable.values = configPage4.iacCLValues;
|
||||||
iacClosedLoopTable.axisX = configPage4.iacBins;
|
iacClosedLoopTable.axisX = configPage4.iacBins;
|
||||||
|
|
||||||
|
@ -162,11 +168,18 @@ void initialiseIdle()
|
||||||
iacCrankStepsTable.axisX = configPage4.iacCrankBins;
|
iacCrankStepsTable.axisX = configPage4.iacCrankBins;
|
||||||
iacStepTime = configPage4.iacStepTime * 1000;
|
iacStepTime = configPage4.iacStepTime * 1000;
|
||||||
|
|
||||||
homeStepper(); //Returns the stepper to the 'home' position
|
completedHomeSteps = 0;
|
||||||
|
idleCounter = 0;
|
||||||
|
idleStepper.curIdleStep = 0;
|
||||||
idleStepper.stepperStatus = SOFF;
|
idleStepper.stepperStatus = SOFF;
|
||||||
|
|
||||||
|
idlePID.SetOutputLimits(0, (configPage4.iacStepHome * 3)); //Maximum number of steps probably needs its own setting
|
||||||
|
idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
|
||||||
|
idlePID.SetMode(AUTOMATIC); //Turn PID on
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
idleInitComplete = configPage4.iacAlgorithm; //Sets which idle method was initialised
|
idleInitComplete = configPage4.iacAlgorithm; //Sets which idle method was initialised
|
||||||
|
currentStatus.idleLoad = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void idleControl()
|
void idleControl()
|
||||||
|
@ -175,10 +188,10 @@ void idleControl()
|
||||||
|
|
||||||
switch(configPage4.iacAlgorithm)
|
switch(configPage4.iacAlgorithm)
|
||||||
{
|
{
|
||||||
case 0: //Case 0 is no idle control ('None')
|
case IAC_ALGORITHM_NONE: //Case 0 is no idle control ('None')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: //Case 1 is on/off idle control
|
case IAC_ALGORITHM_ONOFF: //Case 1 is on/off idle control
|
||||||
if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage4.iacFastTemp) //All temps are offset by 40 degrees
|
if ( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < configPage4.iacFastTemp) //All temps are offset by 40 degrees
|
||||||
{
|
{
|
||||||
digitalWrite(pinIdle1, HIGH);
|
digitalWrite(pinIdle1, HIGH);
|
||||||
|
@ -187,7 +200,7 @@ void idleControl()
|
||||||
else if (idleOn) { digitalWrite(pinIdle1, LOW); idleOn = false; }
|
else if (idleOn) { digitalWrite(pinIdle1, LOW); idleOn = false; }
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: //Case 2 is PWM open loop
|
case IAC_ALGORITHM_PWM_OL: //Case 2 is PWM open loop
|
||||||
//Check for cranking pulsewidth
|
//Check for cranking pulsewidth
|
||||||
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
|
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
|
||||||
{
|
{
|
||||||
|
@ -203,23 +216,98 @@ void idleControl()
|
||||||
if( currentStatus.idleDuty == 0 ) { disableIdle(); break; }
|
if( currentStatus.idleDuty == 0 ) { disableIdle(); break; }
|
||||||
enableIdle();
|
enableIdle();
|
||||||
idle_pwm_target_value = percentage(currentStatus.idleDuty, idle_pwm_max_count);
|
idle_pwm_target_value = percentage(currentStatus.idleDuty, idle_pwm_max_count);
|
||||||
|
currentStatus.idleLoad = currentStatus.idleDuty >> 1;
|
||||||
idleOn = true;
|
idleOn = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: //Case 3 is PWM closed loop
|
case IAC_ALGORITHM_PWM_CL: //Case 3 is PWM closed loop
|
||||||
//No cranking specific value for closed loop (yet?)
|
//No cranking specific value for closed loop (yet?)
|
||||||
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
|
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
|
||||||
//idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD);
|
if( (idleCounter & 31) == 1) { idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD); } //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second
|
||||||
|
|
||||||
idlePID.Compute();
|
idlePID.Compute();
|
||||||
|
idle_pwm_target_value = idle_pid_target_value;
|
||||||
if( idle_pwm_target_value == 0 ) { disableIdle(); }
|
if( idle_pwm_target_value == 0 ) { disableIdle(); }
|
||||||
else{ enableIdle(); } //Turn on the C compare unit (ie turn on the interrupt)
|
else{ enableIdle(); } //Turn on the C compare unit (ie turn on the interrupt)
|
||||||
|
currentStatus.idleLoad = ((unsigned long)(idle_pwm_target_value * 100UL) / idle_pwm_max_count) >> 1;
|
||||||
//idle_pwm_target_value = 104;
|
//idle_pwm_target_value = 104;
|
||||||
|
|
||||||
|
idleCounter++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: //Case 4 is open loop stepper control
|
case IAC_ALGORITHM_STEP_OL: //Case 4 is open loop stepper control
|
||||||
//First thing to check is whether there is currently a step going on and if so, whether it needs to be turned off
|
//First thing to check is whether there is currently a step going on and if so, whether it needs to be turned off
|
||||||
|
if( checkForStepping() ) { return; } //If this is true it means there's either a step taking place or
|
||||||
|
if( !isStepperHomed() ) { return; } //Check whether homing is completed yet.
|
||||||
|
|
||||||
|
//Check for cranking pulsewidth
|
||||||
|
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
|
||||||
|
{
|
||||||
|
//Currently cranking. Use the cranking table
|
||||||
|
idleStepper.targetIdleStep = table2D_getValue(&iacCrankStepsTable, (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
|
||||||
|
doStep();
|
||||||
|
}
|
||||||
|
else if( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < iacStepTable.axisX[IDLE_TABLE_SIZE-1])
|
||||||
|
{
|
||||||
|
//Standard running
|
||||||
|
if ((mainLoopCount & 255) == 1)
|
||||||
|
{
|
||||||
|
//Only do a lookup of the required value around 4 times per second. Any more than this can create too much jitter and require a hyster value that is too high
|
||||||
|
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
|
||||||
|
}
|
||||||
|
doStep();
|
||||||
|
}
|
||||||
|
currentStatus.idleLoad = idleStepper.curIdleStep >> 1; //Current step count (Divided by 2 for byte)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IAC_ALGORITHM_STEP_CL://Case 5 is closed loop stepper control
|
||||||
|
//First thing to check is whether there is currently a step going on and if so, whether it needs to be turned off
|
||||||
|
if( checkForStepping() ) { return; } //If this is true it means there's either a step taking place or
|
||||||
|
if( !isStepperHomed() ) { return; } //Check whether homing is completed yet.
|
||||||
|
if( (idleCounter & 31) == 1) { idlePID.SetTunings(configPage3.idleKP, configPage3.idleKI, configPage3.idleKD); } //This only needs to be run very infrequently, once every 32 calls to idleControl(). This is approx. once per second
|
||||||
|
|
||||||
|
|
||||||
|
idle_cl_target_rpm = table2D_getValue(&iacClosedLoopTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) * 10; //All temps are offset by 40 degrees
|
||||||
|
idlePID.Compute();
|
||||||
|
idleStepper.targetIdleStep = idle_pid_target_value;
|
||||||
|
|
||||||
|
doStep();
|
||||||
|
currentStatus.idleLoad = idleStepper.curIdleStep >> 1; //Current step count (Divided by 2 for byte)
|
||||||
|
idleCounter++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Checks whether the stepper has been homed yet. If it hasn't, will handle the next step
|
||||||
|
Returns:
|
||||||
|
True: If the system has been homed. No other action is taken
|
||||||
|
False: If the motor has not yet been homed. Will also perform another homing step.
|
||||||
|
*/
|
||||||
|
static inline byte isStepperHomed()
|
||||||
|
{
|
||||||
|
if( completedHomeSteps < (configPage4.iacStepHome * 3) ) //Home steps are divided by 3 from TS
|
||||||
|
{
|
||||||
|
digitalWrite(pinStepperDir, STEPPER_BACKWARD); //Sets stepper direction to backwards
|
||||||
|
digitalWrite(pinStepperStep, HIGH);
|
||||||
|
idleStepper.stepStartTime = micros();
|
||||||
|
idleStepper.stepperStatus = STEPPING;
|
||||||
|
completedHomeSteps++;
|
||||||
|
idleOn = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Checks whether a step is currently underway or whether the motor is in 'cooling' state (ie whether it's ready to begin another step or not)
|
||||||
|
Returns:
|
||||||
|
True: If a step is underway or motor is 'cooling'
|
||||||
|
False: If the motor is ready for another step
|
||||||
|
*/
|
||||||
|
static inline byte checkForStepping()
|
||||||
|
{
|
||||||
if(idleStepper.stepperStatus == STEPPING || idleStepper.stepperStatus == COOLING)
|
if(idleStepper.stepperStatus == STEPPING || idleStepper.stepperStatus == COOLING)
|
||||||
{
|
{
|
||||||
if(micros() > (idleStepper.stepStartTime + iacStepTime) )
|
if(micros() > (idleStepper.stepStartTime + iacStepTime) )
|
||||||
|
@ -230,7 +318,7 @@ void idleControl()
|
||||||
digitalWrite(pinStepperStep, LOW); //Turn off the step
|
digitalWrite(pinStepperStep, LOW); //Turn off the step
|
||||||
idleStepper.stepStartTime = micros();
|
idleStepper.stepStartTime = micros();
|
||||||
idleStepper.stepperStatus = COOLING; //'Cooling' is the time the stepper needs to sit in LOW state before the next step can be made
|
idleStepper.stepperStatus = COOLING; //'Cooling' is the time the stepper needs to sit in LOW state before the next step can be made
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -241,94 +329,64 @@ void idleControl()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Means we're in a step, but it doesn't need to turn off yet. No further action at this time
|
//Means we're in a step, but it doesn't need to turn off yet. No further action at this time
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if( completedHomeSteps < (configPage4.iacStepHome * 3) ) //Home steps are divided by 3 from TS
|
|
||||||
{
|
|
||||||
digitalWrite(pinStepperDir, STEPPER_BACKWARD); //Sets stepper direction to backwards
|
|
||||||
digitalWrite(pinStepperStep, HIGH);
|
|
||||||
idleStepper.stepStartTime = micros();
|
|
||||||
idleStepper.stepperStatus = STEPPING;
|
|
||||||
completedHomeSteps++;
|
|
||||||
idleOn = true;
|
|
||||||
}
|
|
||||||
//Check for cranking pulsewidth
|
|
||||||
else if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
|
|
||||||
{
|
|
||||||
//Currently cranking. Use the cranking table
|
|
||||||
idleStepper.targetIdleStep = table2D_getValue(&iacCrankStepsTable, (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 ( idleStepper.targetIdleStep > (idleStepper.curIdleStep - configPage4.iacStepHyster) && idleStepper.targetIdleStep < (idleStepper.curIdleStep + configPage4.iacStepHyster) ) { return; } //Hysteris check
|
|
||||||
else if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards
|
|
||||||
else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards
|
|
||||||
|
|
||||||
digitalWrite(pinStepperStep, HIGH);
|
|
||||||
idleStepper.stepStartTime = micros();
|
|
||||||
idleStepper.stepperStatus = STEPPING;
|
|
||||||
idleOn = true;
|
|
||||||
}
|
|
||||||
else if( (currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET) < iacStepTable.axisX[IDLE_TABLE_SIZE-1])
|
|
||||||
{
|
|
||||||
//Standard running
|
|
||||||
if ((mainLoopCount & 255) == 1)
|
|
||||||
{
|
|
||||||
//Only do a lookup of the required value around 4 times per second. Any more than this can create too much jitter and require a hyster value that is too high
|
|
||||||
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 ( idleStepper.targetIdleStep > (idleStepper.curIdleStep - configPage4.iacStepHyster) && idleStepper.targetIdleStep < (idleStepper.curIdleStep + configPage4.iacStepHyster) ) { return; } //Hysteris check
|
|
||||||
else if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards
|
|
||||||
else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards
|
|
||||||
|
|
||||||
digitalWrite(pinStepperStep, HIGH);
|
|
||||||
idleStepper.stepStartTime = micros();
|
|
||||||
idleStepper.stepperStatus = STEPPING;
|
|
||||||
idleOn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A simple function to home the stepper motor (If in use)
|
Performs a step
|
||||||
*/
|
*/
|
||||||
void homeStepper()
|
static inline void doStep()
|
||||||
{
|
{
|
||||||
//Need to 'home' the stepper on startup
|
if ( idleStepper.targetIdleStep > (idleStepper.curIdleStep - configPage4.iacStepHyster) && idleStepper.targetIdleStep < (idleStepper.curIdleStep + configPage4.iacStepHyster) ) { return; } //Hysteris check
|
||||||
digitalWrite(pinStepperDir, STEPPER_BACKWARD); //Sets stepper direction to backwards
|
else if(idleStepper.targetIdleStep < idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_BACKWARD); idleStepper.curIdleStep--; }//Sets stepper direction to backwards
|
||||||
for(int x=0; x < (configPage4.iacStepHome * 3); x++) //Step counts are divided by 3 in TS. Multiply back out here
|
else if (idleStepper.targetIdleStep > idleStepper.curIdleStep) { digitalWrite(pinStepperDir, STEPPER_FORWARD); idleStepper.curIdleStep++; }//Sets stepper direction to forwards
|
||||||
{
|
|
||||||
digitalWrite(pinStepperStep, HIGH);
|
digitalWrite(pinStepperStep, HIGH);
|
||||||
delayMicroseconds(iacStepTime);
|
idleStepper.stepStartTime = micros();
|
||||||
digitalWrite(pinStepperStep, LOW);
|
idleStepper.stepperStatus = STEPPING;
|
||||||
delayMicroseconds(iacStepTime);
|
idleOn = true;
|
||||||
}
|
|
||||||
digitalWrite(pinStepperDir, STEPPER_FORWARD);
|
|
||||||
idleStepper.curIdleStep = 0;
|
|
||||||
idleStepper.targetIdleStep = 0;
|
|
||||||
idleStepper.stepperStatus = SOFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//This function simply turns off the idle PWM and sets the pin low
|
//This function simply turns off the idle PWM and sets the pin low
|
||||||
static inline void disableIdle()
|
static inline void disableIdle()
|
||||||
{
|
{
|
||||||
|
if(configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_CL || configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_OL)
|
||||||
|
{
|
||||||
IDLE_TIMER_DISABLE();
|
IDLE_TIMER_DISABLE();
|
||||||
digitalWrite(pinIdle1, LOW);
|
digitalWrite(pinIdle1, LOW);
|
||||||
|
}
|
||||||
|
else if (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL || configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL)
|
||||||
|
{
|
||||||
|
idleStepper.targetIdleStep = 1; //Home the stepper
|
||||||
|
if( checkForStepping() ) { return; } //If this is true it means there's either a step taking place or
|
||||||
|
if( !isStepperHomed() ) { return; } //Check whether homing is completed yet.
|
||||||
|
doStep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Any common functions associated with starting the Idle
|
//Any common functions associated with starting the Idle
|
||||||
//Typically this is enabling the PWM interrupt
|
//Typically this is enabling the PWM interrupt
|
||||||
static inline void enableIdle()
|
static inline void enableIdle()
|
||||||
{
|
{
|
||||||
|
if(configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_CL || configPage4.iacAlgorithm == IAC_ALGORITHM_PWM_OL)
|
||||||
|
{
|
||||||
IDLE_TIMER_ENABLE();
|
IDLE_TIMER_ENABLE();
|
||||||
|
}
|
||||||
|
else if (configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL || configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER4_COMPC_vect)
|
ISR(TIMER4_COMPC_vect)
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined (CORE_STM32)
|
||||||
static inline void idleInterrupt() //Most ARM chips can simply call a function
|
static inline void idleInterrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined (CORE_TEENSY)
|
||||||
{
|
{
|
||||||
if (idle_pwm_state)
|
if (idle_pwm_state)
|
||||||
{
|
{
|
||||||
|
@ -367,3 +425,8 @@ static inline void idleInterrupt() //Most ARM chips can simply call a function
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#elif defined (CORE_STM32)
|
||||||
|
{
|
||||||
|
//No PWM idle for STM32 yet
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -157,8 +157,56 @@ See page 136 of the processors datasheet: http://www.atmel.com/Images/doc2549.pd
|
||||||
|
|
||||||
#elif defined(STM32_MCU_SERIES)
|
#elif defined(STM32_MCU_SERIES)
|
||||||
//Placeholders ONLY!
|
//Placeholders ONLY!
|
||||||
|
|
||||||
|
//https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/master/STM32F4/cores/maple/libmaple/timer.h#L51
|
||||||
#define MAX_TIMER_PERIOD 139808 // 2.13333333uS * 65535
|
#define MAX_TIMER_PERIOD 139808 // 2.13333333uS * 65535
|
||||||
#define uS_TO_TIMER_COMPARE(uS) ((uS * 15) >> 5) //Converts a given number of uS into the required number of timer ticks until that time has passed.
|
#define uS_TO_TIMER_COMPARE(uS) ((uS * 15) >> 5) //Converts a given number of uS into the required number of timer ticks until that time has passed.
|
||||||
|
|
||||||
|
#define FUEL1_COUNTER (TIMER2->regs).gen->CNT
|
||||||
|
#define FUEL2_COUNTER (TIMER2->regs).gen->CNT
|
||||||
|
#define FUEL3_COUNTER (TIMER2->regs).gen->CNT
|
||||||
|
#define FUEL4_COUNTER (TIMER2->regs).gen->CNT
|
||||||
|
|
||||||
|
#define IGN1_COUNTER (TIMER3->regs).gen->CNT
|
||||||
|
#define IGN2_COUNTER (TIMER3->regs).gen->CNT
|
||||||
|
#define IGN3_COUNTER (TIMER3->regs).gen->CNT
|
||||||
|
#define IGN4_COUNTER (TIMER3->regs).gen->CNT
|
||||||
|
#define IGN5_COUNTER (TIMER1->regs).gen->CNT
|
||||||
|
|
||||||
|
#define FUEL1_COMPARE (TIMER2->regs).gen->CCR1
|
||||||
|
#define FUEL2_COMPARE (TIMER2->regs).gen->CCR2
|
||||||
|
#define FUEL3_COMPARE (TIMER2->regs).gen->CCR3
|
||||||
|
#define FUEL4_COMPARE (TIMER2->regs).gen->CCR4
|
||||||
|
|
||||||
|
#define IGN1_COMPARE (TIMER3->regs).gen->CCR1
|
||||||
|
#define IGN2_COMPARE (TIMER3->regs).gen->CCR2
|
||||||
|
#define IGN3_COMPARE (TIMER3->regs).gen->CCR3
|
||||||
|
#define IGN4_COMPARE (TIMER3->regs).gen->CCR4
|
||||||
|
#define IGN5_COMPARE (TIMER1->regs).gen->CCR1
|
||||||
|
|
||||||
|
//https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/754bc2969921f1ef262bd69e7faca80b19db7524/STM32F1/system/libmaple/include/libmaple/timer.h#L444
|
||||||
|
#define FUEL1_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC1E
|
||||||
|
#define FUEL2_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC2E
|
||||||
|
#define FUEL3_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC3E
|
||||||
|
#define FUEL4_TIMER_ENABLE() (TIMER2->regs).gen->CCER |= TIMER_CCER_CC4E
|
||||||
|
|
||||||
|
#define IGN1_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC1E
|
||||||
|
#define IGN2_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC2E
|
||||||
|
#define IGN3_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC3E
|
||||||
|
#define IGN4_TIMER_ENABLE() (TIMER3->regs).gen->CCER |= TIMER_CCER_CC4E
|
||||||
|
#define IGN5_TIMER_ENABLE() (TIMER1->regs).gen->CCER |= TIMER_CCER_CC1E
|
||||||
|
|
||||||
|
#define FUEL1_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC1E
|
||||||
|
#define FUEL2_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC2E
|
||||||
|
#define FUEL3_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC3E
|
||||||
|
#define FUEL4_TIMER_DISABLE() (TIMER2->regs).gen->CCER &= ~TIMER_CCER_CC4E
|
||||||
|
|
||||||
|
#define IGN1_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC1E
|
||||||
|
#define IGN2_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC2E
|
||||||
|
#define IGN3_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC3E
|
||||||
|
#define IGN4_TIMER_DISABLE() (TIMER3->regs).gen->CCER &= ~TIMER_CCER_CC4E
|
||||||
|
#define IGN5_TIMER_DISABLE() (TIMER1->regs).gen->CCER &= ~TIMER_CCER_CC1E
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void initialiseSchedulers();
|
void initialiseSchedulers();
|
||||||
|
|
|
@ -428,7 +428,7 @@ void setIgnitionSchedule5(void (*startCallback)(), unsigned long timeout, unsign
|
||||||
//Timer3A (fuel schedule 1) Compare Vector
|
//Timer3A (fuel schedule 1) Compare Vector
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) //fuelSchedules 1 and 5
|
ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) //fuelSchedules 1 and 5
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a function
|
static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -450,7 +450,7 @@ static inline void fuelSchedule1Interrupt() //Most ARM chips can simply call a f
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER3_COMPB_vect, ISR_NOBLOCK) //fuelSchedule2
|
ISR(TIMER3_COMPB_vect, ISR_NOBLOCK) //fuelSchedule2
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a function
|
static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -471,7 +471,7 @@ static inline void fuelSchedule2Interrupt() //Most ARM chips can simply call a f
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER3_COMPC_vect, ISR_NOBLOCK) //fuelSchedule3
|
ISR(TIMER3_COMPC_vect, ISR_NOBLOCK) //fuelSchedule3
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void fuelSchedule3Interrupt() //Most ARM chips can simply call a function
|
static inline void fuelSchedule3Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -492,7 +492,7 @@ static inline void fuelSchedule3Interrupt() //Most ARM chips can simply call a f
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER4_COMPB_vect, ISR_NOBLOCK) //fuelSchedule4
|
ISR(TIMER4_COMPB_vect, ISR_NOBLOCK) //fuelSchedule4
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a function
|
static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -513,7 +513,7 @@ static inline void fuelSchedule4Interrupt() //Most ARM chips can simply call a f
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER5_COMPA_vect) //ignitionSchedule1
|
ISR(TIMER5_COMPA_vect) //ignitionSchedule1
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call a function
|
static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -537,7 +537,7 @@ static inline void ignitionSchedule1Interrupt() //Most ARM chips can simply call
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER5_COMPB_vect) //ignitionSchedule2
|
ISR(TIMER5_COMPB_vect) //ignitionSchedule2
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call a function
|
static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -561,7 +561,7 @@ static inline void ignitionSchedule2Interrupt() //Most ARM chips can simply call
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER5_COMPC_vect) //ignitionSchedule3
|
ISR(TIMER5_COMPC_vect) //ignitionSchedule3
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call a function
|
static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -585,7 +585,7 @@ static inline void ignitionSchedule3Interrupt() //Most ARM chips can simply call
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER4_COMPA_vect) //ignitionSchedule4
|
ISR(TIMER4_COMPA_vect) //ignitionSchedule4
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call a function
|
static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -609,7 +609,7 @@ static inline void ignitionSchedule4Interrupt() //Most ARM chips can simply call
|
||||||
|
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER1_COMPC_vect) //ignitionSchedule5
|
ISR(TIMER1_COMPC_vect) //ignitionSchedule5
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
static inline void ignitionSchedule5Interrupt() //Most ARM chips can simply call a function
|
static inline void ignitionSchedule5Interrupt() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
|
@ -914,7 +914,7 @@ void loop()
|
||||||
vvtControl();
|
vvtControl();
|
||||||
idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient.
|
idleControl(); //Perform any idle related actions. Even at higher frequencies, running 4x per second is sufficient.
|
||||||
}
|
}
|
||||||
if(configPage4.iacAlgorithm == 4) { idleControl(); } //Run idlecontrol every loop for stepper idle.
|
if(configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_OL || configPage4.iacAlgorithm == IAC_ALGORITHM_STEP_CL) { idleControl(); } //Run idlecontrol every loop for stepper idle.
|
||||||
|
|
||||||
//Always check for sync
|
//Always check for sync
|
||||||
//Main loop runs within this clause
|
//Main loop runs within this clause
|
||||||
|
|
|
@ -29,6 +29,8 @@ volatile uint16_t lastRPM_100ms; //Need to record this for rpmDOT calculation
|
||||||
#if defined (CORE_TEENSY)
|
#if defined (CORE_TEENSY)
|
||||||
IntervalTimer lowResTimer;
|
IntervalTimer lowResTimer;
|
||||||
void oneMSInterval();
|
void oneMSInterval();
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
void oneMSInterval();
|
||||||
#endif
|
#endif
|
||||||
void initialiseTimers();
|
void initialiseTimers();
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,11 @@ void initialiseTimers()
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY)
|
||||||
//Uses the PIT timer on Teensy.
|
//Uses the PIT timer on Teensy.
|
||||||
lowResTimer.begin(oneMSInterval, 1000);
|
lowResTimer.begin(oneMSInterval, 1000);
|
||||||
|
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
Timer4.setChannel1Mode(TIMER_OUTPUTCOMPARE);
|
||||||
|
Timer4.setPeriod(1000);
|
||||||
|
Timer4.attachCompare1Interrupt(oneMSInterval);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dwellLimit_uS = (1000 * configPage2.dwellLimit);
|
dwellLimit_uS = (1000 * configPage2.dwellLimit);
|
||||||
|
@ -48,7 +53,7 @@ void initialiseTimers()
|
||||||
//Executes every ~1ms.
|
//Executes every ~1ms.
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) //AVR chips use the ISR for this
|
||||||
ISR(TIMER2_OVF_vect, ISR_NOBLOCK)
|
ISR(TIMER2_OVF_vect, ISR_NOBLOCK)
|
||||||
#elif defined (CORE_TEENSY)
|
#elif defined (CORE_TEENSY) || defined(CORE_STM32)
|
||||||
void oneMSInterval() //Most ARM chips can simply call a function
|
void oneMSInterval() //Most ARM chips can simply call a function
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,11 +30,31 @@ int freeRam ()
|
||||||
|
|
||||||
// The difference is the free, available ram.
|
// The difference is the free, available ram.
|
||||||
return (uint16_t)stackTop - heapTop;
|
return (uint16_t)stackTop - heapTop;
|
||||||
|
#elif defined(CORE_STM32)
|
||||||
|
//Figure this out some_time
|
||||||
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPinMapping(byte boardID)
|
void setPinMapping(byte boardID)
|
||||||
{
|
{
|
||||||
|
//This is dumb, but it'll do for now to get things compiling
|
||||||
|
#if defined(CORE_STM32)
|
||||||
|
#define A0 0
|
||||||
|
#define A1 1
|
||||||
|
#define A2 2
|
||||||
|
#define A3 3
|
||||||
|
#define A4 4
|
||||||
|
#define A5 5
|
||||||
|
#define A6 6
|
||||||
|
#define A7 7
|
||||||
|
#define A8 8
|
||||||
|
#define A9 9
|
||||||
|
#define A13 13
|
||||||
|
#define A14 14
|
||||||
|
#define A15 15
|
||||||
|
#endif
|
||||||
|
|
||||||
switch (boardID)
|
switch (boardID)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
|