Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -r2c08db070a6e09306caf461e7aceeb53097fd995 -rf847ac4a7a0a080c4b62886243f5b863c4e7730d --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 2c08db070a6e09306caf461e7aceeb53097fd995) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision f847ac4a7a0a080c4b62886243f5b863c4e7730d) @@ -7,8 +7,8 @@ * * @file ROPump.c * -* @author (last) Dara Navaei -* @date (last) 21-Dec-2022 +* @author (last) Bill Bracken +* @date (last) 01-Sep-2023 * * @author (original) Sean * @date (original) 04-Apr-2020 @@ -76,14 +76,20 @@ /// Initial conversion factor from target flow rate to PWM duty cycle estimate. #define ROP_FLOW_TO_PWM_DC(flow) ( ROP_FLOW_TO_PWM_SLOPE * flow + ROP_FLOW_TO_PWM_INTERCEPT ) -#define MAX_ALLOWED_FLOW_DEVIATION 0.1F ///< Max allowed deviation from target flow. -#define FLOW_OUT_OF_RANGE_TIME_OUT_MS ( 30 * MS_PER_SECOND ) ///< Flow out of range time out in counts. // TODO - changed to prevent alarms (initial value 12) +#define MAX_ALLOWED_FLOW_DEVIATION_PCT 0.1F ///< Max allowed deviation from target flow in percent. +#define MAX_ALLOWED_FLOW_DEVIATION_MLPM 100.0F ///< Max allowed deviation from target flow in mL/min. +#define FLOW_OUT_OF_RANGE_TIME_OUT_MS ( 12 * MS_PER_SECOND ) ///< Flow out of range time out in counts. +#define FLOW_OUT_OF_LOWER_RANGE_TIMEOUT_MS ( 30 * MS_PER_SECOND ) ///< Flow out of lower range time out in ms +#define FLOW_OUT_OF_LOWER_RANGE_CLEAR_MS ( 10 * MS_PER_SECOND ) ///< Flow out of lower range clear time out in ms #define MAX_PRESSURE_TARGET_TOLERANCE 5 ///< Pressure tolerance from maximum set pressure by user in psi. #define MAX_ALLOWED_PRESSURE_PSI 130 ///< Maximum allowed pressure that the RO pump can go to. #define MIN_ALLOWED_PRESSURE_PSI 10 ///< Minimum allowed pressure that the RO pump can go to. #define MAX_ALLOWED_MEASURED_PRESSURE_PSI 135 ///< Maximum allowed pressure that the sensor measures. RO pump shut off pressure is 140psi. #define MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL MS_PER_SECOND ///< Maximum allowed time that the pressure can be very high. #define MAX_ALLOWED_RAMP_UP_TIME ( 10 * MS_PER_SECOND ) ///< Maximum allowed ramp up time to a flow rate in ms. +#define MAX_ALLOWED_RO_PUMP_PWM_PERCENT ( 0.95F ) ///< Maximum allowed RO Pump PWM . +#define MAX_RO_PUMP_PWM_PERSISTENT_INTERVAL ( 30 * MS_PER_SECOND ) ///< Maximum allowed time that ROPump PWM exceeded max in ms. +#define MAX_RO_PUMP_PWM_CLEAR_INTERVAL ( MS_PER_SECOND ) ///< Maximum clear time for ROPump PWM max exceeded in ms. #define ROP_PSI_TO_PWM_DC(p) ( 0.2F + ( (F32)((p) - 100) * 0.01F ) ) ///< Conversion factor from target PSI to PWM duty cycle estimate. #define SAFETY_SHUTDOWN_TIMEOUT ( 3 * MS_PER_SECOND ) ///< RO pump safety shutdown activation timeout in ms. @@ -184,16 +190,19 @@ MIN_RO_PUMP_DUTY_CYCLE, MAX_RO_PUMP_DUTY_CYCLE ); // Initialize the persistent alarm for flow out of upper and lower range - initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, FLOW_OUT_OF_RANGE_TIME_OUT_MS, FLOW_OUT_OF_RANGE_TIME_OUT_MS ); - initPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FLOW_OUT_OF_RANGE_TIME_OUT_MS, FLOW_OUT_OF_RANGE_TIME_OUT_MS ); + initPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_UPPER_RANGE, FLOW_OUT_OF_RANGE_TIME_OUT_MS, FLOW_OUT_OF_RANGE_TIME_OUT_MS ); + initPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_LOWER_RANGE, FLOW_OUT_OF_LOWER_RANGE_CLEAR_MS, FLOW_OUT_OF_LOWER_RANGE_TIMEOUT_MS ); // Initialize the persistent alarm for max allowed pressure out of range - initPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, - MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); + initPersistentAlarm( ALARM_ID_DG_RO_PUMP_PRESSURE_OUT_OF_RANGE, MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL, + MAX_PRESSURE_OUT_OF_RANGE_PERSISTENT_INTERVAL ); // Initialize the persistent alarm for not turning off the pump - initPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); + initPersistentAlarm( ALARM_ID_DG_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, SAFETY_SHUTDOWN_TIMEOUT, SAFETY_SHUTDOWN_TIMEOUT ); + // Initialize the persistent alarm for maximum RO PWM exceeded + initPersistentAlarm( ALARM_ID_DG_MAX_RO_PUMP_PWM_EXCEEDED, MAX_RO_PUMP_PWM_CLEAR_INTERVAL, MAX_RO_PUMP_PWM_PERSISTENT_INTERVAL ); + // Initialize the variables roControlTimerCounter = 0; roPumpOpenLoopTargetDutyCycle = 0; @@ -314,7 +323,7 @@ * roPumpPWMDutyCyclePctSet, roPumpControlMode * @details Outputs: roPumpOpenLoopTargetDutyCycle, roPumpPWMDutyCyclePct, * roPumpPWMDutyCyclePctSet, roPumpControlMode - * @param: duty which is the duty cycle + * @param duty which is the duty cycle * @return none *************************************************************************/ BOOL setROPumpTargetDutyCycle( F32 duty ) @@ -346,7 +355,7 @@ * resets all the variables associated with the RO pump run. * @details Inputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, flowVerificationCounter, - * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter + * flowVerificationCounter, rampUp2FlowTimeoutCounter * @details Outputs: targetROPumpFlowRate, roPumpState, roPumpPWMDutyCyclePct, * roPumpOpenLoopTargetDutyCycle, roControlTimerCounter, * flowVerificationCounter, isROPumpOn, rampUp2FlowTimeoutCounter @@ -360,7 +369,6 @@ roPumpPWMDutyCyclePct = 0.0F; roPumpOpenLoopTargetDutyCycle = 0.0F; roControlTimerCounter = 0; - //isROPumpOn = FALSE; // TODo remove targetROPumpMaxPressure = 0; pendingROPumpCmdMaxPressure = 0.0F; pendingROPumpCmdTargetFlow = 0.0F; @@ -387,10 +395,16 @@ // to make sure the hardware (especially the ROF) is not damaged. If it is the case, we need to stop immediately F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); BOOL isPressureMax = ( actualPressure >= MAX_ALLOWED_MEASURED_PRESSURE_PSI ? TRUE : FALSE ); - BOOL isDutyCylceOutOfRange = FALSE; + BOOL isDutyCycleOutOfRange = FALSE; + BOOL isMaxPWM = ( roPumpDutyCyclePctSet > MAX_ALLOWED_RO_PUMP_PWM_PERCENT ) ? TRUE : FALSE; - checkPersistentAlarm( ALARM_ID_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure, MAX_ALLOWED_MEASURED_PRESSURE_PSI ); + // The feedback voltage is on the 0V line so when the duty cycle is 0, the feedback is 2.5V + // The duty cycle is calculated by getting the 1 - (ratio of feedback / to the voltage at 0 percent duty cycle). + roPumpFeedbackDutyCyclePct.data = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); + isDutyCycleOutOfRange = ( fabs( getROFeedbackDutyCycle() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); + checkPersistentAlarm( ALARM_ID_DG_RO_PUMP_PRESSURE_OUT_OF_RANGE, isPressureMax, actualPressure, MAX_ALLOWED_MEASURED_PRESSURE_PSI ); + if ( ( getMeasuredFlowRateLPM( RO_FLOW_SENSOR ) > NEARLY_ZERO ) && ( VALVE_STATE_CLOSED == getValveStateName( VBF ) ) ) { // If the RO pump's flow is greater than zero, and the VBf valve is not open (like heat disinfect) it means RO water is being generated @@ -402,41 +416,83 @@ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_RO_PUMP_MONITOR ) != SW_CONFIG_ENABLE_VALUE ) #endif { + // See if the maximum PWM alarm has occurred + checkPersistentAlarm( ALARM_ID_DG_MAX_RO_PUMP_PWM_EXCEEDED, isMaxPWM, roPumpDutyCyclePctSet, MAX_ALLOWED_RO_PUMP_PWM_PERCENT ); + // To monitor the flow, the control mode must be in closed loop mode and the pump should be control to flow state - // If the pump is controlled to the maximum pressure, the flow might be different from the target flow for more than 10% + // If the pump is controlled to the maximum pressure, the flow might be different from the target flow for more than the target // but the pump is not able to achieve the flow. if ( ( PUMP_CONTROL_MODE_CLOSED_LOOP == roPumpControlMode ) && ( RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE == roPumpState ) ) { - F32 currentFlow = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); - F32 targetFlow = getTargetROPumpFlowRateLPM(); - // The flow cannot be out of range for than 10% of the target flow - BOOL isFlowOutOfRange = ( fabs( 1.0F - ( currentFlow / targetFlow ) ) > MAX_ALLOWED_FLOW_DEVIATION ? TRUE : FALSE ); - // Figure out whether flow is out of range from which side - BOOL isFlowOutOfUpperRange = ( isFlowOutOfRange && ( currentFlow > targetFlow ) ? TRUE : FALSE ); - BOOL isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlow < targetFlow ) ? TRUE : FALSE ); + BOOL isFlowOutOfUpperRange = FALSE; + BOOL isFlowOutOfLowerRange = FALSE; + BOOL isFlowOutOfRange = FALSE; + F32 currentFlowLPM = getMeasuredFlowRateLPM( RO_FLOW_SENSOR ); + F32 targetFlowLPM = getTargetROPumpFlowRateLPM(); - checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, isFlowOutOfUpperRange, currentFlow, targetFlow ); - checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, isFlowOutOfLowerRange, currentFlow, targetFlow ); + switch ( getCurrentOperationMode() ) + { + case DG_MODE_GENE: + // The flow cannot be out of target by more than +/- 100 mL/min + isFlowOutOfRange = ( ( fabs( currentFlowLPM - targetFlowLPM ) * ML_PER_LITER ) > MAX_ALLOWED_FLOW_DEVIATION_MLPM ); + isFlowOutOfUpperRange = ( isFlowOutOfRange && ( currentFlowLPM > targetFlowLPM ) ? TRUE : FALSE ); + isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlowLPM < targetFlowLPM ) ? TRUE : FALSE ); + break; + + case DG_MODE_DRAI: + // The flow cannot be out of target by less than 100 mL/min + isFlowOutOfRange = ( ( fabs( currentFlowLPM - targetFlowLPM ) * ML_PER_LITER ) > MAX_ALLOWED_FLOW_DEVIATION_MLPM ); + isFlowOutOfUpperRange = FALSE; + isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlowLPM < targetFlowLPM ) ? TRUE : FALSE ); + break; + + case DG_MODE_FILL: + case DG_MODE_FLUS: + case DG_MODE_CHEM: + case DG_MODE_CHFL: + case DG_MODE_ROPS: + // The flow cannot be out of range for than 10% of the target flow + isFlowOutOfRange = ( fabs( 1.0F - ( currentFlowLPM / targetFlowLPM ) ) > MAX_ALLOWED_FLOW_DEVIATION_PCT ? TRUE : FALSE ); + isFlowOutOfUpperRange = ( isFlowOutOfRange && ( currentFlowLPM > targetFlowLPM ) ? TRUE : FALSE ); + isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlowLPM < targetFlowLPM ) ? TRUE : FALSE ); + break; + + case DG_MODE_HEAT: + case DG_MODE_HCOL: + if ( getTargetROPumpPressurePSI() > CLEANING_MODE_HIGH_TEMP_MAX_RO_PRESSURE_PSI ) + { + // The flow cannot be out of range for than 10% of the target flow + isFlowOutOfRange = ( fabs( 1.0F - ( currentFlowLPM / targetFlowLPM ) ) > MAX_ALLOWED_FLOW_DEVIATION_PCT ? TRUE : FALSE ); + isFlowOutOfUpperRange = ( isFlowOutOfRange && ( currentFlowLPM > targetFlowLPM ) ? TRUE : FALSE ); + isFlowOutOfLowerRange = ( isFlowOutOfRange && ( currentFlowLPM < targetFlowLPM ) ? TRUE : FALSE ); + } + break; + + default: + // Do nothing in the rest of the modes. + // Do not check the flow target in heat disinfect active cool since the flow during cooling might be very different from the target flow + // since the RO pump membrane is hot and the target flow is low so the RO pump's duty cycle is mostly 0% but the flow is still high and + // above the target + break; + } + + checkPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_UPPER_RANGE, isFlowOutOfUpperRange, currentFlowLPM, targetFlowLPM ); + checkPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_LOWER_RANGE, isFlowOutOfLowerRange, currentFlowLPM, targetFlowLPM ); } else { - checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_UPPER_RANGE, FALSE, 0.0F, 0.0F ); - checkPersistentAlarm( ALARM_ID_FLOW_RATE_OUT_OF_LOWER_RANGE, FALSE, 0.0F, 0.0F ); + checkPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_UPPER_RANGE, FALSE, 0.0F, 0.0F ); + checkPersistentAlarm( ALARM_ID_DG_FLOW_RATE_OUT_OF_LOWER_RANGE, FALSE, 0.0F, 0.0F ); } #ifndef _RELEASE_ if ( getHardwareConfigStatus() != HW_CONFIG_BETA ) #endif { - // The feedback voltage is on the 0V line so when the duty cycle is 0, the feedback is 2.5V - // The duty cycle is calculated by getting the 1 - (ratio of feedback / to the voltage at 0 percent duty cycle). - roPumpFeedbackDutyCyclePct.data = 1.0F - ( roFeedbackVoltage / ROP_FEEDBACK_0_PCT_DUTY_CYCLE_VOLTAGE ); - isDutyCylceOutOfRange = ( fabs( getROFeedbackDutyCycle() - roPumpDutyCyclePctSet ) > ROP_DUTY_CYCLE_OUT_OF_RANGE_TOLERANCE ? TRUE : FALSE ); + checkPersistentAlarm( ALARM_ID_DG_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCycleOutOfRange, getROFeedbackDutyCycle(), roPumpDutyCyclePctSet ); - checkPersistentAlarm( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE, isDutyCylceOutOfRange, getROFeedbackDutyCycle(), roPumpDutyCyclePctSet ); - // Check if it the alarm has timed out and if the pump is supposed to be off but it is still on, activate the safety shutdown - if ( ( TRUE == isAlarmActive( ALARM_ID_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) && ( FALSE == isROPumpOn ) ) + if ( ( TRUE == isAlarmActive( ALARM_ID_DG_RO_PUMP_DUTY_CYCLE_OUT_OF_RANGE ) ) && ( FALSE == isROPumpOn ) ) { activateSafetyShutdown(); } @@ -702,11 +758,13 @@ F32 actualPressure = getMeasuredDGPressure( PRESSURE_SENSOR_RO_PUMP_OUTLET ); // Control at set interval - if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL && roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) + if ( ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) && ( roPumpControlMode == PUMP_CONTROL_MODE_CLOSED_LOOP ) ) { if ( actualPressure > targetROPumpMaxPressure ) { + // Reduce the duty cycle and make sure it does not go below 0% roPumpDutyCyclePctSet -= ROP_RAMP_DOWN_DUTY_CYCLE_RATIO; + roPumpDutyCyclePctSet = MAX( roPumpDutyCyclePctSet, MIN_RO_PUMP_DUTY_CYCLE ); resetPIController( PI_CONTROLLER_ID_RO_PUMP_MAX_PRES, roPumpDutyCyclePctSet ); } else @@ -886,7 +944,7 @@ * RO pump data publish interval. * @details Inputs: roPumpDataPublishInterval * @details Outputs: roPumpDataPublishInterval - * @param: value : override RO pump data publish interval with (in ms) + * @param value : override RO pump data publish interval with (in ms) * @return TRUE if override successful, FALSE if not *************************************************************************/ BOOL testSetROPumpDataPublishIntervalOverride( U32 value )