Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r5c967dc311b485769e50e5e4f122be21079b5ae9 -rfba89d67dd2bef913e85a13563e2aa49f0e2e2f5 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 5c967dc311b485769e50e5e4f122be21079b5ae9) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision fba89d67dd2bef913e85a13563e2aa49f0e2e2f5) @@ -26,6 +26,7 @@ #include "OperationModes.h" #include "PIControllers.h" #include "ROPump.h" +#include "SafetyShutdown.h" #include "SystemCommMessages.h" #include "TaskPriority.h" #include "TemperatureSensors.h" @@ -62,8 +63,10 @@ #define MINIMUM_TARGET_TEMPERATURE 10U ///< Minimum allowed target temperature for the heaters. #define MAXIMUM_TARGET_TEMPERATURE 90U ///< Maximum allowed target temperature for the heaters. - #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 120.0 ///< Heaters max allowed internal temperature in degrees C. TODO figure out the max temperature value +#define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heaters max allowed internal temperature timeout in milliseconds. +#define HEATERS_ON_NO_FLOW_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heaters on with no flow time out in milliseconds. /// Heaters self-test enums typedef enum heaters_self_test_states @@ -106,9 +109,6 @@ static PRIMARY_HEATERS_EXEC_STATES_T primaryHeatersExecState; ///< Primary heaters exec state. static TRIMMER_HEATER_EXEC_STATES_T trimmerHeaterExecState; ///< Trimmer heater exec state. -static PRIMARY_HEATERS_EXEC_STATES_T primaryHeatersExecPrevState; ///< Primary heaters exec previous state. -static TRIMMER_HEATER_EXEC_STATES_T trimmerHeaterExecPrevState; ///< Trimmer heater exec previous state. - static F32 primaryHeaterTargetTemperature; ///< Primary heaters target temperature. static F32 trimmerHeaterTargetTemperature; ///< Trimmer heater target temperature. @@ -126,10 +126,16 @@ static U32 selfTestElapsedTime; ///< Self-test elapsed time variable. static BOOL hasStartPrimaryHeaterRequested; ///< Start primary heater request flag. static BOOL hasStartTrimmerHeaterRequested; ///< Start trimmer heater request flag. -static U32 heatersOnWithNoFlowTimeOut; ///< Heaters are on but there is no sufficient flow. +static U32 heatersOnWithNoFlowTimer; ///< Heaters are on but there is no sufficient flow. static TEMPERATURE_SENSORS_T primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_PRIMARY_HEATER; ///< Primary heaters feedback temperature sensors. -static TEMPERATURE_SENSORS_T trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; ///< Trimmer heater feedback temperature sensor. +static TEMPERATURE_SENSORS_T trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; ///< Trimmer heater feedback temperature sensors. +static U32 primaryHeatersInternalTempOutTimer = 0; ///< Primary heaters internal temperature out of range timer. +static U32 trimmerHeaterInternalTempOutTimer = 0; ///< Trimmer heater internal temperature out of range timer. +static BOOL isPrimaryHeatersTempOutOfRange = FALSE; ///< Boolean flag to indicate if the primary heaters internal temperature out of range. +static BOOL isTrimmerHeaterTempOutOfRange = FALSE; ///< Boolean flag to indicate if the trimmer heater internal temperature out of range. +static BOOL isFlowBelowMin = FALSE; ///< Boolean flag to indicate if the flow is below the minimum. + // ********** private function prototypes ********** static HEATERS_SELF_TEST_STATES_T handleHeatersSelfTestStart( void ); @@ -159,19 +165,24 @@ *************************************************************************/ void initHeaters( void ) { - heatersSelfTestState = HEATERS_SELF_TEST_START; - primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_OFF; - trimmerHeaterExecState = TRIMMER_HEATER_EXEC_STATE_OFF; - primaryHeaterTargetTemperature = 0.0; - trimmerHeaterTargetTemperature = 0.0; - primaryHeaterTimerCounter = 0; - trimmerHeaterTimerCounter = 5; - dataPublicationTimerCounter = 0; - isPrimaryHeaterOn = FALSE; - isTrimmerHeaterOn = FALSE; - selfTestElapsedTime = 0; - primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_PRIMARY_HEATER; - trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; + heatersSelfTestState = HEATERS_SELF_TEST_START; + primaryHeatersExecState = PRIMARY_HEATERS_EXEC_STATE_OFF; + trimmerHeaterExecState = TRIMMER_HEATER_EXEC_STATE_OFF; + primaryHeaterTargetTemperature = 0.0; + trimmerHeaterTargetTemperature = 0.0; + primaryHeaterTimerCounter = 0; + trimmerHeaterTimerCounter = 5; + dataPublicationTimerCounter = 0; + isPrimaryHeaterOn = FALSE; + isTrimmerHeaterOn = FALSE; + selfTestElapsedTime = 0; + primaryHeatersFeedbackTempSensor = TEMPSENSORS_OUTLET_PRIMARY_HEATER; + trimmerHeaterFeedbackTempSensor = TEMPSENSORS_OUTLET_REDUNDANT; + primaryHeatersInternalTempOutTimer = 0; + trimmerHeaterInternalTempOutTimer = 0; + isPrimaryHeatersTempOutOfRange = FALSE; + isTrimmerHeaterTempOutOfRange = FALSE; + isFlowBelowMin = FALSE; // 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, @@ -326,43 +337,90 @@ /*********************************************************************//** * @brief - * The execHeatersMonitor function turns off the heaters when RO pump is not on. + * The execHeatersMonitor function turns off the heaters when RO pump is + * not on. * @details Inputs: none * @details Outputs: Turns off the heaters when RO pump is not on * @return none *************************************************************************/ void execHeatersMonitor( void ) { - /*if ( isPrimaryHeaterOn || isTrimmerHeaterOn ) +#ifndef IGNORE_HEATERS_MONITOR + F32 primaryHeatersInternalTemp = getTemperatureValue( TEMPSENSORS_PRIMARY_HEATER_INTERNAL ); + F32 trimmerHeaterInternalTemp = getTemperatureValue( TEMPSENSORS_TRIMMER_HEATER_INTERNAL ); + + // Check if the primary heaters' internal temperature is above the limit + if ( primaryHeatersInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) { - // If the RO pump is not on, turn off the heaters - if ( ( getMeasuredROFlowRate() < MIN_RO_FLOWRATE_LPM ) && ( ++heatersOnWithNoFlowTimeOut > HEATERS_ON_WITH_NO_FLOW_TIMEOUT_COUNT ) ) + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATERS_INTERNAL_TEMP_OUT_OF_RANGE, primaryHeatersInternalTemp ); + + // If it is above the range for the first time, stop the primary heaters + // and set the variables + if ( FALSE == isPrimaryHeatersTempOutOfRange ) { - stopPrimaryHeater(); // TODO - this is so immediate - if other module requests RO pump on and start heater, this monitor may stop the heater request before RO pump has a chance to start - stopTrimmerHeater(); + stopPrimaryHeater(); + isPrimaryHeatersTempOutOfRange = TRUE; + primaryHeatersInternalTempOutTimer = getMSTimerCount(); + } + // If the primary heaters internal temperature was out for more than the define period, activate the safety shutdown + else if ( TRUE == didTimeout( primaryHeatersInternalTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) + { + activateSafetyShutdown(); + } + } - primaryHeatersExecPrevState = primaryHeatersExecState; - trimmerHeaterExecPrevState = trimmerHeaterExecState; + // Check if the trimmer heater internal temperature is above the limit + if ( trimmerHeaterInternalTemp > HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C ) + { + SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_INTERNAL_TEMP_OUT_OF_RANGE, trimmerHeaterInternalTemp ); - heatersOnWithNoFlowTimeOut = 0; + // If it is above the range for the first time, stop the trimmer heater + // and set the variables + if ( FALSE == isTrimmerHeaterTempOutOfRange ) + { + stopTrimmerHeater(); + isTrimmerHeaterTempOutOfRange = TRUE; + trimmerHeaterInternalTempOutTimer = getMSTimerCount(); } + // If the trimmer heater internal temperature was out for more than the define period, activate the safety shutdown + else if ( TRUE == didTimeout( trimmerHeaterInternalTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) + { + activateSafetyShutdown(); + } } - else + + /* + * If any of the heaters are on, check if the flow is below than the minimum value + * If the flow is below minimum for the first time, set the variables + * If the flow is below minimum for more than the defined time, stop the heaters and raise the alarm + * If the flow is in range, reset the variables + */ + if ( ( TRUE == isPrimaryHeaterOn ) || ( TRUE == isTrimmerHeaterOn ) ) { - if ( getMeasuredROFlowRate() > MIN_RO_FLOWRATE_LPM ) + F32 measuredFlow = getMeasuredROFlowRate(); + + if ( measuredFlow < MIN_RO_FLOWRATE_LPM ) { - if ( primaryHeatersExecPrevState != PRIMARY_HEATERS_EXEC_STATE_OFF ) + if ( FALSE == isFlowBelowMin ) { - setPrimaryHeaterTargetTemperature( primaryHeaterTargetTemperature ); - startPrimaryHeater(); + isFlowBelowMin = TRUE; + heatersOnWithNoFlowTimer = getMSTimerCount(); } - if ( trimmerHeaterExecPrevState != TRIMMER_HEATER_EXEC_STATE_OFF ) + else if ( TRUE == didTimeout( heatersOnWithNoFlowTimer, HEATERS_ON_NO_FLOW_TIMEOUT_MS ) ) { - setTrimmerHeaterTargetTemperature( trimmerHeaterTargetTemperature ); - startTrimmerHeater(); + stopPrimaryHeater(); + stopTrimmerHeater(); + + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_DG_HEATERS_ON_WITH_NO_FLOW_TIMEOUT, measuredFlow ); } } - }*/ + else + { + isFlowBelowMin = FALSE; + heatersOnWithNoFlowTimer = getMSTimerCount(); + } + } +#endif // Check for data publication publishHeatersData(); @@ -607,25 +665,38 @@ if ( ++primaryHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) { - F32 outletTemp = getTemperatureValue( primaryHeatersFeedbackTempSensor ); - mainPrimaryHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); - - if ( mainPrimaryHeaterDutyCycle >= MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ) + // 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 + // If the flow is within range, run the PI controller to control the heaters normally + if ( FALSE == isFlowBelowMin ) { - // The duty cycle from the PI controller was greater than max duty cycle of the main primary - // heater. So subtract the remaining from the max main primary heater duty cycle and set - // the rest to the small primary heater - smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle - MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; - mainPrimaryHeaterDutyCycle = MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; - setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); - setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + F32 outletTemp = getTemperatureValue( primaryHeatersFeedbackTempSensor ); + mainPrimaryHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_PRIMARY_HEATER, primaryHeaterTargetTemperature, outletTemp ); + + if ( mainPrimaryHeaterDutyCycle >= MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE ) + { + // The duty cycle from the PI controller was greater than max duty cycle of the main primary + // heater. So subtract the remaining from the max main primary heater duty cycle and set + // the rest to the small primary heater + smallPrimaryHeaterDutyCycle = mainPrimaryHeaterDutyCycle - MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; + mainPrimaryHeaterDutyCycle = MAIN_PRIMARY_HEATER_MAX_DUTY_CYCLE; + setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); + setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + } + else + { + setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); + smallPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; + setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + } } + // Flow is below the minimum required flow to run the primary heaters else { - setMainPrimaryHeaterPWM( mainPrimaryHeaterDutyCycle ); - smallPrimaryHeaterDutyCycle = HEATERS_MIN_DUTY_CYCLE; - setSmallPrimaryHeaterPWM( smallPrimaryHeaterDutyCycle ); + setMainPrimaryHeaterPWM( HEATERS_MIN_DUTY_CYCLE ); + setSmallPrimaryHeaterPWM( HEATERS_MIN_DUTY_CYCLE ); } + primaryHeaterTimerCounter = 0; } @@ -678,7 +749,8 @@ * The handleTrimmerHeaterControlToTarget function handles the trimmer * heater at control state when the heater is active. * @details Inputs: trimmerHeaterTimerCounter, trimmerHeaterDutyCycle - * @details Outputs: trimmerHeaterTimerCounter, trimmerHeaterDutyCycle, isTrimmerHeaterOn + * @details Outputs: trimmerHeaterTimerCounter, trimmerHeaterDutyCycle, + * isTrimmerHeaterOn * @return state (TRIMMER_HEATER_EXEC_STATES_T) *************************************************************************/ static TRIMMER_HEATER_EXEC_STATES_T handleTrimmerHeaterControlToTarget( void ) @@ -687,9 +759,20 @@ if ( ++trimmerHeaterTimerCounter >= CONTROLLER_CHECK_INTERVAL_COUNT ) { - F32 outletTemp = getTemperatureValue( trimmerHeaterFeedbackTempSensor ); - trimmerHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_TRIMMER_HEATER, trimmerHeaterTargetTemperature, outletTemp ); - setTrimmerHeaterPWM( trimmerHeaterDutyCycle ); + // 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 + // If the flow is within range, run the PI controller to control the heaters normally + if ( FALSE == isFlowBelowMin ) + { + F32 outletTemp = getTemperatureValue( trimmerHeaterFeedbackTempSensor ); + trimmerHeaterDutyCycle = runPIController( PI_CONTROLLER_ID_TRIMMER_HEATER, trimmerHeaterTargetTemperature, outletTemp ); + setTrimmerHeaterPWM( trimmerHeaterDutyCycle ); + } + else + { + setTrimmerHeaterPWM( HEATERS_MIN_DUTY_CYCLE ); + } + trimmerHeaterTimerCounter = 0; }