PWM Fan addition (#637)

* Added PWM Fan functionality

PWM Fan output for Teensy and STM32

* Teensy3.5 timer fix for PWM Fan.

* Fix the conflicts with incorporate AFR

* Possibility to use PWM fan on mega too

Not tested at this stage!! Do not merge yet.

* Fix log entry size

* Remove duplicate stuff and use same way off toggling fan

* Fix typo errors

* Move fan pin definitions to globals.h

* Fix problems related to PWM fan.

* Revert previous change.

* Fix problems with idle things

* fix idle duty getting stuck at 100%

* Revert "fix idle duty getting stuck at 100%"

This reverts commit 7e9779483b.

* Revert "Fix problems with idle things"

This reverts commit 8bccb56d9a.

* Revert "Revert previous change."

This reverts commit fcb962864a.

* Remove mega support

* fixes

* more fixes

* moar fixes

* Should be working now

* Update speeduino.ini

* Lots of tweaking

* Update to work better with current FW

* Fix compiler warnings and include update things.

* Minor fixes

* Update logger.ino

* Fan duty working on mega too and fan output will be on/off

Co-authored-by: Pasi Kemppainen <pazi88@users.noreply.github.com>
This commit is contained in:
Pasi Kemppainen 2021-11-24 03:18:41 +02:00 committed by GitHub
parent 07bfc6025c
commit e213f2534e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 219 additions and 43 deletions

View File

@ -360,7 +360,7 @@ page = 1
fanWhenOff = bits, U08, 70, [0:0], "No", "Yes"
fanWhenCranking = bits, U08, 70, [1:1], "No", "Yes"
useDwellMap = bits, U08, 70, [2:2], "No", "Yes"
unused_fan_bits = bits, U08, 70, [3:4]
fanEnable = bits, U08, 70, [3:4], "Off", "On/Off", "PWM", "INVALID"
rtc_mode = bits, U08, 70, [5:6], "Off", "On-board", "INVALID", "INVALID"
incorporateAFR = bits, U08, 70, [7:7], "No", "Yes"
@ -698,7 +698,7 @@ page = 6
; Begin fan control vairables
fanInv = bits, U08, 120, [0:0], "No", "Yes"
fanEnable = bits, U08, 120, [1:1], "Off", "On/Off"
fanUnused = bits, U08, 120, [1:1], "Off", "On/Off"
fanPin = bits, U08, 120, [2:7], "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", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID"
#if CELSIUS
fanSP = scalar, U08, 121, "C", 1.0, -40, -40, 215.0, 0
@ -1012,7 +1012,8 @@ page = 9
boostByGear5 = scalar, U08, 160, { bitStringValue(boostByGearLabels , boostByGearEnabled) }, 2.0, 0.0, 0.0, 511.0, 0
boostByGear6 = scalar, U08, 161, { bitStringValue(boostByGearLabels , boostByGearEnabled) }, 2.0, 0.0, 0.0, 511.0, 0
unused10_160 = array, U08, 162, [30], "", 1, 0, 0, 255, 0
PWMFanDuty = array, U08, 162, [4], "%", 0.5, 0, 0, 100, 1
unused10_160 = array, U08, 166, [26], "", 1, 0, 0, 255, 0
page = 10
#if CELSIUS
@ -1728,6 +1729,7 @@ menuDialog = main
menu = "&Accessories"
subMenu = fanSettings, "Thermo Fan"
subMenu = pwmFan, "PWM Fan Curve", { fanEnable == 2 }
subMenu = LaunchControl, "Launch Control / Flat Shift"
subMenu = fuelpump, "Fuel Pump"
subMenu = NitrousControl, "Nitrous"
@ -2481,13 +2483,18 @@ menuDialog = main
dialog = fanSettings,"Fan Settings",7
topicHelp = "https://wiki.speeduino.com/en/configuration/Thermo_fan"
displayOnlyField = !"No PWM Fan available on MCU", blankfield, {intcan_available == 0 && fanEnable == 2},{intcan_available == 0 && fanEnable == 2}
field = "Fan Mode", fanEnable
field = "Allow fan when off", fanWhenOff, { fanEnable }
field = "Allow fan when cranking", fanWhenCranking, { fanEnable }
field = "Fan output pin", fanPin, { fanEnable }
field = "Fan Output Inverted", fanInv, { fanEnable }
field = "Fan switching temperature", fanSP, { fanEnable }
field = "Fan hysteresis", fanHyster, { fanEnable }
field = "Fan switching temperature", fanSP, { fanEnable == 1 }
field = "Fan hysteresis", fanHyster, { fanEnable == 1 }
field = "PWM fan frequency", fanFreq, { intcan_available && fanEnable == 2 }
dialog = pwmFan, "PWM Fan Curve",
panel = pwm_fan_curve,
dialog = stepper_idle, "Stepper Idle"
field = "Step time (ms)", iacStepTime, { iacAlgorithm == 4 || iacAlgorithm == 5 }
@ -4179,6 +4186,16 @@ cmdVSSratio6 = "E\x99\x06"
yBins = idleAdvValues
size = 450, 200
; PWM Fan duty curve based on temp input
curve = pwm_fan_curve, "Fan PWM Duty"
columnLabel = "Temp", "Duty %"
xAxis = -40, 215, 4
yAxis = 0, 100, 4
xBins = fanPWMBins, coolant
yBins = PWMFanDuty
gauge = cltGauge
size = 400, 400
; Curves for idle control
; Standard duty table for PWM valves
curve = iacPwm_curve, "IAC PWM Duty"
@ -4597,6 +4614,7 @@ cmdVSSratio6 = "E\x99\x06"
lambdaTargetGauge = lambdaTarget, "Target Lambda", "", 0.5, 1.5, 0.82, 0.89, 1.02, 1.09, 3, 3
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
FANdutyCycleGauge = fanDuty, "FAN Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1
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, 1, 1
vvt1AngleGauge = vvt1Angle, "VVT Angle", "deg", -20, 100, 0, -5, 70, 90, 1, 1
@ -4605,7 +4623,7 @@ cmdVSSratio6 = "E\x99\x06"
vvt2AngleGauge = vvt2Angle, "VVT2 Angle", "deg", -20, 100, 0, -5, 70, 90, 1, 1
WMIdutyCycleGauge = wmiPW, "WMI Duty Cycle", "%", 0, 100, -1, -1, 101, 110, 1, 1
gaugeCategory = "Sensor inputs"
mapGauge = map, "Engine MAP", "kPa", 0, {maphigh}, 0, 20, {mapwarn}, {mapdang}, 0, 0
mapGauge_psi = map_psi, "Engine MAP (PSI)", "PSI", -15, 100, 0, 20, 200, 245, 0, 0
@ -4741,7 +4759,7 @@ cmdVSSratio6 = "E\x99\x06"
; you change it.
ochGetCommand = "r\$tsCanId\x30%2o%2c"
ochBlockSize = 121
ochBlockSize = 122
secl = scalar, U08, 0, "sec", 1.000, 0.000
status1 = scalar, U08, 1, "bits", 1.000, 0.000
@ -4882,9 +4900,10 @@ cmdVSSratio6 = "E\x99\x06"
advance2 = scalar, S08, 117, "deg", 1.000, 0.000
sd_status = scalar, U08, 118, "", 1.0, 0.0
emap = scalar, U16, 119, "kpa", 1.000, 0.000
;sd_filenum = scalar, U16, 117, "", 1, 0
;sd_error = scalar, U08, 119, "", 1, 0
;sd_phase = scalar, U08, 120, "", 1, 0
fanDuty = scalar, U08, 121, "%", 0.5, 0.000
;sd_filenum = scalar, U16, 122, "", 1, 0
;sd_error = scalar, U08, 124, "", 1, 0
;sd_phase = scalar, U08, 125, "", 1, 0
#if CELSIUS
coolant = { coolantRaw - 40 } ; Temperature readings are offset by 40 to allow for negatives
@ -5030,7 +5049,8 @@ cmdVSSratio6 = "E\x99\x06"
entry = vvt2Angle, "VVT2 Angle", int, "%.1f", { vvt2Enabled > 0 }
entry = vvt2Target, "VVT2 Target Angle",int, "%.1f", { vvt2Enabled > 0 && vvtMode == 2 } ;;Only show when using close loop vvt
entry = vvt2Duty, "VVT2 Duty", int, "%.1f", { vvt2Enabled > 0 && vvtMode == 2 }
entry = loopsPerSecond, "Loops/s", int, "%d"
entry = fanDuty, "FAN Duty", int, "%d", { fanEnable == 2 }
entry = loopsPerSecond, "Loops/s", int, "%d"
entry = auxin_gauge0, { stringValue(AUXin00Alias) }, int, "%d", {(caninput_sel0b != 0)}
entry = auxin_gauge1, { stringValue(AUXin01Alias) }, int, "%d", { (caninput_sel1b != 0)}

View File

@ -64,13 +64,17 @@ long boost_pwm_target_value;
long boost_cl_target_boost;
byte boostCounter;
byte vvtCounter;
#if defined(PWM_FAN_AVAILABLE)//PWM fan not available on Arduino MEGA
volatile bool fan_pwm_state;
unsigned int fan_pwm_max_count; //Used for variable PWM frequency
volatile unsigned int fan_pwm_cur_value;
long fan_pwm_value;
void fanInterrupt();
#endif
uint32_t vvtWarmTime;
bool vvtIsHot;
bool vvtTimeHold;
byte fanHIGH = HIGH; // Used to invert the cooling fan output
byte fanLOW = LOW; // Used to invert the cooling fan output
volatile bool vvt1_pwm_state;
volatile bool vvt2_pwm_state;
volatile bool vvt1_max_pwm;

View File

@ -21,18 +21,28 @@ Fan control
*/
void initialiseFan()
{
if( configPage6.fanInv == 1 ) { fanHIGH = LOW; fanLOW = HIGH; }
else { fanHIGH = HIGH; fanLOW = LOW; }
digitalWrite(pinFan, fanLOW); //Initiallise program with the fan in the off state
currentStatus.fanOn = false;
fan_pin_port = portOutputRegister(digitalPinToPort(pinFan));
fan_pin_mask = digitalPinToBitMask(pinFan);
FAN_OFF(); //Initiallise program with the fan in the off state
currentStatus.fanDuty = 0;
#if defined(PWM_FAN_AVAILABLE)
DISABLE_FAN_TIMER(); //disable FAN timer if available
if ( configPage2.fanEnable == 2 ) // PWM Fan control
{
#if defined(CORE_TEENSY)
fan_pwm_max_count = 1000000L / (32 * configPage6.fanFreq * 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
#endif
fan_pwm_value = 0;
}
#endif
}
void fanControl()
{
if( configPage6.fanEnable == 1 )
if( configPage2.fanEnable == 1 ) // regular on/off fan control
{
int onTemp = (int)configPage6.fanSP - CALIBRATION_TEMPERATURE_OFFSET;
int offTemp = onTemp - configPage6.fanHyster;
@ -62,6 +72,68 @@ void fanControl()
currentStatus.fanOn = false;
}
}
else if( configPage2.fanEnable == 2 )// PWM Fan control
{
bool fanPermit = false;
if ( configPage2.fanWhenOff == true) { fanPermit = true; }
else { fanPermit = BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN); }
if (fanPermit == true)
{
if(BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && (configPage2.fanWhenCranking == 0))
{
currentStatus.fanDuty = 0; //If the user has elected to disable the fan during cranking, make sure it's off
currentStatus.fanOn = false;
#if defined(PWM_FAN_AVAILABLE)//PWM fan not available on Arduino MEGA
DISABLE_FAN_TIMER();
#endif
}
else
{
currentStatus.fanDuty = table2D_getValue(&fanPWMTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //In normal situation read PWM duty from the table
#if defined(PWM_FAN_AVAILABLE)
fan_pwm_value = halfPercentage(currentStatus.fanDuty, fan_pwm_max_count); //update FAN PWM value last
if (currentStatus.fanDuty > 0)
{
currentStatus.fanOn = true; // update fan on status. Is this even used anywhere??
ENABLE_FAN_TIMER();
}
#endif
}
}
else if (!fanPermit)
{
currentStatus.fanDuty = 0; ////If the user has elected to disable the fan when engine is not running, make sure it's off
}
#if defined(PWM_FAN_AVAILABLE)
if(currentStatus.fanDuty == 0)
{
//Make sure fan has 0% duty)
FAN_OFF();
currentStatus.fanOn = false;
DISABLE_FAN_TIMER();
}
else if (currentStatus.fanDuty == 200)
{
//Make sure fan has 100% duty
FAN_ON();
DISABLE_FAN_TIMER();
}
#else //Just in case if user still has selected PWM fan in TS, even though it warns that it doesn't work on mega.
if(currentStatus.fanDuty == 0)
{
//Make sure fan has 0% duty)
FAN_OFF();
currentStatus.fanOn = false;
}
else if (currentStatus.fanDuty > 0)
{
//Make sure fan has 100% duty
FAN_ON();
currentStatus.fanOn = true;
}
#endif
}
}
void initialiseAuxPWM()
@ -714,3 +786,23 @@ void boostDisable()
}
}
}
#if defined(PWM_FAN_AVAILABLE)
//The interrupt to control the FAN PWM. Mega2560 doesn't have enough timers, so this is only for the ARM chip ones
void fanInterrupt()
{
if (fan_pwm_state == true)
{
FAN_OFF();
FAN_TIMER_COMPARE = FAN_TIMER_COUNTER + (fan_pwm_max_count - fan_pwm_cur_value);
fan_pwm_state = false;
}
else
{
FAN_ON();
FAN_TIMER_COMPARE = FAN_TIMER_COUNTER + fan_pwm_value;
fan_pwm_cur_value = fan_pwm_value;
fan_pwm_state = true;
}
}
#endif

View File

@ -71,21 +71,21 @@
#ifndef PB11 //Hack for F4 BlackPills
#define PB11 PB10
#endif
#define PWM_FAN_AVAILABLE
/*
***********************************************************************************************************
* Schedules
* Timers Table for STM32F1
* TIMER1 TIMER2 TIMER3 TIMER4
* 1 - 1 - INJ1 1 - IGN1 1 - oneMSInterval
* 1 - FAN 1 - INJ1 1 - IGN1 1 - oneMSInterval
* 2 - BOOST 2 - INJ2 2 - IGN2 2 -
* 3 - VVT 3 - INJ3 3 - IGN3 3 -
* 4 - IDLE 4 - INJ4 4 - IGN4 4 -
*
* Timers Table for STM32F4
* TIMER1 TIMER2 TIMER3 TIMER4 TIMER5 TIMER8
* 1 - 1 - INJ1 1 - IGN1 1 - IGN5 1 - INJ5 1 - oneMSInterval
* TIMER1 TIMER2 TIMER3 TIMER4 TIMER5 TIMER11
* 1 - FAN 1 - INJ1 1 - IGN1 1 - IGN5 1 - INJ5 1 - oneMSInterval
* 2 - BOOST 2 - INJ2 2 - IGN2 2 - IGN6 2 - INJ6 2 -
* 3 - VVT 3 - INJ3 3 - IGN3 3 - IGN7 3 - INJ7 3 -
* 4 - IDLE 4 - INJ4 4 - IGN4 4 - IGN8 4 - INJ8 4 -
@ -188,10 +188,15 @@
#define ENABLE_VVT_TIMER() (TIM1)->SR = ~TIM_FLAG_CC3; (TIM1)->DIER |= TIM_DIER_CC3IE
#define DISABLE_VVT_TIMER() (TIM1)->DIER &= ~TIM_DIER_CC3IE
#define ENABLE_FAN_TIMER() (TIM1)->SR = ~TIM_FLAG_CC1; (TIM1)->DIER |= TIM_DIER_CC1IE
#define DISABLE_FAN_TIMER() (TIM1)->DIER &= ~TIM_DIER_CC1IE
#define BOOST_TIMER_COMPARE (TIM1)->CCR2
#define BOOST_TIMER_COUNTER (TIM1)->CNT
#define VVT_TIMER_COMPARE (TIM1)->CCR3
#define VVT_TIMER_COUNTER (TIM1)->CNT
#define FAN_TIMER_COMPARE (TIM1)->CCR1
#define FAN_TIMER_COUNTER (TIM1)->CNT
/*
***********************************************************************************************************

View File

@ -62,10 +62,13 @@ void initBoard()
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
//Need to be initialised last due to instant interrupt
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
@ -97,7 +100,6 @@ void initBoard()
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
//Attach interupt functions
//Injection

View File

@ -69,6 +69,8 @@ extern "C" char* sbrk(int incr);
#endif
#endif
#define PWM_FAN_AVAILABLE
#ifndef LED_BUILTIN
#define LED_BUILTIN PA7
#endif
@ -122,14 +124,14 @@ extern "C" char* sbrk(int incr);
* Schedules
* Timers Table for STM32F1
* TIMER1 TIMER2 TIMER3 TIMER4
* 1 - free 1 - INJ1 1 - IGN1 1 - oneMSInterval
* 1 - FAN 1 - INJ1 1 - IGN1 1 - oneMSInterval
* 2 - BOOST 2 - INJ2 2 - IGN2 2 -
* 3 - VVT 3 - INJ3 3 - IGN3 3 -
* 4 - IDLE 4 - INJ4 4 - IGN4 4 -
*
* Timers Table for STM32F4
* TIMER1 | TIMER2 | TIMER3 | TIMER4 | TIMER5 | TIMER11
* 1 - free |1 - INJ1 |1 - IGN1 |1 - IGN5 |1 - INJ5 |1 - oneMSInterval
* 1 - FAN |1 - INJ1 |1 - IGN1 |1 - IGN5 |1 - INJ5 |1 - oneMSInterval
* 2 - BOOST |2 - INJ2 |2 - IGN2 |2 - IGN6 |2 - INJ6 |
* 3 - VVT |3 - INJ3 |3 - IGN3 |3 - IGN7 |3 - INJ7 |
* 4 - IDLE |4 - INJ4 |4 - IGN4 |4 - IGN8 |4 - INJ8 |
@ -232,10 +234,15 @@ extern "C" char* sbrk(int incr);
#define ENABLE_VVT_TIMER() (TIM1)->SR = ~TIM_FLAG_CC3; (TIM1)->DIER |= TIM_DIER_CC3IE
#define DISABLE_VVT_TIMER() (TIM1)->DIER &= ~TIM_DIER_CC3IE
#define ENABLE_FAN_TIMER() (TIM1)->SR = ~TIM_FLAG_CC1; (TIM1)->DIER |= TIM_DIER_CC1IE
#define DISABLE_FAN_TIMER() (TIM1)->DIER &= ~TIM_DIER_CC1IE
#define BOOST_TIMER_COMPARE (TIM1)->CCR2
#define BOOST_TIMER_COUNTER (TIM1)->CNT
#define VVT_TIMER_COMPARE (TIM1)->CCR3
#define VVT_TIMER_COUNTER (TIM1)->CNT
#define FAN_TIMER_COMPARE (TIM1)->CCR1
#define FAN_TIMER_COUNTER (TIM1)->CNT
/*
***********************************************************************************************************
@ -286,6 +293,7 @@ void fuelSchedule8Interrupt(HardwareTimer*);
#endif
void idleInterrupt(HardwareTimer*);
void vvtInterrupt(HardwareTimer*);
void fanInterrupt(HardwareTimer*);
void ignitionSchedule1Interrupt(HardwareTimer*);
void ignitionSchedule2Interrupt(HardwareTimer*);
void ignitionSchedule3Interrupt(HardwareTimer*);

View File

@ -136,17 +136,22 @@ STM32RTC& rtc = STM32RTC::getInstance();
* Auxilliaries
*/
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (TIMER_RESOLUTION * configPage6.fanFreq * 2); //Converts the frequency in Hz to the number of ticks (at 4uS) it takes to complete 1 cycle
//Need to be initialised last due to instant interrupt
#if ( STM32_CORE_VERSION_MAJOR < 2 )
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
Timer1.attachInterrupt(1, fanInterrupt);
Timer1.attachInterrupt(2, boostInterrupt);
Timer1.attachInterrupt(3, vvtInterrupt);
@ -172,7 +177,6 @@ STM32RTC& rtc = STM32RTC::getInstance();
Timer3.setMode(2, TIMER_OUTPUT_COMPARE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE);
Timer1.setMode(1, TIMER_OUTPUT_COMPARE);
#else //2.0 forward
Timer2.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer2.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
@ -183,7 +187,6 @@ STM32RTC& rtc = STM32RTC::getInstance();
Timer3.setMode(2, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(3, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer3.setMode(4, TIMER_OUTPUT_COMPARE_TOGGLE);
Timer1.setMode(1, TIMER_OUTPUT_COMPARE_TOGGLE);
#endif
//Attach interrupt functions
//Injection
@ -363,6 +366,7 @@ STM32RTC& rtc = STM32RTC::getInstance();
#endif
void idleInterrupt(HardwareTimer*){idleInterrupt();}
void vvtInterrupt(HardwareTimer*){vvtInterrupt();}
void fanInterrupt(HardwareTimer*){fanInterrupt();}
void ignitionSchedule1Interrupt(HardwareTimer*){ignitionSchedule1Interrupt();}
void ignitionSchedule2Interrupt(HardwareTimer*){ignitionSchedule2Interrupt();}
void ignitionSchedule3Interrupt(HardwareTimer*){ignitionSchedule3Interrupt();}

View File

@ -31,6 +31,7 @@
#define SD_CONFIG SdioConfig(FIFO_SDIO) //Set Teensy to use SDIO in FIFO mode. This is the fastest SD mode on Teensy as it offloads most of the writes
#define micros_safe() micros() //timer5 method is not used on anything but AVR, the micros_safe() macro is simply an alias for the normal micros()
#define PWM_FAN_AVAILABLE
#define pinIsReserved(pin) ( ((pin) == 0) || ((pin) == 1) || ((pin) == 3) || ((pin) == 4) ) //Forbiden pins like USB
/*
@ -122,14 +123,20 @@
#define ENABLE_VVT_TIMER() FTM1_C1SC |= FTM_CSC_CHIE
#define DISABLE_VVT_TIMER() FTM1_C1SC &= ~FTM_CSC_CHIE
#define ENABLE_FAN_TIMER() FTM2_C1SC |= FTM_CSC_CHIE
#define DISABLE_FAN_TIMER() FTM2_C1SC &= ~FTM_CSC_CHIE
#define BOOST_TIMER_COMPARE FTM1_C0V
#define BOOST_TIMER_COUNTER FTM1_CNT
#define VVT_TIMER_COMPARE FTM1_C1V
#define VVT_TIMER_COUNTER FTM1_CNT
#define FAN_TIMER_COMPARE FTM2_C1V
#define FAN_TIMER_COUNTER FTM2_CNT
void boostInterrupt();
void vvtInterrupt();
void fanInterrupt();
/*
***********************************************************************************************************

View File

@ -148,11 +148,18 @@ void initBoard()
//Enable channel compare interrupt (This is currently disabled as not in use)
//FTM1_C1SC |= FTM_CSC_CHIE;
FTM2_C1SC &= ~FTM_CSC_MSB; //According to Pg 965 of the K64 datasheet, this should not be needed as MSB is reset to 0 upon reset, but the channel interrupt fails to fire without it
FTM2_C1SC |= FTM_CSC_MSA; //Enable Compare mode
//Enable channel compare interrupt (This is currently disabled as not in use)
//FTM1_C2SC |= FTM_CSC_CHIE;
//Enable IRQ Interrupt
NVIC_ENABLE_IRQ(IRQ_FTM1);
boost_pwm_max_count = 1000000L / (32 * configPage6.boostFreq * 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
vvt_pwm_max_count = 1000000L / (32 * 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
fan_pwm_max_count = 1000000L / (32 * configPage6.fanFreq * 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
}
@ -370,10 +377,10 @@ void ftm2_isr(void)
//FTM2 only has 2 compare channels
//Use separate variables for each test to ensure conversion to bool
bool interrupt1 = (FTM2_C0SC & FTM_CSC_CHF);
bool interrupt2 = (FTM2_C1SC & FTM_CSC_CHF); //Not currently used
bool interrupt2 = (FTM2_C1SC & FTM_CSC_CHF); //For PWM Fan
if(interrupt1) { FTM2_C0SC &= ~FTM_CSC_CHF; idleInterrupt(); }
else if(interrupt2) { FTM2_C1SC &= ~FTM_CSC_CHF; } //Add a callback function here if this is ever used
else if(interrupt2) { FTM2_C1SC &= ~FTM_CSC_CHF; fanInterrupt(); } //For PWM Fan
}
uint16_t freeRam()

View File

@ -25,6 +25,7 @@
#define SD_CONFIG SdioConfig(FIFO_SDIO) //Set Teensy to use SDIO in FIFO mode. This is the fastest SD mode on Teensy as it offloads most of the writes
#define micros_safe() micros() //timer5 method is not used on anything but AVR, the micros_safe() macro is simply an alias for the normal micros()
#define PWM_FAN_AVAILABLE
#define pinIsReserved(pin) ( ((pin) == 0) ) //Forbiden pins like USB
/*
@ -132,10 +133,16 @@
#define ENABLE_VVT_TIMER() TMR3_CSCTRL0 |= TMR_CSCTRL_TCF2EN
#define DISABLE_VVT_TIMER() TMR3_CSCTRL0 &= ~TMR_CSCTRL_TCF2EN
#define ENABLE_FAN_TIMER() TMR3_CSCTRL1 |= TMR_CSCTRL_TCF2EN
#define DISABLE_FAN_TIMER() TMR3_CSCTRL1 &= ~TMR_CSCTRL_TCF2EN
#define BOOST_TIMER_COMPARE PIT_LDVAL1
#define BOOST_TIMER_COUNTER 0
#define VVT_TIMER_COMPARE PIT_LDVAL2
#define VVT_TIMER_COUNTER 0
//these probaply need to be PIT_LDVAL something???
#define FAN_TIMER_COMPARE TMR3_COMP22
#define FAN_TIMER_COUNTER TMR3_CNTR1
void boostInterrupt();
void vvtInterrupt();

View File

@ -63,6 +63,7 @@ void initBoard()
//2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / (2 * configPage6.boostFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle. The x2 is there because the frequency is stored at half value (in a byte) to allow freqneucies up to 511Hz
vvt_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
fan_pwm_max_count = 1000000L / (2 * configPage6.vvtFreq * 2); //Converts the frequency in Hz to the number of ticks (at 2uS) it takes to complete 1 cycle
//TODO: Configure timers here

View File

@ -1,7 +1,7 @@
#ifndef CANCOMMS_H
#define CANCOMMS_H
#define NEW_CAN_PACKET_SIZE 119
#define NEW_CAN_PACKET_SIZE 122
#define CAN_PACKET_SIZE 75
#if ( defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) )

View File

@ -340,6 +340,9 @@ void sendcanValues(uint16_t offset, uint16_t packetLength, byte cmd, byte portTy
fullStatus[116] = currentStatus.advance2; //advance 2
fullStatus[117] = currentStatus.nitrous_status;
fullStatus[118] = currentStatus.TS_SD_Status; //SD card status
fullStatus[119] = lowByte(currentStatus.EMAP); //2 bytes for EMAP
fullStatus[120] = highByte(currentStatus.EMAP);
fullStatus[121] = currentStatus.fanDuty;
for(byte x=0; x<packetLength; x++)
{

View File

@ -478,6 +478,7 @@ extern struct table2D knockWindowStartTable;
extern struct table2D knockWindowDurationTable;
extern struct table2D oilPressureProtectTable;
extern struct table2D wmiAdvTable; //6 bin wmi correction table for timing advance (2D)
extern struct table2D fanPWMTable;
//These are for the direct port manipulation of the injectors, coils and aux outputs
extern volatile PORT_TYPE *inj1_pin_port;
@ -725,6 +726,7 @@ struct statuses {
byte fuelPressure; /**< Fuel pressure in PSI */
byte oilPressure; /**< Oil pressure in PSI */
byte engineProtectStatus;
byte fanDuty;
byte wmiPW;
volatile byte status4; ///< Status bits (See BIT_STATUS4_* defines on top of this file)
int16_t vvt2Angle; //Has to be a long for PID calcs (CL VVT control)
@ -844,7 +846,7 @@ struct config2 {
byte fanWhenOff : 1; ///< Allow running fan with engine off: 0 = Only run fan when engine is running, 1 = Allow even with engine off
byte fanWhenCranking : 1; ///< Set whether the fan output will stay on when the engine is cranking (0=force off, 1=allow on)
byte useDwellMap : 1; ///< Setting to change between fixed dwell value and dwell map (0=Fixed value from @ref configPage4.dwellRun, 1=Use @ref dwellTable)
byte fanUnused : 2; // Unused ?
byte fanEnable : 2; ///< Fan mode. 0=Off, 1=On/Off, 2=PWM
byte rtc_mode : 2; // Unused ?
byte incorporateAFR : 1; ///< Enable AFR target (stoich/afrtgt) compensation in PW calculation
byte asePct[4]; ///< Afterstart enrichment values (%)
@ -1094,7 +1096,7 @@ struct config6 {
byte iacStepHyster; //Hysteresis temperature (*10). Eg 2.2C = 22
byte fanInv : 1; // Fan output inversion bit
byte fanEnable : 1; // Fan enable bit. 0=Off, 1=On/Off
byte fanUnused : 1;
byte fanPin : 6;
byte fanSP; // Cooling fan start temperature
byte fanHyster; // Fan hysteresis
@ -1152,10 +1154,7 @@ struct config9 {
byte boostByGear5;
byte boostByGear6;
byte unused10_162;
byte unused10_163;
byte unused10_164;
byte unused10_165;
byte PWMFanDuty[4];
byte unused10_166;
byte unused10_167;
byte unused10_168;

View File

@ -51,7 +51,8 @@ struct table2D fuelTempTable; ///< 6 bin flex fuel correction table for fuel ad
struct table2D knockWindowStartTable;
struct table2D knockWindowDurationTable;
struct table2D oilPressureProtectTable;
struct table2D wmiAdvTable; ///< 6 bin wmi correction table for timing advance (2D)
struct table2D wmiAdvTable; //6 bin wmi correction table for timing advance (2D)
struct table2D fanPWMTable;
/// volatile inj*_pin_port and inj*_pin_mask vars are for the direct port manipulation of the injectors, coils and aux outputs.
volatile PORT_TYPE *inj1_pin_port;

View File

@ -203,6 +203,12 @@ void initialiseAll()
oilPressureProtectTable.values = configPage10.oilPressureProtMins;
oilPressureProtectTable.axisX = configPage10.oilPressureProtRPM;
fanPWMTable.valueSize = SIZE_BYTE;
fanPWMTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins
fanPWMTable.xSize = 4;
fanPWMTable.values = configPage9.PWMFanDuty;
fanPWMTable.axisX = configPage6.fanPWMBins;
wmiAdvTable.valueSize = SIZE_BYTE;
wmiAdvTable.axisSize = SIZE_BYTE; //Set this table to use byte axis bins
wmiAdvTable.xSize = 6;

View File

@ -10,9 +10,9 @@
#define LOGGER_H
#ifndef UNIT_TEST // Scope guard for unit testing
#define LOG_ENTRY_SIZE 121 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */
#define SD_LOG_ENTRY_SIZE 121 /**< The size of the live data packet used by the SD car.*/
#define SD_LOG_NUM_FIELDS 88 /**< The number of fields that are in the log. This is always smaller than the entry size due to some fields being 2 bytes */
#define LOG_ENTRY_SIZE 122 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */
#define SD_LOG_ENTRY_SIZE 122 /**< The size of the live data packet used by the SD car.*/
#define SD_LOG_NUM_FIELDS 89 /**< The number of fields that are in the log. This is always smaller than the entry size due to some fields being 2 bytes */
#else
#define LOG_ENTRY_SIZE 1 /**< The size of the live data packet. This MUST match ochBlockSize setting in the ini file */
#define SD_LOG_ENTRY_SIZE 1 /**< The size of the live data packet used by the SD car.*/

View File

@ -166,6 +166,7 @@ byte getTSLogEntry(uint16_t byteNum)
case 118: statusValue = currentStatus.TS_SD_Status; break; //SD card status
case 119: statusValue = lowByte(currentStatus.EMAP); break; //2 bytes for EMAP
case 120: statusValue = highByte(currentStatus.EMAP); break;
case 121: statusValue = currentStatus.fanDuty; break;
}
return statusValue;
@ -289,6 +290,7 @@ int16_t getReadableLogEntry(uint16_t logIndex)
case 85: statusValue = currentStatus.advance2; break; //advance 2 (%)
case 86: statusValue = currentStatus.TS_SD_Status; break; //SD card status
case 87: statusValue = currentStatus.EMAP; break;
case 88: statusValue = currentStatus.fanDuty; break;
}
return statusValue;

View File

@ -175,7 +175,7 @@ void oneMSInterval() //Most ARM chips can simply call a function
currentStatus.secl++;
//**************************************************************************************************************************************************
//Check the fan output status
if (configPage6.fanEnable == 1)
if (configPage2.fanEnable >= 1)
{
fanControl(); // Fucntion to turn the cooling fan on/off
}

View File

@ -14,7 +14,7 @@
void doUpdates()
{
#define CURRENT_DATA_VERSION 18
#define CURRENT_DATA_VERSION 19
//Only the latest updat for small flash devices must be retained
#ifndef SMALL_FLASH_MODE
@ -518,6 +518,14 @@ void doUpdates()
storeEEPROMVersion(18);
}
if(readEEPROMVersion() == 18)
{
configPage2.fanEnable = configPage6.fanUnused; // PWM Fan mode added, but take the previous setting of Fan in use.
writeAllConfig();
storeEEPROMVersion(19);
}
//Final check is always for 255 and 0 (Brand new arduino)
if( (readEEPROMVersion() == 0) || (readEEPROMVersion() == 255) )
{