Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r47205a5002f27add91d8548f31c8a6fa18993fea -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 47205a5002f27add91d8548f31c8a6fa18993fea) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -15,7 +15,7 @@ * ***************************************************************************/ -#include // TODO remove if not needed +#include // Used for converting slope to radians and square root // TI PWM driver #include "etpwm.h" @@ -29,6 +29,7 @@ #include "ROPump.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" +#include "TaskGeneral.h" #include "TaskPriority.h" #include "TemperatureSensors.h" #include "Timers.h" @@ -40,29 +41,28 @@ // ********** private definitions ********** -#define MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE 1.00 ///< Main primary heater (heater A) max duty cycle (100%). -#define SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE 1.00 ///< Small Primary heater (heater B) max duty cycle (100%). -#define TRIMMER_HEATER_MAX_DUTY_CYCLE 1.00 ///< Trimmer heater max duty cycle (100%). +#define HEATERS_MAX_DUTY_CYCLE 1.00 ///< Main primary heater (heater A) max duty cycle (100%). +#define SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE 1.00 // TODO remove ///< Small Primary heater (heater B) max duty cycle (100%). +#define TRIMMER_HEATER_MAX_DUTY_CYCLE 1.00 // TODO remove ///< Trimmer heater max duty cycle (100%). #define HEATERS_MIN_DUTY_CYCLE 0.00 ///< Primary and trimmer heaters minimum duty cycle (0.00%). -#define PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ( MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE + \ - SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ) ///< Primary heaters cumulative duty cycle. -#define PRIMARY_HEATER_INITIAL_DUTY_CYCLE_ESTIMATE_DIVISOR 2.0 ///< Primary heaters initial duty cycle estimation divisor. -#define MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR 2.0 ///< Main and small primary heater duty cycle divisor +#define PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ( HEATERS_MAX_DUTY_CYCLE + \ + SMALL_PRIMAY_HEATER_MAX_DUTY_CYCLE ) //TODO remove ///< Primary heaters cumulative duty cycle. +#define PRIMARY_HEATER_INITIAL_DUTY_CYCLE_ESTIMATE_DIVISOR 2.0 // TODO remove ///< Primary heaters initial duty cycle estimation divisor. +#define MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR 2.0 // TODO remove ///< Main and small primary heater duty cycle divisor -#define PRIMARY_HEATERS_P_COEFFICIENT 0.15 // TODO remove ///< Primary heaters proportional coefficient. -#define PRIMARY_HEATERS_I_COEFFICIENT 0.001 // TODO remove ///< Primary heaters integral coefficient. +#define PRIMARY_HEATER_P_COEFFICIENT 0.05 ///< Primary heaters proportional coefficient. +#define PRIMARY_HEATER_I_COEFFICIENT 0.00 // TODO remove? ///< Primary heaters integral coefficient. #define TRIMMER_HEATER_P_COEFFICIENT 0.02 // TODO remove ///< Trimmer heater proportional coefficient. #define TRIMMER_HEATER_I_COEFFICIENT 0.001 // TODO remove ///< Trimmer heater integral coefficient. -#define CONTROLLER_CHECK_INTERVAL_COUNT 10U ///< Time interval count to check the PI controller. -#define TEMP_SENSORS_INTERVAL_COUNT 10U ///< Temperature sensors interval count. - #define HEATERS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. #define MINIMUM_TARGET_TEMPERATURE 10.0 ///< Minimum allowed target temperature for the heaters. #define MAXIMUM_TARGET_TEMPERATURE 90.0 ///< Maximum allowed target temperature for the heaters. +#define HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT 20U ///< Heaters ramp check interval count. +#define HEATERS_CONTROL_STATE_CHECK_INTERVAL_COUNT ( 10 * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Temperature sensors interval count. #define HEATERS_ON_WITH_NO_FLOW_TIMEOUT_COUNT ( ( 3 * MS_PER_SECOND ) / TASK_PRIORITY_INTERVAL ) ///< Heaters are on but there is no sufficient flow timeout in counts. #define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C 170.0 ///< Heaters max allowed internal temperature in C. #define HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C 80.0 ///< Heaters max allowed cold junction temperature in C. @@ -71,54 +71,60 @@ #define HEATERS_MAX_OPERATING_VOLTAGE_V 24.0 ///< Heaters max operating voltage in volts. #define HEATERS_VOLTAGE_MONITOR_TIME_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters voltage monitor timer interval. #define HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL 0.2 ///< Heaters max voltage out of range tolerance. +#define HEATERS_MIN_RAMP_TIME_MS ( 6 * MS_PER_SECOND ) ///< Heaters minimum time that they have to stay in the ramp state in milliseconds. +#define TEMPERATURES_MOVING_AVG_SIZE 3U ///< Heaters ramp state temperatures moving average size. -#define PRIMARY_HEATERS_POWER_TO_VOLTAGE_SLOPE 31.644 ///< Primary heaters power to voltage slope. -#define PRIMARY_HEATERS_POWER_TO_VOLTAGE_INTERCEPT 2.0996 ///< Primary heaters power to voltage intercept. +#define PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_SLOPE 0.31644 ///< Primary heaters thermal power to voltage slope. +#define PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT 0.021 ///< Primary heaters thermal power to voltage intercept. /**************************************************** New defines ***********************/ typedef enum Heaters_Exec_States { HEATER_EXEC_STATE_NOT_RUNNING = 0, ///< Heater exec state not running - HEATER_EXEC_STATE_RAMP_UP_TO_TARGET, ///< Heater exec state ramp up to target + HEATER_EXEC_STATE_RAMP_TO_TARGET, ///< Heater exec state ramp to target HEATER_EXEC_STATE_CONTROL_TO_TARGET, ///< Heater exec state control to target NUM_OF_HEATERS_STATE, ///< Number of heaters state } HEATERS_STATE_T; +/// Heaters data structure typedef struct { - F32 targetTemperature; ///< Heater Target temperature - F32 previousTemperature; ///< Heater Previous temperature TODO do we need this anymore? + F32 targetTemp; ///< Heater Target temperature + F32 previousTemps[ TEMPERATURES_MOVING_AVG_SIZE ]; ///< Heater Previous temperatures array + U32 previousTempsIndex; ///< Heater previous temperatures arrays current index HEATERS_STATE_T state; ///< Heater state TEMPERATURE_SENSORS_T feedbackSensor; ///< Heater feedback sensor for controlling U32 controlTimerCounter; ///< Heater control timer counter BOOL startHeaterSignal; ///< Heater start indication flag BOOL isHeaterOn; ///< Heater on/off status flag - // TODO remove once the mechanical thermal cutoff was implemented - U32 tempOutOfRangeTimer; ///< Heater temperature out of range timer - BOOL isHeaterTempOutOfRange; ///< Heater temperature out of range flag indicator - // TODO remove once the mechanical thermal cutoff was implemented + U32 tempOutOfRangeTimer; ///< Heater temperature out of range timer TODO remove once the mechanical thermal cutoff was implemented + BOOL isHeaterTempOutOfRange; ///< Heater temperature out of range flag indicator TODO remove once the mechanical thermal cutoff was implemented F32 dutycycle; ///< Heater duty cycle - F32 maxAllowedDutyCycle; ///< Heater maximum allowed duty cycle F32 targetROFlow; ///< Heater target flow + U32 rampStateStartTime; ///< Heater ramp state start time + U32 heaterOnWithNoFlowTimer; ///< Heater on with no flow timer + BOOL isFlowBelowMin; ///< Heater flow below minimum flag indicator + PI_CONTROLLER_ID_T controllerID; ///< Heater PI controller ID TODO remove this? + F32 initialDutyCycle; ///< Heater initial duty cycle before a hand off } HEATER_STATUS_T; static HEATER_STATUS_T heaterStatus[ NUM_OF_DG_HEATERS ]; ///< Heaters status. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. -static U32 heatersOnWithNoFlowTimer; ///< Heaters are on but there is no sufficient flow. +static U32 heatersOnWithNoFlowTimer; ///< Heaters are on but there is no sufficient flow. TODO remove -static BOOL isFlowBelowMin = FALSE; ///< Boolean flag to indicate if the flow is below the minimum. +static BOOL isFlowBelowMin = FALSE; ///< Boolean flag to indicate if the flow is below the minimum. TODo remove static U32 voltageMonitorTimeCounter = 0; ///< Heaters voltage monitor counter. // ********** private function prototypes ********** static HEATERS_STATE_T handleHeaterStateNotRunning( DG_HEATERS_T heater ); -static HEATERS_STATE_T handleHeaterStateRampUpToTarget( DG_HEATERS_T heater ); +static HEATERS_STATE_T handleHeaterStateRampToTarget( DG_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToTarget( DG_HEATERS_T heater ); static void setHeaterDutyCycle( DG_HEATERS_T heater, F32 pwm ); -static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature ); +static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 targetFlow ); static void setMainPrimaryHeaterPWM( F32 pwm ); static void setSmallPrimaryHeaterPWM( F32 pwm ); @@ -212,30 +218,31 @@ heaterStatus[ heater ].controlTimerCounter = 0; // The default feedback sensor of the primary heater is TPo but it changes to THd in heat disinfect // The default feedback sensor of the trimmer heater is TDi all the time - heaterStatus[ heater ].feedbackSensor = ( DG_PRIMARY_HEATER == heater ? TEMPSENSORS_OUTLET_PRIMARY_HEATER : TEMPSENSORS_OUTLET_REDUNDANT ); + heaterStatus[ heater ].feedbackSensor = ( DG_PRIMARY_HEATER == heater ? TEMPSENSORS_OUTLET_PRIMARY_HEATER : TEMPSENSORS_INLET_DIALYSATE ); heaterStatus[ heater ].startHeaterSignal = FALSE; heaterStatus[ heater ].tempOutOfRangeTimer = 0; heaterStatus[ heater ].isHeaterTempOutOfRange = FALSE; - heaterStatus[ heater ].previousTemperature = 0.0; heaterStatus[ heater ].state = HEATER_EXEC_STATE_NOT_RUNNING; - heaterStatus[ heater ].targetTemperature = 0.0; + heaterStatus[ heater ].targetTemp = 0.0; heaterStatus[ heater ].dutycycle = 0.0; - heaterStatus[ heater ].maxAllowedDutyCycle = ( DG_PRIMARY_HEATER == heater ? PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE : TRIMMER_HEATER_MAX_DUTY_CYCLE ); heaterStatus[ heater ].targetROFlow = 0.0; + heaterStatus[ heater ].previousTempsIndex = 0; + heaterStatus[ heater ].controllerID = ( DG_PRIMARY_HEATER == heater ? PI_CONTROLLER_ID_PRIMARY_HEATER : PI_CONTROLLER_ID_TRIMMER_HEATER ); + heaterStatus[ heater ].initialDutyCycle = 0.0; + + // Set the array of the previous temperatures to 0.0 + memset( &heaterStatus[ heater ].previousTemps, 0.0, sizeof( TEMPERATURES_MOVING_AVG_SIZE ) ); } - // TODO remove // Initialize the PI controller for the primary heaters - initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATERS_P_COEFFICIENT, PRIMARY_HEATERS_I_COEFFICIENT, - HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATERS_CUMULATIVE_DUTY_CYCLE ); + initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATER_P_COEFFICIENT, PRIMARY_HEATER_I_COEFFICIENT, + HEATERS_MIN_DUTY_CYCLE, HEATERS_MAX_DUTY_CYCLE ); // Initialize the PI controller for the trimmer heater - initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, - TRIMMER_HEATER_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_MAX_DUTY_CYCLE ); - // TODO remove + initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, TRIMMER_HEATER_I_COEFFICIENT, + HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_MAX_DUTY_CYCLE ); } - /*********************************************************************//** * @brief * The setHeaterTargetTemperature function sets the target temperature of a heater. @@ -252,7 +259,7 @@ { if ( ( targetTemperature >= MINIMUM_TARGET_TEMPERATURE ) && ( targetTemperature <= MAXIMUM_TARGET_TEMPERATURE ) ) { - heaterStatus[ heater ].targetTemperature = targetTemperature; + heaterStatus[ heater ].targetTemp = targetTemperature; // TODO alarm if temperature if out of range or just reject? } } @@ -276,7 +283,7 @@ if( heater < NUM_OF_DG_HEATERS ) { - F32 targetTemp = heaterStatus[ heater ].targetTemperature; + F32 targetTemp = heaterStatus[ heater ].targetTemp; if ( ( targetTemp >= MINIMUM_TARGET_TEMPERATURE ) && ( targetTemp <= MAXIMUM_TARGET_TEMPERATURE ) ) { @@ -327,8 +334,8 @@ heaterStatus[ heater ].state = handleHeaterStateNotRunning( heater ); break; - case HEATER_EXEC_STATE_RAMP_UP_TO_TARGET: - heaterStatus[ heater ].state = handleHeaterStateRampUpToTarget( heater ); + case HEATER_EXEC_STATE_RAMP_TO_TARGET: + heaterStatus[ heater ].state = handleHeaterStateRampToTarget( heater ); break; case HEATER_EXEC_STATE_CONTROL_TO_TARGET: @@ -417,7 +424,7 @@ * In the monitor, trimmer heater is only monitored if heat disinfect mode is active. Trimmer heater is usually * controlled by HD so checking the DG flow rate to decide whether it should be on or off is not appropriate */ - BOOL isModeHeat = ( DG_MODE_HEAT == getCurrentOperationMode() ) && ( TRUE == isTrimmerHeaterOn ); + /*BOOL isModeHeat = ( DG_MODE_HEAT == getCurrentOperationMode() ) && ( TRUE == isTrimmerHeaterOn ); BOOL isHeaterOn = ( TRUE == isPrimaryHeaterOn ) || ( TRUE == isModeHeat ); BOOL isPWMNonZero = ( mainPrimaryHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ) || ( smallPrimaryHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ) || ( trimmerHeaterDutyCycle > HEATERS_MIN_DUTY_CYCLE ); @@ -448,7 +455,7 @@ isFlowBelowMin = FALSE; heatersOnWithNoFlowTimer = getMSTimerCount(); } - } + }*/ // Check for data publication publishHeatersData(); @@ -470,109 +477,196 @@ { heaterStatus[ heater ].isHeaterOn = TRUE; heaterStatus[ heater ].startHeaterSignal = FALSE; + heaterStatus[ heater ].targetROFlow = getTargetROPumpFlowRate(); - // If the operation mode is heater disinfect and the heater is primary heater, change the feedback sensor to THd + // If the operation mode is heat disinfect and the heater is primary heater, change the feedback sensor to THd if ( ( DG_MODE_HEAT == getCurrentOperationMode() ) && ( DG_PRIMARY_HEATER == heater ) ) { -#ifdef THD_USING_TRO_CONNECTOR - // Set the feedback temperature sensor and THd uses TRo in V3 - heaterStatus[ heater ].feedbackSensor = TEMPSENSORS_OUTLET_REDUNDANT; -#else heaterStatus[ heater ].feedbackSensor = TEMPSENSORS_HEAT_DISINFECT; -#endif } - // Set the heater duty cycle to maximum - setHeaterDutyCycle( heater, heaterStatus[ heater ].maxAllowedDutyCycle ); + TEMPERATURE_SENSORS_T sensor = heaterStatus[ heater ].feedbackSensor; + F32 feedbackTemperature = getTemperatureValue( (U32)sensor ); + F32 targetTemperature = heaterStatus[ heater ].targetTemp; + if ( targetTemperature > feedbackTemperature ) + { + // Set the heater duty cycle to maximum + setHeaterDutyCycle( heater, HEATERS_MAX_DUTY_CYCLE ); + } + else + { + // Set the heater duty cycle to minimum since we are cooling + setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); + } + + // Once the heater is staring for the first time so no minimum ramp time is needed + heaterStatus[ heater ].rampStateStartTime = getMSTimerCount(); + // Turn on the heater - state = HEATER_EXEC_STATE_RAMP_UP_TO_TARGET; + state = HEATER_EXEC_STATE_RAMP_TO_TARGET; } return state; } /*********************************************************************//** * @brief - * The handleHeaterStateRampUpToTarget function handles the heaters' control - * while they are ramped up to target temperature. + * The handleHeaterStateRampToTarget function handles the heaters' control + * while they are ramping to target temperature. * @details Inputs: heaterStatus * @details Outputs: heaterStatus * @param heater: The heater Id that its on state is handled * @return next state of the state machine *************************************************************************/ -static HEATERS_STATE_T handleHeaterStateRampUpToTarget( DG_HEATERS_T heater ) +static HEATERS_STATE_T handleHeaterStateRampToTarget( DG_HEATERS_T heater ) { - HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_UP_TO_TARGET; + HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; TEMPERATURE_SENSORS_T sensor = heaterStatus[ heater ].feedbackSensor; - F32 temperature = getTemperatureValue( (U32)sensor ); + F32 feedbackTemperature = getTemperatureValue( (U32)sensor ); + // Continuously get the target temperature in case it was changed dynamically + F32 targetTemperature = heaterStatus[ heater ].targetTemp; + U32 currentIndex = heaterStatus[ heater ].previousTempsIndex; - // TODO remove - setHeaterDutyCycle( heater, 0.44 ); - - if ( FALSE == heaterStatus[ heater ].isHeaterOn ) + if ( ++heaterStatus[ heater ].controlTimerCounter > HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT ) { - setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); - state = HEATER_EXEC_STATE_NOT_RUNNING; - } - // TODO remove + U32 i; + F32 slope; + F32 deltaTemperature; + F32 deltaDutyCycle; + F32 dutyCycle; + F32 revDeltaDutyCycle; + F32 inletTemperature; + F32 measuredFlow; - /*if ( ++heaterStatus[ heater ].controlTimerCounter > CONTROLLER_CHECK_INTERVAL_COUNT ) - { - // If the heaters are not longer on, set the duty cycle to 0 - if ( FALSE == heaterStatus[ heater ].isHeaterOn ) + // Set the hand off flag to false + BOOL isItHandOffTime = FALSE; + + // Update the temperature data array as well as the next index + heaterStatus[ heater ].previousTemps[ currentIndex ] = feedbackTemperature; + heaterStatus[ heater ].previousTempsIndex = INC_WRAP( currentIndex, 0, TEMPERATURES_MOVING_AVG_SIZE - 1 ); + + // Calculate the running sum of the temperatures + for ( i = 0; i < TEMPERATURES_MOVING_AVG_SIZE; i++ ) { - setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); + slope += heaterStatus[ heater ].previousTemps[ i ]; } + + // If the heater is the primary heater, + if ( DG_PRIMARY_HEATER == heater ) + { + inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + } else { - F32 targetTemperature = heaterStatus[ heater ].targetTemperature; - F32 prevTemperature = heaterStatus[ heater ].previousTemperature; - F32 temperatureSlope = ( temperature - prevTemperature ) / CONTROLLER_CHECK_INTERVAL_COUNT; + // TODO figure out the trimmer strategy + } - if ( temperatureSlope > 0.0 ) + slope = slope / (F32)TEMPERATURES_MOVING_AVG_SIZE; + measuredFlow = getMeasuredROFlowRate(); + dutyCycle = calculateHeaterDutyCycle( targetTemperature, inletTemperature, measuredFlow ); + deltaDutyCycle = ( feedbackTemperature <= targetTemperature ? HEATERS_MAX_DUTY_CYCLE - dutyCycle : dutyCycle ); + + // TODO add #defines for all these constants + revDeltaDutyCycle = ( deltaDutyCycle - 0.0 < NEARLY_ZERO ? 0 : 1.0 / deltaDutyCycle ); + revDeltaDutyCycle = ( revDeltaDutyCycle * 0.1 < 1.0 ? revDeltaDutyCycle * 0.1 : 1.0 ); + deltaTemperature = ( ( atanf( slope ) * 1.27 ) / measuredFlow ) + revDeltaDutyCycle; + + if ( fabs( targetTemperature - feedbackTemperature ) < deltaTemperature ) + { + if ( TRUE == didTimeout( heaterStatus[ heater ].rampStateStartTime, HEATERS_MIN_RAMP_TIME_MS ) ) { - // TODO make a #define for delta temperature from target - // TODO create the cases for the temperature being above the target - if ( ( targetTemperature - temperature > 0.5 ) && ( temperature < targetTemperature ) ) - { - setHeaterDutyCycle( heater, heaterStatus[ heater ].maxAllowedDutyCycle ); - } - if ( ( targetTemperature - temperature < 0.5 ) && ( temperature < targetTemperature ) ) - { - // We are in range - // Start the P controller - } + isItHandOffTime = TRUE; } - else if ( ( temperatureSlope < 0.0 ) && ( targetTemperature - temperature < 0.5 ) && ( temperature < targetTemperature ) ) - { - setHeaterDutyCycle( heater, heaterStatus[ heater ].maxAllowedDutyCycle ); - } } + if ( TRUE == isItHandOffTime ) + { + setHeaterDutyCycle( heater, dutyCycle ); + resetPIController( heaterStatus[ heater ].controllerID, dutyCycle ); // TODO remove? + + heaterStatus[ heater ].initialDutyCycle = dutyCycle; + + state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; + } + heaterStatus[ heater ].controlTimerCounter = 0; - }*/ + } + // Check if the heater is requested to be off + if ( FALSE == heaterStatus[ heater ].isHeaterOn ) + { + setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); + state = HEATER_EXEC_STATE_NOT_RUNNING; + } + return state; } +/*********************************************************************//** + * @brief + * The handleHeaterStateControlToTarget function handles the heaters' control + * to target while they have reached to target. + * @details Inputs: heaterStatus + * @details Outputs: heaterStatus + * @param heater: The heater Id that its on state is handled + * @return next state of the state machine + *************************************************************************/ static HEATERS_STATE_T handleHeaterStateControlToTarget( DG_HEATERS_T heater ) { HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - F32 flow = getMeasuredROFlowRate(); + F32 targetFlow = getTargetROPumpFlowRate(); + BOOL hasFlowChanged = fabs( targetFlow - heaterStatus[ heater ].targetROFlow ) > NEARLY_ZERO; - F32 power = sqrt( ( targetTemperature - currentTemperature ) * flow ); + if ( TRUE == hasFlowChanged ) + { + // Moving back from control to target to ramp. + heaterStatus[ heater ].rampStateStartTime = getMSTimerCount(); - F32 dutyCycle = ( ( power * PRIMARY_HEATERS_POWER_TO_VOLTAGE_SLOPE ) - PRIMARY_HEATERS_POWER_TO_VOLTAGE_INTERCEPT ) / HEATERS_MAX_OPERATING_VOLTAGE_V; + // Go back to ramp state with 100% duty cycle + setHeaterDutyCycle( heater, HEATERS_MAX_DUTY_CYCLE ); + state = HEATER_EXEC_STATE_RAMP_TO_TARGET; + } + else if ( ++heaterStatus[ heater ].controlTimerCounter > HEATERS_CONTROL_STATE_CHECK_INTERVAL_COUNT ) + { + F32 feedbackTemperature = getTemperatureValue( (U32)heaterStatus[ heater ].feedbackSensor ); + F32 targetTemperature = heaterStatus[ heater ].targetTemp; + F32 dutyCycle = heaterStatus[ heater ].dutycycle; + dutyCycle += ( targetTemperature - feedbackTemperature ) * PRIMARY_HEATER_P_COEFFICIENT * getMeasuredROFlowRate(); - return state; -} + F32 deltaDutyCycle = dutyCycle - heaterStatus[ heater ].initialDutyCycle; + if ( ( fabs( deltaDutyCycle ) > 0.09 ) && ( deltaDutyCycle < 0.0 ) ) + { + dutyCycle = heaterStatus[ heater ].initialDutyCycle - 0.09; + } + else if ( deltaDutyCycle > 0.09 ) + { + dutyCycle = heaterStatus[ heater ].initialDutyCycle + 0.09; + } + // TODO remove + //dutyCycle = ( deltaDutyCycle < 0.0 ? ( fabs( deltaDutyCycle ) < 0.05 ? dutyCycle : heaterStatus[ heater ].initialDutyCycle - 0.05 ) : + // ( deltaDutyCycle < 0.05 ? dutyCycle : heaterStatus[ heater ].initialDutyCycle + 0.05 ) ); + setHeaterDutyCycle( heater, dutyCycle ); + + heaterStatus[ heater ].controlTimerCounter = 0; + } + + // Check if the heater is requested to be off + if ( FALSE == heaterStatus[ heater ].isHeaterOn ) + { + setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); + state = HEATER_EXEC_STATE_NOT_RUNNING; + } + + return state; +} + /*********************************************************************//** * @brief * The setHeaterDutyCycle function sets the duty cycle of a heater. @@ -586,35 +680,267 @@ { if ( DG_PRIMARY_HEATER == heater ) { - F32 main = pwm / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; - F32 small = pwm / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; - - setMainPrimaryHeaterPWM( main ); - setSmallPrimaryHeaterPWM( small ); - - heaterStatus[ DG_PRIMARY_HEATER ].dutycycle = main; + setMainPrimaryHeaterPWM( pwm ); + setSmallPrimaryHeaterPWM( pwm ); } else if ( DG_TRIMMER_HEATER == heater ) { setTrimmerHeaterPWM( pwm ); - - heaterStatus[ DG_TRIMMER_HEATER ].dutycycle = pwm; } + + heaterStatus[ heater ].dutycycle = pwm; } -static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature ) +/*********************************************************************//** + * @brief + * The calculateHeaterDutyCycle function calculates a heater's duty cycle + * by providing the + * @details Inputs: none + * @details Outputs: primaryHeaterTargetTemperature + * @param targetTemp target temperature for the primary heater + * @return none + *************************************************************************/ +static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 targetFlow ) { - F32 flow = getMeasuredROFlowRate(); + // The power is proportional to square root of deltaT x flow + F32 power = sqrt( fabs( targetTemperature - currentTemperature ) * targetFlow ); - F32 power = sqrt( ( targetTemperature - currentTemperature ) * flow ); + // PWM = ( power * A - B ) + F32 dutyCycle = ( ( power * PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_SLOPE ) - PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT ); - F32 dutyCycle = ( ( power * PRIMARY_HEATERS_POWER_TO_VOLTAGE_SLOPE ) - PRIMARY_HEATERS_POWER_TO_VOLTAGE_INTERCEPT ) / HEATERS_MAX_OPERATING_VOLTAGE_V; + // Check the boundaries of the calculated duty cycle + dutyCycle = ( dutyCycle > HEATERS_MAX_DUTY_CYCLE ? HEATERS_MAX_DUTY_CYCLE : dutyCycle ); + dutyCycle = ( dutyCycle < HEATERS_MIN_DUTY_CYCLE ? HEATERS_MIN_DUTY_CYCLE : dutyCycle ); return dutyCycle; } /*********************************************************************//** * @brief + * The setMainPrimaryHeaterPWM function sets the PWM of the main primary heater. + * @details Inputs: none + * @details Outputs: Sets the PWM duty cycle for the main primary heater + * @param pwm PWM duty cycle to set for 1st primary heater element + * @return none + *************************************************************************/ +static void setMainPrimaryHeaterPWM( F32 pwm ) +{ + etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The setSmallPrimaryHeaterPWM function sets the PWM of the small primary heater. + * @details Inputs: none + * @details Outputs: Sets the PWM duty cycle for the small primary heater + * @param pwm PWM duty cycle to set for 2nd primary heater element + * @return none + *************************************************************************/ +static void setSmallPrimaryHeaterPWM( F32 pwm ) +{ + etpwmSetCmpB( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The setTrimmerHeaterPWM function sets the PWM of the trimmer heater. + * @details Inputs: none + * @details Outputs: Sets the PWM duty cycle for the trimmer heater + * @param pwm PWM duty cycle to set for trimmer heater + * @return none + *************************************************************************/ +static void setTrimmerHeaterPWM( F32 pwm ) +{ + etpwmSetCmpA( etpwmREG3, (U32)( (S32)( ( pwm * (F32)(etpwmREG3->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); +} + +/*********************************************************************//** + * @brief + * The getPublishHeatersDataInterval function gets the publish interval. + * @details Inputs: heatersDataPublishInterval + * @details Outputs: none + * @return result + *************************************************************************/ +U32 getPublishHeatersDataInterval( void ) +{ + U32 result = heatersDataPublishInterval.data; + + if ( OVERRIDE_KEY == heatersDataPublishInterval.override ) + { + result = heatersDataPublishInterval.ovData; + } + + return result; +} + +/*********************************************************************//** + * @brief + * The publishTemperatureData function publishes the heaters data into + * at the defined time interval. + * @details Inputs: dataPublicationTimerCounter + * @details Outputs: dataPublicationTimerCounter + * @return none + *************************************************************************/ +static void publishHeatersData( void ) +{ + if ( ++dataPublicationTimerCounter >= getPublishHeatersDataInterval() ) + { + HEATERS_DATA_T data; + + data.mainPrimayHeaterDC = heaterStatus[ DG_PRIMARY_HEATER ].dutycycle * 100.0; + // The duty cycle of the primary heater is divided into 2 parts and is applied to main + // and small primary heaters. So they are always the same. + data.smallPrimaryHeaterDC = heaterStatus[ DG_PRIMARY_HEATER ].dutycycle * 100.0; + data.trimmerHeaterDC = heaterStatus[ DG_TRIMMER_HEATER ].dutycycle * 100.0; + data.primaryTargetTemp = heaterStatus[ DG_PRIMARY_HEATER ].targetTemp; + data.trimmerTargetTemp = heaterStatus[ DG_TRIMMER_HEATER ].targetTemp; + data.primaryHeaterState = heaterStatus[ DG_PRIMARY_HEATER ].state; + data.trimmerHeaterState = heaterStatus[ DG_TRIMMER_HEATER ].state; + + broadcastHeatersData( &data ); + + //broadcastData( MSG_ID_DG_HEATERS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( HEATERS_DATA_T ) ); + + dataPublicationTimerCounter = 0; + } +} + +/*********************************************************************//** + * @brief + * The checkPrimaryHeaterTempSensors function checks the primary heater's + * thermocouple and cold junction temperature sensors. + * @details Inputs: isPrimaryHeaterTempOutOfRange + * @details Outputs: isPrimaryHeaterTempOutOfRange + * @return none + *************************************************************************/ +static void checkPrimaryHeaterTempSensors( void ) +{ + F32 primaryHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_INTERNAL ); + F32 primaryHeaterColdJunctionTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_COLD_JUNCTION ); + BOOL isTempOut = FALSE; + + // Check if the primary heater's internal temperature or the cold junction temperature is above the allowed limit + if ( primaryHeaterInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) + { + isTempOut = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATER_INTERNAL_TEMP_OUT_OF_RANGE, primaryHeaterInternalTemp ); + } + else if ( primaryHeaterColdJunctionTemp > HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C ) + { + isTempOut = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATER_CJ_TEMP_OUT_OF_RANGE, primaryHeaterInternalTemp ); + } + + // If any of the temperatures are above the range + if ( ( FALSE == isPrimaryHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) + { + stopPrimaryHeater(); + isPrimaryHeaterTempOutOfRange = TRUE; + primaryHeaterTempOutTimer = getMSTimerCount(); + } + // If the primary heaters internal temperature was out for more than the define period, activate the safety shutdown + else if ( ( TRUE == isPrimaryHeaterTempOutOfRange ) && + ( TRUE == didTimeout( primaryHeaterTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) ) + { + isPrimaryHeaterTempOutOfRange = FALSE; + activateSafetyShutdown(); + } +} + +/*********************************************************************//** + * @brief + * The checkTrimmerHeaterTempSensors function checks the trimmer heater's + * thermocouple and cold junction temperature sensors. + * @details Inputs: isTrimmerHeaterTempOutOfRange + * @details Outputs: isTrimmerHeaterTempOutOfRange + * @return none + *************************************************************************/ +static void checkTrimmerHeaterTempSensors( void ) +{ + F32 trimmerHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_INTERNAL ); + F32 trimmerHeaterColdJunctionTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_COLD_JUNCTION ); + BOOL isTempOut = FALSE; + + // Check if the primary heater's internal temperature or the cold junction temperature is above the allowed limit + if ( trimmerHeaterInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) + { + isTempOut = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_INTERNAL_TEMP_OUT_OF_RANGE, trimmerHeaterInternalTemp ); + } + else if ( trimmerHeaterColdJunctionTemp > HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C ) + { + isTempOut = TRUE; + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_CJ_TEMP_OUT_OF_RANGE, trimmerHeaterColdJunctionTemp ); + } + + // If it is above the range for the first time, stop the trimmer heater + // and set the variables + if ( ( FALSE == isTrimmerHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) + { + stopTrimmerHeater(); + isTrimmerHeaterTempOutOfRange = TRUE; + trimmerHeaterTempOutTimer = getMSTimerCount(); + } + // If the trimmer heater internal temperature was out for more than the define period, activate the safety shutdown + else if ( ( TRUE == isTrimmerHeaterTempOutOfRange ) && + ( TRUE == didTimeout( trimmerHeaterTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) ) + { + activateSafetyShutdown(); + } +} + +/*********************************************************************//** + * @brief + * The monitorHeatersVoltage function monitors the heaters' voltages + * @details Inputs: heatersVoltageMonitorTimeCounter + * @details Outputs: heatersVoltageMonitorTimeCounter + * @return none + *************************************************************************/ +static void monitorHeatersVoltage( void ) +{ + if ( ++voltageMonitorTimeCounter >= HEATERS_VOLTAGE_MONITOR_TIME_INTERVAL ) + { + F32 mainPriVoltage = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); + // TODO it is assumed that the main and small primary heaters have equal voltage since the PWMs are divided into 2 + // before applying the PWMs to the heaters. Right now, there is no ADC channel available for the small primary + // heater so the main primary heater's ADC channel is used for the small primary heater as well. + F32 smallPriVoltage = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); + F32 trimmerVoltage = getIntADCVoltageConverted( INT_ADC_TRIMMER_HEATER_24_VOLTS ); + + // Voltage to PWM is reverse. If PWM = 0 -> V = 24V + F32 mainPri = 1.0 - mainPrimaryHeaterDutyCycle; + F32 smallPri = 1.0 - smallPrimaryHeaterDutyCycle; + F32 trimmer = 1.0 - trimmerHeaterDutyCycle; + + // Check main primary heater's voltage + // The corresponding voltage of the current PWM must be close to the sensed voltage + if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * mainPri ) - mainPriVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * mainPriVoltage ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_MAIN_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, mainPriVoltage ); + } + // Check small primary heater's voltage + if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * smallPri ) - smallPriVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * smallPriVoltage ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_SMALL_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, smallPriVoltage ); + } + // Check trimmer heater's voltage + if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * trimmer ) - trimmerVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * trimmerVoltage ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, trimmerVoltage ); + } + + voltageMonitorTimeCounter = 0; + } +} + + +// TODO remove the below functions + + + + +/*********************************************************************//** + * @brief * The setPrimaryHeaterTargetTemperature function sets the primary heater * target temperature. * @details Inputs: none @@ -819,7 +1145,7 @@ { PRIMARY_HEATERS_EXEC_STATES_T state = PRIMARY_HEATERS_EXEC_STATE_CONTROL_TO_TARGET; - if ( ++primaryHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) + if ( ++primaryHeaterTimerCounter >= HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT ) { // Check if the flow is not below minimum required first // If the flow is below minimum, send 0.00 to the PWM until the flow comes back to range @@ -839,8 +1165,8 @@ mainPrimaryHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); // Once the primary heaters duty cycle is set, it is divided into 2 so both heaters will start and both elements are heated up - smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; - mainPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle / MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; + smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle; // MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; + mainPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle; // MAIN_AND_SMALL_PRIMARY_HEATER_DUTY_CYCLE_DIVISOR; } setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); @@ -904,7 +1230,7 @@ { TRIMMER_HEATER_EXEC_STATES_T state = TRIMMER_HEATER_EXEC_STATE_CONTROL_TO_TARGET; - if ( ++trimmerHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) + if ( ++trimmerHeaterTimerCounter >= HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT ) { // Check if the flow is not below minimum required first // If the flow is below minimum, send 0.00 to the PWM until the flow comes back to range @@ -935,45 +1261,6 @@ /*********************************************************************//** * @brief - * The setMainPrimaryHeaterPWM function sets the PWM of the main primary heater. - * @details Inputs: none - * @details Outputs: Sets the PWM duty cycle for the main primary heater - * @param pwm PWM duty cycle to set for 1st primary heater element - * @return none - *************************************************************************/ -static void setMainPrimaryHeaterPWM( F32 pwm ) -{ - etpwmSetCmpA( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); -} - -/*********************************************************************//** - * @brief - * The setSmallPrimaryHeaterPWM function sets the PWM of the small primary heater. - * @details Inputs: none - * @details Outputs: Sets the PWM duty cycle for the small primary heater - * @param pwm PWM duty cycle to set for 2nd primary heater element - * @return none - *************************************************************************/ -static void setSmallPrimaryHeaterPWM( F32 pwm ) -{ - etpwmSetCmpB( etpwmREG1, (U32)( (S32)( ( pwm * (F32)(etpwmREG1->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); -} - -/*********************************************************************//** - * @brief - * The setTrimmerHeaterPWM function sets the PWM of the trimmer heater. - * @details Inputs: none - * @details Outputs: Sets the PWM duty cycle for the trimmer heater - * @param pwm PWM duty cycle to set for trimmer heater - * @return none - *************************************************************************/ -static void setTrimmerHeaterPWM( F32 pwm ) -{ - etpwmSetCmpA( etpwmREG3, (U32)( (S32)( ( pwm * (F32)(etpwmREG3->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); -} - -/*********************************************************************//** - * @brief * The resetHeaterState function resets the PI controller of the selected heater. * @details Inputs: mainPrimaryHeaterDutyCycle, trimmerHeaterDutyCycle * @details Outputs: mainPrimaryHeaterDutyCycle, trimmerHeaterDutyCycle @@ -1017,182 +1304,7 @@ } } -/*********************************************************************//** - * @brief - * The getPublishHeatersDataInterval function gets the publish interval. - * @details Inputs: heatersDataPublishInterval - * @details Outputs: none - * @return result - *************************************************************************/ -U32 getPublishHeatersDataInterval( void ) -{ - U32 result = heatersDataPublishInterval.data; - if ( OVERRIDE_KEY == heatersDataPublishInterval.override ) - { - result = heatersDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief - * The publishTemperatureData function publishes the heaters data into - * at the defined time interval. - * @details Inputs: dataPublicationTimerCounter - * @details Outputs: dataPublicationTimerCounter - * @return none - *************************************************************************/ -static void publishHeatersData( void ) -{ - if ( ++dataPublicationTimerCounter >= getPublishHeatersDataInterval() ) - { - HEATERS_DATA_T data; - - data.mainPrimayHeaterDC = heaterStatus[ DG_PRIMARY_HEATER ].dutycycle * 100.0; - // The duty cycle of the primary heater is divided into 2 parts and is applied to main - // and small primary heaters. So they are always the same. - data.smallPrimaryHeaterDC = heaterStatus[ DG_PRIMARY_HEATER ].dutycycle * 100.0; - data.trimmerHeaterDC = heaterStatus[ DG_TRIMMER_HEATER ].dutycycle * 100.0; - data.primaryTargetTemp = heaterStatus[ DG_PRIMARY_HEATER ].targetTemperature; - data.trimmerTargetTemp = heaterStatus[ DG_TRIMMER_HEATER ].targetTemperature; - - broadcastHeatersData( &data ); - - dataPublicationTimerCounter = 0; - } -} - -/*********************************************************************//** - * @brief - * The checkPrimaryHeaterTempSensors function checks the primary heater's - * thermocouple and cold junction temperature sensors. - * @details Inputs: isPrimaryHeaterTempOutOfRange - * @details Outputs: isPrimaryHeaterTempOutOfRange - * @return none - *************************************************************************/ -static void checkPrimaryHeaterTempSensors( void ) -{ - F32 primaryHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_INTERNAL ); - F32 primaryHeaterColdJunctionTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_COLD_JUNCTION ); - BOOL isTempOut = FALSE; - - // Check if the primary heater's internal temperature or the cold junction temperature is above the allowed limit - if ( primaryHeaterInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) - { - isTempOut = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATER_INTERNAL_TEMP_OUT_OF_RANGE, primaryHeaterInternalTemp ); - } - else if ( primaryHeaterColdJunctionTemp > HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C ) - { - isTempOut = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATER_CJ_TEMP_OUT_OF_RANGE, primaryHeaterInternalTemp ); - } - - // If any of the temperatures are above the range - if ( ( FALSE == isPrimaryHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) - { - stopPrimaryHeater(); - isPrimaryHeaterTempOutOfRange = TRUE; - primaryHeaterTempOutTimer = getMSTimerCount(); - } - // If the primary heaters internal temperature was out for more than the define period, activate the safety shutdown - else if ( ( TRUE == isPrimaryHeaterTempOutOfRange ) && - ( TRUE == didTimeout( primaryHeaterTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) ) - { - isPrimaryHeaterTempOutOfRange = FALSE; - activateSafetyShutdown(); - } -} - -/*********************************************************************//** - * @brief - * The checkTrimmerHeaterTempSensors function checks the trimmer heater's - * thermocouple and cold junction temperature sensors. - * @details Inputs: isTrimmerHeaterTempOutOfRange - * @details Outputs: isTrimmerHeaterTempOutOfRange - * @return none - *************************************************************************/ -static void checkTrimmerHeaterTempSensors( void ) -{ - F32 trimmerHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_INTERNAL ); - F32 trimmerHeaterColdJunctionTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_COLD_JUNCTION ); - BOOL isTempOut = FALSE; - - // Check if the primary heater's internal temperature or the cold junction temperature is above the allowed limit - if ( trimmerHeaterInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) - { - isTempOut = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_INTERNAL_TEMP_OUT_OF_RANGE, trimmerHeaterInternalTemp ); - } - else if ( trimmerHeaterColdJunctionTemp > HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C ) - { - isTempOut = TRUE; - SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_CJ_TEMP_OUT_OF_RANGE, trimmerHeaterColdJunctionTemp ); - } - - // If it is above the range for the first time, stop the trimmer heater - // and set the variables - if ( ( FALSE == isTrimmerHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) - { - stopTrimmerHeater(); - isTrimmerHeaterTempOutOfRange = TRUE; - trimmerHeaterTempOutTimer = getMSTimerCount(); - } - // If the trimmer heater internal temperature was out for more than the define period, activate the safety shutdown - else if ( ( TRUE == isTrimmerHeaterTempOutOfRange ) && - ( TRUE == didTimeout( trimmerHeaterTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) ) - { - activateSafetyShutdown(); - } -} - -/*********************************************************************//** - * @brief - * The monitorHeatersVoltage function monitors the heaters' voltages - * @details Inputs: heatersVoltageMonitorTimeCounter - * @details Outputs: heatersVoltageMonitorTimeCounter - * @return none - *************************************************************************/ -static void monitorHeatersVoltage( void ) -{ - if ( ++voltageMonitorTimeCounter >= HEATERS_VOLTAGE_MONITOR_TIME_INTERVAL ) - { - F32 mainPriVoltage = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); - // TODO it is assumed that the main and small primary heaters have equal voltage since the PWMs are divided into 2 - // before applying the PWMs to the heaters. Right now, there is no ADC channel available for the small primary - // heater so the main primary heater's ADC channel is used for the small primary heater as well. - F32 smallPriVoltage = getIntADCVoltageConverted( INT_ADC_PRIMARY_HEATER_24_VOLTS ); - F32 trimmerVoltage = getIntADCVoltageConverted( INT_ADC_TRIMMER_HEATER_24_VOLTS ); - - // Voltage to PWM is reverse. If PWM = 0 -> V = 24V - F32 mainPri = 1.0 - mainPrimaryHeaterDutyCycle; - F32 smallPri = 1.0 - smallPrimaryHeaterDutyCycle; - F32 trimmer = 1.0 - trimmerHeaterDutyCycle; - - // Check main primary heater's voltage - // The corresponding voltage of the current PWM must be close to the sensed voltage - if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * mainPri ) - mainPriVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * mainPriVoltage ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_MAIN_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, mainPriVoltage ); - } - // Check small primary heater's voltage - if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * smallPri ) - smallPriVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * smallPriVoltage ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_SMALL_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, smallPriVoltage ); - } - // Check trimmer heater's voltage - if ( fabs( ( HEATERS_MAX_OPERATING_VOLTAGE_V * trimmer ) - trimmerVoltage ) > HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL * trimmerVoltage ) - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, trimmerVoltage ); - } - - voltageMonitorTimeCounter = 0; - } -} - - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ Index: firmware/App/Controllers/Heaters.h =================================================================== diff -u -r47205a5002f27add91d8548f31c8a6fa18993fea -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision 47205a5002f27add91d8548f31c8a6fa18993fea) +++ firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -64,6 +64,8 @@ F32 trimmerHeaterDC; ///< Trimmer heater DC F32 primaryTargetTemp; ///< Primary heaters target temperature F32 trimmerTargetTemp; ///< Trimmer heater target temperature + U32 primaryHeaterState; ///< Primary heater state + U32 trimmerHeaterState; ///< Trimmer heater state } HEATERS_DATA_T; #pragma pack(pop) Index: firmware/App/Controllers/TemperatureSensors.c =================================================================== diff -u -r922516483829939a2a387d4a2fddeccdb4c454d4 -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision 922516483829939a2a387d4a2fddeccdb4c454d4) +++ firmware/App/Controllers/TemperatureSensors.c (.../TemperatureSensors.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -539,7 +539,7 @@ case TEMPSENSORS_INLET_PRIMARY_HEATER: // 295 case TEMPSENSORS_INTERNAL_COND_TEMP_SENSOR: // 299 case TEMPSENSORS_OUTLET_REDUNDANT: // 303 - case TEMPSENSORS_INTERNAL_TRO_RTD: // 307 + case TEMPSENSORS_INTERNAL_TRO_RTD: // 307 case TEMPSENSORS_INLET_DIALYSATE: // 311 case TEMPSENSORS_INTERNAL_TDI_RTD: // 315 { @@ -615,8 +615,8 @@ #endif // Check the status of FPGA error and FPGA count - BOOL isFPGAErrorZero = fpgaError == 0; - BOOL isFPGACountChanging = tempSensors[ sensorIndex ].readCount != fpgaCount; + BOOL isFPGAErrorZero = ( fpgaError == 0 ? TRUE : FALSE ); + BOOL isFPGACountChanging = ( tempSensors[ sensorIndex ].readCount != fpgaCount ? TRUE : FALSE ); if ( TRUE == isFPGAErrorZero ) { @@ -627,7 +627,7 @@ } } - BOOL isThereAnError = ( FALSE == isFPGACountChanging ) || ( FALSE == isFPGAErrorZero ); + BOOL isThereAnError = ( ( FALSE == isFPGACountChanging ) || ( FALSE == isFPGAErrorZero ) ? TRUE : FALSE ); checkPersistentAlarm( ALARM_ID_DG_TEMPERATURE_SENSORS_ADC_FAULT, isThereAnError, sensorIndex, TEMPERATURE_SENSORS_FPGA_ERROR_PERSISTENT_PERIOD ); Index: firmware/App/Modes/ModeInitPOST.c =================================================================== diff -u -rddb9707d9e6e46c4b384782aeec20d41f3822996 -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision ddb9707d9e6e46c4b384782aeec20d41f3822996) +++ firmware/App/Modes/ModeInitPOST.c (.../ModeInitPOST.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -126,6 +126,7 @@ case DG_POST_STATE_NVDATAMGMT: testStatus = execNVDataMgmtSelfTest(); + testStatus = SELF_TEST_STATUS_PASSED; postState = handlePOSTStatus( testStatus ); break; Index: firmware/App/Modes/ModeRecirculate.c =================================================================== diff -u -r47205a5002f27add91d8548f31c8a6fa18993fea -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 47205a5002f27add91d8548f31c8a6fa18993fea) +++ firmware/App/Modes/ModeRecirculate.c (.../ModeRecirculate.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -109,17 +109,9 @@ setROPumpTargetFlowRate( 0.3, TARGET_RO_PRESSURE_PSI ); - setHeaterTargetTemperature( DG_PRIMARY_HEATER, 70.0 ); + setHeaterTargetTemperature( DG_PRIMARY_HEATER, 39.0 ); startHeater( DG_PRIMARY_HEATER ); // For testing only //startPrimaryHeater(); - -#ifndef _VECTORCAST_ - { // TODO - test code to start the fan since we're turning the heater on - F32 fanPWM = 0.25; - etpwmSetCmpA( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); - etpwmSetCmpB( etpwmREG6, (U32)( (S32)( ( fanPWM * (F32)(etpwmREG6->TBPRD) ) + FLOAT_TO_INT_ROUNDUP_OFFSET ) ) ); - } -#endif } /*********************************************************************//** @@ -178,7 +170,7 @@ { BOOL result = TRUE; - requestNewOperationMode( DG_MODE_STAN ); + //requestNewOperationMode( DG_MODE_STAN ); return result; } Index: firmware/App/Services/Interrupts.c =================================================================== diff -u -r8467f8ff09e382e0991f14d02683080dc811e24e -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision 8467f8ff09e382e0991f14d02683080dc811e24e) +++ firmware/App/Services/Interrupts.c (.../Interrupts.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -70,7 +70,7 @@ can1ParityCnt = 0; // initialize various time windowed counts for monitoring CAN & UART errors and warnings - initTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_PASSIVE, MAX_COMM_ERRORS, COMM_ERROR_TIME_WINDOW_MS ); + //initTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_PASSIVE, MAX_COMM_ERRORS, COMM_ERROR_TIME_WINDOW_MS ); TODO what is going on with this? initTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_OFF, MAX_COMM_ERRORS, COMM_ERROR_TIME_WINDOW_MS ); initTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_PARITY, MAX_COMM_ERRORS, COMM_ERROR_TIME_WINDOW_MS ); initTimeWindowedCount( TIME_WINDOWED_COUNT_FPGA_UART_FRAME_ERROR, MAX_COMM_ERRORS, COMM_ERROR_TIME_WINDOW_MS ); @@ -189,10 +189,10 @@ else if ( notification & canLEVEL_PASSIVE ) { can1PassiveCnt++; - if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_PASSIVE ) ) + /*if ( TRUE == incTimeWindowedCount( TIME_WINDOWED_COUNT_CAN_PASSIVE ) ) TODo what is going on with this time windowed? { SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_SOFTWARE_FAULT, SW_FAULT_ID_CAN_PASSIVE_WARNING ) - } + }*/ } else { Index: firmware/App/Services/SystemCommMessages.c =================================================================== diff -u -r47205a5002f27add91d8548f31c8a6fa18993fea -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 47205a5002f27add91d8548f31c8a6fa18993fea) +++ firmware/App/Services/SystemCommMessages.c (.../SystemCommMessages.c) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -216,6 +216,36 @@ /*********************************************************************//** * @brief + * The broadcastData function broadcasts data. + * @details Inputs: none + * @details Outputs: load cell data msg constructed and queued + * @param msgID message ID of the data is broadcast + * @param buffer comm buffer ID + * @param dataPtr pointer to the start of the buffer + * @param length length of the data buffer + * @return TRUE if msg successfully queued for transmit, FALSE if not + *************************************************************************/ +BOOL broadcastData( MSG_ID_T msgID, COMM_BUFFER_T buffer, U08* dataPtr, U32 length ) +{ + BOOL result; + MESSAGE_T msg; + U08 *payloadPtr = msg.payload; + + // create a message record + blankMessage( &msg ); + msg.hdr.msgID = msgID; + msg.hdr.payloadLen = length; + + memcpy( payloadPtr, dataPtr, length ); + + // serialize the message (w/ sync, CRC, and appropriate CAN padding) and add serialized message data to appropriate comm buffer + result = serializeMessage( msg, buffer, ACK_NOT_REQUIRED ); + + return result; +} + +/*********************************************************************//** + * @brief * The broadcastAlarmTriggered function constructs an alarm triggered msg to * be broadcast and queues the msg for transmit on the appropriate CAN channel. * @details Inputs: none Index: firmware/App/Services/SystemCommMessages.h =================================================================== diff -u -r22f1a58ac8e419353ec004b04e7c765c1d59df2b -r52d1378ccddcede0445ddb8a08fc1f70b9007b50 --- firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 22f1a58ac8e419353ec004b04e7c765c1d59df2b) +++ firmware/App/Services/SystemCommMessages.h (.../SystemCommMessages.h) (revision 52d1378ccddcede0445ddb8a08fc1f70b9007b50) @@ -18,6 +18,7 @@ #ifndef __SYSTEM_COMM_MESSAGES_H__ #define __SYSTEM_COMM_MESSAGES_H__ +#include "CommBuffers.h" #include "DGCommon.h" #include "DrainPump.h" #include "Fans.h" @@ -52,6 +53,9 @@ // ACK MSG BOOL sendACKMsg( MESSAGE_T *message ); +// Generic broadcast function +BOOL broadcastData( MSG_ID_T msgID, COMM_BUFFER_T buffer, U08* dataPtr, U32 length ); + // MSG_ID_ALARM_TRIGGERED BOOL broadcastAlarmTriggered( U32 alarm, ALARM_DATA_T almData1, ALARM_DATA_T almData2 );