2015-05-30 12:36:40 -07:00
/*
Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright ( C ) Josh Stewart
A full copy of the license may be found in the projects root directory
*/
2017-07-30 06:04:37 -07:00
//Old PID method. Retained incase the new one has issues
//integerPID boostPID(&MAPx100, &boost_pwm_target_value, &boostTargetx100, configPage3.boostKP, configPage3.boostKI, configPage3.boostKD, DIRECT);
2017-07-29 05:38:54 -07:00
integerPIDnew boostPID ( & currentStatus . MAP , & boost_pwm_target_value , & boost_cl_target_boost , configPage3 . boostKP , configPage3 . boostKI , configPage3 . boostKD , DIRECT ) ; //This is the PID object if that algorithm is used. Needs to be global as it maintains state outside of each function call
2015-05-30 12:36:40 -07:00
/*
2015-08-20 06:21:27 -07:00
Fan control
2015-05-30 12:36:40 -07:00
*/
void initialiseFan ( )
{
2017-05-31 01:13:04 -07:00
if ( configPage4 . fanInv = = 1 ) { fanHIGH = LOW ; fanLOW = HIGH ; }
else { fanHIGH = HIGH ; fanLOW = LOW ; }
2016-10-26 13:03:42 -07:00
digitalWrite ( pinFan , fanLOW ) ; //Initiallise program with the fan in the off state
currentStatus . fanOn = false ;
2015-05-30 12:36:40 -07:00
}
2015-06-02 05:56:18 -07:00
void fanControl ( )
2015-05-30 12:36:40 -07:00
{
2017-05-31 01:13:04 -07:00
if ( configPage4 . fanEnable = = 1 )
2016-10-26 13:03:42 -07:00
{
int onTemp = ( int ) configPage4 . fanSP - CALIBRATION_TEMPERATURE_OFFSET ;
int offTemp = onTemp - configPage4 . fanHyster ;
2017-02-11 01:33:07 -08:00
2017-05-31 01:13:04 -07:00
if ( ( ! currentStatus . fanOn ) & & ( currentStatus . coolant > = onTemp ) ) { digitalWrite ( pinFan , fanHIGH ) ; currentStatus . fanOn = true ; }
if ( ( currentStatus . fanOn ) & & ( currentStatus . coolant < = offTemp ) ) { digitalWrite ( pinFan , fanLOW ) ; currentStatus . fanOn = false ; }
2016-10-26 13:03:42 -07:00
}
2015-05-30 12:36:40 -07:00
}
2015-08-20 06:21:27 -07:00
2015-09-26 16:14:29 -07:00
void initialiseAuxPWM ( )
{
2017-07-23 23:34:13 -07:00
# if defined(CORE_AVR)
TCCR1B = 0x00 ; //Disbale Timer1 while we set it up
TCNT1 = 0 ; //Reset Timer Count
TIFR1 = 0x00 ; //Timer1 INT Flag Reg: Clear Timer Overflow Flag
TCCR1A = 0x00 ; //Timer1 Control Reg A: Wave Gen Mode normal (Simply counts up from 0 to 65535 (16-bit int)
TCCR1B = ( 1 < < CS12 ) ; //Timer1 Control Reg B: Timer Prescaler set to 256. 1 tick = 16uS. Refer to http://www.instructables.com/files/orig/F3T/TIKL/H3WSA4V7/F3TTIKLH3WSA4V7.jpg
2017-07-23 23:40:50 -07:00
# elif defined(CORE_TEENSY)
//REALLY NEED TO DO THIS!
2017-07-23 23:34:13 -07:00
# endif
2017-02-11 01:33:07 -08:00
2015-09-26 16:14:29 -07:00
boost_pin_port = portOutputRegister ( digitalPinToPort ( pinBoost ) ) ;
boost_pin_mask = digitalPinToBitMask ( pinBoost ) ;
2015-09-26 23:41:07 -07:00
vvt_pin_port = portOutputRegister ( digitalPinToPort ( pinVVT_1 ) ) ;
vvt_pin_mask = digitalPinToBitMask ( pinVVT_1 ) ;
2017-02-11 01:33:07 -08:00
2017-08-27 21:35:49 -07:00
# if defined(CORE_STM32) //2uS resolution Min 8Hz, Max 5KHz
boost_pwm_max_count = 1000000L / ( configPage3 . boostFreq * 2 ) ; //Converts the frequency in Hz to the number of ticks (at 16uS) 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 / ( configPage3 . vvtFreq * 2 ) ; //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
# else
boost_pwm_max_count = 1000000L / ( 16 * configPage3 . boostFreq * 2 ) ; //Converts the frequency in Hz to the number of ticks (at 16uS) 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 / ( 16 * configPage3 . vvtFreq * 2 ) ; //Converts the frequency in Hz to the number of ticks (at 16uS) it takes to complete 1 cycle
# endif
2017-05-31 01:13:04 -07:00
//TIMSK1 |= (1 << OCIE1A); <---- Not required as compare A is turned on when needed by boost control
2017-07-23 23:34:13 -07:00
ENABLE_VVT_TIMER ( ) ; //Turn on the B compare unit (ie turn on the interrupt)
2016-05-22 03:12:44 -07:00
2017-02-19 22:57:46 -08:00
boostPID . SetOutputLimits ( percentage ( configPage1 . boostMinDuty , boost_pwm_max_count ) , percentage ( configPage1 . boostMaxDuty , boost_pwm_max_count ) ) ;
2017-02-14 21:51:01 -08:00
boostPID . SetTunings ( configPage3 . boostKP , configPage3 . boostKI , configPage3 . boostKD ) ;
2016-05-22 03:12:44 -07:00
boostPID . SetMode ( AUTOMATIC ) ; //Turn PID on
2017-02-11 01:33:07 -08:00
2017-03-16 00:17:12 -07:00
currentStatus . boostDuty = 0 ;
2017-02-11 01:33:07 -08:00
boostCounter = 0 ;
2017-08-31 13:38:41 -07:00
# if defined(CORE_STM32) //Need to be initialised last due to instant interrupt
2017-09-01 12:16:45 -07:00
if ( boost_pwm_max_count > 0 ) { Timer1 . attachInterrupt ( 2 , boostInterrupt ) ; }
if ( vvt_pwm_max_count > 0 ) { Timer1 . attachInterrupt ( 3 , vvtInterrupt ) ; }
2017-08-31 13:38:41 -07:00
Timer1 . resume ( ) ;
# endif
2015-09-26 16:14:29 -07:00
}
2015-08-20 06:21:27 -07:00
2015-09-26 16:14:29 -07:00
void boostControl ( )
{
2017-05-31 01:13:04 -07:00
if ( configPage3 . boostEnabled = = 1 )
2015-09-26 23:41:07 -07:00
{
2017-05-31 01:13:04 -07:00
if ( currentStatus . MAP > = 100 )
2017-05-12 01:14:14 -07:00
{
2017-05-31 01:13:04 -07:00
MAPx100 = currentStatus . MAP * 100 ;
2017-07-29 05:38:54 -07:00
if ( ( boostCounter & 3 ) = = 1 ) { boost_cl_target_boost = get3DTableValue ( & boostTable , currentStatus . TPS , currentStatus . RPM ) * 2 ; } //Boost target table is in kpa and divided by 2
2017-05-31 01:13:04 -07:00
//If flex fuel is enabled, there can be an adder to the boost target based on ethanol content
if ( configPage1 . flexEnabled = = 1 )
{
int16_t boostAdder = ( ( ( int16_t ) configPage1 . flexBoostHigh - ( int16_t ) configPage1 . flexBoostLow ) * currentStatus . ethanolPct ) / 100 ;
boostAdder = boostAdder + configPage1 . flexBoostLow ; //Required in case flexBoostLow is less than 0
boost_cl_target_boost = boost_cl_target_boost + boostAdder ;
}
boostTargetx100 = boost_cl_target_boost * 100 ;
currentStatus . boostTarget = boost_cl_target_boost > > 1 ; //Boost target is sent as a byte value to TS and so is divided by 2
if ( currentStatus . boostTarget > 0 )
{
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 ( ) ;
currentStatus . boostDuty = ( unsigned long ) ( boost_pwm_target_value * 100UL ) / boost_pwm_max_count ;
2017-07-24 00:05:55 -07:00
if ( currentStatus . boostDuty = = 0 ) { DISABLE_BOOST_TIMER ( ) ; BOOST_PIN_LOW ( ) ; } //If boost duty is 0, shut everything down
else { ENABLE_BOOST_TIMER ( ) ; } //Turn on the compare unit (ie turn on the interrupt) if boost duty >0
2017-05-31 01:13:04 -07:00
}
else
{
//If boost target is 0, turn everything off
2017-07-23 23:34:13 -07:00
DISABLE_BOOST_TIMER ( ) ; //Turn off timer
BOOST_PIN_LOW ( ) ;
2017-05-31 01:13:04 -07:00
}
}
else
{
//Boost control does nothing if kPa below 100
2017-07-23 23:34:13 -07:00
DISABLE_BOOST_TIMER ( ) ; //Turn off timer
BOOST_PIN_LOW ( ) ; //Make sure solenoid is off (0% duty)
2017-05-12 01:14:14 -07:00
}
2015-09-26 23:41:07 -07:00
}
2017-07-23 23:34:13 -07:00
else { DISABLE_BOOST_TIMER ( ) ; } // Disable timer channel
2017-02-11 01:33:07 -08:00
boostCounter + + ;
2015-09-26 23:41:07 -07:00
}
void vvtControl ( )
{
2017-05-31 01:13:04 -07:00
if ( configPage3 . vvtEnabled = = 1 )
2015-09-26 23:41:07 -07:00
{
byte vvtDuty = get3DTableValue ( & vvtTable , currentStatus . TPS , currentStatus . RPM ) ;
2017-07-23 23:04:29 -07:00
if ( vvtDuty = = 0 )
{
//Make sure solenoid is off (0% duty)
VVT_PIN_LOW ( ) ;
DISABLE_VVT_TIMER ( ) ;
}
else if ( vvtDuty > = 100 )
{
//Make sure solenoid is on (100% duty)
VVT_PIN_HIGH ( ) ;
DISABLE_VVT_TIMER ( ) ;
}
else
{
vvt_pwm_target_value = percentage ( vvtDuty , vvt_pwm_max_count ) ;
ENABLE_VVT_TIMER ( ) ;
}
2015-09-26 23:41:07 -07:00
}
2017-07-23 23:04:29 -07:00
else { DISABLE_VVT_TIMER ( ) ; } // Disable timer channel
2015-09-26 16:14:29 -07:00
}
2017-02-11 01:33:07 -08:00
2015-09-26 23:41:07 -07:00
//The interrupt to control the Boost PWM
2017-07-23 23:34:13 -07:00
# if defined(CORE_AVR)
ISR ( TIMER1_COMPA_vect )
2017-08-27 21:35:49 -07:00
# elif defined (CORE_TEENSY) || defined(CORE_STM32)
2017-07-23 23:34:13 -07:00
static inline void boostInterrupt ( ) //Most ARM chips can simply call a function
# endif
2015-09-26 23:41:07 -07:00
{
if ( boost_pwm_state )
{
2017-07-23 23:34:13 -07:00
BOOST_PIN_LOW ( ) ; // Switch pin to low
BOOST_TIMER_COMPARE = BOOST_TIMER_COUNTER + ( boost_pwm_max_count - boost_pwm_cur_value ) ;
2015-09-26 23:41:07 -07:00
boost_pwm_state = false ;
}
else
{
2017-07-23 23:34:13 -07:00
BOOST_PIN_HIGH ( ) ; // Switch pin high
BOOST_TIMER_COMPARE = BOOST_TIMER_COUNTER + boost_pwm_target_value ;
2015-09-26 23:41:07 -07:00
boost_pwm_cur_value = boost_pwm_target_value ;
boost_pwm_state = true ;
2017-02-11 01:33:07 -08:00
}
2015-09-26 23:41:07 -07:00
}
2015-08-20 06:21:27 -07:00
2015-09-26 23:41:07 -07:00
//The interrupt to control the VVT PWM
2017-07-23 23:34:13 -07:00
# if defined(CORE_AVR)
ISR ( TIMER1_COMPB_vect )
2017-08-27 21:35:49 -07:00
# elif defined (CORE_TEENSY) || defined(CORE_STM32)
2017-07-23 23:34:13 -07:00
static inline void vvtInterrupt ( ) //Most ARM chips can simply call a function
# endif
2015-09-26 23:41:07 -07:00
{
if ( vvt_pwm_state )
{
2017-07-23 23:34:13 -07:00
VVT_PIN_LOW ( ) ; // Switch pin to low
VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + ( vvt_pwm_max_count - vvt_pwm_cur_value ) ;
2015-09-26 23:41:07 -07:00
vvt_pwm_state = false ;
}
else
{
2017-07-23 23:34:13 -07:00
VVT_PIN_HIGH ( ) ; // Switch pin high
VVT_TIMER_COMPARE = VVT_TIMER_COUNTER + vvt_pwm_target_value ;
2015-09-26 23:41:07 -07:00
vvt_pwm_cur_value = vvt_pwm_target_value ;
vvt_pwm_state = true ;
2017-02-11 01:33:07 -08:00
}
2015-09-26 23:41:07 -07:00
}
2016-01-12 22:06:55 -08:00